diff --git a/Jenkinsfile b/Jenkinsfile
index 7dfdaf30452..e7f2ec4e2c1 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -66,7 +66,7 @@ pipeline {
}
deleteDir()
withCredentials([string(credentialsId: 'geyser-discord-webhook', variable: 'DISCORD_WEBHOOK')]) {
- discordSend description: "**Build:** [${currentBuild.id}](${env.BUILD_URL})\n**Status:** [${currentBuild.currentResult}](${env.BUILD_URL})\n${changes}\n\n[**Artifacts on Jenkins**](https://ci.nukkitx.com/job/Geyser)", footer: 'Cloudburst Jenkins', link: env.BUILD_URL, successful: currentBuild.resultIsBetterOrEqualTo('SUCCESS'), title: "${env.JOB_NAME} #${currentBuild.id}", webhookURL: DISCORD_WEBHOOK
+ discordSend description: "**Build:** [${currentBuild.id}](${env.BUILD_URL})\n**Status:** [${currentBuild.currentResult}](${env.BUILD_URL})\n${changes}\n\n[**Artifacts on Jenkins**](https://ci.opencollab.dev/job/GeyserMC/job/Geyser)", footer: 'Open Collaboration Jenkins', link: env.BUILD_URL, successful: currentBuild.resultIsBetterOrEqualTo('SUCCESS'), title: "${env.JOB_NAME} #${currentBuild.id}", webhookURL: DISCORD_WEBHOOK
}
}
}
diff --git a/README.md b/README.md
index 2033a66ed13..816f765d6b2 100644
--- a/README.md
+++ b/README.md
@@ -3,7 +3,7 @@
[![forthebadge made-with-java](http://ForTheBadge.com/images/badges/made-with-java.svg)](https://java.com/)
[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
-[![Build Status](https://ci.nukkitx.com/job/Geyser/job/master/badge/icon)](https://ci.nukkitx.com/job/GeyserMC/job/Geyser/job/master/)
+[![Build Status](https://ci.opencollab.dev/job/Geyser/job/master/badge/icon)](https://ci.opencollab.dev/job/GeyserMC/job/Geyser/job/master/)
[![Discord](https://img.shields.io/discord/613163671870242838.svg?color=%237289da&label=discord)](http://discord.geysermc.org/)
[![HitCount](http://hits.dwyl.io/Geyser/GeyserMC.svg)](http://hits.dwyl.io/Geyser/GeyserMC)
[![Crowdin](https://badges.crowdin.net/geyser/localized.svg)](https://translate.geysermc.org/)
@@ -52,6 +52,8 @@ Take a look [here](https://github.com/GeyserMC/Geyser/wiki#Setup) for how to set
The following things can't be fixed because of Bedrock limitations. They might be fixable in the future, but not as of now.
- Custom heads in inventories
+- Clickable links in chat
+- Glowing effect
## Compiling
1. Clone the repo to your computer
diff --git a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigot1_12WorldManager.java b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigot1_12WorldManager.java
index b00ddafaa2b..bae9ca07559 100644
--- a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigot1_12WorldManager.java
+++ b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigot1_12WorldManager.java
@@ -125,7 +125,7 @@ public void getBlocksInSection(GeyserSession session, int x, int y, int z, Chunk
for (int blockY = 0; blockY < 16; blockY++) { // Cache-friendly iteration order
for (int blockZ = 0; blockZ < 16; blockZ++) {
for (int blockX = 0; blockX < 16; blockX++) {
- Block block = world.getBlockAt(x, y, z);
+ Block block = world.getBlockAt((x << 4) + blockX, (y << 4) + blockY, (z << 4) + blockZ);
// Black magic that gets the old block state ID
int blockId = (block.getType().getId() << 4) | (block.getData() & 0xF);
chunk.set(blockX, blockY, blockZ, getLegacyBlock(storage, blockId, (x << 4) + blockX, (y << 4) + blockY, (z << 4) + blockZ));
diff --git a/connector/pom.xml b/connector/pom.xml
index 5f578039427..60879effe4e 100644
--- a/connector/pom.xml
+++ b/connector/pom.xml
@@ -32,7 +32,7 @@
com.github.CloudburstMC.Protocol
bedrock-v422
- 87d862d69d
+ d41b84e86c
compile
@@ -124,14 +124,26 @@
26201a4
compile
-
- io.netty
- netty-all
-
net.kyori
adventure-text-serializer-gson
+
+ com.github.steveice10
+ packetlib
+
+
+
+
+ com.github.steveice10
+ PacketLib
+ 54f761c
+ compile
+
+
+ io.netty
+ netty-all
+
@@ -140,6 +152,12 @@
4.1.43.Final
compile
+
+ io.netty
+ netty-codec-haproxy
+ 4.1.56.Final
+ compile
+
org.reflections
reflections
diff --git a/connector/src/main/java/org/geysermc/connector/GeyserConnector.java b/connector/src/main/java/org/geysermc/connector/GeyserConnector.java
index 977c8aa910a..55af05f964b 100644
--- a/connector/src/main/java/org/geysermc/connector/GeyserConnector.java
+++ b/connector/src/main/java/org/geysermc/connector/GeyserConnector.java
@@ -46,6 +46,7 @@
import org.geysermc.connector.network.translators.BiomeTranslator;
import org.geysermc.connector.network.translators.EntityIdentifierRegistry;
import org.geysermc.connector.network.translators.PacketTranslatorRegistry;
+import org.geysermc.connector.network.translators.collision.CollisionTranslator;
import org.geysermc.connector.network.translators.effect.EffectRegistry;
import org.geysermc.connector.network.translators.item.ItemRegistry;
import org.geysermc.connector.network.translators.item.ItemTranslator;
@@ -56,7 +57,6 @@
import org.geysermc.connector.network.translators.world.WorldManager;
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
import org.geysermc.connector.network.translators.world.block.entity.BlockEntityTranslator;
-import org.geysermc.connector.network.translators.collision.CollisionTranslator;
import org.geysermc.connector.network.translators.world.block.entity.SkullBlockEntityTranslator;
import org.geysermc.connector.event.events.geyser.GeyserStopEvent;
import org.geysermc.connector.utils.DimensionUtils;
@@ -70,10 +70,7 @@
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.text.DecimalFormat;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
@@ -346,6 +343,38 @@ public void removePlayer(GeyserSession player) {
players.remove(player);
}
+ /**
+ * Gets a player by their current UUID
+ *
+ * @param uuid the uuid
+ * @return the player or null
if there is no player online with this UUID
+ */
+ public GeyserSession getPlayerByUuid(UUID uuid) {
+ for (GeyserSession session : players) {
+ if (session.getPlayerEntity().getUuid().equals(uuid)) {
+ return session;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Gets a player by their Xbox user identifier
+ *
+ * @param xuid the Xbox user identifier
+ * @return the player or null
if there is no player online with this xuid
+ */
+ public GeyserSession getPlayerByXuid(String xuid) {
+ for (GeyserSession session : players) {
+ if (session.getAuthData() != null && session.getAuthData().getXboxUUID().equals(xuid)) {
+ return session;
+ }
+ }
+
+ return null;
+ }
+
public static GeyserConnector start(PlatformType platformType, GeyserBootstrap bootstrap) {
return new GeyserConnector(platformType, bootstrap);
}
diff --git a/connector/src/main/java/org/geysermc/connector/command/defaults/VersionCommand.java b/connector/src/main/java/org/geysermc/connector/command/defaults/VersionCommand.java
index 562bc9fb594..88fab368399 100644
--- a/connector/src/main/java/org/geysermc/connector/command/defaults/VersionCommand.java
+++ b/connector/src/main/java/org/geysermc/connector/command/defaults/VersionCommand.java
@@ -71,7 +71,7 @@ public void execute(CommandSender sender, String[] args) {
Properties gitProp = new Properties();
gitProp.load(FileUtils.getResource("git.properties"));
- String buildXML = WebUtils.getBody("https://ci.nukkitx.com/job/GeyserMC/job/Geyser/job/" + URLEncoder.encode(gitProp.getProperty("git.branch"), StandardCharsets.UTF_8.toString()) + "/lastSuccessfulBuild/api/xml?xpath=//buildNumber");
+ String buildXML = WebUtils.getBody("https://ci.opencollab.dev/job/GeyserMC/job/Geyser/job/" + URLEncoder.encode(gitProp.getProperty("git.branch"), StandardCharsets.UTF_8.toString()) + "/lastSuccessfulBuild/api/xml?xpath=//buildNumber");
if (buildXML.startsWith("")) {
int latestBuildNum = Integer.parseInt(buildXML.replaceAll("<(\\\\)?(/)?buildNumber>", "").trim());
int buildNum = Integer.parseInt(gitProp.getProperty("git.build.number"));
diff --git a/connector/src/main/java/org/geysermc/connector/configuration/GeyserConfiguration.java b/connector/src/main/java/org/geysermc/connector/configuration/GeyserConfiguration.java
index dfa30ae92cf..a8044ef3209 100644
--- a/connector/src/main/java/org/geysermc/connector/configuration/GeyserConfiguration.java
+++ b/connector/src/main/java/org/geysermc/connector/configuration/GeyserConfiguration.java
@@ -34,7 +34,7 @@
public interface GeyserConfiguration {
- // Modify this when you update the config
+ // Modify this when you introduce breaking changes into the config
int CURRENT_CONFIG_VERSION = 4;
IBedrockConfiguration getBedrock();
@@ -117,6 +117,8 @@ interface IRemoteConfiguration {
void setPort(int port);
String getAuthType();
+
+ boolean isUseProxyProtocol();
}
interface IUserAuthenticationInfo {
diff --git a/connector/src/main/java/org/geysermc/connector/configuration/GeyserJacksonConfiguration.java b/connector/src/main/java/org/geysermc/connector/configuration/GeyserJacksonConfiguration.java
index 67fa04492ad..c403bdf1182 100644
--- a/connector/src/main/java/org/geysermc/connector/configuration/GeyserJacksonConfiguration.java
+++ b/connector/src/main/java/org/geysermc/connector/configuration/GeyserJacksonConfiguration.java
@@ -148,6 +148,9 @@ public static class RemoteConfiguration implements IRemoteConfiguration {
@Setter
@JsonProperty("auth-type")
private String authType = "online";
+
+ @JsonProperty("use-proxy-protocol")
+ private boolean useProxyProtocol = false;
}
@Getter
diff --git a/connector/src/main/java/org/geysermc/connector/entity/AreaEffectCloudEntity.java b/connector/src/main/java/org/geysermc/connector/entity/AreaEffectCloudEntity.java
index 308d2121a37..bffba186e69 100644
--- a/connector/src/main/java/org/geysermc/connector/entity/AreaEffectCloudEntity.java
+++ b/connector/src/main/java/org/geysermc/connector/entity/AreaEffectCloudEntity.java
@@ -29,6 +29,7 @@
import com.github.steveice10.mc.protocol.data.game.world.particle.Particle;
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.connector.entity.type.EntityType;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.effect.EffectRegistry;
@@ -45,6 +46,8 @@ public AreaEffectCloudEntity(long entityId, long geyserId, EntityType entityType
metadata.put(EntityData.AREA_EFFECT_CLOUD_RADIUS, 0.0f);
metadata.put(EntityData.AREA_EFFECT_CLOUD_CHANGE_RATE, -0.005f);
metadata.put(EntityData.AREA_EFFECT_CLOUD_CHANGE_ON_PICKUP, -0.5f);
+
+ metadata.getFlags().setFlag(EntityFlag.FIRE_IMMUNE, true);
}
@Override
diff --git a/connector/src/main/java/org/geysermc/connector/entity/ThrownPotionEntity.java b/connector/src/main/java/org/geysermc/connector/entity/ThrownPotionEntity.java
new file mode 100644
index 00000000000..e9ea5fd7f43
--- /dev/null
+++ b/connector/src/main/java/org/geysermc/connector/entity/ThrownPotionEntity.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.connector.entity;
+
+import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
+import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
+import com.github.steveice10.mc.protocol.data.game.entity.metadata.MetadataType;
+import com.github.steveice10.opennbt.tag.builtin.StringTag;
+import com.github.steveice10.opennbt.tag.builtin.Tag;
+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.connector.GeyserConnector;
+import org.geysermc.connector.entity.type.EntityType;
+import org.geysermc.connector.network.session.GeyserSession;
+import org.geysermc.connector.network.translators.item.ItemEntry;
+import org.geysermc.connector.network.translators.item.ItemRegistry;
+import org.geysermc.connector.network.translators.item.Potion;
+
+import java.util.EnumSet;
+
+public class ThrownPotionEntity extends ThrowableEntity {
+ private static final EnumSet NON_ENCHANTED_POTIONS = EnumSet.of(Potion.WATER, Potion.MUNDANE, Potion.THICK, Potion.AWKWARD);
+
+ public ThrownPotionEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
+ super(entityId, geyserId, entityType, position, motion, rotation);
+ }
+
+ @Override
+ public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
+ if (entityMetadata.getId() == 7 && entityMetadata.getType() == MetadataType.ITEM) {
+ ItemStack itemStack = (ItemStack) entityMetadata.getValue();
+ ItemEntry itemEntry = ItemRegistry.getItem(itemStack);
+ if (itemEntry.getJavaIdentifier().endsWith("potion") && itemStack.getNbt() != null) {
+ Tag potionTag = itemStack.getNbt().get("Potion");
+ if (potionTag instanceof StringTag) {
+ Potion potion = Potion.getByJavaIdentifier(((StringTag) potionTag).getValue());
+ if (potion != null) {
+ metadata.put(EntityData.POTION_AUX_VALUE, potion.getBedrockId());
+ metadata.getFlags().setFlag(EntityFlag.ENCHANTED, !NON_ENCHANTED_POTIONS.contains(potion));
+ } else {
+ metadata.put(EntityData.POTION_AUX_VALUE, 0);
+ GeyserConnector.getInstance().getLogger().debug("Unknown java potion: " + potionTag.getValue());
+ }
+ }
+
+ boolean isLingering = itemEntry.getJavaIdentifier().equals("minecraft:lingering_potion");
+ metadata.getFlags().setFlag(EntityFlag.LINGERING, isLingering);
+ }
+ }
+
+ super.updateBedrockMetadata(entityMetadata, session);
+ }
+}
diff --git a/connector/src/main/java/org/geysermc/connector/entity/type/EntityType.java b/connector/src/main/java/org/geysermc/connector/entity/type/EntityType.java
index 3e6b6c72d10..79a69d6481a 100644
--- a/connector/src/main/java/org/geysermc/connector/entity/type/EntityType.java
+++ b/connector/src/main/java/org/geysermc/connector/entity/type/EntityType.java
@@ -123,7 +123,7 @@ public enum EntityType {
PAINTING(PaintingEntity.class, 83, 0f),
MINECART(MinecartEntity.class, 84, 0.7f, 0.98f, 0.98f, 0.35f),
FIREBALL(ItemedFireballEntity.class, 85, 1.0f),
- THROWN_POTION(ThrowableEntity.class, 86, 0.25f, 0.25f, 0.25f, 0f, "minecraft:splash_potion"),
+ THROWN_POTION(ThrownPotionEntity.class, 86, 0.25f, 0.25f, 0.25f, 0f, "minecraft:splash_potion"),
THROWN_ENDERPEARL(ThrowableEntity.class, 87, 0.25f, 0.25f, 0.25f, 0f, "minecraft:ender_pearl"),
LEASH_KNOT(LeashKnotEntity.class, 88, 0.5f, 0.375f),
WITHER_SKULL(WitherSkullEntity.class, 89, 0.3125f),
diff --git a/connector/src/main/java/org/geysermc/connector/network/LoggingPacketHandler.java b/connector/src/main/java/org/geysermc/connector/network/LoggingPacketHandler.java
index 7f52eb2d920..bfff1b3d3b1 100644
--- a/connector/src/main/java/org/geysermc/connector/network/LoggingPacketHandler.java
+++ b/connector/src/main/java/org/geysermc/connector/network/LoggingPacketHandler.java
@@ -132,11 +132,6 @@ public boolean handle(EntityEventPacket packet) {
return defaultHandler(packet);
}
- @Override
- public boolean handle(EntityFallPacket packet) {
- return defaultHandler(packet);
- }
-
@Override
public boolean handle(EntityPickRequestPacket packet) {
return defaultHandler(packet);
@@ -826,4 +821,43 @@ public boolean handle(PositionTrackingDBClientRequestPacket packet) {
public boolean handle(PositionTrackingDBServerBroadcastPacket packet) {
return defaultHandler(packet);
}
+
+ // 1.16.100 new packets
+
+ @Override
+ public boolean handle(MotionPredictionHintsPacket packet) {
+ return defaultHandler(packet);
+ }
+
+ @Override
+ public boolean handle(AnimateEntityPacket packet) {
+ return defaultHandler(packet);
+ }
+
+ @Override
+ public boolean handle(CameraShakePacket packet) {
+ return defaultHandler(packet);
+ }
+
+ @Override
+ public boolean handle(PlayerFogPacket packet) {
+ return defaultHandler(packet);
+ }
+
+ @Override
+ public boolean handle(CorrectPlayerMovePredictionPacket packet) {
+ return defaultHandler(packet);
+ }
+
+ @Override
+ public boolean handle(ItemComponentPacket packet) {
+ return defaultHandler(packet);
+ }
+
+ // 1.16.200 new packet
+
+ @Override
+ public boolean handle(FilterTextPacket packet) {
+ return defaultHandler(packet);
+ }
}
\ No newline at end of file
diff --git a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java
index 7e2bce109a6..188fb95f6f5 100644
--- a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java
+++ b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java
@@ -40,6 +40,7 @@
import com.github.steveice10.mc.protocol.packet.ingame.client.world.ClientTeleportConfirmPacket;
import com.github.steveice10.mc.protocol.packet.ingame.server.ServerRespawnPacket;
import com.github.steveice10.mc.protocol.packet.login.server.LoginSuccessPacket;
+import com.github.steveice10.packetlib.BuiltinFlags;
import com.github.steveice10.packetlib.Client;
import com.github.steveice10.packetlib.event.session.*;
import com.github.steveice10.packetlib.packet.Packet;
@@ -260,6 +261,12 @@ public class GeyserSession implements CommandSender {
@Setter
private ScheduledFuture> movementSendIfIdle;
+ /**
+ * Controls whether the daylight cycle gamerule has been sent to the client, so the sun/moon remain motionless.
+ */
+ @Setter
+ private boolean daylightCycle = true;
+
private boolean reducedDebugInfo = false;
@Setter
@@ -479,6 +486,10 @@ public void authenticate(String username, String password) {
}
downstream = new Client(remoteServer.getAddress(), remoteServer.getPort(), protocol, new TcpSessionFactory());
+ if (connector.getConfig().getRemote().isUseProxyProtocol()) {
+ downstream.getSession().setFlag(BuiltinFlags.ENABLE_CLIENT_PROXY_PROTOCOL, true);
+ downstream.getSession().setFlag(BuiltinFlags.CLIENT_PROXIED_ADDRESS, upstream.getAddress());
+ }
// Let Geyser handle sending the keep alive
downstream.getSession().setFlag(MinecraftConstants.AUTOMATIC_KEEP_ALIVE_MANAGEMENT, false);
downstream.getSession().addListener(new SessionAdapter() {
@@ -685,7 +696,6 @@ public void sendForm(FormWindow window, int id) {
public void setRenderDistance(int renderDistance) {
renderDistance = GenericMath.ceil(++renderDistance * MathUtils.SQRT_OF_TWO); //square to circle
- if (renderDistance > 32) renderDistance = 32; // <3 u ViaVersion but I don't like crashing clients x)
this.renderDistance = renderDistance;
ChunkRadiusUpdatedPacket chunkRadiusUpdatedPacket = new ChunkRadiusUpdatedPacket();
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockBlockPickRequestTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockBlockPickRequestTranslator.java
index 3e40ddd6f4c..f7e3fbd9c3f 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockBlockPickRequestTranslator.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockBlockPickRequestTranslator.java
@@ -46,7 +46,6 @@ public void translate(BlockPickRequestPacket packet, GeyserSession session) {
return;
}
- String targetIdentifier = BlockTranslator.getJavaIdBlockMap().inverse().get(blockToPick).split("\\[")[0];
- InventoryUtils.findOrCreatePickedBlock(session, targetIdentifier);
+ InventoryUtils.findOrCreateItem(session, BlockTranslator.getPickItem(blockToPick));
}
}
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockEntityPickRequestTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockEntityPickRequestTranslator.java
index 4aa044ee452..d03aa7b738b 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockEntityPickRequestTranslator.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockEntityPickRequestTranslator.java
@@ -110,6 +110,6 @@ public void translate(EntityPickRequestPacket packet, GeyserSession session) {
// Verify it is, indeed, an item
if (entry == null) return;
- InventoryUtils.findOrCreatePickedBlock(session, fullItemName);
+ InventoryUtils.findOrCreateItem(session, fullItemName);
}
}
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockFilterTextTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockFilterTextTranslator.java
new file mode 100644
index 00000000000..8c963076483
--- /dev/null
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockFilterTextTranslator.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.connector.network.translators.bedrock;
+
+import com.nukkitx.protocol.bedrock.packet.FilterTextPacket;
+import org.geysermc.connector.network.session.GeyserSession;
+import org.geysermc.connector.network.translators.PacketTranslator;
+import org.geysermc.connector.network.translators.Translator;
+
+/**
+ * Used to send strings to the server and filter out unwanted words.
+ * Java doesn't care, so we don't care, and we approve all strings.
+ */
+@Translator(packet = FilterTextPacket.class)
+public class BedrockFilterTextTranslator extends PacketTranslator {
+
+ @Override
+ public void translate(FilterTextPacket packet, GeyserSession session) {
+ packet.setFromServer(true);
+ session.sendUpstreamPacket(packet);
+ }
+}
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockTextTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockTextTranslator.java
index e4a76569445..955a9a539ec 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockTextTranslator.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockTextTranslator.java
@@ -38,7 +38,7 @@ public class BedrockTextTranslator extends PacketTranslator {
@Override
public void translate(TextPacket packet, GeyserSession session) {
- String message = packet.getMessage().replaceAll("^\\.", "/").trim();
+ String message = packet.getMessage();
if (MessageTranslator.isTooLong(message, session)) {
return;
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/BannerTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/BannerTranslator.java
index 14b9343622f..5e5bc354224 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/BannerTranslator.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/BannerTranslator.java
@@ -45,8 +45,39 @@
@ItemRemapper
public class BannerTranslator extends ItemTranslator {
+ /**
+ * Holds what a Java ominous banner pattern looks like.
+ *
+ * Translating the patterns over to Bedrock does not work effectively, but Bedrock has a dedicated type for
+ * ominous banners that we set instead. This variable is used to detect Java ominous banner patterns, and apply
+ * the correct ominous banner pattern if Bedrock pulls the item from creative.
+ */
+ public static final ListTag OMINOUS_BANNER_PATTERN;
+
private final List appliedItems;
+ static {
+ OMINOUS_BANNER_PATTERN = new ListTag("Patterns");
+ // Construct what an ominous banner is supposed to look like
+ OMINOUS_BANNER_PATTERN.add(getPatternTag("mr", 9));
+ OMINOUS_BANNER_PATTERN.add(getPatternTag("bs", 8));
+ OMINOUS_BANNER_PATTERN.add(getPatternTag("cs", 7));
+ OMINOUS_BANNER_PATTERN.add(getPatternTag("bo", 8));
+ OMINOUS_BANNER_PATTERN.add(getPatternTag("ms", 15));
+ OMINOUS_BANNER_PATTERN.add(getPatternTag("hh", 8));
+ OMINOUS_BANNER_PATTERN.add(getPatternTag("mc", 8));
+ OMINOUS_BANNER_PATTERN.add(getPatternTag("bo", 15));
+ }
+
+ private static CompoundTag getPatternTag(String pattern, int color) {
+ StringTag patternType = new StringTag("Pattern", pattern);
+ IntTag colorTag = new IntTag("Color", color);
+ CompoundTag tag = new CompoundTag("");
+ tag.put(patternType);
+ tag.put(colorTag);
+ return tag;
+ }
+
public BannerTranslator() {
appliedItems = ItemRegistry.ITEM_ENTRIES.values()
.stream()
@@ -62,7 +93,7 @@ public BannerTranslator() {
*/
public static NbtList convertBannerPattern(ListTag patterns) {
List tagsList = new ArrayList<>();
- for (com.github.steveice10.opennbt.tag.builtin.Tag patternTag : patterns.getValue()) {
+ for (Tag patternTag : patterns.getValue()) {
NbtMap newPatternTag = getBedrockBannerPattern((CompoundTag) patternTag);
if (newPatternTag != null) {
tagsList.add(newPatternTag);
@@ -134,7 +165,13 @@ public ItemData translateToBedrock(ItemStack itemStack, ItemEntry itemEntry) {
ListTag patterns = blockEntityTag.get("Patterns");
NbtMapBuilder builder = itemData.getTag().toBuilder();
- builder.put("Patterns", convertBannerPattern(patterns));
+ if (patterns.equals(OMINOUS_BANNER_PATTERN)) {
+ // Remove the current patterns and set the ominous banner type
+ builder.remove("Patterns");
+ builder.putInt("Type", 1);
+ } else {
+ builder.put("Patterns", convertBannerPattern(patterns));
+ }
itemData = ItemData.of(itemData.getId(), itemData.getDamage(), itemData.getCount(), builder.build());
}
@@ -151,7 +188,14 @@ public ItemStack translateToJava(ItemData itemData, ItemEntry itemEntry) {
ItemStack itemStack = super.translateToJava(itemData, itemEntry);
NbtMap nbtTag = itemData.getTag();
- if (nbtTag.containsKey("Patterns", NbtType.COMPOUND)) {
+ if (nbtTag.containsKey("Type", NbtType.INT) && nbtTag.getInt("Type") == 1) {
+ // Ominous banner pattern
+ itemStack.getNbt().remove("Type");
+ CompoundTag blockEntityTag = new CompoundTag("BlockEntityTag");
+ blockEntityTag.put(OMINOUS_BANNER_PATTERN);
+
+ itemStack.getNbt().put(blockEntityTag);
+ } else if (nbtTag.containsKey("Patterns", NbtType.COMPOUND)) {
List patterns = nbtTag.getList("Patterns", NbtType.COMPOUND);
CompoundTag blockEntityTag = new CompoundTag("BlockEntityTag");
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareCommandsTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareCommandsTranslator.java
index 8f52433665f..2247b55be15 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareCommandsTranslator.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareCommandsTranslator.java
@@ -52,9 +52,14 @@ public class JavaDeclareCommandsTranslator extends PacketTranslator commandData = new ArrayList<>();
Int2ObjectMap commands = new Int2ObjectOpenHashMap<>();
Int2ObjectMap> commandArgs = new Int2ObjectOpenHashMap<>();
@@ -83,14 +88,14 @@ public void translate(ServerDeclareCommandsPacket packet, GeyserSession session)
}
// The command flags, not sure what these do apart from break things
- List flags = new ArrayList<>();
+ List flags = Collections.emptyList();
// Loop through all the found commands
for (int commandID : commands.keySet()) {
String commandName = commands.get(commandID);
// Create a basic alias
- CommandEnumData aliases = new CommandEnumData( commandName + "Aliases", new String[] { commandName.toLowerCase() }, false);
+ CommandEnumData aliases = new CommandEnumData(commandName + "Aliases", new String[] { commandName.toLowerCase() }, false);
// Get and parse all params
CommandParamData[][] params = getParams(packet.getNodes()[commandID], packet.getNodes());
@@ -102,9 +107,7 @@ public void translate(ServerDeclareCommandsPacket packet, GeyserSession session)
// Add our commands to the AvailableCommandsPacket for the bedrock client
AvailableCommandsPacket availableCommandsPacket = new AvailableCommandsPacket();
- for (CommandData data : commandData) {
- availableCommandsPacket.getCommands().add(data);
- }
+ availableCommandsPacket.getCommands().addAll(commandData);
GeyserConnector.getInstance().getLogger().debug("Sending command packet of " + commandData.size() + " commands");
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityStatusTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityStatusTranslator.java
index 8c84a5c9772..8b68bf61fbb 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityStatusTranslator.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityStatusTranslator.java
@@ -89,6 +89,7 @@ public void translate(ServerEntityStatusPacket packet, GeyserSession session) {
case LIVING_DROWN:
case LIVING_HURT:
case LIVING_HURT_SWEET_BERRY_BUSH:
+ case LIVING_HURT_THORNS:
entityEventPacket.setType(EntityEventType.HURT);
break;
case LIVING_DEATH:
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaPlayBuiltinSoundTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaPlayBuiltinSoundTranslator.java
index d849c917935..1c057f45f3e 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaPlayBuiltinSoundTranslator.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaPlayBuiltinSoundTranslator.java
@@ -34,8 +34,8 @@
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.PacketTranslator;
import org.geysermc.connector.network.translators.Translator;
-import org.geysermc.connector.network.translators.world.block.BlockTranslator;
import org.geysermc.connector.network.translators.sound.SoundRegistry;
+import org.geysermc.connector.network.translators.world.block.BlockTranslator;
@Translator(packet = ServerPlayBuiltinSoundPacket.class)
public class JavaPlayBuiltinSoundTranslator extends PacketTranslator {
@@ -82,7 +82,11 @@ public void translate(ServerPlayBuiltinSoundPacket packet, GeyserSession session
// 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) {
- soundPacket.setExtraData(BlockTranslator.getBedrockBlockId(BlockTranslator.getJavaBlockState(soundMapping.getIdentifier())));
+ if (!soundMapping.getIdentifier().equals(":")) {
+ soundPacket.setExtraData(BlockTranslator.getBedrockBlockId(BlockTranslator.getJavaBlockState(soundMapping.getIdentifier())));
+ } else {
+ session.getConnector().getLogger().debug("PLACE sound mapping identifier was invalid! Please report: " + packet.toString());
+ }
soundPacket.setIdentifier(":");
} else {
soundPacket.setExtraData(soundMapping.getExtraData());
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaUpdateTimeTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaUpdateTimeTranslator.java
index 8dc68918550..dff78697f74 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaUpdateTimeTranslator.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaUpdateTimeTranslator.java
@@ -25,49 +25,38 @@
package org.geysermc.connector.network.translators.java.world;
-import com.nukkitx.protocol.bedrock.data.GameRuleData;
-import com.nukkitx.protocol.bedrock.packet.GameRulesChangedPacket;
-import it.unimi.dsi.fastutil.longs.Long2LongMap;
-import it.unimi.dsi.fastutil.longs.Long2LongOpenHashMap;
+import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerUpdateTimePacket;
+import com.nukkitx.protocol.bedrock.packet.SetTimePacket;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.PacketTranslator;
import org.geysermc.connector.network.translators.Translator;
-import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerUpdateTimePacket;
-import com.nukkitx.protocol.bedrock.packet.SetTimePacket;
-
@Translator(packet = ServerUpdateTimePacket.class)
public class JavaUpdateTimeTranslator extends PacketTranslator {
- // If negative, the last time is stored so we know it's not some plugin behavior doing weird things.
- // Per-player for multi-world support
- private static final Long2LongMap LAST_RECORDED_TIMES = new Long2LongOpenHashMap();
-
@Override
public void translate(ServerUpdateTimePacket packet, GeyserSession session) {
-
// Bedrock sends a GameRulesChangedPacket if there is no daylight cycle
// Java just sends a negative long if there is no daylight cycle
- long lastTime = LAST_RECORDED_TIMES.getOrDefault(session.getPlayerEntity().getEntityId(), 0);
long time = packet.getTime();
- if (lastTime != time) {
- // https://minecraft.gamepedia.com/Day-night_cycle#24-hour_Minecraft_day
- SetTimePacket setTimePacket = new SetTimePacket();
- setTimePacket.setTime((int) Math.abs(time) % 24000);
- session.sendUpstreamPacket(setTimePacket);
- // TODO: Performance efficient to always do this?
- LAST_RECORDED_TIMES.put(session.getPlayerEntity().getEntityId(), time);
- }
- if (lastTime < 0 && time >= 0) {
+ // https://minecraft.gamepedia.com/Day-night_cycle#24-hour_Minecraft_day
+ SetTimePacket setTimePacket = new SetTimePacket();
+ setTimePacket.setTime((int) Math.abs(time) % 24000);
+ session.sendUpstreamPacket(setTimePacket);
+ if (!session.isDaylightCycle() && time >= 0) {
+ // Client thinks there is no daylight cycle but there is
setDoDaylightCycleGamerule(session, true);
- } else if (lastTime != time && time < 0) {
+ } else if (session.isDaylightCycle() && time < 0) {
+ // Client thinks there is daylight cycle but there isn't
setDoDaylightCycleGamerule(session, false);
}
}
private void setDoDaylightCycleGamerule(GeyserSession session, boolean doCycle) {
session.sendGameRule("dodaylightcycle", doCycle);
+ // Save the value so we don't have to constantly send a daylight cycle gamerule update
+ session.setDaylightCycle(doCycle);
}
}
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/BlockTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/BlockTranslator.java
index e84dccf0483..c32cbf527aa 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/BlockTranslator.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/BlockTranslator.java
@@ -30,7 +30,10 @@
import com.google.common.collect.HashBiMap;
import com.nukkitx.nbt.*;
import it.unimi.dsi.fastutil.ints.*;
-import it.unimi.dsi.fastutil.objects.*;
+import it.unimi.dsi.fastutil.objects.Object2IntMap;
+import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
+import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
+import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.event.EventManager;
import org.geysermc.connector.event.events.registry.BlockEntityRegistryEvent;
@@ -68,8 +71,6 @@ public class BlockTranslator {
// Bedrock carpet ID, used in LlamaEntity.java for decoration
public static final int CARPET = 171;
- public static final Int2ObjectMap JAVA_ID_TO_BLOCK_ENTITY_MAP = new Int2ObjectOpenHashMap<>();
-
public static final Int2DoubleMap JAVA_RUNTIME_ID_TO_HARDNESS = new Int2DoubleOpenHashMap();
public static final Int2BooleanMap JAVA_RUNTIME_ID_TO_CAN_HARVEST_WITH_HAND = new Int2BooleanOpenHashMap();
public static final Int2ObjectMap JAVA_RUNTIME_ID_TO_TOOL_TYPE = new Int2ObjectOpenHashMap<>();
@@ -77,6 +78,8 @@ public class BlockTranslator {
// The index of the collision data in collision.json
public static final Int2IntMap JAVA_RUNTIME_ID_TO_COLLISION_INDEX = new Int2IntOpenHashMap();
+ private static final Int2ObjectMap JAVA_RUNTIME_ID_TO_PICK_ITEM = new Int2ObjectOpenHashMap<>();
+
/**
* Java numeric ID to java unique identifier, used for block names in the statistics screen
*/
@@ -143,11 +146,6 @@ public class BlockTranslator {
addedStatesMap.defaultReturnValue(-1);
List paletteList = new ArrayList<>();
- Reflections ref = GeyserConnector.getInstance().useXmlReflections() ? FileUtils.getReflections("org.geysermc.connector.network.translators.world.block.entity") : new Reflections("org.geysermc.connector.network.translators.world.block.entity");
- Set> blockEntityClasses = EventManager.getInstance().triggerEvent(new BlockEntityRegistryEvent(
- ref.getTypesAnnotatedWith(BlockEntity.class)
- )).getEvent().getRegisteredTranslators();
-
int waterRuntimeId = -1;
int javaRuntimeId = -1;
int airRuntimeId = -1;
@@ -196,20 +194,13 @@ public class BlockTranslator {
JAVA_RUNTIME_ID_TO_COLLISION_INDEX.put(javaRuntimeId, collisionIndexNode.intValue());
}
- JAVA_ID_BLOCK_MAP.put(javaId, javaRuntimeId);
-
- // Used for adding all "special" Java block states to block state map
- String identifier;
- String bedrockIdentifier = entry.getValue().get("bedrock_identifier").asText();
- for (Class> clazz : blockEntityClasses) {
- identifier = clazz.getAnnotation(BlockEntity.class).regex();
- // Endswith, or else the block bedrock gets picked up for bed
- if (bedrockIdentifier.endsWith(identifier) && !identifier.equals("")) {
- JAVA_ID_TO_BLOCK_ENTITY_MAP.put(javaRuntimeId, clazz.getAnnotation(BlockEntity.class).name());
- break;
- }
+ JsonNode pickItemNode = entry.getValue().get("pick_item");
+ if (pickItemNode != null) {
+ JAVA_RUNTIME_ID_TO_PICK_ITEM.put(javaRuntimeId, pickItemNode.textValue());
}
+ JAVA_ID_BLOCK_MAP.put(javaId, javaRuntimeId);
+
BlockStateValues.storeBlockStateValues(entry, javaRuntimeId);
String cleanJavaIdentifier = entry.getKey().split("\\[")[0];
@@ -219,6 +210,8 @@ public class BlockTranslator {
JAVA_ID_TO_JAVA_IDENTIFIER_MAP.put(uniqueJavaId, cleanJavaIdentifier);
}
+ String bedrockIdentifier = entry.getValue().get("bedrock_identifier").asText();
+
if (!cleanJavaIdentifier.equals(bedrockIdentifier)) {
JAVA_TO_BEDROCK_IDENTIFIERS.put(cleanJavaIdentifier, bedrockIdentifier);
}
@@ -375,12 +368,12 @@ public static int getBlockStateVersion() {
return BLOCK_STATE_VERSION;
}
+ /**
+ * @param javaId the Java string identifier to search for
+ * @return the Java block state integer, or {@link #JAVA_AIR_ID} if there is no valid entry.
+ */
public static int getJavaBlockState(String javaId) {
- return JAVA_ID_BLOCK_MAP.get(javaId);
- }
-
- public static String getBlockEntityString(int javaId) {
- return JAVA_ID_TO_BLOCK_ENTITY_MAP.get(javaId);
+ return JAVA_ID_BLOCK_MAP.getOrDefault(javaId, JAVA_AIR_ID);
}
public static boolean isWaterlogged(int state) {
@@ -394,4 +387,19 @@ public static BiMap getJavaIdBlockMap() {
public static int getJavaWaterloggedState(int bedrockId) {
return BEDROCK_TO_JAVA_BLOCK_MAP.get(1 << 31 | bedrockId);
}
+
+ /**
+ * Get the item a Java client would receive when pressing
+ * the Pick Block key on a specific Java block state.
+ *
+ * @param javaId The Java runtime id of the block
+ * @return The Java identifier of the item
+ */
+ public static String getPickItem(int javaId) {
+ String itemIdentifier = JAVA_RUNTIME_ID_TO_PICK_ITEM.get(javaId);
+ if (itemIdentifier == null) {
+ return JAVA_ID_BLOCK_MAP.inverse().get(javaId).split("\\[")[0];
+ }
+ return itemIdentifier;
+ }
}
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BannerBlockEntityTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BannerBlockEntityTranslator.java
index f5e1d5948c5..b59794796f4 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BannerBlockEntityTranslator.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BannerBlockEntityTranslator.java
@@ -47,7 +47,13 @@ public void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState)
if (tag.contains("Patterns")) {
ListTag patterns = tag.get("Patterns");
- builder.put("Patterns", BannerTranslator.convertBannerPattern(patterns));
+ if (patterns.equals(BannerTranslator.OMINOUS_BANNER_PATTERN)) {
+ // This is an ominous banner; don't try to translate the raw patterns (it doesn't translate correctly)
+ // and tell the Bedrock client that this is an ominous banner
+ builder.putInt("Type", 1);
+ } else {
+ builder.put("Patterns", BannerTranslator.convertBannerPattern(patterns));
+ }
}
if (tag.contains("CustomName")) {
diff --git a/connector/src/main/java/org/geysermc/connector/skin/SkinManager.java b/connector/src/main/java/org/geysermc/connector/skin/SkinManager.java
index 70b5a29856d..e23b4b52386 100644
--- a/connector/src/main/java/org/geysermc/connector/skin/SkinManager.java
+++ b/connector/src/main/java/org/geysermc/connector/skin/SkinManager.java
@@ -83,11 +83,10 @@ public static PlayerListPacket.Entry buildEntryManually(GeyserSession session, U
// This attempts to find the xuid of the player so profile images show up for xbox accounts
String xuid = "";
- for (GeyserSession player : GeyserConnector.getInstance().getPlayers()) {
- if (player.getPlayerEntity().getUuid() != null && player.getPlayerEntity().getUuid().equals(uuid)) {
- xuid = player.getAuthData().getXboxUUID();
- break;
- }
+ GeyserSession player = GeyserConnector.getInstance().getPlayerByUuid(uuid);
+
+ if (player.getPlayerEntity().getUuid() != null && player != null) {
+ xuid = player.getAuthData().getXboxUUID();
}
PlayerListPacket.Entry entry;
@@ -274,11 +273,10 @@ public static GameProfileData from(GameProfile profile) {
// return default skin with default cape when texture data is invalid
String skinUrl = isAlex ? SkinProvider.EMPTY_SKIN_ALEX.getTextureUrl() : SkinProvider.EMPTY_SKIN.getTextureUrl();
if ("steve".equals(skinUrl) || "alex".equals(skinUrl)) {
- for (GeyserSession session : GeyserConnector.getInstance().getPlayers()) {
- if (session.getPlayerEntity().getUuid() != null && session.getPlayerEntity().getUuid().equals(profile.getId())) {
- skinUrl = session.getClientData().getSkinId();
- break;
- }
+ GeyserSession session = GeyserConnector.getInstance().getPlayerByUuid(profile.getId());
+
+ if (session.getPlayerEntity().getUuid() != null && session != null) {
+ skinUrl = session.getClientData().getSkinId();
}
}
return new GameProfileData(skinUrl, SkinProvider.EMPTY_CAPE.getTextureUrl(), isAlex);
diff --git a/connector/src/main/java/org/geysermc/connector/skin/SkinProvider.java b/connector/src/main/java/org/geysermc/connector/skin/SkinProvider.java
index 117198685a5..948e4b37447 100644
--- a/connector/src/main/java/org/geysermc/connector/skin/SkinProvider.java
+++ b/connector/src/main/java/org/geysermc/connector/skin/SkinProvider.java
@@ -144,12 +144,10 @@ public static CompletableFuture requestSkinAndCape(UUID playerId, S
String newSkinUrl = skinUrl;
if ("steve".equals(skinUrl) || "alex".equals(skinUrl)) {
- // TODO: Don't have a for loop for this? Have a proper map?
- for (GeyserSession session : GeyserConnector.getInstance().getPlayers()) {
- if (session.getPlayerEntity().getUuid().equals(playerId)) {
- newSkinUrl = session.getClientData().getSkinId();
- break;
- }
+ GeyserSession session = GeyserConnector.getInstance().getPlayerByUuid(playerId);
+
+ if (session != null) {
+ newSkinUrl = session.getClientData().getSkinId();
}
}
diff --git a/connector/src/main/java/org/geysermc/connector/utils/InventoryUtils.java b/connector/src/main/java/org/geysermc/connector/utils/InventoryUtils.java
index c1224e6e255..75bd7c94ef7 100644
--- a/connector/src/main/java/org/geysermc/connector/utils/InventoryUtils.java
+++ b/connector/src/main/java/org/geysermc/connector/utils/InventoryUtils.java
@@ -46,6 +46,7 @@
import org.geysermc.connector.network.translators.item.ItemEntry;
import org.geysermc.connector.network.translators.item.ItemRegistry;
import org.geysermc.connector.network.translators.item.ItemTranslator;
+import org.geysermc.connector.network.translators.world.block.BlockTranslator;
import java.util.Collections;
import java.util.Objects;
@@ -168,13 +169,17 @@ public static ItemData createUnusableSpaceBlock(String description) {
* @param session the Bedrock client's session
* @param itemName the Java identifier of the item to search/select
*/
- public static void findOrCreatePickedBlock(GeyserSession session, String itemName) {
+ public static void findOrCreateItem(GeyserSession session, String itemName) {
// Get the inventory to choose a slot to pick
Inventory inventory = session.getInventoryCache().getOpenInventory();
if (inventory == null) {
inventory = session.getInventory();
}
+ if (itemName.equals("minecraft:air")) {
+ return;
+ }
+
// Check hotbar for item
for (int i = 36; i < 45; i++) {
if (inventory.getItem(i) == null) {
@@ -219,12 +224,17 @@ public static void findOrCreatePickedBlock(GeyserSession session, String itemNam
}
}
- ClientCreativeInventoryActionPacket actionPacket = new ClientCreativeInventoryActionPacket(slot,
- new ItemStack(ItemRegistry.getItemEntry(itemName).getJavaId()));
- if ((slot - 36) != session.getInventory().getHeldItemSlot()) {
- setHotbarItem(session, slot);
+ ItemEntry entry = ItemRegistry.getItemEntry(itemName);
+ if (entry != null) {
+ ClientCreativeInventoryActionPacket actionPacket = new ClientCreativeInventoryActionPacket(slot,
+ new ItemStack(entry.getJavaId()));
+ if ((slot - 36) != session.getInventory().getHeldItemSlot()) {
+ setHotbarItem(session, slot);
+ }
+ session.sendDownstreamPacket(actionPacket);
+ } else {
+ session.getConnector().getLogger().debug("Cannot find item for block " + itemName);
}
- session.sendDownstreamPacket(actionPacket);
}
}
diff --git a/connector/src/main/resources/config.yml b/connector/src/main/resources/config.yml
index bdb212160de..ac9ec753d83 100644
--- a/connector/src/main/resources/config.yml
+++ b/connector/src/main/resources/config.yml
@@ -32,6 +32,11 @@ remote:
port: 25565
# Authentication type. Can be offline, online, or floodgate (see https://github.com/GeyserMC/Geyser/wiki/Floodgate).
auth-type: online
+ # Whether to enable PROXY protocol or not while connecting to the server.
+ # This is useful only when:
+ # 1) Your server supports PROXY protocol (it probably doesn't)
+ # 2) You run Velocity or BungeeCord with respective option enabled.
+ use-proxy-protocol: false
# Floodgate uses encryption to ensure use from authorised sources.
# This should point to the public key generated by Floodgate (Bungee or CraftBukkit)