From a4399f0c1ea278e7ba7a6435b0d68bc89d01d29d Mon Sep 17 00:00:00 2001 From: Tim203 Date: Thu, 16 Dec 2021 00:19:51 +0100 Subject: [PATCH 01/72] Implemented Floodgate's 'packet' plugin message --- .../java/JavaCustomPayloadTranslator.java | 41 ++++++++++++++----- .../geyser/util/PluginMessageUtils.java | 2 +- 2 files changed, 31 insertions(+), 12 deletions(-) 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 c0b56fb63..4070aac86 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,19 +25,22 @@ package org.geysermc.geyser.translator.protocol.java; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundCustomPayloadPacket; import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundCustomPayloadPacket; +import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundCustomPayloadPacket; import com.google.common.base.Charsets; import com.nukkitx.protocol.bedrock.packet.TransferPacket; -import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.GeyserLogger; -import org.geysermc.geyser.session.auth.AuthType; -import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.translator.protocol.PacketTranslator; -import org.geysermc.geyser.translator.protocol.Translator; +import com.nukkitx.protocol.bedrock.packet.UnknownPacket; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; import org.geysermc.cumulus.Form; import org.geysermc.cumulus.Forms; import org.geysermc.cumulus.util.FormType; +import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.GeyserLogger; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.session.auth.AuthType; +import org.geysermc.geyser.translator.protocol.PacketTranslator; +import org.geysermc.geyser.translator.protocol.Translator; import java.nio.charset.StandardCharsets; @@ -62,8 +65,7 @@ public class JavaCustomPayloadTranslator extends PacketTranslator Date: Thu, 16 Dec 2021 21:58:40 +0100 Subject: [PATCH 02/72] Packet ids can't be negative --- .../translator/protocol/java/JavaCustomPayloadTranslator.java | 2 +- 1 file changed, 1 insertion(+), 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 4070aac86..14f54c710 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 @@ -112,7 +112,7 @@ public class JavaCustomPayloadTranslator extends PacketTranslator Date: Sat, 22 Jan 2022 12:20:52 +0100 Subject: [PATCH 03/72] Update Geyser to use the latest features of Cumulus 1.1 --- common/pom.xml | 2 +- .../geyser/session/GeyserSession.java | 4 +- .../session/cache/AdvancementsCache.java | 36 +++------- .../geyser/session/cache/FormCache.java | 27 ++++--- ...edrockServerSettingsRequestTranslator.java | 15 ++-- .../java/JavaCustomPayloadTranslator.java | 13 ++-- .../geyser/util/LoginEncryptionUtils.java | 72 ++++++++----------- .../geysermc/geyser/util/SettingsUtils.java | 14 ++-- .../geysermc/geyser/util/StatisticsUtils.java | 23 ++---- 9 files changed, 82 insertions(+), 124 deletions(-) diff --git a/common/pom.xml b/common/pom.xml index 8e7be26f4..54a65ab99 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -20,7 +20,7 @@ org.geysermc.cumulus cumulus - 1.0-SNAPSHOT + 1.1-SNAPSHOT com.google.code.gson 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 742a2e4a9..9113792ba 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -76,7 +76,7 @@ import lombok.Getter; import lombok.NonNull; import lombok.Setter; import org.geysermc.common.PlatformType; -import org.geysermc.cumulus.Form; +import org.geysermc.cumulus.form.Form; import org.geysermc.cumulus.util.FormBuilder; import org.geysermc.floodgate.crypto.FloodgateCipher; import org.geysermc.floodgate.util.BedrockData; @@ -1183,7 +1183,7 @@ public class GeyserSession implements GeyserConnection, CommandSender { formCache.showForm(form); } - public void sendForm(FormBuilder formBuilder) { + public void sendForm(FormBuilder formBuilder) { formCache.showForm(formBuilder.build()); } 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 9d3e4f5aa..ec633beb3 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 @@ -29,13 +29,12 @@ import com.github.steveice10.mc.protocol.data.game.advancement.Advancement; import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundSeenAdvancementsPacket; import lombok.Getter; import lombok.Setter; -import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.translator.text.MessageTranslator; +import org.geysermc.cumulus.form.SimpleForm; import org.geysermc.geyser.level.GeyserAdvancement; +import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.text.MinecraftLocale; -import org.geysermc.cumulus.SimpleForm; -import org.geysermc.cumulus.response.SimpleFormResponse; +import org.geysermc.geyser.translator.text.MessageTranslator; import java.util.HashMap; import java.util.List; @@ -87,18 +86,13 @@ public class AdvancementsCache { builder.content("advancements.empty"); } - builder.responseHandler((form, responseData) -> { - SimpleFormResponse response = form.parseResponse(responseData); - if (!response.isCorrect()) { - return; - } - + builder.validResultHandler((form, response) -> { String id = ""; int advancementIndex = 0; for (Map.Entry advancement : storedAdvancements.entrySet()) { if (advancement.getValue().getParentId() == null) { // Root advancement - if (advancementIndex == response.getClickedButtonId()) { + if (advancementIndex == response.clickedButtonId()) { id = advancement.getKey(); break; } else { @@ -148,21 +142,18 @@ public class AdvancementsCache { builder.button(GeyserLocale.getPlayerLocaleString("gui.back", language)); - builder.responseHandler((form, responseData) -> { - SimpleFormResponse response = form.parseResponse(responseData); - if (!response.isCorrect()) { - // Indicate that we have closed the current advancement tab - session.sendDownstreamPacket(new ServerboundSeenAdvancementsPacket()); - return; - } + builder.closedResultHandler(form -> { + // Indicate that we have closed the current advancement tab + session.sendDownstreamPacket(new ServerboundSeenAdvancementsPacket()); + }).validResultHandler((form, response) -> { GeyserAdvancement advancement = null; int advancementIndex = 0; // Loop around to find the advancement that the client pressed for (GeyserAdvancement advancementEntry : storedAdvancements.values()) { if (advancementEntry.getParentId() != null && currentAdvancementCategoryId.equals(advancementEntry.getRootId(this))) { - if (advancementIndex == response.getClickedButtonId()) { + if (advancementIndex == response.clickedButtonId()) { advancement = advancementEntry; break; } else { @@ -219,12 +210,7 @@ public class AdvancementsCache { .title(MessageTranslator.convertMessage(advancement.getDisplayData().getTitle())) .content(content) .button(GeyserLocale.getPlayerLocaleString("gui.back", language)) - .responseHandler((form, responseData) -> { - SimpleFormResponse response = form.parseResponse(responseData); - if (response.isCorrect()) { - buildAndShowListForm(); - } - }) + .validResultHandler((form, response) -> buildAndShowListForm()) ); } diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/FormCache.java b/core/src/main/java/org/geysermc/geyser/session/cache/FormCache.java index 965966ca4..d44f1a9d1 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/FormCache.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/FormCache.java @@ -31,17 +31,18 @@ import com.nukkitx.protocol.bedrock.packet.NetworkStackLatencyPacket; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import lombok.RequiredArgsConstructor; +import org.geysermc.cumulus.form.Form; +import org.geysermc.cumulus.form.SimpleForm; +import org.geysermc.cumulus.form.impl.FormDefinitions; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.cumulus.Form; -import org.geysermc.cumulus.SimpleForm; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.Consumer; @RequiredArgsConstructor public class FormCache { + private final FormDefinitions formDefinitions = FormDefinitions.instance(); private final AtomicInteger formId = new AtomicInteger(0); private final Int2ObjectMap
forms = new Int2ObjectOpenHashMap<>(); private final GeyserSession session; @@ -61,9 +62,11 @@ public class FormCache { } private void sendForm(int windowId, Form form) { + String jsonData = formDefinitions.codecFor(form).jsonData(form); + ModalFormRequestPacket formRequestPacket = new ModalFormRequestPacket(); formRequestPacket.setFormId(windowId); - formRequestPacket.setFormData(form.getJsonData()); + formRequestPacket.setFormData(jsonData); session.sendUpstreamPacket(formRequestPacket); // Hack to fix the (url) image loading bug @@ -88,17 +91,11 @@ public class FormCache { return; } - Consumer responseConsumer = form.getResponseHandler(); - if (responseConsumer != null) { - try { - responseConsumer.accept(response.getFormData()); - } catch (Exception e) { - GeyserImpl.getInstance().getLogger().error("Error while processing form response!", e); - } + try { + formDefinitions.definitionFor(form) + .handleFormResponse(form, response.getFormData()); + } catch (Exception e) { + GeyserImpl.getInstance().getLogger().error("Error while processing form response!", e); } } - - public boolean removeWindow(int id) { - return forms.remove(id) != null; - } } 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 ccf68ac53..6cc60dd45 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,26 +27,31 @@ package org.geysermc.geyser.translator.protocol.bedrock; import com.nukkitx.protocol.bedrock.packet.ServerSettingsRequestPacket; import com.nukkitx.protocol.bedrock.packet.ServerSettingsResponsePacket; +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.cumulus.CustomForm; import java.util.concurrent.TimeUnit; @Translator(packet = ServerSettingsRequestPacket.class) public class BedrockServerSettingsRequestTranslator extends PacketTranslator { + private final FormDefinitions formDefinitions = FormDefinitions.instance(); + @Override public void translate(GeyserSession session, ServerSettingsRequestPacket packet) { - CustomForm window = SettingsUtils.buildForm(session); - int windowId = session.getFormCache().addForm(window); + CustomForm form = SettingsUtils.buildForm(session); + int formId = session.getFormCache().addForm(form); + + String jsonData = formDefinitions.codecFor(form).jsonData(form); // Fixes https://bugs.mojang.com/browse/MCPE-94012 because of the delay session.scheduleInEventLoop(() -> { ServerSettingsResponsePacket serverSettingsResponsePacket = new ServerSettingsResponsePacket(); - serverSettingsResponsePacket.setFormData(window.getJsonData()); - serverSettingsResponsePacket.setFormId(windowId); + serverSettingsResponsePacket.setFormData(jsonData); + serverSettingsResponsePacket.setFormId(formId); session.sendUpstreamPacket(serverSettingsResponsePacket); }, 1, TimeUnit.SECONDS); } 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 04151c07f..6a65d85f1 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,19 +25,19 @@ package org.geysermc.geyser.translator.protocol.java; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundCustomPayloadPacket; import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundCustomPayloadPacket; +import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundCustomPayloadPacket; import com.google.common.base.Charsets; import com.nukkitx.protocol.bedrock.packet.TransferPacket; +import org.geysermc.cumulus.Forms; +import org.geysermc.cumulus.form.Form; +import org.geysermc.cumulus.util.FormType; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserLogger; -import org.geysermc.geyser.session.auth.AuthType; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.session.auth.AuthType; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; -import org.geysermc.cumulus.Form; -import org.geysermc.cumulus.Forms; -import org.geysermc.cumulus.util.FormType; import java.nio.charset.StandardCharsets; @@ -68,8 +68,7 @@ public class JavaCustomPayloadTranslator extends PacketTranslator { + Form form = Forms.fromJson(dataString, type, (ignored, response) -> { byte[] raw = response.getBytes(StandardCharsets.UTF_8); byte[] finalData = new byte[raw.length + 2]; 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 5a1063a10..f54242263 100644 --- a/core/src/main/java/org/geysermc/geyser/util/LoginEncryptionUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/LoginEncryptionUtils.java @@ -37,17 +37,15 @@ import com.nukkitx.network.util.Preconditions; import com.nukkitx.protocol.bedrock.packet.LoginPacket; import com.nukkitx.protocol.bedrock.packet.ServerToClientHandshakePacket; import com.nukkitx.protocol.bedrock.util.EncryptionUtils; +import org.geysermc.cumulus.form.CustomForm; +import org.geysermc.cumulus.form.ModalForm; +import org.geysermc.cumulus.form.SimpleForm; +import org.geysermc.cumulus.response.result.ResultType; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.configuration.GeyserConfiguration; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.auth.AuthData; import org.geysermc.geyser.session.auth.BedrockClientData; -import org.geysermc.cumulus.CustomForm; -import org.geysermc.cumulus.ModalForm; -import org.geysermc.cumulus.SimpleForm; -import org.geysermc.cumulus.response.CustomFormResponse; -import org.geysermc.cumulus.response.ModalFormResponse; -import org.geysermc.cumulus.response.SimpleFormResponse; import org.geysermc.geyser.text.GeyserLocale; import javax.crypto.SecretKey; @@ -232,26 +230,24 @@ public class LoginEncryptionUtils { .optionalButton("geyser.auth.login.form.notice.btn_login.mojang", isPasswordAuthEnabled) .button("geyser.auth.login.form.notice.btn_login.microsoft") .button("geyser.auth.login.form.notice.btn_disconnect") - .responseHandler((form, responseData) -> { - SimpleFormResponse response = form.parseResponse(responseData); - if (!response.isCorrect()) { - buildAndShowLoginWindow(session); - return; - } - - if (isPasswordAuthEnabled && response.getClickedButtonId() == 0) { + .resultHandler( + (form, result) -> buildAndShowLoginWindow(session), + ResultType.CLOSED, ResultType.INVALID + ) + .validResultHandler((form, response) -> { + if (isPasswordAuthEnabled && response.clickedButtonId() == 0) { session.setMicrosoftAccount(false); buildAndShowLoginDetailsWindow(session); return; } - if (isPasswordAuthEnabled && response.getClickedButtonId() == 1) { + if (isPasswordAuthEnabled && response.clickedButtonId() == 1) { session.setMicrosoftAccount(true); buildAndShowMicrosoftAuthenticationWindow(session); return; } - if (response.getClickedButtonId() == 0) { + if (response.clickedButtonId() == 0) { // Just show the OAuth code session.authenticateWithMicrosoftCode(); return; @@ -269,15 +265,11 @@ public class LoginEncryptionUtils { .label("geyser.auth.login.form.details.desc") .input("geyser.auth.login.form.details.email", "account@geysermc.org", "") .input("geyser.auth.login.form.details.pass", "123456", "") - .responseHandler((form, responseData) -> { - CustomFormResponse response = form.parseResponse(responseData); - if (!response.isCorrect()) { - buildAndShowLoginDetailsWindow(session); - return; - } - - session.authenticate(response.next(), response.next()); - })); + .resultHandler( + (form, result) -> buildAndShowLoginDetailsWindow(session), + ResultType.CLOSED, ResultType.INVALID + ) + .validResultHandler((form, response) -> session.authenticate(response.next(), response.next()))); } /** @@ -291,16 +283,14 @@ public class LoginEncryptionUtils { .button("geyser.auth.login.method.browser") .button("geyser.auth.login.method.password") .button("geyser.auth.login.form.notice.btn_disconnect") - .responseHandler((form, responseData) -> { - SimpleFormResponse response = form.parseResponse(responseData); - if (!response.isCorrect()) { - buildAndShowLoginWindow(session); - return; - } - - if (response.getClickedButtonId() == 0) { + .resultHandler( + (form, result) -> buildAndShowLoginWindow(session), + ResultType.CLOSED, ResultType.INVALID + ) + .validResultHandler((form, response) -> { + if (response.clickedButtonId() == 0) { session.authenticateWithMicrosoftCode(); - } else if (response.getClickedButtonId() == 1) { + } else if (response.clickedButtonId() == 1) { buildAndShowLoginDetailsWindow(session); } else { session.disconnect(GeyserLocale.getPlayerLocaleString("geyser.auth.login.form.disconnect", session.getLocale())); @@ -318,14 +308,12 @@ public class LoginEncryptionUtils { .content("%xbox.signin.website\n%xbox.signin.url\n%xbox.signin.enterCode\n" + msCode.user_code) .button1("%gui.done") .button2("%menu.disconnect") - .responseHandler((form, responseData) -> { - ModalFormResponse response = form.parseResponse(responseData); - if (!response.isCorrect()) { - buildAndShowMicrosoftAuthenticationWindow(session); - return; - } - - if (response.getClickedButtonId() == 1) { + .resultHandler( + (form, result) -> buildAndShowMicrosoftAuthenticationWindow(session), + ResultType.CLOSED, ResultType.INVALID + ) + .validResultHandler((form, response) -> { + if (response.clickedButtonId() == 1) { session.disconnect(GeyserLocale.getPlayerLocaleString("geyser.auth.login.form.disconnect", session.getLocale())); } }) 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 ea3412451..eb8c133d4 100644 --- a/core/src/main/java/org/geysermc/geyser/util/SettingsUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/SettingsUtils.java @@ -27,13 +27,12 @@ package org.geysermc.geyser.util; import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; import com.github.steveice10.mc.protocol.data.game.setting.Difficulty; +import org.geysermc.cumulus.component.DropdownComponent; +import org.geysermc.cumulus.form.CustomForm; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.level.GameRule; -import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.level.WorldManager; -import org.geysermc.cumulus.CustomForm; -import org.geysermc.cumulus.component.DropdownComponent; -import org.geysermc.cumulus.response.CustomFormResponse; +import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.text.MinecraftLocale; @@ -115,12 +114,7 @@ public class SettingsUtils { } } - builder.responseHandler((form, responseData) -> { - CustomFormResponse response = form.parseResponse(responseData); - if (response.isClosed() || response.isInvalid()) { - return; - } - + builder.validResultHandler((form, response) -> { if (showClientSettings) { // Client can only see its coordinates if reducedDebugInfo is disabled and coordinates are enabled in geyser config. if (session.getPreferencesCache().isAllowShowCoordinates()) { 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 447661e21..2eec54652 100644 --- a/core/src/main/java/org/geysermc/geyser/util/StatisticsUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/StatisticsUtils.java @@ -26,12 +26,11 @@ package org.geysermc.geyser.util; import com.github.steveice10.mc.protocol.data.game.statistic.*; -import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.cumulus.form.SimpleForm; +import org.geysermc.cumulus.util.FormImage; import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.type.ItemMappings; -import org.geysermc.cumulus.SimpleForm; -import org.geysermc.cumulus.response.SimpleFormResponse; -import org.geysermc.cumulus.util.FormImage; +import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.text.MinecraftLocale; @@ -68,12 +67,7 @@ public class StatisticsUtils { .button("stat.itemsButton - stat_type.minecraft.dropped", FormImage.Type.PATH, "textures/ui/trash_default") .button("stat.mobsButton - geyser.statistics.killed", FormImage.Type.PATH, "textures/items/diamond_sword") .button("stat.mobsButton - geyser.statistics.killed_by", FormImage.Type.PATH, "textures/ui/wither_heart_flash") - .responseHandler((form, responseData) -> { - SimpleFormResponse response = form.parseResponse(responseData); - if (!response.isCorrect()) { - return; - } - + .validResultHandler((form, response) -> { SimpleForm.Builder builder = SimpleForm.builder() .translator(StatisticsUtils::translate, language); @@ -81,7 +75,7 @@ public class StatisticsUtils { List content = new ArrayList<>(); ItemMappings mappings = session.getItemMappings(); - switch (response.getClickedButtonId()) { + switch (response.clickedButtonId()) { case 0: builder.title("stat.generalButton"); @@ -202,12 +196,7 @@ public class StatisticsUtils { session.sendForm( builder.content(assembledContent.toString()) .button("gui.back", FormImage.Type.PATH, "textures/gui/newgui/undo") - .responseHandler((form1, subFormResponseData) -> { - SimpleFormResponse response1 = form.parseResponse(subFormResponseData); - if (response1.isCorrect()) { - buildAndSendStatisticsMenu(session); - } - })); + .validResultHandler((form1, response1) -> buildAndSendStatisticsMenu(session))); })); } From 53de9f4a31cd52dea3c6526f799e41f96a4fcfa6 Mon Sep 17 00:00:00 2001 From: Tim203 Date: Wed, 26 Jan 2022 12:10:15 +0100 Subject: [PATCH 04/72] Deploy the Cumulus changes for Geyser so Floodgate can use them --- Jenkinsfile | 1 + ap/pom.xml | 4 ++-- api/base/pom.xml | 2 +- api/geyser/pom.xml | 4 ++-- api/pom.xml | 2 +- bootstrap/bungeecord/pom.xml | 4 ++-- bootstrap/pom.xml | 4 ++-- bootstrap/spigot/pom.xml | 4 ++-- bootstrap/sponge/pom.xml | 4 ++-- bootstrap/standalone/pom.xml | 4 ++-- bootstrap/velocity/pom.xml | 4 ++-- common/pom.xml | 2 +- core/pom.xml | 8 ++++---- .../protocol/java/JavaCustomPayloadTranslator.java | 2 +- pom.xml | 2 +- 15 files changed, 26 insertions(+), 25 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 481c02310..d1081b0d1 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -23,6 +23,7 @@ pipeline { stage ('Deploy') { when { branch "master" + branch "feature/cumulus-1.1" // allow Floodgate to build } steps { diff --git a/ap/pom.xml b/ap/pom.xml index cc282dd55..e14829ab1 100644 --- a/ap/pom.xml +++ b/ap/pom.xml @@ -6,9 +6,9 @@ org.geysermc geyser-parent - 2.0.0-SNAPSHOT + 2.0.1-cumulus-SNAPSHOT ap - 2.0.0-SNAPSHOT + 2.0.1-cumulus-SNAPSHOT \ No newline at end of file diff --git a/api/base/pom.xml b/api/base/pom.xml index 0d7ed05da..c584885ce 100644 --- a/api/base/pom.xml +++ b/api/base/pom.xml @@ -5,7 +5,7 @@ org.geysermc api-parent - 2.0.0-SNAPSHOT + 2.0.1-cumulus-SNAPSHOT 4.0.0 diff --git a/api/geyser/pom.xml b/api/geyser/pom.xml index 89349e8ac..7cee80208 100644 --- a/api/geyser/pom.xml +++ b/api/geyser/pom.xml @@ -5,7 +5,7 @@ org.geysermc api-parent - 2.0.0-SNAPSHOT + 2.0.1-cumulus-SNAPSHOT 4.0.0 @@ -26,7 +26,7 @@ org.geysermc base-api - 2.0.0-SNAPSHOT + 2.0.1-cumulus-SNAPSHOT compile diff --git a/api/pom.xml b/api/pom.xml index b3d0262ea..d79922690 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -6,7 +6,7 @@ org.geysermc geyser-parent - 2.0.0-SNAPSHOT + 2.0.1-cumulus-SNAPSHOT api-parent diff --git a/bootstrap/bungeecord/pom.xml b/bootstrap/bungeecord/pom.xml index 9dcd0943e..73cea9ec4 100644 --- a/bootstrap/bungeecord/pom.xml +++ b/bootstrap/bungeecord/pom.xml @@ -6,7 +6,7 @@ org.geysermc bootstrap-parent - 2.0.0-SNAPSHOT + 2.0.1-cumulus-SNAPSHOT bootstrap-bungeecord @@ -14,7 +14,7 @@ org.geysermc core - 2.0.0-SNAPSHOT + 2.0.1-cumulus-SNAPSHOT compile diff --git a/bootstrap/pom.xml b/bootstrap/pom.xml index 3b0bdda55..e4710e085 100644 --- a/bootstrap/pom.xml +++ b/bootstrap/pom.xml @@ -6,7 +6,7 @@ org.geysermc geyser-parent - 2.0.0-SNAPSHOT + 2.0.1-cumulus-SNAPSHOT bootstrap-parent pom @@ -34,7 +34,7 @@ org.geysermc ap - 2.0.0-SNAPSHOT + 2.0.1-cumulus-SNAPSHOT provided diff --git a/bootstrap/spigot/pom.xml b/bootstrap/spigot/pom.xml index 5aa2c59cf..7aca462c9 100644 --- a/bootstrap/spigot/pom.xml +++ b/bootstrap/spigot/pom.xml @@ -6,7 +6,7 @@ org.geysermc bootstrap-parent - 2.0.0-SNAPSHOT + 2.0.1-cumulus-SNAPSHOT bootstrap-spigot @@ -25,7 +25,7 @@ org.geysermc core - 2.0.0-SNAPSHOT + 2.0.1-cumulus-SNAPSHOT compile diff --git a/bootstrap/sponge/pom.xml b/bootstrap/sponge/pom.xml index fa7989b43..0587e811f 100644 --- a/bootstrap/sponge/pom.xml +++ b/bootstrap/sponge/pom.xml @@ -6,7 +6,7 @@ org.geysermc bootstrap-parent - 2.0.0-SNAPSHOT + 2.0.1-cumulus-SNAPSHOT bootstrap-sponge @@ -14,7 +14,7 @@ org.geysermc core - 2.0.0-SNAPSHOT + 2.0.1-cumulus-SNAPSHOT compile diff --git a/bootstrap/standalone/pom.xml b/bootstrap/standalone/pom.xml index 00c0410e4..cb6b01b6a 100644 --- a/bootstrap/standalone/pom.xml +++ b/bootstrap/standalone/pom.xml @@ -6,7 +6,7 @@ org.geysermc bootstrap-parent - 2.0.0-SNAPSHOT + 2.0.1-cumulus-SNAPSHOT bootstrap-standalone @@ -18,7 +18,7 @@ org.geysermc core - 2.0.0-SNAPSHOT + 2.0.1-cumulus-SNAPSHOT compile diff --git a/bootstrap/velocity/pom.xml b/bootstrap/velocity/pom.xml index e1e3331ef..87fa95637 100644 --- a/bootstrap/velocity/pom.xml +++ b/bootstrap/velocity/pom.xml @@ -6,7 +6,7 @@ org.geysermc bootstrap-parent - 2.0.0-SNAPSHOT + 2.0.1-cumulus-SNAPSHOT bootstrap-velocity @@ -14,7 +14,7 @@ org.geysermc core - 2.0.0-SNAPSHOT + 2.0.1-cumulus-SNAPSHOT compile diff --git a/common/pom.xml b/common/pom.xml index 54a65ab99..6c204aa9b 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -6,7 +6,7 @@ org.geysermc geyser-parent - 2.0.0-SNAPSHOT + 2.0.1-cumulus-SNAPSHOT common diff --git a/core/pom.xml b/core/pom.xml index 4da6bdbe0..121b58548 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -6,7 +6,7 @@ org.geysermc geyser-parent - 2.0.0-SNAPSHOT + 2.0.1-cumulus-SNAPSHOT core @@ -21,19 +21,19 @@ org.geysermc ap - 2.0.0-SNAPSHOT + 2.0.1-cumulus-SNAPSHOT provided org.geysermc geyser-api - 2.0.0-SNAPSHOT + 2.0.1-cumulus-SNAPSHOT compile org.geysermc common - 2.0.0-SNAPSHOT + 2.0.1-cumulus-SNAPSHOT compile 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 6a65d85f1..5713465eb 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 @@ -60,7 +60,7 @@ public class JavaCustomPayloadTranslator extends PacketTranslator4.0.0 org.geysermc geyser-parent - 2.0.0-SNAPSHOT + 2.0.1-cumulus-SNAPSHOT pom Geyser Allows for players from Minecraft Bedrock Edition to join Minecraft Java Edition servers. From 2573b47de963acd761ef3845c4dcd847276d2d5e Mon Sep 17 00:00:00 2001 From: Tim203 Date: Wed, 26 Jan 2022 12:20:29 +0100 Subject: [PATCH 05/72] Actually deploy --- Jenkinsfile | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index d1081b0d1..f1c8be56e 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -22,8 +22,10 @@ pipeline { stage ('Deploy') { when { - branch "master" - branch "feature/cumulus-1.1" // allow Floodgate to build + anyOf { + branch "master" + branch "feature/cumulus-1.1" // allow Floodgate to build + } } steps { From 05e98c3a103c5a28f6b29ac1e86c7d4f7cc7e632 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Wed, 4 May 2022 15:54:19 -0400 Subject: [PATCH 06/72] Fix edge case in health code since 1.18.30 Fixes #2957 --- .../entity/type/player/SessionPlayerEntity.java | 4 ++++ .../java/entity/player/JavaSetHealthTranslator.java | 13 +++++++++++++ 2 files changed, 17 insertions(+) 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 ae8d23810..6edcd60f3 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 @@ -134,6 +134,10 @@ public class SessionPlayerEntity extends PlayerEntity { return maxHealth; } + public float getHealth() { + return this.health; + } + public void setHealth(float health) { this.health = health; } 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 d989fe964..67047d00e 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 @@ -27,6 +27,7 @@ package org.geysermc.geyser.translator.protocol.java.entity.player; import com.github.steveice10.mc.protocol.packet.ingame.clientbound.entity.player.ClientboundSetHealthPacket; import com.nukkitx.protocol.bedrock.data.AttributeData; +import com.nukkitx.protocol.bedrock.packet.RespawnPacket; import com.nukkitx.protocol.bedrock.packet.UpdateAttributesPacket; import org.geysermc.geyser.entity.attribute.GeyserAttributeType; import org.geysermc.geyser.entity.type.player.SessionPlayerEntity; @@ -43,6 +44,18 @@ public class JavaSetHealthTranslator extends PacketTranslator 0f) { + // Needed as of 1.18.30 (tested with a totem of undying on SPIGOT 1.12.2 + // This shouldn't be triggered on a proper respawn because JavaSetHealthTranslator sets the health back to 20 + // https://github.com/GeyserMC/Geyser/issues/2957 + RespawnPacket respawnPacket = new RespawnPacket(); + respawnPacket.setRuntimeEntityId(0); + respawnPacket.setPosition(entity.getPosition()); + respawnPacket.setState(RespawnPacket.State.SERVER_READY); + session.sendUpstreamPacket(respawnPacket); + } + entity.setHealth(packet.getHealth()); UpdateAttributesPacket attributesPacket = new UpdateAttributesPacket(); From f38c1fbc0f663f82e0374198e42a7487cbb8eb5c Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Fri, 6 May 2022 15:32:43 -0400 Subject: [PATCH 07/72] Spigot: programmatically add Geyser permissions and fix reloading --- .../platform/spigot/GeyserSpigotPlugin.java | 37 +++++++++++++++++-- .../spigot/src/main/resources/plugin.yml | 31 ---------------- .../geyser/command/GeyserCommand.java | 9 +++++ .../geyser/command/defaults/DumpCommand.java | 5 +++ .../geyser/command/defaults/ListCommand.java | 5 +++ .../command/defaults/ReloadCommand.java | 5 +++ .../geyser/command/defaults/StopCommand.java | 5 +++ .../command/defaults/VersionCommand.java | 5 +++ 8 files changed, 67 insertions(+), 35 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 6e490bfca..4ece501c4 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 @@ -32,6 +32,8 @@ import com.viaversion.viaversion.api.protocol.version.ProtocolVersion; import me.lucko.commodore.CommodoreProvider; import org.bukkit.Bukkit; import org.bukkit.command.PluginCommand; +import org.bukkit.permissions.Permission; +import org.bukkit.permissions.PermissionDefault; import org.bukkit.plugin.java.JavaPlugin; import org.geysermc.common.PlatformType; import org.geysermc.geyser.Constants; @@ -39,6 +41,7 @@ import org.geysermc.geyser.GeyserBootstrap; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.adapters.spigot.SpigotAdapters; import org.geysermc.geyser.command.CommandManager; +import org.geysermc.geyser.command.GeyserCommand; import org.geysermc.geyser.configuration.GeyserConfiguration; import org.geysermc.geyser.dump.BootstrapDumpInfo; import org.geysermc.geyser.level.WorldManager; @@ -61,10 +64,16 @@ import java.io.IOException; import java.net.SocketAddress; import java.nio.file.Path; import java.util.List; +import java.util.Map; import java.util.UUID; import java.util.logging.Level; public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { + /** + * Determines if the plugin has been ran once before, including before /geyser reload. + */ + private static boolean INITIALIZED = false; + private GeyserSpigotCommandManager geyserCommandManager; private GeyserSpigotConfiguration geyserConfig; private GeyserSpigotInjector geyserInjector; @@ -232,14 +241,32 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { } geyserLogger.debug("Using default world manager: " + this.geyserWorldManager.getClass()); } - GeyserSpigotBlockPlaceListener blockPlaceListener = new GeyserSpigotBlockPlaceListener(geyser, this.geyserWorldManager); - Bukkit.getServer().getPluginManager().registerEvents(blockPlaceListener, this); - - Bukkit.getServer().getPluginManager().registerEvents(new GeyserPistonListener(geyser, this.geyserWorldManager), this); PluginCommand pluginCommand = this.getCommand("geyser"); pluginCommand.setExecutor(new GeyserSpigotCommandExecutor(geyser)); + if (!INITIALIZED) { + // Register permissions so they appear in, for example, LuckPerms' UI + // Re-registering permissions throws an error + for (Map.Entry entry : geyserCommandManager.getCommands().entrySet()) { + GeyserCommand command = entry.getValue(); + if (command.getAliases().contains(entry.getKey())) { + // Don't register aliases + continue; + } + + Bukkit.getPluginManager().addPermission(new Permission(command.getPermission(), + GeyserLocale.getLocaleStringLog(command.getDescription()), + command.isSuggestedOpOnly() ? PermissionDefault.OP : PermissionDefault.TRUE)); + } + + // Events cannot be unregistered - re-registering results in duplicate firings + GeyserSpigotBlockPlaceListener blockPlaceListener = new GeyserSpigotBlockPlaceListener(geyser, this.geyserWorldManager); + Bukkit.getServer().getPluginManager().registerEvents(blockPlaceListener, this); + + Bukkit.getServer().getPluginManager().registerEvents(new GeyserPistonListener(geyser, this.geyserWorldManager), this); + } + boolean brigadierSupported = CommodoreProvider.isSupported(); geyserLogger.debug("Brigadier supported? " + brigadierSupported); if (brigadierSupported) { @@ -248,6 +275,8 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { // Check to ensure the current setup can support the protocol version Geyser uses GeyserSpigotVersionChecker.checkForSupportedProtocol(geyserLogger, isViaVersion); + + INITIALIZED = true; } @Override diff --git a/bootstrap/spigot/src/main/resources/plugin.yml b/bootstrap/spigot/src/main/resources/plugin.yml index 18773402e..aa2747979 100644 --- a/bootstrap/spigot/src/main/resources/plugin.yml +++ b/bootstrap/spigot/src/main/resources/plugin.yml @@ -9,34 +9,3 @@ commands: geyser: description: The main command for Geyser. usage: /geyser -permissions: - geyser.command.help: - description: Shows help for all registered commands. - default: true - geyser.command.offhand: - description: Puts an items in your offhand. - default: true - geyser.command.advancements: - description: Shows the advancements of the player on the server. - default: true - geyser.command.tooltips: - description: Toggles showing advanced tooltips on your items. - default: true - geyser.command.statistics: - description: Shows the statistics of the player on the server. - default: true - geyser.command.settings: - description: Modify user settings - default: true - geyser.command.list: - description: List all players connected through Geyser. - default: op - geyser.command.dump: - description: Dumps Geyser debug information for bug reports. - default: op - geyser.command.reload: - description: Reloads the Geyser configurations. Kicks all players when used! - default: false - geyser.command.version: - description: Shows the current Geyser version and checks for updates. - default: op 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 20451b5e8..a22c69c04 100644 --- a/core/src/main/java/org/geysermc/geyser/command/GeyserCommand.java +++ b/core/src/main/java/org/geysermc/geyser/command/GeyserCommand.java @@ -86,4 +86,13 @@ public abstract class GeyserCommand { public boolean isBedrockOnly() { return false; } + + /** + * Used for permission defaults on server implementations. + * + * @return if this command is designated to be used only by server operators. + */ + public boolean isSuggestedOpOnly() { + return false; + } } \ No newline at end of file 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 bd98d2b31..0bac381ba 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 @@ -145,4 +145,9 @@ public class DumpCommand extends GeyserCommand { public List getSubCommands() { return Arrays.asList("offline", "full", "logs"); } + + @Override + public boolean isSuggestedOpOnly() { + return true; + } } 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 f1004c3fb..0a4cfa023 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 @@ -51,4 +51,9 @@ public class ListCommand extends GeyserCommand { sender.sendMessage(message); } + + @Override + public boolean isSuggestedOpOnly() { + 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 b6a728382..e970e5d3d 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 @@ -54,4 +54,9 @@ public class ReloadCommand extends GeyserCommand { geyser.getSessionManager().disconnectAll("geyser.commands.reload.kick"); geyser.reload(); } + + @Override + public boolean isSuggestedOpOnly() { + return true; + } } 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 903e3bf4b..9c7bd8140 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 @@ -54,4 +54,9 @@ public class StopCommand extends GeyserCommand { geyser.getBootstrap().onDisable(); } + + @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 6ec816b12..f4f62892a 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 @@ -100,4 +100,9 @@ public class VersionCommand extends GeyserCommand { } } } + + @Override + public boolean isSuggestedOpOnly() { + return true; + } } From db13b4c276f7be829af85ba66e0dc07486696247 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Tue, 10 May 2022 12:40:15 -0400 Subject: [PATCH 08/72] Fix decoding for some UTF-8 characters --- core/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/pom.xml b/core/pom.xml index adc841ebe..8af2aa907 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -121,7 +121,7 @@ com.github.CloudburstMC.Protocol bedrock-v503 - 2a344e4 + 297567d compile From b33cc512b480901c205aa4b1f4d216ea5156a22a Mon Sep 17 00:00:00 2001 From: David Choo Date: Sat, 14 May 2022 15:12:18 -0400 Subject: [PATCH 09/72] Add custom skull render distance (#2751) * Add player skull render distance * Improve updateVisibleSkulls a bit Avoid rechecking visibility on small movements * Periodically despawn unused skull entities * Don't hide skull entity for position/rotation changes Prevents flickering for skulls that are rotating * Update visible skulls when a skull is removed * Only update on removal if an entity is assigned * No need to check for skull in ChunkUtils Update copyright year * Avoid rechecking all skulls when a skull is added/removed * Allow skull render distance and number to be configured Renamed some fields to better match their values * Compare texture property directly from GameProfile * Remove unnecessary blockState field from SkullPlayerEntity * Use binarySearch for insertion Wait for player movement before loading skulls * Allow culling to be disabled by setting max-visible-custom-skulls to -1 * Only remove skulls in inRangeSkulls when culling is enabled * Add suggestions from review * Merge the for loops in updateVisibleSkulls * Fix skulls being leaked on chunk unload --- .../configuration/GeyserConfiguration.java | 4 + .../GeyserJacksonConfiguration.java | 6 + .../entity/type/player/SkullPlayerEntity.java | 72 ++++-- .../geyser/session/GeyserSession.java | 3 +- .../geyser/session/cache/SkullCache.java | 211 ++++++++++++++++++ .../entity/SkullBlockEntityTranslator.java | 58 +---- .../player/BedrockMovePlayerTranslator.java | 2 + .../level/JavaBlockEntityDataTranslator.java | 2 +- .../level/JavaForgetLevelChunkTranslator.java | 15 +- .../JavaLevelChunkWithLightTranslator.java | 2 +- .../org/geysermc/geyser/util/ChunkUtils.java | 6 +- core/src/main/resources/config.yml | 7 + 12 files changed, 306 insertions(+), 82 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/session/cache/SkullCache.java 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 7bb73a648..1f188cf40 100644 --- a/core/src/main/java/org/geysermc/geyser/configuration/GeyserConfiguration.java +++ b/core/src/main/java/org/geysermc/geyser/configuration/GeyserConfiguration.java @@ -101,6 +101,10 @@ public interface GeyserConfiguration { boolean isAllowCustomSkulls(); + int getMaxVisibleCustomSkulls(); + + int getCustomSkullRenderDistance(); + IMetricsInfo getMetrics(); int getPendingAuthenticationTimeout(); 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 03a3617e3..30a947e53 100644 --- a/core/src/main/java/org/geysermc/geyser/configuration/GeyserJacksonConfiguration.java +++ b/core/src/main/java/org/geysermc/geyser/configuration/GeyserJacksonConfiguration.java @@ -130,6 +130,12 @@ public abstract class GeyserJacksonConfiguration implements GeyserConfiguration @JsonProperty("allow-custom-skulls") private boolean allowCustomSkulls = true; + @JsonProperty("max-visible-custom-skulls") + private int maxVisibleCustomSkulls = 128; + + @JsonProperty("custom-skull-render-distance") + private int customSkullRenderDistance = 32; + @JsonProperty("add-non-bedrock-items") private boolean addNonBedrockItems = true; 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 f1a447b57..6c15a4d3e 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 @@ -26,33 +26,28 @@ package org.geysermc.geyser.entity.type.player; import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.math.vector.Vector3i; import com.nukkitx.protocol.bedrock.data.GameType; import com.nukkitx.protocol.bedrock.data.PlayerPermission; import com.nukkitx.protocol.bedrock.data.command.CommandPermission; import com.nukkitx.protocol.bedrock.data.entity.EntityData; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import com.nukkitx.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; +import org.geysermc.geyser.skin.SkullSkinManager; import java.util.UUID; +import java.util.concurrent.TimeUnit; /** * A wrapper to handle skulls more effectively - skulls have to be treated as entities since there are no * custom player skulls in Bedrock. */ public class SkullPlayerEntity extends PlayerEntity { - /** - * Stores the block state that the skull is associated with. Used to determine if the block in the skull's position - * has changed - */ - @Getter - private final int blockState; - public SkullPlayerEntity(GeyserSession session, long geyserId, Vector3f position, float rotation, int blockState, String texturesProperty) { - super(session, 0, geyserId, UUID.randomUUID(), position, Vector3f.ZERO, rotation, 0, rotation, "", texturesProperty); - this.blockState = blockState; + public SkullPlayerEntity(GeyserSession session, long geyserId) { + super(session, 0, geyserId, UUID.randomUUID(), Vector3f.ZERO, Vector3f.ZERO, 0, 0, 0, "", null); setPlayerList(false); } @@ -95,8 +90,57 @@ public class SkullPlayerEntity extends PlayerEntity { session.sendUpstreamPacket(addPlayerPacket); } - public void despawnEntity(Vector3i position) { - this.despawnEntity(); - session.getSkullCache().remove(position, this); + /** + * 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) { + if (!skull.getTexturesProperty().equals(getTexturesProperty())) { + // Make skull invisible as we change skins + setFlag(EntityFlag.INVISIBLE, true); + updateBedrockMetadata(); + + setTexturesProperty(skull.getTexturesProperty()); + + SkullSkinManager.requestAndHandleSkin(this, session, (skin -> session.scheduleInEventLoop(() -> { + // Delay to minimize split-second "player" pop-in + setFlag(EntityFlag.INVISIBLE, false); + updateBedrockMetadata(); + }, 250, TimeUnit.MILLISECONDS))); + } else { + // Just a rotation/position change + setFlag(EntityFlag.INVISIBLE, false); + updateBedrockMetadata(); + } + + float x = skull.getPosition().getX() + .5f; + float y = skull.getPosition().getY() - .01f; + float z = skull.getPosition().getZ() + .5f; + float rotation; + + int blockState = skull.getBlockState(); + byte floorRotation = BlockStateValues.getSkullRotation(blockState); + if (floorRotation == -1) { + // Wall skull + 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 + } + } else { + rotation = (180f + (floorRotation * 22.5f)) % 360; + } + + moveAbsolute(Vector3f.from(x, y, z), rotation, 0, rotation, true, 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 72eaaf0f7..5f264329e 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 @@ public class GeyserSession implements GeyserConnection, CommandSender { private final LodestoneCache lodestoneCache; private final PistonCache pistonCache; private final PreferencesCache preferencesCache; + private final SkullCache skullCache; private final TagCache tagCache; private final WorldCache worldCache; @@ -220,7 +221,6 @@ public class GeyserSession implements GeyserConnection, CommandSender { @Setter private ItemMappings itemMappings; - private final Map skullCache = new Object2ObjectOpenHashMap<>(); private final Long2ObjectMap storedMaps = new Long2ObjectOpenHashMap<>(); /** @@ -530,6 +530,7 @@ public class GeyserSession implements GeyserConnection, CommandSender { this.lodestoneCache = new LodestoneCache(); this.pistonCache = new PistonCache(this); this.preferencesCache = new PreferencesCache(this); + this.skullCache = new SkullCache(this); this.tagCache = new TagCache(); this.worldCache = new WorldCache(this); 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 new file mode 100644 index 000000000..f26e1cce3 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/session/cache/SkullCache.java @@ -0,0 +1,211 @@ +/* + * 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.session.cache; + +import com.nukkitx.math.vector.Vector3f; +import com.nukkitx.math.vector.Vector3i; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import lombok.Data; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.geysermc.geyser.entity.type.player.SkullPlayerEntity; +import org.geysermc.geyser.session.GeyserSession; + +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; + + private Vector3f lastPlayerPosition; + + private long lastCleanup = System.currentTimeMillis(); + + public SkullCache(GeyserSession session) { + this.session = session; + this.maxVisibleSkulls = session.getGeyser().getConfig().getMaxVisibleCustomSkulls(); + this.cullingEnabled = this.maxVisibleSkulls != -1; + + // Normal skulls are not rendered beyond 64 blocks + int distance = Math.min(session.getGeyser().getConfig().getCustomSkullRenderDistance(), 64); + this.skullRenderDistanceSquared = distance * distance; + } + + public void putSkull(Vector3i position, String texturesProperty, int blockState) { + Skull skull = skulls.computeIfAbsent(position, Skull::new); + skull.texturesProperty = texturesProperty; + skull.blockState = blockState; + + if (skull.entity != null) { + skull.entity.updateSkull(skull); + } else { + if (!cullingEnabled) { + assignSkullEntity(skull); + return; + } + if (lastPlayerPosition == null) { + return; + } + skull.distanceSquared = position.distanceSquared(lastPlayerPosition.getX(), lastPlayerPosition.getY(), lastPlayerPosition.getZ()); + if (skull.distanceSquared < skullRenderDistanceSquared) { + // Keep list in order + int i = Collections.binarySearch(inRangeSkulls, skull, Comparator.comparingInt(Skull::getDistanceSquared)); + if (i < 0) { // skull.distanceSquared is a new distance value + i = -i - 1; + } + inRangeSkulls.add(i, skull); + + if (i < maxVisibleSkulls) { + // Reassign entity from the farthest skull to this one + if (inRangeSkulls.size() > maxVisibleSkulls) { + freeSkullEntity(inRangeSkulls.get(maxVisibleSkulls)); + } + assignSkullEntity(skull); + } + } + } + } + + public void removeSkull(Vector3i position) { + Skull skull = skulls.remove(position); + if (skull != null) { + boolean hadEntity = skull.entity != null; + freeSkullEntity(skull); + + if (cullingEnabled) { + inRangeSkulls.remove(skull); + if (hadEntity && inRangeSkulls.size() >= maxVisibleSkulls) { + // Reassign entity to the closest skull without an entity + assignSkullEntity(inRangeSkulls.get(maxVisibleSkulls - 1)); + } + } + } + } + + public void updateVisibleSkulls() { + if (cullingEnabled) { + // No need to recheck skull visibility for small movements + if (lastPlayerPosition != null && session.getPlayerEntity().getPosition().distanceSquared(lastPlayerPosition) < 4) { + return; + } + lastPlayerPosition = session.getPlayerEntity().getPosition(); + + inRangeSkulls.clear(); + for (Skull skull : skulls.values()) { + skull.distanceSquared = skull.position.distanceSquared(lastPlayerPosition.getX(), lastPlayerPosition.getY(), lastPlayerPosition.getZ()); + if (skull.distanceSquared > skullRenderDistanceSquared) { + freeSkullEntity(skull); + } else { + inRangeSkulls.add(skull); + } + } + inRangeSkulls.sort(Comparator.comparingInt(Skull::getDistanceSquared)); + + for (int i = inRangeSkulls.size() - 1; i >= 0; i--) { + if (i < maxVisibleSkulls) { + assignSkullEntity(inRangeSkulls.get(i)); + } else { + freeSkullEntity(inRangeSkulls.get(i)); + } + } + } + + // 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(); + skull.entity.updateSkull(skull); + } + } + + private void freeSkullEntity(Skull skull) { + if (skull.entity != null) { + skull.entity.free(); + unusedSkullEntities.addFirst(skull.entity); + skull.entity = null; + } + } + + public void clear() { + skulls.clear(); + inRangeSkulls.clear(); + unusedSkullEntities.clear(); + totalSkullEntities = 0; + lastPlayerPosition = null; + } + + @RequiredArgsConstructor + @Data + public static class Skull { + private String texturesProperty; + private int blockState; + private SkullPlayerEntity entity; + + private final Vector3i position; + private int distanceSquared; + } +} 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 50d79c10f..94e2d4767 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 @@ -29,19 +29,14 @@ 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.nukkitx.math.vector.Vector3f; import com.nukkitx.math.vector.Vector3i; import com.nukkitx.nbt.NbtMapBuilder; -import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; -import org.geysermc.geyser.entity.type.player.SkullPlayerEntity; import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.skin.SkinProvider; -import org.geysermc.geyser.skin.SkullSkinManager; import java.util.LinkedHashMap; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.TimeUnit; @BlockEntity(type = BlockEntityType.SKULL) public class SkullBlockEntityTranslator extends BlockEntityTranslator implements RequiresBlockState { @@ -74,65 +69,18 @@ public class SkullBlockEntityTranslator extends BlockEntityTranslator implements return CompletableFuture.completedFuture(null); } - public static void spawnPlayer(GeyserSession session, CompoundTag tag, int posX, int posY, int posZ, int blockState) { - float x = posX + .5f; - float y = posY - .01f; - float z = posZ + .5f; - float rotation; - - byte floorRotation = BlockStateValues.getSkullRotation(blockState); - if (floorRotation == -1) { - // Wall skull - 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 - } - } else { - rotation = (180f + (floorRotation * 22.5f)) % 360; - } - + public static void translateSkull(GeyserSession session, CompoundTag tag, int posX, int posY, int posZ, int blockState) { Vector3i blockPosition = Vector3i.from(posX, posY, posZ); - Vector3f entityPosition = Vector3f.from(x, y, z); - getTextures(tag).whenComplete((texturesProperty, throwable) -> { if (texturesProperty == null) { session.getGeyser().getLogger().debug("Custom skull with invalid SkullOwner tag: " + blockPosition + " " + tag); return; } - if (session.getEventLoop().inEventLoop()) { - spawnPlayer(session, texturesProperty, blockPosition, entityPosition, rotation, blockState); + session.getSkullCache().putSkull(blockPosition, texturesProperty, blockState); } else { - session.executeInEventLoop(() -> spawnPlayer(session, texturesProperty, blockPosition, entityPosition, rotation, blockState)); + session.executeInEventLoop(() -> session.getSkullCache().putSkull(blockPosition, texturesProperty, blockState)); } }); } - - private static void spawnPlayer(GeyserSession session, String texturesProperty, Vector3i blockPosition, - Vector3f entityPosition, float rotation, int blockState) { - long geyserId = session.getEntityCache().getNextEntityId().incrementAndGet(); - - SkullPlayerEntity existingSkull = session.getSkullCache().get(blockPosition); - if (existingSkull != null) { - // Ensure that two skulls can't spawn on the same point - existingSkull.despawnEntity(blockPosition); - } - - SkullPlayerEntity player = new SkullPlayerEntity(session, geyserId, entityPosition, rotation, blockState, texturesProperty); - - // Cache entity - session.getSkullCache().put(blockPosition, player); - - player.spawnEntity(); - - SkullSkinManager.requestAndHandleSkin(player, session, (skin -> session.scheduleInEventLoop(() -> { - // Delay to minimize split-second "player" pop-in - player.setFlag(EntityFlag.INVISIBLE, false); - player.updateBedrockMetadata(); - }, 250, TimeUnit.MILLISECONDS))); - } } 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 8732b7909..0d3ef4cbc 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 @@ -140,6 +140,8 @@ public class BedrockMovePlayerTranslator extends PacketTranslator { @@ -41,19 +43,18 @@ public class JavaForgetLevelChunkTranslator extends PacketTranslator iterator = session.getSkullCache().keySet().iterator(); - while (iterator.hasNext()) { - Vector3i position = iterator.next(); + // Checks if a skull is in an unloaded chunk then removes it + List removedSkulls = new ArrayList<>(); + for (Vector3i position : session.getSkullCache().getSkulls().keySet()) { if ((position.getX() >> 4) == packet.getX() && (position.getZ() >> 4) == packet.getZ()) { - session.getSkullCache().get(position).despawnEntity(); - iterator.remove(); + removedSkulls.add(position); } } + removedSkulls.forEach(session.getSkullCache()::removeSkull); if (!session.getGeyser().getWorldManager().shouldExpectLecternHandled()) { // Do the same thing with lecterns - iterator = session.getLecternCache().iterator(); + Iterator iterator = session.getLecternCache().iterator(); while (iterator.hasNext()) { Vector3i position = iterator.next(); if ((position.getX() >> 4) == packet.getX() && (position.getZ() >> 4) == packet.getZ()) { 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 3855b1139..47ba98274 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 @@ -275,7 +275,7 @@ public class JavaLevelChunkWithLightTranslator extends PacketTranslator Date: Sun, 15 May 2022 13:52:18 -0400 Subject: [PATCH 10/72] Always show the world border at least five blocks away Previously, no indication that the world border exists would show if warning blocks was set to 0. --- .../geyser/session/GeyserSession.java | 14 ++++++++----- .../geyser/session/cache/WorldBorder.java | 20 +++++++++++++++---- 2 files changed, 25 insertions(+), 9 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 5f264329e..0daa43da8 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -69,7 +69,10 @@ import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import com.nukkitx.protocol.bedrock.packet.*; import io.netty.channel.Channel; import io.netty.channel.EventLoop; -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.longs.Long2ObjectMap; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; @@ -94,7 +97,6 @@ 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.type.player.SkullPlayerEntity; import org.geysermc.geyser.inventory.Inventory; import org.geysermc.geyser.inventory.PlayerInventory; import org.geysermc.geyser.inventory.recipe.GeyserRecipe; @@ -1092,15 +1094,17 @@ public class GeyserSession implements GeyserConnection, CommandSender { worldBorder.resize(); } - if (!worldBorder.isWithinWarningBoundaries()) { + boolean shouldShowFog = !worldBorder.isWithinWarningBoundaries(); + if (shouldShowFog || worldBorder.isCloseToBorderBoundaries()) { // Show particles representing where the world border is worldBorder.drawWall(); // Set the mood - if (!isInWorldBorderWarningArea) { + if (shouldShowFog && !isInWorldBorderWarningArea) { isInWorldBorderWarningArea = true; sendFog("minecraft:fog_crimson_forest"); } - } else if (isInWorldBorderWarningArea) { + } + if (!shouldShowFog && isInWorldBorderWarningArea) { // Clear fog as we are outside the world border now removeFog("minecraft:fog_crimson_forest"); isInWorldBorderWarningArea = false; 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 66922ff0b..09e7e9234 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 @@ -139,6 +139,18 @@ public class WorldBorder { return position.getX() > minX && position.getX() < maxX && position.getZ() > minZ && position.getZ() < maxZ; } + private static final int CLOSE_TO_BORDER = 5; + + /** + * @return if the player is close to the border boundaries. Used to always indicate a border even if there is no + * warning blocks set. + */ + public boolean isCloseToBorderBoundaries() { + Vector3f position = session.getPlayerEntity().getPosition(); + return !(position.getX() > minX + CLOSE_TO_BORDER && position.getX() < maxX - CLOSE_TO_BORDER + && position.getZ() > minZ + CLOSE_TO_BORDER && position.getZ() < maxZ - CLOSE_TO_BORDER); + } + /** * Confirms that the entity is within world border boundaries when they move. * Otherwise, if {@code adjustPosition} is true, this function will push the player back. @@ -246,16 +258,16 @@ public class WorldBorder { float particlePosY = entityPosition.getY(); float particlePosZ = entityPosition.getZ(); - if (entityPosition.getX() > warningMaxX) { + if (entityPosition.getX() > Math.min(warningMaxX, maxX - CLOSE_TO_BORDER)) { drawWall(Vector3f.from(maxX, particlePosY, particlePosZ), true); } - if (entityPosition.getX() < warningMinX) { + if (entityPosition.getX() < Math.max(warningMinX, minX + CLOSE_TO_BORDER)) { drawWall(Vector3f.from(minX, particlePosY, particlePosZ), true); } - if (entityPosition.getZ() > warningMaxZ) { + if (entityPosition.getZ() > Math.min(warningMaxZ, maxZ - CLOSE_TO_BORDER)) { drawWall(Vector3f.from(particlePosX, particlePosY, maxZ), false); } - if (entityPosition.getZ() < warningMinZ) { + if (entityPosition.getZ() < Math.max(warningMinZ, minZ + CLOSE_TO_BORDER)) { drawWall(Vector3f.from(particlePosX, particlePosY, minZ), false); } } From 8c9d1fe09f7d7eff90b12619df140177e980650c Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sun, 15 May 2022 14:23:52 -0400 Subject: [PATCH 11/72] Allow language file overrides By placing a locale file in `languages/ll_CC.properties`, any strings in that file will take priority over Geyser's own. --- .gitignore | 3 +- .../geysermc/geyser/text/GeyserLocale.java | 43 ++++++++++++++++--- 2 files changed, 38 insertions(+), 8 deletions(-) diff --git a/.gitignore b/.gitignore index 401002e1d..f1baa3abb 100644 --- a/.gitignore +++ b/.gitignore @@ -244,4 +244,5 @@ locales/ /cache/ /packs/ /dump.json -/saved-refresh-tokens.json \ No newline at end of file +/saved-refresh-tokens.json +/languages/ \ No newline at end of file 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 da6ea4dc0..86e015c0f 100644 --- a/core/src/main/java/org/geysermc/geyser/text/GeyserLocale.java +++ b/core/src/main/java/org/geysermc/geyser/text/GeyserLocale.java @@ -28,10 +28,10 @@ package org.geysermc.geyser.text; import org.geysermc.geyser.GeyserBootstrap; import org.geysermc.geyser.GeyserImpl; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; +import java.io.*; import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; import java.text.MessageFormat; import java.util.HashMap; import java.util.Locale; @@ -116,12 +116,22 @@ public class GeyserLocale { return locale; } + Properties localeProp = new Properties(); + + File localLanguage; + Path localFolder = bootstrap.getConfigFolder().resolve("languages"); + if (Files.exists(localFolder)) { + localLanguage = localFolder.resolve(locale + ".properties").toFile(); + } else { + localLanguage = null; + } + boolean validLocalLanguage = localLanguage != null && localLanguage.exists(); + InputStream localeStream = bootstrap.getResourceOrNull("languages/texts/" + locale + ".properties"); // Load the locale if (localeStream != null) { try { - Properties localeProp = new Properties(); try (InputStreamReader reader = new InputStreamReader(localeStream, StandardCharsets.UTF_8)) { localeProp.load(reader); } catch (Exception e) { @@ -130,18 +140,37 @@ public class GeyserLocale { // Insert the locale into the mappings LOCALE_MAPPINGS.put(locale, localeProp); - return locale; } finally { try { localeStream.close(); } catch (IOException ignored) {} } } else { - if (GeyserImpl.getInstance() != null) { + if (GeyserImpl.getInstance() != null && !validLocalLanguage) { + // Don't warn on missing locales if a local file has been found GeyserImpl.getInstance().getLogger().warning("Missing locale: " + locale); } - return null; } + + // Load any language overrides that exist after, to override any strings that we just added + // By loading both, we ensure that if a language string doesn't exist in the custom properties folder, + // it's loaded from our jar + if (validLocalLanguage) { + try (InputStream stream = new FileInputStream(localLanguage)) { + 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(); + } + } + + LOCALE_MAPPINGS.putIfAbsent(locale, localeProp); + } + return localeProp.isEmpty() ? null : locale; } /** From c3c8161a43b8c4ce77a535e14a73060904ebb289 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 21 May 2022 16:28:36 +0100 Subject: [PATCH 12/72] Bump gson from 2.8.6 to 2.8.9 in /common (#2982) Bumps [gson](https://github.com/google/gson) from 2.8.6 to 2.8.9. - [Release notes](https://github.com/google/gson/releases) - [Changelog](https://github.com/google/gson/blob/master/CHANGELOG.md) - [Commits](https://github.com/google/gson/compare/gson-parent-2.8.6...gson-parent-2.8.9) --- updated-dependencies: - dependency-name: com.google.code.gson:gson dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- common/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/pom.xml b/common/pom.xml index b3903f412..0786f3f4d 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -25,7 +25,7 @@ com.google.code.gson gson - 2.8.6 + 2.8.9 \ No newline at end of file From 38625312a167c1c419166a3327f771f84cb74fca Mon Sep 17 00:00:00 2001 From: David Choo Date: Sat, 21 May 2022 11:54:32 -0400 Subject: [PATCH 13/72] Prevent max health from being set below 0 (#2980) * Prevent max health from being set below 0 * Add more detail to comment --- .../java/org/geysermc/geyser/entity/type/LivingEntity.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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 0cce0f8df..87b709309 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 @@ -300,7 +300,9 @@ public class LivingEntity extends Entity { if (javaAttribute.getType() instanceof AttributeType.Builtin type) { switch (type) { case GENERIC_MAX_HEALTH -> { - this.maxHealth = (float) AttributeUtils.calculateValue(javaAttribute); + // 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_ATTACK_DAMAGE -> newAttributes.add(calculateAttribute(javaAttribute, GeyserAttributeType.ATTACK_DAMAGE)); From 5339127105eb531f1376963811f535b2c17e4f50 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Tue, 24 May 2022 16:16:40 -0700 Subject: [PATCH 14/72] Start work on 1.19 --- core/pom.xml | 6 +- .../geysermc/geyser/FloodgateKeyLoader.java | 4 +- .../java/org/geysermc/geyser/GeyserImpl.java | 39 ++++++++----- .../entity/type/FallingBlockEntity.java | 4 +- .../geyser/entity/type/FishingHookEntity.java | 2 +- .../geyser/entity/type/ItemFrameEntity.java | 4 +- .../geyser/entity/type/PaintingEntity.java | 1 + .../geysermc/geyser/level/JavaDimension.java | 42 ++++++++++++++ .../geyser/session/GeyserSession.java | 13 ++--- .../protocol/java/JavaLoginTranslator.java | 30 +++++----- ...tor.java => JavaSystemChatTranslator.java} | 13 +++-- .../player/JavaBlockBreakAckTranslator.java | 24 ++------ .../entity/spawn/JavaAddEntityTranslator.java | 9 +-- .../entity/spawn/JavaAddMobTranslator.java | 57 ------------------- .../spawn/JavaAddPaintingTranslator.java | 49 ---------------- 15 files changed, 117 insertions(+), 180 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/level/JavaDimension.java rename core/src/main/java/org/geysermc/geyser/translator/protocol/java/{JavaChatTranslator.java => JavaSystemChatTranslator.java} (84%) delete mode 100644 core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/spawn/JavaAddMobTranslator.java delete mode 100644 core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/spawn/JavaAddPaintingTranslator.java diff --git a/core/pom.xml b/core/pom.xml index 8af2aa907..c9047ee4b 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -153,9 +153,9 @@ compile - com.github.GeyserMC - MCProtocolLib - 0771504 + com.github.steveice10 + mcprotocollib + 1.19-SNAPSHOT compile diff --git a/core/src/main/java/org/geysermc/geyser/FloodgateKeyLoader.java b/core/src/main/java/org/geysermc/geyser/FloodgateKeyLoader.java index 6d47c38c6..0aa1d39c3 100644 --- a/core/src/main/java/org/geysermc/geyser/FloodgateKeyLoader.java +++ b/core/src/main/java/org/geysermc/geyser/FloodgateKeyLoader.java @@ -43,7 +43,7 @@ public class FloodgateKeyLoader { if (floodgateDataFolder != null) { Path autoKey = floodgateDataFolder.resolve("key.pem"); if (Files.exists(autoKey)) { - logger.info(GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.auto_loaded")); + logger.debug(GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.auto_loaded")); return autoKey; } else { logger.error(GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.missing_key")); @@ -52,7 +52,7 @@ public class FloodgateKeyLoader { Path floodgateKey; if (config.getFloodgateKeyFile().equals("public-key.pem")) { - logger.info("Floodgate 2.0 doesn't use a public/private key system anymore. We'll search for key.pem instead"); + logger.debug("Floodgate 2.0 doesn't use a public/private key system anymore. We'll search for key.pem instead"); floodgateKey = geyserDataFolder.resolve("key.pem"); } else { floodgateKey = geyserDataFolder.resolve(config.getFloodgateKeyFile()); diff --git a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java index f3ebfa4a3..c84e62121 100644 --- a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java +++ b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java @@ -66,6 +66,7 @@ import org.geysermc.geyser.session.SessionManager; import org.geysermc.geyser.session.auth.AuthType; import org.geysermc.geyser.skin.FloodgateSkinUploader; import org.geysermc.geyser.skin.SkinProvider; +import org.geysermc.geyser.text.ChatColor; import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.text.MinecraftLocale; import org.geysermc.geyser.translator.inventory.item.ItemTranslator; @@ -249,18 +250,6 @@ public class GeyserImpl implements GeyserApi { // Ensure that PacketLib does not create an event loop for handling packets; we'll do that ourselves TcpSession.USE_EVENT_LOOP_FOR_PACKETS = false; - if (config.getRemote().getAuthType() == AuthType.FLOODGATE) { - try { - Key key = new AesKeyProducer().produceFrom(config.getFloodgateKeyPath()); - cipher = new AesCipher(new Base64Topping()); - cipher.init(key); - logger.info(GeyserLocale.getLocaleStringLog("geyser.auth.floodgate.loaded_key")); - skinUploader = new FloodgateSkinUploader(this).start(); - } catch (Exception exception) { - logger.severe(GeyserLocale.getLocaleStringLog("geyser.auth.floodgate.bad_key"), exception); - } - } - String branch = "unknown"; int buildNumber = -1; if (this.productionEnvironment()) { @@ -321,14 +310,34 @@ public class GeyserImpl implements GeyserApi { if (shouldStartListener) { bedrockServer.bind().whenComplete((avoid, throwable) -> { if (throwable == null) { - logger.info(GeyserLocale.getLocaleStringLog("geyser.core.start", config.getBedrock().getAddress(), String.valueOf(config.getBedrock().getPort()))); + logger.info(GeyserLocale.getLocaleStringLog("geyser.core.start", config.getBedrock().getAddress(), + String.valueOf(config.getBedrock().getPort()))); } else { - logger.severe(GeyserLocale.getLocaleStringLog("geyser.core.fail", config.getBedrock().getAddress(), String.valueOf(config.getBedrock().getPort()))); - throwable.printStackTrace(); + String address = config.getBedrock().getAddress(); + int port = config.getBedrock().getPort(); + logger.severe(GeyserLocale.getLocaleStringLog("geyser.core.fail", address, String.valueOf(port))); + if (!"0.0.0.0".equals(address)) { + logger.info(ChatColor.GREEN + "Suggestion: try setting `address` under `bedrock` in the Geyser config back to 0.0.0.0"); + logger.info(ChatColor.GREEN + "Then, restart this server."); + } } }).join(); } + if (config.getRemote().getAuthType() == AuthType.FLOODGATE) { + try { + Key key = new AesKeyProducer().produceFrom(config.getFloodgateKeyPath()); + cipher = new AesCipher(new Base64Topping()); + cipher.init(key); + logger.debug(GeyserLocale.getLocaleStringLog("geyser.auth.floodgate.loaded_key")); + // Note: this is positioned after the bind so the skin uploader doesn't try to run if Geyser fails + // to load successfully. Spigot complains about class loader if the plugin is disabled. + skinUploader = new FloodgateSkinUploader(this).start(); + } catch (Exception exception) { + logger.severe(GeyserLocale.getLocaleStringLog("geyser.auth.floodgate.bad_key"), exception); + } + } + if (config.getMetrics().isEnabled()) { metrics = new Metrics(this, "GeyserMC", config.getMetrics().getUniqueId(), false, java.util.logging.Logger.getLogger("")); metrics.addCustomChart(new Metrics.SingleLineChart("players", sessionManager::size)); 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 ceb3ea15c..3e64cfcea 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 @@ -36,8 +36,8 @@ import java.util.UUID; public class FallingBlockEntity extends Entity { - public FallingBlockEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, Vector3f position, Vector3f motion, float yaw, float pitch, int javaId) { - super(session, entityId, geyserId, uuid, EntityDefinitions.FALLING_BLOCK, position, motion, yaw, pitch, 0f); + public FallingBlockEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw, int javaId) { + super(session, entityId, geyserId, uuid, EntityDefinitions.FALLING_BLOCK, position, motion, yaw, pitch, headYaw); this.dirtyMetadata.put(EntityData.VARIANT, session.getBlockMappings().getBedrockBlockId(javaId)); } 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 52ad82370..57b597781 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 @@ -56,7 +56,7 @@ public class FishingHookEntity extends ThrowableEntity { private final BoundingBox boundingBox; - public FishingHookEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, Vector3f position, Vector3f motion, float yaw, float pitch, PlayerEntity owner) { + public FishingHookEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw, PlayerEntity owner) { super(session, entityId, geyserId, uuid, EntityDefinitions.FISHING_BOBBER, position, motion, yaw, pitch, 0f); this.boundingBox = new BoundingBox(0.125, 0.125, 0.125, 0.25, 0.25, 0.25); 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 9cfa22a1f..bc7736e9b 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 @@ -79,8 +79,8 @@ public class ItemFrameEntity extends Entity { */ private boolean changed = true; - public ItemFrameEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, Direction direction) { - super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, 0f); + public ItemFrameEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw, Direction direction) { + super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw); NbtMapBuilder blockBuilder = NbtMap.builder() .putString("name", this.definition.entityType() == EntityType.GLOW_ITEM_FRAME ? "minecraft:glow_frame" : "minecraft:frame") 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 70b5d52ba..9a2bbd5a4 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 @@ -33,6 +33,7 @@ import org.geysermc.geyser.level.PaintingType; import java.util.UUID; +// TODO 1.19 public class PaintingEntity extends Entity { private static final double OFFSET = -0.46875; private final PaintingType paintingName; diff --git a/core/src/main/java/org/geysermc/geyser/level/JavaDimension.java b/core/src/main/java/org/geysermc/geyser/level/JavaDimension.java new file mode 100644 index 000000000..b297739a9 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/level/JavaDimension.java @@ -0,0 +1,42 @@ +/* + * 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; + +import com.github.steveice10.opennbt.tag.builtin.CompoundTag; + +/** + * 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) { + + public static JavaDimension load(CompoundTag tag) { +// int minY = ((IntTag) dimensionTag.get("min_y")).getValue(); +// int maxY = ((IntTag) dimensionTag.get("height")).getValue(); + return new JavaDimension(0, 0, 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 0daa43da8..607c9f84d 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -101,6 +101,7 @@ 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.GeyserStonecutterData; +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; @@ -319,11 +320,9 @@ public class GeyserSession implements GeyserConnection, CommandSender { @Setter private String dimension = DimensionUtils.OVERWORLD; /** - * Whether piglins and hoglins are safe from conversion in this dimension. - * This controls if they have the shaking effect applied in the dimension. + * All dimensions that the client could possibly connect to. */ - @Setter - private boolean dimensionPiglinSafe; + private final Map dimensions = new Object2ObjectOpenHashMap<>(3); @Setter private int breakingBlock; @@ -1261,9 +1260,9 @@ public class GeyserSession implements GeyserConnection, CommandSender { ServerboundUseItemPacket useItemPacket; if (playerInventory.getItemInHand().getJavaId() == shield.getJavaId()) { - useItemPacket = new ServerboundUseItemPacket(Hand.MAIN_HAND); + useItemPacket = new ServerboundUseItemPacket(Hand.MAIN_HAND, 0); //TODO } else if (playerInventory.getOffhand().getJavaId() == shield.getJavaId()) { - useItemPacket = new ServerboundUseItemPacket(Hand.OFF_HAND); + useItemPacket = new ServerboundUseItemPacket(Hand.OFF_HAND, 0); } else { // No blocking return false; @@ -1292,7 +1291,7 @@ public class GeyserSession implements GeyserConnection, CommandSender { private boolean disableBlocking() { if (playerEntity.getFlag(EntityFlag.BLOCKING)) { ServerboundPlayerActionPacket releaseItemPacket = new ServerboundPlayerActionPacket(PlayerAction.RELEASE_USE_ITEM, - BlockUtils.POSITION_ZERO, Direction.DOWN); + BlockUtils.POSITION_ZERO, Direction.DOWN, 0); //TODO sendDownstreamPacket(releaseItemPacket); playerEntity.setFlag(EntityFlag.BLOCKING, false); return 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 b68c0996d..c7165083d 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 @@ -34,15 +34,16 @@ import com.nukkitx.protocol.bedrock.packet.GameRulesChangedPacket; import com.nukkitx.protocol.bedrock.packet.SetPlayerGameTypePacket; import org.geysermc.floodgate.pluginmessage.PluginMessageChannels; import org.geysermc.geyser.entity.type.player.PlayerEntity; +import org.geysermc.geyser.level.JavaDimension; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.auth.AuthType; import org.geysermc.geyser.translator.level.BiomeTranslator; 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.PluginMessageUtils; +import java.util.Map; + @Translator(packet = ClientboundLoginPacket.class) public class JavaLoginTranslator extends PacketTranslator { @@ -51,12 +52,15 @@ public class JavaLoginTranslator extends PacketTranslator dimensions = session.getDimensions(); + dimensions.clear(); + // If the player is already initialized and a join game packet is sent, they // are swapping servers - String newDimension = DimensionUtils.getNewDimension(packet.getDimension()); + //String newDimension = DimensionUtils.getNewDimension(packet.getDimension()); if (session.isSpawned()) { - String fakeDim = DimensionUtils.getTemporaryDimension(session.getDimension(), newDimension); - DimensionUtils.switchDimension(session, fakeDim); + //String fakeDim = DimensionUtils.getTemporaryDimension(session.getDimension(), newDimension); + //DimensionUtils.switchDimension(session, fakeDim); session.getWorldCache().removeScoreboard(); } @@ -70,7 +74,7 @@ public class JavaLoginTranslator extends PacketTranslator { +@Translator(packet = ClientboundSystemChatPacket.class) +public class JavaSystemChatTranslator extends PacketTranslator { @Override - public void translate(GeyserSession session, ClientboundChatPacket packet) { + public void translate(GeyserSession session, ClientboundSystemChatPacket packet) { TextPacket textPacket = new TextPacket(); textPacket.setPlatformChatId(""); textPacket.setSourceName(""); textPacket.setXuid(session.getAuthData().xuid()); + // TODO new types textPacket.setType(switch (packet.getType()) { case CHAT -> TextPacket.Type.CHAT; case SYSTEM -> TextPacket.Type.SYSTEM; - case NOTIFICATION -> TextPacket.Type.TIP; + case GAME_INFO -> TextPacket.Type.TIP; default -> TextPacket.Type.RAW; }); textPacket.setNeedsTranslation(false); - textPacket.setMessage(MessageTranslator.convertMessage(packet.getMessage(), session.getLocale())); + textPacket.setMessage(MessageTranslator.convertMessage(packet.getContent(), session.getLocale())); session.sendUpstreamPacket(textPacket); } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaBlockBreakAckTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaBlockBreakAckTranslator.java index 634d4d424..714603997 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaBlockBreakAckTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaBlockBreakAckTranslator.java @@ -25,30 +25,16 @@ package org.geysermc.geyser.translator.protocol.java.entity.player; -import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerAction; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.entity.player.ClientboundBlockBreakAckPacket; -import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.data.LevelEventType; -import com.nukkitx.protocol.bedrock.packet.LevelEventPacket; +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.geyser.level.block.BlockStateValues; -import org.geysermc.geyser.util.ChunkUtils; -@Translator(packet = ClientboundBlockBreakAckPacket.class) -public class JavaBlockBreakAckTranslator extends PacketTranslator { +@Translator(packet = ClientboundBlockChangedAckPacket.class) +public class JavaBlockBreakAckTranslator extends PacketTranslator { @Override - public void translate(GeyserSession session, ClientboundBlockBreakAckPacket packet) { - ChunkUtils.updateBlock(session, packet.getNewState(), packet.getPosition()); - if (packet.getAction() == PlayerAction.START_DIGGING && !packet.isSuccessful()) { - LevelEventPacket stopBreak = new LevelEventPacket(); - stopBreak.setType(LevelEventType.BLOCK_STOP_BREAK); - stopBreak.setPosition(Vector3f.from(packet.getPosition().getX(), packet.getPosition().getY(), packet.getPosition().getZ())); - stopBreak.setData(0); - session.setBreakingBlock(BlockStateValues.JAVA_AIR_ID); - session.sendUpstreamPacket(stopBreak); - } + public void translate(GeyserSession session, ClientboundBlockChangedAckPacket packet) { + // TODO } } \ No newline at end of file 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 33a347658..9d2a383f5 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 @@ -52,6 +52,7 @@ public class JavaAddEntityTranslator extends PacketTranslator definition = Registries.ENTITY_DEFINITIONS.get(packet.getType()); if (definition == null) { @@ -62,11 +63,11 @@ public class JavaAddEntityTranslator extends PacketTranslator { - - @Override - public void translate(GeyserSession session, ClientboundAddMobPacket packet) { - Vector3f position = Vector3f.from(packet.getX(), packet.getY(), packet.getZ()); - Vector3f motion = Vector3f.from(packet.getMotionX(), packet.getMotionY(), packet.getMotionZ()); - - EntityDefinition definition = Registries.ENTITY_DEFINITIONS.get(packet.getType()); - if (definition == null) { - session.getGeyser().getLogger().warning(GeyserLocale.getLocaleStringLog("geyser.entity.type_null", packet.getType())); - return; - } - - Entity entity = definition.factory().create(session, packet.getEntityId(), session.getEntityCache().getNextEntityId().incrementAndGet(), - packet.getUuid(), definition, position, motion, packet.getYaw(), packet.getPitch(), packet.getHeadYaw() - ); - session.getEntityCache().spawnEntity(entity); - } -} diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/spawn/JavaAddPaintingTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/spawn/JavaAddPaintingTranslator.java deleted file mode 100644 index 6f11640c7..000000000 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/spawn/JavaAddPaintingTranslator.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 com.github.steveice10.mc.protocol.packet.ingame.clientbound.entity.spawn.ClientboundAddPaintingPacket; -import com.nukkitx.math.vector.Vector3f; -import org.geysermc.geyser.entity.type.PaintingEntity; -import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.translator.protocol.PacketTranslator; -import org.geysermc.geyser.translator.protocol.Translator; -import org.geysermc.geyser.level.PaintingType; - -@Translator(packet = ClientboundAddPaintingPacket.class) -public class JavaAddPaintingTranslator extends PacketTranslator { - - @Override - public void translate(GeyserSession session, ClientboundAddPaintingPacket packet) { - Vector3f position = Vector3f.from(packet.getPosition().getX(), packet.getPosition().getY(), packet.getPosition().getZ()); - - PaintingEntity entity = new PaintingEntity(session, packet.getEntityId(), - session.getEntityCache().getNextEntityId().incrementAndGet(), packet.getUuid(), - position, PaintingType.getByPaintingType(packet.getPaintingType()), packet.getDirection().getHorizontalIndex()); - - session.getEntityCache().spawnEntity(entity); - } -} From bbf45b6a4cc8ec3b389923d5b6dbca3e83ce21b0 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Wed, 25 May 2022 15:55:15 -0400 Subject: [PATCH 15/72] Compiles; provide your own mappings for now --- core/pom.xml | 4 +- .../command/defaults/OffhandCommand.java | 2 +- .../geyser/entity/EntityDefinitions.java | 2 +- .../geyser/entity/type/PaintingEntity.java | 19 +++--- .../type/living/animal/HoglinEntity.java | 2 +- .../type/living/monster/BasePiglinEntity.java | 2 +- .../geyser/level/GeyserWorldManager.java | 9 ++- .../geysermc/geyser/level/JavaDimension.java | 24 ++++++-- .../geyser/network/MinecraftProtocol.java | 6 -- .../populator/BlockRegistryPopulator.java | 6 +- .../populator/ItemRegistryPopulator.java | 4 +- .../geyser/session/GeyserSession.java | 37 +++++++++-- .../geyser/session/cache/TagCache.java | 1 + .../inventory/BeaconInventoryTranslator.java | 8 ++- .../translator/level/BiomeTranslator.java | 36 +++++------ .../BedrockCommandRequestTranslator.java | 7 +-- ...BedrockInventoryTransactionTranslator.java | 18 +++--- .../BedrockLecternUpdateTranslator.java | 3 +- .../BedrockMobEquipmentTranslator.java | 2 +- .../bedrock/BedrockTextTranslator.java | 4 +- .../player/BedrockActionTranslator.java | 10 +-- .../entity/player/BedrockEmoteTranslator.java | 2 +- .../protocol/java/JavaCommandsTranslator.java | 2 +- .../protocol/java/JavaLoginTranslator.java | 57 ++++++++++++++--- .../java/JavaPlayerChatTranslator.java | 60 ++++++++++++++++++ .../protocol/java/JavaRespawnTranslator.java | 9 +-- .../java/JavaSystemChatTranslator.java | 1 + .../org/geysermc/geyser/util/ChunkUtils.java | 22 +++---- .../geysermc/geyser/util/DimensionUtils.java | 22 ------- .../geysermc/geyser/util/JavaCodecEntry.java | 61 +++++++++++++++++++ 30 files changed, 310 insertions(+), 132 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaPlayerChatTranslator.java create mode 100644 core/src/main/java/org/geysermc/geyser/util/JavaCodecEntry.java diff --git a/core/pom.xml b/core/pom.xml index c9047ee4b..2d06c6bff 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -120,8 +120,8 @@ com.github.CloudburstMC.Protocol - bedrock-v503 - 297567d + bedrock-beta + 49323e0 compile 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 1d29d5122..f17ca5e21 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 @@ -47,7 +47,7 @@ public class OffhandCommand extends GeyserCommand { } ServerboundPlayerActionPacket releaseItemPacket = new ServerboundPlayerActionPacket(PlayerAction.SWAP_HANDS, BlockUtils.POSITION_ZERO, - Direction.DOWN); + Direction.DOWN, session.getNextSequence()); session.sendDownstreamPacket(releaseItemPacket); } 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 1de571c94..7069b55b2 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java +++ b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java @@ -272,7 +272,7 @@ public final class EntityDefinitions { .type(EntityType.LLAMA_SPIT) .heightAndWidth(0.25f) .build(); - PAINTING = EntityDefinition.inherited(null, entityBase) + PAINTING = EntityDefinition.inherited(PaintingEntity::new, entityBase) .type(EntityType.PAINTING) .build(); SHULKER_BULLET = EntityDefinition.inherited(ThrowableEntity::new, entityBase) 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 9a2bbd5a4..3fa4e90b2 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 @@ -27,26 +27,27 @@ package org.geysermc.geyser.entity.type; import com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.packet.AddPaintingPacket; -import org.geysermc.geyser.entity.EntityDefinitions; -import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.level.PaintingType; +import org.geysermc.geyser.session.GeyserSession; import java.util.UUID; -// TODO 1.19 public class PaintingEntity extends Entity { private static final double OFFSET = -0.46875; - private final PaintingType paintingName; - private final int direction; + private PaintingType paintingName; + private int direction; - public PaintingEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, Vector3f position, PaintingType paintingName, int direction) { - super(session, entityId, geyserId, uuid, EntityDefinitions.PAINTING, position, Vector3f.ZERO, 0f, 0f, 0f); - this.paintingName = paintingName; - this.direction = direction; + public PaintingEntity(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 spawnEntity() { + // Wait until we get the metadata needed + } + + public void paintingtodo() { AddPaintingPacket addPaintingPacket = new AddPaintingPacket(); addPaintingPacket.setUniqueEntityId(geyserId); addPaintingPacket.setRuntimeEntityId(geyserId); 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 362c25256..a96d3072c 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 @@ -49,7 +49,7 @@ public class HoglinEntity extends AnimalEntity { @Override protected boolean isShaking() { - return (!isImmuneToZombification && !session.isDimensionPiglinSafe()) || super.isShaking(); + return (!isImmuneToZombification && !session.getDimensionType().piglinSafe()) || super.isShaking(); } @Override 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 ed26a71e1..e003dd080 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 @@ -48,6 +48,6 @@ public class BasePiglinEntity extends MonsterEntity { @Override protected boolean isShaking() { - return (!isImmuneToZombification && !session.isDimensionPiglinSafe()) || super.isShaking(); + return (!isImmuneToZombification && !session.getDimensionType().piglinSafe()) || super.isShaking(); } } 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 5766cabbf..100917793 100644 --- a/core/src/main/java/org/geysermc/geyser/level/GeyserWorldManager.java +++ b/core/src/main/java/org/geysermc/geyser/level/GeyserWorldManager.java @@ -27,15 +27,14 @@ package org.geysermc.geyser.level; import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; import com.github.steveice10.mc.protocol.data.game.setting.Difficulty; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundChatPacket; import com.nukkitx.nbt.NbtMap; import com.nukkitx.nbt.NbtMapBuilder; import it.unimi.dsi.fastutil.objects.Object2ObjectMap; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.ChunkCache; import org.geysermc.geyser.translator.inventory.LecternInventoryTranslator; -import org.geysermc.geyser.level.block.BlockStateValues; import java.util.Locale; @@ -83,7 +82,7 @@ public class GeyserWorldManager extends WorldManager { @Override public void setGameRule(GeyserSession session, String name, Object value) { - session.sendDownstreamPacket(new ServerboundChatPacket("/gamerule " + name + " " + value)); + session.sendCommand("gamerule " + name + " " + value); gameruleCache.put(name, String.valueOf(value)); } @@ -109,12 +108,12 @@ public class GeyserWorldManager extends WorldManager { @Override public void setPlayerGameMode(GeyserSession session, GameMode gameMode) { - session.sendDownstreamPacket(new ServerboundChatPacket("/gamemode " + gameMode.name().toLowerCase(Locale.ROOT))); + session.sendCommand("gamemode " + gameMode.name().toLowerCase(Locale.ROOT)); } @Override public void setDifficulty(GeyserSession session, Difficulty difficulty) { - session.sendDownstreamPacket(new ServerboundChatPacket("/difficulty " + difficulty.name().toLowerCase(Locale.ROOT))); + session.sendCommand("difficulty " + difficulty.name().toLowerCase(Locale.ROOT)); } @Override 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 b297739a9..45ccf3821 100644 --- a/core/src/main/java/org/geysermc/geyser/level/JavaDimension.java +++ b/core/src/main/java/org/geysermc/geyser/level/JavaDimension.java @@ -26,17 +26,31 @@ package org.geysermc.geyser.level; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; +import com.github.steveice10.opennbt.tag.builtin.IntTag; +import org.geysermc.geyser.util.JavaCodecEntry; + +import java.util.Map; /** * 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) { +public record JavaDimension(int minY, int maxY, boolean piglinSafe, double worldCoordinateScale) { - public static JavaDimension load(CompoundTag tag) { -// int minY = ((IntTag) dimensionTag.get("min_y")).getValue(); -// int maxY = ((IntTag) dimensionTag.get("height")).getValue(); - return new JavaDimension(0, 0, false); + public static void load(CompoundTag tag, Map map) { + for (CompoundTag dimension : JavaCodecEntry.iterateOverTag(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(); + // 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; + // Load world coordinate scale for the world border + double coordinateScale = ((Number) elements.get("coordinate_scale").getValue()).doubleValue(); + + map.put((String) dimension.get("name").getValue(), new JavaDimension(minY, maxY, piglinSafe, coordinateScale)); + } } } diff --git a/core/src/main/java/org/geysermc/geyser/network/MinecraftProtocol.java b/core/src/main/java/org/geysermc/geyser/network/MinecraftProtocol.java index 828b04a9d..f4afceb21 100644 --- a/core/src/main/java/org/geysermc/geyser/network/MinecraftProtocol.java +++ b/core/src/main/java/org/geysermc/geyser/network/MinecraftProtocol.java @@ -28,8 +28,6 @@ package org.geysermc.geyser.network; import com.github.steveice10.mc.protocol.codec.MinecraftCodec; import com.github.steveice10.mc.protocol.codec.PacketCodec; import com.nukkitx.protocol.bedrock.BedrockPacketCodec; -import com.nukkitx.protocol.bedrock.v475.Bedrock_v475; -import com.nukkitx.protocol.bedrock.v486.Bedrock_v486; import com.nukkitx.protocol.bedrock.v503.Bedrock_v503; import java.util.ArrayList; @@ -58,10 +56,6 @@ public final class MinecraftProtocol { private static final PacketCodec DEFAULT_JAVA_CODEC = MinecraftCodec.CODEC; static { - SUPPORTED_BEDROCK_CODECS.add(Bedrock_v475.V475_CODEC.toBuilder().minecraftVersion("1.18.0/1.18.1/1.18.2").build()); - SUPPORTED_BEDROCK_CODECS.add(Bedrock_v486.V486_CODEC.toBuilder() - .minecraftVersion("1.18.10/1.18.12") // 1.18.11 is also supported, but was only on Switch and since that auto-updates it's not needed - .build()); SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC.toBuilder() .minecraftVersion("1.18.30/1.18.31") .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 412d7d779..55782447f 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 @@ -171,8 +171,10 @@ public class BlockRegistryPopulator { int bedrockRuntimeId = blockStateOrderedMap.getOrDefault(buildBedrockState(entry.getValue(), stateVersion, stateMapper), -1); if (bedrockRuntimeId == -1) { - throw new RuntimeException("Unable to find " + javaId + " Bedrock runtime ID! Built NBT tag: \n" + - buildBedrockState(entry.getValue(), stateVersion, stateMapper)); + bedrockRuntimeId = 0; + //TODO remove + //throw new RuntimeException("Unable to find " + javaId + " Bedrock runtime ID! Built NBT tag: \n" + + // buildBedrockState(entry.getValue(), stateVersion, stateMapper)); } switch (javaId) { 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 37b6c49f4..39321ae02 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,7 +252,9 @@ public class ItemRegistryPopulator { int bedrockId = bedrockIdentifierToId.getInt(bedrockIdentifier); if (bedrockId == Short.MIN_VALUE) { - throw new RuntimeException("Missing Bedrock ID in mappings: " + bedrockIdentifier); + bedrockId = 0; + //TODO remove + //throw new RuntimeException("Missing Bedrock ID in mappings: " + bedrockIdentifier); } int stackSize = mappingItem.getStackSize(); 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 607c9f84d..e93c7392e 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -36,6 +36,7 @@ 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.MessageType; 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; @@ -47,6 +48,8 @@ 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.handshake.serverbound.ClientIntentionPacket; +import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundChatCommandPacket; +import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundChatPacket; import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundClientInformationPacket; import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundMovePlayerPosPacket; import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundPlayerAbilitiesPacket; @@ -69,6 +72,7 @@ import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import com.nukkitx.protocol.bedrock.packet.*; import io.netty.channel.Channel; import io.netty.channel.EventLoop; +import it.unimi.dsi.fastutil.bytes.ByteArrays; import it.unimi.dsi.fastutil.ints.Int2IntMap; import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; @@ -81,6 +85,7 @@ import lombok.AccessLevel; import lombok.Getter; import lombok.NonNull; import lombok.Setter; +import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.checkerframework.common.value.qual.IntRange; import org.geysermc.common.PlatformType; import org.geysermc.cumulus.Form; @@ -125,6 +130,7 @@ import java.net.ConnectException; import java.net.InetAddress; import java.net.InetSocketAddress; import java.nio.charset.StandardCharsets; +import java.time.Instant; import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ScheduledFuture; @@ -319,11 +325,16 @@ public class GeyserSession implements GeyserConnection, CommandSender { */ @Setter private String dimension = DimensionUtils.OVERWORLD; + @MonotonicNonNull + @Setter + private JavaDimension dimensionType = null; /** * All dimensions that the client could possibly connect to. */ private final Map dimensions = new Object2ObjectOpenHashMap<>(3); + private final Map chatTypes = new EnumMap<>(MessageType.class); + @Setter private int breakingBlock; @@ -1260,9 +1271,9 @@ public class GeyserSession implements GeyserConnection, CommandSender { ServerboundUseItemPacket useItemPacket; if (playerInventory.getItemInHand().getJavaId() == shield.getJavaId()) { - useItemPacket = new ServerboundUseItemPacket(Hand.MAIN_HAND, 0); //TODO + useItemPacket = new ServerboundUseItemPacket(Hand.MAIN_HAND, getNextSequence()); } else if (playerInventory.getOffhand().getJavaId() == shield.getJavaId()) { - useItemPacket = new ServerboundUseItemPacket(Hand.OFF_HAND, 0); + useItemPacket = new ServerboundUseItemPacket(Hand.OFF_HAND, getNextSequence()); } else { // No blocking return false; @@ -1291,7 +1302,7 @@ public class GeyserSession implements GeyserConnection, CommandSender { private boolean disableBlocking() { if (playerEntity.getFlag(EntityFlag.BLOCKING)) { ServerboundPlayerActionPacket releaseItemPacket = new ServerboundPlayerActionPacket(PlayerAction.RELEASE_USE_ITEM, - BlockUtils.POSITION_ZERO, Direction.DOWN, 0); //TODO + BlockUtils.POSITION_ZERO, Direction.DOWN, getNextSequence()); sendDownstreamPacket(releaseItemPacket); playerEntity.setFlag(EntityFlag.BLOCKING, false); return true; @@ -1357,7 +1368,21 @@ public class GeyserSession implements GeyserConnection, CommandSender { @Override public String getLocale() { return clientData.getLanguageCode(); - } + } + + /** + * Sends a chat message to the Java server. + */ + public void sendChat(String message) { + sendDownstreamPacket(new ServerboundChatPacket(message, Instant.now().toEpochMilli(), 0L, ByteArrays.EMPTY_ARRAY, false)); + } + + /** + * Sends a command to the Java server. + */ + public void sendCommand(String command) { + sendDownstreamPacket(new ServerboundChatCommandPacket(command, Instant.now().toEpochMilli(), 0L, Collections.emptyMap(), false)); + } public void setServerRenderDistance(int renderDistance) { renderDistance = GenericMath.ceil(++renderDistance * MathUtils.SQRT_OF_TWO); //square to circle @@ -1636,6 +1661,10 @@ public class GeyserSession implements GeyserConnection, CommandSender { sendDownstreamPacket(clientSettingsPacket); } + public int getNextSequence() { + return 0; + } + /** * Used for updating statistic values since we only get changes from the server * 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 d46a39616..993d93e0b 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 @@ -69,6 +69,7 @@ public class TagCache { } public void loadPacket(GeyserSession session, ClientboundUpdateTagsPacket packet) { + System.out.println(packet); Map blockTags = packet.getTags().get("minecraft:block"); this.leaves = IntList.of(blockTags.get("minecraft:leaves")); this.wool = IntList.of(blockTags.get("minecraft:wool")); 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 f194d0d3f..54dc533c6 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 @@ -48,6 +48,8 @@ import org.geysermc.geyser.inventory.updater.UIInventoryUpdater; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.util.InventoryUtils; +import java.util.OptionalInt; + public class BeaconInventoryTranslator extends AbstractBlockInventoryTranslator { public BeaconInventoryTranslator() { super(1, new BlockInventoryHolder("minecraft:beacon", com.nukkitx.protocol.bedrock.data.inventory.ContainerType.BEACON) { @@ -111,11 +113,15 @@ public class BeaconInventoryTranslator extends AbstractBlockInventoryTranslator public ItemStackResponsePacket.Response translateSpecialRequest(GeyserSession session, Inventory inventory, ItemStackRequest request) { // Input a beacon payment BeaconPaymentStackRequestActionData beaconPayment = (BeaconPaymentStackRequestActionData) request.getActions()[0]; - ServerboundSetBeaconPacket packet = new ServerboundSetBeaconPacket(beaconPayment.getPrimaryEffect(), beaconPayment.getSecondaryEffect()); + ServerboundSetBeaconPacket packet = new ServerboundSetBeaconPacket(toJava(beaconPayment.getPrimaryEffect()), toJava(beaconPayment.getSecondaryEffect())); session.sendDownstreamPacket(packet); return acceptRequest(request, makeContainerEntries(session, inventory, IntSets.emptySet())); } + private OptionalInt toJava(int effectChoice) { + return effectChoice == -1 ? OptionalInt.empty() : OptionalInt.of(effectChoice); + } + @Override public int bedrockSlotToJava(StackRequestSlotInfoData slotInfoData) { if (slotInfoData.getContainer() == ContainerSlotType.BEACON_PAYMENT) { 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 ac9a0517a..24b6f950f 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 @@ -42,6 +42,7 @@ import org.geysermc.geyser.level.chunk.bitarray.BitArray; 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.util.JavaCodecEntry; import org.geysermc.geyser.util.MathUtils; // Array index formula by https://wiki.vg/Chunk_Format @@ -55,27 +56,26 @@ public class BiomeTranslator { ListTag serverBiomes = worldGen.get("value"); session.setBiomeGlobalPalette(MathUtils.getGlobalPaletteForSize(serverBiomes.size())); - for (Tag tag : serverBiomes) { - CompoundTag biomeTag = (CompoundTag) tag; - + for (CompoundTag biomeTag : JavaCodecEntry.iterateOverTag(worldGen)) { String javaIdentifier = ((StringTag) biomeTag.get("name")).getValue(); - int bedrockId = Registries.BIOME_IDENTIFIERS.get().getOrDefault(javaIdentifier, -1); + int bedrockId = Registries.BIOME_IDENTIFIERS.get().getOrDefault(javaIdentifier, 0); int javaId = ((IntTag) biomeTag.get("id")).getValue(); - 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); - } + // 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); 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 73ca9b222..0aa57b077 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 @@ -25,15 +25,13 @@ package org.geysermc.geyser.translator.protocol.bedrock; +import com.nukkitx.protocol.bedrock.packet.CommandRequestPacket; import org.geysermc.common.PlatformType; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.command.CommandManager; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; - -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundChatPacket; -import com.nukkitx.protocol.bedrock.packet.CommandRequestPacket; import org.geysermc.geyser.translator.text.MessageTranslator; @Translator(packet = CommandRequestPacket.class) @@ -52,8 +50,7 @@ public class BedrockCommandRequestTranslator extends PacketTranslator { - ServerboundUseItemPacket itemPacket = new ServerboundUseItemPacket(Hand.MAIN_HAND); + ServerboundUseItemPacket itemPacket = new ServerboundUseItemPacket(Hand.MAIN_HAND, session.getNextSequence()); session.sendDownstreamPacket(itemPacket); }, 5, TimeUnit.MILLISECONDS)); } @@ -336,7 +338,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator legacySlots = packet.getLegacySlots(); @@ -418,7 +420,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator session.sendDownstreamPacket(new ServerboundUseItemPacket(Hand.MAIN_HAND)), + session.scheduleInEventLoop(() -> session.sendDownstreamPacket(new ServerboundUseItemPacket(Hand.MAIN_HAND, session.getNextSequence())), 50, TimeUnit.MILLISECONDS); } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockTextTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockTextTranslator.java index 91ed5aa2b..e52fac371 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockTextTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockTextTranslator.java @@ -25,7 +25,6 @@ package org.geysermc.geyser.translator.protocol.bedrock; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundChatPacket; import com.nukkitx.protocol.bedrock.packet.TextPacket; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.ChatColor; @@ -63,7 +62,6 @@ public class BedrockTextTranslator extends PacketTranslator { return; } - ServerboundChatPacket chatPacket = new ServerboundChatPacket(message); - session.sendDownstreamPacket(chatPacket); + session.sendChat(message); } } 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 5429899fa..f6edd731b 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 @@ -130,7 +130,8 @@ public class BedrockActionTranslator extends PacketTranslator { if (session.getGeyser().getConfig().getEmoteOffhandWorkaround() != EmoteOffhandWorkaroundOption.DISABLED) { // Activate the workaround - we should trigger the offhand now ServerboundPlayerActionPacket swapHandsPacket = new ServerboundPlayerActionPacket(PlayerAction.SWAP_HANDS, BlockUtils.POSITION_ZERO, - Direction.DOWN); + Direction.DOWN, session.getNextSequence()); session.sendDownstreamPacket(swapHandsPacket); if (session.getGeyser().getConfig().getEmoteOffhandWorkaround() == EmoteOffhandWorkaroundOption.NO_EMOTES) { 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 00b60fec0..115a44bdd 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 @@ -222,7 +222,7 @@ public class JavaCommandsTranslator extends PacketTranslator CommandParam.BLOCK_POSITION; case COLUMN_POS, VEC3 -> CommandParam.POSITION; case MESSAGE -> CommandParam.MESSAGE; - case NBT, NBT_COMPOUND_TAG, NBT_TAG, NBT_PATH -> CommandParam.JSON; + case NBT_COMPOUND_TAG, NBT_TAG, NBT_PATH -> CommandParam.JSON; //TODO NBT was removed case RESOURCE_LOCATION, FUNCTION -> CommandParam.FILE_PATH; case BOOL -> ENUM_BOOLEAN; case OPERATION -> CommandParam.OPERATOR; // ">=", "==", etc 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 c7165083d..b7f169627 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,8 +25,12 @@ package org.geysermc.geyser.translator.protocol.java; +import com.github.steveice10.mc.protocol.data.game.MessageType; import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundLoginPacket; import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundCustomPayloadPacket; +import com.github.steveice10.opennbt.SNBTIO; +import com.github.steveice10.opennbt.tag.builtin.CompoundTag; +import com.github.steveice10.opennbt.tag.builtin.IntTag; import com.nukkitx.protocol.bedrock.data.GameRuleData; import com.nukkitx.protocol.bedrock.data.PlayerPermission; import com.nukkitx.protocol.bedrock.packet.AdventureSettingsPacket; @@ -40,8 +44,14 @@ import org.geysermc.geyser.session.auth.AuthType; import org.geysermc.geyser.translator.level.BiomeTranslator; 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.JavaCodecEntry; import org.geysermc.geyser.util.PluginMessageUtils; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; import java.util.Map; @Translator(packet = ClientboundLoginPacket.class) @@ -55,12 +65,37 @@ public class JavaLoginTranslator extends PacketTranslator dimensions = session.getDimensions(); dimensions.clear(); + JavaDimension.load(packet.getDimensionCodec(), dimensions); + + SNBTIO.StringifiedNBTWriter writer = new SNBTIO.StringifiedNBTWriter(System.out); + try { + writer.writeTag(packet.getDimensionCodec(), true); + } catch (IOException e) { + e.printStackTrace(); + } + + for (CompoundTag tag : JavaCodecEntry.iterateOverTag(packet.getDimensionCodec().get("minecraft:chat_type"))) { + int id = ((IntTag) tag.get("id")).getValue(); + MessageType type = MessageType.values()[id]; + CompoundTag element = tag.get("element"); + CompoundTag chat = element.get("chat"); + if (chat == null) { + continue; + } + + try (ByteArrayOutputStream out = new ByteArrayOutputStream(); SNBTIO.StringifiedNBTWriter nbtWriter = new SNBTIO.StringifiedNBTWriter(out)) { + nbtWriter.writeTag(chat, false); + System.out.println(out.toString(StandardCharsets.UTF_8)); + } catch (IOException e) { + e.printStackTrace(); + } + } + // If the player is already initialized and a join game packet is sent, they // are swapping servers - //String newDimension = DimensionUtils.getNewDimension(packet.getDimension()); if (session.isSpawned()) { - //String fakeDim = DimensionUtils.getTemporaryDimension(session.getDimension(), newDimension); - //DimensionUtils.switchDimension(session, fakeDim); + String fakeDim = DimensionUtils.getTemporaryDimension(session.getDimension(), packet.getDimension()); + DimensionUtils.switchDimension(session, fakeDim); session.getWorldCache().removeScoreboard(); } @@ -110,13 +145,15 @@ public class JavaLoginTranslator extends PacketTranslator { + + @Override + public void translate(GeyserSession session, ClientboundPlayerChatPacket packet) { + System.out.println(packet); + TextPacket textPacket = new TextPacket(); + textPacket.setPlatformChatId(""); + textPacket.setSourceName(""); + textPacket.setXuid(session.getAuthData().xuid()); + // TODO new types + textPacket.setType(switch (packet.getType()) { + case CHAT -> TextPacket.Type.CHAT; + case SYSTEM -> TextPacket.Type.SYSTEM; + case GAME_INFO -> TextPacket.Type.TIP; + default -> TextPacket.Type.RAW; + }); + + textPacket.setNeedsTranslation(false); + Component message = packet.getUnsignedContent() == null ? packet.getSignedContent() : packet.getUnsignedContent(); + textPacket.setMessage(MessageTranslator.convertMessage(message, session.getLocale())); + + session.sendUpstreamPacket(textPacket); + } +} 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 03d006a50..2d8c379f9 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 @@ -33,9 +33,9 @@ import com.nukkitx.protocol.bedrock.packet.SetPlayerGameTypePacket; import org.geysermc.geyser.entity.attribute.GeyserAttributeType; import org.geysermc.geyser.entity.type.player.SessionPlayerEntity; 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.translator.inventory.InventoryTranslator; import org.geysermc.geyser.util.ChunkUtils; import org.geysermc.geyser.util.DimensionUtils; @@ -78,7 +78,7 @@ public class JavaRespawnTranslator extends PacketTranslator iterateOverTag(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(); + } + }; + } + }; + } +} From 193fa23146f6b502906d6051111a93144bfe11d4 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Wed, 25 May 2022 18:44:33 -0400 Subject: [PATCH 16/72] Paintings work --- .../geyser/entity/EntityDefinitions.java | 5 +-- .../geyser/entity/type/PaintingEntity.java | 34 ++++++++++++------- .../geysermc/geyser/level/PaintingType.java | 10 ++---- .../geyser/session/cache/TagCache.java | 1 - .../protocol/java/JavaLoginTranslator.java | 5 +-- .../entity/spawn/JavaAddEntityTranslator.java | 8 ++--- 6 files changed, 35 insertions(+), 28 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 7069b55b2..4f3910636 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java +++ b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java @@ -272,8 +272,9 @@ public final class EntityDefinitions { .type(EntityType.LLAMA_SPIT) .heightAndWidth(0.25f) .build(); - PAINTING = EntityDefinition.inherited(PaintingEntity::new, entityBase) + PAINTING = EntityDefinition.inherited(null, entityBase) .type(EntityType.PAINTING) + .addTranslator(MetadataType.PAINTING_VARIANT, PaintingEntity::setPaintingType) .build(); SHULKER_BULLET = EntityDefinition.inherited(ThrowableEntity::new, entityBase) .type(EntityType.SHULKER_BULLET) @@ -871,7 +872,7 @@ public final class EntityDefinitions { CAT = EntityDefinition.inherited(CatEntity::new, tameableEntityBase) .type(EntityType.CAT) .height(0.35f).width(0.3f) - .addTranslator(MetadataType.INT, CatEntity::setCatVariant) + .addTranslator(MetadataType.CAT_VARIANT, CatEntity::setCatVariant) .addTranslator(MetadataType.BOOLEAN, CatEntity::setResting) .addTranslator(null) // "resting state one" //TODO .addTranslator(MetadataType.INT, CatEntity::setCollarColor) 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 3fa4e90b2..cdd9449e5 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,6 +25,8 @@ 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 com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.packet.AddPaintingPacket; import org.geysermc.geyser.entity.EntityDefinition; @@ -35,11 +37,11 @@ import java.util.UUID; public class PaintingEntity extends Entity { private static final double OFFSET = -0.46875; - private PaintingType paintingName; - private int direction; + private final Direction direction; - public PaintingEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public PaintingEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw, Direction direction) { super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw); + this.direction = direction; } @Override @@ -47,13 +49,21 @@ public class PaintingEntity extends Entity { // Wait until we get the metadata needed } - public void paintingtodo() { + public void setPaintingType(ObjectEntityMetadata entityMetadata) { + PaintingType type = PaintingType.getByPaintingType(entityMetadata.getValue()); AddPaintingPacket addPaintingPacket = new AddPaintingPacket(); addPaintingPacket.setUniqueEntityId(geyserId); addPaintingPacket.setRuntimeEntityId(geyserId); - addPaintingPacket.setMotive(paintingName.getBedrockName()); - addPaintingPacket.setPosition(fixOffset()); - addPaintingPacket.setDirection(direction); + addPaintingPacket.setMotive(type.getBedrockName()); + addPaintingPacket.setPosition(fixOffset(type)); + addPaintingPacket.setDirection(switch (direction) { + //TODO this doesn't seem right. Why did it work fine before? + case SOUTH -> 0; + case WEST -> 1; + case NORTH -> 2; + case EAST -> 3; + default -> 0; + }); session.sendUpstreamPacket(addPaintingPacket); valid = true; @@ -66,17 +76,17 @@ public class PaintingEntity extends Entity { // Do nothing, as head look messes up paintings } - private Vector3f fixOffset() { + 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 heightOffset = paintingName.getHeight() > 1 && paintingName.getHeight() != 3 ? 0.5 : 0; return switch (direction) { - case 0 -> position.add(widthOffset, heightOffset, OFFSET); - case 1 -> position.add(-OFFSET, heightOffset, widthOffset); - case 2 -> position.add(-widthOffset, heightOffset, -OFFSET); - case 3 -> position.add(OFFSET, heightOffset, -widthOffset); + case SOUTH -> position.add(widthOffset, heightOffset, OFFSET); + case WEST -> position.add(-OFFSET, heightOffset, widthOffset); + case NORTH -> position.add(-widthOffset, heightOffset, -OFFSET); + case EAST -> position.add(OFFSET, heightOffset, -widthOffset); default -> position; }; } 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 1d8b56030..43c51efd4 100644 --- a/core/src/main/java/org/geysermc/geyser/level/PaintingType.java +++ b/core/src/main/java/org/geysermc/geyser/level/PaintingType.java @@ -60,13 +60,9 @@ public enum PaintingType { BURNING_SKULL("BurningSkull", 4, 4); private static final PaintingType[] VALUES = values(); - private String bedrockName; - private int width; - private int height; - - public com.github.steveice10.mc.protocol.data.game.entity.type.PaintingType toJavaType() { - return com.github.steveice10.mc.protocol.data.game.entity.type.PaintingType.valueOf(name()); - } + private final String bedrockName; + private final int width; + private final int height; public static PaintingType getByName(String javaName) { for (PaintingType paintingName : VALUES) { 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 993d93e0b..d46a39616 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 @@ -69,7 +69,6 @@ public class TagCache { } public void loadPacket(GeyserSession session, ClientboundUpdateTagsPacket packet) { - System.out.println(packet); Map blockTags = packet.getTags().get("minecraft:block"); this.leaves = IntList.of(blockTags.get("minecraft:leaves")); this.wool = IntList.of(blockTags.get("minecraft:wool")); 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 b7f169627..5a8eaaaa6 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 @@ -106,10 +106,12 @@ public class JavaLoginTranslator extends PacketTranslator Date: Wed, 25 May 2022 19:17:49 -0400 Subject: [PATCH 17/72] Switch all Position instances to Vector3i --- .../command/defaults/OffhandCommand.java | 4 ++-- .../entity/type/EnderCrystalEntity.java | 8 +++----- .../geyser/entity/type/LivingEntity.java | 20 +++++++------------ .../type/living/merchant/VillagerEntity.java | 3 +-- .../entity/type/player/PlayerEntity.java | 3 +-- .../holder/BlockInventoryHolder.java | 6 ++---- .../geysermc/geyser/level/WorldManager.java | 14 +------------ .../geyser/session/GeyserSession.java | 2 +- .../BedrockBlockEntityDataTranslator.java | 6 +++--- .../BedrockCommandBlockUpdateTranslator.java | 6 ++---- ...BedrockInventoryTransactionTranslator.java | 10 ++++------ .../BedrockLecternUpdateTranslator.java | 3 +-- .../player/BedrockActionTranslator.java | 14 +++++-------- .../entity/player/BedrockEmoteTranslator.java | 4 ++-- .../level/JavaBlockEntityDataTranslator.java | 11 +++++----- .../java/level/JavaBlockEventTranslator.java | 14 ++++++------- .../java/level/JavaBlockUpdateTranslator.java | 5 ++--- .../java/level/JavaExplodeTranslator.java | 5 ++--- .../java/level/JavaLevelEventTranslator.java | 4 +++- ...JavaSetDefaultSpawnPositionTranslator.java | 4 +--- .../geyser/util/BlockEntityUtils.java | 5 ----- .../org/geysermc/geyser/util/BlockUtils.java | 14 ++++++------- .../org/geysermc/geyser/util/ChunkUtils.java | 15 +------------- 23 files changed, 61 insertions(+), 119 deletions(-) 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 f17ca5e21..b0d0e1ce6 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 @@ -28,11 +28,11 @@ package org.geysermc.geyser.command.defaults; import com.github.steveice10.mc.protocol.data.game.entity.object.Direction; import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerAction; import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundPlayerActionPacket; +import com.nukkitx.math.vector.Vector3i; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.command.CommandSender; import org.geysermc.geyser.command.GeyserCommand; import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.util.BlockUtils; public class OffhandCommand extends GeyserCommand { @@ -46,7 +46,7 @@ public class OffhandCommand extends GeyserCommand { return; } - ServerboundPlayerActionPacket releaseItemPacket = new ServerboundPlayerActionPacket(PlayerAction.SWAP_HANDS, BlockUtils.POSITION_ZERO, + ServerboundPlayerActionPacket releaseItemPacket = new ServerboundPlayerActionPacket(PlayerAction.SWAP_HANDS, Vector3i.ZERO, Direction.DOWN, session.getNextSequence()); session.sendDownstreamPacket(releaseItemPacket); } 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 a1e91bfd2..f9e4af7c1 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 @@ -26,7 +26,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.Position; import com.nukkitx.math.vector.Vector3f; import com.nukkitx.math.vector.Vector3i; import com.nukkitx.protocol.bedrock.data.entity.EntityData; @@ -50,13 +49,12 @@ public class EnderCrystalEntity extends Entity { setFlag(EntityFlag.FIRE_IMMUNE, true); } - public void setBlockTarget(EntityMetadata, ?> entityMetadata) { + public void setBlockTarget(EntityMetadata, ?> entityMetadata) { // Show beam // Usually performed client-side on Bedrock except for Ender Dragon respawn event - Optional optionalPos = entityMetadata.getValue(); + Optional optionalPos = entityMetadata.getValue(); if (optionalPos.isPresent()) { - Position pos = optionalPos.get(); - dirtyMetadata.put(EntityData.BLOCK_TARGET, Vector3i.from(pos.getX(), pos.getY(), pos.getZ())); + dirtyMetadata.put(EntityData.BLOCK_TARGET, optionalPos.get()); } else { dirtyMetadata.put(EntityData.BLOCK_TARGET, Vector3i.ZERO); } 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 87b709309..2550643d3 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 @@ -29,7 +29,6 @@ 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.Position; 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; @@ -52,17 +51,13 @@ import lombok.Setter; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.entity.attribute.GeyserAttributeType; import org.geysermc.geyser.inventory.GeyserItemStack; -import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.registry.type.ItemMapping; +import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.util.AttributeUtils; import org.geysermc.geyser.util.ChunkUtils; import org.geysermc.geyser.util.InteractionResult; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Optional; -import java.util.UUID; +import java.util.*; @Getter @Setter @@ -123,12 +118,11 @@ public class LivingEntity extends Entity { session.sendUpstreamPacket(attributesPacket); } - public Vector3i setBedPosition(EntityMetadata, ?> entityMetadata) { - Optional optionalPos = entityMetadata.getValue(); + public Vector3i setBedPosition(EntityMetadata, ?> entityMetadata) { + Optional optionalPos = entityMetadata.getValue(); if (optionalPos.isPresent()) { - Position bedPosition = optionalPos.get(); - Vector3i vector = Vector3i.from(bedPosition.getX(), bedPosition.getY(), bedPosition.getZ()); - dirtyMetadata.put(EntityData.BED_POSITION, vector); + Vector3i bedPosition = optionalPos.get(); + dirtyMetadata.put(EntityData.BED_POSITION, bedPosition); int bed = session.getGeyser().getWorldManager().getBlockAt(session, bedPosition); // Bed has to be updated, or else player is floating in the air ChunkUtils.updateBlock(session, bed, bedPosition); @@ -136,7 +130,7 @@ public class LivingEntity extends Entity { // Has to be a byte or it does not work // (Bed position is what actually triggers sleep - "pose" is only optional) dirtyMetadata.put(EntityData.PLAYER_FLAGS, (byte) 2); - return vector; + return bedPosition; } else { // Player is no longer sleeping dirtyMetadata.put(EntityData.PLAYER_FLAGS, (byte) 0); 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 866ba36fc..e77d34f23 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 @@ -26,7 +26,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.Position; import com.github.steveice10.mc.protocol.data.game.entity.metadata.VillagerData; import com.nukkitx.math.vector.Vector3f; import com.nukkitx.math.vector.Vector3i; @@ -103,7 +102,7 @@ public class VillagerEntity extends AbstractMerchantEntity { } @Override - public Vector3i setBedPosition(EntityMetadata, ?> entityMetadata) { + public Vector3i setBedPosition(EntityMetadata, ?> entityMetadata) { return bedPosition = super.setBedPosition(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 5c0b18838..8bb47db81 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 @@ -27,7 +27,6 @@ package org.geysermc.geyser.entity.type.player; 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.Position; 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; @@ -265,7 +264,7 @@ public class PlayerEntity extends LivingEntity { } @Override - public Vector3i setBedPosition(EntityMetadata, ?> entityMetadata) { + public Vector3i setBedPosition(EntityMetadata, ?> entityMetadata) { return bedPosition = super.setBedPosition(entityMetadata); } 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 0da085e5d..fd26cc170 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 @@ -25,7 +25,6 @@ package org.geysermc.geyser.inventory.holder; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; import com.google.common.collect.ImmutableSet; import com.nukkitx.math.vector.Vector3i; import com.nukkitx.nbt.NbtMap; @@ -36,9 +35,9 @@ import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket; import com.nukkitx.protocol.bedrock.packet.UpdateBlockPacket; import org.geysermc.geyser.inventory.Container; import org.geysermc.geyser.inventory.Inventory; +import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.inventory.InventoryTranslator; -import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.util.BlockUtils; import java.util.Collections; @@ -154,8 +153,7 @@ public class BlockInventoryHolder extends InventoryHolder { } Vector3i holderPos = inventory.getHolderPosition(); - Position pos = new Position(holderPos.getX(), holderPos.getY(), holderPos.getZ()); - int realBlock = session.getGeyser().getWorldManager().getBlockAt(session, pos.getX(), pos.getY(), pos.getZ()); + int realBlock = session.getGeyser().getWorldManager().getBlockAt(session, holderPos.getX(), holderPos.getY(), holderPos.getZ()); UpdateBlockPacket blockPacket = new UpdateBlockPacket(); blockPacket.setDataLayer(0); blockPacket.setBlockPosition(holderPos); 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 fc86739e2..69f5d5beb 100644 --- a/core/src/main/java/org/geysermc/geyser/level/WorldManager.java +++ b/core/src/main/java/org/geysermc/geyser/level/WorldManager.java @@ -25,7 +25,6 @@ package org.geysermc.geyser.level; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; import com.github.steveice10.mc.protocol.data.game.setting.Difficulty; import com.nukkitx.math.vector.Vector3i; @@ -41,17 +40,6 @@ import org.geysermc.geyser.session.GeyserSession; */ public abstract class WorldManager { - /** - * Gets the Java block state at the specified location - * - * @param session the session - * @param position the position - * @return the block state at the specified location - */ - public int getBlockAt(GeyserSession session, Position position) { - return this.getBlockAt(session, position.getX(), position.getY(), position.getZ()); - } - /** * Gets the Java block state at the specified location * @@ -59,7 +47,7 @@ public abstract class WorldManager { * @param vector the position * @return the block state at the specified location */ - public int getBlockAt(GeyserSession session, Vector3i vector) { + public final int getBlockAt(GeyserSession session, Vector3i vector) { return this.getBlockAt(session, vector.getX(), vector.getY(), vector.getZ()); } 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 e93c7392e..357e964ea 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -1302,7 +1302,7 @@ public class GeyserSession implements GeyserConnection, CommandSender { private boolean disableBlocking() { if (playerEntity.getFlag(EntityFlag.BLOCKING)) { ServerboundPlayerActionPacket releaseItemPacket = new ServerboundPlayerActionPacket(PlayerAction.RELEASE_USE_ITEM, - BlockUtils.POSITION_ZERO, Direction.DOWN, getNextSequence()); + Vector3i.ZERO, Direction.DOWN, getNextSequence()); sendDownstreamPacket(releaseItemPacket); playerEntity.setFlag(EntityFlag.BLOCKING, false); return true; 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 1f2f29ea5..c759e0f3d 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,9 +25,9 @@ package org.geysermc.geyser.translator.protocol.bedrock; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundSetJigsawBlockPacket; import com.github.steveice10.mc.protocol.packet.ingame.serverbound.level.ServerboundSignUpdatePacket; +import com.nukkitx.math.vector.Vector3i; import com.nukkitx.nbt.NbtMap; import com.nukkitx.protocol.bedrock.packet.BlockEntityDataPacket; import com.nukkitx.protocol.bedrock.v503.Bedrock_v503; @@ -109,7 +109,7 @@ public class BedrockBlockEntityDataTranslator extends PacketTranslator { @@ -43,7 +43,7 @@ public class BedrockEmoteTranslator extends PacketTranslator { public void translate(GeyserSession session, EmotePacket packet) { if (session.getGeyser().getConfig().getEmoteOffhandWorkaround() != EmoteOffhandWorkaroundOption.DISABLED) { // Activate the workaround - we should trigger the offhand now - ServerboundPlayerActionPacket swapHandsPacket = new ServerboundPlayerActionPacket(PlayerAction.SWAP_HANDS, BlockUtils.POSITION_ZERO, + ServerboundPlayerActionPacket swapHandsPacket = new ServerboundPlayerActionPacket(PlayerAction.SWAP_HANDS, Vector3i.ZERO, Direction.DOWN, session.getNextSequence()); session.sendDownstreamPacket(swapHandsPacket); 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 826d53a49..3738156e4 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,20 +25,19 @@ package org.geysermc.geyser.translator.protocol.java.level; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; 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.nukkitx.math.vector.Vector3i; import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket; -import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.translator.protocol.PacketTranslator; -import org.geysermc.geyser.translator.protocol.Translator; import org.geysermc.geyser.level.block.BlockStateValues; +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; import org.geysermc.geyser.util.BlockEntityUtils; @Translator(packet = ClientboundBlockEntityDataPacket.class) @@ -60,7 +59,7 @@ public class JavaBlockEntityDataTranslator extends PacketTranslator= 2 && session.getGameMode() == GameMode.CREATIVE && packet.getNbt() != null && packet.getNbt().size() > 5) { ContainerOpenPacket openPacket = new ContainerOpenPacket(); - openPacket.setBlockPosition(Vector3i.from(packet.getPosition().getX(), packet.getPosition().getY(), packet.getPosition().getZ())); + openPacket.setBlockPosition(position); openPacket.setId((byte) 1); openPacket.setType(ContainerType.COMMAND_BLOCK); openPacket.setUniqueEntityId(-1); 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 6adf1e00f..8824f88c4 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,7 +25,6 @@ package org.geysermc.geyser.translator.protocol.java.level; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; import com.github.steveice10.mc.protocol.data.game.level.block.value.*; import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.ClientboundBlockEventPacket; import com.nukkitx.math.vector.Vector3i; @@ -49,9 +48,8 @@ public class JavaBlockEventTranslator extends PacketTranslator 0 ? 1 : 0); @@ -78,20 +76,20 @@ public class JavaBlockEventTranslator extends PacketTranslator new PistonBlockEntity(session, pos, direction, true, true)); + PistonBlockEntity blockEntity = pistonCache.getPistons().computeIfAbsent(position, pos -> new PistonBlockEntity(session, pos, direction, true, true)); if (blockEntity.getAction() != action) { blockEntity.setAction(action, Object2IntMaps.emptyMap()); } } } else { - PistonBlockEntity blockEntity = pistonCache.getPistons().computeIfAbsent(vector, pos -> { + PistonBlockEntity blockEntity = pistonCache.getPistons().computeIfAbsent(position, pos -> { int blockId = session.getGeyser().getWorldManager().getBlockAt(session, position); boolean sticky = BlockStateValues.isStickyPiston(blockId); boolean extended = action != PistonValueType.PUSHING; @@ -108,7 +106,7 @@ public class JavaBlockEventTranslator extends PacketTranslator Date: Wed, 25 May 2022 21:48:38 -0400 Subject: [PATCH 18/72] Chat messages now show up correctly. --- .../geysermc/geyser/level/JavaDimension.java | 2 +- .../geyser/session/GeyserSession.java | 3 +- .../geysermc/geyser/text/TextDecoration.java | 93 +++++++++++++++++++ .../translator/level/BiomeTranslator.java | 2 +- .../event/SoundEventEventTranslator.java | 2 +- .../protocol/java/JavaLoginTranslator.java | 28 ++---- .../java/JavaPlayerChatTranslator.java | 32 ++++++- .../java/JavaSystemChatTranslator.java | 1 - .../geysermc/geyser/util/JavaCodecEntry.java | 4 +- 9 files changed, 139 insertions(+), 28 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/text/TextDecoration.java 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 45ccf3821..5f3c96b86 100644 --- a/core/src/main/java/org/geysermc/geyser/level/JavaDimension.java +++ b/core/src/main/java/org/geysermc/geyser/level/JavaDimension.java @@ -39,7 +39,7 @@ 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 : JavaCodecEntry.iterateOverTag(tag.get("minecraft:dimension_type"))) { + for (CompoundTag dimension : JavaCodecEntry.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(); 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 357e964ea..13f00e68f 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -121,6 +121,7 @@ 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.*; @@ -333,7 +334,7 @@ public class GeyserSession implements GeyserConnection, CommandSender { */ private final Map dimensions = new Object2ObjectOpenHashMap<>(3); - private final Map chatTypes = new EnumMap<>(MessageType.class); + private final Map chatTypes = new EnumMap<>(MessageType.class); @Setter private int breakingBlock; diff --git a/core/src/main/java/org/geysermc/geyser/text/TextDecoration.java b/core/src/main/java/org/geysermc/geyser/text/TextDecoration.java new file mode 100644 index 000000000..296cacaf5 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/text/TextDecoration.java @@ -0,0 +1,93 @@ +/* + * 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 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 java.util.EnumSet; +import java.util.Locale; +import java.util.Set; + +public final class TextDecoration { + private final String translationKey; + private final Style style; + private final Set parameters; + + public TextDecoration(CompoundTag tag) { + translationKey = (String) tag.get("translation_key").getValue(); + + CompoundTag styleTag = tag.get("style"); + Style.Builder builder = Style.style(); + StringTag color = styleTag.get("color"); + if (color != null) { + builder.color(NamedTextColor.NAMES.value(color.getValue())); + } + //TODO implement the rest + Tag italic = styleTag.get("italic"); + if (italic != null && ((Number) italic.getValue()).byteValue() == (byte) 1) { + 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))); + } + } + + 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 enum Parameter { + CONTENT, + SENDER, + TEAM_NAME + } +} 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 24b6f950f..537c93a41 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 @@ -56,7 +56,7 @@ public class BiomeTranslator { ListTag serverBiomes = worldGen.get("value"); session.setBiomeGlobalPalette(MathUtils.getGlobalPaletteForSize(serverBiomes.size())); - for (CompoundTag biomeTag : JavaCodecEntry.iterateOverTag(worldGen)) { + for (CompoundTag biomeTag : JavaCodecEntry.iterateAsTag(worldGen)) { String javaIdentifier = ((StringTag) biomeTag.get("name")).getValue(); int bedrockId = Registries.BIOME_IDENTIFIERS.get().getOrDefault(javaIdentifier, 0); int javaId = ((IntTag) biomeTag.get("id")).getValue(); 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 049870114..1cb3670fb 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 @@ -40,7 +40,7 @@ public record SoundEventEventTranslator(SoundEvent soundEvent, levelSoundEvent.setIdentifier(identifier); levelSoundEvent.setExtraData(extraData); levelSoundEvent.setRelativeVolumeDisabled(packet.isBroadcast()); - levelSoundEvent.setPosition(Vector3f.from(packet.getPosition().getX(), packet.getPosition().getY(), packet.getPosition().getZ()).add(0.5f, 0.5f, 0.5f)); + levelSoundEvent.setPosition(Vector3f.from(packet.getPosition().getX() + 0.5f, packet.getPosition().getY() + 0.5f, packet.getPosition().getZ() + 0.5f)); levelSoundEvent.setBabySound(false); session.sendUpstreamPacket(levelSoundEvent); } 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 5a8eaaaa6..46e9b2f12 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 @@ -28,7 +28,6 @@ package org.geysermc.geyser.translator.protocol.java; import com.github.steveice10.mc.protocol.data.game.MessageType; import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundLoginPacket; import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundCustomPayloadPacket; -import com.github.steveice10.opennbt.SNBTIO; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.IntTag; import com.nukkitx.protocol.bedrock.data.GameRuleData; @@ -41,6 +40,7 @@ import org.geysermc.geyser.entity.type.player.PlayerEntity; import org.geysermc.geyser.level.JavaDimension; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.auth.AuthType; +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; @@ -49,9 +49,6 @@ import org.geysermc.geyser.util.DimensionUtils; import org.geysermc.geyser.util.JavaCodecEntry; import org.geysermc.geyser.util.PluginMessageUtils; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.nio.charset.StandardCharsets; import java.util.Map; @Translator(packet = ClientboundLoginPacket.class) @@ -67,28 +64,21 @@ public class JavaLoginTranslator extends PacketTranslator chatTypes = session.getChatTypes(); + chatTypes.clear(); + for (CompoundTag tag : JavaCodecEntry.iterateAsTag(packet.getDimensionCodec().get("minecraft:chat_type"))) { int id = ((IntTag) tag.get("id")).getValue(); - MessageType type = MessageType.values()[id]; CompoundTag element = tag.get("element"); CompoundTag chat = element.get("chat"); if (chat == null) { continue; } - - try (ByteArrayOutputStream out = new ByteArrayOutputStream(); SNBTIO.StringifiedNBTWriter nbtWriter = new SNBTIO.StringifiedNBTWriter(out)) { - nbtWriter.writeTag(chat, false); - System.out.println(out.toString(StandardCharsets.UTF_8)); - } catch (IOException e) { - e.printStackTrace(); + CompoundTag decoration = chat.get("decoration"); + if (decoration == null) { + continue; } + MessageType type = MessageType.VALUES[id]; + chatTypes.put(type, new TextDecoration(decoration)); } // If the player is already initialized and a join game packet is sent, they 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 22e4d95ac..be1635fdd 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 @@ -28,17 +28,22 @@ package org.geysermc.geyser.translator.protocol.java; import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundPlayerChatPacket; import com.nukkitx.protocol.bedrock.packet.TextPacket; import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.TranslatableComponent; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.text.TextDecoration; 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.List; +import java.util.Set; + @Translator(packet = ClientboundPlayerChatPacket.class) public class JavaPlayerChatTranslator extends PacketTranslator { @Override public void translate(GeyserSession session, ClientboundPlayerChatPacket packet) { - System.out.println(packet); TextPacket textPacket = new TextPacket(); textPacket.setPlatformChatId(""); textPacket.setSourceName(""); @@ -53,7 +58,30 @@ public class JavaPlayerChatTranslator extends PacketTranslator parameters = decoration.parameters(); + List args = new ArrayList<>(3); + if (parameters.contains(TextDecoration.Parameter.TEAM_NAME)) { + args.add(packet.getSenderTeamName()); + } + if (parameters.contains(TextDecoration.Parameter.SENDER)) { + args.add(packet.getSenderName()); + } + if (parameters.contains(TextDecoration.Parameter.CONTENT)) { + args.add(message); + } + withDecoration.args(args); + textPacket.setMessage(MessageTranslator.convertMessage(withDecoration.build(), session.getLocale())); + } else { + textPacket.setMessage(MessageTranslator.convertMessage(message, session.getLocale())); + } session.sendUpstreamPacket(textPacket); } 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 a22360e30..b82f2e194 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 @@ -37,7 +37,6 @@ public class JavaSystemChatTranslator extends PacketTranslator iterateOverTag(CompoundTag tag) { + public static Iterable iterateAsTag(CompoundTag tag) { ListTag value = tag.get("value"); Iterator originalIterator = value.iterator(); return new Iterable<>() { From c5de293373bd556abc8dff309a3f36bede867b39 Mon Sep 17 00:00:00 2001 From: davchoo Date: Wed, 25 May 2022 19:41:31 -0400 Subject: [PATCH 19/72] Allow 1.19.0 to join and use new block mappings --- .../geyser/network/MinecraftProtocol.java | 9 +- .../geyser/network/UpstreamPacketHandler.java | 1 + .../populator/BlockRegistryPopulator.java | 124 +- .../populator/ItemRegistryPopulator.java | 4 +- .../geyser/session/GeyserSession.java | 6 + .../bedrock/block_palette.1_19_0.nbt | Bin 0 -> 46005 bytes .../bedrock/creative_items.1_19_0.json | 5437 +++++++++++++++++ .../bedrock/runtime_item_states.1_19_0.json | 4530 ++++++++++++++ core/src/main/resources/mappings | 2 +- 9 files changed, 10066 insertions(+), 47 deletions(-) create mode 100644 core/src/main/resources/bedrock/block_palette.1_19_0.nbt create mode 100644 core/src/main/resources/bedrock/creative_items.1_19_0.json create mode 100644 core/src/main/resources/bedrock/runtime_item_states.1_19_0.json diff --git a/core/src/main/java/org/geysermc/geyser/network/MinecraftProtocol.java b/core/src/main/java/org/geysermc/geyser/network/MinecraftProtocol.java index f4afceb21..a7b2ebd9e 100644 --- a/core/src/main/java/org/geysermc/geyser/network/MinecraftProtocol.java +++ b/core/src/main/java/org/geysermc/geyser/network/MinecraftProtocol.java @@ -28,6 +28,7 @@ package org.geysermc.geyser.network; import com.github.steveice10.mc.protocol.codec.MinecraftCodec; import com.github.steveice10.mc.protocol.codec.PacketCodec; import com.nukkitx.protocol.bedrock.BedrockPacketCodec; +import com.nukkitx.protocol.bedrock.beta.BedrockBeta; import com.nukkitx.protocol.bedrock.v503.Bedrock_v503; import java.util.ArrayList; @@ -43,7 +44,7 @@ public final class MinecraftProtocol { * Default Bedrock codec that should act as a fallback. Should represent the latest available * release of the game that Geyser supports. */ - public static final BedrockPacketCodec DEFAULT_BEDROCK_CODEC = Bedrock_v503.V503_CODEC; + public static final BedrockPacketCodec DEFAULT_BEDROCK_CODEC = BedrockBeta.BETA_CODEC; /** * A list of all supported Bedrock versions that can join Geyser */ @@ -56,9 +57,13 @@ public final class MinecraftProtocol { private static final PacketCodec DEFAULT_JAVA_CODEC = MinecraftCodec.CODEC; static { - SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC.toBuilder() + SUPPORTED_BEDROCK_CODECS.add(Bedrock_v503.V503_CODEC.toBuilder() .minecraftVersion("1.18.30/1.18.31") .build()); + + SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC.toBuilder() + .minecraftVersion("1.19.0") + .build()); } /** 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 5ae6fbca9..07fa19bee 100644 --- a/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java +++ b/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java @@ -164,6 +164,7 @@ public class UpstreamPacketHandler extends LoggingPacketHandler { // Allow custom items to work stackPacket.getExperiments().add(new ExperimentData("data_driven_items", true)); } + stackPacket.getExperiments().add(new ExperimentData("wild_update", true)); session.sendUpstreamPacket(stackPacket); break; 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 55782447f..e811a0a62 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 @@ -28,8 +28,7 @@ package org.geysermc.geyser.registry.populator; import com.fasterxml.jackson.databind.JsonNode; import com.google.common.collect.ImmutableMap; import com.nukkitx.nbt.*; -import com.nukkitx.protocol.bedrock.v475.Bedrock_v475; -import com.nukkitx.protocol.bedrock.v486.Bedrock_v486; +import com.nukkitx.protocol.bedrock.beta.BedrockBeta; import com.nukkitx.protocol.bedrock.v503.Bedrock_v503; import it.unimi.dsi.fastutil.ints.IntOpenHashSet; import it.unimi.dsi.fastutil.ints.IntSet; @@ -61,51 +60,94 @@ public class BlockRegistryPopulator { private static final ImmutableMap, BiFunction> BLOCK_MAPPERS; private static final BiFunction EMPTY_MAPPER = (bedrockIdentifier, statesBuilder) -> null; - private static final BiFunction V486_MAPPER = (bedrockIdentifier, statesBuilder) -> { - statesBuilder.remove("no_drop_bit"); // Used in skulls - if (bedrockIdentifier.equals("minecraft:glow_lichen")) { - // Moved around north, south, west - int bits = (int) statesBuilder.get("multi_face_direction_bits"); - boolean north = (bits & (1 << 2)) != 0; - boolean south = (bits & (1 << 3)) != 0; - boolean west = (bits & (1 << 4)) != 0; - if (north) { - bits |= 1 << 4; - } else { - bits &= ~(1 << 4); + private static final BiFunction V503_MAPPER = (bedrockIdentifier, statesBuilder) -> { + // TODO some new blocks exist in the block palette, but don't properly work in game (mangrove leaves + mud stuff) + if (bedrockIdentifier.contains("stone_block_slab")) { + return bedrockIdentifier.replace("stone_block_slab", "stone_slab"); + } + switch (bedrockIdentifier) { + case "minecraft:mangrove_planks" -> { + statesBuilder.putString("wood_type", "jungle"); + return "minecraft:planks"; } - if (south) { - bits |= 1 << 2; - } else { - bits &= ~(1 << 2); + case "minecraft:mangrove_log" -> { + statesBuilder.putString("old_log_type", "jungle"); + return "minecraft:log"; } - if (west) { - bits |= 1 << 3; - } else { - bits &= ~(1 << 3); + case "minecraft:stripped_mangrove_log" -> { + return "minecraft:stripped_jungle_log"; + } + case "minecraft:mangrove_roots", "minecraft:muddy_mangrove_roots", "minecraft:mangrove_wood" -> { + statesBuilder.putString("wood_type", "jungle"); + statesBuilder.putBoolean("stripped_bit", false); + statesBuilder.putString("pillar_axis", "x"); + return "minecraft:wood"; + } + case "minecraft:stripped_mangrove_wood" -> { + statesBuilder.putString("wood_type", "jungle"); + statesBuilder.putBoolean("stripped_bit", true); + return "minecraft:wood"; + } + case "minecraft:mangrove_standing_sign" -> { + return "minecraft:jungle_standing_sign"; + } + case "minecraft:mangrove_wall_sign" -> { + return "minecraft:jungle_wall_sign"; + } + case "minecraft:mangrove_pressure_plate" -> { + return "minecraft:jungle_pressure_plate"; + } + case "minecraft:mangrove_trapdoor" -> { + return "minecraft:jungle_trapdoor"; + } + case "minecraft:mangrove_button" -> { + return "minecraft:jungle_button"; + } + case "minecraft:mangrove_stairs" -> { + return "minecraft:jungle_stairs"; + } + case "minecraft:mangrove_slab" -> { + statesBuilder.putString("wood_type", "jungle"); + return "minecraft:wooden_slab"; + } + case "minecraft:mangrove_double_slab" -> { + statesBuilder.putString("wood_type", "jungle"); + return "minecraft:double_wooden_slab"; + } + case "minecraft:mangrove_fence_gate" -> { + return "minecraft:jungle_fence_gate"; + } + case "minecraft:mangrove_fence" -> { + statesBuilder.putString("wood_type", "jungle"); + return "minecraft:fence"; + } + case "minecraft:mangrove_door" -> { + return "minecraft:jungle_door"; + } + case "minecraft:mangrove_propagule" -> { + statesBuilder.put("growth", statesBuilder.get("propagule_stage")); + statesBuilder.remove("propagule_stage"); + + statesBuilder.putInt("facing_direction", 0); + + if ((Byte) statesBuilder.remove("hanging") == 1) { + return "minecraft:mangrove_propagule_hanging"; + } else { + return "minecraft:mangrove_propagule"; + } + } + case "minecraft:sculk_shrieker" -> { + statesBuilder.remove("can_summon"); + return bedrockIdentifier; } - statesBuilder.put("multi_face_direction_bits", bits); } return null; }; static { ImmutableMap.Builder, BiFunction> stateMapperBuilder = ImmutableMap., BiFunction>builder() - .put(ObjectIntPair.of("1_18_0", Bedrock_v475.V475_CODEC.getProtocolVersion()), EMPTY_MAPPER) - .put(ObjectIntPair.of("1_18_10", Bedrock_v486.V486_CODEC.getProtocolVersion()), V486_MAPPER) - .put(ObjectIntPair.of("1_18_30", Bedrock_v503.V503_CODEC.getProtocolVersion()), (bedrockIdentifier, statesBuilder) -> { - // Apply these fixes too - V486_MAPPER.apply(bedrockIdentifier, statesBuilder); - return switch (bedrockIdentifier) { - case "minecraft:pistonArmCollision" -> "minecraft:piston_arm_collision"; - case "minecraft:stickyPistonArmCollision" -> "minecraft:sticky_piston_arm_collision"; - case "minecraft:movingBlock" -> "minecraft:moving_block"; - case "minecraft:tripWire" -> "minecraft:trip_wire"; - case "minecraft:seaLantern" -> "minecraft:sea_lantern"; - case "minecraft:concretePowder" -> "minecraft:concrete_powder"; - default -> null; - }; - }); + .put(ObjectIntPair.of("1_18_30", Bedrock_v503.V503_CODEC.getProtocolVersion()), V503_MAPPER) + .put(ObjectIntPair.of("1_19_0", BedrockBeta.BETA_CODEC.getProtocolVersion()), EMPTY_MAPPER); BLOCK_MAPPERS = stateMapperBuilder.build(); } @@ -171,10 +213,8 @@ public class BlockRegistryPopulator { int bedrockRuntimeId = blockStateOrderedMap.getOrDefault(buildBedrockState(entry.getValue(), stateVersion, stateMapper), -1); if (bedrockRuntimeId == -1) { - bedrockRuntimeId = 0; - //TODO remove - //throw new RuntimeException("Unable to find " + javaId + " Bedrock runtime ID! Built NBT tag: \n" + - // buildBedrockState(entry.getValue(), stateVersion, stateMapper)); + throw new RuntimeException("Unable to find " + javaId + " Bedrock runtime ID! Built NBT tag: \n" + + buildBedrockState(entry.getValue(), stateVersion, stateMapper)); } switch (javaId) { 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 39321ae02..65d416065 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 @@ -31,6 +31,7 @@ import com.nukkitx.nbt.NbtMap; import com.nukkitx.nbt.NbtMapBuilder; import com.nukkitx.nbt.NbtType; import com.nukkitx.nbt.NbtUtils; +import com.nukkitx.protocol.bedrock.beta.BedrockBeta; import com.nukkitx.protocol.bedrock.data.SoundEvent; import com.nukkitx.protocol.bedrock.data.inventory.ComponentItemData; import com.nukkitx.protocol.bedrock.data.inventory.ItemData; @@ -66,9 +67,8 @@ public class ItemRegistryPopulator { public static void populate() { Map paletteVersions = new Object2ObjectOpenHashMap<>(); - paletteVersions.put("1_18_0", new PaletteVersion(Bedrock_v475.V475_CODEC.getProtocolVersion(), Collections.emptyMap())); - paletteVersions.put("1_18_10", new PaletteVersion(Bedrock_v486.V486_CODEC.getProtocolVersion(), Collections.emptyMap())); paletteVersions.put("1_18_30", new PaletteVersion(Bedrock_v503.V503_CODEC.getProtocolVersion(), Collections.emptyMap())); + paletteVersions.put("1_19_0", new PaletteVersion(BedrockBeta.BETA_CODEC.getProtocolVersion(), Collections.emptyMap())); 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 13f00e68f..e4d7fab35 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -64,6 +64,7 @@ import com.github.steveice10.packetlib.tcp.TcpClientSession; import com.github.steveice10.packetlib.tcp.TcpSession; import com.nukkitx.math.GenericMath; import com.nukkitx.math.vector.*; +import com.nukkitx.nbt.NbtMap; import com.nukkitx.protocol.bedrock.BedrockPacket; import com.nukkitx.protocol.bedrock.BedrockServerSession; import com.nukkitx.protocol.bedrock.data.*; @@ -1461,6 +1462,11 @@ public class GeyserSession implements GeyserConnection, CommandSender { startGamePacket.setInventoriesServerAuthoritative(true); startGamePacket.setServerEngine(""); // Do we want to fill this in? + startGamePacket.setPlayerPropertyData(NbtMap.EMPTY); + startGamePacket.setWorldTemplateId(UUID.randomUUID()); + + startGamePacket.getExperiments().add(new ExperimentData("wild_update", true)); + SyncedPlayerMovementSettings settings = new SyncedPlayerMovementSettings(); settings.setMovementMode(AuthoritativeMovementMode.CLIENT); settings.setRewindHistorySize(0); diff --git a/core/src/main/resources/bedrock/block_palette.1_19_0.nbt b/core/src/main/resources/bedrock/block_palette.1_19_0.nbt new file mode 100644 index 0000000000000000000000000000000000000000..8c095ad027bb063c35d9c2a67c3d3d5dffdf7925 GIT binary patch literal 46005 zcmeFZXHZnZ_bn<>U=R_3AxaJk3{irBl0gZAC^<+DlA|CQ$wA@}1q1;_B@8)B4nvTj zfaIJ(hMZpy{BFJb>fTrNZoR7e|8o7XU8j5ZaQbwgeO9mC=g>vq-MIQkuuzZhKCTc~ zt{fh>iO{cjv%Th>a;`h|HN#`X{`9^uF@CJ2BsMiY*EgT@n=uHyr-bw*p%U%AYy1{^ z@E~e0iZEzGGw593OIdWO2P~;ls|iuH#1yPg$oYKd+k_v}%rDx~6Q#S>7vx zYNI?+*%R&KpVO5M?)kh>DY#T-E9IP2Vg3F539D?%()#L1QGWbm9d*ec{E|OXvi_VO zJ|sJ9kSXiKE;pyuX?$au+vY{~ifUc9#z4-jMo&nfQJ4JKu731VSm(1W-?WC#e&rXo zA4gyN_dZ*A4la8RLOln$_dXl0J#8F}zmR%~bG-%OCNZ5AJ81WpHKJ2^-8)B(;xM zjlQHaj$M|Wr@ovU$bIw3L-X=oS%Fi$Oww;}S(ZfmxczhA#%Wu@S4ZdGV;Ay#j`dwW6@_m`*V*n z8*>&kxwm%DRK)dtJHk%I8s}TRGo~HqDwf@Q*0+Tn$9F}S_TAIbP5+*Wsi0fi`rKo? z{(+9Vi|D%}$7d|_7Y#-&Lr!T$IaO6*OCB29s5N(Lx|x<&Vnv$FT8h;zriqWas^5z$ z!SxzwSruWEMDZ+1w!W?jAD3m*Wi@vm=`inPSKo6!N_wDSpwzdn(`Qd31Wt}M!2x=o|9qmy8|EeLRG7ZU zq|dVMLBhqc4@X|6xzJ9wYajINMqnpf-xMAq;u#|P6^E6=T)7~@DxpYZidnWGu_%^o zop}?5(N~7mQ-*a_5OW)NCGPr>WzDJ!9&cu&C>9?zZgQ4BeBcsMRTYh@La@|sRyfu^ z`sn3-^t9}L9O66D|F@RI9&NK@XOW~Z(W=t>`4|mZ0Q3Pc&$CZoRhW+oWqLdnDm?e! z1L^3>U^YYMuDqTHi)(-0HR82cNm~l|O}O*uk*}WBY+*f(Ko&EmLXKd-cs@%YE3!^^XAyZY~@0$cB8aw1!#i0B5`7e?kLIZl*ias#FWxd=l%ar#!Tn9r3PgF?^1I}Q+L+p1*SCvzyx%b4Z z*xggNZ(3S=sql4S33PoY`o+AwijlhTeL^cs@lVA0$+WH4h?T?>0XygTw^LObJnfch z`Vy&!`yV?lsXbpp%NK>l^x60RBTzONt0;#%)_~!=&KCV z?jLr@Fmhjwe40g8`m$H7i0EB06}QII8a>-_ry<=~^%@6t=EnJ{aMU!D2mZXwRDqPgk!#{L7JSC~@7VT^`-Gjl`M$|*y;3_bLq;jH8Rm~KEd4_cDA!fn>l|0?4D~*kUYc0K zcU$?|_{-u#s{btL@gel2*>Giu$!pF2{RfhhJv=&=z12I9pP`Eqe&x#_v45Ieau`5{ zjMKoV{@M~jZ*2;OL_Rca*bi4sQ!6TS?{Iq6R)fnu2%XmDvL0U|7NV}<;yS>*PR9u zP=c?~bt#pNG&z&)nQ^iSzR#em{l9&C+{aJJfAz&5e3N@f-?wCyW0A=_pD@lixj{#H zF)^3Ah`fn$uw_tB)+OEmF0-ij!+TyF%e5Pi9%#y@>OIl9cy~wh>1p!ImYsbu1Np_R zr972chqkX(bMyV39uxhW{Bhw?h3%X_U@1t>!jKKY`{8dh>?<9o$^AbyTW2Px!-5H% zJ=Naf$G_Q=4(iH1Df-Yn&N$_=vG>pPNmz&G6My3V%J0Ot9rNgn^XRgfpbPg|k|1Hk zwAC?q1F-<~A2z)Z=T4AHUkyoK4O!_7+Vl8C3j79_gA_yMinMDQx^pJY@9^8{Q)hlx znlrnTWHztzPk+DE^0LM9UFB0&ZfMu5I%EZ(b2 zU-rL^zVKM=e^MY1kvBjbnGdD>m6M-WHh{Yie5$r8`sMLYs3VZh^V5WFWITbDe)>y= zT2zR6z(MV!&C^YHSrXfO_xo74=^9pQPWk)(+95)^oHW`zJL7~#TTHvg*NqShz56`c zs6U>`oMQz1O7M*kN>)X?_fM4I6WG4VoYfc?JlamXr@*iM5VTO<4(W=cp1K{+B2;Uy zS4nQ=6<-7m;rjQ8TRcifre2VxK?U}?|7$Mcz;YRkXkb}@53#2|QX90_*5Etx(3Ziw z@6hncLnkdxcab-OJ7+bIB8EH;ZKrl~?A#*ya_(_?a%uiPU*A!dQ|Z^JCUBg1?p>ry ztE+4}t`b9+q3o?$yYDn|ZhQH4r{3GgL~cIC|1oZMBeTVinv-=mS53Rg<(cz!(ew{B z-Kg>I9UGMGyn5r~7Ld5Z`qNK-J{fVnbdLdO3QwM5u`>!*^#k-fiXFKPgQCt78`Xq=4E%eQAuEe)UD`e8#mpWOI%-+Yd}WRGIFseUsj>=stVq z@PLct_)f%7B^7r%U5T*wI!YRqLz!9jQe$6bl@M-QldvCU^ z;igdH%s~zRs5@4?F=3rqss3bnlietD*)5^C-&ypTmYZF9|F~K+!ugx`R86q$M%%k- zb%D1<%NKD3nQ>*1a~6?tchP5Y>oRC0HqETvU{2-#9W?_kof*@0vdaE1%~?e^O6wfXeWIRv{6KxH_qn`qJ47(E$(bABjsWv+qF!K zsjnLQ7r!yAPm1pgm(QLdYKZe44^I_T8Ul8U@9270PO|r&S2dnyEU)j+N;UY#h(4Qh z(tWzPzVLftgw5CFBXs=LY0=C0pF5f=9o5Q@J5p2{CNA4qxyKB-*{Lj;3$pbSzOD81 z4CQq$iQ6xauT3{ArQJ)l`|~%1`ha;gsn>Vvb^gJ1I$-gX;dgB+=c z-JiM2RP-IRX@Q#JqD z)$fREpXBXkijJ-h@~8Vg@q46yf^IO;1r85;np6^f#?C}B+l{9%rnUZhWqb5fz2Uko zU>j~TwcD=UgQX144ukH-qo<%%rqHMrXm#21NhJZas=e{+e|lmHW&Je4<>GghHK3p611p_2Z!4! zfgc~7BaYp%8N~%OxcnKxx#B+@piut!;N#&$*B%BhyP5k#q8XPPvnr_# zt7o-Xqfdv>y~B8((y&^$Oyu6YN4Pvqr%*PkResYG^o(`L#6-X`)nSUCZO|N`a2s4b zjJ21mlzqNS4s43kE*H)>MfE*{cen9X^A#IGi(pZ0aF`)7`gM>y%~zftQEj4Z-%tGI zlShB5QhZcz*?ojZe_GE{H0w}ai22W(ekyU`5-s0yO9g-WiSw7cxrTz5up2JfVC=-- z6c2qi6x{ZZ{>WUPeSCO>?^NWk0LImc4a=JFU!Pc6W=>b@eFUWg#us(;1xji8$muTK~?aXu(_lRA9bz3H%yWN@Gkrtn0Gb zvgEV%w8ZtgvGPAovfXV=3ASfNmQ$s;qRLm3WBBPH2USYBuXy%i=Ai6}Ga{7yc#BUl z``AubcGM=0u^^P2jy*rVa@VkTk)_uB#dkJ5dE*IY}u=Wo+ zz4HAMl0M~IXHXTG`1J4ghwjCS)DJnx$%>QGPrLiGYy)`;-6zN|PnK;^vkx-z*Uicl zB3jr}hA*iZI@y^mOt4d;?kspk(nGT)^GqUPjG-GVi~*g|{~f>+sqqoU?V9`GDDc63 zEZb7Xe4&C^|hSHvqA0iS;@S0KI)n}S22&6v#aW~ zMVJZK^%tslKDe#H`aE}NJfRI9_#n+MYlUfQc zdMgfOB&RY9_vaqSWMCFbEr^GIBlftBy67U1Gbw9$92s{0@Z9)v8cWsy7V-9@T}XFb zZBp0+lvgd)$tQ9v13a%U?{i$j&nN7_q^23pEvRLPDoo`_lUJg3y1ECAtSol zHVYQ-mM|MEyjp{|2pCMYB2DX~ZidzM4K5a>_9G@GvTB);sBuZEWo=LX4fS;U!To)n zptW?yqNFNA81jCcX)5%s3}%sZ&S|P9OBDXZ17Xg2xdxFUXHjniO7>a zzqq5FolU*6o;gIMprZ+2HqklvraMCj;$O@-&DR_0wYwg%QwfQZbSRJ0E=TKH*%x+m zYd+!z{hA)Tu-V#g0)XvN_)4THX23=;~{mQ3x`Yf_Vc8I`c>72CJvRRpYBJmeBjyjqwERN zT9MV{lQ09lytZ_`qLpLG+YyN7>>aU;`~_>7Cj*-3C48{C^@EI4i*S-^U)BdPr^|FN z=@0v5ahxud%J>hX${TGBywz^aUz}gu94N(^Nvhr7uQ7X?9kOuTpsu58KRwHp@9wyA z6G|%P@&Sq8SMcUmi`CQyxm)Eyp>NRkv}K;H+?4Ho|01*$49mqdEvN6K(gF&{e5)eEA8Uah;kQ%gsA( zT@`M-(L#5lt9UC)Od0wD=Qo3GIkiJeXS8%*>(+W`2J&r%@4U!WFdM%+56-K*ib)Xu zpz-CObDr0T8_Pd;+)66ooORj`Wk0_Cm@IDT^`GC=u;qN^$3J7K`;uCbZ01bph3JkE zv2KmgNDg8va3?M|%xnUGo<%XXy9O!<=j_*7n&f$1Lu}DJa1y?m3vqzad@FyuunyOJ zu%1D|tsS~MqqW(#6c;26iT-V9vwfg{2U*20rN|fL3?AzYgYfAHZc7d=UD}=jsv^J{V$QHraw)s zjK|!%{JLIz=G%(>!Gh$6yM}|la?=1+9q+t#Y>`n(1O zq+e~`8P~mBm85iUZGW+t)Llb|t3*CSBdnudQf)fh8(^|enpSHRl7=P!hP?v*;3uWS zcOT<7Ur{`l-tO;pUghuUyQD1cuHR%_E2jGp!WHhKZuiY3C8R<0-bu+xQOILil zdt8Ha8DCE(7C&EPCXgI+33Gf5yWiWI(ASm#YfUf+y zI!fR5mMarR?K9K$4x>MjC`KS0G2S+gC#+`I$ShW#epAmqoE3Z;A=@Vk1yWyrxC0GJ zi6mM&!_s?RNxu8`9eJ@QGBi79#EzY30x*@|_uZkr^ZSf%rpD^U&P=!Oe6weHQ+?NY zAeF%SBffPncKKE#cOT-$;VH?$qr1bYu9gqC`t0ZS5uHz1Cr*>6X>Kcz&<*j`_Y@4# zYm=tq#I(D57)*=XQfnqhcw{WLEzG$k+QnmFa-*`PsIvc|SPfX$ZN((!T;VXy#2;O5 zfvQA8^;o2RrF-U`Y{Ju@*Vh?3MxX44yw$q;Fq1(t&Z6%qM(RTt)$?4&+)sMlV)E8viJmbgW=?gz za$b3Z+_|}WxIAs1?PUqdXHWldFItWuOWgQ(JnQ%Ht=Qu+luCT=-&!Q`4cI5J>iWOL#3#x82yt_Xvl%&T9U#IRXT6KL46_dA_O#dQD)&2RGNqf8cR|PBfB))zI>gT!l zKHqs}d%CSoTz5Fb&sPHde8~r1c%`)q0LoXgVBrAQstB+mzltO{1KsimVA<*??G=>1p|}qyq&4KE%4$&Zxsz>vyZzPUJc}+Pi%|r zznvH^`}K*b{?AX0?f>n>xU@eSsMC^s{-o4h_C)(XV`|fNHKuuD_-EMQqP&1%B^!h8 zb+cYDgTpu`|4h?*DXMPM8|vTDy=~2WT`#4BV&bbU))8X%ObB+mKRj(Jo|2jzjJRJ0 z`L<*F;6* zfSf}%Q=>)xlrf8+BQ6O064G_ER$Ul%AjHJwFNHKd=X6 zHyk$4*H>}dbJ!omle!;1MV*5ig}YgDWecqL=e{@G?OGoBc=KX+=jSUD-@0#hch(g3 z_sML+KXal*N5r$NoriTreMc>{Dk-oL$3KF}W(!>yTujf2tSLR5UL!l>19jyxXlD3O z+%AiTYu$~5iI-BE7v+U#)cVJjH7In^P@->tmFk9gZ%soM*>U#v-1}H=7ntCyXXV4;Zs4!w}AU&ZQc^&ZJ6tV+a!Rb&ek?#no}1Q7t?;!)cWVOPDU;?^ezae_o1PYnrKx~@z2Q(O|1?3 z3#4-w2j|-xmy5Y8WaNASm#CKq1Q5`3l*SPOgu2`Jn8Q1$?bd9g7g=L-cJPj&57N-6 zB;tfSt6r9rkb<~A8B5w2j(9E6<8+S@Pv_Tr3^hnK552J(HE!#VnHIklvnUGUs;s+M z+3+%BiP2^Q!ce`bNQ|bODqcS)3S#j9YJOc}EaPAYlVC+-iQ$9EfPq@md%?+)ns} zAz--2xcz2}cinUBrKQGWTU~`tVn#h`2X4yt{Ed3dY`kQ*$H3t1o^v}arIgxRq3&#Q zMLOGU5>&Z`0NA{=B}YfX{|>au(su)12 zGOpOFI;+3rV76xNSll@`WH4e9hS_gl65vy{IePd2&y~1nh-JIWtG15Q%C%hYmxa>{B`*JdiiruWG?YLOyH6Jc z@7_;eZ7xp?2BstKS~GA{?1CQ8Lh!(-r@*{19Ho!ATiUqkttl?e8qRQ9VPGzomWE1o zFc8*ibubW>yacF34;aL2U`kbiDY68n{K~}!po*&sQ-I1GfT{EX=27rG!th_SQRQ~k zcX+KsCk&@8zuT3FHXXY_f6 zcj3jcU}_amWvpU4(v#oRedDne+g{#rUuYHZe29aX(RnyhlL z+u>a<{x~8deHeL((z_rC*B|tCyk}cFC%Slxf}}nHE6|u6@mitB_#Pp?PTzY5HDnbJ zv++~v;8w2fmY5aUC<>CQ^t;m8+4X5Pk0^b{4h#N&o$qv-L`v9B9BE*A&&G9YVRp|?a#X_ruF)l(p_?jhb=)k zay=DB{*Iz2#Xnb$_K&SiDfv00Hj%vSr1g3a&#p&Nl9R_A zPiW~YGdV@Mx6slLc5(`E*Y9eQLkMYFqK+R#;si&{x1Yh=F$1BlCJMRhT#P z3^S;RxMRV6Hwq?4<5>-pqc<-B$h-*{%PwH7zXD@C28`X6%Pc?+R}}*Q*{lNN6a>s$ zQXyPbcC2i92NQFosYDO4U5`U7Vd&omYJPo2thsh4lM0Bb#0-U9kCO)>9(705710Sy&)@CG?50aThmyR`hqbo}QcI`3RezqHZv{5HO@gYo zApp)TZMoBt3cLfYzUUtSuL(y0MypiayC{N4$vUP*ZmX05F3%k%M31nc_U4*%!irw@8qp9 z$qW<8lW`OzVARd4*@Ii77TcAQ+G2k4P9)DZQ;-NoQ}Y{ANe4hTm0QQMWIhSqxoPlS z=nkHC0YKV?LU%&6iviO40*qD}FuGSR;K>l8dsTq|NT&)^=rsUD+X|w0Fb4Wo|CY-` z5BhCZNsNnaJLRhl3&b#zKIR^h<)H_6x>*%At_(s=<&t3O%I_1Cdb3+Nc)jh zYY>)~tBbNiwU;=Ujq?r(@KfH@OBpW-7sb3iZU>=SbDE5#HgJ;wKW)86%Gf-u5QKU$ zO@)bQI0v%}VaHrMX5BM%Cr$!RZq8K5C|_F0ooF z01%su2t9^RijQD@rM7aBd3B4J0ZAx5g-)qF2%dJ2D+Vue3`TEBIgNwOX;tS}y!a7H zT=!)ka}K_1An_|;2@5AO^x42ee7QouEXZ>j>SAW+U*3 z<4me?_!3K#v?>K95)7E<(_3ox2R&bk&=X#<>G*9>DLt;#I^Yz9(~r{gXK+^1)an!) zAtUD>aswRZpS}@BX_ThcXmlUoE)Dwx5oxRS%>hfPMa5reCp5KY><&0MLEjgv7s$xP z{4P;1_6Q)9O}-uv00RO;@4?{}6a+edme|ld7yQq#AsmpRmLu-Q#iHU-*>mWxDMkWZ z!cc=Ae+FJfZ611ak=wY~T$as#UxM@~h)cfQ!kW|gXC$$QkR!y?`xSG!3oPixF;+IQJt{j$^`^;!pf@(5c3Jk zU4W?qfu9h>cTD!+*`Hv(m*(=&pyzuPaWEF>bP6nR_BELAUM6b^=Bt-xFJaLFt!8~!WR^dD`u68j%+FyXt zECWX86EOM}phEYm0s)Xt6)4kf0Eo85ag6)zZ1K3eo(5817|rSIN+2QNR!8WqHGh(G z(#wPB3y=_nIHAnE8_56W$J$wX)ONNyw$y% z8qkybH*woIO`Bqp+r%hH%F^+rv*C_L3axR1gkicvuD~v&H+}#8oVXQEr1#SUtLVWOmr-Vf^7|mDl z?&g9A1fb{bcOB*a54-t4?B@TloBxgMCQ~tR$~*rX1|%Y5`6s4{xpr}Ja>_kUPRl}k zNJQ#Xt;iaakqkI{J1lofMlK#kAK6WoPU0hk%GBT?eCyJ7^@;iT^6tvP@b&m%S z^{<2kbj@knTyRNAlehe}i+t=hH|));U*qBsE%hoT^<;HQ)}_p5Q<4hB2=N;V24+Jy zjW>J}`Xbq0tr%lxL)VREjNxm>*v9a6W9$I(4Nyi74jIWejj`u6&@M>;VM5UraA2Cr zw?J*uHgHA%L$@BP5~F8 zH{?{}kwUwA4m8_kz2K~g_t_oB(iRh0{z>u|6(hghi&)2sA4+`ko0-SjmDmM0mTBl2*3 zQGnfrG~c{B3l}GPVR$2HIP0I;DXo8n%)p8}c5~9YyG#K2x;y%EyQ8lvD1)!LV@ts| z-LWx8&@Rv|u+t|AT|o}Y=HTE^N)uFEt>k0{u2*vJuUB%=U)L)+)PGiTV%IA>OMq`c-HR;p^d!guBh%DH?_Jqg$PxOfqFTeZnZAfZuj*r%GI_-W7Tq=jKLehG)1f1c?A^y4^#c z(&DO;iR6yMv>+U?jIXN)o`B>n9RtrM#hQ|Xnoqpc59~X#{^g!gke9_U1O|{ho2m{w z!3ha;+v6n}6jS-w9XvF_ZDEbf>Rj}qB(2Ee4V;6!nyaqN{UHp$*Pb@UohUgg{g(e* z8y~wRp}l#f9&XUBnO;t4Pu9;Su&9lrBozr2;@1-hoWn(#FCoFblC2*pahlHV!izZ& z;mXU%tLVy$$%_O=65_^-sRjY)P6R-X9B3CLK>k-1iU1iw+<7r$k-%KZ7eRd2@`cj1 zd_mrIEnl$kUCS2|*YZVD$F+PhM?oSs9aS#Q-r)n^y7;zZC#B!31?UYoIiNS;XnJD| z=uMOspf_~nfZhb7=}j}BH#|mw-iU*88wfd|H&_rrZ~U(54YcK&-aIq9rZ+*w*Yw7$ z_?q4@YF*PCe9minbAudBZ|1~EE!zG|=uPXE#oYH~RUkgnyak#iy(v&CX-v@)ra4eA zX)Heh^BS-q8k;K@AYszjT~z?}lExb7m^2Q@z+5foC~&WqbMWTt<(w47^>U67_i8x@ zZMt60kx*PO=WbvbTbvdhWZ#>}V2;M+h#&;*TEr{zV|}+?hyD3eb9u)-lwdg4SSJ zqpQZr1C*IJAY>eKMd9FbueHZiu&WiDC>$C45EAHg#{lU-gpb); zQW2;$3tcfWvdWYsRRJ8*%}M2E3JU=ZKsp#qW^jav@-w@5ya|@MJ>PrdnVG^7@l=mZ z2_ZgJOBy9CiNOf#E&mV>KeGdmy?L!^unf^0nEt&nRsMA;=LkxYdK)NHp8+eCex&f8 z6PWrv#sKvM0P`yjnBf<|v?73+xN>O*Xy&Q{+$X}LgTO2h0P~OCjxb9V7p-0Nz`Oj= z+Qlp*B{5pNsFA@%YZo@qPCvAEv52A|2HHibAq`f*^0xbQJ9cGB*gBvyO}jvbfuxiJ zv8J;JC^W{`3XKJjW&Dm$CvOIA)_|&iL;$w+qIDe01JFvXb_3`*Rr3Ir1RiluZ&O1E zfLwd*F|DPF7OY23+XDgww;RvufktD)ez~{<)Eu;8YY#lbfoARD13Wk4E+AHoBpz77 zGTe(lvyy{2DM(6_Z%PNi`Hd8Y`Cx=$T7$t1j>uEM_|=$#v0=+Vip2RrK~nJ@D$NKL zGEo2*pvOmqFbphawYfqW(4nrDg_jvU>P~8eVPG+v0*hckFJ@bUc$v|Q*#?1NZ0^5l zUk(-0&j%@p|M!cPyXTtYyLM;tbLi#N=qY!*&M^nGTgE9tc(Pf86r;Ik5m?gx;b1n8 z-X#c2vagfMcH7ryC=nekj47@z1mzX01o(g3oP%07Evu!ZfQHckF<>YGYdW89eTF+& z!Z5?O!kFYAqA=gw!WguO(IKU&fL_$;rf@J@l6EXscao9Re4aNJA2)BY?AC?RzrEid z^q$kS#xJH#4@z8`zKIzC-_e)&8P^WM)1C6bXo}F`rneK>#sMlrgWngkNhonu)j1|w zs6J3Mkob4w0%<(}!2=S;7}q-tv}gy17)qdZYL`_=D0QQ zR!}ehzecLJ5G_2Yq5W&l2-GjmxA0{G!W5I5W~rs>LclI7I5;hXw+SH0wsn9-x)>NW z?f%fzno!y%BNrI)3Xyq4HACIV7rcL31KJa|CH?=G$k*Fv*j zsH`moab>`5tn8$R#u76DDukgrgW(uPkaxWFP9FTY*x>PgqZ_C@fYI7W5{7~`EF}zR zJYWr*7hx=cUcb9w3Cf|#AGtRUcd*Jx(Z^R8n|8$dBQ@9r8U zvjCHo3l9Cv04jcnb_oKg>Z(E(pf9<={3HVvK&XXE@Dknxw|WX!&@4R@NWld0(4af* zLP>ZNWM;--0kaO^K1Z_f(4aFjjW>c@`lh2AZsFU?lZ=3TlkqZ8Zb*6G0Ock$1!yww zd(f#U^FAQg?4ZzDs=rqWELxC?!cVIOa!t<$Xcgdw)_3eW0KA&<(?F#`E0)VZwz-<} zAOm$JSsnt}=4#FZ+2%^KMCYo|ll~ZZqD9NBD7ghLphzYxOG%OQ=}UAP7eYd{``j=j zkw-B4*H7nh-g9l&`OV1wfD%`xA7TcO3m8faBeo!TdJ{ev=wUx)0hy~CmuBTFIPW88 z8aLn|e+9$~WDqw!7wx$>au|uCIDsw0nF%CMI1oCnt_=>0fQECcLz}et0!jo_D?a^|<|a7@yPhPZq~w4)*==yG(-Rm1^mjV}%(f6~Zu` zU*QZ!NKam7CrAEZ^u*st0+}oDg#R5tLBju@x>T1$I=f=KofFy?gC@1B2nrJLfalkv zkZx{wG+9yv4~Xpgu*v7G+Pt3#>cfQp8P|tNbiM$n(+QZK0APMe0rL~M36Ea6AOM=U zs)z$#XDr+}6GW!%bQ7 zD)FZ@w?Jlz^CmeJe@6gLd(ZA`e@T92t=GeZP;v_1@nD?x&6O6+oMq~gpFdMn0B)rXDM>0m^GeT=yO}Gjp#FddYkL|-LU+tRhPsq7V@eW%U_jep(#>EUmj^Ldn0Yx2`;Sr`bFEY_{zs`6#>MWR z-foD(w==mr0@zHz@}@f-Io}(=W@1v%6sG5j!t?>&f&p?^w+Y6t5?Hi=1BIv60;2P4 z1GLI^8v{hgp##9HWb8D^K%sT|U66sg%EqE|RY0>oeg{Yl`Y|^T=nh(`pF-!V(D~Ri z;5o{24juGiLE(a2UAMm^FGQP%*_`)wFgBM(bIcbrJqnVN&$p!K;Db&=@q%BUTpGO%AsAw! zfZm4SWkrZ@P$s0d9V>hl_W!rD`Q_81isi}C53Q5F{0;i~-_8lbJ}x%|Fq)?nfp|Z~ z!E9Q%PY{+eUne!UNDV@@zPF~r22lkEvrXYTD7USV3UJ%eV{jDJDZJi<5CG~yekRlD zdJlqT31C3$(MZFu*IN)uevy%Y1Pw}K>3RnO%qi$SY_&?bzk-rC6$J--YPy{n7$7My zdQ;vJoK{YYTE8qaFDP;G=N-&uxH}*(*?%CRx_yAQKvKbG0_{T_Y?xi6A37y@9tR}` z!;a9|!$b!(K)B3u4D@<@ys_CBx^F1)E`ptchu)L-W^gN~SrgdgBnB3MS@>AlM4k;>nO3%lGTkx&>ZYOsG!G1?>-<*YV||!J{Xea zrAO~RsO7{(?>^v!w)>%XA6!v*8~g0POpZ5ld1?O7wwwQoZ8xI_9C`mWY#tTS@Xf9= zd_257w8Dee@Zqn<=}Y>W@a0ucO0bKa*cIhe*XFbC4nQLtW#~zJpDdc8B2YXp@skwFANa zwETZ;_%u8n89Dz@IB}`(i{k4oz&e%BoNil)9HI3tH}2v>^{HNJbPiS7{U|Mw z<_IVCjiny!gIi9HDH`f^e4W#7>n!dxheRa(-;kuv*&EagzZqeLOhG-*e|P+Gi7a_Y zYhTXI7x5Llse&3U{va#yX zrKNvlqG&c{eVb9R!bjtOsl}j3g^yTp*YY>Uu)=V!YD1Mz+yAi3ALCn}D_MC@{;J`O z&p!EhGj?pDr8Kc|&3EXTXrprY>Fz5PkAgg}ygV^=^~aj(4XWxse1e^?Mw(2dRgaaF zJ@WFr3iG_0US9lGt3LTHeM_l;L_nstoJc^S>IZ>7o1-%&GQ{wROm;QxZ#N+yl*K2qPzRmgQ(K5+iLrC#xR zM=tTruW^A6F%Lv;pn*LA|8N1Yi&=w^{Z4vNQ1tR;qpF(skL(jU+5I2kYoKWR<;!XH zg6W5LTgyAYUuAF=L`X_+M65l54RKCR(Q3F(JvkFkEs8sSDAG}L|M~BP{^0}*>+WUi zZm4xP_i%z?!Tn5%{)OM(|K5_nc+8s-l<+*#f?@IQytcw|>wj0Il7HS(N`iXBoUPVw z#IT(tn-g=`f1X`cm>4Q|r!QjNGt82dkGs*Tu$#H-QL1JM;xqc?ulFftT)$yAZ=pob zH*+5DhqNWN1WH7O&948pOA)vbnS|S787F@q%x6)5tOW1b;n5zf17De$TnC^5fO9nX z2>|T|0L=i1qd_YG`e@J&fcHjGs{8BOjhfW&m5y$jcGPzdWXYHsXGvKfF$*91N6Aa+ z!{yeu7an{=ZuJsnv^?L^tra{rmv)1SJgxuorsn>!LsXhZy4mWMoXmQ}tA=llA~oAc zWxHDBpz<(^A~t?vJW%g+-b*Fio+$iBKlBlP!(+S(aoDop66$%^$6xYk%WWtBu z$~HNBStt1UQtO)GJbcUhyyeupVM_?61YVVqI~c23tJi)7E%r*8wAJ{0%lUWuE5q=F zKM^fvDJ9GvD=U;0-^X&Bv>!YcOD>(>vV0IY!a(q72!k3s>Hu=yI!i5^@c8G5zg1MofAviO> z3%Y(j{dkMczUFdd?dQg$zlDRx`!y$gY|FoW^D?7ENwsLAO&BQA`1tft|Dl2 zee5gWRb&9ZJmsEnw$=u|PW3e({bj1mW$;<5{#{X(iG#Cfk8@f!yLUeS?SoXW(lR^3 zKxP zFbeZWD#@je%{}e-Lvhr7CYYGjv4jA1@o)jK%PchH*hl??$723{O4Qvv7NPLvD2-(J z1bc?icb+HdRWBy}HNmQIfk+>(8+UieNv^NKOfRE7cR z9pK&Ei8kQE0bJyFfJ+!~kp(Unv%p0~J^MH>KL4-|>w`rvDOX2nUKo5{+gYaJ>`e~S z$>yW#sDey!&#$bfjyDRoTHXn?C5Am$s`z#LqBZaeeFW&UlL<%o!fxK(k4aND8XY>u4Vx?DBq-zO7!N9Z&5Ax}X~D5Q1;s#(h(R_3uUA`5uxi z)zMWZ@l=aFewnN%K=(iimV29w6*?M15RcpfUn6Qe`qaEYa;|FRH0$$)r#k%!a9cpT zoePnRtPADtl8aF5-l3UOXw>_wpSbH}<^HM-AC)t!Qh4KrjTP$%GZOEKU zbqU8Ny0pX24ybi84BOh2$%~*-+AHg6VqBHAjOW!S)^llIl~WZ_nU9ULGb4N4>3I1* zc(-iF^d@HUe`YOv45lXRZ`k@dit1`l@hM@zoG zY`nBat;aW(^hInIoNIP_xt}EtIoiedJLbi6A2zD#xBe}n`So%^L>%+CY<0l}Axt}5 z>v5@T!;cHDD$`Z9uZsoVUQH^2J|%VL5J$$np2fqB<}`wH<5m62zmNGgUall|TNDzr zNi}L2^mEo({o+U*sXg2}p4(+FkLN7X`ty<3xJIBl@|{Vm%Y9>Q_l~8(#S~=SlVBx^ z1uu3}7KXdQ!c5&&Pn}m$5oVJtOnDF|!34*I(A9u+h?(_|n@*x#sHbL=Y*?&{;FV`Z z@ILpwMAr{CT-rV*J))+qE)0F|U*u~1biwEgk}B6Q=|Vj-o215Kg*e_LEhwM6dK>ub z&10Tu<;jM1qZIdcztzD7#8wo>P;RK%6s@jek_GJaf`Zp5W_Q-Iw-XnAHqpO7h#l-B zIp7{igvqeZF^BINrti?_(_#Hg@GXB)r`aTjG^-L>PnB-4QZj3jYoiUfQA1OYsCiF< zQD6AHD;u>EdfS0m+C>=jPHVYIw@B|l!|LWqL znqOa>-s_8FadmNoby^Tj?-~9t*4{I$spe}RRZ$TY5JZqJy@MdV_aePZN2FKjgla>Y zfT0*V(tGa^KtzGiLhnWC9U%}poQcoxJ=gR8&-;Ek=X}^})~vZ_GMT-vWY5f+d-aFD zI%Fq@Ct|1ID>xX|!v1!s#p-W|6zq-X-X}N4>u2%o#)3oTpqq5IR9{ZdGZ-Z3e&W-vlh^PuOFtZ$6as}!m0E8$d_n4{@h_OeHcFim-kzzG1|n!K!bH#tFMuhA>w#Q!2t{JFVoM*Xgr zaTovUfSGR?ArO*2*6J@fyZKU^g)7FVEwzE(LQU+4qnlf)$WY1xcOKQg(hr?JruXi} zyLx=-Hvc{Q4F81QqHra)O=!$pggyQ0_wUn5u9b3syj6T9*V1lDn6Ah#~6!0m#fU#a8#_hWacBO3x98ZIbS`VtV{jRi#$ z@A0>oCHQzBU$@DSls7#Yj#a+Sv!8tggG!9Yw?2qX--t?y-FKr~&4$l(39)bqxT$sb zL;}-N*GXx^_gc<6B?5*Xt5>7vXC2X5?ca^W3RF4KR~($+WZ!otuE68n9@_f$Ox&V>!~Z=ZOzJnx}jlsg&b?*7a0LRrhc;Mu5~uVH(Wj)?&&GzOnBGJJ~n(lF8m6^c1oXyR@Jfm6{uBp74y_H{@Y+G)wo?VDO_q=_3LX}SD{b6LpCUbOIR*|KcdZty*n8w8dA{?ALZFadl-a?~P zE1fBaFKAU2B0TsFvnOq#hWoN21MAy^Qixpe#=kW3btXiVRybT(g*5UV@DGX*ww^yc3pt97cYRJRGzQrJ+1QhC2 z;-{`nyitbi)$)fvyMq@y`q-J>*NypAeoQ;H6a;>$6L7-QV|<7z-IFUuP4|272DQ4$ zMV4(wobHBjt^X9}a$a!!+)>;pk$E$4n4)g%NSb`rRO9*yaYRdgd4n zqi>zMj9J=t4pQ1zt81l)#7>*Vz+1PuPNYrubKpyC5Cqo}gISMq3l!$h#&rTrA`rw; z+!D2Vv5b!Jrrb8yW;=P~yzUjei1GJnC!7z9z|)QRktP$94p5wdl4k&v4vfVNC{)D2 zVhI#4pfK43r5|H)0SY4tuy_)9_Mcyt`}P`7z+mU}Tqn;MPIRjdZJQ@@rq!@eEqg4L z2aM~Yzor+j!~Ck^0r`S_BOsYkjnCTPia-QTnFqEzH)=D?K4X|ojM=H$g;6+TwVKh) z+RT@I23dW@qsb%XG{1k_U?WZ{%=&Wv!^Zr8v_=h@w#=q z3u^2UO=rF~mnIS}n+gf@-C@`WhUMpV{u$|cJQn5ad*4ApOzdM#RvK0Nl%{(0%k6w; z6nJmR5XM)Q^GpuO$!zRv*V3F_d07Ao%5`+=ATPW@9Z=-iS?={uRz$&xSA9;OX_I`r za}=Q;dvxS5KB|s?*a9X&X)gL9YWB`1)i%WeiLRd{R}U*cx_w%Cb*(#t6CG^rlqRog zBs3Dyy1QU;R^=8~w`tk*JX|w$s-JfK*%#4>Y^+q_i0oI@DRM&@YH4x{q6Y@_lp8<< z2G|NkbiIgV@~iZT{i04Bkl)_o%*obi5JxiG^W$nvkWo4Ike@ZCb+_>PBd1EAwBmh7 z%^+XB^Id9B9O@RFew*X%z510p&$aap(Z)$!^qOXHpqTQ-lHe@wkz?Ix{;R+YrYWSJ zcd~8@uRMi&!<0$5aiS-TmW1XiqgkprF0e&~g(@*1$H&s_jh1Mowz;k7xJ_T&Lcucf zFzgvHUtaD#-sKP5TrapQIPa7NX_?e4iv`&%PD8Jl(( z^Y2}90hoa2`_oKC0RuuaF}5SIfG1zW;V1s@$9&D`0GX;b@_}|h_(Pg(mi_}4wGW?j z6V|m;?zBNVY5?gCWVz96dP8eM@UTVvoPLT($zV=mV&nKA-!{(mg`iQ!{pjzL1Xeyo z{TEa%HA$sbVSSJTJSc>*tOgHt3MiQjeD-+%4 zqvRTy^vSSZ4BqH^WTUFdtRIsh?8ZP^NCy-uF$J+XNDjq@BV40uPug?o`6gToZxqT_ zg6d`%36USRGwztIkVtL*)eCzK{Gc)8Vo@I5@qIO2Y{SKswE zyN!YH(?U{IB3H1vDCe?2_j|tXlnCAy#P~hEhH_17cx1$>YYHv0PK`V^e%d22fW&F2 z5>h1bZAfUXqBr?HRZlKZ?k57pS7^#`j)4(RI6jj-K>y z?ec~NoQe1rxb7gXYK^$6+Szc@#mP2#1<#aO{hzzNK*N@{-fS={;dOx@H(SSE?WlS$bTbETT1&UuJ9(OFRAKm+(F{Tv)GQZuE+(q)=(;_XS-v>>1>dZe6{$x+_xj zXDTEd5J$syZXv)_+X-1_3MSVZm?^jrr~2Z*X5_*DMIHTLOw!`WT@>xQAPV*WdScEw zo#t>b+x?L=>|<35&4Z6s-{~KGG!}}-l_||d-(Q>xU?Z3J&2B)?cYlOZ*_Be(SHA3m zqWid240W^?i`N=tC*ZvB8Myj@$nLVPB{zw9D`BGx%w2aUsCsFu)Y9UfhEJ=_qXU zD9kn3-xd8Zt{Y|xOp$C$%Dj5>ogE=7$|8F6*q#5R3Z0MkbG!oWIycS^e6rS0%R4zY zEBZU;LXf6U$Z|F}K06Khf9zW3L)@535u-h`cSpb9D(ahTsw(3*7=Adwcn<%y<0g7UP5b>#!EasTv3>o;X z6`vzU2I0{MV#5zo?LyNWLQQQ$#TzAtyIK;~5H z-|xJ`-JK)Ii7}BWz3UlWUnNc6Vu+(wrSG{VOOA|MCz63c>ly5RH?-wNpK)4bx-xCH zH798tT|h-rL(0Fi#m1Kzlfe|ovRJthe-h239gD~kd2yE+P5R_);SZ)+DXMb;m#N(! zt@cc&akZkaX>VV%nYwO0bzN=cO%=5ND}~~1!9*;?H755bq`xfj1V!+1yWd*Ai52>M z|1}SG%wL%9@V{W+SQe){Zv<#w`e={w&(f0C~l71=>e55b>P(LM%Z7wJ} zMJr+Yh&kVfu~cwV!*Oe?adOtNbeK=*(S6v1W1^*{4%ic9pFG#>qPM8m{0iTZlLNe} z7F91VeS|A})KGj`FHY4f@u-ov>!xU+f{jNNo4#Dye7*mrRT2l)p_C`pIc%{Fk*8|P z+G?rBL~#QN%Rh~O}XOPzqctm2P zEZrA;iIr|c`@%L!=}15HA_V#(EE0*RV}Ay@H_+Of_FA^Tb{6F0GOc_mxT1`*U?7(l z7AVb2a(v7q5P5bqd+M9|4E@R}B^`gW4IjHX2`+U0I?V>cEmW2|w1tv>-Tb=ud5(6d zYGcb7?w$qM0ZZiREOxur{n%US%W_@!x^17}DtGByQWBiOcvt9?5>i;(T9+Vcb_Lg! zRA#h{7s1Qs&fh4GPTk5hrol?##+={hs*U1XTtO$6em5r-hX-j>BZ=+68}AoUoaj&> z6zmbPumAH-+o1*(Wsw&q=NNLV25-PaV(CP5HA_lI{uXlf#!Ewox?0Yg-V^?&9nPjO z2$%g9lR`^%MLNaFjn0lLS*w5%EytYTculdRxMt2-9Me zMH8WZNuZIbXKkNAoORYqNGw-ie>85-C$i4wu;uO8fqWbZUjydV^&0uBfyJ1Z^YG99 z%xd~^8q98oQsP7nH@Kg~ZQh0YGe;UXloBCAXx&HaQ~c*Bbvh#s?~ZhaV?-E6get9u zy06m3&`nAP7$NPt*_z7pM1fA!_c= ze01kbM>?y7NAeF(hm*b8tUh1mbXXEt7v6G{-1#svD>nKE`_P7b2zUL-=;&>XxLO0^ zcHyXiKR{`G#%f9-{qo2tzQ3@JxSK^WLn)^j07*q59 zv^V)d#t9`;X?GEg-!fSFbtCUrUil|R0cf|t^`Es~T?k)x$B9Vyx#-`h1*~NsM+Ad} zT+71!&1ThCRmbOQkPr3E|1do%(l@@YrpgMI<rH0kr`O!ZXT*@}kAea3b5CY} z=F*XXtj@9s!_goa?em@DQ6E5Z%*j8xHaL|$E2cG{Iyp;sI19t5CX+u=KOhgDGpfIX zp6+yVrZKfC1{_&Xe_@&h>C6A5<|N42p_6R#g590X$UeGF6S~dKDW`KEqu9UetcFKc z&b39g$uU%hG3gOis!aM3Rc09B3IrUvmLa#}Feei+(+LkDZg7F%bGW7NQyDI`EQwWj z1$6n@LeHX(2565+cL9(M15|*&MB?r0FYxX1KmS%#|3bEhowJFYkc|5LQuooqcB31O zp!Vjs2Pvf9=6CvKdvSkHMX`}c^N^Ho*8y@-V_tIBg=nRNic^P4!Q@s$;*eqg*q@tD zBNZ#d%8{d6ZF+RAy{7h+^W+ebLFGtz##)a2oYsLBoeQgP0krN>^GFwYgsJ^fi5wT- z{z@i{4C04@wP9cu7#NRlLBIpuv*$Y74w^MCvZF1JbkEduw*53~sAWe384A&KIp~9c z4w&nr-n%^l=a^#Q!Wl+^$mrLVXzpZqzJ$S9QoFfTf253rRllk%5V&$c^kGD#JjSMg zvE4C(6!NF#*)RT&$%%@SXnH~9>a&_X|6KkwdsmYf)aibavD z?x12Rs5shzY5*1W$&st}izm`fqGtJ#tM@=*27ekCXf=4sr$vJtNm9Hw<9}=N0&Dru z;_f2pYDesldiqZRq6p$eN~lbmh1I0kxZiE2ui$?H3erSuw% zKec?9wY5-bI~mol>u5k97Wbl=rTnpFGsDeS8Iaah`3tp^(w`zy9Q~Ia#vJ?I^D+@A z!yBc<5Kr(dnIg$W>aU!iOjt&Yt61zd^JvRKInA`@XSf-t$JA=Z#?2 z>dr8Gk71T+@h!^hOngyFv}t8KxD@!i_*;SKL5oelh6-}Qbfg-Y^+(fR<|siCMrr+ZqpiX5jAHbu z>^1moy-G-~*jCXtRll?h(KJo-hv{aFIh)$kt3OkY;k1w*!kOw-7-D|%CjUA_Zr@vd zPE5+5Dn)*1DIQVX8LS+~7-t2$2V<6F92Otf%M_KF^lJ1e_?~?6!Jo#o@Yjk2se>(> zW?-VqnMu9u@4f&Y^aD;!pJ(YRI0tW>=vBp`Dk7%UyevEh=q6jcAsL=+FV!3bSFBSR zXtN%oUU(z?3v+d%dj3s&7FAQIN|SLlZ(E!%&y2Oh_U~KGtbfnB>w+dPnI1O;y#XYYfeOuP5Ua{XTf;rI^~sL8huty_Xukt25;x4lfF5!Kiq{|*lJ{l9~A`JcgQ{X01Fn|A;g zW&Mduajv;T-I{IHysb%F$3Go#{>$vJLwF$GWAWmbcdPed$Nbsl80hlToW}5O1_@K~o8?%= zFhsEGefd%Z94)GR0!^HY5;L?{JG1(MhfbDgOH?7UNLtgNR%|6Y`?Ip!3Znb)I=4nbap2nJ4{ZYX@uby=Nw^D*6eC=|C~wd4pJcf~o|5 zRsMO%!;Qy4ljFTQy7(HKZ3BqI-={JLv_p^-8?x((eN9-`QknlYvc(Is-g6pEO0BkY zVs8}RCn??gD!(FPBRy+R9Ge@uBI3Z)=KwT?m8*Vgci)2uz(t<_@Nbh?sk9fFkk;MK z6x!yPlYY{To9iTf-eZz^3T2jayQd6|78LW;Z=x|xIC1k2=OR`_Txe4ZG51gC4Zmg#ExSlH2|U(WL*XYQ8{+ z^@7fCe;c)2F`)5cSmj3wh6Dh4`){=`a~Se=uf_x1)mi+nYOpj=0~e6SKyu-Iv6jW=4Xum8LuWTLzN_|#4C}Y-u1!%^Ioo8 zv{1W;A3O(Dz%XLIDpo30a}1<)6E^vJaLK8aDrvVEhp#h1C7BU?5{^^7Ew@v+?d9&7 z)c@2o?Ek%Is)pD2z~d6T9>JZ+D~EYJCIbd7h7P*U=TBa#MT0M3gX{V3?>+dc4SKSB zbdjK)t^a>KVV`;@>l7-jh+$UMVdDs_2c9D?(F%R~c8Qh*8^uGO-Ftu z0^Lqiaf<(&an{dbCa23~q3NTJ=?{ayq_^_U^Av%i$SQb3ikWp&wy+QMN5q)=8gmoy z&D*c!;%~BuW$~W_M5jdJI~W$nlJDbZ^bT6@e=CiBuuQj6RXkQ2%NF0MDu#X!61>}q z@=5E!kiom@(+{o;67eL%%fuZTN_HeOc}z+d9ks61<$$k2+Im;Nhb7X}lFP%=Y^|$h z1R9V-cNQGA1PrT_G?`26BC>HQuYv-II2NXn0*L6c{2^Dz7SPR^Un#W`%zqIEJ5G+hEq><$TZO8HU;TI4!fj_={Tv%ZtQOzF2@ z>XN3*APUK&NH$5+W}w7}vq{b!x!>v%IX_Z(yYD;xV%i-p zdW?*&>5|;?GT%w^@cPUu5uLSl^GUw(fDhm)l@F|K*Yc z7~hZE(yajFJ9f|)nP%HRHqgf$B(TvEw0UNP6_ozH?uOg=>ooQ>_m49?Nc(#xKkUX5 zezX(=2Id7P{~!YhW~;0P_Fy&c*f$~;)$~Eo#&nlMZR#P8>rjEjEsZnXO28DxmBO%4*C(1j6?jz;2zH;V=2f%bS)Zgpx^-I`cui+-m_hD-DFFG z_)*IJfClxcr7#8B&QKqEx1~^^XkRIocBqTSNT(TdeD$H{QIEXUa%wGNXzdEfVgAc) zQX~=Y5o6U;orLotj1xrX(oGSagcK|Cn(U1$WLa`#@t_s7zbyLIXYMoVaG$}yll6Vq z_70M0`C*TJMic5%!ozIsg5_k(S;M1^hc?1mDOJ#gUit9h80vn?&$5BCi`7dCylToo z5k(+9vQY{g{gaBW)^tAs2k^>C7I7YfMA9lgTYofi!7;+8stc9LAktZ#UVrOL1TQ7W z5ZLds&XU{civ1P3))i}>9VLn*4{}2%yp-GiLy`a45)tcjQ& z-{-XqKxGlze5Kh;rmp$N%8LYA!2L;qzM?VJi~E5?@ch8DKkaL*C6-l7uZB*I9n{6v zkqV_uMJ&Tdl3PskwH)_V7pn|w&Z9c<-;m%#CaWJ3LRy-Nr!%p|ySO!A z6!W`LjpItSc3)cyuc&_ZWN&*cQi?wnhVX#+Ge}AhSEk^*NQ&q)5LSli#_nsk84!ae zL!`6^8Hec3yZofGOf4%DRlvj4vqA$9z8mxLku!P1zG%UqwYj zXMIz*9<5tJ^s_guiYZqu41QP@P%fXdvW#s=g~L@wP?ce^{;7qlIZoNGX&Nz)?J8aK zp^W6gkL|uosYUbthJU7u{4_kl`n>@+cQ8v^Lh9>~`KWTj@c$q@ZsJCJ`x7fUJ9c%& z(#ZlJLMGr6XbXihb$GUmhzRX(53*%f(HSG%IM$P-~4%5wEx9-IB%@P+EZUdJ`z+K-rfwlX8>FDtprKV^III@c}?`zCU-j2Vgfx^gmZI z^O`OHEcLe-$zLQp`#sYU-NWZnb+Fr19mx4|xaC&-``b3H8JxKNrZOgEDFGiFc?JFM zd)j?Ix`Riy5?l0_ql``F>ae8zR$hiBg{p7F*tFHAMI9;s}Yyi7b7mrS0h~4B@UI3)Guz2t6zNFSD(#V0>5u@ z7cJcu+qZx#c7bm>j}Q~^$7Y&u>t52@1`7_i_b?myhuRWH_*ca{{6)vdzmP?UWYr`q zSAw7ELvB0_M<2l!w36w*jXc8w{j*R@*|hz8nU2?EbSyb{>K z8%-?3>J;!$VE18I{pvAXJ^m z76yiHw+t$wJ0qu@oZslWR8v4730DRUKrgbQw$eQ;uZro;NGK;U1_h7|K`(4TG6=oU z2gxw>Vje)eDJQRF6wp^A&t39X$07QgU-@Zl!N1#lW;NusjTG2m@Qgzz#4l2!L(F0n8Z#dxn9*FtBcN zr(1{9h^*7YCCUJo-Ho7VJ>Afy7V3Q^7kZaP!|^U{7bp@gmj;QLNn0(b6LpYxMpjub zp@HHho-RZgExcOw!g3X5z+QUrhH!is#Fi@(2~`!z(<1}QNPp7cLdhzz*ujwacJ*N0WTBtwaEc7Mo%7VlE= z=FeZ99-qOK2ur9X8qYm;3k8b&Q)fI|35TUT3p0IlGljJ^11_6mvK$AFSTjz~{o*x1 z_IbYel_}!;_}5)s>BEzM6~v6TO3fF2*g*ZOfI<1|`xbqi(bazyJRf_D9Z*JCh;02^ zz_yAr-!r>>>DdaYZL*uY7f`{xuzacH8r8X>_q+EHb!_dfOHeZdZ&ei^m4lgpSi!ee z8)tHabO%JW2U1vU#V^De+zt-T;s*Rr1D<2DLR`fXTX{ZD*$$N}qNj(zxgXEgNsGh9 z3l9H-aRe+H{c@@0b5jtUB-upsB0caceljhG%R;8GIP3nbTMqSp0G*|iSZDBz%bQZ_ z{i0+z`);8@b()F-887wD(S1tSl)!vsglDD6Xn#5P2a5`4rb?UfQ9AbqJ|)OD2rSKlakhSzx~^_-HRRjh`iGH{}dA5z;| z6Iz&{l<2GwdSVaP;3Baz{Y1Fl-cBN9*ahpMHI2S6VAvJ)OyhUTYRcQYFGY}&!3iUz z`47Scu^!QSroJV6ou`hiE7>Z-He(Obm6uLSq=aq^W}-AUbtuG#JZh%PIWS7s$%=XP zoR3v#4x?x?7H%eg)yZOA9X(9d0DHvn%Tfpw9`wHBLT%Kb#nG5Ck?UlwK%wP#7I@k7 zjSg~-OGe)dj&!g-WZ2n=u?=7wI1Yz+hsy*DIe8qF@i#mlL+uoKEQZxzT&tT+ zDp5EU`i&PG#GSdNZFip@2BCnTE>(C;8L<-F_TpWNZXRo)4Qt`EN24o8&!eKjgPpRG z7{2i-Ysx2j`6A2D!`;IF?-^|yQ9I$A_xS@1@kyCcaxz0nZ_a5edZW%yI2XmRAwMsZ~7?b zemKYq{2x~~l0j@=$l1o@5>5p1Nv7+ZaEYfd8+5*|itxllm<ReP< zwJ_ImgI_4krRf!7Ij%3GlxR(pw^I^9=7YZrx{$xQF1oP6E(aU(XTQs1HO z5=}$hsP>gY)h0D$>ZX|qAS-;DB3C{A+JE;itUtWw!hhnVMZaC7Dg$D|guC-=r6g*B zh|nhxG6gmX^+ns|RXd83bB`1WIEgjBM9|1WN+gj@E>Yg%xn@LGe0mg^^56+bT#dj3 z15|d7q~X0J-h)n!CUP((&FpBj>Um*H{;2n4vhP)JDP?@{L5+k2B#16seeUYcdhC$` zh)#MD`&k?k!~je|IP0+@0{7Nqrv-uV69$4@6o@7uKj3duYAvgYO|mjXNmeCFpd^So}H(a1TkU4`BS3XX7Awcwu*6eN|m!^ka;;+liTvx z<{B$KI;^W;ST{75<;#PH>@8MVP8tvxM7aaRIU;n;s=0dEo_7)WsFTAeMI;5=HYRKH zLbFOSMy{&%+2-1pb#V_#9XBFx>gQ3@J2D99Q~gQib z8}S+L;mn4_u5AXcx#P>MOzFd4698?bf+6- z2ku;&@ReFBbE0R6j^_b83?ZRzrZ0|`tR9;j#iS~rqm@jtgrn(g zj{E5lCrv0tH?JMhm=r$|U>XA^NEI;YZ2=PsgQ~`$3W14#1DG5zrWkx&ti+$2n~T7$ zkos}1Y^N!gN<8|)xSl#E07+c>{H%ptCBDB|pKKHV@Zn-Ie4@j^Ls#c&tP3?964l~- z?(7DuRy!A?RT-sADNsl#P!LST?ysCH7gdx88sbhK>f5B}_OafVj)p@MlnKX~Sj^Gt zWRINNqut7q@-0Zf>0O7GiCwf*(oqLvjKJtt%UnkQaYw37mnAP_1ACYRW1rGakEoGs z$nq5u_IZ72Hdl|OPWRizB!4P=&WU*RddX^R@OoDfQPi=I|tANp8mNHlthuEH%FLd8wTCm`cLQRZV1(nVey zD%@Cscnwd>^IVeyOk_7@6L`04CXjYKfD+#q2m z5#o2&?2cKG5~9{zNsjmpYv$(@^fY~~E8e|4jho-3-(EW?SLf!7t3Hdnrn9K!mn_b3 zO>9eB#e`)WXruK5bGhm`lK5vt+78N1K;z@As$18-G0-mlbA)<$NBf3GWW<)!DbdY~ z%U^UzTBLHh*|eSN(b?CgH0BlqsubW!KYM-_VU5bMY9bjBAQ@du68lO_7x|Z;H9VfKLCbsCLl8{#aKw(?XmQQ z(;~%rFvUWZt z{%=Gh_IbIOZ1jt=Z)@K;+@o5uI_vuI2H$1KW9Q(ZI5JCyCMF z`>F^>%zc#!o;OBcXkJ|OemyFrcY@wY=W4`z_I;Htsq)P;8{D+$v9o@D?*W1ZjvhhA zAIUW|u|rck`CK3J;(pCXDHR!!9}avhbsCW&Z>-bAcUoJJ&kAfe{_tj3fVMiLi9GTY z_q~^Up3upsq$rDXKu8G zIQ&oVjmnZIy|e#Lvy$Gpf>syj8}zkFYkUzftY%W&B9!MGeW)(znO^KtTX1H1p{+X0 zM0Zemsg%q4V)wrG!(tcT0w>G)8LftAZX%%~u<9hU4LZC&?n8o*mBiCf8F$siz?<`l z9T$qBg1o!DI|>i>%0zy=^8Bpm9QS1DaXa4YZkev@{g69C-~8pJ@t(Fuf5sC1q~3L% zYMN>38vgM^w>LT0Kw;+f4;1E*>(Y4T53bW-zo>lk8H?Rnvg`U6DUI-&tuJp6ZdIsM zaR2`z+Kw-V@kF|-@;_~&13sH^#4SBox}A(S^lc{zZ)9LB36I#qOtq)`Qk9P~e~yxm z<7>+{FA&YVC8itmio?FSEhfArHXHNO!@i8HE*tZr!_phGLc>xU)BM9#B`!!6gmqZA zrO7hs1vZZ~-s^rP@cqSbgq}{y+2YMcTYjL(_FW5Pq+7ansKH7&YqC?v@%p9L(N`KO zpA#Tf&~2FpBrv7%ygkE2>}I%ap3?S#?XDx|LgDorj=ieSb0-p-jKNq47$jJ{cTl_G z__|N&4Q{CrPI((&9w|C*ur=?~rI^*hE=yLBI_ZU9_u9O+{8bvy=@Cv=Q2NvVCHXYi zY6GghI@l%63PL`<@atHce+H^?pB{mB(n0P2F#+Io0Qr9=8Ruuw-ACDFFUdmMYU^!Z zLs#@?CuOZ%x{KX-NU_#7iSKt6)>z*EihGs66TvXJ?5RO-GAH-o%jT2rVczwm`%Wz7 znJ96Q$4-g^Z9X#Z@Z>27J)W*GcXF0~ubfuuD;>_BymdQ2!%fjy|CfMir&Vb2UeVL5 zW}Kc=hw_qIi3yDp|5?kQUR%|a6`bFBiq9MjmsCx7JwG$nW&CbRPS@#!bGGMSnKH^O z6tFEk)c^5J|A%cPH^i8oO#5LLUoNA(gNmwu{@%!_AXV70#v(KnpN}f+aS8Vo$p1~o z81z_iJPqXZLZUs&KSoimo8wXn4z-a9+glEp(FaI)z`MS-DuNQCi)^(wJ&c7-6ev|W z_GRs>qGq#Mle@v)OT!%{Q}N{3&PgE&Hh)^n^N zO||G5)3aGsnrdNpp5a;I@8W5QgmvfpFR781y&iQR%cEDJ9xIl)O(H)`ZHA3FwmhjK z5_fJB_@#DQ zul$R>l}))nzWc>z*NlQEYte%q`_=ssXb}6DYh|oD*$_)rh-|(mQ>D=JMeS3mM1h`B z+g>iB6}cCt!rYK5BMCB;z$Uz~^gVNWU1aBB5o}Z#xfzcY9XN@b%|2(W#p~>Sg!l5P zDG%;T@sKaxbxh4Kl3cxclaZ}*Zl{r zjq8rN2H&oo33xvuGuo(szOk2&RIu@{SKN0~`401L7U4&=Taj8jt57CG%$N3q@Aq~s zzoMpS@E;if%1wDr>fZxhR=kJD$E58#ZYy;Gy)G_!g6uA{*EehgUU~av+wx95Tc|tx z96xIneLpsw#ze$0_vBNF@*c#!OnGmR%9BN&?aVlwTjzcQQSQ`S-}g+`sh?~MYFf)< z5$N%V0cWn^JGe8QywX@lPe+y0>heUITJ$T6UT5j!-*#vIMJzA&E^5bBm7=_i&-I(B z-p*XqK97p-hd%rpIUWwvjszhQbC>d1UO&BAuDfiEXi0l9m?%-Z8r@8+CO`6MGp;Pn ziQxN{!8!KXuW>?R;VtKrrSzRtoXN3WIEQs(Bd6ZWV(N$NPuq^o--bmz(xhTF+qM49 zGq>_|{>uJ2cJM>eTeotVHf7!lb+v0~H?~ZLRIU{TFh~5OJp6Bl?+3bMK`r_c=Ra4l zpBtW_`dpI*i#L9;mfG`azq@f+EyIYt>@!qVm}*qkrC9~fRtT6QYP&6H4q40N5KUHq z&j?a14!2W9l6Fi{sbY2SWn)vRzHi(eq|Yx`i2Wu*rFvs-bueMdU4_XH@%Y&3o6g`X z;l3i|SHBq8r?(o|vk&3mhYqhSZmShuh>jYNDTzyRpN*+*vN(2V3N2Wyyq^Ux9W{s> zd;8qTT!m7c&Rm1m$XtWe$o$XiY>uZsRQu_p0cBhqOS%+Z0_eUVgE;M%aQ= z(&7_=S8uM3-ld*aezC#BetZAh(SF}VWxTOE(IMNI3c9t{JQv!|{k}8Q&d756lklkb0z^Rw8VPQLC&=i{egZ#zRx!a$Z z#?UJC6_-(c8tgn)?|0EtRTt~P_UR)=(P5~Mn*2gyxtAK!!D6cWr-4A%>af{h3q2a;qg(%i1%s4w(I@G3Pq zu=1KIEPsuRhpQajqsAtUwr-ri5bS!I#L-iaOKE9_Du!~~C(yiVoV%Y`mfq(1m5-k*ZN{D1qU5h*7U!flE~TOn!_%?L!XfXrn5pfkr7IUjwpmA_WDb9P zZ3&@VOdMkYXMgVZ-sFP&osk^P}!gK93j?IvblB`VSo`z)+1yuO(*He1_=_a6Eq!U z6)cm?taAw1pmtt~@$$v8xeZn$WP6|J^k|2F@Gt~#JCAS;SJM(Dm{~I`8F%@nHTPrw9TR_JY`H2<&e;3@4#VGmmA<6b2mp&$@Lt{+4QOXipJZVY%;*FJTbNkpEz7M};(l?-)x@l^PUzdPccX%WCoppFIx^{ma2D)~7Qz-PMTg3r_eV+)?<-=Rm z1&Xlvv}@mH?l&sG>{;b7C$xSqb6~?DA{3$bQqQ|@^K}{?7s;jnj}8c#JZzfiE$5!0 z0nuf((vPTp_Gz-}5`~#jN&DYZtrF?y{s&zAR-aCG7@F&d9Sdn znAhB|c{Z5^B1-BI^81(D=C>Qm?)K?-E}jnl zbhs{rOO)}1_L~pKldJ$~J$&&Hjn3QM8UwpeHm0OW$$Tm0Dan~%QT}#+?CAiioa1Fi zfeK&8X+}x{c=QNEBfmS5+=)ZxKxju~wjcVkQ)dOx9<)0W0WBROJ%&$(4L%<+fZY7E zJ|RhZ_mn~sbokZbFV}0H_Gxzx;dtrJ+Yd9+k!`~T5S}qSA{KEY5?F)JuPXHqfxJTE z?`|#eYJ7M{ZwEBXYW1#-w$%q4e;cBdH8EnAktu7>2j9Gy&L1!9Z$tA^BNcCHi4KH6 zG}fqhJby=zRM^*gHz-MPmyqG~&X>=l(gb8fOBiiflEwk246DH5o|WwygxS+M^Zug? zyxdZbxQfC*!U@9s;B(VLw8n|U2L^T}F(0~lH=OqgqUWyone3WEEH?cMNi{4vX2qDh zK$AcFP|WC$ml1^vorC}qK5N=uc=W(%V6QWY<=`A9y-`y>qJ>F9Y)_F;7^ES-k(#xfuWdZ=KU<4w_E%eiUfu z6wzAkG!?|TZ=Kd5H8R4Xs`$&C(Cv93At9| zQ{zzKY{=1*J?d6Is@|lB`6VU){hrmp+FR8o7Dngf`U#kY{Oca13v!N#6GR zjwQ1AR&4pLSbLkeex{25Zv2&C@#a&*lEvb*lsbuCVve7V`(00@C!kLjgDG)%e1Y-` zCu-?8Ywwrdm}?Z-;oy1)F5eVA1nmmZ;^XTDgq?R3tpw#I3)@Z_l{T{#4Lsi{+Ab1F zN|WbZBQ#Xi*u~2wA#(dDb+ThlE7dQ4XP#0NwDWZillb0m6?uF|G5&F&_tOWT?cex$ zKZOo-u#7al54%}_5DBLCcAh(}^rM!(s!_+m6nktI(R*G~ z1ikI-O?6FwE-HJI9V;e%N9Jzuzxla^MgGl#|2?ibx5)R~*m=a9{5Wc>w_8=XU_!WCaan9$_WhP5})YS zLQqIXuCj$}O%Dgha?75EQE3>x z?ufFzr`AK@)Yc%7$syP#UwzAFFtqlU4(T9q3O?P`yI50Mqu16E0Av=V=XE>zr?uA1 zWxc71{^2k3vycl9#{EPtQmn@cU5~%n%5+@opbxk`YXB@6c#ZC+JhwHl`L1eNBG88o zD(z)^wE6$M=E_)E+FO}V$z;W3_I+*RtP8Q;a`?mNgpb?uGhTHE0%u08X}PwpDtSRI z5pb4gTSsrD9%vkz5q&lZ7ld5P%OORO4W!%INzU_U58`fA^Nvidee^aY(@1vFO=850 zVWvu9q7;D(Gg)yaKOw1V5b70EBm`a}C_&y6ufN0lk5?Sq_w$V&d znjN~HvCOuChOl?ou}yMq@0C_Ef3;b9YyL4GYG(F%dSYe>-gwV(f6*KXya}0^zeeR2 zgyqw9f%~h?(K+{}7uS1z1Vy=hmb8}_lD0M%E)U}!ulJ^V5L{A{$AE)fKS2BrD&=*3ytQShtZn=yzr23IzJ!3x%Pjx za+P6Geczf6K@gBG1*D`!au^9orMsk*5RjG@1O%1tZb=12QaS{rkr_ach9QP->AR2j z`Q88h@PF=yd+&#N&pPkfd+jy*JhRt1>pgR($w@JN*qE@~6<|24VO|6~zrT?0ir9&^ zt%zy1q+C>S@sn5Ov(7|D@}=ndOBm-`=2gPESFh_8=L8$%2Enb~T&s_zb~f6ys-+xAs^&}lSJ@zr;*XQ*+7 zPlSE|8WRzrTfXL8CgL6jfDJv^10*;G_L{9_{5yh9!H|qZXkRKMDNix8p~i!XoJ)Qx zr^c zj;|lBj9oI+?sazkzW|QuH#zs_2?OZn>nf#1Q$xY*WrTvdvgovF=BheMRwDTrq zsx}rrw659Ccv$<*R9RVzQsvvZ0;q-<4fDCNFs#KY_)VIm!`xQRPo%hbrv97)U1+)2 zw{@AXMdX}nn71N9lYG#G$K|98Vl^g2~|ZMqauMYLffX!6#- ze__*l2tVc}jbi%UG|U=IX_GeI}>JcpBc7-N@>L$8=4C zb_bImeoDqGIH}V43)mgZeE7)`ufU8?Ki$A+#h5&APK1IXN4ZHxD@{q0p1m4vF^ha2 zDb9~y+m#U)Y-}~y)mA3Ru`oB5;^ypZ?;J)uN;jo*X_(pQ_w#I{?B@7;ySKEx zEc8TJ6ZSp}JA=oE#QE#0cxzAYif8S13g^(|?ERl&ayMoAa=C+&arX3heVSUY6fIk?E zp&yxpf$t{D+1lnn0;m><`U6qYfckU;*N-eI+1sm!VkojraCeG^;eT(md0q1ND$GvP zCd<#bucuCDWlso&V9>{lQ+P`LT9Z9i8fx5VzW9{>TzC1z$5;{EsXFNo2G zDeA?8!Gt)A3K?eZJkzF3c=d zv8!2x8Bgq3U+;6F=!)gNuP9(K+!C3vk9|+SO+BtVvtFGX)`qWAz*lLR54e~Q0KN_j z#BQIFTg@Sbg^--K{>zZIy_3DN3|;^&pn6I_}3D& z^}yqO^Gu#e5-V%*%rHvP?g49czg*@rjOWG zavwt0Lle%Xw{->wUun%An(+8cMDVll_5WN^J#xKS*w%!Q(U3!B7}n|$m6N0F&)oNf zp__&24ejcyCZ*CZCbJjE@hmO%zq``ZvUF8-zfV}2n}x@?qk|4wwT5TKc<e$w7{DJ z_ZE(9+G>numo`c-!hGcL3~~8Y)V$t)y|6Q!Mcw6K>I7Xa1Z{`7il7`DCRGl)eemM7Ino z#h*dv5;6*bF*6B_Du0HY?aTPyU2zh4?UkX2{f4|`MX`PxjIWPvrfkh7-l^V|VcK(= z<$9$AL9$EsEctve{80$$>0L7T>c@wFa!*A?gdDN;UwcAV~)I5*GxZ3V{U#9uT~PAQOTL2s$B{fMByCF2LDWnx(k!i^0;j zw5StX{>&p7|H6j#?AlyD-JNmwhvo5P->g|(udlx8QOz9*Pq3Hf*DA+sQu?OTRLB~| z|Kh)ncZxLEeZxDjq&Jf=QQ`JZDDpnG$Q$e{_7|k;Rg6?jpLGlY#hfn}!ND7QVX7}v ztNmCtGM{wnO5v$9M76smp`Kl5qAXx5-Lt-#XP8N?Ba8t5{0@7MTsigP^e+z!8(TSj zs|1W6KUR8Cwk~Sfz5Of1UJ-t3+1` zMe>CCHYZ`lzR-*Vg|4X!uYCLL^jT+(u&!6-hSX7m_t19UOm)&g$KyLvkIjZKNYRBh z3IR0Q*=-EZ=mu;In7WWQ3PAh})9iiS-*E^V3g+e+p_27Z3!4{ePR)chooqT^urkhZ zQSY=-kRpx0`q;{D1g~uI?>;^Jah8MZ#15`30GEF zKwxy9I16KxZb|RO(}>?(hOx;WDI`%T`p2O!+`U`+G4ejY;NzP`8WJZt=4Uxss>eAP zkK0K8p7w_qETu+$cM~EXa$w71@)vN4kOh@;CVwSwpM%?|351Qr$RCSEaoTq_BIN4P z@QlT5D4zzr*e6o49LfOo6XWWae)*GeZRP>)x)=>li0ww!iP!2bt8@ zAae*Z_5Yd($V~ogj{j|YjoI$7>qoh$!pkPXk@d*fCr%OPJCU)>&4P4hP7z(>^sKX9 zR!j7s2aIT?=I!%myd07HpCff%IWB2_j%+-x{;A~cD9mj}FCXZsz}<3huh>(eX?L)A zWj6INRC5RrGoA{psLa^o=6iHpPN1XxlBQFn&t+L`uTvxpT?P)^U-xEBoTc+d8nbR+ zm>+~NNBArTPf*YucHy%|pPDZsg#OMTUSb%K-$yTDl1;vpOxQNZ>ddiZ0ycf z{!oyot&-N{#}P51{dXSY>27P2F>L#DyXPF2%;nDDlU8UP!YSK!XNqL;eVE<8bAYF2 zN{Q_7D}?zzFn%AYi+OqD(W0!8LqM+9SqY!>f_(*5a;0U_>_{hUpXkG&b3lH7r!>E$lnw%{La_4AIV5^!bklZa`%RS_qe#du*5dDP@5tki>wQsa!G=tF0 zc~Se+s24m*wm2!SeDy2|b#+fd)i4a+fQRs7-Ph8qG)t94hsic>R4BfdO_FX4rJOpRDje-1t z$W3WjrvJ8#x_EKd^9B#6Yj01KUe?VwbKT3?7y>uqlEZ_1m1S$`jS=SB-N(ZAtf-Tv zmHdE;vew^c9KR>Oi3Yf4*k~tv?NcLqDhJGNdXLVUwh*qf*?Q`gO$Jlv3)Hy186>9Dy02!|eciX^inKxB6}LHe`z)M8 z7)iQX8AXK=P1N1mnY-$+qGe?bQVIjVq-X@3@btE2_|TqU8i!TWoXd{811N(7X`mdE z8ip{D75*%GBuw}kwV=yiB>{9eVSr7iaae8!{vw+?3WV*N7;(r*B13ap7JwHSss1Qn z?HY1eb6J_aL1doze+8gW=wOUHhz zJamff!-em&6)VQqv+Bdu&e&EJbTEHH;+ducPsKL^UKehzCm4sDJNmTf{*B zb;Jl~{LLZrARE-~_aA;@R2uQb;b)@RjL%`#yo@rzG`yaWb4&GFvG5I#iUm0^>qOdB+?as3;Ext%%F{u|?JxGj|W12jMj-SJYyadeAF2 zTDU6;oSUxGw#B*sJPnL+Q%Gva#s*#!>koU+ z#xYrvNgTjTM6tIhe)5U{a~xf`SD>@|=Tm%z<&LNWXc^)I$5-oybfm>$Fk58nxB>tE zmd%NwjaW3AzH&p@Z6^wQr7YG_4p1*>IBaj+^paFd=S0HGB zQGy_~s{2U!uUZ90vB!_=O}6|eIM4rEaM;yn-Zs;DkBty~i&X^6c1)%-skqe_uf|1G zlRo-z`Azowu%XE~;|2sd6T@oo56mxxh>(k7D|AR@~v1j4(sy}qtR{AE-Y8p z{ccE^tl|*hO{Sn+LrkUoEt6GUq_We-Bb6uFWdiOs`)L-#ub1#uJ0W}#=K%`m0l*z9 z=Q5dj-h?^)8Ck+tbN@0@cq4TUURau(1wUuO8&0OsH7+6bP6Uxx zOSDXF<))R;+y$H+duH3}hC%9g6VwUIU{GGf$5O7voK<$=Yi;2#Uslt~$t3bremOQS zWaL30f@0fAs3OQ-ewnLPlQh^#FJk2Rvxy*~I>&pCPxOkYIvBU*-DF$Ptiq;wo6`rV znHJQn1Zsu^%|c6;(%pRp9d8X$*&RpsF%&H>+U#v@{|D2Uav^E7Tq|tJPR$%>G zaT<2FXFNN5@k#5w+KeY(Bt=d}_iaQO=(aCvE^%M2{WP%feIybWD;x5}ZNaJoQ`^TW zR@7-zDE5jNduMR_54{LuI#`giv5V}X^~`0}-61QaI;aIK!;l+sX9*GYKp!TMM#hv4 zcw=sUiLEyW$AAvb8H%X)hl)ZK=thSpaJKM7HdpddKD#`ux4fw&igG?)ZwDWKEapW&>o zxPcT0CIMT1Bx)P);HegM5o!!B#;lD=U{0RU3uMx9Solk8M{1$5UJn6^ z424pnj7ET&Ak)pi$^ADxf`1=g+5Zq;!9T&N{NIAZ=RQ8mbn&LO?h||4?hyO(sxD%i z*gm~TO6mhP7QAOjGUlV$Cw-TRm+lGF@+LDf(vDYO?0-MyRUWP>LyLsqdOT6ME1$zG z@_>M^owFyYjfJcBLe%@$(`3U}iMxUsFOc)WvtqRL=M!UcCp)!U1ECK-?qdnICO`86 zzuF!9bzcvYB#VS`53jHX>5VYyt;=qlh zH@iufIIkO%;AopwOOGRPu}oC~ z!Rw)*$-Z8i*uc41`n*?+v)=9v*7*V-QnyElNc(A{V4J+^HnFqd&n_Hl3Wvwef)!mj z$$iXB0`u^v?NT=F{@+8+QV5R;DYmrPr)(bA4W&ApN!PV(IYS!ooh}xG+Vv!%D+YYK zW}W5uegbTS2E{ literal 0 HcmV?d00001 diff --git a/core/src/main/resources/bedrock/creative_items.1_19_0.json b/core/src/main/resources/bedrock/creative_items.1_19_0.json new file mode 100644 index 000000000..3a356a802 --- /dev/null +++ b/core/src/main/resources/bedrock/creative_items.1_19_0.json @@ -0,0 +1,5437 @@ +{ + "items" : [ + { + "id" : "minecraft:planks", + "blockRuntimeId" : 6071 + }, + { + "id" : "minecraft:planks", + "blockRuntimeId" : 6072 + }, + { + "id" : "minecraft:planks", + "blockRuntimeId" : 6073 + }, + { + "id" : "minecraft:planks", + "blockRuntimeId" : 6074 + }, + { + "id" : "minecraft:planks", + "blockRuntimeId" : 6075 + }, + { + "id" : "minecraft:planks", + "blockRuntimeId" : 6076 + }, + { + "id" : "minecraft:mangrove_planks", + "blockRuntimeId" : 947 + }, + { + "id" : "minecraft:crimson_planks", + "blockRuntimeId" : 4850 + }, + { + "id" : "minecraft:warped_planks", + "blockRuntimeId" : 920 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1182 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1183 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1184 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1185 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1186 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1187 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1194 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1189 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1190 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1188 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1191 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1195 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1192 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1193 + }, + { + "id" : "minecraft:blackstone_wall", + "blockRuntimeId" : 3930 + }, + { + "id" : "minecraft:polished_blackstone_wall", + "blockRuntimeId" : 6724 + }, + { + "id" : "minecraft:polished_blackstone_brick_wall", + "blockRuntimeId" : 971 + }, + { + "id" : "minecraft:cobbled_deepslate_wall", + "blockRuntimeId" : 8082 + }, + { + "id" : "minecraft:deepslate_tile_wall", + "blockRuntimeId" : 5071 + }, + { + "id" : "minecraft:polished_deepslate_wall", + "blockRuntimeId" : 7817 + }, + { + "id" : "minecraft:deepslate_brick_wall", + "blockRuntimeId" : 429 + }, + { + "id" : "minecraft:mud_brick_wall", + "blockRuntimeId" : 730 + }, + { + "id" : "minecraft:fence", + "blockRuntimeId" : 7364 + }, + { + "id" : "minecraft:fence", + "blockRuntimeId" : 7365 + }, + { + "id" : "minecraft:fence", + "blockRuntimeId" : 7366 + }, + { + "id" : "minecraft:fence", + "blockRuntimeId" : 7367 + }, + { + "id" : "minecraft:fence", + "blockRuntimeId" : 7368 + }, + { + "id" : "minecraft:fence", + "blockRuntimeId" : 7369 + }, + { + "id" : "minecraft:mangrove_fence", + "blockRuntimeId" : 6633 + }, + { + "id" : "minecraft:nether_brick_fence", + "blockRuntimeId" : 4290 + }, + { + "id" : "minecraft:crimson_fence", + "blockRuntimeId" : 7996 + }, + { + "id" : "minecraft:warped_fence", + "blockRuntimeId" : 5853 + }, + { + "id" : "minecraft:fence_gate", + "blockRuntimeId" : 76 + }, + { + "id" : "minecraft:spruce_fence_gate", + "blockRuntimeId" : 6584 + }, + { + "id" : "minecraft:birch_fence_gate", + "blockRuntimeId" : 3777 + }, + { + "id" : "minecraft:jungle_fence_gate", + "blockRuntimeId" : 5365 + }, + { + "id" : "minecraft:acacia_fence_gate", + "blockRuntimeId" : 7586 + }, + { + "id" : "minecraft:dark_oak_fence_gate", + "blockRuntimeId" : 4173 + }, + { + "id" : "minecraft:mangrove_fence_gate", + "blockRuntimeId" : 4625 + }, + { + "id" : "minecraft:crimson_fence_gate", + "blockRuntimeId" : 4661 + }, + { + "id" : "minecraft:warped_fence_gate", + "blockRuntimeId" : 5399 + }, + { + "id" : "minecraft:normal_stone_stairs", + "blockRuntimeId" : 633 + }, + { + "id" : "minecraft:stone_stairs", + "blockRuntimeId" : 3708 + }, + { + "id" : "minecraft:mossy_cobblestone_stairs", + "blockRuntimeId" : 4092 + }, + { + "id" : "minecraft:oak_stairs", + "blockRuntimeId" : 273 + }, + { + "id" : "minecraft:spruce_stairs", + "blockRuntimeId" : 128 + }, + { + "id" : "minecraft:birch_stairs", + "blockRuntimeId" : 7003 + }, + { + "id" : "minecraft:jungle_stairs", + "blockRuntimeId" : 6967 + }, + { + "id" : "minecraft:acacia_stairs", + "blockRuntimeId" : 6200 + }, + { + "id" : "minecraft:dark_oak_stairs", + "blockRuntimeId" : 5063 + }, + { + "id" : "minecraft:mangrove_stairs", + "blockRuntimeId" : 4595 + }, + { + "id" : "minecraft:stone_brick_stairs", + "blockRuntimeId" : 931 + }, + { + "id" : "minecraft:mossy_stone_brick_stairs", + "blockRuntimeId" : 5883 + }, + { + "id" : "minecraft:sandstone_stairs", + "blockRuntimeId" : 3587 + }, + { + "id" : "minecraft:smooth_sandstone_stairs", + "blockRuntimeId" : 3627 + }, + { + "id" : "minecraft:red_sandstone_stairs", + "blockRuntimeId" : 5350 + }, + { + "id" : "minecraft:smooth_red_sandstone_stairs", + "blockRuntimeId" : 5546 + }, + { + "id" : "minecraft:granite_stairs", + "blockRuntimeId" : 3537 + }, + { + "id" : "minecraft:polished_granite_stairs", + "blockRuntimeId" : 4150 + }, + { + "id" : "minecraft:diorite_stairs", + "blockRuntimeId" : 4391 + }, + { + "id" : "minecraft:polished_diorite_stairs", + "blockRuntimeId" : 6714 + }, + { + "id" : "minecraft:andesite_stairs", + "blockRuntimeId" : 5308 + }, + { + "id" : "minecraft:polished_andesite_stairs", + "blockRuntimeId" : 7028 + }, + { + "id" : "minecraft:brick_stairs", + "blockRuntimeId" : 6530 + }, + { + "id" : "minecraft:nether_brick_stairs", + "blockRuntimeId" : 106 + }, + { + "id" : "minecraft:red_nether_brick_stairs", + "blockRuntimeId" : 6602 + }, + { + "id" : "minecraft:end_brick_stairs", + "blockRuntimeId" : 6382 + }, + { + "id" : "minecraft:quartz_stairs", + "blockRuntimeId" : 4767 + }, + { + "id" : "minecraft:smooth_quartz_stairs", + "blockRuntimeId" : 7700 + }, + { + "id" : "minecraft:purpur_stairs", + "blockRuntimeId" : 7755 + }, + { + "id" : "minecraft:prismarine_stairs", + "blockRuntimeId" : 7263 + }, + { + "id" : "minecraft:dark_prismarine_stairs", + "blockRuntimeId" : 7430 + }, + { + "id" : "minecraft:prismarine_bricks_stairs", + "blockRuntimeId" : 206 + }, + { + "id" : "minecraft:crimson_stairs", + "blockRuntimeId" : 6280 + }, + { + "id" : "minecraft:warped_stairs", + "blockRuntimeId" : 3718 + }, + { + "id" : "minecraft:blackstone_stairs", + "blockRuntimeId" : 7019 + }, + { + "id" : "minecraft:polished_blackstone_stairs", + "blockRuntimeId" : 4297 + }, + { + "id" : "minecraft:polished_blackstone_brick_stairs", + "blockRuntimeId" : 4477 + }, + { + "id" : "minecraft:cut_copper_stairs", + "blockRuntimeId" : 4604 + }, + { + "id" : "minecraft:exposed_cut_copper_stairs", + "blockRuntimeId" : 4587 + }, + { + "id" : "minecraft:weathered_cut_copper_stairs", + "blockRuntimeId" : 4305 + }, + { + "id" : "minecraft:oxidized_cut_copper_stairs", + "blockRuntimeId" : 351 + }, + { + "id" : "minecraft:waxed_cut_copper_stairs", + "blockRuntimeId" : 393 + }, + { + "id" : "minecraft:waxed_exposed_cut_copper_stairs", + "blockRuntimeId" : 3902 + }, + { + "id" : "minecraft:waxed_weathered_cut_copper_stairs", + "blockRuntimeId" : 6167 + }, + { + "id" : "minecraft:waxed_oxidized_cut_copper_stairs", + "blockRuntimeId" : 5840 + }, + { + "id" : "minecraft:cobbled_deepslate_stairs", + "blockRuntimeId" : 147 + }, + { + "id" : "minecraft:deepslate_tile_stairs", + "blockRuntimeId" : 4653 + }, + { + "id" : "minecraft:polished_deepslate_stairs", + "blockRuntimeId" : 294 + }, + { + "id" : "minecraft:deepslate_brick_stairs", + "blockRuntimeId" : 7422 + }, + { + "id" : "minecraft:mud_brick_stairs", + "blockRuntimeId" : 5522 + }, + { + "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:iron_door" + }, + { + "id" : "minecraft:crimson_door" + }, + { + "id" : "minecraft:warped_door" + }, + { + "id" : "minecraft:trapdoor", + "blockRuntimeId" : 229 + }, + { + "id" : "minecraft:spruce_trapdoor", + "blockRuntimeId" : 6552 + }, + { + "id" : "minecraft:birch_trapdoor", + "blockRuntimeId" : 6650 + }, + { + "id" : "minecraft:jungle_trapdoor", + "blockRuntimeId" : 5381 + }, + { + "id" : "minecraft:acacia_trapdoor", + "blockRuntimeId" : 5589 + }, + { + "id" : "minecraft:dark_oak_trapdoor", + "blockRuntimeId" : 7502 + }, + { + "id" : "minecraft:mangrove_trapdoor", + "blockRuntimeId" : 4485 + }, + { + "id" : "minecraft:iron_trapdoor", + "blockRuntimeId" : 321 + }, + { + "id" : "minecraft:crimson_trapdoor", + "blockRuntimeId" : 4333 + }, + { + "id" : "minecraft:warped_trapdoor", + "blockRuntimeId" : 4733 + }, + { + "id" : "minecraft:iron_bars", + "blockRuntimeId" : 4801 + }, + { + "id" : "minecraft:glass", + "blockRuntimeId" : 6164 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1133 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1141 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1140 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1148 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1145 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1147 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1134 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1137 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1138 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1146 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1142 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1136 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1144 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1143 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1135 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1139 + }, + { + "id" : "minecraft:tinted_glass", + "blockRuntimeId" : 5975 + }, + { + "id" : "minecraft:glass_pane", + "blockRuntimeId" : 5233 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4852 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4860 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4859 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4867 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4864 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4866 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4853 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4856 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4857 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4865 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4861 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4855 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4863 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4862 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4854 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4858 + }, + { + "id" : "minecraft:ladder", + "blockRuntimeId" : 8262 + }, + { + "id" : "minecraft:scaffolding", + "blockRuntimeId" : 3571 + }, + { + "id" : "minecraft:stone_block_slab", + "blockRuntimeId" : 4270 + }, + { + "id" : "minecraft:stone_block_slab4", + "blockRuntimeId" : 5822 + }, + { + "id" : "minecraft:stone_block_slab", + "blockRuntimeId" : 4273 + }, + { + "id" : "minecraft:stone_block_slab2", + "blockRuntimeId" : 5793 + }, + { + "id" : "minecraft:wooden_slab", + "blockRuntimeId" : 5270 + }, + { + "id" : "minecraft:wooden_slab", + "blockRuntimeId" : 5271 + }, + { + "id" : "minecraft:wooden_slab", + "blockRuntimeId" : 5272 + }, + { + "id" : "minecraft:wooden_slab", + "blockRuntimeId" : 5273 + }, + { + "id" : "minecraft:wooden_slab", + "blockRuntimeId" : 5274 + }, + { + "id" : "minecraft:wooden_slab", + "blockRuntimeId" : 5275 + }, + { + "id" : "minecraft:mangrove_slab", + "blockRuntimeId" : 1149 + }, + { + "id" : "minecraft:stone_block_slab", + "blockRuntimeId" : 4275 + }, + { + "id" : "minecraft:stone_block_slab4", + "blockRuntimeId" : 5820 + }, + { + "id" : "minecraft:stone_block_slab", + "blockRuntimeId" : 4271 + }, + { + "id" : "minecraft:stone_block_slab4", + "blockRuntimeId" : 5823 + }, + { + "id" : "minecraft:stone_block_slab2", + "blockRuntimeId" : 5794 + }, + { + "id" : "minecraft:stone_block_slab2", + "blockRuntimeId" : 5788 + }, + { + "id" : "minecraft:stone_block_slab4", + "blockRuntimeId" : 5824 + }, + { + "id" : "minecraft:stone_block_slab3", + "blockRuntimeId" : 5805 + }, + { + "id" : "minecraft:stone_block_slab3", + "blockRuntimeId" : 5810 + }, + { + "id" : "minecraft:stone_block_slab3", + "blockRuntimeId" : 5811 + }, + { + "id" : "minecraft:stone_block_slab3", + "blockRuntimeId" : 5808 + }, + { + "id" : "minecraft:stone_block_slab3", + "blockRuntimeId" : 5809 + }, + { + "id" : "minecraft:stone_block_slab3", + "blockRuntimeId" : 5807 + }, + { + "id" : "minecraft:stone_block_slab3", + "blockRuntimeId" : 5806 + }, + { + "id" : "minecraft:stone_block_slab", + "blockRuntimeId" : 4274 + }, + { + "id" : "minecraft:stone_block_slab", + "blockRuntimeId" : 4277 + }, + { + "id" : "minecraft:stone_block_slab2", + "blockRuntimeId" : 5795 + }, + { + "id" : "minecraft:stone_block_slab3", + "blockRuntimeId" : 5804 + }, + { + "id" : "minecraft:stone_block_slab", + "blockRuntimeId" : 4276 + }, + { + "id" : "minecraft:stone_block_slab4", + "blockRuntimeId" : 5821 + }, + { + "id" : "minecraft:stone_block_slab2", + "blockRuntimeId" : 5789 + }, + { + "id" : "minecraft:stone_block_slab2", + "blockRuntimeId" : 5790 + }, + { + "id" : "minecraft:stone_block_slab2", + "blockRuntimeId" : 5791 + }, + { + "id" : "minecraft:stone_block_slab2", + "blockRuntimeId" : 5792 + }, + { + "id" : "minecraft:crimson_slab", + "blockRuntimeId" : 5900 + }, + { + "id" : "minecraft:warped_slab", + "blockRuntimeId" : 6484 + }, + { + "id" : "minecraft:blackstone_slab", + "blockRuntimeId" : 910 + }, + { + "id" : "minecraft:polished_blackstone_slab", + "blockRuntimeId" : 6018 + }, + { + "id" : "minecraft:polished_blackstone_brick_slab", + "blockRuntimeId" : 4192 + }, + { + "id" : "minecraft:cut_copper_slab", + "blockRuntimeId" : 5235 + }, + { + "id" : "minecraft:exposed_cut_copper_slab", + "blockRuntimeId" : 6600 + }, + { + "id" : "minecraft:weathered_cut_copper_slab", + "blockRuntimeId" : 6053 + }, + { + "id" : "minecraft:oxidized_cut_copper_slab", + "blockRuntimeId" : 5282 + }, + { + "id" : "minecraft:waxed_cut_copper_slab", + "blockRuntimeId" : 7815 + }, + { + "id" : "minecraft:waxed_exposed_cut_copper_slab", + "blockRuntimeId" : 249 + }, + { + "id" : "minecraft:waxed_weathered_cut_copper_slab", + "blockRuntimeId" : 6545 + }, + { + "id" : "minecraft:waxed_oxidized_cut_copper_slab", + "blockRuntimeId" : 708 + }, + { + "id" : "minecraft:cobbled_deepslate_slab", + "blockRuntimeId" : 7310 + }, + { + "id" : "minecraft:polished_deepslate_slab", + "blockRuntimeId" : 288 + }, + { + "id" : "minecraft:deepslate_tile_slab", + "blockRuntimeId" : 4291 + }, + { + "id" : "minecraft:deepslate_brick_slab", + "blockRuntimeId" : 3716 + }, + { + "id" : "minecraft:mud_brick_slab", + "blockRuntimeId" : 3910 + }, + { + "id" : "minecraft:brick_block", + "blockRuntimeId" : 4765 + }, + { + "id" : "minecraft:chiseled_nether_bricks", + "blockRuntimeId" : 7249 + }, + { + "id" : "minecraft:cracked_nether_bricks", + "blockRuntimeId" : 4552 + }, + { + "id" : "minecraft:quartz_bricks", + "blockRuntimeId" : 6351 + }, + { + "id" : "minecraft:stonebrick", + "blockRuntimeId" : 6547 + }, + { + "id" : "minecraft:stonebrick", + "blockRuntimeId" : 6548 + }, + { + "id" : "minecraft:stonebrick", + "blockRuntimeId" : 6549 + }, + { + "id" : "minecraft:stonebrick", + "blockRuntimeId" : 6550 + }, + { + "id" : "minecraft:end_bricks", + "blockRuntimeId" : 281 + }, + { + "id" : "minecraft:prismarine", + "blockRuntimeId" : 6087 + }, + { + "id" : "minecraft:polished_blackstone_bricks", + "blockRuntimeId" : 4680 + }, + { + "id" : "minecraft:cracked_polished_blackstone_bricks", + "blockRuntimeId" : 7214 + }, + { + "id" : "minecraft:gilded_blackstone", + "blockRuntimeId" : 4586 + }, + { + "id" : "minecraft:chiseled_polished_blackstone", + "blockRuntimeId" : 5062 + }, + { + "id" : "minecraft:deepslate_tiles", + "blockRuntimeId" : 4581 + }, + { + "id" : "minecraft:cracked_deepslate_tiles", + "blockRuntimeId" : 4160 + }, + { + "id" : "minecraft:deepslate_bricks", + "blockRuntimeId" : 5464 + }, + { + "id" : "minecraft:cracked_deepslate_bricks", + "blockRuntimeId" : 5364 + }, + { + "id" : "minecraft:chiseled_deepslate", + "blockRuntimeId" : 5234 + }, + { + "id" : "minecraft:cobblestone", + "blockRuntimeId" : 3615 + }, + { + "id" : "minecraft:mossy_cobblestone", + "blockRuntimeId" : 252 + }, + { + "id" : "minecraft:cobbled_deepslate", + "blockRuntimeId" : 6670 + }, + { + "id" : "minecraft:smooth_stone", + "blockRuntimeId" : 4582 + }, + { + "id" : "minecraft:sandstone", + "blockRuntimeId" : 3653 + }, + { + "id" : "minecraft:sandstone", + "blockRuntimeId" : 3654 + }, + { + "id" : "minecraft:sandstone", + "blockRuntimeId" : 3655 + }, + { + "id" : "minecraft:sandstone", + "blockRuntimeId" : 3656 + }, + { + "id" : "minecraft:red_sandstone", + "blockRuntimeId" : 6580 + }, + { + "id" : "minecraft:red_sandstone", + "blockRuntimeId" : 6581 + }, + { + "id" : "minecraft:red_sandstone", + "blockRuntimeId" : 6582 + }, + { + "id" : "minecraft:red_sandstone", + "blockRuntimeId" : 6583 + }, + { + "id" : "minecraft:coal_block", + "blockRuntimeId" : 5398 + }, + { + "id" : "minecraft:dried_kelp_block", + "blockRuntimeId" : 7979 + }, + { + "id" : "minecraft:gold_block", + "blockRuntimeId" : 291 + }, + { + "id" : "minecraft:iron_block", + "blockRuntimeId" : 8261 + }, + { + "id" : "minecraft:copper_block", + "blockRuntimeId" : 4651 + }, + { + "id" : "minecraft:exposed_copper", + "blockRuntimeId" : 593 + }, + { + "id" : "minecraft:weathered_copper", + "blockRuntimeId" : 8246 + }, + { + "id" : "minecraft:oxidized_copper", + "blockRuntimeId" : 3553 + }, + { + "id" : "minecraft:waxed_copper", + "blockRuntimeId" : 7734 + }, + { + "id" : "minecraft:waxed_exposed_copper", + "blockRuntimeId" : 694 + }, + { + "id" : "minecraft:waxed_weathered_copper", + "blockRuntimeId" : 707 + }, + { + "id" : "minecraft:waxed_oxidized_copper", + "blockRuntimeId" : 7542 + }, + { + "id" : "minecraft:cut_copper", + "blockRuntimeId" : 4689 + }, + { + "id" : "minecraft:exposed_cut_copper", + "blockRuntimeId" : 6166 + }, + { + "id" : "minecraft:weathered_cut_copper", + "blockRuntimeId" : 7197 + }, + { + "id" : "minecraft:oxidized_cut_copper", + "blockRuntimeId" : 5478 + }, + { + "id" : "minecraft:waxed_cut_copper", + "blockRuntimeId" : 7293 + }, + { + "id" : "minecraft:waxed_exposed_cut_copper", + "blockRuntimeId" : 3809 + }, + { + "id" : "minecraft:waxed_weathered_cut_copper", + "blockRuntimeId" : 4851 + }, + { + "id" : "minecraft:waxed_oxidized_cut_copper", + "blockRuntimeId" : 214 + }, + { + "id" : "minecraft:emerald_block", + "blockRuntimeId" : 1159 + }, + { + "id" : "minecraft:diamond_block", + "blockRuntimeId" : 272 + }, + { + "id" : "minecraft:lapis_block", + "blockRuntimeId" : 4286 + }, + { + "id" : "minecraft:raw_iron_block", + "blockRuntimeId" : 8260 + }, + { + "id" : "minecraft:raw_copper_block", + "blockRuntimeId" : 5269 + }, + { + "id" : "minecraft:raw_gold_block", + "blockRuntimeId" : 361 + }, + { + "id" : "minecraft:quartz_block", + "blockRuntimeId" : 3696 + }, + { + "id" : "minecraft:quartz_block", + "blockRuntimeId" : 3698 + }, + { + "id" : "minecraft:quartz_block", + "blockRuntimeId" : 3697 + }, + { + "id" : "minecraft:quartz_block", + "blockRuntimeId" : 3699 + }, + { + "id" : "minecraft:prismarine", + "blockRuntimeId" : 6085 + }, + { + "id" : "minecraft:prismarine", + "blockRuntimeId" : 6086 + }, + { + "id" : "minecraft:slime", + "blockRuntimeId" : 4233 + }, + { + "id" : "minecraft:honey_block", + "blockRuntimeId" : 892 + }, + { + "id" : "minecraft:honeycomb_block", + "blockRuntimeId" : 4476 + }, + { + "id" : "minecraft:hay_block", + "blockRuntimeId" : 695 + }, + { + "id" : "minecraft:bone_block", + "blockRuntimeId" : 4234 + }, + { + "id" : "minecraft:nether_brick", + "blockRuntimeId" : 7272 + }, + { + "id" : "minecraft:red_nether_brick", + "blockRuntimeId" : 146 + }, + { + "id" : "minecraft:netherite_block", + "blockRuntimeId" : 3775 + }, + { + "id" : "minecraft:lodestone", + "blockRuntimeId" : 8259 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 3458 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 3466 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 3465 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 3473 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 3470 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 3472 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 3459 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 3462 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 3463 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 3471 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 3467 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 3461 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 3469 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 3468 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 3460 + }, + { + "id" : "minecraft:wool", + "blockRuntimeId" : 3464 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 949 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 957 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 956 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 964 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 961 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 963 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 950 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 953 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 954 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 962 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 958 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 952 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 960 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 959 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 951 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 955 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 6264 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 6272 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 6271 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 6279 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 6276 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 6278 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 6265 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 6268 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 6269 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 6277 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 6273 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 6267 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 6275 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 6274 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 6266 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 6270 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 660 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 668 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 667 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 675 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 672 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 674 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 661 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 664 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 665 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 673 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 669 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 663 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 671 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 670 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 662 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 666 + }, + { + "id" : "minecraft:clay", + "blockRuntimeId" : 7124 + }, + { + "id" : "minecraft:hardened_clay", + "blockRuntimeId" : 641 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 6176 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 6184 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 6183 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 6191 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 6188 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 6190 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 6177 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 6180 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 6181 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 6189 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 6185 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 6179 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 6187 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 6186 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 6178 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 6182 + }, + { + "id" : "minecraft:white_glazed_terracotta", + "blockRuntimeId" : 5573 + }, + { + "id" : "minecraft:silver_glazed_terracotta", + "blockRuntimeId" : 3531 + }, + { + "id" : "minecraft:gray_glazed_terracotta", + "blockRuntimeId" : 8253 + }, + { + "id" : "minecraft:black_glazed_terracotta", + "blockRuntimeId" : 5834 + }, + { + "id" : "minecraft:brown_glazed_terracotta", + "blockRuntimeId" : 3547 + }, + { + "id" : "minecraft:red_glazed_terracotta", + "blockRuntimeId" : 4167 + }, + { + "id" : "minecraft:orange_glazed_terracotta", + "blockRuntimeId" : 1151 + }, + { + "id" : "minecraft:yellow_glazed_terracotta", + "blockRuntimeId" : 913 + }, + { + "id" : "minecraft:lime_glazed_terracotta", + "blockRuntimeId" : 223 + }, + { + "id" : "minecraft:green_glazed_terracotta", + "blockRuntimeId" : 6610 + }, + { + "id" : "minecraft:cyan_glazed_terracotta", + "blockRuntimeId" : 5358 + }, + { + "id" : "minecraft:light_blue_glazed_terracotta", + "blockRuntimeId" : 5471 + }, + { + "id" : "minecraft:blue_glazed_terracotta", + "blockRuntimeId" : 5465 + }, + { + "id" : "minecraft:purple_glazed_terracotta", + "blockRuntimeId" : 7011 + }, + { + "id" : "minecraft:magenta_glazed_terracotta", + "blockRuntimeId" : 965 + }, + { + "id" : "minecraft:pink_glazed_terracotta", + "blockRuntimeId" : 6539 + }, + { + "id" : "minecraft:purpur_block", + "blockRuntimeId" : 7714 + }, + { + "id" : "minecraft:purpur_block", + "blockRuntimeId" : 7716 + }, + { + "id" : "minecraft:packed_mud", + "blockRuntimeId" : 283 + }, + { + "id" : "minecraft:mud_bricks", + "blockRuntimeId" : 6889 + }, + { + "id" : "minecraft:nether_wart_block", + "blockRuntimeId" : 4293 + }, + { + "id" : "minecraft:warped_wart_block", + "blockRuntimeId" : 5905 + }, + { + "id" : "minecraft:shroomlight", + "blockRuntimeId" : 5061 + }, + { + "id" : "minecraft:crimson_nylium", + "blockRuntimeId" : 4189 + }, + { + "id" : "minecraft:warped_nylium", + "blockRuntimeId" : 6349 + }, + { + "id" : "minecraft:basalt", + "blockRuntimeId" : 4349 + }, + { + "id" : "minecraft:polished_basalt", + "blockRuntimeId" : 24 + }, + { + "id" : "minecraft:smooth_basalt", + "blockRuntimeId" : 1157 + }, + { + "id" : "minecraft:soul_soil", + "blockRuntimeId" : 5830 + }, + { + "id" : "minecraft:dirt", + "blockRuntimeId" : 5751 + }, + { + "id" : "minecraft:dirt", + "blockRuntimeId" : 5752 + }, + { + "id" : "minecraft:farmland", + "blockRuntimeId" : 3912 + }, + { + "id" : "minecraft:grass", + "blockRuntimeId" : 6975 + }, + { + "id" : "minecraft:grass_path", + "blockRuntimeId" : 8081 + }, + { + "id" : "minecraft:podzol", + "blockRuntimeId" : 4650 + }, + { + "id" : "minecraft:mycelium", + "blockRuntimeId" : 3683 + }, + { + "id" : "minecraft:mud", + "blockRuntimeId" : 6684 + }, + { + "id" : "minecraft:stone", + "blockRuntimeId" : 653 + }, + { + "id" : "minecraft:iron_ore", + "blockRuntimeId" : 4690 + }, + { + "id" : "minecraft:gold_ore", + "blockRuntimeId" : 912 + }, + { + "id" : "minecraft:diamond_ore", + "blockRuntimeId" : 4361 + }, + { + "id" : "minecraft:lapis_ore", + "blockRuntimeId" : 7699 + }, + { + "id" : "minecraft:redstone_ore", + "blockRuntimeId" : 4289 + }, + { + "id" : "minecraft:coal_ore", + "blockRuntimeId" : 4287 + }, + { + "id" : "minecraft:copper_ore", + "blockRuntimeId" : 3554 + }, + { + "id" : "minecraft:emerald_ore", + "blockRuntimeId" : 7347 + }, + { + "id" : "minecraft:quartz_ore", + "blockRuntimeId" : 4501 + }, + { + "id" : "minecraft:nether_gold_ore", + "blockRuntimeId" : 27 + }, + { + "id" : "minecraft:ancient_debris", + "blockRuntimeId" : 6107 + }, + { + "id" : "minecraft:deepslate_iron_ore", + "blockRuntimeId" : 7273 + }, + { + "id" : "minecraft:deepslate_gold_ore", + "blockRuntimeId" : 6106 + }, + { + "id" : "minecraft:deepslate_diamond_ore", + "blockRuntimeId" : 8038 + }, + { + "id" : "minecraft:deepslate_lapis_ore", + "blockRuntimeId" : 7262 + }, + { + "id" : "minecraft:deepslate_redstone_ore", + "blockRuntimeId" : 6616 + }, + { + "id" : "minecraft:deepslate_emerald_ore", + "blockRuntimeId" : 6350 + }, + { + "id" : "minecraft:deepslate_coal_ore", + "blockRuntimeId" : 7196 + }, + { + "id" : "minecraft:deepslate_copper_ore", + "blockRuntimeId" : 105 + }, + { + "id" : "minecraft:gravel", + "blockRuntimeId" : 8287 + }, + { + "id" : "minecraft:stone", + "blockRuntimeId" : 654 + }, + { + "id" : "minecraft:stone", + "blockRuntimeId" : 656 + }, + { + "id" : "minecraft:stone", + "blockRuntimeId" : 658 + }, + { + "id" : "minecraft:blackstone", + "blockRuntimeId" : 7585 + }, + { + "id" : "minecraft:deepslate", + "blockRuntimeId" : 253 + }, + { + "id" : "minecraft:stone", + "blockRuntimeId" : 655 + }, + { + "id" : "minecraft:stone", + "blockRuntimeId" : 657 + }, + { + "id" : "minecraft:stone", + "blockRuntimeId" : 659 + }, + { + "id" : "minecraft:polished_blackstone", + "blockRuntimeId" : 3682 + }, + { + "id" : "minecraft:polished_deepslate", + "blockRuntimeId" : 7754 + }, + { + "id" : "minecraft:sand", + "blockRuntimeId" : 4195 + }, + { + "id" : "minecraft:sand", + "blockRuntimeId" : 4196 + }, + { + "id" : "minecraft:cactus", + "blockRuntimeId" : 6986 + }, + { + "id" : "minecraft:log", + "blockRuntimeId" : 6672 + }, + { + "id" : "minecraft:stripped_oak_log", + "blockRuntimeId" : 7543 + }, + { + "id" : "minecraft:log", + "blockRuntimeId" : 6673 + }, + { + "id" : "minecraft:stripped_spruce_log", + "blockRuntimeId" : 6288 + }, + { + "id" : "minecraft:log", + "blockRuntimeId" : 6674 + }, + { + "id" : "minecraft:stripped_birch_log", + "blockRuntimeId" : 5972 + }, + { + "id" : "minecraft:log", + "blockRuntimeId" : 6675 + }, + { + "id" : "minecraft:stripped_jungle_log", + "blockRuntimeId" : 642 + }, + { + "id" : "minecraft:log2", + "blockRuntimeId" : 3830 + }, + { + "id" : "minecraft:stripped_acacia_log", + "blockRuntimeId" : 5848 + }, + { + "id" : "minecraft:log2", + "blockRuntimeId" : 3831 + }, + { + "id" : "minecraft:stripped_dark_oak_log", + "blockRuntimeId" : 216 + }, + { + "id" : "minecraft:mangrove_log", + "blockRuntimeId" : 348 + }, + { + "id" : "minecraft:stripped_mangrove_log", + "blockRuntimeId" : 8284 + }, + { + "id" : "minecraft:crimson_stem", + "blockRuntimeId" : 5897 + }, + { + "id" : "minecraft:stripped_crimson_stem", + "blockRuntimeId" : 6948 + }, + { + "id" : "minecraft:warped_stem", + "blockRuntimeId" : 6486 + }, + { + "id" : "minecraft:stripped_warped_stem", + "blockRuntimeId" : 7400 + }, + { + "id" : "minecraft:wood", + "blockRuntimeId" : 3474 + }, + { + "id" : "minecraft:wood", + "blockRuntimeId" : 3480 + }, + { + "id" : "minecraft:wood", + "blockRuntimeId" : 3475 + }, + { + "id" : "minecraft:wood", + "blockRuntimeId" : 3481 + }, + { + "id" : "minecraft:wood", + "blockRuntimeId" : 3476 + }, + { + "id" : "minecraft:wood", + "blockRuntimeId" : 3482 + }, + { + "id" : "minecraft:wood", + "blockRuntimeId" : 3477 + }, + { + "id" : "minecraft:wood", + "blockRuntimeId" : 3483 + }, + { + "id" : "minecraft:wood", + "blockRuntimeId" : 3478 + }, + { + "id" : "minecraft:wood", + "blockRuntimeId" : 3484 + }, + { + "id" : "minecraft:wood", + "blockRuntimeId" : 3479 + }, + { + "id" : "minecraft:wood", + "blockRuntimeId" : 3485 + }, + { + "id" : "minecraft:mangrove_wood", + "blockRuntimeId" : 4161 + }, + { + "id" : "minecraft:stripped_mangrove_wood", + "blockRuntimeId" : 4229 + }, + { + "id" : "minecraft:crimson_hyphae", + "blockRuntimeId" : 4294 + }, + { + "id" : "minecraft:stripped_crimson_hyphae", + "blockRuntimeId" : 6499 + }, + { + "id" : "minecraft:warped_hyphae", + "blockRuntimeId" : 5902 + }, + { + "id" : "minecraft:stripped_warped_hyphae", + "blockRuntimeId" : 5579 + }, + { + "id" : "minecraft:leaves", + "blockRuntimeId" : 6090 + }, + { + "id" : "minecraft:leaves", + "blockRuntimeId" : 6091 + }, + { + "id" : "minecraft:leaves", + "blockRuntimeId" : 6092 + }, + { + "id" : "minecraft:leaves", + "blockRuntimeId" : 6093 + }, + { + "id" : "minecraft:leaves2", + "blockRuntimeId" : 4353 + }, + { + "id" : "minecraft:leaves2", + "blockRuntimeId" : 4354 + }, + { + "id" : "minecraft:mangrove_leaves", + "blockRuntimeId" : 6666 + }, + { + "id" : "minecraft:azalea_leaves", + "blockRuntimeId" : 7710 + }, + { + "id" : "minecraft:azalea_leaves_flowered", + "blockRuntimeId" : 6339 + }, + { + "id" : "minecraft:sapling", + "blockRuntimeId" : 712 + }, + { + "id" : "minecraft:sapling", + "blockRuntimeId" : 713 + }, + { + "id" : "minecraft:sapling", + "blockRuntimeId" : 714 + }, + { + "id" : "minecraft:sapling", + "blockRuntimeId" : 715 + }, + { + "id" : "minecraft:sapling", + "blockRuntimeId" : 716 + }, + { + "id" : "minecraft:sapling", + "blockRuntimeId" : 717 + }, + { + "id" : "minecraft:mangrove_propagule", + "blockRuntimeId" : 6976 + }, + { + "id" : "minecraft:bee_nest", + "blockRuntimeId" : 5754 + }, + { + "id" : "minecraft:wheat_seeds" + }, + { + "id" : "minecraft:pumpkin_seeds" + }, + { + "id" : "minecraft:melon_seeds" + }, + { + "id" : "minecraft:beetroot_seeds" + }, + { + "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", + "blockRuntimeId" : 392 + }, + { + "id" : "minecraft:melon_slice" + }, + { + "id" : "minecraft:glistering_melon_slice" + }, + { + "id" : "minecraft:sweet_berries" + }, + { + "id" : "minecraft:glow_berries" + }, + { + "id" : "minecraft:pumpkin", + "blockRuntimeId" : 4577 + }, + { + "id" : "minecraft:carved_pumpkin", + "blockRuntimeId" : 7378 + }, + { + "id" : "minecraft:lit_pumpkin", + "blockRuntimeId" : 6685 + }, + { + "id" : "minecraft:honeycomb" + }, + { + "id" : "minecraft:tallgrass", + "blockRuntimeId" : 929 + }, + { + "id" : "minecraft:double_plant", + "blockRuntimeId" : 5455 + }, + { + "id" : "minecraft:tallgrass", + "blockRuntimeId" : 928 + }, + { + "id" : "minecraft:double_plant", + "blockRuntimeId" : 5454 + }, + { + "id" : "minecraft:nether_sprouts" + }, + { + "id" : "minecraft:coral", + "blockRuntimeId" : 6492 + }, + { + "id" : "minecraft:coral", + "blockRuntimeId" : 6490 + }, + { + "id" : "minecraft:coral", + "blockRuntimeId" : 6491 + }, + { + "id" : "minecraft:coral", + "blockRuntimeId" : 6489 + }, + { + "id" : "minecraft:coral", + "blockRuntimeId" : 6493 + }, + { + "id" : "minecraft:coral", + "blockRuntimeId" : 6497 + }, + { + "id" : "minecraft:coral", + "blockRuntimeId" : 6495 + }, + { + "id" : "minecraft:coral", + "blockRuntimeId" : 6496 + }, + { + "id" : "minecraft:coral", + "blockRuntimeId" : 6494 + }, + { + "id" : "minecraft:coral", + "blockRuntimeId" : 6498 + }, + { + "id" : "minecraft:coral_fan", + "blockRuntimeId" : 4616 + }, + { + "id" : "minecraft:coral_fan", + "blockRuntimeId" : 4614 + }, + { + "id" : "minecraft:coral_fan", + "blockRuntimeId" : 4615 + }, + { + "id" : "minecraft:coral_fan", + "blockRuntimeId" : 4613 + }, + { + "id" : "minecraft:coral_fan", + "blockRuntimeId" : 4617 + }, + { + "id" : "minecraft:coral_fan_dead", + "blockRuntimeId" : 69 + }, + { + "id" : "minecraft:coral_fan_dead", + "blockRuntimeId" : 67 + }, + { + "id" : "minecraft:coral_fan_dead", + "blockRuntimeId" : 68 + }, + { + "id" : "minecraft:coral_fan_dead", + "blockRuntimeId" : 66 + }, + { + "id" : "minecraft:coral_fan_dead", + "blockRuntimeId" : 70 + }, + { + "id" : "minecraft:kelp" + }, + { + "id" : "minecraft:seagrass", + "blockRuntimeId" : 246 + }, + { + "id" : "minecraft:crimson_roots", + "blockRuntimeId" : 7573 + }, + { + "id" : "minecraft:warped_roots", + "blockRuntimeId" : 4362 + }, + { + "id" : "minecraft:yellow_flower", + "blockRuntimeId" : 302 + }, + { + "id" : "minecraft:red_flower", + "blockRuntimeId" : 3616 + }, + { + "id" : "minecraft:red_flower", + "blockRuntimeId" : 3617 + }, + { + "id" : "minecraft:red_flower", + "blockRuntimeId" : 3618 + }, + { + "id" : "minecraft:red_flower", + "blockRuntimeId" : 3619 + }, + { + "id" : "minecraft:red_flower", + "blockRuntimeId" : 3620 + }, + { + "id" : "minecraft:red_flower", + "blockRuntimeId" : 3621 + }, + { + "id" : "minecraft:red_flower", + "blockRuntimeId" : 3622 + }, + { + "id" : "minecraft:red_flower", + "blockRuntimeId" : 3623 + }, + { + "id" : "minecraft:red_flower", + "blockRuntimeId" : 3624 + }, + { + "id" : "minecraft:red_flower", + "blockRuntimeId" : 3625 + }, + { + "id" : "minecraft:red_flower", + "blockRuntimeId" : 3626 + }, + { + "id" : "minecraft:double_plant", + "blockRuntimeId" : 5452 + }, + { + "id" : "minecraft:double_plant", + "blockRuntimeId" : 5453 + }, + { + "id" : "minecraft:double_plant", + "blockRuntimeId" : 5456 + }, + { + "id" : "minecraft:double_plant", + "blockRuntimeId" : 5457 + }, + { + "id" : "minecraft:wither_rose", + "blockRuntimeId" : 6165 + }, + { + "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", + "blockRuntimeId" : 894 + }, + { + "id" : "minecraft:weeping_vines", + "blockRuntimeId" : 5479 + }, + { + "id" : "minecraft:twisting_vines", + "blockRuntimeId" : 5691 + }, + { + "id" : "minecraft:waterlily", + "blockRuntimeId" : 1158 + }, + { + "id" : "minecraft:deadbush", + "blockRuntimeId" : 4677 + }, + { + "id" : "minecraft:bamboo", + "blockRuntimeId" : 3684 + }, + { + "id" : "minecraft:snow", + "blockRuntimeId" : 4194 + }, + { + "id" : "minecraft:ice", + "blockRuntimeId" : 6689 + }, + { + "id" : "minecraft:packed_ice", + "blockRuntimeId" : 282 + }, + { + "id" : "minecraft:blue_ice", + "blockRuntimeId" : 7027 + }, + { + "id" : "minecraft:snow_layer", + "blockRuntimeId" : 155 + }, + { + "id" : "minecraft:pointed_dripstone", + "blockRuntimeId" : 7416 + }, + { + "id" : "minecraft:dripstone_block", + "blockRuntimeId" : 893 + }, + { + "id" : "minecraft:moss_carpet", + "blockRuntimeId" : 286 + }, + { + "id" : "minecraft:moss_block", + "blockRuntimeId" : 6538 + }, + { + "id" : "minecraft:dirt_with_roots", + "blockRuntimeId" : 5397 + }, + { + "id" : "minecraft:hanging_roots", + "blockRuntimeId" : 205 + }, + { + "id" : "minecraft:mangrove_roots", + "blockRuntimeId" : 6175 + }, + { + "id" : "minecraft:muddy_mangrove_roots", + "blockRuntimeId" : 345 + }, + { + "id" : "minecraft:big_dripleaf", + "blockRuntimeId" : 5980 + }, + { + "id" : "minecraft:small_dripleaf_block", + "blockRuntimeId" : 4320 + }, + { + "id" : "minecraft:spore_blossom", + "blockRuntimeId" : 7312 + }, + { + "id" : "minecraft:azalea", + "blockRuntimeId" : 6888 + }, + { + "id" : "minecraft:flowering_azalea", + "blockRuntimeId" : 5477 + }, + { + "id" : "minecraft:glow_lichen", + "blockRuntimeId" : 5684 + }, + { + "id" : "minecraft:amethyst_block", + "blockRuntimeId" : 290 + }, + { + "id" : "minecraft:budding_amethyst", + "blockRuntimeId" : 7002 + }, + { + "id" : "minecraft:amethyst_cluster", + "blockRuntimeId" : 7810 + }, + { + "id" : "minecraft:large_amethyst_bud", + "blockRuntimeId" : 4728 + }, + { + "id" : "minecraft:medium_amethyst_bud", + "blockRuntimeId" : 4376 + }, + { + "id" : "minecraft:small_amethyst_bud", + "blockRuntimeId" : 304 + }, + { + "id" : "minecraft:tuff", + "blockRuntimeId" : 347 + }, + { + "id" : "minecraft:calcite", + "blockRuntimeId" : 215 + }, + { + "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", + "blockRuntimeId" : 3546 + }, + { + "id" : "minecraft:red_mushroom", + "blockRuntimeId" : 4585 + }, + { + "id" : "minecraft:crimson_fungus", + "blockRuntimeId" : 7753 + }, + { + "id" : "minecraft:warped_fungus", + "blockRuntimeId" : 287 + }, + { + "id" : "minecraft:brown_mushroom_block", + "blockRuntimeId" : 7362 + }, + { + "id" : "minecraft:red_mushroom_block", + "blockRuntimeId" : 3611 + }, + { + "id" : "minecraft:brown_mushroom_block", + "blockRuntimeId" : 7363 + }, + { + "id" : "minecraft:brown_mushroom_block", + "blockRuntimeId" : 7348 + }, + { + "id" : "minecraft:egg" + }, + { + "id" : "minecraft:sugar_cane" + }, + { + "id" : "minecraft:sugar" + }, + { + "id" : "minecraft:rotten_flesh" + }, + { + "id" : "minecraft:bone" + }, + { + "id" : "minecraft:web", + "blockRuntimeId" : 6713 + }, + { + "id" : "minecraft:spider_eye" + }, + { + "id" : "minecraft:mob_spawner", + "blockRuntimeId" : 401 + }, + { + "id" : "minecraft:monster_egg", + "blockRuntimeId" : 4144 + }, + { + "id" : "minecraft:monster_egg", + "blockRuntimeId" : 4145 + }, + { + "id" : "minecraft:monster_egg", + "blockRuntimeId" : 4146 + }, + { + "id" : "minecraft:monster_egg", + "blockRuntimeId" : 4147 + }, + { + "id" : "minecraft:monster_egg", + "blockRuntimeId" : 4148 + }, + { + "id" : "minecraft:monster_egg", + "blockRuntimeId" : 4149 + }, + { + "id" : "minecraft:infested_deepslate", + "blockRuntimeId" : 4641 + }, + { + "id" : "minecraft:dragon_egg", + "blockRuntimeId" : 7271 + }, + { + "id" : "minecraft:turtle_egg", + "blockRuntimeId" : 7997 + }, + { + "id" : "minecraft:frog_spawn", + "blockRuntimeId" : 4399 + }, + { + "id" : "minecraft:pearlescent_froglight", + "blockRuntimeId" : 6435 + }, + { + "id" : "minecraft:verdant_froglight", + "blockRuntimeId" : 6481 + }, + { + "id" : "minecraft:ochre_froglight", + "blockRuntimeId" : 3510 + }, + { + "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: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:obsidian", + "blockRuntimeId" : 428 + }, + { + "id" : "minecraft:crying_obsidian", + "blockRuntimeId" : 6722 + }, + { + "id" : "minecraft:bedrock", + "blockRuntimeId" : 7017 + }, + { + "id" : "minecraft:soul_sand", + "blockRuntimeId" : 5831 + }, + { + "id" : "minecraft:netherrack", + "blockRuntimeId" : 7037 + }, + { + "id" : "minecraft:magma", + "blockRuntimeId" : 8009 + }, + { + "id" : "minecraft:nether_wart" + }, + { + "id" : "minecraft:end_stone", + "blockRuntimeId" : 3836 + }, + { + "id" : "minecraft:chorus_flower", + "blockRuntimeId" : 4530 + }, + { + "id" : "minecraft:chorus_plant", + "blockRuntimeId" : 5505 + }, + { + "id" : "minecraft:chorus_fruit" + }, + { + "id" : "minecraft:popped_chorus_fruit" + }, + { + "id" : "minecraft:sponge", + "blockRuntimeId" : 629 + }, + { + "id" : "minecraft:sponge", + "blockRuntimeId" : 630 + }, + { + "id" : "minecraft:coral_block", + "blockRuntimeId" : 5237 + }, + { + "id" : "minecraft:coral_block", + "blockRuntimeId" : 5238 + }, + { + "id" : "minecraft:coral_block", + "blockRuntimeId" : 5239 + }, + { + "id" : "minecraft:coral_block", + "blockRuntimeId" : 5240 + }, + { + "id" : "minecraft:coral_block", + "blockRuntimeId" : 5241 + }, + { + "id" : "minecraft:coral_block", + "blockRuntimeId" : 5242 + }, + { + "id" : "minecraft:coral_block", + "blockRuntimeId" : 5243 + }, + { + "id" : "minecraft:coral_block", + "blockRuntimeId" : 5244 + }, + { + "id" : "minecraft:coral_block", + "blockRuntimeId" : 5245 + }, + { + "id" : "minecraft:coral_block", + "blockRuntimeId" : 5246 + }, + { + "id" : "minecraft:sculk", + "blockRuntimeId" : 7036 + }, + { + "id" : "minecraft:sculk_vein", + "blockRuntimeId" : 7132 + }, + { + "id" : "minecraft:sculk_catalyst", + "blockRuntimeId" : 3613 + }, + { + "id" : "minecraft:sculk_shrieker", + "blockRuntimeId" : 219 + }, + { + "id" : "minecraft:sculk_sensor", + "blockRuntimeId" : 4389 + }, + { + "id" : "minecraft:reinforced_deepslate", + "blockRuntimeId" : 5832 + }, + { + "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: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", + "blockRuntimeId" : 724 + }, + { + "id" : "minecraft:soul_torch", + "blockRuntimeId" : 4644 + }, + { + "id" : "minecraft:sea_pickle", + "blockRuntimeId" : 5855 + }, + { + "id" : "minecraft:lantern", + "blockRuntimeId" : 7074 + }, + { + "id" : "minecraft:soul_lantern", + "blockRuntimeId" : 5749 + }, + { + "id" : "minecraft:candle", + "blockRuntimeId" : 7403 + }, + { + "id" : "minecraft:white_candle", + "blockRuntimeId" : 5300 + }, + { + "id" : "minecraft:orange_candle", + "blockRuntimeId" : 362 + }, + { + "id" : "minecraft:magenta_candle", + "blockRuntimeId" : 418 + }, + { + "id" : "minecraft:light_blue_candle", + "blockRuntimeId" : 4569 + }, + { + "id" : "minecraft:yellow_candle", + "blockRuntimeId" : 6192 + }, + { + "id" : "minecraft:lime_candle", + "blockRuntimeId" : 6368 + }, + { + "id" : "minecraft:pink_candle", + "blockRuntimeId" : 7370 + }, + { + "id" : "minecraft:gray_candle", + "blockRuntimeId" : 939 + }, + { + "id" : "minecraft:light_gray_candle", + "blockRuntimeId" : 6224 + }, + { + "id" : "minecraft:cyan_candle", + "blockRuntimeId" : 7726 + }, + { + "id" : "minecraft:purple_candle", + "blockRuntimeId" : 7038 + }, + { + "id" : "minecraft:blue_candle" + }, + { + "id" : "minecraft:brown_candle", + "blockRuntimeId" : 5875 + }, + { + "id" : "minecraft:green_candle", + "blockRuntimeId" : 686 + }, + { + "id" : "minecraft:red_candle", + "blockRuntimeId" : 4681 + }, + { + "id" : "minecraft:black_candle", + "blockRuntimeId" : 171 + }, + { + "id" : "minecraft:crafting_table", + "blockRuntimeId" : 5854 + }, + { + "id" : "minecraft:cartography_table", + "blockRuntimeId" : 8288 + }, + { + "id" : "minecraft:fletching_table", + "blockRuntimeId" : 5833 + }, + { + "id" : "minecraft:smithing_table", + "blockRuntimeId" : 3726 + }, + { + "id" : "minecraft:beehive", + "blockRuntimeId" : 6108 + }, + { + "id" : "minecraft:campfire" + }, + { + "id" : "minecraft:soul_campfire" + }, + { + "id" : "minecraft:furnace", + "blockRuntimeId" : 7802 + }, + { + "id" : "minecraft:blast_furnace", + "blockRuntimeId" : 7567 + }, + { + "id" : "minecraft:smoker", + "blockRuntimeId" : 647 + }, + { + "id" : "minecraft:respawn_anchor", + "blockRuntimeId" : 681 + }, + { + "id" : "minecraft:brewing_stand" + }, + { + "id" : "minecraft:anvil", + "blockRuntimeId" : 6634 + }, + { + "id" : "minecraft:anvil", + "blockRuntimeId" : 6638 + }, + { + "id" : "minecraft:anvil", + "blockRuntimeId" : 6642 + }, + { + "id" : "minecraft:grindstone", + "blockRuntimeId" : 8039 + }, + { + "id" : "minecraft:enchanting_table", + "blockRuntimeId" : 6723 + }, + { + "id" : "minecraft:bookshelf", + "blockRuntimeId" : 6671 + }, + { + "id" : "minecraft:lectern", + "blockRuntimeId" : 6940 + }, + { + "id" : "minecraft:cauldron" + }, + { + "id" : "minecraft:composter", + "blockRuntimeId" : 5415 + }, + { + "id" : "minecraft:chest", + "blockRuntimeId" : 7115 + }, + { + "id" : "minecraft:trapped_chest", + "blockRuntimeId" : 5583 + }, + { + "id" : "minecraft:ender_chest", + "blockRuntimeId" : 4369 + }, + { + "id" : "minecraft:barrel", + "blockRuntimeId" : 4518 + }, + { + "id" : "minecraft:undyed_shulker_box", + "blockRuntimeId" : 3681 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 5316 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 5324 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 5323 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 5331 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 5328 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 5330 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 5317 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 5320 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 5321 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 5329 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 5325 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 5319 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 5327 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 5326 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 5318 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 5322 + }, + { + "id" : "minecraft:armor_stand" + }, + { + "id" : "minecraft:noteblock", + "blockRuntimeId" : 346 + }, + { + "id" : "minecraft:jukebox", + "blockRuntimeId" : 4874 + }, + { + "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:disc_fragment_5" + }, + { + "id" : "minecraft:glowstone_dust" + }, + { + "id" : "minecraft:glowstone", + "blockRuntimeId" : 3885 + }, + { + "id" : "minecraft:redstone_lamp", + "blockRuntimeId" : 251 + }, + { + "id" : "minecraft:sea_lantern", + "blockRuntimeId" : 7546 + }, + { + "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:crimson_sign" + }, + { + "id" : "minecraft:warped_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:beacon", + "blockRuntimeId" : 145 + }, + { + "id" : "minecraft:bell", + "blockRuntimeId" : 6908 + }, + { + "id" : "minecraft:conduit", + "blockRuntimeId" : 4232 + }, + { + "id" : "minecraft:stonecutter_block", + "blockRuntimeId" : 7574 + }, + { + "id" : "minecraft:end_portal_frame", + "blockRuntimeId" : 6077 + }, + { + "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", + "blockRuntimeId" : 5891 + }, + { + "id" : "minecraft:lightning_rod", + "blockRuntimeId" : 1176 + }, + { + "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: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:rail", + "blockRuntimeId" : 3920 + }, + { + "id" : "minecraft:golden_rail", + "blockRuntimeId" : 5332 + }, + { + "id" : "minecraft:detector_rail", + "blockRuntimeId" : 4132 + }, + { + "id" : "minecraft:activator_rail", + "blockRuntimeId" : 309 + }, + { + "id" : "minecraft:minecart" + }, + { + "id" : "minecraft:chest_minecart" + }, + { + "id" : "minecraft:hopper_minecart" + }, + { + "id" : "minecraft:tnt_minecart" + }, + { + "id" : "minecraft:redstone" + }, + { + "id" : "minecraft:redstone_block", + "blockRuntimeId" : 3776 + }, + { + "id" : "minecraft:redstone_torch", + "blockRuntimeId" : 3525 + }, + { + "id" : "minecraft:lever", + "blockRuntimeId" : 6514 + }, + { + "id" : "minecraft:wooden_button", + "blockRuntimeId" : 6391 + }, + { + "id" : "minecraft:spruce_button", + "blockRuntimeId" : 4321 + }, + { + "id" : "minecraft:birch_button", + "blockRuntimeId" : 7766 + }, + { + "id" : "minecraft:jungle_button", + "blockRuntimeId" : 116 + }, + { + "id" : "minecraft:acacia_button", + "blockRuntimeId" : 7231 + }, + { + "id" : "minecraft:dark_oak_button", + "blockRuntimeId" : 93 + }, + { + "id" : "minecraft:mangrove_button", + "blockRuntimeId" : 7062 + }, + { + "id" : "minecraft:stone_button", + "blockRuntimeId" : 596 + }, + { + "id" : "minecraft:crimson_button", + "blockRuntimeId" : 4432 + }, + { + "id" : "minecraft:warped_button", + "blockRuntimeId" : 7250 + }, + { + "id" : "minecraft:polished_blackstone_button", + "blockRuntimeId" : 7790 + }, + { + "id" : "minecraft:tripwire_hook", + "blockRuntimeId" : 5914 + }, + { + "id" : "minecraft:wooden_pressure_plate", + "blockRuntimeId" : 8063 + }, + { + "id" : "minecraft:spruce_pressure_plate", + "blockRuntimeId" : 3759 + }, + { + "id" : "minecraft:birch_pressure_plate", + "blockRuntimeId" : 3555 + }, + { + "id" : "minecraft:jungle_pressure_plate", + "blockRuntimeId" : 3635 + }, + { + "id" : "minecraft:acacia_pressure_plate", + "blockRuntimeId" : 5247 + }, + { + "id" : "minecraft:dark_oak_pressure_plate", + "blockRuntimeId" : 5956 + }, + { + "id" : "minecraft:mangrove_pressure_plate", + "blockRuntimeId" : 3869 + }, + { + "id" : "minecraft:crimson_pressure_plate", + "blockRuntimeId" : 8268 + }, + { + "id" : "minecraft:warped_pressure_plate", + "blockRuntimeId" : 256 + }, + { + "id" : "minecraft:stone_pressure_plate", + "blockRuntimeId" : 3886 + }, + { + "id" : "minecraft:light_weighted_pressure_plate", + "blockRuntimeId" : 3665 + }, + { + "id" : "minecraft:heavy_weighted_pressure_plate", + "blockRuntimeId" : 1160 + }, + { + "id" : "minecraft:polished_blackstone_pressure_plate", + "blockRuntimeId" : 6232 + }, + { + "id" : "minecraft:observer", + "blockRuntimeId" : 3513 + }, + { + "id" : "minecraft:daylight_detector", + "blockRuntimeId" : 4197 + }, + { + "id" : "minecraft:repeater" + }, + { + "id" : "minecraft:comparator" + }, + { + "id" : "minecraft:hopper" + }, + { + "id" : "minecraft:dropper", + "blockRuntimeId" : 7385 + }, + { + "id" : "minecraft:dispenser", + "blockRuntimeId" : 8013 + }, + { + "id" : "minecraft:piston", + "blockRuntimeId" : 922 + }, + { + "id" : "minecraft:sticky_piston", + "blockRuntimeId" : 4364 + }, + { + "id" : "minecraft:tnt", + "blockRuntimeId" : 6707 + }, + { + "id" : "minecraft:name_tag" + }, + { + "id" : "minecraft:loom", + "blockRuntimeId" : 3826 + }, + { + "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: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", + "blockRuntimeId" : 6390 + }, + { + "id" : "minecraft:lodestone_compass" + } + ] +} \ No newline at end of file diff --git a/core/src/main/resources/bedrock/runtime_item_states.1_19_0.json b/core/src/main/resources/bedrock/runtime_item_states.1_19_0.json new file mode 100644 index 000000000..b1ffe6353 --- /dev/null +++ b/core/src/main/resources/bedrock/runtime_item_states.1_19_0.json @@ -0,0 +1,4530 @@ +[ + { + "name" : "minecraft:acacia_boat", + "id" : 379 + }, + { + "name" : "minecraft:acacia_button", + "id" : -140 + }, + { + "name" : "minecraft:acacia_chest_boat", + "id" : 643 + }, + { + "name" : "minecraft:acacia_door", + "id" : 556 + }, + { + "name" : "minecraft:acacia_fence_gate", + "id" : 187 + }, + { + "name" : "minecraft:acacia_pressure_plate", + "id" : -150 + }, + { + "name" : "minecraft:acacia_sign", + "id" : 579 + }, + { + "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" : 487 + }, + { + "name" : "minecraft:air", + "id" : -158 + }, + { + "name" : "minecraft:allay_spawn_egg", + "id" : 631 + }, + { + "name" : "minecraft:allow", + "id" : 210 + }, + { + "name" : "minecraft:amethyst_block", + "id" : -327 + }, + { + "name" : "minecraft:amethyst_cluster", + "id" : -329 + }, + { + "name" : "minecraft:amethyst_shard", + "id" : 624 + }, + { + "name" : "minecraft:ancient_debris", + "id" : -271 + }, + { + "name" : "minecraft:andesite_stairs", + "id" : -171 + }, + { + "name" : "minecraft:anvil", + "id" : 145 + }, + { + "name" : "minecraft:apple", + "id" : 257 + }, + { + "name" : "minecraft:armor_stand", + "id" : 552 + }, + { + "name" : "minecraft:arrow", + "id" : 301 + }, + { + "name" : "minecraft:axolotl_bucket", + "id" : 369 + }, + { + "name" : "minecraft:axolotl_spawn_egg", + "id" : 500 + }, + { + "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" : 598 + }, + { + "name" : "minecraft:bamboo", + "id" : -163 + }, + { + "name" : "minecraft:bamboo_sapling", + "id" : -164 + }, + { + "name" : "minecraft:banner", + "id" : 567 + }, + { + "name" : "minecraft:banner_pattern", + "id" : 651 + }, + { + "name" : "minecraft:barrel", + "id" : -203 + }, + { + "name" : "minecraft:barrier", + "id" : -161 + }, + { + "name" : "minecraft:basalt", + "id" : -234 + }, + { + "name" : "minecraft:bat_spawn_egg", + "id" : 453 + }, + { + "name" : "minecraft:beacon", + "id" : 138 + }, + { + "name" : "minecraft:bed", + "id" : 418 + }, + { + "name" : "minecraft:bedrock", + "id" : 7 + }, + { + "name" : "minecraft:bee_nest", + "id" : -218 + }, + { + "name" : "minecraft:bee_spawn_egg", + "id" : 494 + }, + { + "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" : 376 + }, + { + "name" : "minecraft:birch_button", + "id" : -141 + }, + { + "name" : "minecraft:birch_chest_boat", + "id" : 640 + }, + { + "name" : "minecraft:birch_door", + "id" : 554 + }, + { + "name" : "minecraft:birch_fence_gate", + "id" : 184 + }, + { + "name" : "minecraft:birch_pressure_plate", + "id" : -151 + }, + { + "name" : "minecraft:birch_sign", + "id" : 577 + }, + { + "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_dye", + "id" : 395 + }, + { + "name" : "minecraft:black_glazed_terracotta", + "id" : 235 + }, + { + "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:blast_furnace", + "id" : -196 + }, + { + "name" : "minecraft:blaze_powder", + "id" : 429 + }, + { + "name" : "minecraft:blaze_rod", + "id" : 423 + }, + { + "name" : "minecraft:blaze_spawn_egg", + "id" : 456 + }, + { + "name" : "minecraft:bleach", + "id" : 596 + }, + { + "name" : "minecraft:blue_candle", + "id" : -424 + }, + { + "name" : "minecraft:blue_candle_cake", + "id" : -441 + }, + { + "name" : "minecraft:blue_dye", + "id" : 399 + }, + { + "name" : "minecraft:blue_glazed_terracotta", + "id" : 231 + }, + { + "name" : "minecraft:blue_ice", + "id" : -11 + }, + { + "name" : "minecraft:boat", + "id" : 649 + }, + { + "name" : "minecraft:bone", + "id" : 415 + }, + { + "name" : "minecraft:bone_block", + "id" : 216 + }, + { + "name" : "minecraft:bone_meal", + "id" : 411 + }, + { + "name" : "minecraft:book", + "id" : 387 + }, + { + "name" : "minecraft:bookshelf", + "id" : 47 + }, + { + "name" : "minecraft:border_block", + "id" : 212 + }, + { + "name" : "minecraft:bordure_indented_banner_pattern", + "id" : 586 + }, + { + "name" : "minecraft:bow", + "id" : 300 + }, + { + "name" : "minecraft:bowl", + "id" : 321 + }, + { + "name" : "minecraft:bread", + "id" : 261 + }, + { + "name" : "minecraft:brewing_stand", + "id" : 431 + }, + { + "name" : "minecraft:brick", + "id" : 383 + }, + { + "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_dye", + "id" : 398 + }, + { + "name" : "minecraft:brown_glazed_terracotta", + "id" : 232 + }, + { + "name" : "minecraft:brown_mushroom", + "id" : 39 + }, + { + "name" : "minecraft:brown_mushroom_block", + "id" : 99 + }, + { + "name" : "minecraft:bubble_column", + "id" : -160 + }, + { + "name" : "minecraft:bucket", + "id" : 360 + }, + { + "name" : "minecraft:budding_amethyst", + "id" : -328 + }, + { + "name" : "minecraft:cactus", + "id" : 81 + }, + { + "name" : "minecraft:cake", + "id" : 417 + }, + { + "name" : "minecraft:calcite", + "id" : -326 + }, + { + "name" : "minecraft:camera", + "id" : 593 + }, + { + "name" : "minecraft:campfire", + "id" : 589 + }, + { + "name" : "minecraft:candle", + "id" : -412 + }, + { + "name" : "minecraft:candle_cake", + "id" : -429 + }, + { + "name" : "minecraft:carpet", + "id" : 171 + }, + { + "name" : "minecraft:carrot", + "id" : 279 + }, + { + "name" : "minecraft:carrot_on_a_stick", + "id" : 517 + }, + { + "name" : "minecraft:carrots", + "id" : 141 + }, + { + "name" : "minecraft:cartography_table", + "id" : -200 + }, + { + "name" : "minecraft:carved_pumpkin", + "id" : -155 + }, + { + "name" : "minecraft:cat_spawn_egg", + "id" : 488 + }, + { + "name" : "minecraft:cauldron", + "id" : 432 + }, + { + "name" : "minecraft:cave_spider_spawn_egg", + "id" : 457 + }, + { + "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" : 619 + }, + { + "name" : "minecraft:chain_command_block", + "id" : 189 + }, + { + "name" : "minecraft:chainmail_boots", + "id" : 342 + }, + { + "name" : "minecraft:chainmail_chestplate", + "id" : 340 + }, + { + "name" : "minecraft:chainmail_helmet", + "id" : 339 + }, + { + "name" : "minecraft:chainmail_leggings", + "id" : 341 + }, + { + "name" : "minecraft:charcoal", + "id" : 303 + }, + { + "name" : "minecraft:chemical_heat", + "id" : 192 + }, + { + "name" : "minecraft:chemistry_table", + "id" : 238 + }, + { + "name" : "minecraft:chest", + "id" : 54 + }, + { + "name" : "minecraft:chest_boat", + "id" : 646 + }, + { + "name" : "minecraft:chest_minecart", + "id" : 389 + }, + { + "name" : "minecraft:chicken", + "id" : 275 + }, + { + "name" : "minecraft:chicken_spawn_egg", + "id" : 435 + }, + { + "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" : 558 + }, + { + "name" : "minecraft:chorus_plant", + "id" : 240 + }, + { + "name" : "minecraft:clay", + "id" : 82 + }, + { + "name" : "minecraft:clay_ball", + "id" : 384 + }, + { + "name" : "minecraft:client_request_placeholder_block", + "id" : -465 + }, + { + "name" : "minecraft:clock", + "id" : 393 + }, + { + "name" : "minecraft:coal", + "id" : 302 + }, + { + "name" : "minecraft:coal_block", + "id" : 173 + }, + { + "name" : "minecraft:coal_ore", + "id" : 16 + }, + { + "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" : 412 + }, + { + "name" : "minecraft:cod", + "id" : 264 + }, + { + "name" : "minecraft:cod_bucket", + "id" : 364 + }, + { + "name" : "minecraft:cod_spawn_egg", + "id" : 480 + }, + { + "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" : 563 + }, + { + "name" : "minecraft:comparator", + "id" : 522 + }, + { + "name" : "minecraft:compass", + "id" : 391 + }, + { + "name" : "minecraft:composter", + "id" : -213 + }, + { + "name" : "minecraft:compound", + "id" : 594 + }, + { + "name" : "minecraft:concrete", + "id" : 236 + }, + { + "name" : "minecraft:concrete_powder", + "id" : 237 + }, + { + "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" : 551 + }, + { + "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" : 504 + }, + { + "name" : "minecraft:copper_ore", + "id" : -311 + }, + { + "name" : "minecraft:coral", + "id" : -131 + }, + { + "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" : 436 + }, + { + "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" : 582 + }, + { + "name" : "minecraft:creeper_spawn_egg", + "id" : 441 + }, + { + "name" : "minecraft:crimson_button", + "id" : -260 + }, + { + "name" : "minecraft:crimson_door", + "id" : 616 + }, + { + "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_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" : 614 + }, + { + "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" : 575 + }, + { + "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_dye", + "id" : 401 + }, + { + "name" : "minecraft:cyan_glazed_terracotta", + "id" : 229 + }, + { + "name" : "minecraft:dark_oak_boat", + "id" : 380 + }, + { + "name" : "minecraft:dark_oak_button", + "id" : -142 + }, + { + "name" : "minecraft:dark_oak_chest_boat", + "id" : 644 + }, + { + "name" : "minecraft:dark_oak_door", + "id" : 557 + }, + { + "name" : "minecraft:dark_oak_fence_gate", + "id" : 186 + }, + { + "name" : "minecraft:dark_oak_pressure_plate", + "id" : -152 + }, + { + "name" : "minecraft:dark_oak_sign", + "id" : 580 + }, + { + "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:deadbush", + "id" : 32 + }, + { + "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" : 304 + }, + { + "name" : "minecraft:diamond_axe", + "id" : 319 + }, + { + "name" : "minecraft:diamond_block", + "id" : 57 + }, + { + "name" : "minecraft:diamond_boots", + "id" : 350 + }, + { + "name" : "minecraft:diamond_chestplate", + "id" : 348 + }, + { + "name" : "minecraft:diamond_helmet", + "id" : 347 + }, + { + "name" : "minecraft:diamond_hoe", + "id" : 332 + }, + { + "name" : "minecraft:diamond_horse_armor", + "id" : 533 + }, + { + "name" : "minecraft:diamond_leggings", + "id" : 349 + }, + { + "name" : "minecraft:diamond_ore", + "id" : 56 + }, + { + "name" : "minecraft:diamond_pickaxe", + "id" : 318 + }, + { + "name" : "minecraft:diamond_shovel", + "id" : 317 + }, + { + "name" : "minecraft:diamond_sword", + "id" : 316 + }, + { + "name" : "minecraft:diorite_stairs", + "id" : -170 + }, + { + "name" : "minecraft:dirt", + "id" : 3 + }, + { + "name" : "minecraft:dirt_with_roots", + "id" : -318 + }, + { + "name" : "minecraft:disc_fragment_5", + "id" : 638 + }, + { + "name" : "minecraft:dispenser", + "id" : 23 + }, + { + "name" : "minecraft:dolphin_spawn_egg", + "id" : 484 + }, + { + "name" : "minecraft:donkey_spawn_egg", + "id" : 465 + }, + { + "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" : 560 + }, + { + "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" : 483 + }, + { + "name" : "minecraft:dye", + "id" : 650 + }, + { + "name" : "minecraft:echo_shard", + "id" : 648 + }, + { + "name" : "minecraft:egg", + "id" : 390 + }, + { + "name" : "minecraft:elder_guardian_spawn_egg", + "id" : 471 + }, + { + "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" : 564 + }, + { + "name" : "minecraft:emerald", + "id" : 512 + }, + { + "name" : "minecraft:emerald_block", + "id" : 133 + }, + { + "name" : "minecraft:emerald_ore", + "id" : 129 + }, + { + "name" : "minecraft:empty_map", + "id" : 515 + }, + { + "name" : "minecraft:enchanted_book", + "id" : 521 + }, + { + "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" : 653 + }, + { + "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_eye", + "id" : 433 + }, + { + "name" : "minecraft:ender_pearl", + "id" : 422 + }, + { + "name" : "minecraft:enderman_spawn_egg", + "id" : 442 + }, + { + "name" : "minecraft:endermite_spawn_egg", + "id" : 460 + }, + { + "name" : "minecraft:evoker_spawn_egg", + "id" : 475 + }, + { + "name" : "minecraft:experience_bottle", + "id" : 508 + }, + { + "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:farmland", + "id" : 60 + }, + { + "name" : "minecraft:feather", + "id" : 327 + }, + { + "name" : "minecraft:fence", + "id" : 85 + }, + { + "name" : "minecraft:fence_gate", + "id" : 107 + }, + { + "name" : "minecraft:fermented_spider_eye", + "id" : 428 + }, + { + "name" : "minecraft:field_masoned_banner_pattern", + "id" : 585 + }, + { + "name" : "minecraft:filled_map", + "id" : 420 + }, + { + "name" : "minecraft:fire", + "id" : 51 + }, + { + "name" : "minecraft:fire_charge", + "id" : 509 + }, + { + "name" : "minecraft:firefly_spawn_egg", + "id" : 633 + }, + { + "name" : "minecraft:firework_rocket", + "id" : 519 + }, + { + "name" : "minecraft:firework_star", + "id" : 520 + }, + { + "name" : "minecraft:fishing_rod", + "id" : 392 + }, + { + "name" : "minecraft:fletching_table", + "id" : -201 + }, + { + "name" : "minecraft:flint", + "id" : 356 + }, + { + "name" : "minecraft:flint_and_steel", + "id" : 299 + }, + { + "name" : "minecraft:flower_banner_pattern", + "id" : 581 + }, + { + "name" : "minecraft:flower_pot", + "id" : 514 + }, + { + "name" : "minecraft:flowering_azalea", + "id" : -338 + }, + { + "name" : "minecraft:flowing_lava", + "id" : 10 + }, + { + "name" : "minecraft:flowing_water", + "id" : 8 + }, + { + "name" : "minecraft:fox_spawn_egg", + "id" : 490 + }, + { + "name" : "minecraft:frame", + "id" : 513 + }, + { + "name" : "minecraft:frog_spawn", + "id" : -468 + }, + { + "name" : "minecraft:frog_spawn_egg", + "id" : 628 + }, + { + "name" : "minecraft:frosted_ice", + "id" : 207 + }, + { + "name" : "minecraft:furnace", + "id" : 61 + }, + { + "name" : "minecraft:ghast_spawn_egg", + "id" : 454 + }, + { + "name" : "minecraft:ghast_tear", + "id" : 424 + }, + { + "name" : "minecraft:gilded_blackstone", + "id" : -281 + }, + { + "name" : "minecraft:glass", + "id" : 20 + }, + { + "name" : "minecraft:glass_bottle", + "id" : 427 + }, + { + "name" : "minecraft:glass_pane", + "id" : 102 + }, + { + "name" : "minecraft:glistering_melon_slice", + "id" : 434 + }, + { + "name" : "minecraft:globe_banner_pattern", + "id" : 588 + }, + { + "name" : "minecraft:glow_berries", + "id" : 654 + }, + { + "name" : "minecraft:glow_frame", + "id" : 623 + }, + { + "name" : "minecraft:glow_ink_sac", + "id" : 503 + }, + { + "name" : "minecraft:glow_lichen", + "id" : -411 + }, + { + "name" : "minecraft:glow_squid_spawn_egg", + "id" : 502 + }, + { + "name" : "minecraft:glow_stick", + "id" : 601 + }, + { + "name" : "minecraft:glowingobsidian", + "id" : 246 + }, + { + "name" : "minecraft:glowstone", + "id" : 89 + }, + { + "name" : "minecraft:glowstone_dust", + "id" : 394 + }, + { + "name" : "minecraft:goat_horn", + "id" : 627 + }, + { + "name" : "minecraft:goat_spawn_egg", + "id" : 501 + }, + { + "name" : "minecraft:gold_block", + "id" : 41 + }, + { + "name" : "minecraft:gold_ingot", + "id" : 306 + }, + { + "name" : "minecraft:gold_nugget", + "id" : 425 + }, + { + "name" : "minecraft:gold_ore", + "id" : 14 + }, + { + "name" : "minecraft:golden_apple", + "id" : 258 + }, + { + "name" : "minecraft:golden_axe", + "id" : 325 + }, + { + "name" : "minecraft:golden_boots", + "id" : 354 + }, + { + "name" : "minecraft:golden_carrot", + "id" : 283 + }, + { + "name" : "minecraft:golden_chestplate", + "id" : 352 + }, + { + "name" : "minecraft:golden_helmet", + "id" : 351 + }, + { + "name" : "minecraft:golden_hoe", + "id" : 333 + }, + { + "name" : "minecraft:golden_horse_armor", + "id" : 532 + }, + { + "name" : "minecraft:golden_leggings", + "id" : 353 + }, + { + "name" : "minecraft:golden_pickaxe", + "id" : 324 + }, + { + "name" : "minecraft:golden_rail", + "id" : 27 + }, + { + "name" : "minecraft:golden_shovel", + "id" : 323 + }, + { + "name" : "minecraft:golden_sword", + "id" : 322 + }, + { + "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_dye", + "id" : 403 + }, + { + "name" : "minecraft:gray_glazed_terracotta", + "id" : 227 + }, + { + "name" : "minecraft:green_candle", + "id" : -426 + }, + { + "name" : "minecraft:green_candle_cake", + "id" : -443 + }, + { + "name" : "minecraft:green_dye", + "id" : 397 + }, + { + "name" : "minecraft:green_glazed_terracotta", + "id" : 233 + }, + { + "name" : "minecraft:grindstone", + "id" : -195 + }, + { + "name" : "minecraft:guardian_spawn_egg", + "id" : 461 + }, + { + "name" : "minecraft:gunpowder", + "id" : 328 + }, + { + "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" : 571 + }, + { + "name" : "minecraft:heavy_weighted_pressure_plate", + "id" : 148 + }, + { + "name" : "minecraft:hoglin_spawn_egg", + "id" : 496 + }, + { + "name" : "minecraft:honey_block", + "id" : -220 + }, + { + "name" : "minecraft:honey_bottle", + "id" : 592 + }, + { + "name" : "minecraft:honeycomb", + "id" : 591 + }, + { + "name" : "minecraft:honeycomb_block", + "id" : -221 + }, + { + "name" : "minecraft:hopper", + "id" : 527 + }, + { + "name" : "minecraft:hopper_minecart", + "id" : 526 + }, + { + "name" : "minecraft:horse_spawn_egg", + "id" : 458 + }, + { + "name" : "minecraft:husk_spawn_egg", + "id" : 463 + }, + { + "name" : "minecraft:ice", + "id" : 79 + }, + { + "name" : "minecraft:ice_bomb", + "id" : 595 + }, + { + "name" : "minecraft:infested_deepslate", + "id" : -454 + }, + { + "name" : "minecraft:info_update", + "id" : 248 + }, + { + "name" : "minecraft:info_update2", + "id" : 249 + }, + { + "name" : "minecraft:ink_sac", + "id" : 413 + }, + { + "name" : "minecraft:invisible_bedrock", + "id" : 95 + }, + { + "name" : "minecraft:iron_axe", + "id" : 298 + }, + { + "name" : "minecraft:iron_bars", + "id" : 101 + }, + { + "name" : "minecraft:iron_block", + "id" : 42 + }, + { + "name" : "minecraft:iron_boots", + "id" : 346 + }, + { + "name" : "minecraft:iron_chestplate", + "id" : 344 + }, + { + "name" : "minecraft:iron_door", + "id" : 372 + }, + { + "name" : "minecraft:iron_helmet", + "id" : 343 + }, + { + "name" : "minecraft:iron_hoe", + "id" : 331 + }, + { + "name" : "minecraft:iron_horse_armor", + "id" : 531 + }, + { + "name" : "minecraft:iron_ingot", + "id" : 305 + }, + { + "name" : "minecraft:iron_leggings", + "id" : 345 + }, + { + "name" : "minecraft:iron_nugget", + "id" : 569 + }, + { + "name" : "minecraft:iron_ore", + "id" : 15 + }, + { + "name" : "minecraft:iron_pickaxe", + "id" : 297 + }, + { + "name" : "minecraft:iron_shovel", + "id" : 296 + }, + { + "name" : "minecraft:iron_sword", + "id" : 307 + }, + { + "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" : 377 + }, + { + "name" : "minecraft:jungle_button", + "id" : -143 + }, + { + "name" : "minecraft:jungle_chest_boat", + "id" : 641 + }, + { + "name" : "minecraft:jungle_door", + "id" : 555 + }, + { + "name" : "minecraft:jungle_fence_gate", + "id" : 185 + }, + { + "name" : "minecraft:jungle_pressure_plate", + "id" : -153 + }, + { + "name" : "minecraft:jungle_sign", + "id" : 578 + }, + { + "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" : 382 + }, + { + "name" : "minecraft:ladder", + "id" : 65 + }, + { + "name" : "minecraft:lantern", + "id" : -208 + }, + { + "name" : "minecraft:lapis_block", + "id" : 22 + }, + { + "name" : "minecraft:lapis_lazuli", + "id" : 414 + }, + { + "name" : "minecraft:lapis_ore", + "id" : 21 + }, + { + "name" : "minecraft:large_amethyst_bud", + "id" : -330 + }, + { + "name" : "minecraft:lava", + "id" : 11 + }, + { + "name" : "minecraft:lava_bucket", + "id" : 363 + }, + { + "name" : "minecraft:lava_cauldron", + "id" : -210 + }, + { + "name" : "minecraft:lead", + "id" : 547 + }, + { + "name" : "minecraft:leather", + "id" : 381 + }, + { + "name" : "minecraft:leather_boots", + "id" : 338 + }, + { + "name" : "minecraft:leather_chestplate", + "id" : 336 + }, + { + "name" : "minecraft:leather_helmet", + "id" : 335 + }, + { + "name" : "minecraft:leather_horse_armor", + "id" : 530 + }, + { + "name" : "minecraft:leather_leggings", + "id" : 337 + }, + { + "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_dye", + "id" : 407 + }, + { + "name" : "minecraft:light_blue_glazed_terracotta", + "id" : 223 + }, + { + "name" : "minecraft:light_gray_candle", + "id" : -421 + }, + { + "name" : "minecraft:light_gray_candle_cake", + "id" : -438 + }, + { + "name" : "minecraft:light_gray_dye", + "id" : 402 + }, + { + "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_dye", + "id" : 405 + }, + { + "name" : "minecraft:lime_glazed_terracotta", + "id" : 225 + }, + { + "name" : "minecraft:lingering_potion", + "id" : 562 + }, + { + "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" : 473 + }, + { + "name" : "minecraft:lodestone", + "id" : -222 + }, + { + "name" : "minecraft:lodestone_compass", + "id" : 602 + }, + { + "name" : "minecraft:log", + "id" : 17 + }, + { + "name" : "minecraft:log2", + "id" : 162 + }, + { + "name" : "minecraft:loom", + "id" : -204 + }, + { + "name" : "minecraft:magenta_candle", + "id" : -415 + }, + { + "name" : "minecraft:magenta_candle_cake", + "id" : -432 + }, + { + "name" : "minecraft:magenta_dye", + "id" : 408 + }, + { + "name" : "minecraft:magenta_glazed_terracotta", + "id" : 222 + }, + { + "name" : "minecraft:magma", + "id" : 213 + }, + { + "name" : "minecraft:magma_cream", + "id" : 430 + }, + { + "name" : "minecraft:magma_cube_spawn_egg", + "id" : 455 + }, + { + "name" : "minecraft:mangrove_boat", + "id" : 636 + }, + { + "name" : "minecraft:mangrove_button", + "id" : -487 + }, + { + "name" : "minecraft:mangrove_chest_boat", + "id" : 645 + }, + { + "name" : "minecraft:mangrove_door", + "id" : 634 + }, + { + "name" : "minecraft:mangrove_double_slab", + "id" : -499 + }, + { + "name" : "minecraft:mangrove_fence", + "id" : -491 + }, + { + "name" : "minecraft:mangrove_fence_gate", + "id" : -492 + }, + { + "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" : 635 + }, + { + "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" : 599 + }, + { + "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" : 361 + }, + { + "name" : "minecraft:minecart", + "id" : 370 + }, + { + "name" : "minecraft:mob_spawner", + "id" : 52 + }, + { + "name" : "minecraft:mojang_banner_pattern", + "id" : 584 + }, + { + "name" : "minecraft:monster_egg", + "id" : 97 + }, + { + "name" : "minecraft:mooshroom_spawn_egg", + "id" : 440 + }, + { + "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: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" : 466 + }, + { + "name" : "minecraft:mushroom_stew", + "id" : 260 + }, + { + "name" : "minecraft:music_disc_11", + "id" : 544 + }, + { + "name" : "minecraft:music_disc_13", + "id" : 534 + }, + { + "name" : "minecraft:music_disc_5", + "id" : 637 + }, + { + "name" : "minecraft:music_disc_blocks", + "id" : 536 + }, + { + "name" : "minecraft:music_disc_cat", + "id" : 535 + }, + { + "name" : "minecraft:music_disc_chirp", + "id" : 537 + }, + { + "name" : "minecraft:music_disc_far", + "id" : 538 + }, + { + "name" : "minecraft:music_disc_mall", + "id" : 539 + }, + { + "name" : "minecraft:music_disc_mellohi", + "id" : 540 + }, + { + "name" : "minecraft:music_disc_otherside", + "id" : 626 + }, + { + "name" : "minecraft:music_disc_pigstep", + "id" : 620 + }, + { + "name" : "minecraft:music_disc_stal", + "id" : 541 + }, + { + "name" : "minecraft:music_disc_strad", + "id" : 542 + }, + { + "name" : "minecraft:music_disc_wait", + "id" : 545 + }, + { + "name" : "minecraft:music_disc_ward", + "id" : 543 + }, + { + "name" : "minecraft:mutton", + "id" : 550 + }, + { + "name" : "minecraft:mycelium", + "id" : 110 + }, + { + "name" : "minecraft:name_tag", + "id" : 548 + }, + { + "name" : "minecraft:nautilus_shell", + "id" : 570 + }, + { + "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" : 621 + }, + { + "name" : "minecraft:nether_star", + "id" : 518 + }, + { + "name" : "minecraft:nether_wart", + "id" : 294 + }, + { + "name" : "minecraft:nether_wart_block", + "id" : 214 + }, + { + "name" : "minecraft:netherbrick", + "id" : 523 + }, + { + "name" : "minecraft:netherite_axe", + "id" : 607 + }, + { + "name" : "minecraft:netherite_block", + "id" : -270 + }, + { + "name" : "minecraft:netherite_boots", + "id" : 612 + }, + { + "name" : "minecraft:netherite_chestplate", + "id" : 610 + }, + { + "name" : "minecraft:netherite_helmet", + "id" : 609 + }, + { + "name" : "minecraft:netherite_hoe", + "id" : 608 + }, + { + "name" : "minecraft:netherite_ingot", + "id" : 603 + }, + { + "name" : "minecraft:netherite_leggings", + "id" : 611 + }, + { + "name" : "minecraft:netherite_pickaxe", + "id" : 606 + }, + { + "name" : "minecraft:netherite_scrap", + "id" : 613 + }, + { + "name" : "minecraft:netherite_shovel", + "id" : 605 + }, + { + "name" : "minecraft:netherite_sword", + "id" : 604 + }, + { + "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" : 470 + }, + { + "name" : "minecraft:oak_boat", + "id" : 375 + }, + { + "name" : "minecraft:oak_chest_boat", + "id" : 639 + }, + { + "name" : "minecraft:oak_sign", + "id" : 358 + }, + { + "name" : "minecraft:oak_stairs", + "id" : 53 + }, + { + "name" : "minecraft:observer", + "id" : 251 + }, + { + "name" : "minecraft:obsidian", + "id" : 49 + }, + { + "name" : "minecraft:ocelot_spawn_egg", + "id" : 451 + }, + { + "name" : "minecraft:ochre_froglight", + "id" : -471 + }, + { + "name" : "minecraft:orange_candle", + "id" : -414 + }, + { + "name" : "minecraft:orange_candle_cake", + "id" : -431 + }, + { + "name" : "minecraft:orange_dye", + "id" : 409 + }, + { + "name" : "minecraft:orange_glazed_terracotta", + "id" : 221 + }, + { + "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" : 357 + }, + { + "name" : "minecraft:panda_spawn_egg", + "id" : 489 + }, + { + "name" : "minecraft:paper", + "id" : 386 + }, + { + "name" : "minecraft:parrot_spawn_egg", + "id" : 478 + }, + { + "name" : "minecraft:pearlescent_froglight", + "id" : -469 + }, + { + "name" : "minecraft:phantom_membrane", + "id" : 574 + }, + { + "name" : "minecraft:phantom_spawn_egg", + "id" : 486 + }, + { + "name" : "minecraft:pig_spawn_egg", + "id" : 437 + }, + { + "name" : "minecraft:piglin_banner_pattern", + "id" : 587 + }, + { + "name" : "minecraft:piglin_brute_spawn_egg", + "id" : 499 + }, + { + "name" : "minecraft:piglin_spawn_egg", + "id" : 497 + }, + { + "name" : "minecraft:pillager_spawn_egg", + "id" : 491 + }, + { + "name" : "minecraft:pink_candle", + "id" : -419 + }, + { + "name" : "minecraft:pink_candle_cake", + "id" : -436 + }, + { + "name" : "minecraft:pink_dye", + "id" : 404 + }, + { + "name" : "minecraft:pink_glazed_terracotta", + "id" : 226 + }, + { + "name" : "minecraft:piston", + "id" : 33 + }, + { + "name" : "minecraft:piston_arm_collision", + "id" : 34 + }, + { + "name" : "minecraft:planks", + "id" : 5 + }, + { + "name" : "minecraft:podzol", + "id" : 243 + }, + { + "name" : "minecraft:pointed_dripstone", + "id" : -308 + }, + { + "name" : "minecraft:poisonous_potato", + "id" : 282 + }, + { + "name" : "minecraft:polar_bear_spawn_egg", + "id" : 472 + }, + { + "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" : 559 + }, + { + "name" : "minecraft:porkchop", + "id" : 262 + }, + { + "name" : "minecraft:portal", + "id" : 90 + }, + { + "name" : "minecraft:potato", + "id" : 280 + }, + { + "name" : "minecraft:potatoes", + "id" : 142 + }, + { + "name" : "minecraft:potion", + "id" : 426 + }, + { + "name" : "minecraft:powder_snow", + "id" : -306 + }, + { + "name" : "minecraft:powder_snow_bucket", + "id" : 368 + }, + { + "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" : 549 + }, + { + "name" : "minecraft:prismarine_shard", + "id" : 565 + }, + { + "name" : "minecraft:prismarine_stairs", + "id" : -2 + }, + { + "name" : "minecraft:pufferfish", + "id" : 267 + }, + { + "name" : "minecraft:pufferfish_bucket", + "id" : 367 + }, + { + "name" : "minecraft:pufferfish_spawn_egg", + "id" : 481 + }, + { + "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_dye", + "id" : 400 + }, + { + "name" : "minecraft:purple_glazed_terracotta", + "id" : 219 + }, + { + "name" : "minecraft:purpur_block", + "id" : 201 + }, + { + "name" : "minecraft:purpur_stairs", + "id" : 203 + }, + { + "name" : "minecraft:quartz", + "id" : 524 + }, + { + "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" : 528 + }, + { + "name" : "minecraft:rabbit_hide", + "id" : 529 + }, + { + "name" : "minecraft:rabbit_spawn_egg", + "id" : 459 + }, + { + "name" : "minecraft:rabbit_stew", + "id" : 290 + }, + { + "name" : "minecraft:rail", + "id" : 66 + }, + { + "name" : "minecraft:rapid_fertilizer", + "id" : 597 + }, + { + "name" : "minecraft:ravager_spawn_egg", + "id" : 493 + }, + { + "name" : "minecraft:raw_copper", + "id" : 507 + }, + { + "name" : "minecraft:raw_copper_block", + "id" : -452 + }, + { + "name" : "minecraft:raw_gold", + "id" : 506 + }, + { + "name" : "minecraft:raw_gold_block", + "id" : -453 + }, + { + "name" : "minecraft:raw_iron", + "id" : 505 + }, + { + "name" : "minecraft:raw_iron_block", + "id" : -451 + }, + { + "name" : "minecraft:recovery_compass", + "id" : 647 + }, + { + "name" : "minecraft:red_candle", + "id" : -427 + }, + { + "name" : "minecraft:red_candle_cake", + "id" : -444 + }, + { + "name" : "minecraft:red_dye", + "id" : 396 + }, + { + "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:redstone", + "id" : 373 + }, + { + "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" : 419 + }, + { + "name" : "minecraft:repeating_command_block", + "id" : 188 + }, + { + "name" : "minecraft:reserved6", + "id" : 255 + }, + { + "name" : "minecraft:respawn_anchor", + "id" : -272 + }, + { + "name" : "minecraft:rotten_flesh", + "id" : 277 + }, + { + "name" : "minecraft:saddle", + "id" : 371 + }, + { + "name" : "minecraft:salmon", + "id" : 265 + }, + { + "name" : "minecraft:salmon_bucket", + "id" : 365 + }, + { + "name" : "minecraft:salmon_spawn_egg", + "id" : 482 + }, + { + "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" : 572 + }, + { + "name" : "minecraft:sea_lantern", + "id" : 169 + }, + { + "name" : "minecraft:sea_pickle", + "id" : -156 + }, + { + "name" : "minecraft:seagrass", + "id" : -130 + }, + { + "name" : "minecraft:shears", + "id" : 421 + }, + { + "name" : "minecraft:sheep_spawn_egg", + "id" : 438 + }, + { + "name" : "minecraft:shield", + "id" : 355 + }, + { + "name" : "minecraft:shroomlight", + "id" : -230 + }, + { + "name" : "minecraft:shulker_box", + "id" : 218 + }, + { + "name" : "minecraft:shulker_shell", + "id" : 566 + }, + { + "name" : "minecraft:shulker_spawn_egg", + "id" : 469 + }, + { + "name" : "minecraft:silver_glazed_terracotta", + "id" : 228 + }, + { + "name" : "minecraft:silverfish_spawn_egg", + "id" : 443 + }, + { + "name" : "minecraft:skeleton_horse_spawn_egg", + "id" : 467 + }, + { + "name" : "minecraft:skeleton_spawn_egg", + "id" : 444 + }, + { + "name" : "minecraft:skull", + "id" : 516 + }, + { + "name" : "minecraft:skull_banner_pattern", + "id" : 583 + }, + { + "name" : "minecraft:slime", + "id" : 165 + }, + { + "name" : "minecraft:slime_ball", + "id" : 388 + }, + { + "name" : "minecraft:slime_spawn_egg", + "id" : 445 + }, + { + "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:snow", + "id" : 80 + }, + { + "name" : "minecraft:snow_layer", + "id" : 78 + }, + { + "name" : "minecraft:snowball", + "id" : 374 + }, + { + "name" : "minecraft:soul_campfire", + "id" : 622 + }, + { + "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" : 600 + }, + { + "name" : "minecraft:spawn_egg", + "id" : 652 + }, + { + "name" : "minecraft:spider_eye", + "id" : 278 + }, + { + "name" : "minecraft:spider_spawn_egg", + "id" : 446 + }, + { + "name" : "minecraft:splash_potion", + "id" : 561 + }, + { + "name" : "minecraft:sponge", + "id" : 19 + }, + { + "name" : "minecraft:spore_blossom", + "id" : -321 + }, + { + "name" : "minecraft:spruce_boat", + "id" : 378 + }, + { + "name" : "minecraft:spruce_button", + "id" : -144 + }, + { + "name" : "minecraft:spruce_chest_boat", + "id" : 642 + }, + { + "name" : "minecraft:spruce_door", + "id" : 553 + }, + { + "name" : "minecraft:spruce_fence_gate", + "id" : 183 + }, + { + "name" : "minecraft:spruce_pressure_plate", + "id" : -154 + }, + { + "name" : "minecraft:spruce_sign", + "id" : 576 + }, + { + "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" : 625 + }, + { + "name" : "minecraft:squid_spawn_egg", + "id" : 450 + }, + { + "name" : "minecraft:stained_glass", + "id" : 241 + }, + { + "name" : "minecraft:stained_glass_pane", + "id" : 160 + }, + { + "name" : "minecraft:stained_hardened_clay", + "id" : 159 + }, + { + "name" : "minecraft:standing_banner", + "id" : 176 + }, + { + "name" : "minecraft:standing_sign", + "id" : 63 + }, + { + "name" : "minecraft:stick", + "id" : 320 + }, + { + "name" : "minecraft:sticky_piston", + "id" : 29 + }, + { + "name" : "minecraft:sticky_piston_arm_collision", + "id" : -217 + }, + { + "name" : "minecraft:stone", + "id" : 1 + }, + { + "name" : "minecraft:stone_axe", + "id" : 315 + }, + { + "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" : 330 + }, + { + "name" : "minecraft:stone_pickaxe", + "id" : 314 + }, + { + "name" : "minecraft:stone_pressure_plate", + "id" : 70 + }, + { + "name" : "minecraft:stone_shovel", + "id" : 313 + }, + { + "name" : "minecraft:stone_stairs", + "id" : 67 + }, + { + "name" : "minecraft:stone_sword", + "id" : 312 + }, + { + "name" : "minecraft:stonebrick", + "id" : 98 + }, + { + "name" : "minecraft:stonecutter", + "id" : 245 + }, + { + "name" : "minecraft:stonecutter_block", + "id" : -197 + }, + { + "name" : "minecraft:stray_spawn_egg", + "id" : 462 + }, + { + "name" : "minecraft:strider_spawn_egg", + "id" : 495 + }, + { + "name" : "minecraft:string", + "id" : 326 + }, + { + "name" : "minecraft:stripped_acacia_log", + "id" : -8 + }, + { + "name" : "minecraft:stripped_birch_log", + "id" : -6 + }, + { + "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" : 416 + }, + { + "name" : "minecraft:sugar_cane", + "id" : 385 + }, + { + "name" : "minecraft:suspicious_stew", + "id" : 590 + }, + { + "name" : "minecraft:sweet_berries", + "id" : 287 + }, + { + "name" : "minecraft:sweet_berry_bush", + "id" : -207 + }, + { + "name" : "minecraft:tadpole_bucket", + "id" : 630 + }, + { + "name" : "minecraft:tadpole_spawn_egg", + "id" : 629 + }, + { + "name" : "minecraft:tallgrass", + "id" : 31 + }, + { + "name" : "minecraft:target", + "id" : -239 + }, + { + "name" : "minecraft:tinted_glass", + "id" : -334 + }, + { + "name" : "minecraft:tnt", + "id" : 46 + }, + { + "name" : "minecraft:tnt_minecart", + "id" : 525 + }, + { + "name" : "minecraft:torch", + "id" : 50 + }, + { + "name" : "minecraft:totem_of_undying", + "id" : 568 + }, + { + "name" : "minecraft:trapdoor", + "id" : 96 + }, + { + "name" : "minecraft:trapped_chest", + "id" : 146 + }, + { + "name" : "minecraft:trident", + "id" : 546 + }, + { + "name" : "minecraft:trip_wire", + "id" : 132 + }, + { + "name" : "minecraft:tripwire_hook", + "id" : 131 + }, + { + "name" : "minecraft:tropical_fish", + "id" : 266 + }, + { + "name" : "minecraft:tropical_fish_bucket", + "id" : 366 + }, + { + "name" : "minecraft:tropical_fish_spawn_egg", + "id" : 479 + }, + { + "name" : "minecraft:tuff", + "id" : -333 + }, + { + "name" : "minecraft:turtle_egg", + "id" : -159 + }, + { + "name" : "minecraft:turtle_helmet", + "id" : 573 + }, + { + "name" : "minecraft:turtle_spawn_egg", + "id" : 485 + }, + { + "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_spawn_egg", + "id" : 476 + }, + { + "name" : "minecraft:villager_spawn_egg", + "id" : 449 + }, + { + "name" : "minecraft:vindicator_spawn_egg", + "id" : 474 + }, + { + "name" : "minecraft:vine", + "id" : 106 + }, + { + "name" : "minecraft:wall_banner", + "id" : 177 + }, + { + "name" : "minecraft:wall_sign", + "id" : 68 + }, + { + "name" : "minecraft:wandering_trader_spawn_egg", + "id" : 492 + }, + { + "name" : "minecraft:warden_spawn_egg", + "id" : 632 + }, + { + "name" : "minecraft:warped_button", + "id" : -261 + }, + { + "name" : "minecraft:warped_door", + "id" : 617 + }, + { + "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" : 618 + }, + { + "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" : 615 + }, + { + "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" : 362 + }, + { + "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: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" : 334 + }, + { + "name" : "minecraft:wheat_seeds", + "id" : 291 + }, + { + "name" : "minecraft:white_candle", + "id" : -413 + }, + { + "name" : "minecraft:white_candle_cake", + "id" : -430 + }, + { + "name" : "minecraft:white_dye", + "id" : 410 + }, + { + "name" : "minecraft:white_glazed_terracotta", + "id" : 220 + }, + { + "name" : "minecraft:witch_spawn_egg", + "id" : 452 + }, + { + "name" : "minecraft:wither_rose", + "id" : -216 + }, + { + "name" : "minecraft:wither_skeleton_spawn_egg", + "id" : 464 + }, + { + "name" : "minecraft:wolf_spawn_egg", + "id" : 439 + }, + { + "name" : "minecraft:wood", + "id" : -212 + }, + { + "name" : "minecraft:wooden_axe", + "id" : 311 + }, + { + "name" : "minecraft:wooden_button", + "id" : 143 + }, + { + "name" : "minecraft:wooden_door", + "id" : 359 + }, + { + "name" : "minecraft:wooden_hoe", + "id" : 329 + }, + { + "name" : "minecraft:wooden_pickaxe", + "id" : 310 + }, + { + "name" : "minecraft:wooden_pressure_plate", + "id" : 72 + }, + { + "name" : "minecraft:wooden_shovel", + "id" : 309 + }, + { + "name" : "minecraft:wooden_slab", + "id" : 158 + }, + { + "name" : "minecraft:wooden_sword", + "id" : 308 + }, + { + "name" : "minecraft:wool", + "id" : 35 + }, + { + "name" : "minecraft:writable_book", + "id" : 510 + }, + { + "name" : "minecraft:written_book", + "id" : 511 + }, + { + "name" : "minecraft:yellow_candle", + "id" : -417 + }, + { + "name" : "minecraft:yellow_candle_cake", + "id" : -434 + }, + { + "name" : "minecraft:yellow_dye", + "id" : 406 + }, + { + "name" : "minecraft:yellow_flower", + "id" : 37 + }, + { + "name" : "minecraft:yellow_glazed_terracotta", + "id" : 224 + }, + { + "name" : "minecraft:zoglin_spawn_egg", + "id" : 498 + }, + { + "name" : "minecraft:zombie_horse_spawn_egg", + "id" : 468 + }, + { + "name" : "minecraft:zombie_pigman_spawn_egg", + "id" : 448 + }, + { + "name" : "minecraft:zombie_spawn_egg", + "id" : 447 + }, + { + "name" : "minecraft:zombie_villager_spawn_egg", + "id" : 477 + } +] \ No newline at end of file diff --git a/core/src/main/resources/mappings b/core/src/main/resources/mappings index f73b45844..dbd6e2924 160000 --- a/core/src/main/resources/mappings +++ b/core/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit f73b45844f1185c3898db3052ce4ea0d18246168 +Subproject commit dbd6e29245843f8a2469a282c01b4de6157ba4e4 From 66a7efaa967b4d5ca48d5cc3cd01d90994a79594 Mon Sep 17 00:00:00 2001 From: davchoo Date: Wed, 25 May 2022 22:11:35 -0400 Subject: [PATCH 20/72] Yeet 1.18.30 and old palette stuff --- .../geyser/network/MinecraftProtocol.java | 5 - .../populator/BlockRegistryPopulator.java | 86 - .../populator/ItemRegistryPopulator.java | 21 +- .../MerchantInventoryTranslator.java | 11 - .../java/JavaUpdateRecipesTranslator.java | 7 - .../bedrock/block_palette.1_18_0.nbt | Bin 41760 -> 0 bytes .../bedrock/block_palette.1_18_10.nbt | Bin 41783 -> 0 bytes .../bedrock/block_palette.1_18_30.nbt | Bin 45536 -> 0 bytes .../bedrock/creative_items.1_18_0.json | 5206 ---------------- .../bedrock/creative_items.1_18_10.json | 5209 ----------------- .../bedrock/creative_items.1_18_30.json | 5209 ----------------- .../bedrock/runtime_item_states.1_18_0.json | 4322 -------------- .../bedrock/runtime_item_states.1_18_10.json | 4362 -------------- .../bedrock/runtime_item_states.1_18_30.json | 4426 -------------- 14 files changed, 2 insertions(+), 28862 deletions(-) delete mode 100644 core/src/main/resources/bedrock/block_palette.1_18_0.nbt delete mode 100644 core/src/main/resources/bedrock/block_palette.1_18_10.nbt delete mode 100644 core/src/main/resources/bedrock/block_palette.1_18_30.nbt delete mode 100644 core/src/main/resources/bedrock/creative_items.1_18_0.json delete mode 100644 core/src/main/resources/bedrock/creative_items.1_18_10.json delete mode 100644 core/src/main/resources/bedrock/creative_items.1_18_30.json delete mode 100644 core/src/main/resources/bedrock/runtime_item_states.1_18_0.json delete mode 100644 core/src/main/resources/bedrock/runtime_item_states.1_18_10.json delete mode 100644 core/src/main/resources/bedrock/runtime_item_states.1_18_30.json diff --git a/core/src/main/java/org/geysermc/geyser/network/MinecraftProtocol.java b/core/src/main/java/org/geysermc/geyser/network/MinecraftProtocol.java index a7b2ebd9e..fff0d38fe 100644 --- a/core/src/main/java/org/geysermc/geyser/network/MinecraftProtocol.java +++ b/core/src/main/java/org/geysermc/geyser/network/MinecraftProtocol.java @@ -29,7 +29,6 @@ import com.github.steveice10.mc.protocol.codec.MinecraftCodec; import com.github.steveice10.mc.protocol.codec.PacketCodec; import com.nukkitx.protocol.bedrock.BedrockPacketCodec; import com.nukkitx.protocol.bedrock.beta.BedrockBeta; -import com.nukkitx.protocol.bedrock.v503.Bedrock_v503; import java.util.ArrayList; import java.util.Collections; @@ -57,10 +56,6 @@ public final class MinecraftProtocol { private static final PacketCodec DEFAULT_JAVA_CODEC = MinecraftCodec.CODEC; static { - SUPPORTED_BEDROCK_CODECS.add(Bedrock_v503.V503_CODEC.toBuilder() - .minecraftVersion("1.18.30/1.18.31") - .build()); - SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC.toBuilder() .minecraftVersion("1.19.0") .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 e811a0a62..3dfa6c2db 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 @@ -29,7 +29,6 @@ import com.fasterxml.jackson.databind.JsonNode; import com.google.common.collect.ImmutableMap; import com.nukkitx.nbt.*; import com.nukkitx.protocol.bedrock.beta.BedrockBeta; -import com.nukkitx.protocol.bedrock.v503.Bedrock_v503; import it.unimi.dsi.fastutil.ints.IntOpenHashSet; import it.unimi.dsi.fastutil.ints.IntSet; import it.unimi.dsi.fastutil.objects.Object2IntMap; @@ -60,93 +59,8 @@ public class BlockRegistryPopulator { private static final ImmutableMap, BiFunction> BLOCK_MAPPERS; private static final BiFunction EMPTY_MAPPER = (bedrockIdentifier, statesBuilder) -> null; - private static final BiFunction V503_MAPPER = (bedrockIdentifier, statesBuilder) -> { - // TODO some new blocks exist in the block palette, but don't properly work in game (mangrove leaves + mud stuff) - if (bedrockIdentifier.contains("stone_block_slab")) { - return bedrockIdentifier.replace("stone_block_slab", "stone_slab"); - } - switch (bedrockIdentifier) { - case "minecraft:mangrove_planks" -> { - statesBuilder.putString("wood_type", "jungle"); - return "minecraft:planks"; - } - case "minecraft:mangrove_log" -> { - statesBuilder.putString("old_log_type", "jungle"); - return "minecraft:log"; - } - case "minecraft:stripped_mangrove_log" -> { - return "minecraft:stripped_jungle_log"; - } - case "minecraft:mangrove_roots", "minecraft:muddy_mangrove_roots", "minecraft:mangrove_wood" -> { - statesBuilder.putString("wood_type", "jungle"); - statesBuilder.putBoolean("stripped_bit", false); - statesBuilder.putString("pillar_axis", "x"); - return "minecraft:wood"; - } - case "minecraft:stripped_mangrove_wood" -> { - statesBuilder.putString("wood_type", "jungle"); - statesBuilder.putBoolean("stripped_bit", true); - return "minecraft:wood"; - } - case "minecraft:mangrove_standing_sign" -> { - return "minecraft:jungle_standing_sign"; - } - case "minecraft:mangrove_wall_sign" -> { - return "minecraft:jungle_wall_sign"; - } - case "minecraft:mangrove_pressure_plate" -> { - return "minecraft:jungle_pressure_plate"; - } - case "minecraft:mangrove_trapdoor" -> { - return "minecraft:jungle_trapdoor"; - } - case "minecraft:mangrove_button" -> { - return "minecraft:jungle_button"; - } - case "minecraft:mangrove_stairs" -> { - return "minecraft:jungle_stairs"; - } - case "minecraft:mangrove_slab" -> { - statesBuilder.putString("wood_type", "jungle"); - return "minecraft:wooden_slab"; - } - case "minecraft:mangrove_double_slab" -> { - statesBuilder.putString("wood_type", "jungle"); - return "minecraft:double_wooden_slab"; - } - case "minecraft:mangrove_fence_gate" -> { - return "minecraft:jungle_fence_gate"; - } - case "minecraft:mangrove_fence" -> { - statesBuilder.putString("wood_type", "jungle"); - return "minecraft:fence"; - } - case "minecraft:mangrove_door" -> { - return "minecraft:jungle_door"; - } - case "minecraft:mangrove_propagule" -> { - statesBuilder.put("growth", statesBuilder.get("propagule_stage")); - statesBuilder.remove("propagule_stage"); - - statesBuilder.putInt("facing_direction", 0); - - if ((Byte) statesBuilder.remove("hanging") == 1) { - return "minecraft:mangrove_propagule_hanging"; - } else { - return "minecraft:mangrove_propagule"; - } - } - case "minecraft:sculk_shrieker" -> { - statesBuilder.remove("can_summon"); - return bedrockIdentifier; - } - } - return null; - }; - static { ImmutableMap.Builder, BiFunction> stateMapperBuilder = ImmutableMap., BiFunction>builder() - .put(ObjectIntPair.of("1_18_30", Bedrock_v503.V503_CODEC.getProtocolVersion()), V503_MAPPER) .put(ObjectIntPair.of("1_19_0", BedrockBeta.BETA_CODEC.getProtocolVersion()), EMPTY_MAPPER); BLOCK_MAPPERS = stateMapperBuilder.build(); 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 65d416065..2868652bd 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 @@ -36,9 +36,6 @@ import com.nukkitx.protocol.bedrock.data.SoundEvent; import com.nukkitx.protocol.bedrock.data.inventory.ComponentItemData; import com.nukkitx.protocol.bedrock.data.inventory.ItemData; import com.nukkitx.protocol.bedrock.packet.StartGamePacket; -import com.nukkitx.protocol.bedrock.v475.Bedrock_v475; -import com.nukkitx.protocol.bedrock.v486.Bedrock_v486; -import com.nukkitx.protocol.bedrock.v503.Bedrock_v503; import it.unimi.dsi.fastutil.ints.Int2IntMap; import it.unimi.dsi.fastutil.ints.IntArrayList; import it.unimi.dsi.fastutil.ints.IntList; @@ -67,7 +64,6 @@ public class ItemRegistryPopulator { public static void populate() { Map paletteVersions = new Object2ObjectOpenHashMap<>(); - paletteVersions.put("1_18_30", new PaletteVersion(Bedrock_v503.V503_CODEC.getProtocolVersion(), Collections.emptyMap())); paletteVersions.put("1_19_0", new PaletteVersion(BedrockBeta.BETA_CODEC.getProtocolVersion(), Collections.emptyMap())); GeyserBootstrap bootstrap = GeyserImpl.getInstance().getBootstrap(); @@ -230,18 +226,6 @@ public class ItemRegistryPopulator { mappingItem = entry.getValue(); } - String bedrockIdentifier; - if (javaIdentifier.equals("minecraft:globe_banner_pattern") && palette.getValue().protocolVersion() < Bedrock_v486.V486_CODEC.getProtocolVersion()) { - bedrockIdentifier = "minecraft:banner_pattern"; - } else { - bedrockIdentifier = mappingItem.getBedrockIdentifier(); - if (palette.getValue().protocolVersion() >= Bedrock_v503.V503_CODEC.getProtocolVersion()) { - if (bedrockIdentifier.equals("minecraft:sealantern")) { - bedrockIdentifier = "minecraft:sea_lantern"; - } - } - } - if (usingFurnaceMinecart && javaIdentifier.equals("minecraft:furnace_minecart")) { javaFurnaceMinecartId = itemIndex; itemIndex++; @@ -250,11 +234,10 @@ public class ItemRegistryPopulator { continue; } + String bedrockIdentifier = mappingItem.getBedrockIdentifier(); int bedrockId = bedrockIdentifierToId.getInt(bedrockIdentifier); if (bedrockId == Short.MIN_VALUE) { - bedrockId = 0; - //TODO remove - //throw new RuntimeException("Missing Bedrock ID in mappings: " + bedrockIdentifier); + throw new RuntimeException("Missing Bedrock ID in mappings: " + bedrockIdentifier); } int stackSize = mappingItem.getStackSize(); 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 248bd35b7..061f6c5ea 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 @@ -37,7 +37,6 @@ import com.nukkitx.protocol.bedrock.data.inventory.stackrequestactions.AutoCraft import com.nukkitx.protocol.bedrock.data.inventory.stackrequestactions.CraftRecipeStackRequestActionData; import com.nukkitx.protocol.bedrock.packet.ItemStackResponsePacket; import com.nukkitx.protocol.bedrock.packet.SetEntityLinkPacket; -import com.nukkitx.protocol.bedrock.v486.Bedrock_v486; import org.geysermc.geyser.entity.type.Entity; import org.geysermc.geyser.entity.EntityDefinitions; import org.geysermc.geyser.inventory.Inventory; @@ -140,10 +139,6 @@ public class MerchantInventoryTranslator extends BaseInventoryTranslator { @Override public ItemStackResponsePacket.Response translateCraftingRequest(GeyserSession session, Inventory inventory, ItemStackRequest request) { - if (session.getUpstream().getProtocolVersion() < Bedrock_v486.V486_CODEC.getProtocolVersion()) { - return super.translateCraftingRequest(session, inventory, request); - } - // Behavior as of 1.18.10. // We set the net ID to the trade index + 1. This doesn't appear to cause issues and means we don't have to // store a map of net ID to trade index on our end. @@ -153,12 +148,6 @@ public class MerchantInventoryTranslator extends BaseInventoryTranslator { @Override public ItemStackResponsePacket.Response translateAutoCraftingRequest(GeyserSession session, Inventory inventory, ItemStackRequest request) { - if (session.getUpstream().getProtocolVersion() < Bedrock_v486.V486_CODEC.getProtocolVersion()) { - // We're not crafting here - // Called at least by consoles when pressing a trade option button - return translateRequest(session, inventory, request); - } - // 1.18.10 update - seems impossible to call without consoles/controller input // We set the net ID to the trade index + 1. This doesn't appear to cause issues and means we don't have to // store a map of net ID to trade index on our end. 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 1c5a15b0b..f1de83914 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 @@ -38,7 +38,6 @@ import com.nukkitx.nbt.NbtMap; import com.nukkitx.protocol.bedrock.data.inventory.CraftingData; import com.nukkitx.protocol.bedrock.data.inventory.ItemData; import com.nukkitx.protocol.bedrock.packet.CraftingDataPacket; -import com.nukkitx.protocol.bedrock.v486.Bedrock_v486; import it.unimi.dsi.fastutil.ints.*; import lombok.AllArgsConstructor; import lombok.EqualsAndHashCode; @@ -82,8 +81,6 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator= Bedrock_v486.V486_CODEC.getProtocolVersion(); - Int2ObjectMap recipeMap = new Int2ObjectOpenHashMap<>(Registries.RECIPES.forVersion(session.getUpstream().getProtocolVersion())); Int2ObjectMap> unsortedStonecutterData = new Int2ObjectOpenHashMap<>(); CraftingDataPacket craftingDataPacket = new CraftingDataPacket(); @@ -138,10 +135,6 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator { // Required to translate these as of 1.18.10, or else they cannot be crafted - if (!applySmithingRecipes) { - continue; - } - SmithingRecipeData recipeData = (SmithingRecipeData) recipe.getData(); ItemData output = ItemTranslator.translateToBedrock(session, recipeData.getResult()); for (ItemStack base : recipeData.getBase().getOptions()) { diff --git a/core/src/main/resources/bedrock/block_palette.1_18_0.nbt b/core/src/main/resources/bedrock/block_palette.1_18_0.nbt deleted file mode 100644 index 0415c135a3e1221c962da5a1ea3b831b4cab3d76..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 41760 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­vL!Lf=f zJuU0N{$gF zk&t6Zq**e-XJEMQAXp{fumDC*#?$r+6(<4MH<|(j9}hT1aMeGDC*|L8pOij+L?;q2Sd6AHJ}6H1kt4BKR?q+GgTM_+j*Q9wQj6R zGeK-q3FP2f7H#+~C;QOg$ctFOu>gBtan^wT!M0|Sm0*GZAV-`-2k!RbA^!0)nv^Go z0ya)8hn>(8+GYW#3jj!NsiGa(i1>FrZk4V$IOIq0p6I1I%*v;oUPZX-RwVA!0sZ(;| zv_Ioxtq~C4uWlUE%pCOg_%@!)zQxv6<)I?9kuOK8f zu}DvbhomNIq@KoeNy`tOS24+ zES=3)zrRAGkyK2X5nyRP0uJZ-=iPq<4mGH@G0y_R#_RyxrFgLew5rxY6+|wD6OBC4 zgn*<7Ir1>Ph3-fJl6l`dZU2Itc03;&rhiQ2E)XCC)<~oP*gJHp5Y^@n4jYYg^^Jwcyu!8YObJ~d^T}>-@z}L& zu8LcK1%hS0MLFyrJmrdE(_8vjB2H~@v2@PBb^0(2T}206h62Aa>&@)E%9z`pYbWo zQ76r1+LBb^KTo}i@`G8H^MJHNYR}hd= z-Hz!n^!O$_GHZteQIJ_XQedHWEMB(Qn=ZDZUox*A@*{C8XpNxD1c{>9ZCRM6S?!P? z@!x{7k8SOY%$9H0K_+U(J)@2Jj~>{0d)2i@sDCpu+lpL75rZ`@Wady73uIlS%-u6S zgHWBOynYBtOr>!(3?Z%kKuh1;P8me7y@h2+9&+XckUH;fq{=FT{O;1G1@Zw3^4on{ zXuBI5$Y?yEO+%|@qk(4Q&@QR%8%X}qpp`~_=m?b@dBrIG3FibVx#G$pjoj5Rra&vU zb&sV4JP0t)WY&PenRYSEjE73j=venSYr`?X>ZWN8#{)Y#>!fv^x$vSkb|V0y-u%PT~9Ac0k9x|A6Fg`~fFZ1y*#wH=A2VX%DlD|Qk`w0+;mGTyJ zA_e?Ic6e5tew8|s`!D+2K4G)#N_Mi1OSQsFbtMN#=cQ2LoO+TIuIo~$xaE41GrW6J zs5qSZk|P?YQm79r0jv1zy4$-Oh5@Er)5;wWkQ1!6Rv;M#5^eU&Fbu%Q#aeseff;9Q z>1CxsCfXXVq*@;)@~U{0_Ih8y0{`QtUJYK_v{JYi@`h=Wfsr z=*XVr_I(y62(%bS4n92` z2r^MT&|qJzL=EVO5@R%JMIebBe5M~xhX%Zzrm_V;9fWL(=t{i@9p!G8k$260n-`c)O zz_hXa1nOLmV+;HN2-YU8VEW$wN@aDm+}x=*ygD^0=nXBYG;TV%1+~s#$!^U zAl(Xrb8MbpL7>NwVP9*JolfEUYo(ByYI0jk!U0KAC7z+E9zra{wKMKjVlKI|Z>UA*Pqvu304A->BYqdT{Y z`}o%FAp%Rsj8DA_RcYnbN`5AGI+5`pKSfIwvogy~D@|Zi9kigB1baYcR1*|oPyh=e zGp!9ufi%D{NX_eliVpg~X&Q_ApenmLaEQjNAt<}}Hw=T)8XSBX!v;>rJdEdEc`6N1%%f$H zREqd_FeU|{7(H;-0H?ee6avoRbPNUZBn=#7p?uK*im_b=hzCHpn5zI1T#$1xE}w0a z0H-H*xNBVz;Gj_V4;E^G;EZbq+x$Vdu`8=xQ#2`K≥SYbNZ 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 diff --git a/core/src/main/resources/bedrock/block_palette.1_18_10.nbt b/core/src/main/resources/bedrock/block_palette.1_18_10.nbt deleted file mode 100644 index 637bfc95256eed129b1dbb69944601e441b18406..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 41783 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 DvTLIl diff --git a/core/src/main/resources/bedrock/block_palette.1_18_30.nbt b/core/src/main/resources/bedrock/block_palette.1_18_30.nbt deleted file mode 100644 index bf7690970f792f71b62d7b7f0c9a2f80a3292a21..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 45536 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 Date: Thu, 26 May 2022 13:11:39 -0400 Subject: [PATCH 21/72] Implement chest boat --- .../geyser/entity/EntityDefinitions.java | 4 ++++ .../BedrockEntityPickRequestTranslator.java | 5 +++-- .../player/BedrockInteractTranslator.java | 12 +++++------- ...ava => JavaBlockChangedAckTranslator.java} | 2 +- .../level/JavaBlockDestructionTranslator.java | 11 +++-------- .../java/level/JavaLevelEventTranslator.java | 3 ++- .../org/geysermc/geyser/util/EntityUtils.java | 10 ++++++---- .../resources/bedrock/entity_identifiers.dat | Bin 7382 -> 7694 bytes 8 files changed, 24 insertions(+), 23 deletions(-) rename core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/{JavaBlockBreakAckTranslator.java => JavaBlockChangedAckTranslator.java} (94%) 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 4f3910636..a39fb2f13 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 CAVE_SPIDER; 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; @@ -209,6 +210,9 @@ public final class EntityDefinitions { .addTranslator(MetadataType.BOOLEAN, BoatEntity::setPaddlingRight) .addTranslator(MetadataType.INT, (boatEntity, entityMetadata) -> boatEntity.getDirtyMetadata().put(EntityData.BOAT_BUBBLE_TIME, entityMetadata.getValue())) // May not actually do anything .build(); + CHEST_BOAT = EntityDefinition.inherited(BOAT.factory(), BOAT) + .type(EntityType.CHEST_BOAT) + .build(); DRAGON_FIREBALL = EntityDefinition.inherited(FireballEntity::new, entityBase) .type(EntityType.DRAGON_FIREBALL) .heightAndWidth(1.0f) 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 48a089b6e..dc7fe854a 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 @@ -52,7 +52,7 @@ public class BedrockEntityPickRequestTranslator extends PacketTranslator { + case BOAT, CHEST_BOAT -> { // Include type of boat in the name int variant = ((BoatEntity) entity).getVariant(); String typeOfBoat = switch (variant) { @@ -61,9 +61,10 @@ public class BedrockEntityPickRequestTranslator extends PacketTranslator "jungle"; case 4 -> "acacia"; case 5 -> "dark_oak"; + case 6 -> "mangrove"; default -> "oak"; }; - itemName = typeOfBoat + "_boat"; + itemName = typeOfBoat + "_" + entity.getDefinition().entityType().name().toLowerCase(Locale.ROOT); } case LEASH_KNOT -> itemName = "lead"; case CHEST_MINECART, COMMAND_BLOCK_MINECART, FURNACE_MINECART, HOPPER_MINECART, TNT_MINECART -> 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 471668492..fed8f5ce6 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 @@ -28,10 +28,10 @@ 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 com.nukkitx.protocol.bedrock.data.entity.EntityData; -import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket; import com.nukkitx.protocol.bedrock.packet.InteractPacket; @@ -96,12 +96,10 @@ public class BedrockInteractTranslator extends PacketTranslator case OPEN_INVENTORY: if (session.getOpenInventory() == null) { Entity ridingEntity = session.getPlayerEntity().getVehicle(); - if (ridingEntity instanceof AbstractHorseEntity) { - if (ridingEntity.getFlag(EntityFlag.TAMED)) { - // We should request to open the horse inventory instead - ServerboundPlayerCommandPacket openHorseWindowPacket = new ServerboundPlayerCommandPacket(session.getPlayerEntity().getEntityId(), PlayerState.OPEN_HORSE_INVENTORY); - session.sendDownstreamPacket(openHorseWindowPacket); - } + if (ridingEntity instanceof AbstractHorseEntity || (ridingEntity != null && ridingEntity.getDefinition().entityType() == EntityType.CHEST_BOAT)) { + // 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.sendDownstreamPacket(openVehicleWindowPacket); } else { session.setOpenInventory(session.getPlayerInventory()); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaBlockBreakAckTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaBlockChangedAckTranslator.java similarity index 94% rename from core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaBlockBreakAckTranslator.java rename to core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaBlockChangedAckTranslator.java index 714603997..6afb0b3ef 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaBlockBreakAckTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaBlockChangedAckTranslator.java @@ -31,7 +31,7 @@ import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; @Translator(packet = ClientboundBlockChangedAckPacket.class) -public class JavaBlockBreakAckTranslator extends PacketTranslator { +public class JavaBlockChangedAckTranslator extends PacketTranslator { @Override public void translate(GeyserSession session, ClientboundBlockChangedAckPacket packet) { 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 7c4bd561f..84d7f766d 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 @@ -27,14 +27,13 @@ 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 com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.LevelEventType; import com.nukkitx.protocol.bedrock.packet.LevelEventPacket; +import org.geysermc.geyser.registry.BlockRegistries; +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.registry.BlockRegistries; -import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.util.BlockUtils; @Translator(packet = ClientboundBlockDestructionPacket.class) @@ -45,11 +44,7 @@ public class JavaBlockDestructionTranslator 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 -> mountedHeightOffset = -0.1f; + case BOAT, CHEST_BOAT -> mountedHeightOffset = -0.1f; case HOGLIN, ZOGLIN -> { boolean isBaby = mount.getFlag(EntityFlag.BABY); mountedHeightOffset = height - (isBaby ? 0.2f : 0.15f); @@ -160,13 +161,14 @@ public final class EntityUtils { xOffset = -0.6f; } } + case CHEST_BOAT -> xOffset = 0.15F; case CHICKEN -> zOffset = -0.1f; case TRADER_LLAMA, LLAMA -> zOffset = -0.3f; } if (passenger.getDefinition().entityType() == EntityType.SHULKER) { switch (mount.getDefinition().entityType()) { case MINECART, HOPPER_MINECART, TNT_MINECART, CHEST_MINECART, FURNACE_MINECART, SPAWNER_MINECART, - COMMAND_BLOCK_MINECART, BOAT -> yOffset = 0.1875f; + COMMAND_BLOCK_MINECART, BOAT, CHEST_BOAT -> yOffset = 0.1875f; } } /* @@ -182,7 +184,7 @@ public final class EntityUtils { } switch (mount.getDefinition().entityType()) { case MINECART, HOPPER_MINECART, TNT_MINECART, CHEST_MINECART, FURNACE_MINECART, SPAWNER_MINECART, - COMMAND_BLOCK_MINECART, BOAT -> yOffset -= mount.getDefinition().height() * 0.5f; + COMMAND_BLOCK_MINECART, BOAT, CHEST_BOAT -> yOffset -= mount.getDefinition().height() * 0.5f; } Vector3f offset = Vector3f.from(xOffset, yOffset, zOffset); passenger.setRiderSeatPosition(offset); @@ -190,7 +192,7 @@ public final class EntityUtils { } public static void updateRiderRotationLock(Entity passenger, Entity mount, boolean isRiding) { - if (isRiding && mount.getDefinition() == EntityDefinitions.BOAT) { + if (isRiding && mount instanceof BoatEntity) { // Head rotation is locked while riding in a boat passenger.getDirtyMetadata().put(EntityData.RIDER_ROTATION_LOCKED, (byte) 1); passenger.getDirtyMetadata().put(EntityData.RIDER_MAX_ROTATION, 90f); diff --git a/core/src/main/resources/bedrock/entity_identifiers.dat b/core/src/main/resources/bedrock/entity_identifiers.dat index b9da310f5006930506c26435b7f1bf8960006021..2e3733aa6c0adaf4ce3cfa79567502b8333ae1cc 100644 GIT binary patch delta 227 zcmca+*=NJc#lXpynUa%PT*CE^ak3+$#70$L_RSyITRA892}^D67gT1SJb_VQaxHt_ zkoQTwB zK|y8q$p#{g$WrL@81*HX?Pg_BoFIfBLP efMS0+xhHRtHU`sXGRBjwfc#A|36oFBx&Q#Mnk=LM From 2c7730693761536eebada9525b236b3732438bb5 Mon Sep 17 00:00:00 2001 From: davchoo Date: Thu, 26 May 2022 02:11:25 -0400 Subject: [PATCH 22/72] Use new toasts for advancements and simplify advancement form response --- .../geyser/level/GeyserAdvancement.java | 9 ++++ .../session/cache/AdvancementsCache.java | 50 ++++++------------- .../JavaUpdateAdvancementsTranslator.java | 39 ++++++--------- 3 files changed, 38 insertions(+), 60 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 f75405160..fc3c86dd4 100644 --- a/core/src/main/java/org/geysermc/geyser/level/GeyserAdvancement.java +++ b/core/src/main/java/org/geysermc/geyser/level/GeyserAdvancement.java @@ -28,6 +28,7 @@ package org.geysermc.geyser.level; import com.github.steveice10.mc.protocol.data.game.advancement.Advancement; import lombok.NonNull; import org.geysermc.geyser.session.cache.AdvancementsCache; +import org.geysermc.geyser.text.ChatColor; import java.util.List; @@ -69,6 +70,14 @@ public class GeyserAdvancement { return this.advancement.getDisplayData(); } + /** + * @return Purple for challenges and green for normal advancements + */ + public String getDisplayColor() { + Advancement.DisplayData displayData = getDisplayData(); + return displayData != null && displayData.getFrameType() == Advancement.DisplayData.FrameType.CHALLENGE ? ChatColor.LIGHT_PURPLE : ChatColor.GREEN; + } + public String getRootId(AdvancementsCache advancementsCache) { if (rootId == null) { if (this.advancement.getParentId() == null) { 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 0df842d1d..206d97b0b 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 @@ -38,6 +38,7 @@ import org.geysermc.geyser.text.MinecraftLocale; import org.geysermc.cumulus.SimpleForm; import org.geysermc.cumulus.response.SimpleFormResponse; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -76,15 +77,15 @@ public class AdvancementsCache { .translator(MinecraftLocale::getLocaleString, session.getLocale()) .title("gui.advancements"); - boolean hasAdvancements = false; + List rootAdvancementIds = new ArrayList<>(); for (Map.Entry advancement : storedAdvancements.entrySet()) { if (advancement.getValue().getParentId() == null) { // No parent means this is a root advancement - hasAdvancements = true; builder.button(MessageTranslator.convertMessage(advancement.getValue().getDisplayData().getTitle(), session.getLocale())); + rootAdvancementIds.add(advancement.getKey()); } } - if (!hasAdvancements) { + if (rootAdvancementIds.isEmpty()) { builder.content("advancements.empty"); } @@ -94,20 +95,7 @@ public class AdvancementsCache { return; } - String id = ""; - - int advancementIndex = 0; - for (Map.Entry advancement : storedAdvancements.entrySet()) { - if (advancement.getValue().getParentId() == null) { // Root advancement - if (advancementIndex == response.getClickedButtonId()) { - id = advancement.getKey(); - break; - } else { - advancementIndex++; - } - } - } - + String id = rootAdvancementIds.get(response.getClickedButtonId()); if (!id.equals("")) { if (id.equals(currentAdvancementCategoryId)) { // The server thinks we are already on this tab @@ -136,12 +124,16 @@ public class AdvancementsCache { .title(MessageTranslator.convertMessage(categoryAdvancement.getDisplayData().getTitle(), language)) .content(MessageTranslator.convertMessage(categoryAdvancement.getDisplayData().getDescription(), language)); + List visibleAdvancements = new ArrayList<>(); if (currentAdvancementCategoryId != null) { for (GeyserAdvancement advancement : storedAdvancements.values()) { - if (advancement != null) { + boolean earned = isEarned(advancement); + if (earned || !advancement.getDisplayData().isHidden()) { if (advancement.getParentId() != null && currentAdvancementCategoryId.equals(advancement.getRootId(this))) { - boolean color = isEarned(advancement) || !advancement.getDisplayData().isShowToast(); - builder.button((color ? ChatColor.DARK_GREEN : "") + MessageTranslator.convertMessage(advancement.getDisplayData().getTitle()) + '\n'); + String color = earned ? advancement.getDisplayColor() : ""; + builder.button(color + MessageTranslator.convertMessage(advancement.getDisplayData().getTitle()) + '\n'); + + visibleAdvancements.add(advancement); } } } @@ -157,22 +149,8 @@ public class AdvancementsCache { return; } - GeyserAdvancement advancement = null; - int advancementIndex = 0; - // Loop around to find the advancement that the client pressed - for (GeyserAdvancement advancementEntry : storedAdvancements.values()) { - if (advancementEntry.getParentId() != null && - currentAdvancementCategoryId.equals(advancementEntry.getRootId(this))) { - if (advancementIndex == response.getClickedButtonId()) { - advancement = advancementEntry; - break; - } else { - advancementIndex++; - } - } - } - - if (advancement != null) { + if (response.getClickedButtonId() < visibleAdvancements.size()) { + GeyserAdvancement advancement = visibleAdvancements.get(response.getClickedButtonId()); buildAndShowInfoForm(advancement); } else { buildAndShowMenuForm(); 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 f65c17374..a1d8da90c 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 @@ -27,7 +27,7 @@ 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 com.nukkitx.protocol.bedrock.packet.SetTitlePacket; +import com.nukkitx.protocol.bedrock.packet.ToastRequestPacket; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; @@ -36,7 +36,7 @@ import org.geysermc.geyser.session.cache.AdvancementsCache; import org.geysermc.geyser.level.GeyserAdvancement; import org.geysermc.geyser.text.MinecraftLocale; -import java.util.Map; +import java.util.Locale; @Translator(packet = ClientboundUpdateAdvancementsPacket.class) public class JavaUpdateAdvancementsTranslator extends PacketTranslator { @@ -56,48 +56,39 @@ public class JavaUpdateAdvancementsTranslator extends PacketTranslator> progress : packet.getProgress().entrySet()) { - GeyserAdvancement advancement = session.getAdvancementsCache().getStoredAdvancements().get(progress.getKey()); + for (String advancementId : packet.getProgress().keySet()) { + GeyserAdvancement advancement = session.getAdvancementsCache().getStoredAdvancements().get(advancementId); if (advancement != null && advancement.getDisplayData() != null) { - if (session.getAdvancementsCache().isEarned(advancement)) { - // Java uses some pink color for toast challenge completes - String color = advancement.getDisplayData().getFrameType() == Advancement.DisplayData.FrameType.CHALLENGE ? - "§d" : "§a"; + if (advancement.getDisplayData().isShowToast() && session.getAdvancementsCache().isEarned(advancement)) { + String frameType = advancement.getDisplayData().getFrameType().toString().toLowerCase(Locale.ROOT); + String frameTitle = advancement.getDisplayColor() + MinecraftLocale.getLocaleString("advancements.toast." + frameType, session.getLocale()); String advancementName = MessageTranslator.convertMessage(advancement.getDisplayData().getTitle(), session.getLocale()); - // Send an action bar message stating they earned an achievement - // Sent for instances where broadcasting advancements through chat are disabled - SetTitlePacket titlePacket = new SetTitlePacket(); - titlePacket.setText(color + "[" + MinecraftLocale.getLocaleString("advancements.toast." + - advancement.getDisplayData().getFrameType().toString().toLowerCase(), session.getLocale()) + "]§f " + advancementName); - titlePacket.setType(SetTitlePacket.Type.ACTIONBAR); - titlePacket.setFadeOutTime(3); - titlePacket.setFadeInTime(3); - titlePacket.setStayTime(3); - titlePacket.setXuid(""); - titlePacket.setPlatformOnlineId(""); - session.sendUpstreamPacket(titlePacket); + ToastRequestPacket toastRequestPacket = new ToastRequestPacket(); + toastRequestPacket.setTitle(frameTitle); + toastRequestPacket.setContent(advancementName); + session.sendUpstreamPacket(toastRequestPacket); } } } From 59cb0c07c2fa4573357290ab70b52fd109b61889 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Thu, 26 May 2022 16:22:53 -0400 Subject: [PATCH 23/72] Start implementing frogs. Ribbit. --- .../geyser/entity/EntityDefinitions.java | 7 ++ .../geyser/entity/GeyserDirtyMetadata.java | 5 ++ .../entity/type/living/animal/FrogEntity.java | 68 +++++++++++++++++++ 3 files changed, 80 insertions(+) create mode 100644 core/src/main/java/org/geysermc/geyser/entity/type/living/animal/FrogEntity.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 a39fb2f13..59fde11e1 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java +++ b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java @@ -89,6 +89,7 @@ public final class EntityDefinitions { public static final EntityDefinition FIREWORK_ROCKET; public static final EntityDefinition FISHING_BOBBER; public static final EntityDefinition FOX; + public static final EntityDefinition FROG; public static final EntityDefinition FURNACE_MINECART; // Not present on Bedrock public static final EntityDefinition GHAST; public static final EntityDefinition GIANT; @@ -740,6 +741,12 @@ public final class EntityDefinitions { .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) + .build(); HOGLIN = EntityDefinition.inherited(HoglinEntity::new, ageableEntityBase) .type(EntityType.HOGLIN) .height(1.4f).width(1.3965f) 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 f0095d26a..c896c239e 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/GeyserDirtyMetadata.java +++ b/core/src/main/java/org/geysermc/geyser/entity/GeyserDirtyMetadata.java @@ -52,4 +52,9 @@ public final class GeyserDirtyMetadata { public boolean hasEntries() { return !metadata.isEmpty(); } + + @Override + public String toString() { + return metadata.toString(); + } } 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 new file mode 100644 index 000000000..95dd54b7a --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/FrogEntity.java @@ -0,0 +1,68 @@ +/* + * 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.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 com.nukkitx.math.vector.Vector3f; +import com.nukkitx.protocol.bedrock.data.entity.EntityData; +import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; +import org.geysermc.geyser.entity.EntityDefinition; +import org.geysermc.geyser.entity.type.Entity; +import org.geysermc.geyser.session.GeyserSession; + +import java.util.OptionalInt; +import java.util.UUID; + +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) { + super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw); + } + + @Override + public void setPose(Pose pose) { + setFlag(EntityFlag.JUMP_GOAL_JUMP, pose == Pose.LONG_JUMPING); + //TODO croaking and tongue using + super.setPose(pose); + } + + public void setFrogVariant(IntEntityMetadata entityMetadata) { + dirtyMetadata.put(EntityData.VARIANT, entityMetadata.getPrimitiveValue()); + } + + public void setTongueTarget(ObjectEntityMetadata entityMetadata) { + OptionalInt entityId = entityMetadata.getValue(); + if (entityId.isPresent()) { + Entity entity = session.getEntityCache().getEntityByJavaId(entityId.getAsInt()); + if (entity != null) { + dirtyMetadata.put(EntityData.TARGET_EID, entity.getGeyserId()); + } + } else { + dirtyMetadata.put(EntityData.TARGET_EID, 0L); + } + } +} From 4b9055c25260bde8bb80d3202e556f9c27ac7cb2 Mon Sep 17 00:00:00 2001 From: davchoo Date: Thu, 26 May 2022 16:27:54 -0400 Subject: [PATCH 24/72] Add new PaintingTypes --- .../main/java/org/geysermc/geyser/level/PaintingType.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) 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 43c51efd4..5c0cbf643 100644 --- a/core/src/main/java/org/geysermc/geyser/level/PaintingType.java +++ b/core/src/main/java/org/geysermc/geyser/level/PaintingType.java @@ -56,8 +56,12 @@ public enum PaintingType { SKELETON("Skeleton", 4, 3), DONKEY_KONG("DonkeyKong", 4, 3), POINTER("Pointer", 4, 4), - PIG_SCENE("Pigscene", 4, 4), - BURNING_SKULL("BurningSkull", 4, 4); + PIGSCENE("Pigscene", 4, 4), + BURNING_SKULL("BurningSkull", 4, 4), + EARTH("Earth", 2, 2), + WIND("Wind", 2, 2), + WATER("Water", 2, 2), + FIRE("Fire", 2, 2); private static final PaintingType[] VALUES = values(); private final String bedrockName; From 29c819fe21b1d2975c58c4f738aecb8f43a06c95 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Thu, 26 May 2022 17:51:55 -0400 Subject: [PATCH 25/72] Implement allay, plus some interaction fixes --- .../geyser/entity/ChestBoatEntity.java | 51 ++++++++++++++ .../geyser/entity/EntityDefinitions.java | 9 ++- .../type/living/AbstractFishEntity.java | 5 +- .../entity/type/living/AllayEntity.java | 70 +++++++++++++++++++ .../entity/type/living/DolphinEntity.java | 9 +-- .../entity/type/living/IronGolemEntity.java | 5 +- .../geyser/entity/type/living/MobEntity.java | 8 +-- .../entity/type/living/SnowGolemEntity.java | 5 +- .../type/living/animal/AnimalEntity.java | 9 +-- .../type/living/animal/AxolotlEntity.java | 5 +- .../entity/type/living/animal/CowEntity.java | 9 +-- .../entity/type/living/animal/FrogEntity.java | 6 ++ .../entity/type/living/animal/GoatEntity.java | 5 +- .../type/living/animal/MooshroomEntity.java | 9 +-- .../type/living/animal/OcelotEntity.java | 9 +-- .../type/living/animal/PandaEntity.java | 7 +- .../entity/type/living/animal/PigEntity.java | 9 +-- .../type/living/animal/SheepEntity.java | 9 +-- .../type/living/animal/StriderEntity.java | 9 +-- .../animal/horse/AbstractHorseEntity.java | 33 ++++----- .../animal/horse/SkeletonHorseEntity.java | 9 +-- .../animal/horse/ZombieHorseEntity.java | 9 +-- .../living/animal/tameable/CatEntity.java | 5 +- .../living/animal/tameable/ParrotEntity.java | 9 +-- .../living/animal/tameable/WolfEntity.java | 7 +- .../merchant/AbstractMerchantEntity.java | 9 +-- .../type/living/monster/CreeperEntity.java | 9 +-- .../type/living/monster/PiglinEntity.java | 9 +-- .../living/monster/ZombieVillagerEntity.java | 9 +-- .../geysermc/geyser/util/InteractiveTag.java | 3 +- 30 files changed, 258 insertions(+), 101 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/entity/ChestBoatEntity.java create mode 100644 core/src/main/java/org/geysermc/geyser/entity/type/living/AllayEntity.java diff --git a/core/src/main/java/org/geysermc/geyser/entity/ChestBoatEntity.java b/core/src/main/java/org/geysermc/geyser/entity/ChestBoatEntity.java new file mode 100644 index 000000000..76e98d953 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/entity/ChestBoatEntity.java @@ -0,0 +1,51 @@ +/* + * 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.entity; + +import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; +import com.nukkitx.math.vector.Vector3f; +import org.geysermc.geyser.entity.type.BoatEntity; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.util.InteractionResult; +import org.geysermc.geyser.util.InteractiveTag; + +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); + } + + @Override + protected InteractiveTag testInteraction(Hand hand) { + return passengers.isEmpty() && !session.isSneaking() ? super.testInteraction(hand) : InteractiveTag.OPEN_CONTAINER; + } + + @Override + public InteractionResult interact(Hand hand) { + return passengers.isEmpty() && !session.isSneaking() ? super.interact(hand) : InteractionResult.SUCCESS; + } +} 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 59fde11e1..5d1a00968 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java +++ b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java @@ -51,6 +51,7 @@ import org.geysermc.geyser.registry.Registries; 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 ARMOR_STAND; public static final EntityDefinition ARROW; @@ -63,7 +64,7 @@ public final class EntityDefinitions { public static final EntityDefinition CAVE_SPIDER; public static final EntityDefinition CHEST_MINECART; public static final EntityDefinition CHICKEN; - public static final EntityDefinition CHEST_BOAT; + public static final EntityDefinition CHEST_BOAT; public static final EntityDefinition COD; public static final EntityDefinition COMMAND_BLOCK_MINECART; public static final EntityDefinition COW; @@ -211,7 +212,7 @@ public final class EntityDefinitions { .addTranslator(MetadataType.BOOLEAN, BoatEntity::setPaddlingRight) .addTranslator(MetadataType.INT, (boatEntity, entityMetadata) -> boatEntity.getDirtyMetadata().put(EntityData.BOAT_BUBBLE_TIME, entityMetadata.getValue())) // May not actually do anything .build(); - CHEST_BOAT = EntityDefinition.inherited(BOAT.factory(), BOAT) + CHEST_BOAT = EntityDefinition.inherited(ChestBoatEntity::new, BOAT) .type(EntityType.CHEST_BOAT) .build(); DRAGON_FIREBALL = EntityDefinition.inherited(FireballEntity::new, entityBase) @@ -447,6 +448,10 @@ public final class EntityDefinitions { // Extends mob { + ALLAY = EntityDefinition.inherited(AllayEntity::new, mobEntityBase) + .type(EntityType.ALLAY) + .height(0.6f).width(0.35f) + .build(); BAT = EntityDefinition.inherited(BatEntity::new, mobEntityBase) .type(EntityType.BAT) .height(0.9f).width(0.5f) 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 e6cd13f61..842c94e95 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,6 +25,7 @@ package org.geysermc.geyser.entity.type.living; +import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.geyser.entity.EntityDefinition; @@ -49,11 +50,11 @@ public class AbstractFishEntity extends WaterEntity { @Nonnull @Override - protected InteractionResult mobInteract(@Nonnull GeyserItemStack itemInHand) { + protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) { if (EntityUtils.attemptToBucket(session, itemInHand)) { return InteractionResult.SUCCESS; } else { - return super.mobInteract(itemInHand); + return super.mobInteract(hand, itemInHand); } } } 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 new file mode 100644 index 000000000..ab444c4ab --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/AllayEntity.java @@ -0,0 +1,70 @@ +/* + * 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.entity.type.living; + +import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; +import com.nukkitx.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.util.InteractionResult; +import org.geysermc.geyser.util.InteractiveTag; + +import javax.annotation.Nonnull; +import java.util.UUID; + +public class AllayEntity extends MobEntity { + public AllayEntity(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); + } + + @Nonnull + @Override + protected InteractiveTag testMobInteraction(@Nonnull Hand hand, @Nonnull GeyserItemStack itemInHand) { + if (!this.hand.isValid() && !itemInHand.isEmpty()) { + return InteractiveTag.GIVE_ITEM_TO_ALLAY; + } else if (this.hand.isValid() && hand == Hand.MAIN_HAND && itemInHand.isEmpty()) { + // Seems like there isn't a good tag for this yet + return InteractiveTag.GIVE_ITEM_TO_ALLAY; + } else { + return super.testMobInteraction(hand, itemInHand); + } + } + + @Nonnull + @Override + protected InteractionResult mobInteract(@Nonnull Hand hand, @Nonnull GeyserItemStack itemInHand) { + if (!this.hand.isValid() && !itemInHand.isEmpty()) { + //TODO play sound? + return InteractionResult.SUCCESS; + } else if (this.hand.isValid() && hand == Hand.MAIN_HAND && itemInHand.isEmpty()) { + //TOCHECK also play sound here? + return InteractionResult.SUCCESS; + } else { + return super.mobInteract(hand, itemInHand); + } + } +} 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 7085547f8..5d49f3e85 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,6 +25,7 @@ package org.geysermc.geyser.entity.type.living; +import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import com.nukkitx.math.vector.Vector3f; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.inventory.GeyserItemStack; @@ -47,20 +48,20 @@ public class DolphinEntity extends WaterEntity { @Nonnull @Override - protected InteractiveTag testMobInteraction(@Nonnull GeyserItemStack itemInHand) { + protected InteractiveTag testMobInteraction(Hand hand, @Nonnull GeyserItemStack itemInHand) { if (!itemInHand.isEmpty() && session.getTagCache().isFish(itemInHand)) { return InteractiveTag.FEED; } - return super.testMobInteraction(itemInHand); + return super.testMobInteraction(hand, itemInHand); } @Nonnull @Override - protected InteractionResult mobInteract(@Nonnull GeyserItemStack itemInHand) { + protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) { if (!itemInHand.isEmpty() && session.getTagCache().isFish(itemInHand)) { // Feed return InteractionResult.SUCCESS; } - return super.mobInteract(itemInHand); + return super.mobInteract(hand, itemInHand); } } 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 4ab36b00e..e5cbb2f89 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,6 +25,7 @@ package org.geysermc.geyser.entity.type.living; +import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.entity.EntityData; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; @@ -48,7 +49,7 @@ public class IronGolemEntity extends GolemEntity { @Nonnull @Override - protected InteractionResult mobInteract(@Nonnull GeyserItemStack itemInHand) { + protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) { if (itemInHand.getJavaId() == session.getItemMappings().getStoredItems().ironIngot()) { if (health < maxHealth) { // Healing the iron golem @@ -57,6 +58,6 @@ public class IronGolemEntity extends GolemEntity { return InteractionResult.PASS; } } - return super.mobInteract(itemInHand); + return super.mobInteract(hand, itemInHand); } } 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 8734f8bd1..723a9c431 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 @@ -90,7 +90,7 @@ public class MobEntity extends LivingEntity { } } - InteractiveTag tag = testMobInteraction(itemStack); + InteractiveTag tag = testMobInteraction(hand, itemStack); return tag != InteractiveTag.NONE ? tag : super.testInteraction(hand); } } @@ -109,7 +109,7 @@ public class MobEntity extends LivingEntity { if (result.consumesAction()) { return result; } else { - InteractionResult mobResult = mobInteract(itemInHand); + InteractionResult mobResult = mobInteract(hand, itemInHand); return mobResult.consumesAction() ? mobResult : super.interact(hand); } } @@ -137,12 +137,12 @@ public class MobEntity extends LivingEntity { } @Nonnull - protected InteractiveTag testMobInteraction(@Nonnull GeyserItemStack itemInHand) { + protected InteractiveTag testMobInteraction(@Nonnull Hand hand, @Nonnull GeyserItemStack itemInHand) { return InteractiveTag.NONE; } @Nonnull - protected InteractionResult mobInteract(@Nonnull GeyserItemStack itemInHand) { + protected InteractionResult mobInteract(@Nonnull Hand hand, @Nonnull GeyserItemStack itemInHand) { return InteractionResult.PASS; } 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 794f71c04..b075de882 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 @@ -26,6 +26,7 @@ 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 com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.geyser.entity.EntityDefinition; @@ -51,7 +52,7 @@ public class SnowGolemEntity extends GolemEntity { @Nonnull @Override - protected InteractiveTag testMobInteraction(@Nonnull GeyserItemStack itemInHand) { + protected InteractiveTag testMobInteraction(Hand hand, @Nonnull GeyserItemStack itemInHand) { if (session.getItemMappings().getStoredItems().shears() == itemInHand.getJavaId() && isAlive() && !getFlag(EntityFlag.SHEARED)) { // Shearing the snow golem return InteractiveTag.SHEAR; @@ -61,7 +62,7 @@ public class SnowGolemEntity extends GolemEntity { @Nonnull @Override - protected InteractionResult mobInteract(@Nonnull GeyserItemStack itemInHand) { + protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) { if (session.getItemMappings().getStoredItems().shears() == itemInHand.getJavaId() && isAlive() && !getFlag(EntityFlag.SHEARED)) { // Shearing the snow golem return InteractionResult.SUCCESS; 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 64f41c5ad..0da53b7c6 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,6 +25,7 @@ package org.geysermc.geyser.entity.type.living.animal; +import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.entity.EntityEventType; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; @@ -63,16 +64,16 @@ public class AnimalEntity extends AgeableEntity { @Nonnull @Override - protected InteractiveTag testMobInteraction(@Nonnull GeyserItemStack itemInHand) { + protected InteractiveTag testMobInteraction(Hand hand, @Nonnull GeyserItemStack itemInHand) { if (canEat(itemInHand)) { return InteractiveTag.FEED; } - return super.testMobInteraction(itemInHand); + return super.testMobInteraction(hand, itemInHand); } @Nonnull @Override - protected InteractionResult mobInteract(@Nonnull GeyserItemStack itemInHand) { + protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) { if (canEat(itemInHand)) { // FEED if (getFlag(EntityFlag.BABY)) { @@ -82,6 +83,6 @@ public class AnimalEntity extends AgeableEntity { return InteractionResult.CONSUME; } } - return super.mobInteract(itemInHand); + return super.mobInteract(hand, itemInHand); } } 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 aafa2b782..446892016 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 @@ -27,6 +27,7 @@ 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 com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.entity.EntityData; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; @@ -75,11 +76,11 @@ public class AxolotlEntity extends AnimalEntity { @Nonnull @Override - protected InteractionResult mobInteract(@Nonnull GeyserItemStack itemInHand) { + protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) { if (EntityUtils.attemptToBucket(session, itemInHand)) { return InteractionResult.SUCCESS; } else { - return super.mobInteract(itemInHand); + return super.mobInteract(hand, itemInHand); } } } 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 b5ae48b23..3fd55d073 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,6 +25,7 @@ package org.geysermc.geyser.entity.type.living.animal; +import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.SoundEvent; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; @@ -44,9 +45,9 @@ public class CowEntity extends AnimalEntity { @Nonnull @Override - protected InteractiveTag testMobInteraction(@Nonnull GeyserItemStack itemInHand) { + protected InteractiveTag testMobInteraction(Hand hand, @Nonnull GeyserItemStack itemInHand) { if (getFlag(EntityFlag.BABY) || !itemInHand.getMapping(session).getJavaIdentifier().equals("minecraft:bucket")) { - return super.testMobInteraction(itemInHand); + return super.testMobInteraction(hand, itemInHand); } return InteractiveTag.MILK; @@ -54,9 +55,9 @@ public class CowEntity extends AnimalEntity { @Nonnull @Override - protected InteractionResult mobInteract(@Nonnull GeyserItemStack itemInHand) { + protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) { if (getFlag(EntityFlag.BABY) || !itemInHand.getMapping(session).getJavaIdentifier().equals("minecraft:bucket")) { - return super.mobInteract(itemInHand); + return super.mobInteract(hand, itemInHand); } session.playSoundEvent(SoundEvent.MILK, position); 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 95dd54b7a..0a9c5964b 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 @@ -33,6 +33,7 @@ import com.nukkitx.protocol.bedrock.data.entity.EntityData; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.entity.type.Entity; +import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; import java.util.OptionalInt; @@ -65,4 +66,9 @@ public class FrogEntity extends AnimalEntity { dirtyMetadata.put(EntityData.TARGET_EID, 0L); } } + + @Override + public boolean canEat(String javaIdentifierStripped, ItemMapping mapping) { + return javaIdentifierStripped.equals("slime_ball"); + } } 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 817b466fa..a6f2e268e 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 @@ -27,6 +27,7 @@ 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 com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.SoundEvent; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; @@ -65,12 +66,12 @@ public class GoatEntity extends AnimalEntity { @Nonnull @Override - protected InteractionResult mobInteract(@Nonnull GeyserItemStack itemInHand) { + protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) { if (!getFlag(EntityFlag.BABY) && itemInHand.getMapping(session).getJavaIdentifier().equals("minecraft:bucket")) { session.playSoundEvent(isScreamer ? SoundEvent.MILK_SCREAMER : SoundEvent.MILK, position); return InteractionResult.SUCCESS; } else { - return super.mobInteract(itemInHand); + return super.mobInteract(hand, 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 c249663ac..d2b8420fd 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 @@ -26,6 +26,7 @@ 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 com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.entity.EntityData; import org.geysermc.geyser.entity.EntityDefinition; @@ -52,7 +53,7 @@ public class MooshroomEntity extends AnimalEntity { @Nonnull @Override - protected InteractiveTag testMobInteraction(@Nonnull GeyserItemStack itemInHand) { + protected InteractiveTag testMobInteraction(Hand hand, @Nonnull GeyserItemStack itemInHand) { StoredItemMappings storedItems = session.getItemMappings().getStoredItems(); if (!isBaby()) { if (itemInHand.getJavaId() == storedItems.bowl()) { @@ -63,12 +64,12 @@ public class MooshroomEntity extends AnimalEntity { return InteractiveTag.MOOSHROOM_SHEAR; } } - return super.testMobInteraction(itemInHand); + return super.testMobInteraction(hand, itemInHand); } @Nonnull @Override - protected InteractionResult mobInteract(@Nonnull GeyserItemStack itemInHand) { + protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) { StoredItemMappings storedItems = session.getItemMappings().getStoredItems(); boolean isBaby = isBaby(); if (!isBaby && itemInHand.getJavaId() == storedItems.bowl()) { @@ -81,6 +82,6 @@ public class MooshroomEntity extends AnimalEntity { // ? return InteractionResult.SUCCESS; } - return super.mobInteract(itemInHand); + return super.mobInteract(hand, itemInHand); } } 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 4ed2bdce1..af1fe0bad 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,6 +25,7 @@ package org.geysermc.geyser.entity.type.living.animal; +import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.geyser.entity.EntityDefinition; @@ -50,23 +51,23 @@ public class OcelotEntity extends AnimalEntity { @Nonnull @Override - protected InteractiveTag testMobInteraction(@Nonnull GeyserItemStack itemInHand) { + protected InteractiveTag testMobInteraction(Hand hand, @Nonnull GeyserItemStack itemInHand) { if (!getFlag(EntityFlag.TRUSTING) && canEat(itemInHand) && session.getPlayerEntity().getPosition().distanceSquared(position) < 9f) { // Attempt to feed return InteractiveTag.FEED; } else { - return super.testMobInteraction(itemInHand); + return super.testMobInteraction(hand, itemInHand); } } @Nonnull @Override - protected InteractionResult mobInteract(@Nonnull GeyserItemStack itemInHand) { + protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) { if (!getFlag(EntityFlag.TRUSTING) && canEat(itemInHand) && session.getPlayerEntity().getPosition().distanceSquared(position) < 9f) { // Attempt to feed return InteractionResult.SUCCESS; } else { - return super.mobInteract(itemInHand); + return super.mobInteract(hand, itemInHand); } } } 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 d607f113b..51f595526 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 @@ -27,6 +27,7 @@ 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 com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.entity.EntityData; import com.nukkitx.protocol.bedrock.data.entity.EntityEventType; @@ -93,16 +94,16 @@ public class PandaEntity extends AnimalEntity { @Nonnull @Override - protected InteractiveTag testMobInteraction(@Nonnull GeyserItemStack itemInHand) { + protected InteractiveTag testMobInteraction(Hand hand, @Nonnull GeyserItemStack itemInHand) { if (mainGene == Gene.WORRIED && session.isThunder()) { return InteractiveTag.NONE; } - return super.testMobInteraction(itemInHand); + return super.testMobInteraction(hand, itemInHand); } @Nonnull @Override - protected InteractionResult mobInteract(@Nonnull GeyserItemStack itemInHand) { + protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) { if (mainGene == Gene.WORRIED && session.isThunder()) { // Huh! return InteractionResult.PASS; 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 05f628f44..db8a1ccd8 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,6 +25,7 @@ package org.geysermc.geyser.entity.type.living.animal; +import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.geyser.entity.EntityDefinition; @@ -51,12 +52,12 @@ public class PigEntity extends AnimalEntity { @Nonnull @Override - protected InteractiveTag testMobInteraction(@Nonnull GeyserItemStack itemInHand) { + protected InteractiveTag testMobInteraction(Hand hand, @Nonnull GeyserItemStack itemInHand) { if (!canEat(itemInHand) && getFlag(EntityFlag.SADDLED) && passengers.isEmpty() && !session.isSneaking()) { // Mount return InteractiveTag.MOUNT; } else { - InteractiveTag superTag = super.testMobInteraction(itemInHand); + InteractiveTag superTag = super.testMobInteraction(hand, itemInHand); if (superTag != InteractiveTag.NONE) { return superTag; } else { @@ -68,12 +69,12 @@ public class PigEntity extends AnimalEntity { @Nonnull @Override - protected InteractionResult mobInteract(@Nonnull GeyserItemStack itemInHand) { + protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) { if (!canEat(itemInHand) && getFlag(EntityFlag.SADDLED) && passengers.isEmpty() && !session.isSneaking()) { // Mount return InteractionResult.SUCCESS; } else { - InteractionResult superResult = super.mobInteract(itemInHand); + InteractionResult superResult = super.mobInteract(hand, itemInHand); if (superResult.consumesAction()) { return superResult; } else { 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 9481944a7..0febfdb11 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 com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata; +import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.entity.EntityData; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; @@ -55,11 +56,11 @@ public class SheepEntity extends AnimalEntity { @Nonnull @Override - protected InteractiveTag testMobInteraction(@Nonnull GeyserItemStack itemInHand) { + protected InteractiveTag testMobInteraction(Hand hand, @Nonnull GeyserItemStack itemInHand) { if (itemInHand.getJavaId() == session.getItemMappings().getStoredItems().shears()) { return InteractiveTag.SHEAR; } else { - InteractiveTag tag = super.testMobInteraction(itemInHand); + InteractiveTag tag = super.testMobInteraction(hand, itemInHand); if (tag != InteractiveTag.NONE) { return tag; } else { @@ -74,11 +75,11 @@ public class SheepEntity extends AnimalEntity { @Nonnull @Override - protected InteractionResult mobInteract(@Nonnull GeyserItemStack itemInHand) { + protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) { if (itemInHand.getJavaId() == session.getItemMappings().getStoredItems().shears()) { return InteractionResult.CONSUME; } else { - InteractionResult superResult = super.mobInteract(itemInHand); + InteractionResult superResult = super.mobInteract(hand, itemInHand); if (superResult.consumesAction()) { return superResult; } else { 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 5f42b4b67..f8d549299 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,6 +26,7 @@ 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 com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.geyser.entity.type.Entity; @@ -98,12 +99,12 @@ public class StriderEntity extends AnimalEntity { @Nonnull @Override - protected InteractiveTag testMobInteraction(@Nonnull GeyserItemStack itemInHand) { + protected InteractiveTag testMobInteraction(Hand hand, @Nonnull GeyserItemStack itemInHand) { if (!canEat(itemInHand) && getFlag(EntityFlag.SADDLED) && passengers.isEmpty() && !session.isSneaking()) { // Mount Strider return InteractiveTag.RIDE_STRIDER; } else { - InteractiveTag tag = super.testMobInteraction(itemInHand); + InteractiveTag tag = super.testMobInteraction(hand, itemInHand); if (tag != InteractiveTag.NONE) { return tag; } else { @@ -115,12 +116,12 @@ public class StriderEntity extends AnimalEntity { @Nonnull @Override - protected InteractionResult mobInteract(@Nonnull GeyserItemStack itemInHand) { + protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) { if (!canEat(itemInHand) && getFlag(EntityFlag.SADDLED) && passengers.isEmpty() && !session.isSneaking()) { // Mount Strider return InteractionResult.SUCCESS; } else { - InteractionResult superResult = super.mobInteract(itemInHand); + InteractionResult superResult = super.mobInteract(hand, itemInHand); if (superResult.consumesAction()) { return superResult; } else { 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 9139495b8..867d9f799 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 com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata; +import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import com.google.common.collect.ImmutableSet; import com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.entity.EntityData; @@ -129,12 +130,12 @@ public class AbstractHorseEntity extends AnimalEntity { @Nonnull @Override - protected InteractiveTag testMobInteraction(@Nonnull GeyserItemStack itemInHand) { - return testHorseInteraction(itemInHand); + protected InteractiveTag testMobInteraction(Hand hand, @Nonnull GeyserItemStack itemInHand) { + return testHorseInteraction(hand, itemInHand); } @Nonnull - protected final InteractiveTag testHorseInteraction(@Nonnull GeyserItemStack itemInHand) { + protected final InteractiveTag testHorseInteraction(@Nonnull Hand hand, @Nonnull GeyserItemStack itemInHand) { boolean isBaby = isBaby(); if (!isBaby) { if (getFlag(EntityFlag.TAMED) && session.isSneaking()) { @@ -142,7 +143,7 @@ public class AbstractHorseEntity extends AnimalEntity { } if (!passengers.isEmpty()) { - return super.testMobInteraction(itemInHand); + return super.testMobInteraction(hand, itemInHand); } } @@ -171,7 +172,7 @@ public class AbstractHorseEntity extends AnimalEntity { } if (isBaby) { - return super.testMobInteraction(itemInHand); + return super.testMobInteraction(hand, itemInHand); } else { return InteractiveTag.MOUNT; } @@ -179,12 +180,12 @@ public class AbstractHorseEntity extends AnimalEntity { @Nonnull @Override - protected InteractionResult mobInteract(@Nonnull GeyserItemStack itemInHand) { - return mobHorseInteract(itemInHand); + protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) { + return mobHorseInteract(hand, itemInHand); } @Nonnull - protected final InteractionResult mobHorseInteract(@Nonnull GeyserItemStack itemInHand) { + protected final InteractionResult mobHorseInteract(@Nonnull Hand hand, @Nonnull GeyserItemStack itemInHand) { boolean isBaby = isBaby(); if (!isBaby) { if (getFlag(EntityFlag.TAMED) && session.isSneaking()) { @@ -193,7 +194,7 @@ public class AbstractHorseEntity extends AnimalEntity { } if (!passengers.isEmpty()) { - return super.mobInteract(itemInHand); + return super.mobInteract(hand, itemInHand); } } @@ -227,7 +228,7 @@ public class AbstractHorseEntity extends AnimalEntity { } if (isBaby) { - return super.mobInteract(itemInHand); + return super.mobInteract(hand, itemInHand); } else { // Attempt to mount // TODO client-set flags sitting standing? @@ -249,15 +250,15 @@ public class AbstractHorseEntity extends AnimalEntity { /* Just a place to stuff common code for the undead variants without having duplicate code */ - protected final InteractiveTag testUndeadHorseInteraction(@Nonnull GeyserItemStack itemInHand) { + protected final InteractiveTag testUndeadHorseInteraction(@Nonnull Hand hand, @Nonnull GeyserItemStack itemInHand) { if (!getFlag(EntityFlag.TAMED)) { return InteractiveTag.NONE; } else if (isBaby()) { - return testHorseInteraction(itemInHand); + return testHorseInteraction(hand, itemInHand); } else if (session.isSneaking()) { return InteractiveTag.OPEN_CONTAINER; } else if (!passengers.isEmpty()) { - return testHorseInteraction(itemInHand); + return testHorseInteraction(hand, itemInHand); } else { if (session.getItemMappings().getStoredItems().saddle() == itemInHand.getJavaId()) { return InteractiveTag.OPEN_CONTAINER; @@ -271,16 +272,16 @@ public class AbstractHorseEntity extends AnimalEntity { } } - protected final InteractionResult undeadHorseInteract(@Nonnull GeyserItemStack itemInHand) { + protected final InteractionResult undeadHorseInteract(@Nonnull Hand hand, @Nonnull GeyserItemStack itemInHand) { if (!getFlag(EntityFlag.TAMED)) { return InteractionResult.PASS; } else if (isBaby()) { - return mobHorseInteract(itemInHand); + return mobHorseInteract(hand, itemInHand); } else if (session.isSneaking()) { // Opens inventory return InteractionResult.SUCCESS; } else if (!passengers.isEmpty()) { - return mobHorseInteract(itemInHand); + return mobHorseInteract(hand, itemInHand); } else { // The client tests for saddle but it doesn't matter for us at this point. return InteractionResult.SUCCESS; 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 c9f95f507..4d07c7d13 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,6 +25,7 @@ package org.geysermc.geyser.entity.type.living.animal.horse; +import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import com.nukkitx.math.vector.Vector3f; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.inventory.GeyserItemStack; @@ -42,13 +43,13 @@ public class SkeletonHorseEntity extends AbstractHorseEntity { @Nonnull @Override - protected InteractiveTag testMobInteraction(@Nonnull GeyserItemStack itemInHand) { - return testUndeadHorseInteraction(itemInHand); + protected InteractiveTag testMobInteraction(Hand hand, @Nonnull GeyserItemStack itemInHand) { + return testUndeadHorseInteraction(hand, itemInHand); } @Nonnull @Override - protected InteractionResult mobInteract(@Nonnull GeyserItemStack itemInHand) { - return undeadHorseInteract(itemInHand); + protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) { + return undeadHorseInteract(hand, itemInHand); } } 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 ddde11c5d..659a8bad8 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,6 +25,7 @@ package org.geysermc.geyser.entity.type.living.animal.horse; +import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import com.nukkitx.math.vector.Vector3f; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.inventory.GeyserItemStack; @@ -42,13 +43,13 @@ public class ZombieHorseEntity extends AbstractHorseEntity { @Nonnull @Override - protected InteractiveTag testMobInteraction(@Nonnull GeyserItemStack itemInHand) { - return testUndeadHorseInteraction(itemInHand); + protected InteractiveTag testMobInteraction(Hand hand, @Nonnull GeyserItemStack itemInHand) { + return testUndeadHorseInteraction(hand, itemInHand); } @Nonnull @Override - protected InteractionResult mobInteract(@Nonnull GeyserItemStack itemInHand) { - return undeadHorseInteract(itemInHand); + protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) { + return undeadHorseInteract(hand, itemInHand); } } 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 c17503606..022535592 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 @@ -28,6 +28,7 @@ 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 com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.entity.EntityData; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; @@ -105,7 +106,7 @@ public class CatEntity extends TameableEntity { @Nonnull @Override - protected InteractiveTag testMobInteraction(@Nonnull GeyserItemStack itemInHand) { + protected InteractiveTag testMobInteraction(Hand hand, @Nonnull GeyserItemStack itemInHand) { boolean tamed = getFlag(EntityFlag.TAMED); if (tamed && ownerBedrockId == session.getPlayerEntity().getGeyserId()) { // Toggle sitting @@ -117,7 +118,7 @@ public class CatEntity extends TameableEntity { @Nonnull @Override - protected InteractionResult mobInteract(@Nonnull GeyserItemStack itemInHand) { + protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) { boolean tamed = getFlag(EntityFlag.TAMED); if (tamed && ownerBedrockId == session.getPlayerEntity().getGeyserId()) { return InteractionResult.SUCCESS; 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 b7aca99e5..2b49168dd 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,6 +25,7 @@ package org.geysermc.geyser.entity.type.living.animal.tameable; +import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.geyser.entity.EntityDefinition; @@ -58,7 +59,7 @@ public class ParrotEntity extends TameableEntity { @Nonnull @Override - protected InteractiveTag testMobInteraction(@Nonnull GeyserItemStack itemInHand) { + protected InteractiveTag testMobInteraction(Hand hand, @Nonnull GeyserItemStack itemInHand) { String javaIdentifierStripped = itemInHand.getMapping(session).getJavaIdentifier().replace("minecraft:", ""); boolean tame = getFlag(EntityFlag.TAMED); if (!tame && isTameFood(javaIdentifierStripped)) { @@ -69,12 +70,12 @@ public class ParrotEntity extends TameableEntity { // Sitting/standing return getFlag(EntityFlag.SITTING) ? InteractiveTag.STAND : InteractiveTag.SIT; } - return super.testMobInteraction(itemInHand); + return super.testMobInteraction(hand, itemInHand); } @Nonnull @Override - protected InteractionResult mobInteract(@Nonnull GeyserItemStack itemInHand) { + protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) { String javaIdentifierStripped = itemInHand.getMapping(session).getJavaIdentifier().replace("minecraft:", ""); boolean tame = getFlag(EntityFlag.TAMED); if (!tame && isTameFood(javaIdentifierStripped)) { @@ -85,6 +86,6 @@ public class ParrotEntity extends TameableEntity { // Sitting/standing return InteractionResult.SUCCESS; } - return super.mobInteract(itemInHand); + return super.mobInteract(hand, itemInHand); } } 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 8b900f071..bc5209bcb 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 @@ -27,6 +27,7 @@ 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 com.google.common.collect.ImmutableSet; import com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.entity.EntityData; @@ -103,7 +104,7 @@ public class WolfEntity extends TameableEntity { @Nonnull @Override - protected InteractiveTag testMobInteraction(@Nonnull GeyserItemStack itemInHand) { + protected InteractiveTag testMobInteraction(Hand hand, @Nonnull GeyserItemStack itemInHand) { if (getFlag(EntityFlag.ANGRY)) { return InteractiveTag.NONE; } @@ -122,12 +123,12 @@ public class WolfEntity extends TameableEntity { return getFlag(EntityFlag.SITTING) ? InteractiveTag.STAND : InteractiveTag.SIT; } } - return super.testMobInteraction(itemInHand); + return super.testMobInteraction(hand, itemInHand); } @Nonnull @Override - protected InteractionResult mobInteract(@Nonnull GeyserItemStack itemInHand) { + protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) { if (ownerBedrockId == session.getPlayerEntity().getGeyserId() || getFlag(EntityFlag.TAMED) || itemInHand.getMapping(session).getJavaIdentifier().equals("minecraft:bone") && !getFlag(EntityFlag.ANGRY)) { // Sitting toggle or feeding; not angry 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 633ba707f..e6538ebad 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,6 +25,7 @@ package org.geysermc.geyser.entity.type.living.merchant; +import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.geyser.entity.EntityDefinition; @@ -51,7 +52,7 @@ public class AbstractMerchantEntity extends AgeableEntity { @Nonnull @Override - protected InteractiveTag testMobInteraction(@Nonnull GeyserItemStack itemInHand) { + protected InteractiveTag testMobInteraction(Hand hand, @Nonnull GeyserItemStack itemInHand) { String javaIdentifier = itemInHand.getMapping(session).getJavaIdentifier(); if (!javaIdentifier.equals("minecraft:villager_spawn_egg") && (definition != EntityDefinitions.VILLAGER || !getFlag(EntityFlag.SLEEPING) && ((VillagerEntity) this).isCanTradeWith())) { @@ -60,12 +61,12 @@ public class AbstractMerchantEntity extends AgeableEntity { return InteractiveTag.TRADE; } } - return super.testMobInteraction(itemInHand); + return super.testMobInteraction(hand, itemInHand); } @Nonnull @Override - protected InteractionResult mobInteract(@Nonnull GeyserItemStack itemInHand) { + protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) { String javaIdentifier = itemInHand.getMapping(session).getJavaIdentifier(); if (!javaIdentifier.equals("minecraft:villager_spawn_egg") && (definition != EntityDefinitions.VILLAGER || !getFlag(EntityFlag.SLEEPING)) @@ -73,7 +74,7 @@ public class AbstractMerchantEntity extends AgeableEntity { // Trading time return InteractionResult.SUCCESS; } else { - return super.mobInteract(itemInHand); + return super.mobInteract(hand, itemInHand); } } } 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 cf9393410..f73ab257a 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 @@ -27,6 +27,7 @@ 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 com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.SoundEvent; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; @@ -63,23 +64,23 @@ public class CreeperEntity extends MonsterEntity { @Nonnull @Override - protected InteractiveTag testMobInteraction(@Nonnull GeyserItemStack itemInHand) { + protected InteractiveTag testMobInteraction(Hand hand, @Nonnull GeyserItemStack itemInHand) { if (itemInHand.getJavaId() == session.getItemMappings().getStoredItems().flintAndSteel()) { return InteractiveTag.IGNITE_CREEPER; } else { - return super.testMobInteraction(itemInHand); + return super.testMobInteraction(hand, itemInHand); } } @Nonnull @Override - protected InteractionResult mobInteract(@Nonnull GeyserItemStack itemInHand) { + protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) { if (itemInHand.getJavaId() == session.getItemMappings().getStoredItems().flintAndSteel()) { // Ignite creeper session.playSoundEvent(SoundEvent.IGNITE, position); return InteractionResult.SUCCESS; } else { - return super.mobInteract(itemInHand); + return super.mobInteract(hand, itemInHand); } } } 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 f0577ee20..4eb0baa6c 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 @@ -26,6 +26,7 @@ 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 com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.entity.EntityData; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; @@ -71,8 +72,8 @@ public class PiglinEntity extends BasePiglinEntity { @Nonnull @Override - protected InteractiveTag testMobInteraction(@Nonnull GeyserItemStack itemInHand) { - InteractiveTag tag = super.testMobInteraction(itemInHand); + protected InteractiveTag testMobInteraction(Hand hand, @Nonnull GeyserItemStack itemInHand) { + InteractiveTag tag = super.testMobInteraction(hand, itemInHand); if (tag != InteractiveTag.NONE) { return tag; } else { @@ -82,8 +83,8 @@ public class PiglinEntity extends BasePiglinEntity { @Nonnull @Override - protected InteractionResult mobInteract(@Nonnull GeyserItemStack itemInHand) { - InteractionResult superResult = super.mobInteract(itemInHand); + protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) { + InteractionResult superResult = super.mobInteract(hand, itemInHand); if (superResult.consumesAction()) { return superResult; } else { 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 1ec0fc26b..bf5180e36 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 @@ -28,6 +28,7 @@ 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 com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.entity.EntityData; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; @@ -67,22 +68,22 @@ public class ZombieVillagerEntity extends ZombieEntity { @Nonnull @Override - protected InteractiveTag testMobInteraction(@Nonnull GeyserItemStack itemInHand) { + protected InteractiveTag testMobInteraction(Hand hand, @Nonnull GeyserItemStack itemInHand) { if (itemInHand.getJavaId() == session.getItemMappings().getStoredItems().goldenApple()) { return InteractiveTag.CURE; } else { - return super.testMobInteraction(itemInHand); + return super.testMobInteraction(hand, itemInHand); } } @Nonnull @Override - protected InteractionResult mobInteract(@Nonnull GeyserItemStack itemInHand) { + protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) { if (itemInHand.getJavaId() == session.getItemMappings().getStoredItems().goldenApple()) { // The client doesn't know if the entity has weakness as that's not usually sent over the network return InteractionResult.CONSUME; } else { - return super.mobInteract(itemInHand); + return super.mobInteract(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 1e8795478..9607ac61e 100644 --- a/core/src/main/java/org/geysermc/geyser/util/InteractiveTag.java +++ b/core/src/main/java/org/geysermc/geyser/util/InteractiveTag.java @@ -69,7 +69,8 @@ public enum InteractiveTag { EQUIP_ARMOR_STAND("armorstand.equip"), READ, WAKE_VILLAGER("wakevillager"), - BARTER; + BARTER, + GIVE_ITEM_TO_ALLAY("allay"); /** * The full string that should be passed on to the client. From d74b0e236d4a5fb78ece87f1e911d06df1530c04 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Thu, 26 May 2022 18:04:58 -0400 Subject: [PATCH 26/72] Fix encoding SpawnParticleEffectPacket for 1.18.30+ --- .../geyser/entity/type/living/monster/EnderDragonEntity.java | 2 ++ .../translator/protocol/java/entity/JavaAnimateTranslator.java | 3 +++ .../protocol/java/level/JavaLevelParticlesTranslator.java | 2 ++ 3 files changed, 7 insertions(+) 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 99ab1a55c..1d689e806 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 @@ -39,6 +39,7 @@ import org.geysermc.geyser.entity.type.living.MobEntity; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.util.DimensionUtils; +import java.util.Optional; import java.util.Random; import java.util.UUID; import java.util.concurrent.ThreadLocalRandom; @@ -262,6 +263,7 @@ public class EnderDragonEntity extends MobEntity implements Tickable { spawnParticleEffectPacket.setDimensionId(DimensionUtils.javaToBedrock(session.getDimension())); spawnParticleEffectPacket.setPosition(head.getPosition().add(random.nextGaussian() / 2f, random.nextGaussian() / 2f, random.nextGaussian() / 2f)); spawnParticleEffectPacket.setIdentifier("minecraft:dragon_breath_fire"); + spawnParticleEffectPacket.setMolangVariablesJson(Optional.empty()); session.sendUpstreamPacket(spawnParticleEffectPacket); } } 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 b9cbebb22..559964f63 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 @@ -36,6 +36,8 @@ import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; import org.geysermc.geyser.util.DimensionUtils; +import java.util.Optional; + @Translator(packet = ClientboundAnimatePacket.class) public class JavaAnimateTranslator extends PacketTranslator { @@ -77,6 +79,7 @@ public class JavaAnimateTranslator extends PacketTranslator Date: Thu, 26 May 2022 18:09:27 -0400 Subject: [PATCH 27/72] Reinforced deepslate can't be moved by pistons --- .../geyser/registry/populator/BlockRegistryPopulator.java | 2 +- 1 file changed, 1 insertion(+), 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 3dfa6c2db..58a1bdb0f 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 @@ -250,7 +250,7 @@ public class BlockRegistryPopulator { builder.pickItem(pickItemNode.textValue().intern()); } - if (javaId.equals("minecraft:obsidian") || javaId.equals("minecraft:crying_obsidian") || javaId.startsWith("minecraft:respawn_anchor")) { + 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"); From e2ce553d3acad24042d6bb0c33d262bd00eea426 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Thu, 26 May 2022 18:41:19 -0400 Subject: [PATCH 28/72] Warden time --- .../geyser/entity/EntityDefinitions.java | 6 ++ .../type/living/monster/WardenEntity.java | 58 +++++++++++++++++++ .../org/geysermc/geyser/util/MathUtils.java | 19 ++++++ 3 files changed, 83 insertions(+) create mode 100644 core/src/main/java/org/geysermc/geyser/entity/type/living/monster/WardenEntity.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 5d1a00968..198710349 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java +++ b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java @@ -156,6 +156,7 @@ public final class EntityDefinitions { public static final EntityDefinition VILLAGER; public static final EntityDefinition VINDICATOR; public static final EntityDefinition WANDERING_TRADER; + public static final EntityDefinition WARDEN; public static final EntityDefinition WITCH; public static final EntityDefinition WITHER; public static final EntityDefinition WITHER_SKELETON; @@ -561,6 +562,11 @@ public final class EntityDefinitions { .height(0.8f).width(0.4f) .addTranslator(MetadataType.BYTE, VexEntity::setVexFlags) .build(); + WARDEN = EntityDefinition.inherited(WardenEntity::new, mobEntityBase) + .type(EntityType.WARDEN) + .height(2.9f).width(0.9f) + .addTranslator(MetadataType.INT, WardenEntity::setAngerLevel) + .build(); WITHER = EntityDefinition.inherited(WitherEntity::new, mobEntityBase) .type(EntityType.WITHER) .height(3.5f).width(0.9f) 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 new file mode 100644 index 000000000..3a8e9d351 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/WardenEntity.java @@ -0,0 +1,58 @@ +/* + * 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.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 com.nukkitx.math.GenericMath; +import com.nukkitx.math.vector.Vector3f; +import com.nukkitx.protocol.bedrock.data.entity.EntityData; +import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; +import org.geysermc.geyser.entity.EntityDefinition; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.util.MathUtils; + +import java.util.UUID; + +public class WardenEntity extends MonsterEntity { + public WardenEntity(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) { + setFlag(EntityFlag.DIGGING, pose == Pose.DIGGING); + setFlag(EntityFlag.EMERGING, pose == Pose.EMERGING); + setFlag(EntityFlag.ROARING, pose == Pose.ROARING); + setFlag(EntityFlag.SNIFFING, pose == Pose.SNIFFING); + super.setPose(pose); + } + + public void setAngerLevel(IntEntityMetadata entityMetadata) { + float anger = (float) entityMetadata.getPrimitiveValue() / 80f; + dirtyMetadata.put(EntityData.HEARTBEAT_INTERVAL_TICKS, 40 - GenericMath.floor(MathUtils.clamp(anger, 0.0F, 1.0F) * 30F)); + } +} 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 50cfa001e..a89240f25 100644 --- a/core/src/main/java/org/geysermc/geyser/util/MathUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/MathUtils.java @@ -101,6 +101,25 @@ public class MathUtils { return num; } + /** + * Clamps the value between the low and high boundaries + * Copied from {@link com.nukkitx.math.GenericMath} with floats instead. + * + * @param value The value to clamp + * @param low The low bound of the clamp + * @param high The high bound of the clamp + * @return the clamped value + */ + public static double clamp(float value, float low, float high) { + if (value < low) { + return low; + } + if (value > high) { + return high; + } + 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. From 85800eb32bdef9cf9063efc9412d07f2a3320ef1 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Thu, 26 May 2022 18:52:04 -0400 Subject: [PATCH 29/72] Tadpole --- .../geyser/entity/EntityDefinitions.java | 5 ++ .../entity/type/living/TadpoleEntity.java | 66 +++++++++++++++++++ .../entity/type/living/animal/FrogEntity.java | 2 +- .../inventory/item/StoredItemMappings.java | 2 + 4 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 core/src/main/java/org/geysermc/geyser/entity/type/living/TadpoleEntity.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 198710349..eda8e0c84 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java +++ b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java @@ -146,6 +146,7 @@ public final class EntityDefinitions { public static final EntityDefinition SQUID; public static final EntityDefinition STRAY; public static final EntityDefinition STRIDER; + public static final EntityDefinition TADPOLE; public static final EntityDefinition TNT; public static final EntityDefinition TNT_MINECART; public static final EntityDefinition TRADER_LLAMA; @@ -651,6 +652,10 @@ public final class EntityDefinitions { .type(EntityType.SALMON) .height(0.5f).width(0.7f) .build(); + TADPOLE = EntityDefinition.inherited(TadpoleEntity::new, abstractFishEntityBase) + .type(EntityType.TADPOLE) + .height(0.3f).width(0.4f) + .build(); TROPICAL_FISH = EntityDefinition.inherited(TropicalFishEntity::new, abstractFishEntityBase) .type(EntityType.TROPICAL_FISH) .heightAndWidth(0.6f) 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 new file mode 100644 index 000000000..034dffc65 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/TadpoleEntity.java @@ -0,0 +1,66 @@ +/* + * 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.entity.type.living; + +import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; +import com.nukkitx.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.util.InteractionResult; +import org.geysermc.geyser.util.InteractiveTag; + +import javax.annotation.Nonnull; +import java.util.UUID; + +public class TadpoleEntity extends AbstractFishEntity { + public TadpoleEntity(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); + } + + @Nonnull + @Override + protected InteractiveTag testMobInteraction(@Nonnull Hand hand, @Nonnull GeyserItemStack itemInHand) { + if (isFood(itemInHand)) { + return InteractiveTag.FEED; + } + return super.testMobInteraction(hand, itemInHand); + } + + @Nonnull + @Override + protected InteractionResult mobInteract(@Nonnull Hand hand, @Nonnull GeyserItemStack itemInHand) { + if (isFood(itemInHand)) { + //TODO particles + return InteractionResult.SUCCESS; + } + return super.mobInteract(hand, itemInHand); + } + + private boolean isFood(GeyserItemStack itemStack) { + return itemStack.getJavaId() == session.getItemMappings().getStoredItems().slimeBall(); + } +} 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 0a9c5964b..e4bd8c5ce 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 @@ -69,6 +69,6 @@ public class FrogEntity extends AnimalEntity { @Override public boolean canEat(String javaIdentifierStripped, ItemMapping mapping) { - return javaIdentifierStripped.equals("slime_ball"); + return mapping.getJavaId() == session.getItemMappings().getStoredItems().slimeBall(); } } 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 c787f87a1..56b6ee7ac 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 @@ -60,6 +60,7 @@ public class StoredItemMappings { private final int saddle; private final int shears; private final ItemMapping shield; + private final int slimeBall; private final int waterBucket; private final ItemMapping wheat; private final ItemMapping writableBook; @@ -87,6 +88,7 @@ public class StoredItemMappings { this.saddle = load(itemMappings, "saddle").getJavaId(); this.shears = load(itemMappings, "shears").getJavaId(); this.shield = load(itemMappings, "shield"); + this.slimeBall = load(itemMappings, "slime_ball").getJavaId(); this.waterBucket = load(itemMappings, "water_bucket").getJavaId(); this.wheat = load(itemMappings, "wheat"); this.writableBook = load(itemMappings, "writable_book"); From 4a9eec4c549338d9d5d85904ed6120013f980569 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Thu, 26 May 2022 19:34:27 -0400 Subject: [PATCH 30/72] Implement last death position translation --- .../type/player/SessionPlayerEntity.java | 18 ++++++++++++++---- .../protocol/java/JavaLoginTranslator.java | 6 ++++-- .../protocol/java/JavaRespawnTranslator.java | 3 +++ 3 files changed, 21 insertions(+), 6 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 6edcd60f3..db39a34db 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,6 +27,7 @@ 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.nukkitx.math.vector.Vector3f; @@ -40,11 +41,10 @@ import org.geysermc.geyser.entity.attribute.GeyserAttributeType; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.util.AttributeUtils; +import org.geysermc.geyser.util.DimensionUtils; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.UUID; +import javax.annotation.Nullable; +import java.util.*; /** * The entity class specifically for a {@link GeyserSession}'s player. @@ -222,4 +222,14 @@ public class SessionPlayerEntity extends PlayerEntity { this.attributes.put(type, attributeData); return attributeData; } + + public void setLastDeathPosition(@Nullable GlobalPos pos) { + if (pos != null) { + dirtyMetadata.put(EntityData.PLAYER_LAST_DEATH_POS, pos.getPosition()); + dirtyMetadata.put(EntityData.PLAYER_LAST_DEATH_DIMENSION, DimensionUtils.javaToBedrock(pos.getDimension())); + dirtyMetadata.put(EntityData.PLAYER_HAS_DIED, (byte) 1); + } else { + dirtyMetadata.put(EntityData.PLAYER_HAS_DIED, (byte) 0); + } + } } 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 46e9b2f12..27bab75bb 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 @@ -36,7 +36,7 @@ import com.nukkitx.protocol.bedrock.packet.AdventureSettingsPacket; import com.nukkitx.protocol.bedrock.packet.GameRulesChangedPacket; import com.nukkitx.protocol.bedrock.packet.SetPlayerGameTypePacket; import org.geysermc.floodgate.pluginmessage.PluginMessageChannels; -import org.geysermc.geyser.entity.type.player.PlayerEntity; +import org.geysermc.geyser.entity.type.player.SessionPlayerEntity; import org.geysermc.geyser.level.JavaDimension; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.auth.AuthType; @@ -56,7 +56,7 @@ public class JavaLoginTranslator extends PacketTranslator dimensions = session.getDimensions(); @@ -116,6 +116,8 @@ public class JavaLoginTranslator extends PacketTranslator Date: Thu, 26 May 2022 19:57:45 -0400 Subject: [PATCH 31/72] SoundEvent and ParticleEvent are now combined --- .../geysermc/geyser/registry/Registries.java | 6 +- .../loader/SoundEventsRegistryLoader.java | 18 +- .../java/level/JavaLevelEventTranslator.java | 328 +++++++++--------- 3 files changed, 175 insertions(+), 177 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 0b59492d3..8f2a9775a 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/Registries.java +++ b/core/src/main/java/org/geysermc/geyser/registry/Registries.java @@ -27,7 +27,7 @@ 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.SoundEvent; +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; @@ -155,9 +155,9 @@ public final class Registries { public static final SimpleMappedRegistry SOUNDS = SimpleMappedRegistry.create("mappings/sounds.json", SoundRegistryLoader::new); /** - * A mapped registry holding {@link SoundEvent}s to their corresponding {@link LevelEventTranslator}. + * A mapped registry holding {@link LevelEvent}s to their corresponding {@link LevelEventTranslator}. */ - public static final SimpleMappedRegistry SOUND_EVENTS = SimpleMappedRegistry.create("mappings/effects.json", SoundEventsRegistryLoader::new); + public static final SimpleMappedRegistry SOUND_LEVEL_EVENTS = SimpleMappedRegistry.create("mappings/effects.json", SoundEventsRegistryLoader::new); /** * A mapped registry holding {@link SoundTranslator}s to their corresponding {@link SoundInteractionTranslator}. 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 fa7898f97..64d974bc3 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.SoundEvent; +import com.github.steveice10.mc.protocol.data.game.level.event.LevelEvent; import com.nukkitx.protocol.bedrock.data.LevelEventType; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import org.geysermc.geyser.GeyserImpl; @@ -41,37 +41,37 @@ import java.util.Map; /** * Loads sound effects from the given resource path. */ -public class SoundEventsRegistryLoader extends EffectRegistryLoader> { +public class SoundEventsRegistryLoader extends EffectRegistryLoader> { @Override - public Map load(String input) { + public Map load(String input) { this.loadFile(input); Iterator> effectsIterator = this.get(input).fields(); - Map soundEffects = new Object2ObjectOpenHashMap<>(); + Map soundEffects = new Object2ObjectOpenHashMap<>(); while (effectsIterator.hasNext()) { Map.Entry entry = effectsIterator.next(); JsonNode node = entry.getValue(); try { String type = node.get("type").asText(); - SoundEvent javaEffect = null; + LevelEvent javaEffect = null; LevelEventTranslator transformer = null; switch (type) { case "soundLevel" -> { - javaEffect = SoundEvent.valueOf(entry.getKey()); + javaEffect = LevelEvent.valueOf(entry.getKey()); LevelEventType levelEventType = LevelEventType.valueOf(node.get("name").asText()); int data = node.has("data") ? node.get("data").intValue() : 0; transformer = new SoundLevelEventTranslator(levelEventType, data); } case "soundEvent" -> { - javaEffect = SoundEvent.valueOf(entry.getKey()); + javaEffect = LevelEvent.valueOf(entry.getKey()); com.nukkitx.protocol.bedrock.data.SoundEvent soundEvent = com.nukkitx.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 = SoundEvent.valueOf(entry.getKey()); + javaEffect = LevelEvent.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(); @@ -85,7 +85,7 @@ public class SoundEventsRegistryLoader extends EffectRegistryLoader { + effectPacket.setType(LevelEventType.PARTICLE_CROP_GROWTH); + + ComposterEventData composterEventData = (ComposterEventData) packet.getData(); + LevelSoundEventPacket soundEventPacket = new LevelSoundEventPacket(); + switch (composterEventData) { + case FILL -> soundEventPacket.setSound(SoundEvent.COMPOSTER_FILL); + case FILL_SUCCESS -> soundEventPacket.setSound(SoundEvent.COMPOSTER_FILL_LAYER); + } + soundEventPacket.setPosition(pos); + soundEventPacket.setIdentifier(""); + soundEventPacket.setExtraData(-1); + soundEventPacket.setBabySound(false); + soundEventPacket.setRelativeVolumeDisabled(false); + session.sendUpstreamPacket(soundEventPacket); } - GeyserImpl.getInstance().getLogger().debug("Unhandled sound event: " + soundEvent.name()); - } else if (packet.getEvent() instanceof ParticleEvent particleEvent) { - Vector3i origin = packet.getPosition(); - Vector3f pos = Vector3f.from(origin.getX() + 0.5f, origin.getY() + 0.5f, origin.getZ() + 0.5f); + case BLOCK_LAVA_EXTINGUISH -> { + effectPacket.setType(LevelEventType.PARTICLE_EVAPORATE); + effectPacket.setPosition(pos.add(-0.5f, 0.7f, -0.5f)); - LevelEventPacket effectPacket = new LevelEventPacket(); - effectPacket.setPosition(pos); - effectPacket.setData(0); - switch (particleEvent) { - case COMPOSTER -> { - effectPacket.setType(LevelEventType.PARTICLE_CROP_GROWTH); + LevelSoundEventPacket soundEventPacket = new LevelSoundEventPacket(); + soundEventPacket.setSound(SoundEvent.EXTINGUISH_FIRE); + soundEventPacket.setPosition(pos); + soundEventPacket.setIdentifier(""); + soundEventPacket.setExtraData(-1); + soundEventPacket.setBabySound(false); + soundEventPacket.setRelativeVolumeDisabled(false); + session.sendUpstreamPacket(soundEventPacket); + } + case BLOCK_REDSTONE_TORCH_BURNOUT -> { + effectPacket.setType(LevelEventType.PARTICLE_EVAPORATE); + effectPacket.setPosition(pos.add(-0.5f, 0, -0.5f)); - ComposterEventData composterEventData = (ComposterEventData) packet.getData(); - LevelSoundEventPacket soundEventPacket = new LevelSoundEventPacket(); - switch (composterEventData) { - case FILL -> soundEventPacket.setSound(SoundEvent.COMPOSTER_FILL); - case FILL_SUCCESS -> soundEventPacket.setSound(SoundEvent.COMPOSTER_FILL_LAYER); + LevelSoundEventPacket soundEventPacket = new LevelSoundEventPacket(); + soundEventPacket.setSound(SoundEvent.EXTINGUISH_FIRE); + soundEventPacket.setPosition(pos); + soundEventPacket.setIdentifier(""); + soundEventPacket.setExtraData(-1); + soundEventPacket.setBabySound(false); + soundEventPacket.setRelativeVolumeDisabled(false); + session.sendUpstreamPacket(soundEventPacket); + } + case BLOCK_END_PORTAL_FRAME_FILL -> { + effectPacket.setType(LevelEventType.PARTICLE_EVAPORATE); + effectPacket.setPosition(pos.add(-0.5f, 0.3125f, -0.5f)); + + LevelSoundEventPacket soundEventPacket = new LevelSoundEventPacket(); + soundEventPacket.setSound(SoundEvent.BLOCK_END_PORTAL_FRAME_FILL); + soundEventPacket.setPosition(pos); + soundEventPacket.setIdentifier(""); + soundEventPacket.setExtraData(-1); + soundEventPacket.setBabySound(false); + soundEventPacket.setRelativeVolumeDisabled(false); + session.sendUpstreamPacket(soundEventPacket); + } + case SMOKE -> { + effectPacket.setType(LevelEventType.PARTICLE_SHOOT); + + SmokeEventData smokeEventData = (SmokeEventData) packet.getData(); + int data = 0; + switch (smokeEventData) { + case DOWN -> { + data = 4; + pos = pos.add(0, -0.9f, 0); } - soundEventPacket.setPosition(pos); - soundEventPacket.setIdentifier(""); - soundEventPacket.setExtraData(-1); - soundEventPacket.setBabySound(false); - soundEventPacket.setRelativeVolumeDisabled(false); - session.sendUpstreamPacket(soundEventPacket); - } - case BLOCK_LAVA_EXTINGUISH -> { - effectPacket.setType(LevelEventType.PARTICLE_EVAPORATE); - effectPacket.setPosition(pos.add(-0.5f, 0.7f, -0.5f)); - - LevelSoundEventPacket soundEventPacket = new LevelSoundEventPacket(); - soundEventPacket.setSound(SoundEvent.EXTINGUISH_FIRE); - soundEventPacket.setPosition(pos); - soundEventPacket.setIdentifier(""); - soundEventPacket.setExtraData(-1); - soundEventPacket.setBabySound(false); - soundEventPacket.setRelativeVolumeDisabled(false); - session.sendUpstreamPacket(soundEventPacket); - } - case BLOCK_REDSTONE_TORCH_BURNOUT -> { - effectPacket.setType(LevelEventType.PARTICLE_EVAPORATE); - effectPacket.setPosition(pos.add(-0.5f, 0, -0.5f)); - - LevelSoundEventPacket soundEventPacket = new LevelSoundEventPacket(); - soundEventPacket.setSound(SoundEvent.EXTINGUISH_FIRE); - soundEventPacket.setPosition(pos); - soundEventPacket.setIdentifier(""); - soundEventPacket.setExtraData(-1); - soundEventPacket.setBabySound(false); - soundEventPacket.setRelativeVolumeDisabled(false); - session.sendUpstreamPacket(soundEventPacket); - } - case BLOCK_END_PORTAL_FRAME_FILL -> { - effectPacket.setType(LevelEventType.PARTICLE_EVAPORATE); - effectPacket.setPosition(pos.add(-0.5f, 0.3125f, -0.5f)); - - LevelSoundEventPacket soundEventPacket = new LevelSoundEventPacket(); - soundEventPacket.setSound(SoundEvent.BLOCK_END_PORTAL_FRAME_FILL); - soundEventPacket.setPosition(pos); - soundEventPacket.setIdentifier(""); - soundEventPacket.setExtraData(-1); - soundEventPacket.setBabySound(false); - soundEventPacket.setRelativeVolumeDisabled(false); - session.sendUpstreamPacket(soundEventPacket); - } - case SMOKE -> { - effectPacket.setType(LevelEventType.PARTICLE_SHOOT); - - SmokeEventData smokeEventData = (SmokeEventData) packet.getData(); - int data = 0; - switch (smokeEventData) { - case DOWN -> { - data = 4; - pos = pos.add(0, -0.9f, 0); - } - case UP -> { - data = 4; - pos = pos.add(0, 0.5f, 0); - } - case NORTH -> { - data = 1; - pos = pos.add(0, -0.2f, -0.7f); - } - case SOUTH -> { - data = 7; - pos = pos.add(0, -0.2f, 0.7f); - } - case WEST -> { - data = 3; - pos = pos.add(-0.7f, -0.2f, 0); - } - case EAST -> { - data = 5; - pos = pos.add(0.7f, -0.2f, 0); - } + case UP -> { + data = 4; + pos = pos.add(0, 0.5f, 0); } - effectPacket.setPosition(pos); - effectPacket.setData(data); - } - - //TODO: Block break particles when under fire - case BREAK_BLOCK -> { - effectPacket.setType(LevelEventType.PARTICLE_DESTROY_BLOCK); - - BreakBlockEventData breakBlockEventData = (BreakBlockEventData) packet.getData(); - effectPacket.setData(session.getBlockMappings().getBedrockBlockId(breakBlockEventData.getBlockState())); - } - case BREAK_SPLASH_POTION -> { - effectPacket.setType(LevelEventType.PARTICLE_POTION_SPLASH); - effectPacket.setPosition(pos.add(0, -0.5f, 0)); - - BreakPotionEventData splashPotionData = (BreakPotionEventData) packet.getData(); - effectPacket.setData(splashPotionData.getPotionId()); - - LevelSoundEventPacket soundEventPacket = new LevelSoundEventPacket(); - soundEventPacket.setSound(SoundEvent.GLASS); - soundEventPacket.setPosition(pos); - soundEventPacket.setIdentifier(""); - soundEventPacket.setExtraData(-1); - soundEventPacket.setBabySound(false); - soundEventPacket.setRelativeVolumeDisabled(false); - session.sendUpstreamPacket(soundEventPacket); - } - case BREAK_EYE_OF_ENDER -> effectPacket.setType(LevelEventType.PARTICLE_EYE_OF_ENDER_DEATH); - case MOB_SPAWN -> effectPacket.setType(LevelEventType.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(particleEvent == ParticleEvent.BONEMEAL_GROW ? LevelEventType.PARTICLE_TURTLE_EGG : LevelEventType.PARTICLE_CROP_GROWTH); - - BonemealGrowEventData growEventData = (BonemealGrowEventData) packet.getData(); - effectPacket.setData(growEventData.getParticleCount()); - } - case ENDERDRAGON_FIREBALL_EXPLODE -> { - effectPacket.setType(LevelEventType.PARTICLE_EYE_OF_ENDER_DEATH); // TODO - - DragonFireballEventData fireballEventData = (DragonFireballEventData) packet.getData(); - if (fireballEventData == DragonFireballEventData.HAS_SOUND) { - LevelSoundEventPacket soundEventPacket = new LevelSoundEventPacket(); - soundEventPacket.setSound(SoundEvent.EXPLODE); - soundEventPacket.setPosition(pos); - soundEventPacket.setIdentifier(""); - soundEventPacket.setExtraData(-1); - soundEventPacket.setBabySound(false); - soundEventPacket.setRelativeVolumeDisabled(false); - session.sendUpstreamPacket(soundEventPacket); + case NORTH -> { + data = 1; + pos = pos.add(0, -0.2f, -0.7f); + } + case SOUTH -> { + data = 7; + pos = pos.add(0, -0.2f, 0.7f); + } + case WEST -> { + data = 3; + pos = pos.add(-0.7f, -0.2f, 0); + } + case EAST -> { + data = 5; + pos = pos.add(0.7f, -0.2f, 0); } } - case EXPLOSION -> { - effectPacket.setType(LevelEventType.PARTICLE_GENERIC_SPAWN); - effectPacket.setData(61); - } - case EVAPORATE -> { - effectPacket.setType(LevelEventType.PARTICLE_EVAPORATE_WATER); - effectPacket.setPosition(pos.add(-0.5f, 0.5f, -0.5f)); - } - case END_GATEWAY_SPAWN -> { - effectPacket.setType(LevelEventType.PARTICLE_EXPLOSION); + effectPacket.setPosition(pos); + effectPacket.setData(data); + } + //TODO: Block break particles when under fire + case BREAK_BLOCK -> { + effectPacket.setType(LevelEventType.PARTICLE_DESTROY_BLOCK); + + BreakBlockEventData breakBlockEventData = (BreakBlockEventData) packet.getData(); + effectPacket.setData(session.getBlockMappings().getBedrockBlockId(breakBlockEventData.getBlockState())); + } + case BREAK_SPLASH_POTION, BREAK_SPLASH_POTION2 -> { + effectPacket.setType(LevelEventType.PARTICLE_POTION_SPLASH); + effectPacket.setPosition(pos.add(0, -0.5f, 0)); + + BreakPotionEventData splashPotionData = (BreakPotionEventData) packet.getData(); + effectPacket.setData(splashPotionData.getPotionId()); + + LevelSoundEventPacket soundEventPacket = new LevelSoundEventPacket(); + soundEventPacket.setSound(SoundEvent.GLASS); + soundEventPacket.setPosition(pos); + soundEventPacket.setIdentifier(""); + soundEventPacket.setExtraData(-1); + soundEventPacket.setBabySound(false); + soundEventPacket.setRelativeVolumeDisabled(false); + session.sendUpstreamPacket(soundEventPacket); + } + case BREAK_EYE_OF_ENDER -> effectPacket.setType(LevelEventType.PARTICLE_EYE_OF_ENDER_DEATH); + case MOB_SPAWN -> effectPacket.setType(LevelEventType.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(packet.getEvent() == LevelEvent.BONEMEAL_GROW ? LevelEventType.PARTICLE_TURTLE_EGG : LevelEventType.PARTICLE_CROP_GROWTH); + + BonemealGrowEventData growEventData = (BonemealGrowEventData) packet.getData(); + effectPacket.setData(growEventData.getParticleCount()); + } + case ENDERDRAGON_FIREBALL_EXPLODE -> { + effectPacket.setType(LevelEventType.PARTICLE_EYE_OF_ENDER_DEATH); // TODO + + DragonFireballEventData fireballEventData = (DragonFireballEventData) packet.getData(); + if (fireballEventData == DragonFireballEventData.HAS_SOUND) { LevelSoundEventPacket soundEventPacket = new LevelSoundEventPacket(); soundEventPacket.setSound(SoundEvent.EXPLODE); soundEventPacket.setPosition(pos); @@ -253,17 +231,37 @@ public class JavaLevelEventTranslator extends PacketTranslator effectPacket.setType(LevelEventType.PARTICLE_DRIPSTONE_DRIP); - case ELECTRIC_SPARK -> effectPacket.setType(LevelEventType.PARTICLE_ELECTRIC_SPARK); // Matches with a Bedrock server but doesn't seem to match up with Java - case WAX_ON -> effectPacket.setType(LevelEventType.PARTICLE_WAX_ON); - case WAX_OFF -> effectPacket.setType(LevelEventType.PARTICLE_WAX_OFF); - case SCRAPE -> effectPacket.setType(LevelEventType.PARTICLE_SCRAPE); - default -> { - GeyserImpl.getInstance().getLogger().debug("Unhandled particle event: " + particleEvent.name()); - return; - } } - session.sendUpstreamPacket(effectPacket); + case EXPLOSION -> { + effectPacket.setType(LevelEventType.PARTICLE_GENERIC_SPAWN); + effectPacket.setData(61); + } + case EVAPORATE -> { + effectPacket.setType(LevelEventType.PARTICLE_EVAPORATE_WATER); + effectPacket.setPosition(pos.add(-0.5f, 0.5f, -0.5f)); + } + case END_GATEWAY_SPAWN -> { + effectPacket.setType(LevelEventType.PARTICLE_EXPLOSION); + + LevelSoundEventPacket soundEventPacket = new LevelSoundEventPacket(); + soundEventPacket.setSound(SoundEvent.EXPLODE); + soundEventPacket.setPosition(pos); + soundEventPacket.setIdentifier(""); + soundEventPacket.setExtraData(-1); + soundEventPacket.setBabySound(false); + soundEventPacket.setRelativeVolumeDisabled(false); + session.sendUpstreamPacket(soundEventPacket); + } + case DRIPSTONE_DRIP -> effectPacket.setType(LevelEventType.PARTICLE_DRIPSTONE_DRIP); + case ELECTRIC_SPARK -> effectPacket.setType(LevelEventType.PARTICLE_ELECTRIC_SPARK); // Matches with a Bedrock server but doesn't seem to match up with Java + case WAX_ON -> effectPacket.setType(LevelEventType.PARTICLE_WAX_ON); + case WAX_OFF -> effectPacket.setType(LevelEventType.PARTICLE_WAX_OFF); + case SCRAPE -> effectPacket.setType(LevelEventType.PARTICLE_SCRAPE); + default -> { + GeyserImpl.getInstance().getLogger().debug("Unhandled level event: " + packet.getEvent()); + return; + } } + session.sendUpstreamPacket(effectPacket); } } \ No newline at end of file From 3898e4f7e695e81b6c1064daf1844bed35849ef1 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Thu, 26 May 2022 20:02:02 -0400 Subject: [PATCH 32/72] add Swift Sneak enchantment to known enchantments --- .../org/geysermc/geyser/inventory/GeyserEnchantOption.java | 2 +- .../java/org/geysermc/geyser/inventory/item/Enchantment.java | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) 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 2bd4b6756..94462268e 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/GeyserEnchantOption.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/GeyserEnchantOption.java @@ -46,7 +46,7 @@ public class GeyserEnchantOption { */ 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", "oof ouch owie", "enemy on fire", "spider sad", "aj ferguson", "redned", + "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", 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 9872b9441..bcbfe3e17 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 @@ -67,7 +67,8 @@ public enum Enchantment { MULTISHOT, PIERCING, QUICK_CHARGE, - SOUL_SPEED; + SOUL_SPEED, + SWIFT_SNEAK; private static final Enchantment[] VALUES = values(); @@ -109,6 +110,7 @@ public enum Enchantment { FROST_WALKER, BINDING_CURSE, SOUL_SPEED, + SWIFT_SNEAK, SHARPNESS, SMITE, BANE_OF_ARTHROPODS, From 8e3119c8da9678452afef43536dd895b4190c7b8 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Thu, 26 May 2022 20:05:29 -0400 Subject: [PATCH 33/72] Update README for supported versions --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3e247f4b5..aba8babf2 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,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.18.0 - 1.18.31 and Minecraft Java 1.18.2. +### Currently supporting Minecraft Bedrock 1.19 and Minecraft Java 1.19.0. ## Setting Up Take a look [here](https://wiki.geysermc.org/geyser/setup/) for how to set up Geyser. From f079ee430bacac4ddd58d4c51efe8304feb8a8aa Mon Sep 17 00:00:00 2001 From: davchoo Date: Thu, 19 May 2022 19:06:03 -0400 Subject: [PATCH 34/72] Fix missing startup debug logs on Standalone --- .../geyser/platform/standalone/GeyserStandaloneBootstrap.java | 1 + core/src/main/java/org/geysermc/geyser/GeyserImpl.java | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) 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 7c49585d5..1e84e13d9 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 @@ -209,6 +209,7 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap { return; } } + geyserLogger.setDebug(geyserConfig.isDebugMode()); GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger); // Allow libraries like Protocol to have their debug information passthrough diff --git a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java index c84e62121..0cea9fbac 100644 --- a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java +++ b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java @@ -204,7 +204,6 @@ public class GeyserImpl implements GeyserApi { GeyserLogger logger = bootstrap.getGeyserLogger(); GeyserConfiguration config = bootstrap.getGeyserConfig(); - logger.setDebug(config.isDebugMode()); ScoreboardUpdater.init(); From 528e8d6f671796d6febc91a6455bef64c2945f0f Mon Sep 17 00:00:00 2001 From: davchoo Date: Fri, 27 May 2022 11:54:38 -0400 Subject: [PATCH 35/72] Add effects for sculk shrieker and sculk catalyst. Translate vibration particle Bumps NBT version to 2.2.1 for LevelEventGenericPacket --- core/pom.xml | 2 +- .../java/level/JavaLevelEventTranslator.java | 80 ++++++++++++++++++- .../level/JavaLevelParticlesTranslator.java | 47 +++++++++++ .../java/level/JavaSoundTranslator.java | 3 - core/src/main/resources/mappings | 2 +- 5 files changed, 126 insertions(+), 8 deletions(-) diff --git a/core/pom.xml b/core/pom.xml index 2d06c6bff..038f9ec8d 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -72,7 +72,7 @@ com.nukkitx nbt - 2.1.0 + 2.2.1 compile 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 195835a15..8fcfa381f 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,15 +25,15 @@ 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 com.nukkitx.math.vector.Vector3f; import com.nukkitx.math.vector.Vector3i; +import com.nukkitx.nbt.NbtMap; import com.nukkitx.protocol.bedrock.data.LevelEventType; import com.nukkitx.protocol.bedrock.data.SoundEvent; -import com.nukkitx.protocol.bedrock.packet.LevelEventPacket; -import com.nukkitx.protocol.bedrock.packet.LevelSoundEventPacket; -import com.nukkitx.protocol.bedrock.packet.TextPacket; +import com.nukkitx.protocol.bedrock.packet.*; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.session.GeyserSession; @@ -44,6 +44,7 @@ import org.geysermc.geyser.translator.protocol.Translator; import java.util.Collections; import java.util.Locale; +import java.util.Set; @Translator(packet = ClientboundLevelEventPacket.class) public class JavaLevelEventTranslator extends PacketTranslator { @@ -257,6 +258,56 @@ public class JavaLevelEventTranslator extends PacketTranslator effectPacket.setType(LevelEventType.PARTICLE_WAX_ON); case WAX_OFF -> effectPacket.setType(LevelEventType.PARTICLE_WAX_OFF); case SCRAPE -> effectPacket.setType(LevelEventType.PARTICLE_SCRAPE); + case SCULK_BLOCK_CHARGE -> { + SculkBlockChargeEventData eventData = (SculkBlockChargeEventData) packet.getData(); + LevelEventGenericPacket levelEventPacket = new LevelEventGenericPacket(); + // TODO add SCULK_BLOCK_CHARGE sound + if (eventData.getCharge() > 0) { + levelEventPacket.setEventId(2037); + 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() + ); + } else { + levelEventPacket.setEventId(2038); + levelEventPacket.setTag( + NbtMap.builder() + .putInt("x", packet.getPosition().getX()) + .putInt("y", packet.getPosition().getY()) + .putInt("z", packet.getPosition().getZ()) + .build() + ); + } + session.sendUpstreamPacket(levelEventPacket); + return; + } + case SCULK_SHRIEKER_SHRIEK -> { + LevelEventGenericPacket levelEventPacket = new LevelEventGenericPacket(); + levelEventPacket.setEventId(2035); + levelEventPacket.setTag( + NbtMap.builder() + .putInt("originX", packet.getPosition().getX()) + .putInt("originY", packet.getPosition().getY()) + .putInt("originZ", packet.getPosition().getZ()) + .build() + ); + session.sendUpstreamPacket(levelEventPacket); + + LevelSoundEventPacket soundEventPacket = new LevelSoundEventPacket(); + soundEventPacket.setSound(SoundEvent.SCULK_SHRIEKER_SHRIEK); + soundEventPacket.setPosition(packet.getPosition().toFloat()); + soundEventPacket.setExtraData(-1); + soundEventPacket.setIdentifier(""); + soundEventPacket.setBabySound(false); + soundEventPacket.setRelativeVolumeDisabled(false); + session.sendUpstreamPacket(soundEventPacket); + return; + } default -> { GeyserImpl.getInstance().getLogger().debug("Unhandled level event: " + packet.getEvent()); return; @@ -264,4 +315,27 @@ public class JavaLevelEventTranslator extends PacketTranslator blockFaces) { + short facing = 0; + if (blockFaces.contains(Direction.DOWN)) { + facing |= 1; + } + if (blockFaces.contains(Direction.UP)) { + facing |= 1 << 1; + } + if (blockFaces.contains(Direction.SOUTH)) { + facing |= 1 << 2; + } + if (blockFaces.contains(Direction.WEST)) { + facing |= 1 << 3; + } + if (blockFaces.contains(Direction.NORTH)) { + facing |= 1 << 4; + } + if (blockFaces.contains(Direction.EAST)) { + facing |= 1 << 5; + } + return facing; + } } \ No newline at end of file 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 de586b600..a413421a3 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 @@ -27,13 +27,18 @@ 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.level.particle.*; +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 com.nukkitx.math.vector.Vector3f; +import com.nukkitx.nbt.NbtMap; import com.nukkitx.protocol.bedrock.BedrockPacket; import com.nukkitx.protocol.bedrock.data.LevelEventType; import com.nukkitx.protocol.bedrock.data.inventory.ItemData; +import com.nukkitx.protocol.bedrock.packet.LevelEventGenericPacket; import com.nukkitx.protocol.bedrock.packet.LevelEventPacket; import com.nukkitx.protocol.bedrock.packet.SpawnParticleEffectPacket; +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; @@ -131,6 +136,39 @@ public class JavaLevelParticlesTranslator extends PacketTranslator { + VibrationParticleData data = (VibrationParticleData) particle.getData(); + + Vector3f target; + if (data.getPositionSource() instanceof BlockPositionSource blockPositionSource) { + target = blockPositionSource.getPosition().toFloat().add(0.5f, 0.5f, 0.5f); + } else if (data.getPositionSource() instanceof EntityPositionSource entityPositionSource) { + Entity entity = session.getEntityCache().getEntityByJavaId(entityPositionSource.getEntityId()); + if (entity != null) { + target = entity.getPosition().up(entityPositionSource.getYOffset()); + } else { + session.getGeyser().getLogger().debug("Unable to find entity with Java Id: " + entityPositionSource.getEntityId() + " for vibration particle."); + return null; + } + } else { + session.getGeyser().getLogger().debug("Unknown position source " + data.getPositionSource() + " for vibration particle."); + return null; + } + + return (position) -> { + LevelEventGenericPacket packet = new LevelEventGenericPacket(); + packet.setEventId(2027); + packet.setTag( + NbtMap.builder() + .putCompound("origin", buildVec3PositionTag(position)) + .putCompound("target", buildVec3PositionTag(target)) // There is a way to target an entity but that takes an attachPos instead of a y offset + .putFloat("speed", 20f) + .putFloat("timeToLive", data.getArrivalTicks() / 20f) + .build() + ); + return packet; + }; + } default -> { ParticleMapping particleMapping = Registries.PARTICLES.get(particle.getType()); if (particleMapping == null) { //TODO ensure no particle can be null @@ -160,4 +198,13 @@ public class JavaLevelParticlesTranslator extends PacketTranslator Date: Fri, 27 May 2022 13:27:10 -0400 Subject: [PATCH 36/72] Map Darkness status effect --- core/src/main/java/org/geysermc/geyser/util/EntityUtils.java | 1 + 1 file changed, 1 insertion(+) 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 cde39b2db..43ccff5e0 100644 --- a/core/src/main/java/org/geysermc/geyser/util/EntityUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/EntityUtils.java @@ -73,6 +73,7 @@ public final class EntityUtils { case SLOW_FALLING -> 27; case BAD_OMEN -> 28; case HERO_OF_THE_VILLAGE -> 29; + case DARKNESS -> 30; default -> effect.ordinal() + 1; }; } From 7b9a98aa09461ce48f8147bc58b1b915b7023d92 Mon Sep 17 00:00:00 2001 From: davchoo Date: Fri, 27 May 2022 13:59:37 -0400 Subject: [PATCH 37/72] Add croaking and using tongue poses to frog --- .../geysermc/geyser/entity/type/living/animal/FrogEntity.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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 e4bd8c5ce..2c1c884fb 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 @@ -47,7 +47,9 @@ public class FrogEntity extends AnimalEntity { @Override public void setPose(Pose pose) { setFlag(EntityFlag.JUMP_GOAL_JUMP, pose == Pose.LONG_JUMPING); - //TODO croaking and tongue using + setFlag(EntityFlag.CROAKING, pose == Pose.CROAKING); + setFlag(EntityFlag.EAT_MOB, pose == Pose.USING_TONGUE); + super.setPose(pose); } From 87320f0a78ec6c70b498fe899b87143f218c44d7 Mon Sep 17 00:00:00 2001 From: davchoo Date: Fri, 27 May 2022 19:03:12 -0400 Subject: [PATCH 38/72] Fix player head yaw for moveAbsolute teleport Fixes SkullPlayerEntity rotation Remove redundant? overrides --- .../entity/type/player/PlayerEntity.java | 52 +++---------------- 1 file changed, 7 insertions(+), 45 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 8bb47db81..6f2958ffd 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 @@ -168,6 +168,12 @@ public class PlayerEntity extends LivingEntity { } session.sendUpstreamPacket(movePlayerPacket); + + if (teleported) { + // As of 1.19.0, head yaw seems to be ignored during teleports. + updateHeadLookRotation(headYaw); + } + if (leftParrot != null) { leftParrot.moveAbsolute(position, yaw, pitch, headYaw, true, teleported); } @@ -210,52 +216,8 @@ public class PlayerEntity extends LivingEntity { } } - @Override - public void updateHeadLookRotation(float headYaw) { - moveRelative(0, 0, 0, getYaw(), getPitch(), headYaw, isOnGround()); - MovePlayerPacket movePlayerPacket = new MovePlayerPacket(); - movePlayerPacket.setRuntimeEntityId(geyserId); - movePlayerPacket.setPosition(position); - movePlayerPacket.setRotation(getBedrockRotation()); - movePlayerPacket.setMode(MovePlayerPacket.Mode.HEAD_ROTATION); - session.sendUpstreamPacket(movePlayerPacket); - } - - @Override - public void updatePositionAndRotation(double moveX, double moveY, double moveZ, float yaw, float pitch, boolean isOnGround) { - moveRelative(moveX, moveY, moveZ, yaw, pitch, isOnGround); - if (leftParrot != null) { - leftParrot.moveRelative(moveX, moveY, moveZ, yaw, pitch, isOnGround); - } - if (rightParrot != null) { - rightParrot.moveRelative(moveX, moveY, moveZ, yaw, pitch, isOnGround); - } - } - public void updateRotation(float yaw, float pitch, float headYaw, boolean isOnGround) { - // the method below is called by super.updateRotation(yaw, pitch, isOnGround). - // but we have to be able to set the headYaw, so we call the method below directly. - super.moveRelative(0, 0, 0, yaw, pitch, headYaw, isOnGround); - - // Both packets need to be sent or else player head rotation isn't correctly updated - MovePlayerPacket movePlayerPacket = new MovePlayerPacket(); - movePlayerPacket.setRuntimeEntityId(geyserId); - movePlayerPacket.setPosition(position); - movePlayerPacket.setRotation(getBedrockRotation()); - movePlayerPacket.setOnGround(isOnGround); - movePlayerPacket.setMode(MovePlayerPacket.Mode.HEAD_ROTATION); - session.sendUpstreamPacket(movePlayerPacket); - if (leftParrot != null) { - leftParrot.updateRotation(yaw, pitch, isOnGround); - } - if (rightParrot != null) { - rightParrot.updateRotation(yaw, pitch, isOnGround); - } - } - - @Override - public void updateRotation(float yaw, float pitch, boolean isOnGround) { - updateRotation(yaw, pitch, getHeadYaw(), isOnGround); + moveRelative(0, 0, 0, yaw, pitch, headYaw, isOnGround); } @Override From b10ce16506372f611ab7d42478a611a15da9f140 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Fri, 27 May 2022 22:44:03 -0400 Subject: [PATCH 39/72] The wild update experiment is no longer necessary --- .../java/org/geysermc/geyser/network/UpstreamPacketHandler.java | 1 - .../main/java/org/geysermc/geyser/session/GeyserSession.java | 2 -- 2 files changed, 3 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 07fa19bee..5ae6fbca9 100644 --- a/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java +++ b/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java @@ -164,7 +164,6 @@ public class UpstreamPacketHandler extends LoggingPacketHandler { // Allow custom items to work stackPacket.getExperiments().add(new ExperimentData("data_driven_items", true)); } - stackPacket.getExperiments().add(new ExperimentData("wild_update", 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 e4d7fab35..c5f81127e 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -1465,8 +1465,6 @@ public class GeyserSession implements GeyserConnection, CommandSender { startGamePacket.setPlayerPropertyData(NbtMap.EMPTY); startGamePacket.setWorldTemplateId(UUID.randomUUID()); - startGamePacket.getExperiments().add(new ExperimentData("wild_update", true)); - SyncedPlayerMovementSettings settings = new SyncedPlayerMovementSettings(); settings.setMovementMode(AuthoritativeMovementMode.CLIENT); settings.setRewindHistorySize(0); From 84bcadc68735fb3a762d6d029eb1029ab700e362 Mon Sep 17 00:00:00 2001 From: Tim203 Date: Sat, 28 May 2022 23:45:35 +0200 Subject: [PATCH 40/72] Converted the new forms --- ap/pom.xml | 4 +- api/base/pom.xml | 2 +- api/geyser/pom.xml | 4 +- api/pom.xml | 2 +- bootstrap/bungeecord/pom.xml | 4 +- bootstrap/pom.xml | 4 +- bootstrap/spigot/pom.xml | 4 +- bootstrap/sponge/pom.xml | 4 +- bootstrap/standalone/pom.xml | 4 +- bootstrap/velocity/pom.xml | 4 +- common/pom.xml | 4 +- core/pom.xml | 8 +- .../geyser/session/cache/FormCache.java | 22 ++--- .../geyser/util/LoginEncryptionUtils.java | 87 +++++++++++++------ pom.xml | 2 +- 15 files changed, 99 insertions(+), 60 deletions(-) diff --git a/ap/pom.xml b/ap/pom.xml index 0644044a1..b60f37558 100644 --- a/ap/pom.xml +++ b/ap/pom.xml @@ -6,9 +6,9 @@ org.geysermc geyser-parent - 2.0.3-SNAPSHOT + 2.0.3-cumulus-SNAPSHOT ap - 2.0.3-SNAPSHOT + 2.0.3-cumulus-SNAPSHOT \ No newline at end of file diff --git a/api/base/pom.xml b/api/base/pom.xml index 1d051eaa3..4d4d12d90 100644 --- a/api/base/pom.xml +++ b/api/base/pom.xml @@ -5,7 +5,7 @@ org.geysermc api-parent - 2.0.3-SNAPSHOT + 2.0.3-cumulus-SNAPSHOT 4.0.0 diff --git a/api/geyser/pom.xml b/api/geyser/pom.xml index 2a933a2e0..9b67bea9e 100644 --- a/api/geyser/pom.xml +++ b/api/geyser/pom.xml @@ -5,7 +5,7 @@ org.geysermc api-parent - 2.0.3-SNAPSHOT + 2.0.3-cumulus-SNAPSHOT 4.0.0 @@ -26,7 +26,7 @@ org.geysermc base-api - 2.0.3-SNAPSHOT + 2.0.3-cumulus-SNAPSHOT compile diff --git a/api/pom.xml b/api/pom.xml index 5d078fba5..2ff8b4906 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -6,7 +6,7 @@ org.geysermc geyser-parent - 2.0.3-SNAPSHOT + 2.0.3-cumulus-SNAPSHOT api-parent diff --git a/bootstrap/bungeecord/pom.xml b/bootstrap/bungeecord/pom.xml index b2c661447..0c04f139e 100644 --- a/bootstrap/bungeecord/pom.xml +++ b/bootstrap/bungeecord/pom.xml @@ -6,7 +6,7 @@ org.geysermc bootstrap-parent - 2.0.3-SNAPSHOT + 2.0.3-cumulus-SNAPSHOT bootstrap-bungeecord @@ -14,7 +14,7 @@ org.geysermc core - 2.0.3-SNAPSHOT + 2.0.3-cumulus-SNAPSHOT compile diff --git a/bootstrap/pom.xml b/bootstrap/pom.xml index 7d6ac8f98..7c5ac68a1 100644 --- a/bootstrap/pom.xml +++ b/bootstrap/pom.xml @@ -6,7 +6,7 @@ org.geysermc geyser-parent - 2.0.3-SNAPSHOT + 2.0.3-cumulus-SNAPSHOT bootstrap-parent pom @@ -34,7 +34,7 @@ org.geysermc ap - 2.0.3-SNAPSHOT + 2.0.3-cumulus-SNAPSHOT provided diff --git a/bootstrap/spigot/pom.xml b/bootstrap/spigot/pom.xml index e9e7687f4..1f08bf146 100644 --- a/bootstrap/spigot/pom.xml +++ b/bootstrap/spigot/pom.xml @@ -6,7 +6,7 @@ org.geysermc bootstrap-parent - 2.0.3-SNAPSHOT + 2.0.3-cumulus-SNAPSHOT bootstrap-spigot @@ -30,7 +30,7 @@ org.geysermc core - 2.0.3-SNAPSHOT + 2.0.3-cumulus-SNAPSHOT compile diff --git a/bootstrap/sponge/pom.xml b/bootstrap/sponge/pom.xml index 8eba4d73d..96013e69a 100644 --- a/bootstrap/sponge/pom.xml +++ b/bootstrap/sponge/pom.xml @@ -6,7 +6,7 @@ org.geysermc bootstrap-parent - 2.0.3-SNAPSHOT + 2.0.3-cumulus-SNAPSHOT bootstrap-sponge @@ -14,7 +14,7 @@ org.geysermc core - 2.0.3-SNAPSHOT + 2.0.3-cumulus-SNAPSHOT compile diff --git a/bootstrap/standalone/pom.xml b/bootstrap/standalone/pom.xml index 8ee94b793..b3b32cc87 100644 --- a/bootstrap/standalone/pom.xml +++ b/bootstrap/standalone/pom.xml @@ -6,7 +6,7 @@ org.geysermc bootstrap-parent - 2.0.3-SNAPSHOT + 2.0.3-cumulus-SNAPSHOT bootstrap-standalone @@ -18,7 +18,7 @@ org.geysermc core - 2.0.3-SNAPSHOT + 2.0.3-cumulus-SNAPSHOT compile diff --git a/bootstrap/velocity/pom.xml b/bootstrap/velocity/pom.xml index 36882a19e..d81994522 100644 --- a/bootstrap/velocity/pom.xml +++ b/bootstrap/velocity/pom.xml @@ -6,7 +6,7 @@ org.geysermc bootstrap-parent - 2.0.3-SNAPSHOT + 2.0.3-cumulus-SNAPSHOT bootstrap-velocity @@ -14,7 +14,7 @@ org.geysermc core - 2.0.3-SNAPSHOT + 2.0.3-cumulus-SNAPSHOT compile diff --git a/common/pom.xml b/common/pom.xml index 0786f3f4d..fc00d4031 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -6,7 +6,7 @@ org.geysermc geyser-parent - 2.0.3-SNAPSHOT + 2.0.3-cumulus-SNAPSHOT common @@ -20,7 +20,7 @@ org.geysermc.cumulus cumulus - 1.0-SNAPSHOT + 1.1-SNAPSHOT com.google.code.gson diff --git a/core/pom.xml b/core/pom.xml index 8af2aa907..6334615d3 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -6,7 +6,7 @@ org.geysermc geyser-parent - 2.0.3-SNAPSHOT + 2.0.3-cumulus-SNAPSHOT core @@ -21,19 +21,19 @@ org.geysermc ap - 2.0.3-SNAPSHOT + 2.0.3-cumulus-SNAPSHOT provided org.geysermc geyser-api - 2.0.3-SNAPSHOT + 2.0.3-cumulus-SNAPSHOT compile org.geysermc common - 2.0.3-SNAPSHOT + 2.0.3-cumulus-SNAPSHOT compile diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/FormCache.java b/core/src/main/java/org/geysermc/geyser/session/cache/FormCache.java index d44f1a9d1..24acebce0 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/FormCache.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/FormCache.java @@ -43,29 +43,29 @@ import java.util.concurrent.atomic.AtomicInteger; @RequiredArgsConstructor public class FormCache { private final FormDefinitions formDefinitions = FormDefinitions.instance(); - private final AtomicInteger formId = new AtomicInteger(0); + private final AtomicInteger formIdCounter = new AtomicInteger(0); private final Int2ObjectMap forms = new Int2ObjectOpenHashMap<>(); private final GeyserSession session; public int addForm(Form form) { - int windowId = formId.getAndIncrement(); - forms.put(windowId, form); - return windowId; + int formId = formIdCounter.getAndIncrement(); + forms.put(formId, form); + return formId; } public void showForm(Form form) { - int windowId = addForm(form); + int formId = addForm(form); if (session.getUpstream().isInitialized()) { - sendForm(windowId, form); + sendForm(formId, form); } } - private void sendForm(int windowId, Form form) { + private void sendForm(int formId, Form form) { String jsonData = formDefinitions.codecFor(form).jsonData(form); ModalFormRequestPacket formRequestPacket = new ModalFormRequestPacket(); - formRequestPacket.setFormId(windowId); + formRequestPacket.setFormId(formId); formRequestPacket.setFormData(jsonData); session.sendUpstreamPacket(formRequestPacket); @@ -74,8 +74,10 @@ public class FormCache { NetworkStackLatencyPacket latencyPacket = new NetworkStackLatencyPacket(); latencyPacket.setFromServer(true); latencyPacket.setTimestamp(-System.currentTimeMillis()); - session.scheduleInEventLoop(() -> session.sendUpstreamPacket(latencyPacket), - 500, TimeUnit.MILLISECONDS); + session.scheduleInEventLoop( + () -> session.sendUpstreamPacket(latencyPacket), + 500, TimeUnit.MILLISECONDS + ); } } 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 0d369ac19..0d60ad457 100644 --- a/core/src/main/java/org/geysermc/geyser/util/LoginEncryptionUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/LoginEncryptionUtils.java @@ -40,7 +40,10 @@ import com.nukkitx.protocol.bedrock.util.EncryptionUtils; import org.geysermc.cumulus.form.CustomForm; import org.geysermc.cumulus.form.ModalForm; import org.geysermc.cumulus.form.SimpleForm; +import org.geysermc.cumulus.response.SimpleFormResponse; +import org.geysermc.cumulus.response.result.FormResponseResult; import org.geysermc.cumulus.response.result.ResultType; +import org.geysermc.cumulus.response.result.ValidFormResponseResult; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.configuration.GeyserConfiguration; import org.geysermc.geyser.session.GeyserSession; @@ -59,6 +62,7 @@ import java.security.interfaces.ECPublicKey; import java.security.spec.ECGenParameterSpec; import java.util.Iterator; import java.util.UUID; +import java.util.function.BiConsumer; public class LoginEncryptionUtils { private static final ObjectMapper JSON_MAPPER = new ObjectMapper().disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); @@ -264,42 +268,49 @@ public class LoginEncryptionUtils { * Build a window that explains the user's credentials will be saved to the system. */ public static void buildAndShowConsentWindow(GeyserSession session) { - String locale = session.getLocale(); session.sendForm( SimpleForm.builder() + .translator(LoginEncryptionUtils::translate, session.getLocale()) .title("%gui.signIn") - .content(GeyserLocale.getPlayerLocaleString("geyser.auth.login.save_token.warning", locale) + - "\n\n" + - GeyserLocale.getPlayerLocaleString("geyser.auth.login.save_token.proceed", locale)) + .content(""" + geyser.auth.login.save_token.warning + + geyser.auth.login.save_token.proceed""") .button("%gui.ok") .button("%gui.decline") - .responseHandler((form, responseData) -> { - SimpleFormResponse response = form.parseResponse(responseData); - if (response.isCorrect() && response.getClickedButtonId() == 0) { - session.authenticateWithMicrosoftCode(true); - } else { - session.disconnect("%disconnect.quitting"); - } - })); + .resultHandler( + authenticateOrKickHandler(session), + ResultType.CLOSED, ResultType.INVALID, ResultType.VALID + ) + ); } public static void buildAndShowTokenExpiredWindow(GeyserSession session) { - String locale = session.getLocale(); session.sendForm( SimpleForm.builder() - .title(GeyserLocale.getPlayerLocaleString("geyser.auth.login.form.expired", locale)) - .content(GeyserLocale.getPlayerLocaleString("geyser.auth.login.save_token.expired", locale) + - "\n\n" + - GeyserLocale.getPlayerLocaleString("geyser.auth.login.save_token.proceed", locale)) + .translator(LoginEncryptionUtils::translate, session.getLocale()) + .title("geyser.auth.login.form.expired") + .content(""" + geyser.auth.login.save_token.expired + + geyser.auth.login.save_token.proceed""") .button("%gui.ok") - .responseHandler((form, responseData) -> { - SimpleFormResponse response = form.parseResponse(responseData); - if (response.isCorrect()) { - session.authenticateWithMicrosoftCode(true); - } else { - session.disconnect("%disconnect.quitting"); - } - })); + .resultHandler( + authenticateOrKickHandler(session), + ResultType.CLOSED, ResultType.INVALID, ResultType.VALID + ) + ); + } + + private static BiConsumer> authenticateOrKickHandler(GeyserSession session) { + return (form, genericResult) -> { + if (genericResult instanceof ValidFormResponseResult result && + result.response().clickedButtonId() == 0) { + session.authenticateWithMicrosoftCode(true); + } else { + session.disconnect("%disconnect.quitting"); + } + }; } public static void buildAndShowLoginDetailsWindow(GeyserSession session) { @@ -378,4 +389,30 @@ public class LoginEncryptionUtils { }) ); } + + /* + This checks per line if there is something to be translated, and it skips Bedrock translation keys (%) + */ + private static String translate(String key, String locale) { + StringBuilder newValue = new StringBuilder(); + int previousIndex = 0; + while (previousIndex < key.length()) { + int nextIndex = key.indexOf('\n', previousIndex); + int endIndex = nextIndex == -1 ? key.length() : nextIndex; + + // if there is more to this line than just a new line char + if (endIndex - previousIndex > 1) { + String substring = key.substring(previousIndex, endIndex); + if (key.charAt(previousIndex) != '%') { + newValue.append(GeyserLocale.getPlayerLocaleString(substring, locale)); + } else { + newValue.append(substring); + } + } + newValue.append('\n'); + + previousIndex = endIndex + 1; + } + return newValue.toString(); + } } diff --git a/pom.xml b/pom.xml index f4930959d..f0b8f21ab 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ 4.0.0 org.geysermc geyser-parent - 2.0.3-SNAPSHOT + 2.0.3-cumulus-SNAPSHOT pom Geyser Allows for players from Minecraft Bedrock Edition to join Minecraft Java Edition servers. From cbba0d3a7500fdabda8e11a33153c8a52b179359 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sun, 29 May 2022 11:59:32 -0400 Subject: [PATCH 41/72] Update biome mappings --- .../resources/bedrock/biome_definitions.dat | Bin 41668 -> 42385 bytes core/src/main/resources/mappings | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/bedrock/biome_definitions.dat b/core/src/main/resources/bedrock/biome_definitions.dat index 1bd332601f39d973b89e009e17a3f4f9bd4ba3c5..0520c61e28fdd87c24bfdfc25fa30f3f52b70eee 100644 GIT binary patch delta 200 zcmX?dlxgB=rVVb=T%0MXsRi*ViAC9yKZ$&!2h2*KEi#);d;3KJtiwz! delta 60 zcmbPun(4? Date: Sun, 29 May 2022 23:39:40 +0200 Subject: [PATCH 42/72] Use new Cumulus methods --- .../geyser/session/GeyserSession.java | 2 +- .../session/cache/AdvancementsCache.java | 8 +-- .../java/JavaCustomPayloadTranslator.java | 2 +- .../geyser/util/LoginEncryptionUtils.java | 58 ++++++------------- .../geysermc/geyser/util/SettingsUtils.java | 2 +- .../geysermc/geyser/util/StatisticsUtils.java | 4 +- 6 files changed, 28 insertions(+), 48 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 91475fb56..df400d4e9 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -84,7 +84,7 @@ import lombok.Setter; import org.checkerframework.common.value.qual.IntRange; import org.geysermc.common.PlatformType; import org.geysermc.cumulus.form.Form; -import org.geysermc.cumulus.util.FormBuilder; +import org.geysermc.cumulus.form.util.FormBuilder; import org.geysermc.floodgate.crypto.FloodgateCipher; import org.geysermc.floodgate.util.BedrockData; import org.geysermc.geyser.Constants; 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 d1127b0fa..d100f61cb 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 @@ -87,7 +87,7 @@ public class AdvancementsCache { builder.content("advancements.empty"); } - builder.validResultHandler((form, response) -> { + builder.validResultHandler((response) -> { String id = ""; int advancementIndex = 0; @@ -143,11 +143,11 @@ public class AdvancementsCache { builder.button(GeyserLocale.getPlayerLocaleString("gui.back", language)); - builder.closedResultHandler(form -> { + builder.closedResultHandler(() -> { // Indicate that we have closed the current advancement tab session.sendDownstreamPacket(new ServerboundSeenAdvancementsPacket()); - }).validResultHandler((form, response) -> { + }).validResultHandler((response) -> { GeyserAdvancement advancement = null; int advancementIndex = 0; // Loop around to find the advancement that the client pressed @@ -211,7 +211,7 @@ public class AdvancementsCache { .title(MessageTranslator.convertMessage(advancement.getDisplayData().getTitle())) .content(content) .button(GeyserLocale.getPlayerLocaleString("gui.back", language)) - .validResultHandler((form, response) -> buildAndShowListForm()) + .validResultHandler((response) -> buildAndShowListForm()) ); } 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 5696837be..76af190d0 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 @@ -31,7 +31,7 @@ import com.google.common.base.Charsets; import com.nukkitx.protocol.bedrock.packet.TransferPacket; import org.geysermc.cumulus.Forms; import org.geysermc.cumulus.form.Form; -import org.geysermc.cumulus.util.FormType; +import org.geysermc.cumulus.form.util.FormType; import org.geysermc.floodgate.pluginmessage.PluginMessageChannels; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserLogger; 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 0d60ad457..ea1ff770a 100644 --- a/core/src/main/java/org/geysermc/geyser/util/LoginEncryptionUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/LoginEncryptionUtils.java @@ -42,7 +42,6 @@ import org.geysermc.cumulus.form.ModalForm; import org.geysermc.cumulus.form.SimpleForm; import org.geysermc.cumulus.response.SimpleFormResponse; import org.geysermc.cumulus.response.result.FormResponseResult; -import org.geysermc.cumulus.response.result.ResultType; import org.geysermc.cumulus.response.result.ValidFormResponseResult; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.configuration.GeyserConfiguration; @@ -237,26 +236,22 @@ public class LoginEncryptionUtils { .optionalButton("geyser.auth.login.form.notice.btn_login.mojang", isPasswordAuthEnabled) .button("geyser.auth.login.form.notice.btn_login.microsoft") .button("geyser.auth.login.form.notice.btn_disconnect") - .resultHandler( - (form, result) -> buildAndShowLoginWindow(session), - ResultType.CLOSED, ResultType.INVALID - ) - .validResultHandler((form, response) -> { - if (isPasswordAuthEnabled && response.clickedButtonId() == 0) { + .closedOrInvalidResultHandler(() -> buildAndShowLoginWindow(session)) + .validResultHandler((response) -> { + if (response.clickedButtonId() == 0) { session.setMicrosoftAccount(false); buildAndShowLoginDetailsWindow(session); return; } - if (isPasswordAuthEnabled && response.clickedButtonId() == 1) { - session.setMicrosoftAccount(true); - buildAndShowMicrosoftAuthenticationWindow(session); - return; - } - - if (response.clickedButtonId() == 0) { - // Just show the OAuth code - session.authenticateWithMicrosoftCode(); + if (response.clickedButtonId() == 1) { + if (isPasswordAuthEnabled) { + session.setMicrosoftAccount(true); + buildAndShowMicrosoftAuthenticationWindow(session); + } else { + // Just show the OAuth code + session.authenticateWithMicrosoftCode(); + } return; } @@ -278,10 +273,7 @@ public class LoginEncryptionUtils { geyser.auth.login.save_token.proceed""") .button("%gui.ok") .button("%gui.decline") - .resultHandler( - authenticateOrKickHandler(session), - ResultType.CLOSED, ResultType.INVALID, ResultType.VALID - ) + .resultHandler(authenticateOrKickHandler(session)) ); } @@ -295,10 +287,7 @@ public class LoginEncryptionUtils { geyser.auth.login.save_token.proceed""") .button("%gui.ok") - .resultHandler( - authenticateOrKickHandler(session), - ResultType.CLOSED, ResultType.INVALID, ResultType.VALID - ) + .resultHandler(authenticateOrKickHandler(session)) ); } @@ -321,11 +310,8 @@ public class LoginEncryptionUtils { .label("geyser.auth.login.form.details.desc") .input("geyser.auth.login.form.details.email", "account@geysermc.org", "") .input("geyser.auth.login.form.details.pass", "123456", "") - .resultHandler( - (form, result) -> buildAndShowLoginDetailsWindow(session), - ResultType.CLOSED, ResultType.INVALID - ) - .validResultHandler((form, response) -> session.authenticate(response.next(), response.next()))); + .closedOrInvalidResultHandler(() -> buildAndShowLoginDetailsWindow(session)) + .validResultHandler((response) -> session.authenticate(response.next(), response.next()))); } /** @@ -339,11 +325,8 @@ public class LoginEncryptionUtils { .button("geyser.auth.login.method.browser") .button("geyser.auth.login.method.password") .button("geyser.auth.login.form.notice.btn_disconnect") - .resultHandler( - (form, result) -> buildAndShowLoginWindow(session), - ResultType.CLOSED, ResultType.INVALID - ) - .validResultHandler((form, response) -> { + .closedOrInvalidResultHandler(() -> buildAndShowLoginWindow(session)) + .validResultHandler((response) -> { if (response.clickedButtonId() == 0) { session.authenticateWithMicrosoftCode(); } else if (response.clickedButtonId() == 1) { @@ -378,11 +361,8 @@ public class LoginEncryptionUtils { .content(message.toString()) .button1("%gui.done") .button2("%menu.disconnect") - .resultHandler( - (form, result) -> buildAndShowMicrosoftAuthenticationWindow(session), - ResultType.CLOSED, ResultType.INVALID - ) - .validResultHandler((form, response) -> { + .closedOrInvalidResultHandler(() -> buildAndShowMicrosoftAuthenticationWindow(session)) + .validResultHandler((response) -> { if (response.clickedButtonId() == 1) { session.disconnect(GeyserLocale.getPlayerLocaleString("geyser.auth.login.form.disconnect", session.getLocale())); } 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 cdb672100..10c4b863c 100644 --- a/core/src/main/java/org/geysermc/geyser/util/SettingsUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/SettingsUtils.java @@ -114,7 +114,7 @@ public class SettingsUtils { } } - builder.validResultHandler((form, response) -> { + builder.validResultHandler((response) -> { if (showClientSettings) { // Client can only see its coordinates if reducedDebugInfo is disabled and coordinates are enabled in geyser config. if (session.getPreferencesCache().isAllowShowCoordinates()) { 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 2eec54652..149656fd9 100644 --- a/core/src/main/java/org/geysermc/geyser/util/StatisticsUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/StatisticsUtils.java @@ -67,7 +67,7 @@ public class StatisticsUtils { .button("stat.itemsButton - stat_type.minecraft.dropped", FormImage.Type.PATH, "textures/ui/trash_default") .button("stat.mobsButton - geyser.statistics.killed", FormImage.Type.PATH, "textures/items/diamond_sword") .button("stat.mobsButton - geyser.statistics.killed_by", FormImage.Type.PATH, "textures/ui/wither_heart_flash") - .validResultHandler((form, response) -> { + .validResultHandler((response) -> { SimpleForm.Builder builder = SimpleForm.builder() .translator(StatisticsUtils::translate, language); @@ -196,7 +196,7 @@ public class StatisticsUtils { session.sendForm( builder.content(assembledContent.toString()) .button("gui.back", FormImage.Type.PATH, "textures/gui/newgui/undo") - .validResultHandler((form1, response1) -> buildAndSendStatisticsMenu(session))); + .validResultHandler((response1) -> buildAndSendStatisticsMenu(session))); })); } From f79a3ef2f788bb44ebf0d0acd9373440be6c23ba Mon Sep 17 00:00:00 2001 From: davchoo Date: Sun, 29 May 2022 18:56:54 -0400 Subject: [PATCH 43/72] Bump Protocol version to fix command suggestions Fix assert that occurs on Bedrock after typing / --- core/pom.xml | 2 +- .../protocol/java/JavaCommandsTranslator.java | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/core/pom.xml b/core/pom.xml index 038f9ec8d..39c874d35 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -121,7 +121,7 @@ com.github.CloudburstMC.Protocol bedrock-beta - 49323e0 + 51d4fce compile 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 115a44bdd..b6f7a2451 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 @@ -248,7 +248,7 @@ public class JavaCommandsTranslator extends PacketTranslator // So if paramNode.getName() == "value" and enumData.getName() == "bool": - children.add(new ParamInfo(paramNode, new CommandParamData(paramNode.getName(), this.paramNode.isExecutable(), enumData, type, null, Collections.emptyList()))); + children.add(new ParamInfo(paramNode, new CommandParamData(paramNode.getName(), optional, enumData, type, null, Collections.emptyList()))); } } From 7a0a6795d0933b35a91ea709c379f6cbef2b1367 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sun, 29 May 2022 20:31:54 -0400 Subject: [PATCH 44/72] Remove now-obsolete sign workaround. Yay. --- .../geysermc/geyser/session/GeyserSession.java | 9 --------- .../BedrockBlockEntityDataTranslator.java | 16 ++-------------- 2 files changed, 2 insertions(+), 23 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 c5f81127e..f60af61b3 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -492,15 +492,6 @@ public class GeyserSession implements GeyserConnection, CommandSender { @Setter private boolean thunder = false; - /** - * Stores the last text inputted into a sign. - *

- * Bedrock sends packets every time you update the sign, Java only wants the final packet. - * Until we determine that the user has finished editing, we save the sign's current status. - */ - @Setter - private String lastSignMessage; - /** * Stores a map of all statistics sent from the server. * The server only sends new statistics back to us, so in order to show all statistics we need to cache existing ones. 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 c759e0f3d..67f0d0d59 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 @@ -30,7 +30,6 @@ import com.github.steveice10.mc.protocol.packet.ingame.serverbound.level.Serverb import com.nukkitx.math.vector.Vector3i; import com.nukkitx.nbt.NbtMap; import com.nukkitx.protocol.bedrock.packet.BlockEntityDataPacket; -import com.nukkitx.protocol.bedrock.v503.Bedrock_v503; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; @@ -45,16 +44,8 @@ public class BedrockBlockEntityDataTranslator extends PacketTranslator Date: Sun, 29 May 2022 20:39:14 -0400 Subject: [PATCH 45/72] Remove obsolete chunk writing code --- .../JavaLevelChunkWithLightTranslator.java | 21 +++++++------------ 1 file changed, 7 insertions(+), 14 deletions(-) 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 47ba98274..8bc053207 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 @@ -43,7 +43,6 @@ import com.nukkitx.nbt.NbtMap; import com.nukkitx.nbt.NbtUtils; import com.nukkitx.network.VarInts; import com.nukkitx.protocol.bedrock.packet.LevelChunkPacket; -import com.nukkitx.protocol.bedrock.v503.Bedrock_v503; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufAllocator; import io.netty.buffer.ByteBufOutputStream; @@ -52,6 +51,7 @@ import it.unimi.dsi.fastutil.ints.IntList; import it.unimi.dsi.fastutil.ints.IntLists; import it.unimi.dsi.fastutil.objects.ObjectArrayList; 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.chunk.BlockStorage; import org.geysermc.geyser.level.chunk.GeyserChunkSection; @@ -60,7 +60,6 @@ import org.geysermc.geyser.level.chunk.bitarray.BitArrayVersion; import org.geysermc.geyser.level.chunk.bitarray.SingletonBitArray; import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.level.BedrockDimension; import org.geysermc.geyser.translator.level.BiomeTranslator; import org.geysermc.geyser.translator.level.block.entity.BedrockOnlyBlockEntity; import org.geysermc.geyser.translator.level.block.entity.BlockEntityTranslator; @@ -76,7 +75,8 @@ import java.util.BitSet; import java.util.List; import java.util.Map; -import static org.geysermc.geyser.util.ChunkUtils.*; +import static org.geysermc.geyser.util.ChunkUtils.SERIALIZED_CHUNK_DATA; +import static org.geysermc.geyser.util.ChunkUtils.indexYZXtoXZY; @Translator(packet = ClientboundLevelChunkWithLightPacket.class) public class JavaLevelChunkWithLightTranslator extends PacketTranslator { @@ -312,10 +312,8 @@ public class JavaLevelChunkWithLightTranslator extends PacketTranslator= Bedrock_v503.V503_CODEC.getProtocolVersion(); - int biomeCount = isNewVersion ? bedrockDimension.height() >> 4 : 25; + // As of 1.18.30, the amount of biomes read is dependent on how high Bedrock thinks the dimension is + int biomeCount = bedrockDimension.height() >> 4; int dimensionOffset = bedrockDimension.minY() >> 4; for (int i = 0; i < biomeCount; i++) { int biomeYOffset = dimensionOffset + i; @@ -326,13 +324,8 @@ public class JavaLevelChunkWithLightTranslator extends PacketTranslator= (chunkSize + yOffset)) { // This biome section goes above the height of the Java world - if (isNewVersion) { - // A header that says to carry on the biome data from the previous chunk - // This notably fixes biomes in the End - byteBuf.writeByte((127 << 1) | 1); - } else { - byteBuf.writeBytes(ChunkUtils.EMPTY_BIOME_DATA); - } + // The byte written here is a header that says to carry on the biome data from the previous chunk + byteBuf.writeByte((127 << 1) | 1); continue; } From a3cdfc5306dbbc941ea2a751482ce2776503737e Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sun, 29 May 2022 21:11:10 -0400 Subject: [PATCH 46/72] Use correct type for entity metadata --- .../src/main/java/org/geysermc/geyser/entity/type/Entity.java | 4 ++-- .../geyser/entity/type/living/animal/AxolotlEntity.java | 2 +- 2 files changed, 3 insertions(+), 3 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 4dc3a437a..52efcf67e 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 @@ -141,7 +141,7 @@ public class Entity { */ protected void initializeMetadata() { dirtyMetadata.put(EntityData.SCALE, 1f); - dirtyMetadata.put(EntityData.COLOR, 0); + dirtyMetadata.put(EntityData.COLOR, (byte) 0); dirtyMetadata.put(EntityData.MAX_AIR_SUPPLY, getMaxAir()); setDimensions(Pose.STANDING); setFlag(EntityFlag.HAS_GRAVITY, true); @@ -351,7 +351,7 @@ public class Entity { dirtyMetadata.put(EntityData.AIR_SUPPLY, (short) MathUtils.constrain(amount, 0, getMaxAir())); } - protected int getMaxAir() { + protected short getMaxAir() { return 300; } 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 446892016..ca7ee57a2 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 @@ -65,7 +65,7 @@ public class AxolotlEntity extends AnimalEntity { } @Override - protected int getMaxAir() { + protected short getMaxAir() { return 6000; } From 9133008e188da7b4f09c2a308251b9b54701dc3c Mon Sep 17 00:00:00 2001 From: davchoo Date: Mon, 30 May 2022 14:38:03 -0400 Subject: [PATCH 47/72] Translate ClientboundSoundEntityPacket Used by allay, frog, and a few other mobs. Move common code to SoundUtils Update mappings --- .../entity/JavaSoundEntityTranslator.java | 45 ++++++++ .../java/level/JavaCustomSoundTranslator.java | 30 +---- .../java/level/JavaSoundTranslator.java | 62 +--------- .../java/level/JavaStopSoundTranslator.java | 34 +----- .../org/geysermc/geyser/util/SoundUtils.java | 109 +++++++++++++++++- core/src/main/resources/mappings | 2 +- 6 files changed, 162 insertions(+), 120 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSoundEntityTranslator.java 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 new file mode 100644 index 000000000..11a047805 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSoundEntityTranslator.java @@ -0,0 +1,45 @@ +/* + * 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; + +import com.github.steveice10.mc.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; +import org.geysermc.geyser.translator.protocol.Translator; +import org.geysermc.geyser.util.SoundUtils; + +@Translator(packet = ClientboundSoundEntityPacket.class) +public class JavaSoundEntityTranslator extends PacketTranslator { + @Override + public void translate(GeyserSession session, ClientboundSoundEntityPacket packet) { + Entity entity = session.getEntityCache().getEntityByJavaId(packet.getEntityId()); + if (entity == null) { + return; + } + SoundUtils.playBuiltinSound(session, packet.getSound(), entity.getPosition(), packet.getPitch()); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaCustomSoundTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaCustomSoundTranslator.java index 63da6710c..00894bd8b 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaCustomSoundTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaCustomSoundTranslator.java @@ -25,45 +25,21 @@ package org.geysermc.geyser.translator.protocol.java.level; -import com.github.steveice10.mc.protocol.data.game.level.sound.BuiltinSound; -import com.github.steveice10.mc.protocol.data.game.level.sound.CustomSound; import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.ClientboundCustomSoundPacket; import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.packet.*; +import com.nukkitx.protocol.bedrock.packet.PlaySoundPacket; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; -import org.geysermc.geyser.registry.Registries; -import org.geysermc.geyser.registry.type.SoundMapping; +import org.geysermc.geyser.util.SoundUtils; @Translator(packet = ClientboundCustomSoundPacket.class) public class JavaCustomSoundTranslator extends PacketTranslator { @Override public void translate(GeyserSession session, ClientboundCustomSoundPacket packet) { - String packetSound; - if (packet.getSound() instanceof BuiltinSound) { - packetSound = ((BuiltinSound) packet.getSound()).getName(); - } else if (packet.getSound() instanceof CustomSound) { - packetSound = ((CustomSound) packet.getSound()).getName(); - } else { - session.getGeyser().getLogger().debug("Unknown sound packet, we were unable to map this. " + packet.toString()); - return; - } - - SoundMapping soundMapping = Registries.SOUNDS.get(packetSound.replace("minecraft:", "")); - String playsound; - if (soundMapping == null || soundMapping.getPlaysound() == null) { - // no mapping - session.getGeyser().getLogger() - .debug("[PlaySound] Defaulting to sound server gave us for " + packet.toString()); - playsound = packetSound.replace("minecraft:", ""); - } else { - playsound = soundMapping.getPlaysound(); - } - PlaySoundPacket playSoundPacket = new PlaySoundPacket(); - playSoundPacket.setSound(playsound); + playSoundPacket.setSound(SoundUtils.translatePlaySound(packet.getSound())); playSoundPacket.setPosition(Vector3f.from(packet.getX(), packet.getY(), packet.getZ())); playSoundPacket.setVolume(packet.getVolume()); playSoundPacket.setPitch(packet.getPitch()); 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 60e7907e2..626c4527c 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 @@ -27,75 +27,17 @@ package org.geysermc.geyser.translator.protocol.java.level; import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.ClientboundSoundPacket; import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.data.LevelEventType; -import com.nukkitx.protocol.bedrock.data.SoundEvent; -import com.nukkitx.protocol.bedrock.packet.LevelEventPacket; -import com.nukkitx.protocol.bedrock.packet.LevelSoundEventPacket; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; -import org.geysermc.geyser.level.block.BlockStateValues; -import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.util.SoundUtils; -import org.geysermc.geyser.registry.Registries; -import org.geysermc.geyser.registry.type.SoundMapping; @Translator(packet = ClientboundSoundPacket.class) public class JavaSoundTranslator extends PacketTranslator { @Override public void translate(GeyserSession session, ClientboundSoundPacket packet) { - String packetSound = packet.getSound().getName(); - - SoundMapping soundMapping = Registries.SOUNDS.get(packetSound); - if (soundMapping == null) { - session.getGeyser().getLogger().debug("[Builtin] Sound mapping " + packetSound + " not found - " + packet.toString()); - return; - } - - if (soundMapping.isLevelEvent()) { - LevelEventPacket levelEventPacket = new LevelEventPacket(); - levelEventPacket.setPosition(Vector3f.from(packet.getX(), packet.getY(), packet.getZ())); - levelEventPacket.setData(0); - levelEventPacket.setType(LevelEventType.valueOf(soundMapping.getBedrock())); - session.sendUpstreamPacket(levelEventPacket); - return; - } - LevelSoundEventPacket soundPacket = new LevelSoundEventPacket(); - SoundEvent sound = SoundUtils.toSoundEvent(soundMapping.getBedrock()); - if (sound == null) { - sound = SoundUtils.toSoundEvent(packetSound); - } - if (sound == null) { - session.getGeyser().getLogger().debug("[Builtin] Sound for original " + packetSound + " to mappings " + soundPacket - + " was not a playable level sound, or has yet to be mapped to an enum in " - + "NukkitX SoundEvent "); - return; - } - - soundPacket.setSound(sound); - soundPacket.setPosition(Vector3f.from(packet.getX(), packet.getY(), packet.getZ())); - soundPacket.setIdentifier(soundMapping.getIdentifier()); - if (sound == SoundEvent.NOTE) { - // 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(packet.getPitch()) / Math.log10(2)) * 12)) + 12); - } else if (sound == SoundEvent.PLACE && soundMapping.getExtraData() == -1) { - if (!soundMapping.getIdentifier().equals(":")) { - soundPacket.setExtraData(session.getBlockMappings().getBedrockBlockId( - BlockRegistries.JAVA_IDENTIFIERS.getOrDefault(soundMapping.getIdentifier(), BlockStateValues.JAVA_AIR_ID))); - } else { - session.getGeyser().getLogger().debug("PLACE sound mapping identifier was invalid! Please report: " + packet.toString()); - } - soundPacket.setIdentifier(":"); - } else { - soundPacket.setExtraData(soundMapping.getExtraData()); - } - - - soundPacket.setBabySound(false); // might need to adjust this in the future - soundPacket.setRelativeVolumeDisabled(false); - session.sendUpstreamPacket(soundPacket); + Vector3f position = Vector3f.from(packet.getX(), packet.getY(), packet.getZ()); + SoundUtils.playBuiltinSound(session, packet.getSound(), position, packet.getPitch()); } } 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 d9750ad7e..e5bc7999f 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,15 +25,12 @@ package org.geysermc.geyser.translator.protocol.java.level; -import com.github.steveice10.mc.protocol.data.game.level.sound.BuiltinSound; -import com.github.steveice10.mc.protocol.data.game.level.sound.CustomSound; import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundStopSoundPacket; import com.nukkitx.protocol.bedrock.packet.StopSoundPacket; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; -import org.geysermc.geyser.registry.Registries; -import org.geysermc.geyser.registry.type.SoundMapping; +import org.geysermc.geyser.util.SoundUtils; @Translator(packet = ClientboundStopSoundPacket.class) public class JavaStopSoundTranslator extends PacketTranslator { @@ -49,36 +46,11 @@ public class JavaStopSoundTranslator extends PacketTranslator " - + soundMapping + (soundMapping == null ? "[not found]" : "") - + " - " + packet.toString()); - String playsound; - if (soundMapping == null || soundMapping.getPlaysound() == null) { - // no mapping - session.getGeyser().getLogger() - .debug("[StopSound] Defaulting to sound server gave us."); - playsound = packetSound; - } else { - playsound = soundMapping.getPlaysound(); - } - StopSoundPacket stopSoundPacket = new StopSoundPacket(); - stopSoundPacket.setSoundName(playsound); - // packet not mapped in the library + stopSoundPacket.setSoundName(SoundUtils.translatePlaySound(packet.getSound())); stopSoundPacket.setStoppingAllSound(false); session.sendUpstreamPacket(stopSoundPacket); - session.getGeyser().getLogger().debug("[StopSound] Packet sent - " + packet.toString() + " --> " + stopSoundPacket); + session.getGeyser().getLogger().debug("[StopSound] Stopped " + packet.getSound() + " -> " + stopSoundPacket.getSoundName()); } } 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 d2675f13e..44ec06244 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,20 @@ package org.geysermc.geyser.util; +import com.github.steveice10.mc.protocol.data.game.level.sound.BuiltinSound; +import com.github.steveice10.mc.protocol.data.game.level.sound.CustomSound; +import com.github.steveice10.mc.protocol.data.game.level.sound.Sound; +import com.nukkitx.math.vector.Vector3f; +import com.nukkitx.protocol.bedrock.data.LevelEventType; import com.nukkitx.protocol.bedrock.data.SoundEvent; +import com.nukkitx.protocol.bedrock.packet.LevelEventPacket; +import com.nukkitx.protocol.bedrock.packet.LevelSoundEventPacket; +import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.level.block.BlockStateValues; +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; public class SoundUtils { @@ -38,9 +51,103 @@ public class SoundUtils { */ public static SoundEvent toSoundEvent(String sound) { try { - return SoundEvent.valueOf(sound.toUpperCase().replaceAll("\\.", "_")); + return SoundEvent.valueOf(sound.toUpperCase().replace(".", "_")); } catch (Exception ex) { return null; } } + + /** + * Translates a Java Custom or Builtin Sound to its Bedrock equivalent + * + * @param sound the sound to translate + * @return a Bedrock sound + */ + public static String translatePlaySound(Sound sound) { + String packetSound; + if (sound instanceof BuiltinSound builtinSound) { + packetSound = builtinSound.getName(); + } else if (sound instanceof CustomSound customSound) { + packetSound = customSound.getName(); + } else { + GeyserImpl.getInstance().getLogger().debug("Unknown sound, we were unable to map this. " + sound); + return ""; + } + + // Drop the namespace + int colonPos = packetSound.indexOf(":"); + if (colonPos != -1) { + packetSound = packetSound.substring(colonPos + 1); + } + + SoundMapping soundMapping = Registries.SOUNDS.get(packetSound); + if (soundMapping == null || soundMapping.getPlaysound() == null) { + // no mapping + GeyserImpl.getInstance().getLogger().debug("[PlaySound] Defaulting to sound server gave us for " + sound); + return packetSound; + } + return soundMapping.getPlaysound(); + } + + /** + * Translates and plays a Java Builtin Sound for a Bedrock client + * + * @param session the Bedrock client session. + * @param javaSound the builtin sound to play + * @param position the position + * @param pitch the pitch + */ + public static void playBuiltinSound(GeyserSession session, BuiltinSound javaSound, Vector3f position, float pitch) { + String packetSound = javaSound.getName(); + + SoundMapping soundMapping = Registries.SOUNDS.get(packetSound); + if (soundMapping == null) { + session.getGeyser().getLogger().debug("[Builtin] Sound mapping for " + packetSound + " not found"); + return; + } + + if (soundMapping.isLevelEvent()) { + LevelEventPacket levelEventPacket = new LevelEventPacket(); + levelEventPacket.setPosition(position); + levelEventPacket.setData(0); + levelEventPacket.setType(LevelEventType.valueOf(soundMapping.getBedrock())); + session.sendUpstreamPacket(levelEventPacket); + return; + } + + LevelSoundEventPacket soundPacket = new LevelSoundEventPacket(); + SoundEvent sound = SoundUtils.toSoundEvent(soundMapping.getBedrock()); + if (sound == null) { + sound = SoundUtils.toSoundEvent(packetSound); + } + if (sound == null) { + session.getGeyser().getLogger().debug("[Builtin] Sound for original '" + packetSound + "' to mappings '" + soundMapping.getBedrock() + + "' was not a playable level sound, or has yet to be mapped to an enum in SoundEvent."); + return; + } + + soundPacket.setSound(sound); + soundPacket.setPosition(position); + soundPacket.setIdentifier(soundMapping.getIdentifier()); + if (sound == SoundEvent.NOTE) { + // 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); + } else if (sound == SoundEvent.PLACE && soundMapping.getExtraData() == -1) { + if (!soundMapping.getIdentifier().equals(":")) { + int javaId = BlockRegistries.JAVA_IDENTIFIERS.getOrDefault(soundMapping.getIdentifier(), BlockStateValues.JAVA_AIR_ID); + soundPacket.setExtraData(session.getBlockMappings().getBedrockBlockId(javaId)); + } else { + session.getGeyser().getLogger().debug("PLACE sound mapping identifier was invalid! Please report: " + soundMapping); + } + soundPacket.setIdentifier(":"); + } else { + soundPacket.setExtraData(soundMapping.getExtraData()); + } + + soundPacket.setBabySound(false); // might need to adjust this in the future + soundPacket.setRelativeVolumeDisabled(false); + session.sendUpstreamPacket(soundPacket); + } } diff --git a/core/src/main/resources/mappings b/core/src/main/resources/mappings index f0cee51f5..7fc4ac178 160000 --- a/core/src/main/resources/mappings +++ b/core/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit f0cee51f5868a78e18f3ac348eab52d5bbb2ac6f +Subproject commit 7fc4ac178901f2ba2989645d0da44dcfb95575db From c83eb7f142abe8e6d493b3e0d924765223f8e314 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Mon, 30 May 2022 14:51:03 -0400 Subject: [PATCH 48/72] Print CPU name in dump if possible --- .../org/geysermc/geyser/dump/DumpInfo.java | 3 + .../org/geysermc/geyser/util/CpuUtils.java | 94 +++++++++++++++++++ 2 files changed, 97 insertions(+) create mode 100644 core/src/main/java/org/geysermc/geyser/util/CpuUtils.java 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 ca902ea5c..1c9be8c3e 100644 --- a/core/src/main/java/org/geysermc/geyser/dump/DumpInfo.java +++ b/core/src/main/java/org/geysermc/geyser/dump/DumpInfo.java @@ -40,6 +40,7 @@ import org.geysermc.geyser.text.AsteriskSerializer; import org.geysermc.geyser.configuration.GeyserConfiguration; import org.geysermc.geyser.network.MinecraftProtocol; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.util.CpuUtils; import org.geysermc.geyser.util.FileUtils; import org.geysermc.geyser.util.WebUtils; import org.geysermc.floodgate.util.DeviceOs; @@ -64,6 +65,7 @@ public class DumpInfo { private final DumpInfo.VersionInfo versionInfo; private final int cpuCount; + private final String cpuName; private final Locale systemLocale; private final String systemEncoding; private Properties gitInfo; @@ -80,6 +82,7 @@ public class DumpInfo { this.versionInfo = new VersionInfo(); this.cpuCount = Runtime.getRuntime().availableProcessors(); + this.cpuName = CpuUtils.tryGetProcessorName(); this.systemLocale = Locale.getDefault(); this.systemEncoding = System.getProperty("file.encoding"); diff --git a/core/src/main/java/org/geysermc/geyser/util/CpuUtils.java b/core/src/main/java/org/geysermc/geyser/util/CpuUtils.java new file mode 100644 index 000000000..622722e5a --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/util/CpuUtils.java @@ -0,0 +1,94 @@ +/* + * 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 java.io.File; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.List; +import java.util.regex.Pattern; + +public final class CpuUtils { + + public static String tryGetProcessorName() { + try { + if (new File("/proc/cpuinfo").canRead()) { + return getLinuxProcessorName(); + } else { + return getWindowsProcessorName(); + } + } catch (Exception e) { + return e.getMessage(); + } + } + + /** + * Much of the code here was copied from the OSHI project. This is simply stripped down to only get the CPU model. + * https://github.com/oshi/oshi/ + */ + private static String getLinuxProcessorName() throws Exception { + List lines = Files.readAllLines(Paths.get("/proc/cpuinfo"), StandardCharsets.UTF_8); + Pattern whitespaceColonWhitespace = Pattern.compile("\\s+:\\s"); // From ParseUtil + for (String line : lines) { + String[] splitLine = whitespaceColonWhitespace.split(line); + if ("model name".equals(splitLine[0]) || "Processor".equals(splitLine[0])) { + return splitLine[1]; + } + } + return "unknown"; + } + + /** + * https://stackoverflow.com/a/6327663 + */ + private static String getWindowsProcessorName() throws Exception { + final String cpuNameCmd = "reg query \"HKLM\\HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0\" /v ProcessorNameString"; + final String regstrToken = "REG_SZ"; + + Process process = Runtime.getRuntime().exec(cpuNameCmd); + process.waitFor(); + InputStream is = process.getInputStream(); + + StringBuilder sb = new StringBuilder(); + while (is.available() != 0) { + sb.append((char) is.read()); + } + + String result = sb.toString(); + int p = result.indexOf(regstrToken); + + if (p == -1) { + return null; + } + + return result.substring(p + regstrToken.length()).trim(); + } + + private CpuUtils() { + } +} From 196742a597bbf767318663242fb06e6fc3cbec27 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Tue, 31 May 2022 14:25:15 -0400 Subject: [PATCH 49/72] Set entities silent client-side, and more Add warden entity events. Fix up other things. --- .../geyser/entity/EntityDefinitions.java | 2 +- .../entity/{ => type}/ChestBoatEntity.java | 4 +- .../geysermc/geyser/entity/type/Entity.java | 12 ++++++ .../geyser/entity/type/EvokerFangsEntity.java | 3 +- .../geyser/entity/type/FishingHookEntity.java | 13 +++---- .../living/monster/EnderDragonEntity.java | 2 +- .../type/living/monster/WardenEntity.java | 27 ++++++++++++- .../type/player/SessionPlayerEntity.java | 5 +++ .../geyser/registry/type/SoundMapping.java | 6 +-- .../entity/JavaEntityEventTranslator.java | 38 ++++++------------- .../entity/JavaSoundEntityTranslator.java | 2 +- .../java/level/JavaSoundTranslator.java | 2 +- .../org/geysermc/geyser/util/SoundUtils.java | 21 +++++++--- 13 files changed, 86 insertions(+), 51 deletions(-) rename core/src/main/java/org/geysermc/geyser/entity/{ => type}/ChestBoatEntity.java (96%) 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 eda8e0c84..73814628f 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java +++ b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java @@ -184,7 +184,7 @@ public final class EntityDefinitions { .addTranslator(MetadataType.INT, Entity::setAir) // Air/bubbles .addTranslator(MetadataType.OPTIONAL_CHAT, Entity::setDisplayName) .addTranslator(MetadataType.BOOLEAN, Entity::setDisplayNameVisible) - .addTranslator(MetadataType.BOOLEAN, (entity, entityMetadata) -> entity.setFlag(EntityFlag.SILENT, ((BooleanEntityMetadata) entityMetadata).getPrimitiveValue())) + .addTranslator(MetadataType.BOOLEAN, Entity::setSilent) .addTranslator(MetadataType.BOOLEAN, Entity::setGravity) .addTranslator(MetadataType.POSE, (entity, entityMetadata) -> entity.setPose(entityMetadata.getValue())) .addTranslator(MetadataType.INT, Entity::setFreezing) diff --git a/core/src/main/java/org/geysermc/geyser/entity/ChestBoatEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/ChestBoatEntity.java similarity index 96% rename from core/src/main/java/org/geysermc/geyser/entity/ChestBoatEntity.java rename to core/src/main/java/org/geysermc/geyser/entity/type/ChestBoatEntity.java index 76e98d953..724bf921e 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/ChestBoatEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/ChestBoatEntity.java @@ -23,11 +23,11 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.geyser.entity; +package org.geysermc.geyser.entity.type; import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import com.nukkitx.math.vector.Vector3f; -import org.geysermc.geyser.entity.type.BoatEntity; +import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.util.InteractionResult; import org.geysermc.geyser.util.InteractiveTag; 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 52efcf67e..144d1cbf9 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 @@ -94,6 +94,8 @@ public class Entity { private float boundingBoxWidth; @Setter(AccessLevel.NONE) protected String nametag = ""; + @Setter(AccessLevel.NONE) + protected boolean silent = false; /* Metadata end */ protected List passengers = Collections.emptyList(); @@ -148,6 +150,12 @@ public class Entity { setFlag(EntityFlag.HAS_COLLISION, true); setFlag(EntityFlag.CAN_SHOW_NAME, true); setFlag(EntityFlag.CAN_CLIMB, true); + // Let the Java server (or us) supply all sounds for an entity + setClientSideSilent(); + } + + protected void setClientSideSilent() { + setFlag(EntityFlag.SILENT, true); } public void spawnEntity() { @@ -370,6 +378,10 @@ public class Entity { dirtyMetadata.put(EntityData.NAMETAG_ALWAYS_SHOW, (byte) (entityMetadata.getPrimitiveValue() ? 1 : 0)); } + public final void setSilent(BooleanEntityMetadata entityMetadata) { + silent = entityMetadata.getPrimitiveValue(); + } + public void setGravity(BooleanEntityMetadata entityMetadata) { setFlag(EntityFlag.HAS_GRAVITY, !entityMetadata.getPrimitiveValue()); } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/EvokerFangsEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/EvokerFangsEntity.java index 03c71cec6..af7dca68c 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/EvokerFangsEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/EvokerFangsEntity.java @@ -27,7 +27,6 @@ package org.geysermc.geyser.entity.type; import com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.entity.EntityData; -import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import com.nukkitx.protocol.bedrock.packet.PlaySoundPacket; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.session.GeyserSession; @@ -58,7 +57,7 @@ public class EvokerFangsEntity extends Entity implements Tickable { public void setAttackStarted() { this.attackStarted = true; - if (!getFlag(EntityFlag.SILENT)) { + if (!silent) { // Play the chomp sound PlaySoundPacket packet = new PlaySoundPacket(); packet.setPosition(this.position); 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 57b597781..75bdd9021 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 @@ -28,17 +28,16 @@ package org.geysermc.geyser.entity.type; import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata; import com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.entity.EntityData; -import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import com.nukkitx.protocol.bedrock.packet.PlaySoundPacket; import lombok.Getter; import org.geysermc.geyser.entity.EntityDefinitions; import org.geysermc.geyser.entity.type.player.PlayerEntity; -import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.level.physics.BoundingBox; -import org.geysermc.geyser.translator.collision.BlockCollision; -import org.geysermc.geyser.level.block.BlockStateValues; -import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.level.block.BlockPositionIterator; +import org.geysermc.geyser.level.block.BlockStateValues; +import org.geysermc.geyser.level.physics.BoundingBox; +import org.geysermc.geyser.registry.BlockRegistries; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.translator.collision.BlockCollision; import org.geysermc.geyser.util.BlockUtils; import java.util.UUID; @@ -129,7 +128,7 @@ public class FishingHookEntity extends ThrowableEntity { } private void sendSplashSound(GeyserSession session) { - if (!getFlag(EntityFlag.SILENT)) { + if (!silent) { float volume = (float) (0.2f * Math.sqrt(0.2 * (motion.getX() * motion.getX() + motion.getZ() * motion.getZ()) + motion.getY() * motion.getY())); if (volume > 1) { volume = 1; 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 1d689e806..6adcb4694 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 @@ -213,7 +213,7 @@ public class EnderDragonEntity extends MobEntity implements Tickable { */ private void effectTick() { Random random = ThreadLocalRandom.current(); - if (!getFlag(EntityFlag.SILENT)) { + if (!silent) { if (Math.cos(wingPosition * 2f * Math.PI) <= -0.3f && Math.cos(lastWingPosition * 2f * Math.PI) >= -0.3f) { PlaySoundPacket playSoundPacket = new PlaySoundPacket(); playSoundPacket.setSound("mob.enderdragon.flap"); 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 3a8e9d351..0ec12da83 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 @@ -31,13 +31,19 @@ import com.nukkitx.math.GenericMath; import com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.entity.EntityData; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; +import com.nukkitx.protocol.bedrock.packet.PlaySoundPacket; 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 java.util.UUID; +import java.util.concurrent.ThreadLocalRandom; + +public class WardenEntity extends MonsterEntity implements Tickable { + private int heartBeatDelay; + private int tickCount; -public class WardenEntity extends MonsterEntity { public WardenEntity(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,6 +59,23 @@ public class WardenEntity extends MonsterEntity { public void setAngerLevel(IntEntityMetadata entityMetadata) { float anger = (float) entityMetadata.getPrimitiveValue() / 80f; - dirtyMetadata.put(EntityData.HEARTBEAT_INTERVAL_TICKS, 40 - GenericMath.floor(MathUtils.clamp(anger, 0.0F, 1.0F) * 30F)); + heartBeatDelay = 40 - GenericMath.floor(MathUtils.clamp(anger, 0.0F, 1.0F) * 30F); + dirtyMetadata.put(EntityData.HEARTBEAT_INTERVAL_TICKS, heartBeatDelay); + } + + @Override + public void tick() { + if (++tickCount % heartBeatDelay == 0 && !silent) { + // We have to do these calculations because they're clientside on Java Edition but we mute entities + // to prevent hearing their step sounds + ThreadLocalRandom random = ThreadLocalRandom.current(); + + PlaySoundPacket packet = new PlaySoundPacket(); + packet.setSound("mob.warden.heartbeat"); + packet.setPosition(position); + packet.setPitch(1.0f); + packet.setVolume((random.nextFloat() - random.nextFloat()) * 0.2f + 1.0f); + session.sendUpstreamPacket(packet); + } } } 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 db39a34db..d4b703c40 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 @@ -75,6 +75,11 @@ public class SessionPlayerEntity extends PlayerEntity { valid = true; } + @Override + protected void setClientSideSilent() { + // Do nothing, since we want the session player to hear their own footstep sounds for example. + } + @Override public void spawnEntity() { // Already logged in diff --git a/core/src/main/java/org/geysermc/geyser/registry/type/SoundMapping.java b/core/src/main/java/org/geysermc/geyser/registry/type/SoundMapping.java index 4120b6eb5..27b5e631d 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/type/SoundMapping.java +++ b/core/src/main/java/org/geysermc/geyser/registry/type/SoundMapping.java @@ -38,10 +38,10 @@ public class SoundMapping { public SoundMapping(String java, String bedrock, String playsound, int extraData, String identifier, boolean levelEvent) { this.java = java; - this.bedrock = bedrock == null || bedrock.equalsIgnoreCase("") ? null : bedrock; - this.playsound = playsound == null || playsound.equalsIgnoreCase("") ? null : playsound; + this.bedrock = bedrock == null || bedrock.isEmpty() ? null : bedrock; + this.playsound = playsound == null || playsound.isEmpty() ? null : playsound; this.extraData = extraData; - this.identifier = identifier == null || identifier.equalsIgnoreCase("") ? ":" : identifier; + this.identifier = identifier == null || identifier.isEmpty() ? ":" : identifier; this.levelEvent = levelEvent; } } \ No newline at end of file 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 de4a2c22b..ee342ce3f 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 @@ -26,7 +26,6 @@ package org.geysermc.geyser.translator.protocol.java.entity; import com.github.steveice10.mc.protocol.packet.ingame.clientbound.entity.ClientboundEntityEventPacket; -import com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.LevelEventType; import com.nukkitx.protocol.bedrock.data.SoundEvent; import com.nukkitx.protocol.bedrock.data.entity.EntityData; @@ -42,7 +41,6 @@ import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; -import java.util.Random; import java.util.concurrent.ThreadLocalRandom; @Translator(packet = ClientboundEntityEventPacket.class) @@ -50,6 +48,7 @@ public class JavaEntityEventTranslator extends PacketTranslator Date: Tue, 31 May 2022 14:26:08 -0400 Subject: [PATCH 50/72] e --- .../protocol/java/entity/JavaEntityEventTranslator.java | 1 - 1 file changed, 1 deletion(-) 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 ee342ce3f..ed18dc94c 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 @@ -48,7 +48,6 @@ public class JavaEntityEventTranslator extends PacketTranslator Date: Tue, 31 May 2022 14:51:21 -0400 Subject: [PATCH 51/72] Fix frog color translation --- .../geyser/entity/type/living/animal/FrogEntity.java | 7 ++++++- core/src/main/java/org/geysermc/geyser/util/MathUtils.java | 2 +- 2 files changed, 7 insertions(+), 2 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 2c1c884fb..97af056a0 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 @@ -54,7 +54,12 @@ public class FrogEntity extends AnimalEntity { } public void setFrogVariant(IntEntityMetadata entityMetadata) { - dirtyMetadata.put(EntityData.VARIANT, entityMetadata.getPrimitiveValue()); + int variant = entityMetadata.getPrimitiveValue(); + dirtyMetadata.put(EntityData.VARIANT, switch (variant) { + case 1 -> 2; // White + case 2 -> 1; // Green + default -> variant; + }); } public void setTongueTarget(ObjectEntityMetadata entityMetadata) { 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 a89240f25..f1e262bc6 100644 --- a/core/src/main/java/org/geysermc/geyser/util/MathUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/MathUtils.java @@ -110,7 +110,7 @@ public class MathUtils { * @param high The high bound of the clamp * @return the clamped value */ - public static double clamp(float value, float low, float high) { + public static float clamp(float value, float low, float high) { if (value < low) { return low; } From 365f8cf7e3702c7737d4d02117c8bcf41fc33b0b Mon Sep 17 00:00:00 2001 From: davchoo Date: Tue, 31 May 2022 14:58:40 -0400 Subject: [PATCH 52/72] Translate Warden sonic boom event Bump Protocol to fix Sonic boom flag --- core/pom.xml | 2 +- .../entity/type/living/monster/WardenEntity.java | 14 ++++++++++++++ .../java/entity/JavaEntityEventTranslator.java | 6 ++++++ core/src/main/resources/mappings | 2 +- 4 files changed, 22 insertions(+), 2 deletions(-) diff --git a/core/pom.xml b/core/pom.xml index 39c874d35..b639827b6 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -121,7 +121,7 @@ com.github.CloudburstMC.Protocol bedrock-beta - 51d4fce + be0cc73 compile 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 0ec12da83..e99bbd248 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 @@ -44,6 +44,8 @@ public class WardenEntity extends MonsterEntity implements Tickable { private int heartBeatDelay; private int tickCount; + private int sonicBoomTickDuration; + public WardenEntity(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); } @@ -77,5 +79,17 @@ public class WardenEntity extends MonsterEntity implements Tickable { packet.setVolume((random.nextFloat() - random.nextFloat()) * 0.2f + 1.0f); session.sendUpstreamPacket(packet); } + + if (--sonicBoomTickDuration == 0) { + setFlag(EntityFlag.SONIC_BOOM, false); + updateBedrockMetadata(); + } + } + + public void onSonicBoom() { + setFlag(EntityFlag.SONIC_BOOM, true); + updateBedrockMetadata(); + + sonicBoomTickDuration = 3 * 20; } } 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 ed18dc94c..e16159d3b 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.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.monster.WardenEntity; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; @@ -245,6 +246,11 @@ public class JavaEntityEventTranslator extends PacketTranslator Date: Tue, 31 May 2022 15:15:15 -0400 Subject: [PATCH 53/72] Fix sonic boom duration ticking below zero --- .../geyser/entity/type/living/monster/WardenEntity.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) 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 e99bbd248..e5f81691e 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 @@ -80,9 +80,12 @@ public class WardenEntity extends MonsterEntity implements Tickable { session.sendUpstreamPacket(packet); } - if (--sonicBoomTickDuration == 0) { - setFlag(EntityFlag.SONIC_BOOM, false); - updateBedrockMetadata(); + if (sonicBoomTickDuration > 0) { + sonicBoomTickDuration--; + if (sonicBoomTickDuration == 0) { + setFlag(EntityFlag.SONIC_BOOM, false); + updateBedrockMetadata(); + } } } From 3ac2c981a7dc2b9739a729272939c10dddbcf4da Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Thu, 2 Jun 2022 18:57:33 -0400 Subject: [PATCH 54/72] Swap pitch and volume for warden heartbeat --- .../entity/type/living/monster/WardenEntity.java | 4 ++-- .../geyser/registry/loader/SoundRegistryLoader.java | 5 +++-- .../java/org/geysermc/geyser/util/SoundUtils.java | 11 ++++++++--- 3 files changed, 13 insertions(+), 7 deletions(-) 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 e5f81691e..1ca34037c 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 @@ -75,8 +75,8 @@ public class WardenEntity extends MonsterEntity implements Tickable { PlaySoundPacket packet = new PlaySoundPacket(); packet.setSound("mob.warden.heartbeat"); packet.setPosition(position); - packet.setPitch(1.0f); - packet.setVolume((random.nextFloat() - random.nextFloat()) * 0.2f + 1.0f); + packet.setPitch((random.nextFloat() - random.nextFloat()) * 0.2f + 1.0f); + packet.setVolume(1.0f); session.sendUpstreamPacket(packet); } 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 106104d93..6703726ea 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 @@ -54,8 +54,9 @@ public class SoundRegistryLoader implements RegistryLoader next = soundsIterator.next(); JsonNode brMap = next.getValue(); - soundMappings.put(next.getKey(), new SoundMapping( - next.getKey(), + String javaSound = next.getKey(); + soundMappings.put(javaSound, new SoundMapping( + javaSound, brMap.has("bedrock_mapping") && brMap.get("bedrock_mapping").isTextual() ? brMap.get("bedrock_mapping").asText() : null, brMap.has("playsound_mapping") && brMap.get("playsound_mapping").isTextual() ? brMap.get("playsound_mapping").asText() : null, brMap.has("extra_data") && brMap.get("extra_data").isInt() ? brMap.get("extra_data").asInt() : -1, 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 6540c17ca..15348939c 100644 --- a/core/src/main/java/org/geysermc/geyser/util/SoundUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/SoundUtils.java @@ -41,7 +41,9 @@ import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.registry.type.SoundMapping; import org.geysermc.geyser.session.GeyserSession; -public class SoundUtils { +import java.util.Locale; + +public final class SoundUtils { /** * Maps a sound name to a sound event, null if one @@ -50,9 +52,9 @@ public class SoundUtils { * @param sound the sound name * @return a sound event from the given sound */ - public static SoundEvent toSoundEvent(String sound) { + private static SoundEvent toSoundEvent(String sound) { try { - return SoundEvent.valueOf(sound.toUpperCase().replace(".", "_")); + return SoundEvent.valueOf(sound.toUpperCase(Locale.ROOT).replace(".", "_")); } catch (Exception ex) { return null; } @@ -161,4 +163,7 @@ public class SoundUtils { soundPacket.setRelativeVolumeDisabled(false); session.sendUpstreamPacket(soundPacket); } + + private SoundUtils() { + } } From 56daefb0a0093ac525925e998f31a081930b438a Mon Sep 17 00:00:00 2001 From: RednedEpic Date: Sun, 5 Jun 2022 12:19:25 -0500 Subject: [PATCH 55/72] Update PaperMC repo --- bootstrap/spigot/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bootstrap/spigot/pom.xml b/bootstrap/spigot/pom.xml index e9e7687f4..d80408589 100644 --- a/bootstrap/spigot/pom.xml +++ b/bootstrap/spigot/pom.xml @@ -13,7 +13,7 @@ papermc - https://papermc.io/repo/repository/maven-public/ + https://repo.papermc.io/repository/maven-public/ viaversion-repo From bcc68ee4b5913013cec005ae17216659d20dd260 Mon Sep 17 00:00:00 2001 From: RednedEpic Date: Sun, 5 Jun 2022 13:12:36 -0500 Subject: [PATCH 56/72] Update to latest MCPL changes --- .../platform/spigot/GeyserSpigotInjector.java | 3 ++- core/pom.xml | 2 +- .../entity/type/living/ArmorStandEntity.java | 22 +++++++++---------- .../geyser/network/netty/LocalSession.java | 10 ++++++++- .../geyser/session/GeyserSession.java | 8 ++++++- .../protocol/java/JavaLoginTranslator.java | 8 +++---- .../entity/JavaEntityEventTranslator.java | 2 +- .../JavaLevelChunkWithLightTranslator.java | 8 +++---- 8 files changed, 37 insertions(+), 26 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 0d3b8ef16..0fd8d849b 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 @@ -169,9 +169,10 @@ public class GeyserSpigotInjector extends GeyserInjector { * For the future, if someone wants to properly fix this - as of December 28, 2021, it happens on 1.16.5/1.17.1/1.18.1 EXCEPT Spigot 1.16.5 */ private void workAroundWeirdBug(GeyserBootstrap bootstrap) { + MinecraftProtocol protocol = new MinecraftProtocol(); LocalSession session = new LocalSession(bootstrap.getGeyserConfig().getRemote().getAddress(), bootstrap.getGeyserConfig().getRemote().getPort(), this.serverSocketAddress, - InetAddress.getLoopbackAddress().getHostAddress(), new MinecraftProtocol()); + InetAddress.getLoopbackAddress().getHostAddress(), protocol, protocol.createHelper()); session.connect(); } diff --git a/core/pom.xml b/core/pom.xml index b639827b6..6fe54f8d5 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -171,7 +171,7 @@ com.github.steveice10 packetlib - 2.1-SNAPSHOT + 3.0 compile 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 18076763e..04e4727d0 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 @@ -26,9 +26,7 @@ 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.Rotation; import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.entity.EntityData; @@ -165,27 +163,27 @@ public class ArmorStandEntity extends LivingEntity { setFlag(EntityFlag.ADMIRING, (xd & 0x08) == 0x08); // Has no baseplate } - public void setHeadRotation(EntityMetadata entityMetadata) { + public void setHeadRotation(EntityMetadata entityMetadata) { onRotationUpdate(EntityData.MARK_VARIANT, EntityFlag.INTERESTED, EntityFlag.CHARGED, EntityFlag.POWERED, entityMetadata.getValue()); } - public void setBodyRotation(EntityMetadata entityMetadata) { + public void setBodyRotation(EntityMetadata entityMetadata) { onRotationUpdate(EntityData.VARIANT, EntityFlag.IN_LOVE, EntityFlag.CELEBRATING, EntityFlag.CELEBRATING_SPECIAL, entityMetadata.getValue()); } - public void setLeftArmRotation(EntityMetadata entityMetadata) { + public void setLeftArmRotation(EntityMetadata entityMetadata) { onRotationUpdate(EntityData.TRADE_TIER, EntityFlag.CHARGING, EntityFlag.CRITICAL, EntityFlag.DANCING, entityMetadata.getValue()); } - public void setRightArmRotation(EntityMetadata entityMetadata) { + public void setRightArmRotation(EntityMetadata entityMetadata) { onRotationUpdate(EntityData.MAX_TRADE_TIER, EntityFlag.ELDER, EntityFlag.EMOTING, EntityFlag.IDLING, entityMetadata.getValue()); } - public void setLeftLegRotation(EntityMetadata entityMetadata) { + public void setLeftLegRotation(EntityMetadata entityMetadata) { onRotationUpdate(EntityData.SKIN_ID, EntityFlag.IS_ILLAGER_CAPTAIN, EntityFlag.IS_IN_UI, EntityFlag.LINGERING, entityMetadata.getValue()); } - public void setRightLegRotation(EntityMetadata entityMetadata) { + public void setRightLegRotation(EntityMetadata entityMetadata) { onRotationUpdate(EntityData.HURT_DIRECTION, EntityFlag.IS_PREGNANT, EntityFlag.SHEARED, EntityFlag.STALKING, entityMetadata.getValue()); } @@ -200,13 +198,13 @@ public class ArmorStandEntity extends LivingEntity { * @param negativeZToggle the flag to set true if the Z value of rotation is negative * @param rotation the Java rotation value */ - private void onRotationUpdate(EntityData dataLeech, EntityFlag negativeXToggle, EntityFlag negativeYToggle, EntityFlag negativeZToggle, Rotation rotation) { + private void onRotationUpdate(EntityData dataLeech, EntityFlag negativeXToggle, EntityFlag negativeYToggle, EntityFlag negativeZToggle, Vector3f rotation) { // Indicate that rotation should be checked setFlag(EntityFlag.BRIBED, true); - int rotationX = MathUtils.wrapDegreesToInt(rotation.getPitch()); - int rotationY = MathUtils.wrapDegreesToInt(rotation.getYaw()); - int rotationZ = MathUtils.wrapDegreesToInt(rotation.getRoll()); + int rotationX = MathUtils.wrapDegreesToInt(rotation.getX()); + int rotationY = MathUtils.wrapDegreesToInt(rotation.getY()); + int rotationZ = MathUtils.wrapDegreesToInt(rotation.getZ()); // The top bit acts like binary and determines if each rotation goes above 100 // We don't do this for the negative values out of concerns of the number being too big int topBit = (Math.abs(rotationX) >= 100 ? 4 : 0) + (Math.abs(rotationY) >= 100 ? 2 : 0) + (Math.abs(rotationZ) >= 100 ? 1 : 0); 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 f3ccb0d2e..84838afc7 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 @@ -26,6 +26,7 @@ package org.geysermc.geyser.network.netty; 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.*; import io.netty.bootstrap.Bootstrap; @@ -47,11 +48,13 @@ public final class LocalSession extends TcpSession { private final SocketAddress targetAddress; private final String clientIp; + private final PacketCodecHelper codecHelper; - public LocalSession(String host, int port, SocketAddress targetAddress, String clientIp, PacketProtocol protocol) { + public LocalSession(String host, int port, SocketAddress targetAddress, String clientIp, PacketProtocol protocol, PacketCodecHelper codecHelper) { super(host, port, protocol); this.targetAddress = targetAddress; this.clientIp = clientIp; + this.codecHelper = codecHelper; } @Override @@ -102,6 +105,11 @@ public final class LocalSession extends TcpSession { } } + @Override + public PacketCodecHelper getCodecHelper() { + return this.codecHelper; + } + // TODO duplicate code private void addHAProxySupport(ChannelPipeline pipeline) { InetSocketAddress clientAddress = getFlag(BuiltinFlags.CLIENT_PROXIED_ADDRESS); 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 f60af61b3..ff15dafc1 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -34,6 +34,7 @@ import com.github.steveice10.mc.auth.service.MojangAuthenticationService; 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.codec.MinecraftCodecHelper; import com.github.steveice10.mc.protocol.data.ProtocolState; import com.github.steveice10.mc.protocol.data.UnexpectedEncryptionException; import com.github.steveice10.mc.protocol.data.game.MessageType; @@ -843,7 +844,8 @@ public class GeyserSession implements GeyserConnection, CommandSender { if (geyser.getBootstrap().getSocketAddress() != null) { // We're going to connect through the JVM and not through TCP downstream = new LocalSession(this.remoteAddress, this.remotePort, - geyser.getBootstrap().getSocketAddress(), upstream.getAddress().getAddress().getHostAddress(), this.protocol); + geyser.getBootstrap().getSocketAddress(), upstream.getAddress().getAddress().getHostAddress(), + this.protocol, this.downstream.getCodecHelper()); } else { downstream = new TcpClientSession(this.remoteAddress, this.remotePort, this.protocol); disableSrvResolving(); @@ -1737,4 +1739,8 @@ public class GeyserSession implements GeyserConnection, CommandSender { packet.setExtraData(-1); sendUpstreamPacket(packet); } + + public MinecraftCodecHelper getCodecHelper() { + return (MinecraftCodecHelper) this.downstream.getCodecHelper(); + } } 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 27bab75bb..a5c949c10 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 @@ -62,11 +62,11 @@ public class JavaLoginTranslator extends PacketTranslator dimensions = session.getDimensions(); dimensions.clear(); - JavaDimension.load(packet.getDimensionCodec(), dimensions); + JavaDimension.load(packet.getRegistry(), dimensions); Map chatTypes = session.getChatTypes(); chatTypes.clear(); - for (CompoundTag tag : JavaCodecEntry.iterateAsTag(packet.getDimensionCodec().get("minecraft:chat_type"))) { + for (CompoundTag tag : JavaCodecEntry.iterateAsTag(packet.getRegistry().get("minecraft:chat_type"))) { int id = ((IntTag) tag.get("id")).getValue(); CompoundTag element = tag.get("element"); CompoundTag chat = element.get("chat"); @@ -77,7 +77,7 @@ public class JavaLoginTranslator extends PacketTranslator> 4))]; try { - NetInput in = new StreamNetInput(new ByteArrayInputStream(packet.getChunkData())); + ByteBuf in = Unpooled.wrappedBuffer(packet.getChunkData()); for (int sectionY = 0; sectionY < chunkSize; sectionY++) { - ChunkSection javaSection = ChunkSection.read(in, biomeGlobalPalette); + ChunkSection javaSection = session.getCodecHelper().readChunkSection(in, biomeGlobalPalette); javaChunks[sectionY] = javaSection.getChunkData(); javaBiomes[sectionY] = javaSection.getBiomeData(); From 94445a52221eecec3c6d4e176f8c07f9ab065380 Mon Sep 17 00:00:00 2001 From: Tim203 Date: Mon, 6 Jun 2022 00:25:45 +0200 Subject: [PATCH 57/72] Re-added the old sendForm methods --- .../geysermc/geyser/session/GeyserSession.java | 16 ++++++++++++++++ 1 file changed, 16 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 df400d4e9..f198a812c 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -1381,6 +1381,22 @@ public class GeyserSession implements GeyserConnection, CommandSender { formCache.showForm(formBuilder.build()); } + /** + * @deprecated since Cumulus version 1.1, and will be removed when Cumulus 2.0 releases. Please use the new forms instead. + */ + @Deprecated + public void sendForm(org.geysermc.cumulus.Form form) { + sendForm(form.newForm()); + } + + /** + * @deprecated since Cumulus version 1.1, and will be removed when Cumulus 2.0 releases. Please use the new forms instead. + */ + @Deprecated + public void sendForm(org.geysermc.cumulus.util.FormBuilder formBuilder) { + sendForm(formBuilder.build()); + } + private void startGame() { StartGamePacket startGamePacket = new StartGamePacket(); startGamePacket.setUniqueEntityId(playerEntity.getGeyserId()); From 09fb6bf3ba94571ccf655e6a1da71c1eeaa26712 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sun, 5 Jun 2022 18:38:29 -0400 Subject: [PATCH 58/72] Fix direct connection and ensure connecting doesn't block --- .../java/org/geysermc/geyser/network/netty/LocalSession.java | 2 +- .../main/java/org/geysermc/geyser/session/GeyserSession.java | 4 ++-- 2 files changed, 3 insertions(+), 3 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 84838afc7..0781a04b2 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 @@ -58,7 +58,7 @@ public final class LocalSession extends TcpSession { } @Override - public void connect() { + public void connect(boolean wait) { if (this.disconnected) { throw new IllegalStateException("Connection has already been disconnected."); } 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 ff15dafc1..9f0efa3c3 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -845,7 +845,7 @@ public class GeyserSession implements GeyserConnection, CommandSender { // We're going to connect through the JVM and not through TCP downstream = new LocalSession(this.remoteAddress, this.remotePort, geyser.getBootstrap().getSocketAddress(), upstream.getAddress().getAddress().getHostAddress(), - this.protocol, this.downstream.getCodecHelper()); + this.protocol, this.protocol.createHelper()); } else { downstream = new TcpClientSession(this.remoteAddress, this.remotePort, this.protocol); disableSrvResolving(); @@ -1017,7 +1017,7 @@ public class GeyserSession implements GeyserConnection, CommandSender { setDaylightCycle(true); } - downstream.connect(); + downstream.connect(false); } public void disconnect(String reason) { From 86d020096078c441cbef1d94d7e14b1f9602a824 Mon Sep 17 00:00:00 2001 From: Tim203 Date: Mon, 6 Jun 2022 10:03:39 +0200 Subject: [PATCH 59/72] Re-added the old sendForm methods --- .../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 f198a812c..b55d392ad 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -1393,7 +1393,7 @@ public class GeyserSession implements GeyserConnection, CommandSender { * @deprecated since Cumulus version 1.1, and will be removed when Cumulus 2.0 releases. Please use the new forms instead. */ @Deprecated - public void sendForm(org.geysermc.cumulus.util.FormBuilder formBuilder) { + public void sendForm(org.geysermc.cumulus.util.FormBuilder formBuilder) { sendForm(formBuilder.build()); } From 3582d5cd6fc3b22b0a289874aa21fe08c4a988e2 Mon Sep 17 00:00:00 2001 From: Tim203 Date: Tue, 7 Jun 2022 00:19:59 +0200 Subject: [PATCH 60/72] Changed back the Geyser version and use Cumulus 1.1 --- Jenkinsfile | 1 - ap/pom.xml | 4 ++-- api/base/pom.xml | 2 +- api/geyser/pom.xml | 4 ++-- api/pom.xml | 2 +- bootstrap/bungeecord/pom.xml | 4 ++-- bootstrap/pom.xml | 4 ++-- bootstrap/spigot/pom.xml | 4 ++-- bootstrap/sponge/pom.xml | 4 ++-- bootstrap/standalone/pom.xml | 4 ++-- bootstrap/velocity/pom.xml | 4 ++-- common/pom.xml | 4 ++-- core/pom.xml | 8 ++++---- pom.xml | 2 +- 14 files changed, 25 insertions(+), 26 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index f1c8be56e..ac10b06dd 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -24,7 +24,6 @@ pipeline { when { anyOf { branch "master" - branch "feature/cumulus-1.1" // allow Floodgate to build } } diff --git a/ap/pom.xml b/ap/pom.xml index b60f37558..0644044a1 100644 --- a/ap/pom.xml +++ b/ap/pom.xml @@ -6,9 +6,9 @@ org.geysermc geyser-parent - 2.0.3-cumulus-SNAPSHOT + 2.0.3-SNAPSHOT ap - 2.0.3-cumulus-SNAPSHOT + 2.0.3-SNAPSHOT \ No newline at end of file diff --git a/api/base/pom.xml b/api/base/pom.xml index 4d4d12d90..1d051eaa3 100644 --- a/api/base/pom.xml +++ b/api/base/pom.xml @@ -5,7 +5,7 @@ org.geysermc api-parent - 2.0.3-cumulus-SNAPSHOT + 2.0.3-SNAPSHOT 4.0.0 diff --git a/api/geyser/pom.xml b/api/geyser/pom.xml index 9b67bea9e..2a933a2e0 100644 --- a/api/geyser/pom.xml +++ b/api/geyser/pom.xml @@ -5,7 +5,7 @@ org.geysermc api-parent - 2.0.3-cumulus-SNAPSHOT + 2.0.3-SNAPSHOT 4.0.0 @@ -26,7 +26,7 @@ org.geysermc base-api - 2.0.3-cumulus-SNAPSHOT + 2.0.3-SNAPSHOT compile diff --git a/api/pom.xml b/api/pom.xml index 2ff8b4906..5d078fba5 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -6,7 +6,7 @@ org.geysermc geyser-parent - 2.0.3-cumulus-SNAPSHOT + 2.0.3-SNAPSHOT api-parent diff --git a/bootstrap/bungeecord/pom.xml b/bootstrap/bungeecord/pom.xml index 0c04f139e..b2c661447 100644 --- a/bootstrap/bungeecord/pom.xml +++ b/bootstrap/bungeecord/pom.xml @@ -6,7 +6,7 @@ org.geysermc bootstrap-parent - 2.0.3-cumulus-SNAPSHOT + 2.0.3-SNAPSHOT bootstrap-bungeecord @@ -14,7 +14,7 @@ org.geysermc core - 2.0.3-cumulus-SNAPSHOT + 2.0.3-SNAPSHOT compile diff --git a/bootstrap/pom.xml b/bootstrap/pom.xml index 7c5ac68a1..7d6ac8f98 100644 --- a/bootstrap/pom.xml +++ b/bootstrap/pom.xml @@ -6,7 +6,7 @@ org.geysermc geyser-parent - 2.0.3-cumulus-SNAPSHOT + 2.0.3-SNAPSHOT bootstrap-parent pom @@ -34,7 +34,7 @@ org.geysermc ap - 2.0.3-cumulus-SNAPSHOT + 2.0.3-SNAPSHOT provided diff --git a/bootstrap/spigot/pom.xml b/bootstrap/spigot/pom.xml index ff100c6fa..d80408589 100644 --- a/bootstrap/spigot/pom.xml +++ b/bootstrap/spigot/pom.xml @@ -6,7 +6,7 @@ org.geysermc bootstrap-parent - 2.0.3-cumulus-SNAPSHOT + 2.0.3-SNAPSHOT bootstrap-spigot @@ -30,7 +30,7 @@ org.geysermc core - 2.0.3-cumulus-SNAPSHOT + 2.0.3-SNAPSHOT compile diff --git a/bootstrap/sponge/pom.xml b/bootstrap/sponge/pom.xml index 96013e69a..8eba4d73d 100644 --- a/bootstrap/sponge/pom.xml +++ b/bootstrap/sponge/pom.xml @@ -6,7 +6,7 @@ org.geysermc bootstrap-parent - 2.0.3-cumulus-SNAPSHOT + 2.0.3-SNAPSHOT bootstrap-sponge @@ -14,7 +14,7 @@ org.geysermc core - 2.0.3-cumulus-SNAPSHOT + 2.0.3-SNAPSHOT compile diff --git a/bootstrap/standalone/pom.xml b/bootstrap/standalone/pom.xml index b3b32cc87..8ee94b793 100644 --- a/bootstrap/standalone/pom.xml +++ b/bootstrap/standalone/pom.xml @@ -6,7 +6,7 @@ org.geysermc bootstrap-parent - 2.0.3-cumulus-SNAPSHOT + 2.0.3-SNAPSHOT bootstrap-standalone @@ -18,7 +18,7 @@ org.geysermc core - 2.0.3-cumulus-SNAPSHOT + 2.0.3-SNAPSHOT compile diff --git a/bootstrap/velocity/pom.xml b/bootstrap/velocity/pom.xml index d81994522..36882a19e 100644 --- a/bootstrap/velocity/pom.xml +++ b/bootstrap/velocity/pom.xml @@ -6,7 +6,7 @@ org.geysermc bootstrap-parent - 2.0.3-cumulus-SNAPSHOT + 2.0.3-SNAPSHOT bootstrap-velocity @@ -14,7 +14,7 @@ org.geysermc core - 2.0.3-cumulus-SNAPSHOT + 2.0.3-SNAPSHOT compile diff --git a/common/pom.xml b/common/pom.xml index fc00d4031..07fdb2b12 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -6,7 +6,7 @@ org.geysermc geyser-parent - 2.0.3-cumulus-SNAPSHOT + 2.0.3-SNAPSHOT common @@ -20,7 +20,7 @@ org.geysermc.cumulus cumulus - 1.1-SNAPSHOT + 1.1 com.google.code.gson diff --git a/core/pom.xml b/core/pom.xml index d817fab0f..6fe54f8d5 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -6,7 +6,7 @@ org.geysermc geyser-parent - 2.0.3-cumulus-SNAPSHOT + 2.0.3-SNAPSHOT core @@ -21,19 +21,19 @@ org.geysermc ap - 2.0.3-cumulus-SNAPSHOT + 2.0.3-SNAPSHOT provided org.geysermc geyser-api - 2.0.3-cumulus-SNAPSHOT + 2.0.3-SNAPSHOT compile org.geysermc common - 2.0.3-cumulus-SNAPSHOT + 2.0.3-SNAPSHOT compile diff --git a/pom.xml b/pom.xml index f0b8f21ab..f4930959d 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ 4.0.0 org.geysermc geyser-parent - 2.0.3-cumulus-SNAPSHOT + 2.0.3-SNAPSHOT pom Geyser Allows for players from Minecraft Bedrock Edition to join Minecraft Java Edition servers. From 378aa6ed99d5c8bdc9bb9ef8329cba2511b90333 Mon Sep 17 00:00:00 2001 From: Tim203 Date: Tue, 7 Jun 2022 00:31:29 +0200 Subject: [PATCH 61/72] Updated changes for latest Geyser version --- .../floodgate/pluginmessage/PluginMessageChannels.java | 5 ++++- .../protocol/java/JavaCustomPayloadTranslator.java | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/common/src/main/java/org/geysermc/floodgate/pluginmessage/PluginMessageChannels.java b/common/src/main/java/org/geysermc/floodgate/pluginmessage/PluginMessageChannels.java index 37c5d4015..f06c0f9da 100644 --- a/common/src/main/java/org/geysermc/floodgate/pluginmessage/PluginMessageChannels.java +++ b/common/src/main/java/org/geysermc/floodgate/pluginmessage/PluginMessageChannels.java @@ -31,8 +31,11 @@ public final class PluginMessageChannels { public static final String SKIN = "floodgate:skin"; public static final String FORM = "floodgate:form"; public static final String TRANSFER = "floodgate:transfer"; + public static final String PACKET = "floodgate:packet"; - private static final byte[] FLOODGATE_REGISTER_DATA = String.join("\0", SKIN, FORM, TRANSFER).getBytes(Charsets.UTF_8); + private static final byte[] FLOODGATE_REGISTER_DATA = + String.join("\0", SKIN, FORM, TRANSFER, PACKET) + .getBytes(Charsets.UTF_8); /** * Get the prebuilt register data as a byte array 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 32c1f747f..13ace5e23 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 @@ -103,7 +103,7 @@ public class JavaCustomPayloadTranslator extends PacketTranslator Date: Mon, 6 Jun 2022 21:06:02 -0400 Subject: [PATCH 62/72] Add goat horn count --- .../geyser/entity/EntityDefinitions.java | 2 ++ .../entity/type/living/animal/GoatEntity.java | 17 +++++++++++++++++ 2 files changed, 19 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 73814628f..52d9250ac 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java +++ b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java @@ -772,6 +772,8 @@ public final class EntityDefinitions { .type(EntityType.GOAT) .height(1.3f).width(0.9f) .addTranslator(MetadataType.BOOLEAN, GoatEntity::setScreamer) + .addTranslator(MetadataType.BOOLEAN, GoatEntity::setHasLeftHorn) + .addTranslator(MetadataType.BOOLEAN, GoatEntity::setHasRightHorn) .build(); MOOSHROOM = EntityDefinition.inherited(MooshroomEntity::new, ageableEntityBase) .type(EntityType.MOOSHROOM) 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 a6f2e268e..d50eb74c5 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 @@ -30,6 +30,7 @@ import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanE import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.SoundEvent; +import com.nukkitx.protocol.bedrock.data.entity.EntityData; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.inventory.GeyserItemStack; @@ -44,6 +45,8 @@ public class GoatEntity extends AnimalEntity { private static final float LONG_JUMPING_WIDTH = 0.9f * 0.7f; private boolean isScreamer; + private boolean hasLeftHorn; + private boolean hasRightHorn; public GoatEntity(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); @@ -74,4 +77,18 @@ public class GoatEntity extends AnimalEntity { return super.mobInteract(hand, itemInHand); } } + + public void setHasLeftHorn(BooleanEntityMetadata entityMetadata) { + hasLeftHorn = entityMetadata.getPrimitiveValue(); + setHornCount(); + } + + public void setHasRightHorn(BooleanEntityMetadata entityMetadata) { + hasRightHorn = entityMetadata.getPrimitiveValue(); + setHornCount(); + } + + private void setHornCount() { + dirtyMetadata.put(EntityData.GOAT_HORN_COUNT, (hasLeftHorn ? 1 : 0) + (hasRightHorn ? 1 : 0)); + } } From 172167f14f44cf86a8ce43c41d8cdc74cf8cc829 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Mon, 6 Jun 2022 22:54:10 -0400 Subject: [PATCH 63/72] Prepare for release --- core/pom.xml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/core/pom.xml b/core/pom.xml index 6fe54f8d5..7a1dde546 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -120,8 +120,8 @@ com.github.CloudburstMC.Protocol - bedrock-beta - be0cc73 + bedrock-v527 + 977a9a1 compile @@ -153,9 +153,9 @@ compile - com.github.steveice10 - mcprotocollib - 1.19-SNAPSHOT + com.github.GeyserMC + MCProtocolLib + 1e5477f compile From c8856d487d08604184731a1c71f2951fe373eb45 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Mon, 6 Jun 2022 22:56:08 -0400 Subject: [PATCH 64/72] Compile too --- .../java/org/geysermc/geyser/network/MinecraftProtocol.java | 4 ++-- .../geyser/registry/populator/BlockRegistryPopulator.java | 4 ++-- .../geyser/registry/populator/ItemRegistryPopulator.java | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/network/MinecraftProtocol.java b/core/src/main/java/org/geysermc/geyser/network/MinecraftProtocol.java index fff0d38fe..ba21eeb44 100644 --- a/core/src/main/java/org/geysermc/geyser/network/MinecraftProtocol.java +++ b/core/src/main/java/org/geysermc/geyser/network/MinecraftProtocol.java @@ -28,7 +28,7 @@ package org.geysermc.geyser.network; import com.github.steveice10.mc.protocol.codec.MinecraftCodec; import com.github.steveice10.mc.protocol.codec.PacketCodec; import com.nukkitx.protocol.bedrock.BedrockPacketCodec; -import com.nukkitx.protocol.bedrock.beta.BedrockBeta; +import com.nukkitx.protocol.bedrock.v527.Bedrock_v527; import java.util.ArrayList; import java.util.Collections; @@ -43,7 +43,7 @@ public final class MinecraftProtocol { * Default Bedrock codec that should act as a fallback. Should represent the latest available * release of the game that Geyser supports. */ - public static final BedrockPacketCodec DEFAULT_BEDROCK_CODEC = BedrockBeta.BETA_CODEC; + public static final BedrockPacketCodec DEFAULT_BEDROCK_CODEC = Bedrock_v527.V527_CODEC; /** * A list of all supported Bedrock versions that can join Geyser */ 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 58a1bdb0f..25528a919 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 @@ -28,7 +28,7 @@ package org.geysermc.geyser.registry.populator; import com.fasterxml.jackson.databind.JsonNode; import com.google.common.collect.ImmutableMap; import com.nukkitx.nbt.*; -import com.nukkitx.protocol.bedrock.beta.BedrockBeta; +import com.nukkitx.protocol.bedrock.v527.Bedrock_v527; import it.unimi.dsi.fastutil.ints.IntOpenHashSet; import it.unimi.dsi.fastutil.ints.IntSet; import it.unimi.dsi.fastutil.objects.Object2IntMap; @@ -61,7 +61,7 @@ public class BlockRegistryPopulator { static { ImmutableMap.Builder, BiFunction> stateMapperBuilder = ImmutableMap., BiFunction>builder() - .put(ObjectIntPair.of("1_19_0", BedrockBeta.BETA_CODEC.getProtocolVersion()), EMPTY_MAPPER); + .put(ObjectIntPair.of("1_19_0", Bedrock_v527.V527_CODEC.getProtocolVersion()), EMPTY_MAPPER); BLOCK_MAPPERS = stateMapperBuilder.build(); } 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 2868652bd..f3d936b2e 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 @@ -31,11 +31,11 @@ import com.nukkitx.nbt.NbtMap; import com.nukkitx.nbt.NbtMapBuilder; import com.nukkitx.nbt.NbtType; import com.nukkitx.nbt.NbtUtils; -import com.nukkitx.protocol.bedrock.beta.BedrockBeta; import com.nukkitx.protocol.bedrock.data.SoundEvent; import com.nukkitx.protocol.bedrock.data.inventory.ComponentItemData; import com.nukkitx.protocol.bedrock.data.inventory.ItemData; import com.nukkitx.protocol.bedrock.packet.StartGamePacket; +import com.nukkitx.protocol.bedrock.v527.Bedrock_v527; import it.unimi.dsi.fastutil.ints.Int2IntMap; import it.unimi.dsi.fastutil.ints.IntArrayList; import it.unimi.dsi.fastutil.ints.IntList; @@ -64,7 +64,7 @@ public class ItemRegistryPopulator { public static void populate() { Map paletteVersions = new Object2ObjectOpenHashMap<>(); - paletteVersions.put("1_19_0", new PaletteVersion(BedrockBeta.BETA_CODEC.getProtocolVersion(), Collections.emptyMap())); + paletteVersions.put("1_19_0", new PaletteVersion(Bedrock_v527.V527_CODEC.getProtocolVersion(), Collections.emptyMap())); GeyserBootstrap bootstrap = GeyserImpl.getInstance().getBootstrap(); From 2595eae30070fa5d221ad505eef6a9e1606fb1d1 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Tue, 7 Jun 2022 11:14:58 -0400 Subject: [PATCH 65/72] Bump to 2.0.4-SNAPSHOT --- ap/pom.xml | 4 ++-- api/base/pom.xml | 2 +- api/geyser/pom.xml | 4 ++-- api/pom.xml | 2 +- bootstrap/bungeecord/pom.xml | 4 ++-- bootstrap/pom.xml | 4 ++-- bootstrap/spigot/pom.xml | 4 ++-- bootstrap/sponge/pom.xml | 4 ++-- bootstrap/standalone/pom.xml | 4 ++-- bootstrap/velocity/pom.xml | 4 ++-- common/pom.xml | 2 +- core/pom.xml | 8 ++++---- pom.xml | 2 +- 13 files changed, 24 insertions(+), 24 deletions(-) diff --git a/ap/pom.xml b/ap/pom.xml index 0644044a1..0dbb4f504 100644 --- a/ap/pom.xml +++ b/ap/pom.xml @@ -6,9 +6,9 @@ org.geysermc geyser-parent - 2.0.3-SNAPSHOT + 2.0.4-SNAPSHOT ap - 2.0.3-SNAPSHOT + 2.0.4-SNAPSHOT \ No newline at end of file diff --git a/api/base/pom.xml b/api/base/pom.xml index 1d051eaa3..459d7a87a 100644 --- a/api/base/pom.xml +++ b/api/base/pom.xml @@ -5,7 +5,7 @@ org.geysermc api-parent - 2.0.3-SNAPSHOT + 2.0.4-SNAPSHOT 4.0.0 diff --git a/api/geyser/pom.xml b/api/geyser/pom.xml index 2a933a2e0..38af895f0 100644 --- a/api/geyser/pom.xml +++ b/api/geyser/pom.xml @@ -5,7 +5,7 @@ org.geysermc api-parent - 2.0.3-SNAPSHOT + 2.0.4-SNAPSHOT 4.0.0 @@ -26,7 +26,7 @@ org.geysermc base-api - 2.0.3-SNAPSHOT + 2.0.4-SNAPSHOT compile diff --git a/api/pom.xml b/api/pom.xml index 5d078fba5..efc85cc72 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -6,7 +6,7 @@ org.geysermc geyser-parent - 2.0.3-SNAPSHOT + 2.0.4-SNAPSHOT api-parent diff --git a/bootstrap/bungeecord/pom.xml b/bootstrap/bungeecord/pom.xml index b2c661447..3c9f7904e 100644 --- a/bootstrap/bungeecord/pom.xml +++ b/bootstrap/bungeecord/pom.xml @@ -6,7 +6,7 @@ org.geysermc bootstrap-parent - 2.0.3-SNAPSHOT + 2.0.4-SNAPSHOT bootstrap-bungeecord @@ -14,7 +14,7 @@ org.geysermc core - 2.0.3-SNAPSHOT + 2.0.4-SNAPSHOT compile diff --git a/bootstrap/pom.xml b/bootstrap/pom.xml index 7d6ac8f98..b47e95644 100644 --- a/bootstrap/pom.xml +++ b/bootstrap/pom.xml @@ -6,7 +6,7 @@ org.geysermc geyser-parent - 2.0.3-SNAPSHOT + 2.0.4-SNAPSHOT bootstrap-parent pom @@ -34,7 +34,7 @@ org.geysermc ap - 2.0.3-SNAPSHOT + 2.0.4-SNAPSHOT provided diff --git a/bootstrap/spigot/pom.xml b/bootstrap/spigot/pom.xml index d80408589..5f33e313e 100644 --- a/bootstrap/spigot/pom.xml +++ b/bootstrap/spigot/pom.xml @@ -6,7 +6,7 @@ org.geysermc bootstrap-parent - 2.0.3-SNAPSHOT + 2.0.4-SNAPSHOT bootstrap-spigot @@ -30,7 +30,7 @@ org.geysermc core - 2.0.3-SNAPSHOT + 2.0.4-SNAPSHOT compile diff --git a/bootstrap/sponge/pom.xml b/bootstrap/sponge/pom.xml index 8eba4d73d..e70d2d825 100644 --- a/bootstrap/sponge/pom.xml +++ b/bootstrap/sponge/pom.xml @@ -6,7 +6,7 @@ org.geysermc bootstrap-parent - 2.0.3-SNAPSHOT + 2.0.4-SNAPSHOT bootstrap-sponge @@ -14,7 +14,7 @@ org.geysermc core - 2.0.3-SNAPSHOT + 2.0.4-SNAPSHOT compile diff --git a/bootstrap/standalone/pom.xml b/bootstrap/standalone/pom.xml index 8ee94b793..514b80799 100644 --- a/bootstrap/standalone/pom.xml +++ b/bootstrap/standalone/pom.xml @@ -6,7 +6,7 @@ org.geysermc bootstrap-parent - 2.0.3-SNAPSHOT + 2.0.4-SNAPSHOT bootstrap-standalone @@ -18,7 +18,7 @@ org.geysermc core - 2.0.3-SNAPSHOT + 2.0.4-SNAPSHOT compile diff --git a/bootstrap/velocity/pom.xml b/bootstrap/velocity/pom.xml index 36882a19e..fa05bb2c1 100644 --- a/bootstrap/velocity/pom.xml +++ b/bootstrap/velocity/pom.xml @@ -6,7 +6,7 @@ org.geysermc bootstrap-parent - 2.0.3-SNAPSHOT + 2.0.4-SNAPSHOT bootstrap-velocity @@ -14,7 +14,7 @@ org.geysermc core - 2.0.3-SNAPSHOT + 2.0.4-SNAPSHOT compile diff --git a/common/pom.xml b/common/pom.xml index 07fdb2b12..65b6ef7ce 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -6,7 +6,7 @@ org.geysermc geyser-parent - 2.0.3-SNAPSHOT + 2.0.4-SNAPSHOT common diff --git a/core/pom.xml b/core/pom.xml index 7a1dde546..6abb0f446 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -6,7 +6,7 @@ org.geysermc geyser-parent - 2.0.3-SNAPSHOT + 2.0.4-SNAPSHOT core @@ -21,19 +21,19 @@ org.geysermc ap - 2.0.3-SNAPSHOT + 2.0.4-SNAPSHOT provided org.geysermc geyser-api - 2.0.3-SNAPSHOT + 2.0.4-SNAPSHOT compile org.geysermc common - 2.0.3-SNAPSHOT + 2.0.4-SNAPSHOT compile diff --git a/pom.xml b/pom.xml index f4930959d..a9370a3c0 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ 4.0.0 org.geysermc geyser-parent - 2.0.3-SNAPSHOT + 2.0.4-SNAPSHOT pom Geyser Allows for players from Minecraft Bedrock Edition to join Minecraft Java Edition servers. From 5a1e6a6d08fc10afb6de3d32f512f6218f99f7bb Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Tue, 7 Jun 2022 14:46:59 -0400 Subject: [PATCH 66/72] Fix Geyser booting on Spigot 1.19 --- bootstrap/spigot/pom.xml | 7 ++++++- .../geyser/platform/spigot/GeyserSpigotPlugin.java | 9 ++++----- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/bootstrap/spigot/pom.xml b/bootstrap/spigot/pom.xml index 5f33e313e..72b812234 100644 --- a/bootstrap/spigot/pom.xml +++ b/bootstrap/spigot/pom.xml @@ -116,6 +116,12 @@ me.lucko.commodore org.geysermc.geyser.platform.spigot.shaded.commodore + + + io.netty.channel.kqueue + org.geysermc.geyser.platform.spigot.shaded.io.netty.channel.kqueue + @@ -129,7 +135,6 @@ io.netty:netty-transport-native-epoll:* io.netty:netty-transport-native-unix-common:* - io.netty:netty-transport-native-kqueue:* io.netty:netty-handler:* io.netty:netty-common:* io.netty:netty-buffer:* 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 4ece501c4..4b41ad569 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 @@ -29,6 +29,7 @@ import com.viaversion.viaversion.api.Via; 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.command.PluginCommand; @@ -108,11 +109,9 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { } try { - // Required for the Cloudburst Network dependency to initialize. - Class.forName("io.netty.channel.kqueue.KQueue"); - } catch (ClassNotFoundException e) { - // While we could support these older versions, the downside is not having KQueue working at all - // And since there are alternative ways to get Geyser working for these aging platforms, it's not worth it. + // AvailableCommandsSerializer_v291 complains otherwise + ByteBuf.class.getMethod("writeShortLE", int.class); + } catch (NoSuchMethodException e) { getLogger().severe("*********************************************"); getLogger().severe(""); getLogger().severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_server.header")); From 78bb69be4244476d8d8afc6745bf10d120c32efe Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Tue, 7 Jun 2022 15:07:54 -0400 Subject: [PATCH 67/72] Fix LevelEvent reading --- core/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/pom.xml b/core/pom.xml index 6abb0f446..66a3d21c0 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -155,7 +155,7 @@ com.github.GeyserMC MCProtocolLib - 1e5477f + bf3919a compile From 72a9df58e0b14c0d1a4ee594a86c6166dfc53fca Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Wed, 8 Jun 2022 22:30:34 -0400 Subject: [PATCH 68/72] Properly support differently setup chat registries ViaVersion has two entries in its fake chat registry that are not in the same order as Java. This commit supports that properly and renders subtitled text correctly. Resolves #3023 --- core/pom.xml | 2 +- .../geyser/session/GeyserSession.java | 3 +- .../geysermc/geyser/text/ChatTypeEntry.java | 34 +++++++++++++++++++ .../protocol/java/JavaLoginTranslator.java | 30 +++++++++++----- .../java/JavaPlayerChatTranslator.java | 13 +++---- .../java/JavaSystemChatTranslator.java | 8 +---- 6 files changed, 64 insertions(+), 26 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/text/ChatTypeEntry.java diff --git a/core/pom.xml b/core/pom.xml index 66a3d21c0..e0db25db0 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -155,7 +155,7 @@ com.github.GeyserMC MCProtocolLib - bf3919a + 3023c4d compile 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 c18562c88..e8490c240 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -121,6 +121,7 @@ import org.geysermc.geyser.session.auth.AuthType; import org.geysermc.geyser.session.auth.BedrockClientData; import org.geysermc.geyser.session.cache.*; import org.geysermc.geyser.skin.FloodgateSkinUploader; +import org.geysermc.geyser.text.ChatTypeEntry; import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.text.MinecraftLocale; import org.geysermc.geyser.text.TextDecoration; @@ -336,7 +337,7 @@ public class GeyserSession implements GeyserConnection, CommandSender { */ private final Map dimensions = new Object2ObjectOpenHashMap<>(3); - private final Map chatTypes = new EnumMap<>(MessageType.class); + private final Int2ObjectMap chatTypes = new Int2ObjectOpenHashMap<>(7); @Setter private int breakingBlock; diff --git a/core/src/main/java/org/geysermc/geyser/text/ChatTypeEntry.java b/core/src/main/java/org/geysermc/geyser/text/ChatTypeEntry.java new file mode 100644 index 000000000..32be209ca --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/text/ChatTypeEntry.java @@ -0,0 +1,34 @@ +/* + * 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 com.nukkitx.protocol.bedrock.packet.TextPacket; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public record ChatTypeEntry(@Nonnull TextPacket.Type bedrockChatType, @Nullable TextDecoration textDecoration) { +} 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 a5c949c10..74d12bd19 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 @@ -30,16 +30,20 @@ import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundLo import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundCustomPayloadPacket; 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 com.nukkitx.protocol.bedrock.data.GameRuleData; import com.nukkitx.protocol.bedrock.data.PlayerPermission; import com.nukkitx.protocol.bedrock.packet.AdventureSettingsPacket; import com.nukkitx.protocol.bedrock.packet.GameRulesChangedPacket; import com.nukkitx.protocol.bedrock.packet.SetPlayerGameTypePacket; +import com.nukkitx.protocol.bedrock.packet.TextPacket; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import org.geysermc.floodgate.pluginmessage.PluginMessageChannels; import org.geysermc.geyser.entity.type.player.SessionPlayerEntity; import org.geysermc.geyser.level.JavaDimension; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.auth.AuthType; +import org.geysermc.geyser.text.ChatTypeEntry; import org.geysermc.geyser.text.TextDecoration; import org.geysermc.geyser.translator.level.BiomeTranslator; import org.geysermc.geyser.translator.protocol.PacketTranslator; @@ -64,21 +68,29 @@ public class JavaLoginTranslator extends PacketTranslator chatTypes = session.getChatTypes(); + Int2ObjectMap chatTypes = session.getChatTypes(); chatTypes.clear(); for (CompoundTag tag : JavaCodecEntry.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"); - if (chat == null) { - continue; + TextDecoration textDecoration = null; + if (chat != null) { + CompoundTag decorationTag = chat.get("decoration"); + if (decorationTag != null) { + textDecoration = new TextDecoration(decorationTag); + } } - CompoundTag decoration = chat.get("decoration"); - if (decoration == null) { - continue; - } - MessageType type = MessageType.from(id); - chatTypes.put(type, new TextDecoration(decoration)); + MessageType type = MessageType.from(((StringTag) tag.get("name")).getValue()); + // TODO new types? + TextPacket.Type bedrockType = switch (type) { + case CHAT -> TextPacket.Type.CHAT; + case SYSTEM -> TextPacket.Type.SYSTEM; + case GAME_INFO -> TextPacket.Type.TIP; + default -> TextPacket.Type.RAW; + }; + chatTypes.put(id, new ChatTypeEntry(bedrockType, textDecoration)); } // If the player is already initialized and a join game packet is sent, they 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 be1635fdd..f9f4407d9 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 @@ -30,6 +30,7 @@ import com.nukkitx.protocol.bedrock.packet.TextPacket; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.TranslatableComponent; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.text.ChatTypeEntry; import org.geysermc.geyser.text.TextDecoration; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; @@ -44,22 +45,18 @@ public class JavaPlayerChatTranslator extends PacketTranslator TextPacket.Type.CHAT; - case SYSTEM -> TextPacket.Type.SYSTEM; - case GAME_INFO -> TextPacket.Type.TIP; - default -> TextPacket.Type.RAW; - }); + textPacket.setType(entry.bedrockChatType()); textPacket.setNeedsTranslation(false); Component message = packet.getUnsignedContent() == null ? packet.getSignedContent() : packet.getUnsignedContent(); - TextDecoration decoration = session.getChatTypes().get(packet.getType()); + TextDecoration decoration = entry.textDecoration(); 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/translator/protocol/java/JavaSystemChatTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaSystemChatTranslator.java index b82f2e194..fc4a32bac 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 @@ -41,13 +41,7 @@ public class JavaSystemChatTranslator extends PacketTranslator TextPacket.Type.CHAT; - case SYSTEM -> TextPacket.Type.SYSTEM; - case GAME_INFO -> TextPacket.Type.TIP; - default -> TextPacket.Type.RAW; - }); + textPacket.setType(session.getChatTypes().get(packet.getTypeId()).bedrockChatType()); textPacket.setNeedsTranslation(false); textPacket.setMessage(MessageTranslator.convertMessage(packet.getContent(), session.getLocale())); From f1a12d1feb91014b7cda068072be15cf15833556 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Thu, 9 Jun 2022 18:34:25 -0400 Subject: [PATCH 69/72] Bump mappings and MCProtocolLib --- core/pom.xml | 2 +- core/src/main/resources/mappings | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/pom.xml b/core/pom.xml index e0db25db0..df507e892 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -155,7 +155,7 @@ com.github.GeyserMC MCProtocolLib - 3023c4d + bb2b414 compile diff --git a/core/src/main/resources/mappings b/core/src/main/resources/mappings index e13611fd9..99a1f8070 160000 --- a/core/src/main/resources/mappings +++ b/core/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit e13611fd97b1801d4c4b914cd409351a49d19537 +Subproject commit 99a1f8070e844d059454dacbb6e8b203521eed23 From 691d674f018ff25231a6bd018401e6bfc04e4e23 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Thu, 9 Jun 2022 21:40:54 -0400 Subject: [PATCH 70/72] Use PaperServerListPingEvent when available We need to support this or else events that exclusively use PaperServerListPingEvent will not see our call. Fixes https://github.com/GeyserMC/Geyser/issues/3003 --- .../spigot/GeyserPaperPingPassthrough.java | 105 ++++++++++++++++++ .../spigot/GeyserSpigotPingPassthrough.java | 2 +- .../platform/spigot/GeyserSpigotPlugin.java | 8 +- 3 files changed, 113 insertions(+), 2 deletions(-) create mode 100644 bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserPaperPingPassthrough.java 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 new file mode 100644 index 000000000..cbe063931 --- /dev/null +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserPaperPingPassthrough.java @@ -0,0 +1,105 @@ +/* + * 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; + +import com.destroystokyo.paper.event.server.PaperServerListPingEvent; +import com.destroystokyo.paper.network.StatusClient; +import com.destroystokyo.paper.profile.PlayerProfile; +import org.bukkit.Bukkit; +import org.geysermc.geyser.network.MinecraftProtocol; +import org.geysermc.geyser.ping.GeyserPingInfo; +import org.geysermc.geyser.ping.IGeyserPingPassthrough; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.net.InetSocketAddress; + +/** + * This class is used if possible, so listeners listening for PaperServerListPingEvent exclusively have their changes + * applied. + */ +public final class GeyserPaperPingPassthrough implements IGeyserPingPassthrough { + private final GeyserSpigotLogger logger; + + public GeyserPaperPingPassthrough(GeyserSpigotLogger logger) { + this.logger = logger; + } + + @Nullable + @Override + public GeyserPingInfo getPingInformation(InetSocketAddress inetSocketAddress) { + try { + // We'd rather *not* use deprecations here, but unfortunately any Adventure class would be relocated at + // runtime because we still have to shade in our own Adventure class. For now. + PaperServerListPingEvent event = new PaperServerListPingEvent(new GeyserStatusClient(inetSocketAddress), + Bukkit.getMotd(), Bukkit.getOnlinePlayers().size(), Bukkit.getMaxPlayers(), Bukkit.getVersion(), + MinecraftProtocol.getJavaProtocolVersion(), null); + Bukkit.getPluginManager().callEvent(event); + if (event.isCancelled()) { + // We have to send a ping, so not really sure what else to do here. + return null; + } + + GeyserPingInfo.Players players; + if (event.shouldHidePlayers()) { + players = new GeyserPingInfo.Players(1, 0); + } else { + players = new GeyserPingInfo.Players(event.getMaxPlayers(), event.getNumPlayers()); + } + + GeyserPingInfo geyserPingInfo = new GeyserPingInfo(event.getMotd(), players, + new GeyserPingInfo.Version(Bukkit.getVersion(), MinecraftProtocol.getJavaProtocolVersion())); + + if (!event.shouldHidePlayers()) { + for (PlayerProfile profile : event.getPlayerSample()) { + geyserPingInfo.getPlayerList().add(profile.getName()); + } + } + + return geyserPingInfo; + } catch (Exception e) { + logger.debug("Error while getting Paper ping passthrough: " + e); + return null; + } + } + + private record GeyserStatusClient(InetSocketAddress address) implements StatusClient { + @Override + public @NotNull InetSocketAddress getAddress() { + return address; + } + + @Override + public int getProtocolVersion() { + return MinecraftProtocol.getJavaProtocolVersion(); + } + + @Override + public @Nullable InetSocketAddress getVirtualHost() { + 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 19153b750..ae01190c0 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 @@ -30,8 +30,8 @@ import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.event.server.ServerListPingEvent; import org.bukkit.util.CachedServerIcon; -import org.geysermc.geyser.ping.GeyserPingInfo; import org.geysermc.geyser.network.MinecraftProtocol; +import org.geysermc.geyser.ping.GeyserPingInfo; import org.geysermc.geyser.ping.IGeyserPingPassthrough; import javax.annotation.Nonnull; 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 4b41ad569..cee38228c 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 @@ -167,8 +167,14 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { if (geyserConfig.isLegacyPingPassthrough()) { this.geyserSpigotPingPassthrough = GeyserLegacyPingPassthrough.init(geyser); } else { - this.geyserSpigotPingPassthrough = new GeyserSpigotPingPassthrough(geyserLogger); + try { + Class.forName("com.destroystokyo.paper.event.server.PaperServerListPingEvent"); + this.geyserSpigotPingPassthrough = new GeyserPaperPingPassthrough(geyserLogger); + } catch (ClassNotFoundException e) { + this.geyserSpigotPingPassthrough = new GeyserSpigotPingPassthrough(geyserLogger); + } } + geyserLogger.debug("Spigot ping passthrough type: " + (this.geyserSpigotPingPassthrough == null ? null : this.geyserSpigotPingPassthrough.getClass())); this.geyserCommandManager = new GeyserSpigotCommandManager(geyser); From 162aff49787286463189d304a45b683225119259 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Fri, 10 Jun 2022 10:27:07 -0400 Subject: [PATCH 71/72] Better handle chat packets sent before login --- .../geyser/session/GeyserSession.java | 11 +++++---- .../geyser/session/UpstreamSession.java | 22 ++++++++++++++++++ .../geysermc/geyser/text/ChatTypeEntry.java | 23 +++++++++++++++++++ .../protocol/java/JavaLoginTranslator.java | 3 +++ .../java/JavaSystemChatTranslator.java | 6 ++++- 5 files changed, 60 insertions(+), 5 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 e8490c240..c5fe7f2bf 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -37,7 +37,6 @@ import com.github.steveice10.mc.protocol.MinecraftProtocol; import com.github.steveice10.mc.protocol.codec.MinecraftCodecHelper; import com.github.steveice10.mc.protocol.data.ProtocolState; import com.github.steveice10.mc.protocol.data.UnexpectedEncryptionException; -import com.github.steveice10.mc.protocol.data.game.MessageType; 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; @@ -124,10 +123,12 @@ import org.geysermc.geyser.skin.FloodgateSkinUploader; import org.geysermc.geyser.text.ChatTypeEntry; 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.*; +import org.geysermc.geyser.util.ChunkUtils; +import org.geysermc.geyser.util.DimensionUtils; +import org.geysermc.geyser.util.LoginEncryptionUtils; +import org.geysermc.geyser.util.MathUtils; import javax.annotation.Nonnull; import java.net.ConnectException; @@ -337,7 +338,7 @@ public class GeyserSession implements GeyserConnection, CommandSender { */ private final Map dimensions = new Object2ObjectOpenHashMap<>(3); - private final Int2ObjectMap chatTypes = new Int2ObjectOpenHashMap<>(7); + private final Int2ObjectMap chatTypes = new Int2ObjectOpenHashMap<>(8); @Setter private int breakingBlock; @@ -548,6 +549,8 @@ public class GeyserSession implements GeyserConnection, CommandSender { this.playerEntity = new SessionPlayerEntity(this); collisionManager.updatePlayerBoundingBox(this.playerEntity.getPosition()); + ChatTypeEntry.applyDefaults(chatTypes); + this.playerInventory = new PlayerInventory(); this.openInventory = null; this.craftingRecipes = new Int2ObjectOpenHashMap<>(); diff --git a/core/src/main/java/org/geysermc/geyser/session/UpstreamSession.java b/core/src/main/java/org/geysermc/geyser/session/UpstreamSession.java index 060dcc7fb..3250faf64 100644 --- a/core/src/main/java/org/geysermc/geyser/session/UpstreamSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/UpstreamSession.java @@ -33,12 +33,15 @@ import lombok.RequiredArgsConstructor; import lombok.Setter; import java.net.InetSocketAddress; +import java.util.ArrayDeque; +import java.util.Queue; @RequiredArgsConstructor public class UpstreamSession { @Getter private final BedrockServerSession session; @Getter @Setter private boolean initialized = false; + private Queue postStartGamePackets = new ArrayDeque<>(); public void sendPacket(@NonNull BedrockPacket packet) { if (!isClosed()) { @@ -56,6 +59,25 @@ public class UpstreamSession { session.disconnect(reason); } + /** + * Queue a packet that must be delayed until after login. + */ + public void queuePostStartGamePacket(BedrockPacket packet) { + postStartGamePackets.add(packet); + } + + public void sendPostStartGamePackets() { + if (isClosed()) { + return; + } + + BedrockPacket packet; + while ((packet = postStartGamePackets.poll()) != null) { + session.sendPacket(packet); + } + postStartGamePackets = null; + } + public boolean isClosed() { return session.isClosed(); } 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 32be209ca..800eb6c0f 100644 --- a/core/src/main/java/org/geysermc/geyser/text/ChatTypeEntry.java +++ b/core/src/main/java/org/geysermc/geyser/text/ChatTypeEntry.java @@ -25,10 +25,33 @@ package org.geysermc.geyser.text; +import com.github.steveice10.mc.protocol.data.game.MessageType; import com.nukkitx.protocol.bedrock.packet.TextPacket; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import javax.annotation.Nonnull; import javax.annotation.Nullable; public record ChatTypeEntry(@Nonnull TextPacket.Type bedrockChatType, @Nullable TextDecoration textDecoration) { + private static final ChatTypeEntry CHAT = new ChatTypeEntry(TextPacket.Type.CHAT, null); + private static final ChatTypeEntry SYSTEM = new ChatTypeEntry(TextPacket.Type.CHAT, null); + private static final ChatTypeEntry TIP = new ChatTypeEntry(TextPacket.Type.CHAT, null); + private static final ChatTypeEntry RAW = new ChatTypeEntry(TextPacket.Type.CHAT, 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(MessageType.CHAT.ordinal(), CHAT); + chatTypes.put(MessageType.SYSTEM.ordinal(), SYSTEM); + chatTypes.put(MessageType.GAME_INFO.ordinal(), TIP); + chatTypes.put(MessageType.SAY_COMMAND.ordinal(), RAW); + chatTypes.put(MessageType.MSG_COMMAND.ordinal(), RAW); + chatTypes.put(MessageType.TEAM_MSG_COMMAND.ordinal(), RAW); + chatTypes.put(MessageType.EMOTE_COMMAND.ordinal(), RAW); + chatTypes.put(MessageType.TELLRAW_COMMAND.ordinal(), RAW); + } } 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 74d12bd19..cd26e53e5 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 @@ -115,6 +115,9 @@ public class JavaLoginTranslator extends PacketTranslator Date: Sat, 11 Jun 2022 10:03:19 +0200 Subject: [PATCH 72/72] Fixed plugin.yml for spigot --- .../spigot/src/main/resources/plugin.yml | 39 +------------------ 1 file changed, 1 insertion(+), 38 deletions(-) diff --git a/bootstrap/spigot/src/main/resources/plugin.yml b/bootstrap/spigot/src/main/resources/plugin.yml index 013b1d96c..e28b8981d 100644 --- a/bootstrap/spigot/src/main/resources/plugin.yml +++ b/bootstrap/spigot/src/main/resources/plugin.yml @@ -8,41 +8,4 @@ api-version: 1.13 commands: geyser: description: The main command for Geyser. - usage: /geyser -<<<<<<< HEAD -permissions: - geyser.command.help: - description: Shows help for all registered commands. - default: true - geyser.command.offhand: - description: Puts an items in your offhand. - default: true - geyser.command.advancements: - description: Shows the advancements of the player on the server. - default: true - geyser.command.tooltips: - description: Toggles showing advanced tooltips on your items. - default: true - geyser.command.statistics: - description: Shows the statistics of the player on the server. - default: true - geyser.command.settings: - description: Modify user settings - default: true - geyser.command.list: - description: List all players connected through Geyser. - default: op - geyser.command.dump: - description: Dumps Geyser debug information for bug reports. - default: op - geyser.command.reload: - description: Reloads the Geyser configurations. Kicks all players when used! - default: false - geyser.command.version: - description: Shows the current Geyser version and checks for updates. - default: op - geyser.command.extensions: - description: Shows all the loaded extensions. - default: op -======= ->>>>>>> 2595eae30070fa5d221ad505eef6a9e1606fb1d1 + usage: /geyser \ No newline at end of file