Merge branch 'master' of https://github.com/GeyserMC/Geyser into scoreboard-changes

This commit is contained in:
Camotoy 2020-12-30 15:02:49 -05:00
commit 1611e26ec0
No known key found for this signature in database
GPG key ID: 7EEFB66FE798081F
29 changed files with 399 additions and 106 deletions

2
Jenkinsfile vendored
View file

@ -66,7 +66,7 @@ pipeline {
} }
deleteDir() deleteDir()
withCredentials([string(credentialsId: 'geyser-discord-webhook', variable: 'DISCORD_WEBHOOK')]) { 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
} }
} }
} }

View file

@ -3,7 +3,7 @@
[![forthebadge made-with-java](http://ForTheBadge.com/images/badges/made-with-java.svg)](https://java.com/) [![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) [![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/) [![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) [![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/) [![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. 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 - Custom heads in inventories
- Clickable links in chat
- Glowing effect
## Compiling ## Compiling
1. Clone the repo to your computer 1. Clone the repo to your computer

View file

@ -125,7 +125,7 @@ public class GeyserSpigot1_12WorldManager extends GeyserSpigotWorldManager {
for (int blockY = 0; blockY < 16; blockY++) { // Cache-friendly iteration order for (int blockY = 0; blockY < 16; blockY++) { // Cache-friendly iteration order
for (int blockZ = 0; blockZ < 16; blockZ++) { for (int blockZ = 0; blockZ < 16; blockZ++) {
for (int blockX = 0; blockX < 16; blockX++) { 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 // Black magic that gets the old block state ID
int blockId = (block.getType().getId() << 4) | (block.getData() & 0xF); 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)); chunk.set(blockX, blockY, blockZ, getLegacyBlock(storage, blockId, (x << 4) + blockX, (y << 4) + blockY, (z << 4) + blockZ));

View file

@ -32,7 +32,7 @@
<dependency> <dependency>
<groupId>com.github.CloudburstMC.Protocol</groupId> <groupId>com.github.CloudburstMC.Protocol</groupId>
<artifactId>bedrock-v422</artifactId> <artifactId>bedrock-v422</artifactId>
<version>87d862d69d</version> <version>d41b84e86c</version>
<scope>compile</scope> <scope>compile</scope>
<exclusions> <exclusions>
<exclusion> <exclusion>
@ -124,14 +124,26 @@
<version>26201a4</version> <version>26201a4</version>
<scope>compile</scope> <scope>compile</scope>
<exclusions> <exclusions>
<exclusion>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
</exclusion>
<exclusion> <exclusion>
<groupId>net.kyori</groupId> <groupId>net.kyori</groupId>
<artifactId>adventure-text-serializer-gson</artifactId> <artifactId>adventure-text-serializer-gson</artifactId>
</exclusion> </exclusion>
<exclusion>
<groupId>com.github.steveice10</groupId>
<artifactId>packetlib</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.github.steveice10</groupId>
<artifactId>PacketLib</artifactId>
<version>54f761c</version>
<scope>compile</scope>
<exclusions>
<exclusion> <!-- Move this exclusion back to MCProtocolLib it gets the latest PacketLib -->
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
</exclusion>
</exclusions> </exclusions>
</dependency> </dependency>
<dependency> <dependency>
@ -140,6 +152,12 @@
<version>4.1.43.Final</version> <version>4.1.43.Final</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-codec-haproxy</artifactId>
<version>4.1.56.Final</version>
<scope>compile</scope>
</dependency>
<dependency> <dependency>
<groupId>org.reflections</groupId> <groupId>org.reflections</groupId>
<artifactId>reflections</artifactId> <artifactId>reflections</artifactId>

View file

@ -44,6 +44,7 @@ import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.BiomeTranslator; import org.geysermc.connector.network.translators.BiomeTranslator;
import org.geysermc.connector.network.translators.EntityIdentifierRegistry; import org.geysermc.connector.network.translators.EntityIdentifierRegistry;
import org.geysermc.connector.network.translators.PacketTranslatorRegistry; 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.effect.EffectRegistry;
import org.geysermc.connector.network.translators.item.ItemRegistry; import org.geysermc.connector.network.translators.item.ItemRegistry;
import org.geysermc.connector.network.translators.item.ItemTranslator; import org.geysermc.connector.network.translators.item.ItemTranslator;
@ -54,7 +55,6 @@ import org.geysermc.connector.network.translators.sound.SoundRegistry;
import org.geysermc.connector.network.translators.world.WorldManager; 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.BlockTranslator;
import org.geysermc.connector.network.translators.world.block.entity.BlockEntityTranslator; 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.network.translators.world.block.entity.SkullBlockEntityTranslator;
import org.geysermc.connector.scoreboard.ScoreboardUpdater; import org.geysermc.connector.scoreboard.ScoreboardUpdater;
import org.geysermc.connector.utils.DimensionUtils; import org.geysermc.connector.utils.DimensionUtils;
@ -68,10 +68,7 @@ import java.net.InetAddress;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.text.DecimalFormat; import java.text.DecimalFormat;
import java.util.ArrayList; import java.util.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledExecutorService;
@ -328,6 +325,38 @@ public class GeyserConnector {
players.remove(player); players.remove(player);
} }
/**
* Gets a player by their current UUID
*
* @param uuid the uuid
* @return the player or <code>null</code> 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 <code>null</code> 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) { public static GeyserConnector start(PlatformType platformType, GeyserBootstrap bootstrap) {
return new GeyserConnector(platformType, bootstrap); return new GeyserConnector(platformType, bootstrap);
} }

View file

@ -71,7 +71,7 @@ public class VersionCommand extends GeyserCommand {
Properties gitProp = new Properties(); Properties gitProp = new Properties();
gitProp.load(FileUtils.getResource("git.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("<buildNumber>")) { if (buildXML.startsWith("<buildNumber>")) {
int latestBuildNum = Integer.parseInt(buildXML.replaceAll("<(\\\\)?(/)?buildNumber>", "").trim()); int latestBuildNum = Integer.parseInt(buildXML.replaceAll("<(\\\\)?(/)?buildNumber>", "").trim());
int buildNum = Integer.parseInt(gitProp.getProperty("git.build.number")); int buildNum = Integer.parseInt(gitProp.getProperty("git.build.number"));

View file

@ -34,7 +34,7 @@ import java.util.Map;
public interface GeyserConfiguration { 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; int CURRENT_CONFIG_VERSION = 4;
IBedrockConfiguration getBedrock(); IBedrockConfiguration getBedrock();
@ -117,6 +117,8 @@ public interface GeyserConfiguration {
void setPort(int port); void setPort(int port);
String getAuthType(); String getAuthType();
boolean isUseProxyProtocol();
} }
interface IUserAuthenticationInfo { interface IUserAuthenticationInfo {

View file

@ -148,6 +148,9 @@ public abstract class GeyserJacksonConfiguration implements GeyserConfiguration
@Setter @Setter
@JsonProperty("auth-type") @JsonProperty("auth-type")
private String authType = "online"; private String authType = "online";
@JsonProperty("use-proxy-protocol")
private boolean useProxyProtocol = false;
} }
@Getter @Getter

View file

@ -29,6 +29,7 @@ import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadat
import com.github.steveice10.mc.protocol.data.game.world.particle.Particle; import com.github.steveice10.mc.protocol.data.game.world.particle.Particle;
import com.nukkitx.math.vector.Vector3f; import com.nukkitx.math.vector.Vector3f;
import com.nukkitx.protocol.bedrock.data.entity.EntityData; 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.entity.type.EntityType;
import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.effect.EffectRegistry; import org.geysermc.connector.network.translators.effect.EffectRegistry;
@ -45,6 +46,8 @@ public class AreaEffectCloudEntity extends Entity {
metadata.put(EntityData.AREA_EFFECT_CLOUD_RADIUS, 0.0f); 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_RATE, -0.005f);
metadata.put(EntityData.AREA_EFFECT_CLOUD_CHANGE_ON_PICKUP, -0.5f); metadata.put(EntityData.AREA_EFFECT_CLOUD_CHANGE_ON_PICKUP, -0.5f);
metadata.getFlags().setFlag(EntityFlag.FIRE_IMMUNE, true);
} }
@Override @Override

View file

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

View file

@ -123,7 +123,7 @@ public enum EntityType {
PAINTING(PaintingEntity.class, 83, 0f), PAINTING(PaintingEntity.class, 83, 0f),
MINECART(MinecartEntity.class, 84, 0.7f, 0.98f, 0.98f, 0.35f), MINECART(MinecartEntity.class, 84, 0.7f, 0.98f, 0.98f, 0.35f),
FIREBALL(ItemedFireballEntity.class, 85, 1.0f), 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"), THROWN_ENDERPEARL(ThrowableEntity.class, 87, 0.25f, 0.25f, 0.25f, 0f, "minecraft:ender_pearl"),
LEASH_KNOT(LeashKnotEntity.class, 88, 0.5f, 0.375f), LEASH_KNOT(LeashKnotEntity.class, 88, 0.5f, 0.375f),
WITHER_SKULL(WitherSkullEntity.class, 89, 0.3125f), WITHER_SKULL(WitherSkullEntity.class, 89, 0.3125f),

View file

@ -132,11 +132,6 @@ public class LoggingPacketHandler implements BedrockPacketHandler {
return defaultHandler(packet); return defaultHandler(packet);
} }
@Override
public boolean handle(EntityFallPacket packet) {
return defaultHandler(packet);
}
@Override @Override
public boolean handle(EntityPickRequestPacket packet) { public boolean handle(EntityPickRequestPacket packet) {
return defaultHandler(packet); return defaultHandler(packet);
@ -826,4 +821,43 @@ public class LoggingPacketHandler implements BedrockPacketHandler {
public boolean handle(PositionTrackingDBServerBroadcastPacket packet) { public boolean handle(PositionTrackingDBServerBroadcastPacket packet) {
return defaultHandler(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);
}
} }

View file

@ -39,6 +39,7 @@ import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlaye
import com.github.steveice10.mc.protocol.packet.ingame.client.world.ClientTeleportConfirmPacket; 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.ingame.server.ServerRespawnPacket;
import com.github.steveice10.mc.protocol.packet.login.server.LoginSuccessPacket; 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.Client;
import com.github.steveice10.packetlib.event.session.*; import com.github.steveice10.packetlib.event.session.*;
import com.github.steveice10.packetlib.packet.Packet; import com.github.steveice10.packetlib.packet.Packet;
@ -250,6 +251,12 @@ public class GeyserSession implements CommandSender {
@Setter @Setter
private ScheduledFuture<?> movementSendIfIdle; 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; private boolean reducedDebugInfo = false;
@Setter @Setter
@ -453,6 +460,10 @@ public class GeyserSession implements CommandSender {
} }
downstream = new Client(remoteServer.getAddress(), remoteServer.getPort(), protocol, new TcpSessionFactory()); 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 // Let Geyser handle sending the keep alive
downstream.getSession().setFlag(MinecraftConstants.AUTOMATIC_KEEP_ALIVE_MANAGEMENT, false); downstream.getSession().setFlag(MinecraftConstants.AUTOMATIC_KEEP_ALIVE_MANAGEMENT, false);
downstream.getSession().addListener(new SessionAdapter() { downstream.getSession().addListener(new SessionAdapter() {
@ -642,7 +653,6 @@ public class GeyserSession implements CommandSender {
public void setRenderDistance(int renderDistance) { public void setRenderDistance(int renderDistance) {
renderDistance = GenericMath.ceil(++renderDistance * MathUtils.SQRT_OF_TWO); //square to circle 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; this.renderDistance = renderDistance;
ChunkRadiusUpdatedPacket chunkRadiusUpdatedPacket = new ChunkRadiusUpdatedPacket(); ChunkRadiusUpdatedPacket chunkRadiusUpdatedPacket = new ChunkRadiusUpdatedPacket();

View file

@ -46,7 +46,6 @@ public class BedrockBlockPickRequestTranslator extends PacketTranslator<BlockPic
return; return;
} }
String targetIdentifier = BlockTranslator.getJavaIdBlockMap().inverse().get(blockToPick).split("\\[")[0]; InventoryUtils.findOrCreateItem(session, BlockTranslator.getPickItem(blockToPick));
InventoryUtils.findOrCreatePickedBlock(session, targetIdentifier);
} }
} }

View file

@ -110,6 +110,6 @@ public class BedrockEntityPickRequestTranslator extends PacketTranslator<EntityP
// Verify it is, indeed, an item // Verify it is, indeed, an item
if (entry == null) return; if (entry == null) return;
InventoryUtils.findOrCreatePickedBlock(session, fullItemName); InventoryUtils.findOrCreateItem(session, fullItemName);
} }
} }

View file

@ -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<FilterTextPacket> {
@Override
public void translate(FilterTextPacket packet, GeyserSession session) {
packet.setFromServer(true);
session.sendUpstreamPacket(packet);
}
}

View file

@ -38,7 +38,7 @@ public class BedrockTextTranslator extends PacketTranslator<TextPacket> {
@Override @Override
public void translate(TextPacket packet, GeyserSession session) { public void translate(TextPacket packet, GeyserSession session) {
String message = packet.getMessage().replaceAll("^\\.", "/").trim(); String message = packet.getMessage();
if (MessageTranslator.isTooLong(message, session)) { if (MessageTranslator.isTooLong(message, session)) {
return; return;

View file

@ -45,8 +45,39 @@ import java.util.stream.Collectors;
@ItemRemapper @ItemRemapper
public class BannerTranslator extends ItemTranslator { 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<ItemEntry> appliedItems; private final List<ItemEntry> 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() { public BannerTranslator() {
appliedItems = ItemRegistry.ITEM_ENTRIES.values() appliedItems = ItemRegistry.ITEM_ENTRIES.values()
.stream() .stream()
@ -62,7 +93,7 @@ public class BannerTranslator extends ItemTranslator {
*/ */
public static NbtList<NbtMap> convertBannerPattern(ListTag patterns) { public static NbtList<NbtMap> convertBannerPattern(ListTag patterns) {
List<NbtMap> tagsList = new ArrayList<>(); List<NbtMap> tagsList = new ArrayList<>();
for (com.github.steveice10.opennbt.tag.builtin.Tag patternTag : patterns.getValue()) { for (Tag patternTag : patterns.getValue()) {
NbtMap newPatternTag = getBedrockBannerPattern((CompoundTag) patternTag); NbtMap newPatternTag = getBedrockBannerPattern((CompoundTag) patternTag);
if (newPatternTag != null) { if (newPatternTag != null) {
tagsList.add(newPatternTag); tagsList.add(newPatternTag);
@ -134,7 +165,13 @@ public class BannerTranslator extends ItemTranslator {
ListTag patterns = blockEntityTag.get("Patterns"); ListTag patterns = blockEntityTag.get("Patterns");
NbtMapBuilder builder = itemData.getTag().toBuilder(); 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()); itemData = ItemData.of(itemData.getId(), itemData.getDamage(), itemData.getCount(), builder.build());
} }
@ -151,7 +188,14 @@ public class BannerTranslator extends ItemTranslator {
ItemStack itemStack = super.translateToJava(itemData, itemEntry); ItemStack itemStack = super.translateToJava(itemData, itemEntry);
NbtMap nbtTag = itemData.getTag(); 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<NbtMap> patterns = nbtTag.getList("Patterns", NbtType.COMPOUND); List<NbtMap> patterns = nbtTag.getList("Patterns", NbtType.COMPOUND);
CompoundTag blockEntityTag = new CompoundTag("BlockEntityTag"); CompoundTag blockEntityTag = new CompoundTag("BlockEntityTag");

View file

@ -52,9 +52,14 @@ public class JavaDeclareCommandsTranslator extends PacketTranslator<ServerDeclar
public void translate(ServerDeclareCommandsPacket packet, GeyserSession session) { public void translate(ServerDeclareCommandsPacket packet, GeyserSession session) {
// Don't send command suggestions if they are disabled // Don't send command suggestions if they are disabled
if (!session.getConnector().getConfig().isCommandSuggestions()) { if (!session.getConnector().getConfig().isCommandSuggestions()) {
session.getConnector().getLogger().debug("Not sending command suggestions as they are disabled."); session.getConnector().getLogger().debug("Not sending translated command suggestions as they are disabled.");
// Send an empty packet so Bedrock doesn't override /help with its own, built-in help command.
AvailableCommandsPacket emptyPacket = new AvailableCommandsPacket();
session.sendUpstreamPacket(emptyPacket);
return; return;
} }
List<CommandData> commandData = new ArrayList<>(); List<CommandData> commandData = new ArrayList<>();
Int2ObjectMap<String> commands = new Int2ObjectOpenHashMap<>(); Int2ObjectMap<String> commands = new Int2ObjectOpenHashMap<>();
Int2ObjectMap<List<CommandNode>> commandArgs = new Int2ObjectOpenHashMap<>(); Int2ObjectMap<List<CommandNode>> commandArgs = new Int2ObjectOpenHashMap<>();
@ -83,14 +88,14 @@ public class JavaDeclareCommandsTranslator extends PacketTranslator<ServerDeclar
} }
// The command flags, not sure what these do apart from break things // The command flags, not sure what these do apart from break things
List<CommandData.Flag> flags = new ArrayList<>(); List<CommandData.Flag> flags = Collections.emptyList();
// Loop through all the found commands // Loop through all the found commands
for (int commandID : commands.keySet()) { for (int commandID : commands.keySet()) {
String commandName = commands.get(commandID); String commandName = commands.get(commandID);
// Create a basic alias // 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 // Get and parse all params
CommandParamData[][] params = getParams(packet.getNodes()[commandID], packet.getNodes()); CommandParamData[][] params = getParams(packet.getNodes()[commandID], packet.getNodes());
@ -102,9 +107,7 @@ public class JavaDeclareCommandsTranslator extends PacketTranslator<ServerDeclar
// Add our commands to the AvailableCommandsPacket for the bedrock client // Add our commands to the AvailableCommandsPacket for the bedrock client
AvailableCommandsPacket availableCommandsPacket = new AvailableCommandsPacket(); AvailableCommandsPacket availableCommandsPacket = new AvailableCommandsPacket();
for (CommandData data : commandData) { availableCommandsPacket.getCommands().addAll(commandData);
availableCommandsPacket.getCommands().add(data);
}
GeyserConnector.getInstance().getLogger().debug("Sending command packet of " + commandData.size() + " commands"); GeyserConnector.getInstance().getLogger().debug("Sending command packet of " + commandData.size() + " commands");

View file

@ -89,6 +89,7 @@ public class JavaEntityStatusTranslator extends PacketTranslator<ServerEntitySta
case LIVING_DROWN: case LIVING_DROWN:
case LIVING_HURT: case LIVING_HURT:
case LIVING_HURT_SWEET_BERRY_BUSH: case LIVING_HURT_SWEET_BERRY_BUSH:
case LIVING_HURT_THORNS:
entityEventPacket.setType(EntityEventType.HURT); entityEventPacket.setType(EntityEventType.HURT);
break; break;
case LIVING_DEATH: case LIVING_DEATH:

View file

@ -34,8 +34,8 @@ import com.nukkitx.protocol.bedrock.packet.LevelSoundEventPacket;
import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.PacketTranslator;
import org.geysermc.connector.network.translators.Translator; 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.sound.SoundRegistry;
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
@Translator(packet = ServerPlayBuiltinSoundPacket.class) @Translator(packet = ServerPlayBuiltinSoundPacket.class)
public class JavaPlayBuiltinSoundTranslator extends PacketTranslator<ServerPlayBuiltinSoundPacket> { public class JavaPlayBuiltinSoundTranslator extends PacketTranslator<ServerPlayBuiltinSoundPacket> {
@ -82,7 +82,11 @@ public class JavaPlayBuiltinSoundTranslator extends PacketTranslator<ServerPlayB
// Bedrock has a number for each type of note, then proceeds up the scale by adding to that number // 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); soundPacket.setExtraData(soundMapping.getExtraData() + (int)(Math.round((Math.log10(packet.getPitch()) / Math.log10(2)) * 12)) + 12);
} else if (sound == SoundEvent.PLACE && soundMapping.getExtraData() == -1) { } 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(":"); soundPacket.setIdentifier(":");
} else { } else {
soundPacket.setExtraData(soundMapping.getExtraData()); soundPacket.setExtraData(soundMapping.getExtraData());

View file

@ -25,49 +25,38 @@
package org.geysermc.connector.network.translators.java.world; package org.geysermc.connector.network.translators.java.world;
import com.nukkitx.protocol.bedrock.data.GameRuleData; import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerUpdateTimePacket;
import com.nukkitx.protocol.bedrock.packet.GameRulesChangedPacket; import com.nukkitx.protocol.bedrock.packet.SetTimePacket;
import it.unimi.dsi.fastutil.longs.Long2LongMap;
import it.unimi.dsi.fastutil.longs.Long2LongOpenHashMap;
import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.PacketTranslator;
import org.geysermc.connector.network.translators.Translator; 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) @Translator(packet = ServerUpdateTimePacket.class)
public class JavaUpdateTimeTranslator extends PacketTranslator<ServerUpdateTimePacket> { public class JavaUpdateTimeTranslator extends PacketTranslator<ServerUpdateTimePacket> {
// 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 @Override
public void translate(ServerUpdateTimePacket packet, GeyserSession session) { public void translate(ServerUpdateTimePacket packet, GeyserSession session) {
// Bedrock sends a GameRulesChangedPacket if there is no daylight cycle // Bedrock sends a GameRulesChangedPacket if there is no daylight cycle
// Java just sends a negative long 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(); long time = packet.getTime();
if (lastTime != time) { // https://minecraft.gamepedia.com/Day-night_cycle#24-hour_Minecraft_day
// https://minecraft.gamepedia.com/Day-night_cycle#24-hour_Minecraft_day SetTimePacket setTimePacket = new SetTimePacket();
SetTimePacket setTimePacket = new SetTimePacket(); setTimePacket.setTime((int) Math.abs(time) % 24000);
setTimePacket.setTime((int) Math.abs(time) % 24000); session.sendUpstreamPacket(setTimePacket);
session.sendUpstreamPacket(setTimePacket); if (!session.isDaylightCycle() && time >= 0) {
// TODO: Performance efficient to always do this? // Client thinks there is no daylight cycle but there is
LAST_RECORDED_TIMES.put(session.getPlayerEntity().getEntityId(), time);
}
if (lastTime < 0 && time >= 0) {
setDoDaylightCycleGamerule(session, true); 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); setDoDaylightCycleGamerule(session, false);
} }
} }
private void setDoDaylightCycleGamerule(GeyserSession session, boolean doCycle) { private void setDoDaylightCycleGamerule(GeyserSession session, boolean doCycle) {
session.sendGameRule("dodaylightcycle", doCycle); session.sendGameRule("dodaylightcycle", doCycle);
// Save the value so we don't have to constantly send a daylight cycle gamerule update
session.setDaylightCycle(doCycle);
} }
} }

View file

@ -30,15 +30,18 @@ import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap; import com.google.common.collect.HashBiMap;
import com.nukkitx.nbt.*; import com.nukkitx.nbt.*;
import it.unimi.dsi.fastutil.ints.*; 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.GeyserConnector;
import org.geysermc.connector.network.translators.world.block.entity.BlockEntity;
import org.geysermc.connector.utils.FileUtils; import org.geysermc.connector.utils.FileUtils;
import org.reflections.Reflections; import org.reflections.Reflections;
import java.io.DataInputStream; import java.io.DataInputStream;
import java.io.InputStream; import java.io.InputStream;
import java.util.*; import java.util.Iterator;
import java.util.Map;
public class BlockTranslator { public class BlockTranslator {
/** /**
@ -65,8 +68,6 @@ public class BlockTranslator {
// Bedrock carpet ID, used in LlamaEntity.java for decoration // Bedrock carpet ID, used in LlamaEntity.java for decoration
public static final int CARPET = 171; public static final int CARPET = 171;
private static final Int2ObjectMap<String> JAVA_ID_TO_BLOCK_ENTITY_MAP = new Int2ObjectOpenHashMap<>();
public static final Int2DoubleMap JAVA_RUNTIME_ID_TO_HARDNESS = new Int2DoubleOpenHashMap(); 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 Int2BooleanMap JAVA_RUNTIME_ID_TO_CAN_HARVEST_WITH_HAND = new Int2BooleanOpenHashMap();
public static final Int2ObjectMap<String> JAVA_RUNTIME_ID_TO_TOOL_TYPE = new Int2ObjectOpenHashMap<>(); public static final Int2ObjectMap<String> JAVA_RUNTIME_ID_TO_TOOL_TYPE = new Int2ObjectOpenHashMap<>();
@ -74,6 +75,8 @@ public class BlockTranslator {
// The index of the collision data in collision.json // The index of the collision data in collision.json
public static final Int2IntMap JAVA_RUNTIME_ID_TO_COLLISION_INDEX = new Int2IntOpenHashMap(); public static final Int2IntMap JAVA_RUNTIME_ID_TO_COLLISION_INDEX = new Int2IntOpenHashMap();
private static final Int2ObjectMap<String> JAVA_RUNTIME_ID_TO_PICK_ITEM = new Int2ObjectOpenHashMap<>();
/** /**
* Java numeric ID to java unique identifier, used for block names in the statistics screen * Java numeric ID to java unique identifier, used for block names in the statistics screen
*/ */
@ -173,20 +176,13 @@ public class BlockTranslator {
JAVA_RUNTIME_ID_TO_COLLISION_INDEX.put(javaRuntimeId, collisionIndexNode.intValue()); JAVA_RUNTIME_ID_TO_COLLISION_INDEX.put(javaRuntimeId, collisionIndexNode.intValue());
} }
JAVA_ID_BLOCK_MAP.put(javaId, javaRuntimeId); JsonNode pickItemNode = entry.getValue().get("pick_item");
if (pickItemNode != null) {
// Used for adding all "special" Java block states to block state map JAVA_RUNTIME_ID_TO_PICK_ITEM.put(javaRuntimeId, pickItemNode.textValue());
String identifier;
String bedrockIdentifier = entry.getValue().get("bedrock_identifier").asText();
for (Class<?> clazz : ref.getTypesAnnotatedWith(BlockEntity.class)) {
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;
}
} }
JAVA_ID_BLOCK_MAP.put(javaId, javaRuntimeId);
BlockStateValues.storeBlockStateValues(entry, javaRuntimeId); BlockStateValues.storeBlockStateValues(entry, javaRuntimeId);
String cleanJavaIdentifier = entry.getKey().split("\\[")[0]; String cleanJavaIdentifier = entry.getKey().split("\\[")[0];
@ -196,6 +192,8 @@ public class BlockTranslator {
JAVA_ID_TO_JAVA_IDENTIFIER_MAP.put(uniqueJavaId, cleanJavaIdentifier); JAVA_ID_TO_JAVA_IDENTIFIER_MAP.put(uniqueJavaId, cleanJavaIdentifier);
} }
String bedrockIdentifier = entry.getValue().get("bedrock_identifier").asText();
if (!cleanJavaIdentifier.equals(bedrockIdentifier)) { if (!cleanJavaIdentifier.equals(bedrockIdentifier)) {
JAVA_TO_BEDROCK_IDENTIFIERS.put(cleanJavaIdentifier, bedrockIdentifier); JAVA_TO_BEDROCK_IDENTIFIERS.put(cleanJavaIdentifier, bedrockIdentifier);
} }
@ -352,12 +350,12 @@ public class BlockTranslator {
return BLOCK_STATE_VERSION; 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) { public static int getJavaBlockState(String javaId) {
return JAVA_ID_BLOCK_MAP.get(javaId); return JAVA_ID_BLOCK_MAP.getOrDefault(javaId, JAVA_AIR_ID);
}
public static String getBlockEntityString(int javaId) {
return JAVA_ID_TO_BLOCK_ENTITY_MAP.get(javaId);
} }
public static boolean isWaterlogged(int state) { public static boolean isWaterlogged(int state) {
@ -371,4 +369,19 @@ public class BlockTranslator {
public static int getJavaWaterloggedState(int bedrockId) { public static int getJavaWaterloggedState(int bedrockId) {
return BEDROCK_TO_JAVA_BLOCK_MAP.get(1 << 31 | 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;
}
} }

View file

@ -47,7 +47,13 @@ public class BannerBlockEntityTranslator extends BlockEntityTranslator implement
if (tag.contains("Patterns")) { if (tag.contains("Patterns")) {
ListTag patterns = tag.get("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")) { if (tag.contains("CustomName")) {

View file

@ -81,11 +81,10 @@ public class SkinManager {
// This attempts to find the xuid of the player so profile images show up for xbox accounts // This attempts to find the xuid of the player so profile images show up for xbox accounts
String xuid = ""; String xuid = "";
for (GeyserSession player : GeyserConnector.getInstance().getPlayers()) { GeyserSession player = GeyserConnector.getInstance().getPlayerByUuid(uuid);
if (player.getPlayerEntity().getUuid().equals(uuid)) {
xuid = player.getAuthData().getXboxUUID(); if (player != null) {
break; xuid = player.getAuthData().getXboxUUID();
}
} }
PlayerListPacket.Entry entry; PlayerListPacket.Entry entry;
@ -268,11 +267,10 @@ public class SkinManager {
// return default skin with default cape when texture data is invalid // return default skin with default cape when texture data is invalid
String skinUrl = isAlex ? SkinProvider.EMPTY_SKIN_ALEX.getTextureUrl() : SkinProvider.EMPTY_SKIN.getTextureUrl(); String skinUrl = isAlex ? SkinProvider.EMPTY_SKIN_ALEX.getTextureUrl() : SkinProvider.EMPTY_SKIN.getTextureUrl();
if ("steve".equals(skinUrl) || "alex".equals(skinUrl)) { if ("steve".equals(skinUrl) || "alex".equals(skinUrl)) {
for (GeyserSession session : GeyserConnector.getInstance().getPlayers()) { GeyserSession session = GeyserConnector.getInstance().getPlayerByUuid(profile.getId());
if (session.getPlayerEntity().getUuid().equals(profile.getId())) {
skinUrl = session.getClientData().getSkinId(); if (session != null) {
break; skinUrl = session.getClientData().getSkinId();
}
} }
} }
return new GameProfileData(skinUrl, SkinProvider.EMPTY_CAPE.getTextureUrl(), isAlex); return new GameProfileData(skinUrl, SkinProvider.EMPTY_CAPE.getTextureUrl(), isAlex);

View file

@ -144,12 +144,10 @@ public class SkinProvider {
String newSkinUrl = skinUrl; String newSkinUrl = skinUrl;
if ("steve".equals(skinUrl) || "alex".equals(skinUrl)) { if ("steve".equals(skinUrl) || "alex".equals(skinUrl)) {
// TODO: Don't have a for loop for this? Have a proper map? GeyserSession session = GeyserConnector.getInstance().getPlayerByUuid(playerId);
for (GeyserSession session : GeyserConnector.getInstance().getPlayers()) {
if (session.getPlayerEntity().getUuid().equals(playerId)) { if (session != null) {
newSkinUrl = session.getClientData().getSkinId(); newSkinUrl = session.getClientData().getSkinId();
break;
}
} }
} }

View file

@ -46,6 +46,7 @@ import org.geysermc.connector.network.translators.inventory.InventoryTranslator;
import org.geysermc.connector.network.translators.item.ItemEntry; import org.geysermc.connector.network.translators.item.ItemEntry;
import org.geysermc.connector.network.translators.item.ItemRegistry; import org.geysermc.connector.network.translators.item.ItemRegistry;
import org.geysermc.connector.network.translators.item.ItemTranslator; import org.geysermc.connector.network.translators.item.ItemTranslator;
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
import java.util.Collections; import java.util.Collections;
import java.util.Objects; import java.util.Objects;
@ -168,13 +169,17 @@ public class InventoryUtils {
* @param session the Bedrock client's session * @param session the Bedrock client's session
* @param itemName the Java identifier of the item to search/select * @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 // Get the inventory to choose a slot to pick
Inventory inventory = session.getInventoryCache().getOpenInventory(); Inventory inventory = session.getInventoryCache().getOpenInventory();
if (inventory == null) { if (inventory == null) {
inventory = session.getInventory(); inventory = session.getInventory();
} }
if (itemName.equals("minecraft:air")) {
return;
}
// Check hotbar for item // Check hotbar for item
for (int i = 36; i < 45; i++) { for (int i = 36; i < 45; i++) {
if (inventory.getItem(i) == null) { if (inventory.getItem(i) == null) {
@ -219,12 +224,17 @@ public class InventoryUtils {
} }
} }
ClientCreativeInventoryActionPacket actionPacket = new ClientCreativeInventoryActionPacket(slot, ItemEntry entry = ItemRegistry.getItemEntry(itemName);
new ItemStack(ItemRegistry.getItemEntry(itemName).getJavaId())); if (entry != null) {
if ((slot - 36) != session.getInventory().getHeldItemSlot()) { ClientCreativeInventoryActionPacket actionPacket = new ClientCreativeInventoryActionPacket(slot,
setHotbarItem(session, 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);
} }
} }

View file

@ -32,6 +32,11 @@ remote:
port: 25565 port: 25565
# Authentication type. Can be offline, online, or floodgate (see https://github.com/GeyserMC/Geyser/wiki/Floodgate). # Authentication type. Can be offline, online, or floodgate (see https://github.com/GeyserMC/Geyser/wiki/Floodgate).
auth-type: online 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. # Floodgate uses encryption to ensure use from authorised sources.
# This should point to the public key generated by Floodgate (Bungee or CraftBukkit) # This should point to the public key generated by Floodgate (Bungee or CraftBukkit)

@ -1 +1 @@
Subproject commit 2d14c9dc3d75df7463fc7605a6cff63b5926a03e Subproject commit 143285afb4bdf4d5ef40ef7a7959477dabf4d34c