Merge remote-tracking branch 'origin/master' into feature/floodgate-merge

# Conflicts:
#	bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java
#	bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPlugin.java
#	core/src/main/java/org/geysermc/geyser/configuration/GeyserConfiguration.java
#	core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCustomPayloadTranslator.java
#	core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java
This commit is contained in:
Tim203 2023-10-12 21:10:01 +02:00
commit dab61ac41a
No known key found for this signature in database
102 changed files with 678 additions and 837 deletions

View File

@ -2,15 +2,6 @@ name: Build Pull Request
on: on:
pull_request: pull_request:
paths-ignore:
- '.github/ISSUE_TEMPLATE/*.yml'
- '.idea/copyright/*.xml'
- '.gitignore'
- 'CONTRIBUTING.md'
- 'LICENSE'
- 'Jenkinsfile '
- 'README.md'
- 'licenseheader.txt'
jobs: jobs:
build: build:

View File

@ -14,7 +14,7 @@ The ultimate goal of this project is to allow Minecraft: Bedrock Edition users t
Special thanks to the DragonProxy project for being a trailblazer in protocol translation and for all the team members who have joined us here! Special thanks to the DragonProxy project for being a trailblazer in protocol translation and for all the team members who have joined us here!
### Currently supporting Minecraft Bedrock 1.20.0 - 1.20.30 and Minecraft Java 1.20/1.20.1. ### Currently supporting Minecraft Bedrock 1.20.0 - 1.20.32 and Minecraft Java 1.20.2
## Setting Up ## Setting Up
Take a look [here](https://wiki.geysermc.org/geyser/setup/) for how to set up Geyser. Take a look [here](https://wiki.geysermc.org/geyser/setup/) for how to set up Geyser.

View File

@ -36,13 +36,13 @@ import java.util.Collection;
public abstract class ExtensionManager { public abstract class ExtensionManager {
/** /**
* Gets an extension with the given name. * Gets an extension by the given ID.
* *
* @param name the name of the extension * @param id the ID of the extension
* @return an extension with the given name * @return an extension with the given ID
*/ */
@Nullable @Nullable
public abstract Extension extension(@NonNull String name); public abstract Extension extension(@NonNull String id);
/** /**
* Enables the given {@link Extension}. * Enables the given {@link Extension}.

View File

@ -79,7 +79,7 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap {
// Copied from ViaVersion. // Copied from ViaVersion.
// https://github.com/ViaVersion/ViaVersion/blob/b8072aad86695cc8ec6f5e4103e43baf3abf6cc5/bungee/src/main/java/us/myles/ViaVersion/BungeePlugin.java#L43 // https://github.com/ViaVersion/ViaVersion/blob/b8072aad86695cc8ec6f5e4103e43baf3abf6cc5/bungee/src/main/java/us/myles/ViaVersion/BungeePlugin.java#L43
try { try {
ProtocolConstants.class.getField("MINECRAFT_1_19_3"); ProtocolConstants.class.getField("MINECRAFT_1_20_2");
} catch (NoSuchFieldException e) { } catch (NoSuchFieldException e) {
getLogger().warning(" / \\"); getLogger().warning(" / \\");
getLogger().warning(" / \\"); getLogger().warning(" / \\");

View File

@ -118,7 +118,7 @@ modrinth {
syncBodyFrom.set(rootProject.file("README.md").readText()) syncBodyFrom.set(rootProject.file("README.md").readText())
uploadFile.set(tasks.getByPath("remapModrinthJar")) uploadFile.set(tasks.getByPath("remapModrinthJar"))
gameVersions.addAll("1.20", "1.20.1") gameVersions.addAll("1.20.2")
loaders.add("fabric") loaders.add("fabric")
failSilently.set(true) failSilently.set(true)

View File

@ -25,7 +25,7 @@
"depends": { "depends": {
"fabricloader": ">=0.14.21", "fabricloader": ">=0.14.21",
"fabric": "*", "fabric": "*",
"minecraft": ">=1.20", "minecraft": ">=1.20.2",
"fabric-permissions-api-v0": "*" "fabric-permissions-api-v0": "*"
} }
} }

View File

@ -199,7 +199,7 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
commandMap.register(extension.description().id(), "geyserext", pluginCommand); commandMap.register(extension.description().id(), "geyserext", pluginCommand);
} catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException ex) { } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException ex) {
this.geyserLogger.error("Failed to construct PluginCommand for extension " + extension.description().name(), ex); this.geyserLogger.error("Failed to construct PluginCommand for extension " + extension.name(), ex);
} }
} }
} }

View File

@ -128,16 +128,6 @@ public class GeyserVelocityPlugin implements GeyserBootstrap {
this.geyser = GeyserImpl.load(PlatformType.VELOCITY, this, platform); this.geyser = GeyserImpl.load(PlatformType.VELOCITY, this, platform);
// Remove this in like a year
try {
// Should only exist on 1.0
Class.forName("org.geysermc.floodgate.FloodgateAPI");
geyserLogger.severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.outdated",
"https://ci.opencollab.dev/job/GeyserMC/job/Floodgate/job/master/"));
return;
} catch (ClassNotFoundException ignored) {
}
// if (geyserConfig.getRemote().authType() == AuthType.FLOODGATE && proxyServer.getPluginManager().getPlugin("floodgate").isEmpty()) { // if (geyserConfig.getRemote().authType() == AuthType.FLOODGATE && proxyServer.getPluginManager().getPlugin("floodgate").isEmpty()) {
// geyserLogger.severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.not_installed") + " " // geyserLogger.severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.not_installed") + " "
// + GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.disabling")); // + GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.disabling"));

View File

@ -1,91 +0,0 @@
/*
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.connector;
import org.geysermc.api.Geyser;
import org.geysermc.geyser.api.util.PlatformType;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.geyser.GeyserImpl;
import java.util.UUID;
/**
* Deprecated, please use {@link Geyser} or {@link GeyserImpl}.
*
* @deprecated legacy code
*/
@Deprecated
public class GeyserConnector {
public static final String NAME = GeyserImpl.NAME;
public static final String GIT_VERSION = GeyserImpl.GIT_VERSION; // A fallback for running in IDEs
public static final String VERSION = GeyserImpl.VERSION; // A fallback for running in IDEs
public static final String OAUTH_CLIENT_ID = GeyserImpl.OAUTH_CLIENT_ID;
private static final GeyserConnector INSTANCE = new GeyserConnector();
public static GeyserConnector getInstance() {
return INSTANCE;
}
public boolean isShuttingDown() {
return GeyserImpl.getInstance().isShuttingDown();
}
public PlatformType getPlatformType() {
return GeyserImpl.getInstance().getPlatformType();
}
public void shutdown() {
GeyserImpl.getInstance().shutdown();
}
public void reload() {
GeyserImpl.getInstance().reload();
}
public GeyserSession getPlayerByXuid(String xuid) {
org.geysermc.geyser.session.GeyserSession session = GeyserImpl.getInstance().connectionByXuid(xuid);
if (session != null) {
return new GeyserSession(session);
} else {
return null;
}
}
public GeyserSession getPlayerByUuid(UUID uuid) {
org.geysermc.geyser.session.GeyserSession session = GeyserImpl.getInstance().connectionByUuid(uuid);
if (session != null) {
return new GeyserSession(session);
} else {
return null;
}
}
public boolean isProductionEnvironment() {
return GeyserImpl.getInstance().isProductionEnvironment();
}
}

View File

@ -1,161 +0,0 @@
/*
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.connector.network.session;
import com.github.steveice10.packetlib.packet.Packet;
import org.cloudburstmc.protocol.bedrock.packet.BedrockPacket;
import org.geysermc.connector.network.session.auth.AuthData;
/**
* Deprecated, legacy code. Serves as a wrapper around
* the class used now.
*
* @deprecated legacy code
*/
@Deprecated
public class GeyserSession {
private final org.geysermc.geyser.session.GeyserSession handle;
public GeyserSession(org.geysermc.geyser.session.GeyserSession handle) {
this.handle = handle;
}
public AuthData getAuthData() {
return new AuthData(this.handle.getAuthData());
}
public boolean isMicrosoftAccount() {
return this.handle.isMicrosoftAccount();
}
public boolean isClosed() {
return this.handle.isClosed();
}
public String getRemoteAddress() {
return this.handle.remoteServer().address();
}
public int getRemotePort() {
return this.handle.remoteServer().port();
}
public int getRenderDistance() {
return this.handle.getServerRenderDistance();
}
public boolean isSentSpawnPacket() {
return this.handle.isSentSpawnPacket();
}
public boolean isLoggedIn() {
return this.handle.isLoggedIn();
}
public boolean isLoggingIn() {
return this.handle.isLoggingIn();
}
public boolean isSpawned() {
return this.handle.isSpawned();
}
public boolean isInteracting() {
return this.handle.isInteracting();
}
public boolean isCanFly() {
return this.handle.isCanFly();
}
public boolean isFlying() {
return this.handle.isFlying();
}
public void connect() {
this.handle.connect();
}
public void login() {
throw new UnsupportedOperationException();
}
public void authenticate(String username) {
this.handle.authenticate(username);
}
public void authenticate(String username, String password) {
this.handle.authenticate(username, password);
}
public void authenticateWithMicrosoftCode() {
this.handle.authenticateWithMicrosoftCode();
}
public void disconnect(String reason) {
this.handle.disconnect(reason);
}
public void close() {
throw new UnsupportedOperationException();
}
public void executeInEventLoop(Runnable runnable) {
this.handle.executeInEventLoop(runnable);
}
public String getName() {
return this.handle.bedrockUsername();
}
public boolean isConsole() {
return this.handle.isConsole();
}
public String getLocale() {
return this.handle.locale();
}
public void sendUpstreamPacket(BedrockPacket packet) {
this.handle.sendUpstreamPacket(packet);
}
public void sendUpstreamPacketImmediately(BedrockPacket packet) {
this.handle.sendUpstreamPacketImmediately(packet);
}
public void sendDownstreamPacket(Packet packet) {
this.handle.sendDownstreamPacket(packet);
}
public boolean hasPermission(String permission) {
return this.handle.hasPermission(permission);
}
public void sendAdventureSettings() {
this.handle.sendAdventureSettings();
}
}

View File

@ -43,7 +43,6 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.nullness.qual.Nullable;
import org.geysermc.api.Geyser; import org.geysermc.api.Geyser;
import org.geysermc.geyser.api.util.PlatformType;
import org.geysermc.cumulus.form.Form; import org.geysermc.cumulus.form.Form;
import org.geysermc.cumulus.form.util.FormBuilder; import org.geysermc.cumulus.form.util.FormBuilder;
import org.geysermc.erosion.packet.Packets; import org.geysermc.erosion.packet.Packets;
@ -58,6 +57,7 @@ import org.geysermc.geyser.api.event.lifecycle.GeyserShutdownEvent;
import org.geysermc.geyser.api.network.AuthType; import org.geysermc.geyser.api.network.AuthType;
import org.geysermc.geyser.api.network.BedrockListener; import org.geysermc.geyser.api.network.BedrockListener;
import org.geysermc.geyser.api.network.RemoteServer; import org.geysermc.geyser.api.network.RemoteServer;
import org.geysermc.geyser.api.util.PlatformType;
import org.geysermc.geyser.command.GeyserCommandManager; import org.geysermc.geyser.command.GeyserCommandManager;
import org.geysermc.geyser.configuration.GeyserConfiguration; import org.geysermc.geyser.configuration.GeyserConfiguration;
import org.geysermc.geyser.entity.EntityDefinitions; import org.geysermc.geyser.entity.EntityDefinitions;
@ -485,12 +485,6 @@ public class GeyserImpl implements GeyserApi {
} }
if (config.getRemote().authType() == AuthType.ONLINE) { if (config.getRemote().authType() == AuthType.ONLINE) {
if (config.getUserAuths() != null && !config.getUserAuths().isEmpty()) {
getLogger().warning("The 'userAuths' config section is now deprecated, and will be removed in the near future! " +
"Please migrate to the new 'saved-user-logins' config option: " +
"https://wiki.geysermc.org/geyser/understanding-the-config/");
}
// May be written/read to on multiple threads from each GeyserSession as well as writing the config // May be written/read to on multiple threads from each GeyserSession as well as writing the config
savedRefreshTokens = new ConcurrentHashMap<>(); savedRefreshTokens = new ConcurrentHashMap<>();

View File

@ -28,6 +28,7 @@ package org.geysermc.geyser;
import javax.swing.*; import javax.swing.*;
import java.io.InputStream; import java.io.InputStream;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
import java.util.Locale; import java.util.Locale;
import java.util.Scanner; import java.util.Scanner;
@ -60,7 +61,7 @@ public class GeyserMain {
helpStream = GeyserMain.class.getClassLoader().getResourceAsStream("languages/run-help/en_US.txt"); helpStream = GeyserMain.class.getClassLoader().getResourceAsStream("languages/run-help/en_US.txt");
} }
Scanner help = new Scanner(helpStream).useDelimiter("\\Z"); Scanner help = new Scanner(helpStream, StandardCharsets.UTF_8).useDelimiter("\\Z");
String line = ""; String line = "";
while (help.hasNext()) { while (help.hasNext()) {
line = help.next(); line = help.next();

View File

@ -44,7 +44,7 @@ public class StatisticsCommand extends GeyserCommand {
session.setWaitingForStatistics(true); session.setWaitingForStatistics(true);
ServerboundClientCommandPacket ServerboundClientCommandPacket = new ServerboundClientCommandPacket(ClientCommand.STATS); ServerboundClientCommandPacket ServerboundClientCommandPacket = new ServerboundClientCommandPacket(ClientCommand.STATS);
session.sendDownstreamPacket(ServerboundClientCommandPacket); session.sendDownstreamGamePacket(ServerboundClientCommandPacket);
} }
@Override @Override

View File

@ -36,7 +36,6 @@ import org.geysermc.geyser.text.GeyserLocale;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.List; import java.util.List;
import java.util.Map;
public interface GeyserConfiguration { public interface GeyserConfiguration {
/** /**
@ -55,9 +54,6 @@ public interface GeyserConfiguration {
List<String> getSavedUserLogins(); List<String> getSavedUserLogins();
@Deprecated
Map<String, ? extends IUserAuthenticationInfo> getUserAuths();
boolean isCommandSuggestions(); boolean isCommandSuggestions();
@JsonIgnore @JsonIgnore
@ -149,8 +145,6 @@ public interface GeyserConfiguration {
void setPort(int port); void setPort(int port);
boolean isPasswordAuthentication();
boolean isUseProxyProtocol(); boolean isUseProxyProtocol();
boolean isForwardHost(); boolean isForwardHost();
@ -173,18 +167,6 @@ public interface GeyserConfiguration {
boolean replaceSpaces(); boolean replaceSpaces();
} }
interface IUserAuthenticationInfo {
String getEmail();
String getPassword();
/**
* Will be removed after Microsoft accounts are fully migrated
*/
@Deprecated
boolean isMicrosoftAccount();
}
interface IMetricsInfo { interface IMetricsInfo {
boolean isEnabled(); boolean isEnabled();

View File

@ -44,7 +44,6 @@ import java.io.IOException;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.UUID; import java.util.UUID;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -79,8 +78,6 @@ public abstract class GeyserJacksonConfiguration implements GeyserConfiguration
public abstract Path getFloodgateKeyPath(); public abstract Path getFloodgateKeyPath();
private Map<String, UserAuthenticationInfo> userAuths;
@JsonProperty("command-suggestions") @JsonProperty("command-suggestions")
private boolean commandSuggestions = true; private boolean commandSuggestions = true;
@ -287,10 +284,6 @@ public abstract class GeyserJacksonConfiguration implements GeyserConfiguration
return false; return false;
} }
@Getter
@JsonProperty("allow-password-authentication")
private boolean passwordAuthentication = true;
@Getter @Getter
@JsonProperty("use-proxy-protocol") @JsonProperty("use-proxy-protocol")
private boolean useProxyProtocol = false; private boolean useProxyProtocol = false;
@ -300,19 +293,6 @@ public abstract class GeyserJacksonConfiguration implements GeyserConfiguration
private boolean forwardHost = false; private boolean forwardHost = false;
} }
@Getter
@JsonIgnoreProperties(ignoreUnknown = true) // DO NOT REMOVE THIS! Otherwise, after we remove microsoft-account configs will not load
public static class UserAuthenticationInfo implements IUserAuthenticationInfo {
@AsteriskSerializer.Asterisk()
private String email;
@AsteriskSerializer.Asterisk()
private String password;
@JsonProperty("microsoft-account")
private boolean microsoftAccount = false;
}
@Getter @Getter
@JsonIgnoreProperties(ignoreUnknown = true) @JsonIgnoreProperties(ignoreUnknown = true)
public static class MetricsInfo implements IMetricsInfo { public static class MetricsInfo implements IMetricsInfo {

View File

@ -68,7 +68,7 @@ public class InteractionEntity extends Entity {
animatePacket.setAction(AnimatePacket.Action.SWING_ARM); animatePacket.setAction(AnimatePacket.Action.SWING_ARM);
session.sendUpstreamPacket(animatePacket); session.sendUpstreamPacket(animatePacket);
session.sendDownstreamPacket(new ServerboundSwingPacket(hand)); session.sendDownstreamGamePacket(new ServerboundSwingPacket(hand));
return InteractionResult.SUCCESS; return InteractionResult.SUCCESS;
} }

View File

@ -27,6 +27,7 @@ package org.geysermc.geyser.extension;
import it.unimi.dsi.fastutil.objects.Object2ObjectMap; import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.api.extension.Extension; import org.geysermc.geyser.api.extension.Extension;
import org.geysermc.geyser.api.extension.ExtensionDescription; import org.geysermc.geyser.api.extension.ExtensionDescription;
import org.geysermc.geyser.api.extension.exception.InvalidExtensionException; import org.geysermc.geyser.api.extension.exception.InvalidExtensionException;
@ -39,14 +40,17 @@ import java.nio.file.Path;
public class GeyserExtensionClassLoader extends URLClassLoader { public class GeyserExtensionClassLoader extends URLClassLoader {
private final GeyserExtensionLoader loader; private final GeyserExtensionLoader loader;
private final ExtensionDescription description;
private final Object2ObjectMap<String, Class<?>> classes = new Object2ObjectOpenHashMap<>(); private final Object2ObjectMap<String, Class<?>> classes = new Object2ObjectOpenHashMap<>();
private boolean warnedForExternalClassAccess;
public GeyserExtensionClassLoader(GeyserExtensionLoader loader, ClassLoader parent, Path path) throws MalformedURLException { public GeyserExtensionClassLoader(GeyserExtensionLoader loader, ClassLoader parent, Path path, ExtensionDescription description) throws MalformedURLException {
super(new URL[] { path.toUri().toURL() }, parent); super(new URL[] { path.toUri().toURL() }, parent);
this.loader = loader; this.loader = loader;
this.description = description;
} }
public Extension load(ExtensionDescription description) throws InvalidExtensionException { public Extension load() throws InvalidExtensionException {
try { try {
Class<?> jarClass; Class<?> jarClass;
try { try {
@ -76,22 +80,32 @@ public class GeyserExtensionClassLoader extends URLClassLoader {
} }
protected Class<?> findClass(String name, boolean checkGlobal) throws ClassNotFoundException { protected Class<?> findClass(String name, boolean checkGlobal) throws ClassNotFoundException {
if (name.startsWith("org.geysermc.geyser.") || name.startsWith("net.minecraft.")) {
throw new ClassNotFoundException(name);
}
Class<?> result = this.classes.get(name); Class<?> result = this.classes.get(name);
if (result == null) { if (result == null) {
result = super.findClass(name); // Try to find class in current extension
if (result == null && checkGlobal) { try {
result = this.loader.classByName(name); result = super.findClass(name);
} catch (ClassNotFoundException ignored) {
// If class is not found in current extension, check in the global class loader
// This is used for classes that are not in the extension, but are in other extensions
if (checkGlobal) {
if (!warnedForExternalClassAccess) {
GeyserImpl.getInstance().getLogger().warning("Extension " + this.description.name() + " loads class " + name + " from an external source. " +
"This can change at any time and break the extension, additionally to potentially causing unexpected behaviour!");
warnedForExternalClassAccess = true;
}
result = this.loader.classByName(name);
}
} }
if (result != null) { if (result != null) {
// If class is found, cache it
this.loader.setClass(name, result); this.loader.setClass(name, result);
this.classes.put(name, result);
} else {
// If class is not found, throw exception
throw new ClassNotFoundException(name);
} }
this.classes.put(name, result);
} }
return result; return result;
} }

View File

@ -43,9 +43,9 @@ import java.io.Reader;
import java.nio.file.*; import java.nio.file.*;
import java.util.HashMap; import java.util.HashMap;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.stream.Stream;
@RequiredArgsConstructor @RequiredArgsConstructor
public class GeyserExtensionLoader extends ExtensionLoader { public class GeyserExtensionLoader extends ExtensionLoader {
@ -66,26 +66,38 @@ public class GeyserExtensionLoader extends ExtensionLoader {
} }
Path parentFile = path.getParent(); Path parentFile = path.getParent();
Path dataFolder = parentFile.resolve(description.name());
// Extension folders used to be created by name; this changes them to the ID
Path oldDataFolder = parentFile.resolve(description.name());
Path dataFolder = parentFile.resolve(description.id());
if (Files.exists(oldDataFolder) && Files.isDirectory(oldDataFolder) && !oldDataFolder.equals(dataFolder)) {
try {
Files.move(oldDataFolder, dataFolder, StandardCopyOption.REPLACE_EXISTING);
} catch (IOException e) {
throw new InvalidExtensionException("Failed to move data folder for extension " + description.name(), e);
}
}
if (Files.exists(dataFolder) && !Files.isDirectory(dataFolder)) { if (Files.exists(dataFolder) && !Files.isDirectory(dataFolder)) {
throw new InvalidExtensionException("The folder " + dataFolder + " is not a directory and is the data folder for the extension " + description.name() + "!"); throw new InvalidExtensionException("The folder " + dataFolder + " is not a directory and is the data folder for the extension " + description.name() + "!");
} }
final GeyserExtensionClassLoader loader; final GeyserExtensionClassLoader loader;
try { try {
loader = new GeyserExtensionClassLoader(this, getClass().getClassLoader(), path); loader = new GeyserExtensionClassLoader(this, getClass().getClassLoader(), path, description);
} catch (Throwable e) { } catch (Throwable e) {
throw new InvalidExtensionException(e); throw new InvalidExtensionException(e);
} }
this.classLoaders.put(description.name(), loader); this.classLoaders.put(description.id(), loader);
final Extension extension = loader.load(description); final Extension extension = loader.load();
return this.setup(extension, description, dataFolder, new GeyserExtensionEventBus(GeyserImpl.getInstance().eventBus(), extension)); return this.setup(extension, description, dataFolder, new GeyserExtensionEventBus(GeyserImpl.getInstance().eventBus(), extension));
} }
private GeyserExtensionContainer setup(Extension extension, GeyserExtensionDescription description, Path dataFolder, ExtensionEventBus eventBus) { private GeyserExtensionContainer setup(Extension extension, GeyserExtensionDescription description, Path dataFolder, ExtensionEventBus eventBus) {
GeyserExtensionLogger logger = new GeyserExtensionLogger(GeyserImpl.getInstance().getLogger(), description.name()); GeyserExtensionLogger logger = new GeyserExtensionLogger(GeyserImpl.getInstance().getLogger(), description.id());
return new GeyserExtensionContainer(extension, dataFolder, description, this, logger, eventBus); return new GeyserExtensionContainer(extension, dataFolder, description, this, logger, eventBus);
} }
@ -136,46 +148,46 @@ public class GeyserExtensionLoader extends ExtensionLoader {
Map<String, GeyserExtensionContainer> loadedExtensions = new LinkedHashMap<>(); Map<String, GeyserExtensionContainer> loadedExtensions = new LinkedHashMap<>();
Pattern[] extensionFilters = this.extensionFilters(); Pattern[] extensionFilters = this.extensionFilters();
try (Stream<Path> entries = Files.walk(extensionsDirectory)) { List<Path> extensionPaths = Files.walk(extensionsDirectory).toList();
entries.forEach(path -> { extensionPaths.forEach(path -> {
if (Files.isDirectory(path)) { if (Files.isDirectory(path)) {
return;
}
for (Pattern filter : extensionFilters) {
if (!filter.matcher(path.getFileName().toString()).matches()) {
return;
}
}
try {
GeyserExtensionDescription description = this.extensionDescription(path);
String name = description.name();
String id = description.id();
if (extensions.containsKey(id) || extensionManager.extension(id) != null) {
GeyserImpl.getInstance().getLogger().warning(GeyserLocale.getLocaleStringLog("geyser.extensions.load.duplicate", name, path.toString()));
return; return;
} }
for (Pattern filter : extensionFilters) { // Completely different API version
if (!filter.matcher(path.getFileName().toString()).matches()) { if (description.majorApiVersion() != Geyser.api().majorApiVersion()) {
return; GeyserImpl.getInstance().getLogger().error(GeyserLocale.getLocaleStringLog("geyser.extensions.load.failed_api_version", name, description.apiVersion()));
} return;
} }
try { // If the extension requires new API features, being backwards compatible
GeyserExtensionDescription description = this.extensionDescription(path); if (description.minorApiVersion() > Geyser.api().minorApiVersion()) {
GeyserImpl.getInstance().getLogger().error(GeyserLocale.getLocaleStringLog("geyser.extensions.load.failed_api_version", name, description.apiVersion()));
String name = description.name(); return;
if (extensions.containsKey(name) || extensionManager.extension(name) != null) {
GeyserImpl.getInstance().getLogger().warning(GeyserLocale.getLocaleStringLog("geyser.extensions.load.duplicate", name, path.toString()));
return;
}
// Completely different API version
if (description.majorApiVersion() != Geyser.api().majorApiVersion()) {
GeyserImpl.getInstance().getLogger().error(GeyserLocale.getLocaleStringLog("geyser.extensions.load.failed_api_version", name, description.apiVersion()));
return;
}
// If the extension requires new API features, being backwards compatible
if (description.minorApiVersion() > Geyser.api().minorApiVersion()) {
GeyserImpl.getInstance().getLogger().error(GeyserLocale.getLocaleStringLog("geyser.extensions.load.failed_api_version", name, description.apiVersion()));
return;
}
extensions.put(name, path);
loadedExtensions.put(name, this.loadExtension(path, description));
} catch (Exception e) {
GeyserImpl.getInstance().getLogger().error(GeyserLocale.getLocaleStringLog("geyser.extensions.load.failed_with_name", path.getFileName(), path.toAbsolutePath()), e);
} }
});
} extensions.put(id, path);
loadedExtensions.put(id, this.loadExtension(path, description));
} catch (Exception e) {
GeyserImpl.getInstance().getLogger().error(GeyserLocale.getLocaleStringLog("geyser.extensions.load.failed_with_name", path.getFileName(), path.toAbsolutePath()), e);
}
});
for (GeyserExtensionContainer container : loadedExtensions.values()) { for (GeyserExtensionContainer container : loadedExtensions.values()) {
this.extensionContainers.put(container.extension(), container); this.extensionContainers.put(container.extension(), container);

View File

@ -52,8 +52,8 @@ public class GeyserExtensionManager extends ExtensionManager {
} }
@Override @Override
public Extension extension(@NonNull String name) { public Extension extension(@NonNull String id) {
return this.extensions.get(name); return this.extensions.get(id);
} }
@Override @Override
@ -83,7 +83,7 @@ public class GeyserExtensionManager extends ExtensionManager {
if (!extension.isEnabled()) { if (!extension.isEnabled()) {
extension.setEnabled(true); extension.setEnabled(true);
GeyserImpl.getInstance().eventBus().register(extension, extension); GeyserImpl.getInstance().eventBus().register(extension, extension);
GeyserImpl.getInstance().getLogger().info(GeyserLocale.getLocaleStringLog("geyser.extensions.enable.success", extension.description().name())); GeyserImpl.getInstance().getLogger().info(GeyserLocale.getLocaleStringLog("geyser.extensions.enable.success", extension.name()));
} }
} }
@ -98,7 +98,7 @@ public class GeyserExtensionManager extends ExtensionManager {
GeyserImpl.getInstance().eventBus().unregisterAll(extension); GeyserImpl.getInstance().eventBus().unregisterAll(extension);
extension.setEnabled(false); extension.setEnabled(false);
GeyserImpl.getInstance().getLogger().info(GeyserLocale.getLocaleStringLog("geyser.extensions.disable.success", extension.description().name())); GeyserImpl.getInstance().getLogger().info(GeyserLocale.getLocaleStringLog("geyser.extensions.disable.success", extension.name()));
} }
} }
@ -121,6 +121,6 @@ public class GeyserExtensionManager extends ExtensionManager {
@Override @Override
public void register(@NonNull Extension extension) { public void register(@NonNull Extension extension) {
this.extensions.put(extension.name(), extension); this.extensions.put(extension.description().id(), extension);
} }
} }

View File

@ -82,14 +82,14 @@ public class AnvilContainer extends Container {
correctRename = plainNewName; correctRename = plainNewName;
// Java Edition sends a packet every time an item is renamed even slightly in GUI. Fortunately, this works out for us now // Java Edition sends a packet every time an item is renamed even slightly in GUI. Fortunately, this works out for us now
ServerboundRenameItemPacket renameItemPacket = new ServerboundRenameItemPacket(plainNewName); ServerboundRenameItemPacket renameItemPacket = new ServerboundRenameItemPacket(plainNewName);
session.sendDownstreamPacket(renameItemPacket); session.sendDownstreamGamePacket(renameItemPacket);
} else { } else {
// Restore formatting for item since we're not renaming // Restore formatting for item since we're not renaming
correctRename = MessageTranslator.convertMessageLenient(originalName); correctRename = MessageTranslator.convertMessageLenient(originalName);
// Java Edition sends the original custom name when not renaming, // Java Edition sends the original custom name when not renaming,
// if there isn't a custom name an empty string is sent // if there isn't a custom name an empty string is sent
ServerboundRenameItemPacket renameItemPacket = new ServerboundRenameItemPacket(plainOriginalName); ServerboundRenameItemPacket renameItemPacket = new ServerboundRenameItemPacket(plainOriginalName);
session.sendDownstreamPacket(renameItemPacket); session.sendDownstreamGamePacket(renameItemPacket);
} }
useJavaLevelCost = false; useJavaLevelCost = false;

View File

@ -152,7 +152,7 @@ public final class ClickPlan {
changedItems changedItems
); );
session.sendDownstreamPacket(clickPacket); session.sendDownstreamGamePacket(clickPacket);
} }
session.getPlayerInventory().setCursor(simulatedCursor, session); session.getPlayerInventory().setCursor(simulatedCursor, session);

View File

@ -31,7 +31,7 @@ import java.util.Locale;
/** /**
* Potion identifiers and their respective Bedrock IDs used with arrows. * Potion identifiers and their respective Bedrock IDs used with arrows.
* https://minecraft.gamepedia.com/Arrow#Item_Data * https://minecraft.wiki/w/Arrow#Data_values
*/ */
@Getter @Getter
public enum TippedArrowPotion { public enum TippedArrowPotion {

View File

@ -120,7 +120,7 @@ public class AnvilInventoryUpdater extends InventoryUpdater {
// does not result in a FilterTextPacket // does not result in a FilterTextPacket
String originalName = MessageTranslator.convertToPlainTextLenient(ItemUtils.getCustomName(input.getNbt()), session.locale()); String originalName = MessageTranslator.convertToPlainTextLenient(ItemUtils.getCustomName(input.getNbt()), session.locale());
ServerboundRenameItemPacket renameItemPacket = new ServerboundRenameItemPacket(originalName); ServerboundRenameItemPacket renameItemPacket = new ServerboundRenameItemPacket(originalName);
session.sendDownstreamPacket(renameItemPacket); session.sendDownstreamGamePacket(renameItemPacket);
anvilContainer.setNewName(null); anvilContainer.setNewName(null);
} }

View File

@ -52,11 +52,6 @@ public class GeyserAdvancement {
return this.advancement.getId(); return this.advancement.getId();
} }
@NonNull
public List<String> getCriteria() {
return this.advancement.getCriteria();
}
@NonNull @NonNull
public List<List<String>> getRequirements() { public List<List<String>> getRequirements() {
return this.advancement.getRequirements(); return this.advancement.getRequirements();

View File

@ -173,8 +173,8 @@ public final class BlockStateValues {
} }
if (javaId.contains("wall_skull") || javaId.contains("wall_head")) { if (javaId.contains("wall_skull") || javaId.contains("wall_head")) {
String direction = javaId.substring(javaId.lastIndexOf("facing=") + 7); String direction = javaId.substring(javaId.lastIndexOf("facing=") + 7, javaId.lastIndexOf("powered=") - 1);
int rotation = switch (direction.substring(0, direction.length() - 1)) { int rotation = switch (direction) {
case "north" -> 180; case "north" -> 180;
case "west" -> 90; case "west" -> 90;
case "east" -> 270; case "east" -> 270;

View File

@ -46,7 +46,9 @@ public final class GameProtocol {
* Default Bedrock codec that should act as a fallback. Should represent the latest available * Default Bedrock codec that should act as a fallback. Should represent the latest available
* release of the game that Geyser supports. * release of the game that Geyser supports.
*/ */
public static final BedrockCodec DEFAULT_BEDROCK_CODEC = Bedrock_v618.CODEC; public static final BedrockCodec DEFAULT_BEDROCK_CODEC = Bedrock_v618.CODEC.toBuilder()
.minecraftVersion("1.20.31")
.build();
/** /**
* A list of all supported Bedrock versions that can join Geyser * A list of all supported Bedrock versions that can join Geyser
@ -66,7 +68,9 @@ public final class GameProtocol {
SUPPORTED_BEDROCK_CODECS.add(Bedrock_v594.CODEC.toBuilder() SUPPORTED_BEDROCK_CODECS.add(Bedrock_v594.CODEC.toBuilder()
.minecraftVersion("1.20.10/1.20.15") .minecraftVersion("1.20.10/1.20.15")
.build()); .build());
SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC); SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC.toBuilder()
.minecraftVersion("1.20.30/1.20.31")
.build());
} }
/** /**

View File

@ -47,6 +47,10 @@ public class GeyserServerInitializer extends BedrockServerInitializer {
this.geyser = geyser; this.geyser = geyser;
} }
public DefaultEventLoopGroup getEventLoopGroup() {
return eventLoopGroup;
}
@Override @Override
public void initSession(@Nonnull BedrockServerSession bedrockServerSession) { public void initSession(@Nonnull BedrockServerSession bedrockServerSession) {
try { try {
@ -72,4 +76,4 @@ public class GeyserServerInitializer extends BedrockServerInitializer {
protected BedrockPeer createPeer(Channel channel) { protected BedrockPeer createPeer(Channel channel) {
return new GeyserBedrockPeer(channel, this::createSession); return new GeyserBedrockPeer(channel, this::createSession);
} }
} }

View File

@ -52,7 +52,6 @@ import org.geysermc.geyser.api.network.AuthType;
import org.geysermc.geyser.api.pack.PackCodec; import org.geysermc.geyser.api.pack.PackCodec;
import org.geysermc.geyser.api.pack.ResourcePack; import org.geysermc.geyser.api.pack.ResourcePack;
import org.geysermc.geyser.api.pack.ResourcePackManifest; import org.geysermc.geyser.api.pack.ResourcePackManifest;
import org.geysermc.geyser.configuration.GeyserConfiguration;
import org.geysermc.geyser.event.type.SessionLoadResourcePacksEventImpl; import org.geysermc.geyser.event.type.SessionLoadResourcePacksEventImpl;
import org.geysermc.geyser.pack.GeyserResourcePack; import org.geysermc.geyser.pack.GeyserResourcePack;
import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.BlockRegistries;
@ -257,21 +256,9 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
return true; return true;
} }
} }
if (geyser.getConfig().getUserAuths() != null) {
GeyserConfiguration.IUserAuthenticationInfo info = geyser.getConfig().getUserAuths().get(bedrockUsername);
if (info != null) {
geyser.getLogger().info(GeyserLocale.getLocaleStringLog("geyser.auth.stored_credentials", session.getAuthData().name()));
session.setMicrosoftAccount(info.isMicrosoftAccount());
session.authenticate(info.getEmail(), info.getPassword());
return true;
}
}
PendingMicrosoftAuthentication.AuthenticationTask task = geyser.getPendingMicrosoftAuthentication().getTask(session.getAuthData().xuid()); PendingMicrosoftAuthentication.AuthenticationTask task = geyser.getPendingMicrosoftAuthentication().getTask(session.getAuthData().xuid());
if (task != null) { if (task != null) {
if (task.getAuthentication().isDone() && session.onMicrosoftLoginComplete(task)) { return task.getAuthentication().isDone() && session.onMicrosoftLoginComplete(task);
return true;
}
} }
return false; return false;

View File

@ -39,6 +39,7 @@ import io.netty.channel.kqueue.KQueueEventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.DatagramChannel; import io.netty.channel.socket.DatagramChannel;
import io.netty.channel.socket.nio.NioDatagramChannel; import io.netty.channel.socket.nio.NioDatagramChannel;
import io.netty.util.concurrent.Future;
import lombok.Getter; import lombok.Getter;
import net.jodah.expiringmap.ExpirationPolicy; import net.jodah.expiringmap.ExpirationPolicy;
import net.jodah.expiringmap.ExpiringMap; import net.jodah.expiringmap.ExpiringMap;
@ -58,6 +59,7 @@ import org.geysermc.geyser.network.netty.handler.RakPingHandler;
import org.geysermc.geyser.network.netty.proxy.ProxyServerHandler; import org.geysermc.geyser.network.netty.proxy.ProxyServerHandler;
import org.geysermc.geyser.ping.GeyserPingInfo; import org.geysermc.geyser.ping.GeyserPingInfo;
import org.geysermc.geyser.ping.IGeyserPingPassthrough; import org.geysermc.geyser.ping.IGeyserPingPassthrough;
import org.geysermc.geyser.skin.SkinProvider;
import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.text.GeyserLocale;
import org.geysermc.geyser.translator.text.MessageTranslator; import org.geysermc.geyser.translator.text.MessageTranslator;
@ -83,14 +85,21 @@ public final class GeyserServer {
private static final Transport TRANSPORT = compatibleTransport(); private static final Transport TRANSPORT = compatibleTransport();
/**
* See {@link EventLoopGroup#shutdownGracefully(long, long, TimeUnit)}
*/
private static final int SHUTDOWN_QUIET_PERIOD_MS = 100;
private static final int SHUTDOWN_TIMEOUT_MS = 500;
private final GeyserImpl geyser; private final GeyserImpl geyser;
private final EventLoopGroup group; private EventLoopGroup group;
private final ServerBootstrap bootstrap; private final ServerBootstrap bootstrap;
private EventLoopGroup playerGroup;
@Getter @Getter
private final ExpiringMap<InetSocketAddress, InetSocketAddress> proxiedAddresses; private final ExpiringMap<InetSocketAddress, InetSocketAddress> proxiedAddresses;
private ChannelFuture future; private ChannelFuture bootstrapFuture;
public GeyserServer(GeyserImpl geyser, int threadCount) { public GeyserServer(GeyserImpl geyser, int threadCount) {
this.geyser = geyser; this.geyser = geyser;
@ -109,7 +118,7 @@ public final class GeyserServer {
public CompletableFuture<Void> bind(InetSocketAddress address) { public CompletableFuture<Void> bind(InetSocketAddress address) {
CompletableFuture<Void> future = new CompletableFuture<>(); CompletableFuture<Void> future = new CompletableFuture<>();
this.future = this.bootstrap.bind(address).addListener(bindResult -> { this.bootstrapFuture = this.bootstrap.bind(address).addListener(bindResult -> {
if (bindResult.cause() != null) { if (bindResult.cause() != null) {
future.completeExceptionally(bindResult.cause()); future.completeExceptionally(bindResult.cause());
return; return;
@ -117,7 +126,7 @@ public final class GeyserServer {
future.complete(null); future.complete(null);
}); });
Channel channel = this.future.channel(); Channel channel = this.bootstrapFuture.channel();
// Add our ping handler // Add our ping handler
channel.pipeline() channel.pipeline()
@ -132,8 +141,19 @@ public final class GeyserServer {
} }
public void shutdown() { public void shutdown() {
this.group.shutdownGracefully(); try {
this.future.channel().closeFuture().syncUninterruptibly(); Future<?> future1 = this.group.shutdownGracefully(SHUTDOWN_QUIET_PERIOD_MS, SHUTDOWN_TIMEOUT_MS, TimeUnit.MILLISECONDS);
this.group = null;
Future<?> future2 = this.playerGroup.shutdownGracefully(SHUTDOWN_QUIET_PERIOD_MS, SHUTDOWN_TIMEOUT_MS, TimeUnit.MILLISECONDS);
this.playerGroup = null;
future1.sync();
future2.sync();
SkinProvider.shutdown();
} catch (InterruptedException e) {
GeyserImpl.getInstance().getLogger().severe("Exception in shutdown process", e);
}
this.bootstrapFuture.channel().closeFuture().syncUninterruptibly();
} }
private ServerBootstrap createBootstrap(EventLoopGroup group) { private ServerBootstrap createBootstrap(EventLoopGroup group) {
@ -149,11 +169,13 @@ public final class GeyserServer {
} }
} }
GeyserServerInitializer serverInitializer = new GeyserServerInitializer(this.geyser);
playerGroup = serverInitializer.getEventLoopGroup();
return new ServerBootstrap() return new ServerBootstrap()
.channelFactory(RakChannelFactory.server(TRANSPORT.datagramChannel())) .channelFactory(RakChannelFactory.server(TRANSPORT.datagramChannel()))
.group(group) .group(group)
.option(RakChannelOption.RAK_HANDLE_PING, true) .option(RakChannelOption.RAK_HANDLE_PING, true)
.childHandler(new GeyserServerInitializer(this.geyser)); .childHandler(serverInitializer);
} }
public boolean onConnectionRequest(InetSocketAddress inetSocketAddress) { public boolean onConnectionRequest(InetSocketAddress inetSocketAddress) {
@ -217,7 +239,7 @@ public final class GeyserServer {
.version(GameProtocol.DEFAULT_BEDROCK_CODEC.getMinecraftVersion()) // Required to not be empty as of 1.16.210.59. Can only contain . and numbers. .version(GameProtocol.DEFAULT_BEDROCK_CODEC.getMinecraftVersion()) // Required to not be empty as of 1.16.210.59. Can only contain . and numbers.
.ipv4Port(this.geyser.getConfig().getBedrock().port()) .ipv4Port(this.geyser.getConfig().getBedrock().port())
.ipv6Port(this.geyser.getConfig().getBedrock().port()) .ipv6Port(this.geyser.getConfig().getBedrock().port())
.serverId(future.channel().config().getOption(RakChannelOption.RAK_GUID)); .serverId(bootstrapFuture.channel().config().getOption(RakChannelOption.RAK_GUID));
if (config.isPassthroughMotd() && pingInfo != null && pingInfo.getDescription() != null) { if (config.isPassthroughMotd() && pingInfo != null && pingInfo.getDescription() != null) {
String[] motd = MessageTranslator.convertMessageLenient(pingInfo.getDescription()).split("\n"); String[] motd = MessageTranslator.convertMessageLenient(pingInfo.getDescription()).split("\n");

View File

@ -27,9 +27,9 @@ package org.geysermc.geyser.registry;
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundDelimiterPacket; import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundDelimiterPacket;
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundTabListPacket; import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundTabListPacket;
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.ClientboundChunkBatchStartPacket;
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.ClientboundLightUpdatePacket; import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.ClientboundLightUpdatePacket;
import io.netty.channel.EventLoop; import io.netty.channel.EventLoop;
import org.cloudburstmc.protocol.bedrock.packet.RequestPermissionsPacket;
import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.registry.loader.RegistryLoaders; import org.geysermc.geyser.registry.loader.RegistryLoaders;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
@ -44,10 +44,10 @@ public class PacketTranslatorRegistry<T> extends AbstractMappedRegistry<Class<?
private static final Set<Class<?>> IGNORED_PACKETS = Collections.newSetFromMap(new IdentityHashMap<>()); private static final Set<Class<?>> IGNORED_PACKETS = Collections.newSetFromMap(new IdentityHashMap<>());
static { static {
IGNORED_PACKETS.add(ClientboundChunkBatchStartPacket.class); // we don't track chunk batch sizes/periods
IGNORED_PACKETS.add(ClientboundDelimiterPacket.class); // Not implemented, spams logs
IGNORED_PACKETS.add(ClientboundLightUpdatePacket.class); // Light is handled on Bedrock for us IGNORED_PACKETS.add(ClientboundLightUpdatePacket.class); // Light is handled on Bedrock for us
IGNORED_PACKETS.add(ClientboundTabListPacket.class); // Cant be implemented in Bedrock IGNORED_PACKETS.add(ClientboundTabListPacket.class); // Cant be implemented in Bedrock
IGNORED_PACKETS.add(ClientboundDelimiterPacket.class); // Not implemented, spams logs
IGNORED_PACKETS.add(RequestPermissionsPacket.class); // Bedrock client asks permission to switch default game mode, but we handle this ourselves
} }
protected PacketTranslatorRegistry() { protected PacketTranslatorRegistry() {

View File

@ -72,9 +72,9 @@ public class CustomBlockRegistryPopulator {
private static Set<CustomBlockData> CUSTOM_BLOCKS; private static Set<CustomBlockData> CUSTOM_BLOCKS;
private static Set<String> CUSTOM_BLOCK_NAMES; private static Set<String> CUSTOM_BLOCK_NAMES;
private static Int2ObjectMap<CustomBlockState> BLOCK_STATE_OVERRIDES;
private static Map<String, CustomBlockData> CUSTOM_BLOCK_ITEM_OVERRIDES; private static Map<String, CustomBlockData> CUSTOM_BLOCK_ITEM_OVERRIDES;
private static Map<JavaBlockState, CustomBlockState> NON_VANILLA_BLOCK_STATE_OVERRIDES; private static Map<JavaBlockState, CustomBlockState> NON_VANILLA_BLOCK_STATE_OVERRIDES;
private static Map<String, CustomBlockState> BLOCK_STATE_OVERRIDES_QUEUE;
/** /**
* Initializes custom blocks defined by API * Initializes custom blocks defined by API
@ -82,9 +82,9 @@ public class CustomBlockRegistryPopulator {
private static void populateBedrock() { private static void populateBedrock() {
CUSTOM_BLOCKS = new ObjectOpenHashSet<>(); CUSTOM_BLOCKS = new ObjectOpenHashSet<>();
CUSTOM_BLOCK_NAMES = new ObjectOpenHashSet<>(); CUSTOM_BLOCK_NAMES = new ObjectOpenHashSet<>();
BLOCK_STATE_OVERRIDES = new Int2ObjectOpenHashMap<>();
CUSTOM_BLOCK_ITEM_OVERRIDES = new HashMap<>(); CUSTOM_BLOCK_ITEM_OVERRIDES = new HashMap<>();
NON_VANILLA_BLOCK_STATE_OVERRIDES = new HashMap<>(); NON_VANILLA_BLOCK_STATE_OVERRIDES = new HashMap<>();
BLOCK_STATE_OVERRIDES_QUEUE = new HashMap<>();
GeyserImpl.getInstance().getEventBus().fire(new GeyserDefineCustomBlocksEvent() { GeyserImpl.getInstance().getEventBus().fire(new GeyserDefineCustomBlocksEvent() {
@Override @Override
@ -103,18 +103,11 @@ public class CustomBlockRegistryPopulator {
@Override @Override
public void registerOverride(@NonNull String javaIdentifier, @NonNull CustomBlockState customBlockState) { public void registerOverride(@NonNull String javaIdentifier, @NonNull CustomBlockState customBlockState) {
int id = BlockRegistries.JAVA_IDENTIFIER_TO_ID.getOrDefault(javaIdentifier, -1);
if (id == -1) {
throw new IllegalArgumentException("Unknown Java block state. Identifier: " + javaIdentifier);
}
if (!CUSTOM_BLOCKS.contains(customBlockState.block())) { if (!CUSTOM_BLOCKS.contains(customBlockState.block())) {
throw new IllegalArgumentException("Custom block is unregistered. Name: " + customBlockState.name()); throw new IllegalArgumentException("Custom block is unregistered. Name: " + customBlockState.name());
} }
CustomBlockState oldBlockState = BLOCK_STATE_OVERRIDES.put(id, customBlockState); // We can't register these yet as we don't have the java block id registry populated
if (oldBlockState != null) { BLOCK_STATE_OVERRIDES_QUEUE.put(javaIdentifier, customBlockState);
GeyserImpl.getInstance().getLogger().debug("Duplicate block state override for Java Identifier: " +
javaIdentifier + " Old override: " + oldBlockState.name() + " New override: " + customBlockState.name());
}
} }
@Override @Override
@ -139,10 +132,28 @@ public class CustomBlockRegistryPopulator {
* Registers all vanilla custom blocks and skulls defined by API and mappings * Registers all vanilla custom blocks and skulls defined by API and mappings
*/ */
private static void populateVanilla() { private static void populateVanilla() {
Int2ObjectMap<CustomBlockState> blockStateOverrides = new Int2ObjectOpenHashMap<>();
for (CustomSkull customSkull : BlockRegistries.CUSTOM_SKULLS.get().values()) { for (CustomSkull customSkull : BlockRegistries.CUSTOM_SKULLS.get().values()) {
CUSTOM_BLOCKS.add(customSkull.getCustomBlockData()); CUSTOM_BLOCKS.add(customSkull.getCustomBlockData());
} }
for(Map.Entry<String, CustomBlockState> entry : BLOCK_STATE_OVERRIDES_QUEUE.entrySet()) {
int id = BlockRegistries.JAVA_IDENTIFIER_TO_ID.getOrDefault(entry.getKey(), -1);
if (id == -1) {
GeyserImpl.getInstance().getLogger().warning("Custom block state override for Java Identifier: " +
entry.getKey() + " could not be registered as it is not a valid block state.");
continue;
}
CustomBlockState oldBlockState = blockStateOverrides.put(id, entry.getValue());
if (oldBlockState != null) {
GeyserImpl.getInstance().getLogger().warning("Duplicate block state override for Java Identifier: " +
entry.getKey() + " Old override: " + oldBlockState.name() + " New override: " + entry.getValue().name());
}
}
BLOCK_STATE_OVERRIDES_QUEUE = null;
Map<CustomBlockData, Set<Integer>> extendedCollisionBoxes = new HashMap<>(); Map<CustomBlockData, Set<Integer>> extendedCollisionBoxes = new HashMap<>();
Map<BoxComponent, CustomBlockData> extendedCollisionBoxSet = new HashMap<>(); Map<BoxComponent, CustomBlockData> extendedCollisionBoxSet = new HashMap<>();
MappingsConfigReader mappingsConfigReader = new MappingsConfigReader(); MappingsConfigReader mappingsConfigReader = new MappingsConfigReader();
@ -153,7 +164,7 @@ public class CustomBlockRegistryPopulator {
} }
block.states().forEach((javaIdentifier, customBlockState) -> { block.states().forEach((javaIdentifier, customBlockState) -> {
int id = BlockRegistries.JAVA_IDENTIFIER_TO_ID.getOrDefault(javaIdentifier, -1); int id = BlockRegistries.JAVA_IDENTIFIER_TO_ID.getOrDefault(javaIdentifier, -1);
BLOCK_STATE_OVERRIDES.put(id, customBlockState.state()); blockStateOverrides.put(id, customBlockState.state());
BoxComponent extendedCollisionBox = customBlockState.extendedCollisionBox(); BoxComponent extendedCollisionBox = customBlockState.extendedCollisionBox();
if (extendedCollisionBox != null) { if (extendedCollisionBox != null) {
CustomBlockData extendedCollisionBlock = extendedCollisionBoxSet.computeIfAbsent(extendedCollisionBox, box -> { CustomBlockData extendedCollisionBlock = extendedCollisionBoxSet.computeIfAbsent(extendedCollisionBox, box -> {
@ -167,9 +178,9 @@ public class CustomBlockRegistryPopulator {
}); });
}); });
BlockRegistries.CUSTOM_BLOCK_STATE_OVERRIDES.set(BLOCK_STATE_OVERRIDES); BlockRegistries.CUSTOM_BLOCK_STATE_OVERRIDES.set(blockStateOverrides);
if (BLOCK_STATE_OVERRIDES.size() != 0) { if (blockStateOverrides.size() != 0) {
GeyserImpl.getInstance().getLogger().info("Registered " + BLOCK_STATE_OVERRIDES.size() + " custom block overrides."); GeyserImpl.getInstance().getLogger().info("Registered " + blockStateOverrides.size() + " custom block overrides.");
} }
BlockRegistries.CUSTOM_BLOCK_ITEM_OVERRIDES.set(CUSTOM_BLOCK_ITEM_OVERRIDES); BlockRegistries.CUSTOM_BLOCK_ITEM_OVERRIDES.set(CUSTOM_BLOCK_ITEM_OVERRIDES);

View File

@ -26,10 +26,7 @@
package org.geysermc.geyser.session; package org.geysermc.geyser.session;
import com.github.steveice10.mc.auth.data.GameProfile; import com.github.steveice10.mc.auth.data.GameProfile;
import com.github.steveice10.mc.auth.exception.request.InvalidCredentialsException;
import com.github.steveice10.mc.auth.exception.request.RequestException; import com.github.steveice10.mc.auth.exception.request.RequestException;
import com.github.steveice10.mc.auth.service.AuthenticationService;
import com.github.steveice10.mc.auth.service.MojangAuthenticationService;
import com.github.steveice10.mc.auth.service.MsaAuthenticationService; import com.github.steveice10.mc.auth.service.MsaAuthenticationService;
import com.github.steveice10.mc.protocol.MinecraftConstants; import com.github.steveice10.mc.protocol.MinecraftConstants;
import com.github.steveice10.mc.protocol.MinecraftProtocol; import com.github.steveice10.mc.protocol.MinecraftProtocol;
@ -45,15 +42,15 @@ import com.github.steveice10.mc.protocol.data.game.setting.ChatVisibility;
import com.github.steveice10.mc.protocol.data.game.setting.SkinPart; import com.github.steveice10.mc.protocol.data.game.setting.SkinPart;
import com.github.steveice10.mc.protocol.data.game.statistic.CustomStatistic; import com.github.steveice10.mc.protocol.data.game.statistic.CustomStatistic;
import com.github.steveice10.mc.protocol.data.game.statistic.Statistic; import com.github.steveice10.mc.protocol.data.game.statistic.Statistic;
import com.github.steveice10.mc.protocol.packet.common.serverbound.ServerboundClientInformationPacket;
import com.github.steveice10.mc.protocol.packet.handshake.serverbound.ClientIntentionPacket; import com.github.steveice10.mc.protocol.packet.handshake.serverbound.ClientIntentionPacket;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundChatCommandPacket; import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundChatCommandPacket;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundChatPacket; import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundChatPacket;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundClientInformationPacket;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundMovePlayerPosPacket; import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundMovePlayerPosPacket;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundPlayerAbilitiesPacket; import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundPlayerAbilitiesPacket;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundPlayerActionPacket; import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundPlayerActionPacket;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundUseItemPacket; import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundUseItemPacket;
import com.github.steveice10.mc.protocol.packet.login.serverbound.ServerboundCustomQueryPacket; import com.github.steveice10.mc.protocol.packet.login.serverbound.ServerboundCustomQueryAnswerPacket;
import com.github.steveice10.packetlib.BuiltinFlags; import com.github.steveice10.packetlib.BuiltinFlags;
import com.github.steveice10.packetlib.Session; import com.github.steveice10.packetlib.Session;
import com.github.steveice10.packetlib.event.session.ConnectedEvent; import com.github.steveice10.packetlib.event.session.ConnectedEvent;
@ -253,10 +250,6 @@ public class GeyserSession extends FloodgateConnection implements GeyserConnecti
@Setter @Setter
private RemoteServer remoteServer; private RemoteServer remoteServer;
@Deprecated
@Setter
private boolean microsoftAccount;
private final SessionPlayerEntity playerEntity; private final SessionPlayerEntity playerEntity;
private final AdvancementsCache advancementsCache; private final AdvancementsCache advancementsCache;
@ -355,7 +348,7 @@ public class GeyserSession extends FloodgateConnection implements GeyserConnecti
private Vector2i lastChunkPosition = null; private Vector2i lastChunkPosition = null;
@Setter @Setter
private int clientRenderDistance = -1; private int clientRenderDistance = -1;
private int serverRenderDistance; private int serverRenderDistance = -1;
// Exposed for GeyserConnect usage // Exposed for GeyserConnect usage
protected boolean sentSpawnPacket; protected boolean sentSpawnPacket;
@ -764,76 +757,20 @@ public class GeyserSession extends FloodgateConnection implements GeyserConnecti
} }
public void authenticate(String username) { public void authenticate(String username) {
authenticate(username, "");
}
public void authenticate(String username, String password) {
if (loggedIn) { if (loggedIn) {
geyser.getLogger().severe(GeyserLocale.getLocaleStringLog("geyser.auth.already_loggedin", username)); geyser.getLogger().severe(GeyserLocale.getLocaleStringLog("geyser.auth.already_loggedin", username));
return; return;
} }
loggingIn = true; loggingIn = true;
// Always replace spaces with underscores to avoid illegal nicknames, e.g. with GeyserConnect
protocol = new MinecraftProtocol(username.replace(' ', '_'));
// Use a future to prevent timeouts as all the authentication is handled sync try {
CompletableFuture.supplyAsync(() -> { connectDownstream();
try { } catch (Throwable t) {
if (password != null && !password.isEmpty()) { t.printStackTrace();
AuthenticationService authenticationService; }
if (microsoftAccount) {
authenticationService = new MsaAuthenticationService(GeyserImpl.OAUTH_CLIENT_ID);
} else {
authenticationService = new MojangAuthenticationService();
}
authenticationService.setUsername(username);
authenticationService.setPassword(password);
authenticationService.login();
GameProfile profile = authenticationService.getSelectedProfile();
if (profile == null) {
// Java account is offline
disconnect(GeyserLocale.getPlayerLocaleString("geyser.network.remote.invalid_account", clientData.getLanguageCode()));
return null;
}
protocol = new MinecraftProtocol(profile, authenticationService.getAccessToken());
} else {
// always replace spaces when using Floodgate,
// as usernames with spaces cause issues with Bungeecord's login cycle.
// However, this doesn't affect the final username as Floodgate is still in charge of that.
// So if you have (for example) replace spaces enabled on Floodgate the spaces will re-appear.
String validUsername = username;
if (this.remoteServer.authType() == AuthType.FLOODGATE) {
validUsername = username.replace(' ', '_');
}
protocol = new MinecraftProtocol(validUsername);
}
} catch (InvalidCredentialsException | IllegalArgumentException e) {
geyser.getLogger().info(GeyserLocale.getLocaleStringLog("geyser.auth.login.invalid", username));
disconnect(GeyserLocale.getPlayerLocaleString("geyser.auth.login.invalid.kick", getClientData().getLanguageCode()));
} catch (RequestException ex) {
disconnect(ex.getMessage());
}
return null;
}).whenComplete((aVoid, ex) -> {
if (ex != null) {
disconnect(ex.toString());
}
if (this.closed) {
if (ex != null) {
geyser.getLogger().error("", ex);
}
// Client disconnected during the authentication attempt
return;
}
try {
connectDownstream();
} catch (Throwable t) {
t.printStackTrace();
}
});
} }
public void authenticateWithRefreshToken(String refreshToken) { public void authenticateWithRefreshToken(String refreshToken) {
@ -1240,7 +1177,7 @@ public class GeyserSession extends FloodgateConnection implements GeyserConnecti
if (position != null) { if (position != null) {
ServerboundMovePlayerPosPacket packet = new ServerboundMovePlayerPosPacket(playerEntity.isOnGround(), ServerboundMovePlayerPosPacket packet = new ServerboundMovePlayerPosPacket(playerEntity.isOnGround(),
position.getX(), position.getY(), position.getZ()); position.getX(), position.getY(), position.getZ());
sendDownstreamPacket(packet); sendDownstreamGamePacket(packet);
} }
lastMovementTimestamp = System.currentTimeMillis(); lastMovementTimestamp = System.currentTimeMillis();
} }
@ -1422,7 +1359,7 @@ public class GeyserSession extends FloodgateConnection implements GeyserConnecti
return false; return false;
} }
sendDownstreamPacket(useItemPacket); sendDownstreamGamePacket(useItemPacket);
playerEntity.setFlag(EntityFlag.BLOCKING, true); playerEntity.setFlag(EntityFlag.BLOCKING, true);
// Metadata should be updated later // Metadata should be updated later
return true; return true;
@ -1456,7 +1393,7 @@ public class GeyserSession extends FloodgateConnection implements GeyserConnecti
if (playerEntity.getFlag(EntityFlag.BLOCKING)) { if (playerEntity.getFlag(EntityFlag.BLOCKING)) {
ServerboundPlayerActionPacket releaseItemPacket = new ServerboundPlayerActionPacket(PlayerAction.RELEASE_USE_ITEM, ServerboundPlayerActionPacket releaseItemPacket = new ServerboundPlayerActionPacket(PlayerAction.RELEASE_USE_ITEM,
Vector3i.ZERO, Direction.DOWN, 0); Vector3i.ZERO, Direction.DOWN, 0);
sendDownstreamPacket(releaseItemPacket); sendDownstreamGamePacket(releaseItemPacket);
playerEntity.setFlag(EntityFlag.BLOCKING, false); playerEntity.setFlag(EntityFlag.BLOCKING, false);
return true; return true;
} }
@ -1466,7 +1403,7 @@ public class GeyserSession extends FloodgateConnection implements GeyserConnecti
public void requestOffhandSwap() { public void requestOffhandSwap() {
ServerboundPlayerActionPacket swapHandsPacket = new ServerboundPlayerActionPacket(PlayerAction.SWAP_HANDS, Vector3i.ZERO, ServerboundPlayerActionPacket swapHandsPacket = new ServerboundPlayerActionPacket(PlayerAction.SWAP_HANDS, Vector3i.ZERO,
Direction.DOWN, 0); Direction.DOWN, 0);
sendDownstreamPacket(swapHandsPacket); sendDownstreamGamePacket(swapHandsPacket);
} }
@Override @Override
@ -1501,14 +1438,14 @@ public class GeyserSession extends FloodgateConnection implements GeyserConnecti
* Sends a chat message to the Java server. * Sends a chat message to the Java server.
*/ */
public void sendChat(String message) { public void sendChat(String message) {
sendDownstreamPacket(new ServerboundChatPacket(message, Instant.now().toEpochMilli(), 0L, null, 0, new BitSet())); sendDownstreamGamePacket(new ServerboundChatPacket(message, Instant.now().toEpochMilli(), 0L, null, 0, new BitSet()));
} }
/** /**
* Sends a command to the Java server. * Sends a command to the Java server.
*/ */
public void sendCommand(String command) { public void sendCommand(String command) {
sendDownstreamPacket(new ServerboundChatCommandPacket(command, Instant.now().toEpochMilli(), 0L, Collections.emptyList(), 0, new BitSet())); sendDownstreamGamePacket(new ServerboundChatCommandPacket(command, Instant.now().toEpochMilli(), 0L, Collections.emptyList(), 0, new BitSet()));
} }
public void setServerRenderDistance(int renderDistance) { public void setServerRenderDistance(int renderDistance) {
@ -1660,6 +1597,39 @@ public class GeyserSession extends FloodgateConnection implements GeyserConnecti
upstream.sendPacketImmediately(packet); upstream.sendPacketImmediately(packet);
} }
/**
* Send a packet to the remote server if in the game state.
*
* @param packet the java edition packet from MCProtocolLib
*/
public void sendDownstreamGamePacket(Packet packet) {
sendDownstreamPacket(packet, ProtocolState.GAME);
}
/**
* Send a packet to the remote server if in the login state.
*
* @param packet the java edition packet from MCProtocolLib
*/
public void sendDownstreamLoginPacket(Packet packet) {
sendDownstreamPacket(packet, ProtocolState.LOGIN);
}
/**
* Send a packet to the remote server if in the specified state.
*
* @param packet the java edition packet from MCProtocolLib
* @param intendedState the state the client should be in
*/
public void sendDownstreamPacket(Packet packet, ProtocolState intendedState) {
if (protocol.getState() != intendedState) {
geyser.getLogger().debug("Tried to send " + packet.getClass().getSimpleName() + " packet while not in " + intendedState.name() + " state");
return;
}
sendDownstreamPacket(packet);
}
/** /**
* Send a packet to the remote server. * Send a packet to the remote server.
* *
@ -1687,7 +1657,8 @@ public class GeyserSession extends FloodgateConnection implements GeyserConnecti
} }
private void sendDownstreamPacket0(Packet packet) { private void sendDownstreamPacket0(Packet packet) {
if (protocol.getState().equals(ProtocolState.GAME) || packet.getClass() == ServerboundCustomQueryPacket.class) { ProtocolState state = protocol.getState();
if (state == ProtocolState.GAME || state == ProtocolState.CONFIGURATION || packet.getClass() == ServerboundCustomQueryAnswerPacket.class) {
downstream.sendPacket(packet); downstream.sendPacket(packet);
} else { } else {
geyser.getLogger().debug("Tried to send downstream packet " + packet.getClass().getSimpleName() + " before connected to the server"); geyser.getLogger().debug("Tried to send downstream packet " + packet.getClass().getSimpleName() + " before connected to the server");
@ -1802,7 +1773,7 @@ public class GeyserSession extends FloodgateConnection implements GeyserConnecti
// We're "flying locked" in this gamemode // We're "flying locked" in this gamemode
flying = true; flying = true;
ServerboundPlayerAbilitiesPacket abilitiesPacket = new ServerboundPlayerAbilitiesPacket(true); ServerboundPlayerAbilitiesPacket abilitiesPacket = new ServerboundPlayerAbilitiesPacket(true);
sendDownstreamPacket(abilitiesPacket); sendDownstreamGamePacket(abilitiesPacket);
} }
abilities.add(Ability.FLYING); abilities.add(Ability.FLYING);
} }
@ -1846,8 +1817,11 @@ public class GeyserSession extends FloodgateConnection implements GeyserConnecti
if (clientRenderDistance != -1) { if (clientRenderDistance != -1) {
// The client has sent a render distance // The client has sent a render distance
return clientRenderDistance; return clientRenderDistance;
} else if (serverRenderDistance != -1) {
// only known once ClientboundLoginPacket is received
return serverRenderDistance;
} }
return serverRenderDistance; return 2; // unfortunate default until we got more info
} }
// We need to send our skin parts to the server otherwise java sees us with no hat, jacket etc // We need to send our skin parts to the server otherwise java sees us with no hat, jacket etc

View File

@ -97,7 +97,7 @@ public class AdvancementsCache {
} else { } else {
// Send a packet indicating that we intend to open this particular advancement window // Send a packet indicating that we intend to open this particular advancement window
ServerboundSeenAdvancementsPacket packet = new ServerboundSeenAdvancementsPacket(id); ServerboundSeenAdvancementsPacket packet = new ServerboundSeenAdvancementsPacket(id);
session.sendDownstreamPacket(packet); session.sendDownstreamGamePacket(packet);
// Wait for a response there // Wait for a response there
} }
} }
@ -137,7 +137,7 @@ public class AdvancementsCache {
builder.closedResultHandler(() -> { builder.closedResultHandler(() -> {
// Indicate that we have closed the current advancement tab // Indicate that we have closed the current advancement tab
session.sendDownstreamPacket(new ServerboundSeenAdvancementsPacket()); session.sendDownstreamGamePacket(new ServerboundSeenAdvancementsPacket());
}).validResultHandler((response) -> { }).validResultHandler((response) -> {
if (response.clickedButtonId() < visibleAdvancements.size()) { if (response.clickedButtonId() < visibleAdvancements.size()) {
@ -146,7 +146,7 @@ public class AdvancementsCache {
} else { } else {
buildAndShowMenuForm(); buildAndShowMenuForm();
// Indicate that we have closed the current advancement tab // Indicate that we have closed the current advancement tab
session.sendDownstreamPacket(new ServerboundSeenAdvancementsPacket()); session.sendDownstreamGamePacket(new ServerboundSeenAdvancementsPacket());
} }
}); });

View File

@ -68,7 +68,7 @@ public class BookEditCache {
packet = null; packet = null;
return; return;
} }
session.sendDownstreamPacket(packet); session.sendDownstreamGamePacket(packet);
packet = null; packet = null;
lastBookUpdate = System.currentTimeMillis(); lastBookUpdate = System.currentTimeMillis();
} }

View File

@ -25,9 +25,10 @@
package org.geysermc.geyser.session.cache; package org.geysermc.geyser.session.cache;
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundUpdateTagsPacket; import com.github.steveice10.mc.protocol.packet.common.clientbound.ClientboundUpdateTagsPacket;
import it.unimi.dsi.fastutil.ints.IntList; import it.unimi.dsi.fastutil.ints.IntList;
import it.unimi.dsi.fastutil.ints.IntLists; import it.unimi.dsi.fastutil.ints.IntLists;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.geysermc.geyser.GeyserLogger; import org.geysermc.geyser.GeyserLogger;
import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.item.type.Item;
@ -112,7 +113,7 @@ public class TagCache {
} }
} }
private IntList load(int[] tags) { private IntList load(int @Nullable[] tags) {
if (tags == null) { if (tags == null) {
return IntLists.EMPTY_LIST; return IntLists.EMPTY_LIST;
} }

View File

@ -58,7 +58,7 @@ import java.util.function.Predicate;
public class SkinProvider { public class SkinProvider {
private static final boolean ALLOW_THIRD_PARTY_CAPES = GeyserImpl.getInstance().getConfig().isAllowThirdPartyCapes(); private static final boolean ALLOW_THIRD_PARTY_CAPES = GeyserImpl.getInstance().getConfig().isAllowThirdPartyCapes();
static final ExecutorService EXECUTOR_SERVICE = Executors.newFixedThreadPool(ALLOW_THIRD_PARTY_CAPES ? 21 : 14); static ExecutorService EXECUTOR_SERVICE;
static final Skin EMPTY_SKIN; static final Skin EMPTY_SKIN;
static final Cape EMPTY_CAPE = new Cape("", "no-cape", ByteArrays.EMPTY_ARRAY, -1, true); static final Cape EMPTY_CAPE = new Cape("", "no-cape", ByteArrays.EMPTY_ARRAY, -1, true);
@ -133,6 +133,20 @@ public class SkinProvider {
WEARING_CUSTOM_SKULL_SLIM = new SkinGeometry("{\"geometry\" :{\"default\" :\"geometry.humanoid.wearingCustomSkullSlim\"}}", wearingCustomSkullSlim, false); WEARING_CUSTOM_SKULL_SLIM = new SkinGeometry("{\"geometry\" :{\"default\" :\"geometry.humanoid.wearingCustomSkullSlim\"}}", wearingCustomSkullSlim, false);
} }
private static ExecutorService getExecutorService() {
if (EXECUTOR_SERVICE == null) {
EXECUTOR_SERVICE = Executors.newFixedThreadPool(ALLOW_THIRD_PARTY_CAPES ? 21 : 14);
}
return EXECUTOR_SERVICE;
}
public static void shutdown() {
if (EXECUTOR_SERVICE != null) {
EXECUTOR_SERVICE.shutdown();
EXECUTOR_SERVICE = null;
}
}
public static void registerCacheImageTask(GeyserImpl geyser) { public static void registerCacheImageTask(GeyserImpl geyser) {
// Schedule Daily Image Expiry if we are caching them // Schedule Daily Image Expiry if we are caching them
if (geyser.getConfig().getCacheImages() > 0) { if (geyser.getConfig().getCacheImages() > 0) {
@ -302,7 +316,7 @@ public class SkinProvider {
GeyserImpl.getInstance().getLogger().debug("Took " + (System.currentTimeMillis() - time) + "ms for " + playerId); GeyserImpl.getInstance().getLogger().debug("Took " + (System.currentTimeMillis() - time) + "ms for " + playerId);
return skinAndCape; return skinAndCape;
}, EXECUTOR_SERVICE); }, getExecutorService());
} }
static CompletableFuture<Skin> requestSkin(UUID playerId, String textureUrl, boolean newThread) { static CompletableFuture<Skin> requestSkin(UUID playerId, String textureUrl, boolean newThread) {
@ -320,7 +334,7 @@ public class SkinProvider {
CompletableFuture<Skin> future; CompletableFuture<Skin> future;
if (newThread) { if (newThread) {
future = CompletableFuture.supplyAsync(() -> supplySkin(playerId, textureUrl), EXECUTOR_SERVICE) future = CompletableFuture.supplyAsync(() -> supplySkin(playerId, textureUrl), getExecutorService())
.whenCompleteAsync((skin, throwable) -> { .whenCompleteAsync((skin, throwable) -> {
skin.updated = true; skin.updated = true;
CACHED_JAVA_SKINS.put(textureUrl, skin); CACHED_JAVA_SKINS.put(textureUrl, skin);
@ -349,7 +363,7 @@ public class SkinProvider {
CompletableFuture<Cape> future; CompletableFuture<Cape> future;
if (newThread) { if (newThread) {
future = CompletableFuture.supplyAsync(() -> supplyCape(capeUrl, provider), EXECUTOR_SERVICE) future = CompletableFuture.supplyAsync(() -> supplyCape(capeUrl, provider), getExecutorService())
.whenCompleteAsync((cape, throwable) -> { .whenCompleteAsync((cape, throwable) -> {
CACHED_JAVA_CAPES.put(capeUrl, cape); CACHED_JAVA_CAPES.put(capeUrl, cape);
requestedCapes.remove(capeUrl); requestedCapes.remove(capeUrl);
@ -388,7 +402,7 @@ public class SkinProvider {
CompletableFuture<Skin> future; CompletableFuture<Skin> future;
if (newThread) { if (newThread) {
future = CompletableFuture.supplyAsync(() -> supplyEars(skin, earsUrl), EXECUTOR_SERVICE) future = CompletableFuture.supplyAsync(() -> supplyEars(skin, earsUrl), getExecutorService())
.whenCompleteAsync((outSkin, throwable) -> { }); .whenCompleteAsync((outSkin, throwable) -> { });
} else { } else {
Skin ears = supplyEars(skin, earsUrl); // blocking Skin ears = supplyEars(skin, earsUrl); // blocking
@ -620,7 +634,7 @@ public class SkinProvider {
} }
return null; return null;
} }
}, EXECUTOR_SERVICE); }, getExecutorService());
} }
/** /**
@ -646,7 +660,7 @@ public class SkinProvider {
} }
return null; return null;
} }
}, EXECUTOR_SERVICE).thenCompose(uuid -> { }, getExecutorService()).thenCompose(uuid -> {
if (uuid == null) { if (uuid == null) {
return CompletableFuture.completedFuture(null); return CompletableFuture.completedFuture(null);
} }

View File

@ -76,7 +76,7 @@ public class MinecraftLocale {
public static void downloadAndLoadLocale(String locale) { public static void downloadAndLoadLocale(String locale) {
locale = locale.toLowerCase(Locale.ROOT); locale = locale.toLowerCase(Locale.ROOT);
if (locale.equals("nb_no")) { if (locale.equals("nb_no")) {
// Different locale code - https://minecraft.fandom.com/wiki/Language // Different locale code - https://minecraft.wiki/w/Language
locale = "no_no"; locale = "no_no";
} }

View File

@ -114,12 +114,12 @@ public class BeaconInventoryTranslator extends AbstractBlockInventoryTranslator
// Input a beacon payment // Input a beacon payment
BeaconPaymentAction beaconPayment = (BeaconPaymentAction) request.getActions()[0]; BeaconPaymentAction beaconPayment = (BeaconPaymentAction) request.getActions()[0];
ServerboundSetBeaconPacket packet = new ServerboundSetBeaconPacket(toJava(beaconPayment.getPrimaryEffect()), toJava(beaconPayment.getSecondaryEffect())); ServerboundSetBeaconPacket packet = new ServerboundSetBeaconPacket(toJava(beaconPayment.getPrimaryEffect()), toJava(beaconPayment.getSecondaryEffect()));
session.sendDownstreamPacket(packet); session.sendDownstreamGamePacket(packet);
return acceptRequest(request, makeContainerEntries(session, inventory, IntSets.emptySet())); return acceptRequest(request, makeContainerEntries(session, inventory, IntSets.emptySet()));
} }
private OptionalInt toJava(int effectChoice) { private OptionalInt toJava(int effectChoice) {
return effectChoice == 0 ? OptionalInt.empty() : OptionalInt.of(effectChoice); return effectChoice == 0 ? OptionalInt.empty() : OptionalInt.of(effectChoice - 1);
} }
@Override @Override

View File

@ -129,7 +129,7 @@ public class EnchantingInventoryTranslator extends AbstractBlockInventoryTransla
return rejectRequest(request); return rejectRequest(request);
} }
ServerboundContainerButtonClickPacket packet = new ServerboundContainerButtonClickPacket(inventory.getJavaId(), javaSlot); ServerboundContainerButtonClickPacket packet = new ServerboundContainerButtonClickPacket(inventory.getJavaId(), javaSlot);
session.sendDownstreamPacket(packet); session.sendDownstreamGamePacket(packet);
return acceptRequest(request, makeContainerEntries(session, inventory, IntSets.emptySet())); return acceptRequest(request, makeContainerEntries(session, inventory, IntSets.emptySet()));
} }

View File

@ -102,7 +102,7 @@ public class LecternInventoryTranslator extends BaseInventoryTranslator {
if (session.isDroppingLecternBook()) { if (session.isDroppingLecternBook()) {
// We have to enter the inventory GUI to eject the book // We have to enter the inventory GUI to eject the book
ServerboundContainerButtonClickPacket packet = new ServerboundContainerButtonClickPacket(inventory.getJavaId(), 3); ServerboundContainerButtonClickPacket packet = new ServerboundContainerButtonClickPacket(inventory.getJavaId(), 3);
session.sendDownstreamPacket(packet); session.sendDownstreamGamePacket(packet);
session.setDroppingLecternBook(false); session.setDroppingLecternBook(false);
InventoryUtils.closeInventory(session, inventory.getJavaId(), false); InventoryUtils.closeInventory(session, inventory.getJavaId(), false);
} else if (lecternContainer.getBlockEntityTag() == null) { } else if (lecternContainer.getBlockEntityTag() == null) {
@ -153,7 +153,7 @@ public class LecternInventoryTranslator extends BaseInventoryTranslator {
session.getLecternCache().add(position); session.getLecternCache().add(position);
// Close the window - we will reopen it once the client has this data synced // Close the window - we will reopen it once the client has this data synced
ServerboundContainerClosePacket closeWindowPacket = new ServerboundContainerClosePacket(lecternContainer.getJavaId()); ServerboundContainerClosePacket closeWindowPacket = new ServerboundContainerClosePacket(lecternContainer.getJavaId());
session.sendDownstreamPacket(closeWindowPacket); session.sendDownstreamGamePacket(closeWindowPacket);
InventoryUtils.closeInventory(session, inventory.getJavaId(), false); InventoryUtils.closeInventory(session, inventory.getJavaId(), false);
} }
} }

View File

@ -149,7 +149,7 @@ public class LoomInventoryTranslator extends AbstractBlockInventoryTranslator {
// And the Java loom window has a fixed row/width of four // And the Java loom window has a fixed row/width of four
// So... Number / 4 = row (so we don't have to bother there), and number % 4 is our column, which leads us back to our index. :) // So... Number / 4 = row (so we don't have to bother there), and number % 4 is our column, which leads us back to our index. :)
ServerboundContainerButtonClickPacket packet = new ServerboundContainerButtonClickPacket(inventory.getJavaId(), index); ServerboundContainerButtonClickPacket packet = new ServerboundContainerButtonClickPacket(inventory.getJavaId(), index);
session.sendDownstreamPacket(packet); session.sendDownstreamGamePacket(packet);
GeyserItemStack inputCopy = inventory.getItem(0).copy(1); GeyserItemStack inputCopy = inventory.getItem(0).copy(1);
inputCopy.setNetId(session.getNextItemNetId()); inputCopy.setNetId(session.getNextItemNetId());

View File

@ -155,7 +155,7 @@ public class MerchantInventoryTranslator extends BaseInventoryTranslator {
private ItemStackResponse handleTrade(GeyserSession session, Inventory inventory, ItemStackRequest request, int tradeChoice) { private ItemStackResponse handleTrade(GeyserSession session, Inventory inventory, ItemStackRequest request, int tradeChoice) {
ServerboundSelectTradePacket packet = new ServerboundSelectTradePacket(tradeChoice); ServerboundSelectTradePacket packet = new ServerboundSelectTradePacket(tradeChoice);
session.sendDownstreamPacket(packet); session.sendDownstreamGamePacket(packet);
if (session.isEmulatePost1_13Logic()) { if (session.isEmulatePost1_13Logic()) {
// 1.18 Java cooperates nicer than older versions // 1.18 Java cooperates nicer than older versions

View File

@ -359,7 +359,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator {
} }
ServerboundSetCreativeModeSlotPacket creativeDropPacket = new ServerboundSetCreativeModeSlotPacket(-1, sourceItem.getItemStack(dropAction.getCount())); ServerboundSetCreativeModeSlotPacket creativeDropPacket = new ServerboundSetCreativeModeSlotPacket(-1, sourceItem.getItemStack(dropAction.getCount()));
session.sendDownstreamPacket(creativeDropPacket); session.sendDownstreamGamePacket(creativeDropPacket);
sourceItem.sub(dropAction.getCount()); sourceItem.sub(dropAction.getCount());
} }
@ -494,7 +494,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator {
dropStack = new ItemStack(javaCreativeItem.getId(), dropAction.getCount(), javaCreativeItem.getNbt()); dropStack = new ItemStack(javaCreativeItem.getId(), dropAction.getCount(), javaCreativeItem.getNbt());
} }
ServerboundSetCreativeModeSlotPacket creativeDropPacket = new ServerboundSetCreativeModeSlotPacket(-1, dropStack); ServerboundSetCreativeModeSlotPacket creativeDropPacket = new ServerboundSetCreativeModeSlotPacket(-1, dropStack);
session.sendDownstreamPacket(creativeDropPacket); session.sendDownstreamGamePacket(creativeDropPacket);
break; break;
} }
default: default:
@ -515,7 +515,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator {
ItemStack itemStack = item.isEmpty() ? new ItemStack(-1, 0, null) : item.getItemStack(); ItemStack itemStack = item.isEmpty() ? new ItemStack(-1, 0, null) : item.getItemStack();
ServerboundSetCreativeModeSlotPacket creativePacket = new ServerboundSetCreativeModeSlotPacket(slot, itemStack); ServerboundSetCreativeModeSlotPacket creativePacket = new ServerboundSetCreativeModeSlotPacket(slot, itemStack);
session.sendDownstreamPacket(creativePacket); session.sendDownstreamGamePacket(creativePacket);
} }
private static boolean isCraftingGrid(ItemStackRequestSlotData slotInfoData) { private static boolean isCraftingGrid(ItemStackRequestSlotData slotInfoData) {

View File

@ -69,7 +69,7 @@ public class StonecutterInventoryTranslator extends AbstractBlockInventoryTransl
if (container.getStonecutterButton() != button) { if (container.getStonecutterButton() != button) {
// Getting the index of the item in the Java stonecutter list // Getting the index of the item in the Java stonecutter list
ServerboundContainerButtonClickPacket packet = new ServerboundContainerButtonClickPacket(inventory.getJavaId(), button); ServerboundContainerButtonClickPacket packet = new ServerboundContainerButtonClickPacket(inventory.getJavaId(), button);
session.sendDownstreamPacket(packet); session.sendDownstreamGamePacket(packet);
container.setStonecutterButton(button); container.setStonecutterButton(button);
} }

View File

@ -41,6 +41,10 @@ public class DecoratedPotBlockEntityTranslator extends BlockEntityTranslator {
@Override @Override
public void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState) { public void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState) {
if (tag == null) {
return;
}
// exact same format // exact same format
if (tag.get("sherds") instanceof ListTag sherds) { if (tag.get("sherds") instanceof ListTag sherds) {
List<String> translated = new ArrayList<>(4); List<String> translated = new ArrayList<>(4);

View File

@ -64,7 +64,7 @@ public class BedrockAnimateTranslator extends PacketTranslator<AnimatePacket> {
// and Bedrock 1.19.51. // and Bedrock 1.19.51.
// Note for the future: we should probably largely ignore this packet and instead replicate // Note for the future: we should probably largely ignore this packet and instead replicate
// all actions on our end, and send swings where needed. // all actions on our end, and send swings where needed.
session.sendDownstreamPacket(new ServerboundSwingPacket(Hand.MAIN_HAND)); session.sendDownstreamGamePacket(new ServerboundSwingPacket(Hand.MAIN_HAND));
session.activateArmAnimationTicking(); session.activateArmAnimationTicking();
} }
}, },
@ -77,12 +77,12 @@ public class BedrockAnimateTranslator extends PacketTranslator<AnimatePacket> {
// Packet value is a float of how long one has been rowing, so we convert that into a boolean // Packet value is a float of how long one has been rowing, so we convert that into a boolean
session.setSteeringLeft(packet.getRowingTime() > 0.0); session.setSteeringLeft(packet.getRowingTime() > 0.0);
ServerboundPaddleBoatPacket steerLeftPacket = new ServerboundPaddleBoatPacket(session.isSteeringLeft(), session.isSteeringRight()); ServerboundPaddleBoatPacket steerLeftPacket = new ServerboundPaddleBoatPacket(session.isSteeringLeft(), session.isSteeringRight());
session.sendDownstreamPacket(steerLeftPacket); session.sendDownstreamGamePacket(steerLeftPacket);
} }
case ROW_RIGHT -> { case ROW_RIGHT -> {
session.setSteeringRight(packet.getRowingTime() > 0.0); session.setSteeringRight(packet.getRowingTime() > 0.0);
ServerboundPaddleBoatPacket steerRightPacket = new ServerboundPaddleBoatPacket(session.isSteeringLeft(), session.isSteeringRight()); ServerboundPaddleBoatPacket steerRightPacket = new ServerboundPaddleBoatPacket(session.isSteeringLeft(), session.isSteeringRight());
session.sendDownstreamPacket(steerRightPacket); session.sendDownstreamGamePacket(steerRightPacket);
} }
} }
} }

View File

@ -108,7 +108,7 @@ public class BedrockBlockEntityDataTranslator extends PacketTranslator<BlockEnti
if (iterator < lines.length) lines[iterator] = newMessage.toString(); if (iterator < lines.length) lines[iterator] = newMessage.toString();
Vector3i pos = Vector3i.from(tag.getInt("x"), tag.getInt("y"), tag.getInt("z")); Vector3i pos = Vector3i.from(tag.getInt("x"), tag.getInt("y"), tag.getInt("z"));
ServerboundSignUpdatePacket signUpdatePacket = new ServerboundSignUpdatePacket(pos, lines, session.getWorldCache().isEditingSignOnFront()); ServerboundSignUpdatePacket signUpdatePacket = new ServerboundSignUpdatePacket(pos, lines, session.getWorldCache().isEditingSignOnFront());
session.sendDownstreamPacket(signUpdatePacket); session.sendDownstreamGamePacket(signUpdatePacket);
} else if (id.equals("JigsawBlock")) { } else if (id.equals("JigsawBlock")) {
// Client has just sent a jigsaw block update // Client has just sent a jigsaw block update
@ -120,7 +120,7 @@ public class BedrockBlockEntityDataTranslator extends PacketTranslator<BlockEnti
String joint = tag.getString("joint"); String joint = tag.getString("joint");
ServerboundSetJigsawBlockPacket jigsawPacket = new ServerboundSetJigsawBlockPacket(pos, name, target, pool, ServerboundSetJigsawBlockPacket jigsawPacket = new ServerboundSetJigsawBlockPacket(pos, name, target, pool,
finalState, joint); finalState, joint);
session.sendDownstreamPacket(jigsawPacket); session.sendDownstreamGamePacket(jigsawPacket);
} }
} }

View File

@ -53,13 +53,13 @@ public class BedrockCommandBlockUpdateTranslator extends PacketTranslator<Comman
boolean automatic = !packet.isRedstoneMode(); // Automatic = Always Active option in Java boolean automatic = !packet.isRedstoneMode(); // Automatic = Always Active option in Java
ServerboundSetCommandBlockPacket commandBlockPacket = new ServerboundSetCommandBlockPacket( ServerboundSetCommandBlockPacket commandBlockPacket = new ServerboundSetCommandBlockPacket(
packet.getBlockPosition(), command, mode, outputTracked, isConditional, automatic); packet.getBlockPosition(), command, mode, outputTracked, isConditional, automatic);
session.sendDownstreamPacket(commandBlockPacket); session.sendDownstreamGamePacket(commandBlockPacket);
} else { } else {
ServerboundSetCommandMinecartPacket commandMinecartPacket = new ServerboundSetCommandMinecartPacket( ServerboundSetCommandMinecartPacket commandMinecartPacket = new ServerboundSetCommandMinecartPacket(
session.getEntityCache().getEntityByGeyserId(packet.getMinecartRuntimeEntityId()).getEntityId(), session.getEntityCache().getEntityByGeyserId(packet.getMinecartRuntimeEntityId()).getEntityId(),
command, outputTracked command, outputTracked
); );
session.sendDownstreamPacket(commandMinecartPacket); session.sendDownstreamGamePacket(commandMinecartPacket);
} }
} }
} }

View File

@ -55,7 +55,7 @@ public class BedrockContainerCloseTranslator extends PacketTranslator<ContainerC
if (openInventory != null) { if (openInventory != null) {
if (bedrockId == openInventory.getBedrockId()) { if (bedrockId == openInventory.getBedrockId()) {
ServerboundContainerClosePacket closeWindowPacket = new ServerboundContainerClosePacket(openInventory.getJavaId()); ServerboundContainerClosePacket closeWindowPacket = new ServerboundContainerClosePacket(openInventory.getJavaId());
session.sendDownstreamPacket(closeWindowPacket); session.sendDownstreamGamePacket(closeWindowPacket);
InventoryUtils.closeInventory(session, openInventory.getJavaId(), false); InventoryUtils.closeInventory(session, openInventory.getJavaId(), false);
} else if (openInventory.isPending()) { } else if (openInventory.isPending()) {
InventoryUtils.displayInventory(session, openInventory); InventoryUtils.displayInventory(session, openInventory);

View File

@ -137,7 +137,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
ServerboundContainerClickPacket dropPacket = new ServerboundContainerClickPacket( ServerboundContainerClickPacket dropPacket = new ServerboundContainerClickPacket(
inventory.getJavaId(), inventory.getStateId(), hotbarSlot, clickType.actionType, clickType.action, inventory.getJavaId(), inventory.getStateId(), hotbarSlot, clickType.actionType, clickType.action,
inventory.getCursor().getItemStack(), changedItem); inventory.getCursor().getItemStack(), changedItem);
session.sendDownstreamPacket(dropPacket); session.sendDownstreamGamePacket(dropPacket);
return; return;
} }
if (session.getPlayerInventory().getItemInHand().isEmpty()) { if (session.getPlayerInventory().getItemInHand().isEmpty()) {
@ -150,7 +150,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
Direction.DOWN, Direction.DOWN,
0 0
); );
session.sendDownstreamPacket(dropPacket); session.sendDownstreamGamePacket(dropPacket);
if (dropAll) { if (dropAll) {
session.getPlayerInventory().setItemInHand(GeyserItemStack.EMPTY); session.getPlayerInventory().setItemInHand(GeyserItemStack.EMPTY);
@ -309,7 +309,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
packet.getClickPosition().getX(), packet.getClickPosition().getY(), packet.getClickPosition().getZ(), packet.getClickPosition().getX(), packet.getClickPosition().getY(), packet.getClickPosition().getZ(),
false, false,
session.getWorldCache().nextPredictionSequence()); session.getWorldCache().nextPredictionSequence());
session.sendDownstreamPacket(blockPacket); session.sendDownstreamGamePacket(blockPacket);
Item item = session.getPlayerInventory().getItemInHand().asItem(); Item item = session.getPlayerInventory().getItemInHand().asItem();
if (packet.getItemInHand() != null) { if (packet.getItemInHand() != null) {
@ -384,7 +384,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
} }
ServerboundUseItemPacket useItemPacket = new ServerboundUseItemPacket(Hand.MAIN_HAND, session.getWorldCache().nextPredictionSequence()); ServerboundUseItemPacket useItemPacket = new ServerboundUseItemPacket(Hand.MAIN_HAND, session.getWorldCache().nextPredictionSequence());
session.sendDownstreamPacket(useItemPacket); session.sendDownstreamGamePacket(useItemPacket);
List<LegacySetItemSlotData> legacySlots = packet.getLegacySlots(); List<LegacySetItemSlotData> legacySlots = packet.getLegacySlots();
if (packet.getActions().size() == 1 && legacySlots.size() > 0) { if (packet.getActions().size() == 1 && legacySlots.size() > 0) {
@ -453,13 +453,13 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
if (itemFrameEntity != null) { if (itemFrameEntity != null) {
ServerboundInteractPacket attackPacket = new ServerboundInteractPacket(itemFrameEntity.getEntityId(), ServerboundInteractPacket attackPacket = new ServerboundInteractPacket(itemFrameEntity.getEntityId(),
InteractAction.ATTACK, session.isSneaking()); InteractAction.ATTACK, session.isSneaking());
session.sendDownstreamPacket(attackPacket); session.sendDownstreamGamePacket(attackPacket);
break; break;
} }
PlayerAction action = session.getGameMode() == GameMode.CREATIVE ? PlayerAction.START_DIGGING : PlayerAction.FINISH_DIGGING; PlayerAction action = session.getGameMode() == GameMode.CREATIVE ? PlayerAction.START_DIGGING : PlayerAction.FINISH_DIGGING;
ServerboundPlayerActionPacket breakPacket = new ServerboundPlayerActionPacket(action, packet.getBlockPosition(), Direction.VALUES[packet.getBlockFace()], sequence); ServerboundPlayerActionPacket breakPacket = new ServerboundPlayerActionPacket(action, packet.getBlockPosition(), Direction.VALUES[packet.getBlockFace()], sequence);
session.sendDownstreamPacket(breakPacket); session.sendDownstreamGamePacket(breakPacket);
} }
} }
break; break;
@ -468,7 +468,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
// Followed to the Minecraft Protocol specification outlined at wiki.vg // Followed to the Minecraft Protocol specification outlined at wiki.vg
ServerboundPlayerActionPacket releaseItemPacket = new ServerboundPlayerActionPacket(PlayerAction.RELEASE_USE_ITEM, Vector3i.ZERO, ServerboundPlayerActionPacket releaseItemPacket = new ServerboundPlayerActionPacket(PlayerAction.RELEASE_USE_ITEM, Vector3i.ZERO,
Direction.DOWN, 0); Direction.DOWN, 0);
session.sendDownstreamPacket(releaseItemPacket); session.sendDownstreamGamePacket(releaseItemPacket);
} }
break; break;
case ITEM_USE_ON_ENTITY: case ITEM_USE_ON_ENTITY:
@ -490,7 +490,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
} }
ServerboundInteractPacket attackPacket = new ServerboundInteractPacket(entityId, ServerboundInteractPacket attackPacket = new ServerboundInteractPacket(entityId,
InteractAction.ATTACK, session.isSneaking()); InteractAction.ATTACK, session.isSneaking());
session.sendDownstreamPacket(attackPacket); session.sendDownstreamGamePacket(attackPacket);
// Since 1.19.10, LevelSoundEventPackets are no longer sent by the client when attacking entities // Since 1.19.10, LevelSoundEventPackets are no longer sent by the client when attacking entities
CooldownUtils.sendCooldown(session); CooldownUtils.sendCooldown(session);
@ -510,7 +510,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
Vector3f clickPosition = packet.getClickPosition().sub(entityPosition); Vector3f clickPosition = packet.getClickPosition().sub(entityPosition);
boolean isSpectator = session.getGameMode() == GameMode.SPECTATOR; boolean isSpectator = session.getGameMode() == GameMode.SPECTATOR;
for (Hand hand : EntityUtils.HANDS) { for (Hand hand : EntityUtils.HANDS) {
session.sendDownstreamPacket(new ServerboundInteractPacket(entity.getEntityId(), session.sendDownstreamGamePacket(new ServerboundInteractPacket(entity.getEntityId(),
InteractAction.INTERACT_AT, clickPosition.getX(), clickPosition.getY(), clickPosition.getZ(), InteractAction.INTERACT_AT, clickPosition.getX(), clickPosition.getY(), clickPosition.getZ(),
hand, session.isSneaking())); hand, session.isSneaking()));
@ -522,7 +522,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
} }
if (!result.consumesAction()) { if (!result.consumesAction()) {
session.sendDownstreamPacket(new ServerboundInteractPacket(entity.getEntityId(), session.sendDownstreamGamePacket(new ServerboundInteractPacket(entity.getEntityId(),
InteractAction.INTERACT, hand, session.isSneaking())); InteractAction.INTERACT, hand, session.isSneaking()));
if (!isSpectator) { if (!isSpectator) {
result = entity.interact(hand); result = entity.interact(hand);
@ -532,7 +532,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
if (result.consumesAction()) { if (result.consumesAction()) {
if (result.shouldSwing() && hand == Hand.OFF_HAND) { if (result.shouldSwing() && hand == Hand.OFF_HAND) {
// Currently, Bedrock will send us the arm swing packet in most cases. But it won't for offhand. // Currently, Bedrock will send us the arm swing packet in most cases. But it won't for offhand.
session.sendDownstreamPacket(new ServerboundSwingPacket(hand)); session.sendDownstreamGamePacket(new ServerboundSwingPacket(hand));
// Note here to look into sending the animation packet back to Bedrock // Note here to look into sending the animation packet back to Bedrock
} }
return; return;
@ -629,7 +629,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
lookAt(session, target); lookAt(session, target);
ServerboundUseItemPacket itemPacket = new ServerboundUseItemPacket(Hand.MAIN_HAND, session.getWorldCache().nextPredictionSequence()); ServerboundUseItemPacket itemPacket = new ServerboundUseItemPacket(Hand.MAIN_HAND, session.getWorldCache().nextPredictionSequence());
session.sendDownstreamPacket(itemPacket); session.sendDownstreamGamePacket(itemPacket);
return true; return true;
} }
@ -671,7 +671,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
ServerboundMovePlayerPosRotPacket returnPacket = new ServerboundMovePlayerPosRotPacket(entity.isOnGround(), playerPosition.getX(), playerPosition.getY(), playerPosition.getZ(), entity.getYaw(), entity.getPitch()); ServerboundMovePlayerPosRotPacket returnPacket = new ServerboundMovePlayerPosRotPacket(entity.isOnGround(), playerPosition.getX(), playerPosition.getY(), playerPosition.getZ(), entity.getYaw(), entity.getPitch());
// This matches Java edition behavior // This matches Java edition behavior
ServerboundMovePlayerPosRotPacket movementPacket = new ServerboundMovePlayerPosRotPacket(entity.isOnGround(), playerPosition.getX(), playerPosition.getY(), playerPosition.getZ(), yaw, pitch); ServerboundMovePlayerPosRotPacket movementPacket = new ServerboundMovePlayerPosRotPacket(entity.isOnGround(), playerPosition.getX(), playerPosition.getY(), playerPosition.getZ(), yaw, pitch);
session.sendDownstreamPacket(movementPacket); session.sendDownstreamGamePacket(movementPacket);
if (session.getLookBackScheduledFuture() != null) { if (session.getLookBackScheduledFuture() != null) {
session.getLookBackScheduledFuture().cancel(false); session.getLookBackScheduledFuture().cancel(false);
@ -683,7 +683,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
// The player moved/rotated so there is no need to change their rotation back // The player moved/rotated so there is no need to change their rotation back
return; return;
} }
session.sendDownstreamPacket(returnPacket); session.sendDownstreamGamePacket(returnPacket);
}, 150, TimeUnit.MILLISECONDS)); }, 150, TimeUnit.MILLISECONDS));
} }
} }

View File

@ -49,7 +49,7 @@ public class BedrockItemFrameDropItemTranslator extends PacketTranslator<ItemFra
if (entity != null) { if (entity != null) {
ServerboundInteractPacket interactPacket = new ServerboundInteractPacket(entity.getEntityId(), ServerboundInteractPacket interactPacket = new ServerboundInteractPacket(entity.getEntityId(),
InteractAction.ATTACK, Hand.MAIN_HAND, session.isSneaking()); InteractAction.ATTACK, Hand.MAIN_HAND, session.isSneaking());
session.sendDownstreamPacket(interactPacket); session.sendDownstreamGamePacket(interactPacket);
} }
} }
} }

View File

@ -58,7 +58,7 @@ public class BedrockLecternUpdateTranslator extends PacketTranslator<LecternUpda
0, 0, 0, // Java doesn't care about these when dealing with a lectern 0, 0, 0, // Java doesn't care about these when dealing with a lectern
false, false,
session.getWorldCache().nextPredictionSequence()); session.getWorldCache().nextPredictionSequence());
session.sendDownstreamPacket(blockPacket); session.sendDownstreamGamePacket(blockPacket);
} else { } else {
// Bedrock wants to either move a page or exit // Bedrock wants to either move a page or exit
if (!(session.getOpenInventory() instanceof LecternContainer lecternContainer)) { if (!(session.getOpenInventory() instanceof LecternContainer lecternContainer)) {
@ -69,7 +69,7 @@ public class BedrockLecternUpdateTranslator extends PacketTranslator<LecternUpda
if (lecternContainer.getCurrentBedrockPage() == packet.getPage()) { if (lecternContainer.getCurrentBedrockPage() == packet.getPage()) {
// The same page means Bedrock is closing the window // The same page means Bedrock is closing the window
ServerboundContainerClosePacket closeWindowPacket = new ServerboundContainerClosePacket(lecternContainer.getJavaId()); ServerboundContainerClosePacket closeWindowPacket = new ServerboundContainerClosePacket(lecternContainer.getJavaId());
session.sendDownstreamPacket(closeWindowPacket); session.sendDownstreamGamePacket(closeWindowPacket);
InventoryUtils.closeInventory(session, lecternContainer.getJavaId(), false); InventoryUtils.closeInventory(session, lecternContainer.getJavaId(), false);
} else { } else {
// Each "page" Bedrock gives to us actually represents two pages (think opening a book and seeing two pages) // Each "page" Bedrock gives to us actually represents two pages (think opening a book and seeing two pages)
@ -83,12 +83,12 @@ public class BedrockLecternUpdateTranslator extends PacketTranslator<LecternUpda
if (newJavaPage > currentJavaPage) { if (newJavaPage > currentJavaPage) {
for (int i = currentJavaPage; i < newJavaPage; i++) { for (int i = currentJavaPage; i < newJavaPage; i++) {
ServerboundContainerButtonClickPacket clickButtonPacket = new ServerboundContainerButtonClickPacket(session.getOpenInventory().getJavaId(), 2); ServerboundContainerButtonClickPacket clickButtonPacket = new ServerboundContainerButtonClickPacket(session.getOpenInventory().getJavaId(), 2);
session.sendDownstreamPacket(clickButtonPacket); session.sendDownstreamGamePacket(clickButtonPacket);
} }
} else { } else {
for (int i = currentJavaPage; i > newJavaPage; i--) { for (int i = currentJavaPage; i > newJavaPage; i--) {
ServerboundContainerButtonClickPacket clickButtonPacket = new ServerboundContainerButtonClickPacket(session.getOpenInventory().getJavaId(), 1); ServerboundContainerButtonClickPacket clickButtonPacket = new ServerboundContainerButtonClickPacket(session.getOpenInventory().getJavaId(), 1);
session.sendDownstreamPacket(clickButtonPacket); session.sendDownstreamGamePacket(clickButtonPacket);
} }
} }
} }

View File

@ -58,7 +58,7 @@ public class BedrockMobEquipmentTranslator extends PacketTranslator<MobEquipment
session.getPlayerInventory().setHeldItemSlot(newSlot); session.getPlayerInventory().setHeldItemSlot(newSlot);
ServerboundSetCarriedItemPacket setCarriedItemPacket = new ServerboundSetCarriedItemPacket(newSlot); ServerboundSetCarriedItemPacket setCarriedItemPacket = new ServerboundSetCarriedItemPacket(newSlot);
session.sendDownstreamPacket(setCarriedItemPacket); session.sendDownstreamGamePacket(setCarriedItemPacket);
GeyserItemStack newItem = session.getPlayerInventory().getItemInHand(); GeyserItemStack newItem = session.getPlayerInventory().getItemInHand();
@ -66,7 +66,7 @@ public class BedrockMobEquipmentTranslator extends PacketTranslator<MobEquipment
// Activate shield since we are already sneaking // Activate shield since we are already sneaking
// (No need to send a release item packet - Java doesn't do this when swapping items) // (No need to send a release item packet - Java doesn't do this when swapping items)
// Required to do it a tick later or else it doesn't register // Required to do it a tick later or else it doesn't register
session.scheduleInEventLoop(() -> session.sendDownstreamPacket(new ServerboundUseItemPacket(Hand.MAIN_HAND, session.getWorldCache().nextPredictionSequence())), session.scheduleInEventLoop(() -> session.sendDownstreamGamePacket(new ServerboundUseItemPacket(Hand.MAIN_HAND, session.getWorldCache().nextPredictionSequence())),
50, TimeUnit.MILLISECONDS); 50, TimeUnit.MILLISECONDS);
} }

View File

@ -72,6 +72,6 @@ public class BedrockMoveEntityAbsoluteTranslator extends PacketTranslator<MoveEn
packet.getPosition().getX(), y, packet.getPosition().getZ(), packet.getPosition().getX(), y, packet.getPosition().getZ(),
packet.getRotation().getY() - 90, packet.getRotation().getX() packet.getRotation().getY() - 90, packet.getRotation().getX()
); );
session.sendDownstreamPacket(ServerboundMoveVehiclePacket); session.sendDownstreamGamePacket(ServerboundMoveVehiclePacket);
} }
} }

View File

@ -25,7 +25,7 @@
package org.geysermc.geyser.translator.protocol.bedrock; package org.geysermc.geyser.translator.protocol.bedrock;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundKeepAlivePacket; import com.github.steveice10.mc.protocol.packet.common.serverbound.ServerboundKeepAlivePacket;
import org.cloudburstmc.protocol.bedrock.data.AttributeData; import org.cloudburstmc.protocol.bedrock.data.AttributeData;
import org.cloudburstmc.protocol.bedrock.packet.NetworkStackLatencyPacket; import org.cloudburstmc.protocol.bedrock.packet.NetworkStackLatencyPacket;
import org.cloudburstmc.protocol.bedrock.packet.UpdateAttributesPacket; import org.cloudburstmc.protocol.bedrock.packet.UpdateAttributesPacket;

View File

@ -50,7 +50,7 @@ public class BedrockPlayerInputTranslator extends PacketTranslator<PlayerInputPa
packet.getInputMotion().getX(), packet.getInputMotion().getY(), packet.isJumping(), packet.isSneaking() packet.getInputMotion().getX(), packet.getInputMotion().getY(), packet.isJumping(), packet.isSneaking()
); );
session.sendDownstreamPacket(playerInputPacket); session.sendDownstreamGamePacket(playerInputPacket);
// Bedrock only sends movement vehicle packets while moving // Bedrock only sends movement vehicle packets while moving
// This allows horses to take damage while standing on magma // This allows horses to take damage while standing on magma
@ -83,7 +83,7 @@ public class BedrockPlayerInputTranslator extends PacketTranslator<PlayerInputPa
vehiclePosition.getX(), vehiclePosition.getY(), vehiclePosition.getZ(), vehiclePosition.getX(), vehiclePosition.getY(), vehiclePosition.getZ(),
vehicle.getYaw() - 90, vehicle.getPitch() vehicle.getYaw() - 90, vehicle.getPitch()
); );
session.sendDownstreamPacket(moveVehiclePacket); session.sendDownstreamGamePacket(moveVehiclePacket);
} }
} }
} }

View File

@ -42,6 +42,7 @@ public class BedrockRequestAbilityTranslator extends PacketTranslator<RequestAbi
@Override @Override
public void translate(GeyserSession session, RequestAbilityPacket packet) { public void translate(GeyserSession session, RequestAbilityPacket packet) {
// TODO: Since 1.20.30, this was replaced by a START_FLYING and STOP_FLYING case in BedrockActionTranslator
if (packet.getAbility() == Ability.FLYING) { if (packet.getAbility() == Ability.FLYING) {
boolean isFlying = packet.isBoolValue(); boolean isFlying = packet.isBoolValue();
if (!isFlying && session.getGameMode() == GameMode.SPECTATOR) { if (!isFlying && session.getGameMode() == GameMode.SPECTATOR) {
@ -57,7 +58,7 @@ public class BedrockRequestAbilityTranslator extends PacketTranslator<RequestAbi
session.setFlying(isFlying); session.setFlying(isFlying);
ServerboundPlayerAbilitiesPacket abilitiesPacket = new ServerboundPlayerAbilitiesPacket(isFlying); ServerboundPlayerAbilitiesPacket abilitiesPacket = new ServerboundPlayerAbilitiesPacket(isFlying);
session.sendDownstreamPacket(abilitiesPacket); session.sendDownstreamGamePacket(abilitiesPacket);
} }
} }
} }

View File

@ -39,7 +39,7 @@ public class BedrockRespawnTranslator extends PacketTranslator<RespawnPacket> {
public void translate(GeyserSession session, RespawnPacket packet) { public void translate(GeyserSession session, RespawnPacket packet) {
if (packet.getState() == RespawnPacket.State.CLIENT_READY) { if (packet.getState() == RespawnPacket.State.CLIENT_READY) {
ServerboundClientCommandPacket javaRespawnPacket = new ServerboundClientCommandPacket(ClientCommand.RESPAWN); ServerboundClientCommandPacket javaRespawnPacket = new ServerboundClientCommandPacket(ClientCommand.RESPAWN);
session.sendDownstreamPacket(javaRespawnPacket); session.sendDownstreamGamePacket(javaRespawnPacket);
} }
} }
} }

View File

@ -39,7 +39,7 @@ public class BedrockShowCreditsTranslator extends PacketTranslator<ShowCreditsPa
public void translate(GeyserSession session, ShowCreditsPacket packet) { public void translate(GeyserSession session, ShowCreditsPacket packet) {
if (packet.getStatus() == ShowCreditsPacket.Status.END_CREDITS) { if (packet.getStatus() == ShowCreditsPacket.Status.END_CREDITS) {
ServerboundClientCommandPacket javaRespawnPacket = new ServerboundClientCommandPacket(ClientCommand.RESPAWN); ServerboundClientCommandPacket javaRespawnPacket = new ServerboundClientCommandPacket(ClientCommand.RESPAWN);
session.sendDownstreamPacket(javaRespawnPacket); session.sendDownstreamGamePacket(javaRespawnPacket);
} }
} }
} }

View File

@ -49,7 +49,7 @@ public class BedrockEntityEventTranslator extends PacketTranslator<EntityEventPa
case COMPLETE_TRADE -> { case COMPLETE_TRADE -> {
// Not sent as of 1.18.10 // Not sent as of 1.18.10
ServerboundSelectTradePacket selectTradePacket = new ServerboundSelectTradePacket(packet.getData()); ServerboundSelectTradePacket selectTradePacket = new ServerboundSelectTradePacket(packet.getData());
session.sendDownstreamPacket(selectTradePacket); session.sendDownstreamGamePacket(selectTradePacket);
session.scheduleInEventLoop(() -> { session.scheduleInEventLoop(() -> {
Inventory openInventory = session.getOpenInventory(); Inventory openInventory = session.getOpenInventory();

View File

@ -26,10 +26,6 @@
package org.geysermc.geyser.translator.protocol.bedrock.entity.player; package org.geysermc.geyser.translator.protocol.bedrock.entity.player;
import com.github.steveice10.mc.protocol.data.game.entity.object.Direction; import com.github.steveice10.mc.protocol.data.game.entity.object.Direction;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundInteractPacket;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundPlayerAbilitiesPacket;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundPlayerActionPacket;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundPlayerCommandPacket;
import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import com.github.steveice10.mc.protocol.data.game.entity.player.InteractAction; import com.github.steveice10.mc.protocol.data.game.entity.player.InteractAction;
@ -97,7 +93,7 @@ public class BedrockActionTranslator extends PacketTranslator<PlayerActionPacket
case START_SWIMMING: case START_SWIMMING:
if (!entity.getFlag(EntityFlag.SWIMMING)) { if (!entity.getFlag(EntityFlag.SWIMMING)) {
ServerboundPlayerCommandPacket startSwimPacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.START_SPRINTING); ServerboundPlayerCommandPacket startSwimPacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.START_SPRINTING);
session.sendDownstreamPacket(startSwimPacket); session.sendDownstreamGamePacket(startSwimPacket);
session.setSwimming(true); session.setSwimming(true);
} }
@ -106,7 +102,7 @@ public class BedrockActionTranslator extends PacketTranslator<PlayerActionPacket
// Prevent packet spam when Bedrock players are crawling near the edge of a block // Prevent packet spam when Bedrock players are crawling near the edge of a block
if (!session.getCollisionManager().mustPlayerCrawlHere()) { if (!session.getCollisionManager().mustPlayerCrawlHere()) {
ServerboundPlayerCommandPacket stopSwimPacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.STOP_SPRINTING); ServerboundPlayerCommandPacket stopSwimPacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.STOP_SPRINTING);
session.sendDownstreamPacket(stopSwimPacket); session.sendDownstreamGamePacket(stopSwimPacket);
session.setSwimming(false); session.setSwimming(false);
} }
@ -114,45 +110,45 @@ public class BedrockActionTranslator extends PacketTranslator<PlayerActionPacket
case START_GLIDE: case START_GLIDE:
// Otherwise gliding will not work in creative // Otherwise gliding will not work in creative
ServerboundPlayerAbilitiesPacket playerAbilitiesPacket = new ServerboundPlayerAbilitiesPacket(false); ServerboundPlayerAbilitiesPacket playerAbilitiesPacket = new ServerboundPlayerAbilitiesPacket(false);
session.sendDownstreamPacket(playerAbilitiesPacket); session.sendDownstreamGamePacket(playerAbilitiesPacket);
case STOP_GLIDE: case STOP_GLIDE:
ServerboundPlayerCommandPacket glidePacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.START_ELYTRA_FLYING); ServerboundPlayerCommandPacket glidePacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.START_ELYTRA_FLYING);
session.sendDownstreamPacket(glidePacket); session.sendDownstreamGamePacket(glidePacket);
break; break;
case START_SNEAK: case START_SNEAK:
ServerboundPlayerCommandPacket startSneakPacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.START_SNEAKING); ServerboundPlayerCommandPacket startSneakPacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.START_SNEAKING);
session.sendDownstreamPacket(startSneakPacket); session.sendDownstreamGamePacket(startSneakPacket);
session.startSneaking(); session.startSneaking();
break; break;
case STOP_SNEAK: case STOP_SNEAK:
ServerboundPlayerCommandPacket stopSneakPacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.STOP_SNEAKING); ServerboundPlayerCommandPacket stopSneakPacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.STOP_SNEAKING);
session.sendDownstreamPacket(stopSneakPacket); session.sendDownstreamGamePacket(stopSneakPacket);
session.stopSneaking(); session.stopSneaking();
break; break;
case START_SPRINT: case START_SPRINT:
if (!entity.getFlag(EntityFlag.SWIMMING)) { if (!entity.getFlag(EntityFlag.SWIMMING)) {
ServerboundPlayerCommandPacket startSprintPacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.START_SPRINTING); ServerboundPlayerCommandPacket startSprintPacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.START_SPRINTING);
session.sendDownstreamPacket(startSprintPacket); session.sendDownstreamGamePacket(startSprintPacket);
session.setSprinting(true); session.setSprinting(true);
} }
break; break;
case STOP_SPRINT: case STOP_SPRINT:
if (!entity.getFlag(EntityFlag.SWIMMING)) { if (!entity.getFlag(EntityFlag.SWIMMING)) {
ServerboundPlayerCommandPacket stopSprintPacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.STOP_SPRINTING); ServerboundPlayerCommandPacket stopSprintPacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.STOP_SPRINTING);
session.sendDownstreamPacket(stopSprintPacket); session.sendDownstreamGamePacket(stopSprintPacket);
} }
session.setSprinting(false); session.setSprinting(false);
break; break;
case DROP_ITEM: case DROP_ITEM:
ServerboundPlayerActionPacket dropItemPacket = new ServerboundPlayerActionPacket(PlayerAction.DROP_ITEM, ServerboundPlayerActionPacket dropItemPacket = new ServerboundPlayerActionPacket(PlayerAction.DROP_ITEM,
vector, Direction.VALUES[packet.getFace()], 0); vector, Direction.VALUES[packet.getFace()], 0);
session.sendDownstreamPacket(dropItemPacket); session.sendDownstreamGamePacket(dropItemPacket);
break; break;
case STOP_SLEEP: case STOP_SLEEP:
ServerboundPlayerCommandPacket stopSleepingPacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.LEAVE_BED); ServerboundPlayerCommandPacket stopSleepingPacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.LEAVE_BED);
session.sendDownstreamPacket(stopSleepingPacket); session.sendDownstreamGamePacket(stopSleepingPacket);
break; break;
case START_BREAK: { case START_BREAK: {
// Ignore START_BREAK when the player is CREATIVE to avoid Spigot receiving 2 packets it interpets as block breaking. https://github.com/GeyserMC/Geyser/issues/4021 // Ignore START_BREAK when the player is CREATIVE to avoid Spigot receiving 2 packets it interpets as block breaking. https://github.com/GeyserMC/Geyser/issues/4021
@ -189,12 +185,12 @@ public class BedrockActionTranslator extends PacketTranslator<PlayerActionPacket
if (identifier.startsWith("minecraft:fire") || identifier.startsWith("minecraft:soul_fire")) { if (identifier.startsWith("minecraft:fire") || identifier.startsWith("minecraft:soul_fire")) {
ServerboundPlayerActionPacket startBreakingPacket = new ServerboundPlayerActionPacket(PlayerAction.START_DIGGING, fireBlockPos, ServerboundPlayerActionPacket startBreakingPacket = new ServerboundPlayerActionPacket(PlayerAction.START_DIGGING, fireBlockPos,
Direction.VALUES[packet.getFace()], session.getWorldCache().nextPredictionSequence()); Direction.VALUES[packet.getFace()], session.getWorldCache().nextPredictionSequence());
session.sendDownstreamPacket(startBreakingPacket); session.sendDownstreamGamePacket(startBreakingPacket);
} }
ServerboundPlayerActionPacket startBreakingPacket = new ServerboundPlayerActionPacket(PlayerAction.START_DIGGING, ServerboundPlayerActionPacket startBreakingPacket = new ServerboundPlayerActionPacket(PlayerAction.START_DIGGING,
vector, Direction.VALUES[packet.getFace()], session.getWorldCache().nextPredictionSequence()); vector, Direction.VALUES[packet.getFace()], session.getWorldCache().nextPredictionSequence());
session.sendDownstreamPacket(startBreakingPacket); session.sendDownstreamGamePacket(startBreakingPacket);
break; break;
} }
case CONTINUE_BREAK: case CONTINUE_BREAK:
@ -236,7 +232,7 @@ public class BedrockActionTranslator extends PacketTranslator<PlayerActionPacket
// Break the block // Break the block
ServerboundPlayerActionPacket finishBreakingPacket = new ServerboundPlayerActionPacket(PlayerAction.FINISH_DIGGING, ServerboundPlayerActionPacket finishBreakingPacket = new ServerboundPlayerActionPacket(PlayerAction.FINISH_DIGGING,
vector, Direction.VALUES[packet.getFace()], session.getWorldCache().nextPredictionSequence()); vector, Direction.VALUES[packet.getFace()], session.getWorldCache().nextPredictionSequence());
session.sendDownstreamPacket(finishBreakingPacket); session.sendDownstreamGamePacket(finishBreakingPacket);
session.setBlockBreakStartTime(0); session.setBlockBreakStartTime(0);
break; break;
} }
@ -253,13 +249,13 @@ public class BedrockActionTranslator extends PacketTranslator<PlayerActionPacket
if (itemFrameEntity != null) { if (itemFrameEntity != null) {
ServerboundInteractPacket interactPacket = new ServerboundInteractPacket(itemFrameEntity.getEntityId(), ServerboundInteractPacket interactPacket = new ServerboundInteractPacket(itemFrameEntity.getEntityId(),
InteractAction.ATTACK, Hand.MAIN_HAND, session.isSneaking()); InteractAction.ATTACK, Hand.MAIN_HAND, session.isSneaking());
session.sendDownstreamPacket(interactPacket); session.sendDownstreamGamePacket(interactPacket);
break; break;
} }
} }
ServerboundPlayerActionPacket abortBreakingPacket = new ServerboundPlayerActionPacket(PlayerAction.CANCEL_DIGGING, vector, Direction.DOWN, 0); ServerboundPlayerActionPacket abortBreakingPacket = new ServerboundPlayerActionPacket(PlayerAction.CANCEL_DIGGING, vector, Direction.DOWN, 0);
session.sendDownstreamPacket(abortBreakingPacket); session.sendDownstreamGamePacket(abortBreakingPacket);
LevelEventPacket stopBreak = new LevelEventPacket(); LevelEventPacket stopBreak = new LevelEventPacket();
stopBreak.setType(LevelEvent.BLOCK_STOP_BREAK); stopBreak.setType(LevelEvent.BLOCK_STOP_BREAK);
stopBreak.setPosition(vector.toFloat()); stopBreak.setPosition(vector.toFloat());
@ -287,7 +283,7 @@ public class BedrockActionTranslator extends PacketTranslator<PlayerActionPacket
case MISSED_SWING: case MISSED_SWING:
// TODO Re-evaluate after pre-1.20.10 is no longer supported? // TODO Re-evaluate after pre-1.20.10 is no longer supported?
if (session.getArmAnimationTicks() == -1) { if (session.getArmAnimationTicks() == -1) {
session.sendDownstreamPacket(new ServerboundSwingPacket(Hand.MAIN_HAND)); session.sendDownstreamGamePacket(new ServerboundSwingPacket(Hand.MAIN_HAND));
session.activateArmAnimationTicking(); session.activateArmAnimationTicking();
// Send packet to Bedrock so it knows // Send packet to Bedrock so it knows
@ -297,6 +293,40 @@ public class BedrockActionTranslator extends PacketTranslator<PlayerActionPacket
session.sendUpstreamPacket(animatePacket); session.sendUpstreamPacket(animatePacket);
} }
break; break;
case START_FLYING: // Since 1.20.30
if (session.isCanFly()) {
if (session.getGameMode() == GameMode.SPECTATOR) {
// should already be flying
session.sendAdventureSettings();
break;
}
if (session.getPlayerEntity().getFlag(EntityFlag.SWIMMING) && session.getCollisionManager().isPlayerInWater()) {
// As of 1.18.1, Java Edition cannot fly while in water, but it can fly while crawling
// If this isn't present, swimming on a 1.13.2 server and then attempting to fly will put you into a flying/swimming state that is invalid on JE
session.sendAdventureSettings();
break;
}
session.setFlying(true);
session.sendDownstreamGamePacket(new ServerboundPlayerAbilitiesPacket(true));
} else {
// update whether we can fly
session.sendAdventureSettings();
// stop flying
PlayerActionPacket stopFlyingPacket = new PlayerActionPacket();
stopFlyingPacket.setRuntimeEntityId(session.getPlayerEntity().getGeyserId());
stopFlyingPacket.setAction(PlayerActionType.STOP_FLYING);
stopFlyingPacket.setBlockPosition(Vector3i.ZERO);
stopFlyingPacket.setResultPosition(Vector3i.ZERO);
stopFlyingPacket.setFace(0);
session.sendUpstreamPacket(stopFlyingPacket);
}
break;
case STOP_FLYING:
session.setFlying(false);
session.sendDownstreamGamePacket(new ServerboundPlayerAbilitiesPacket(false));
break;
} }
} }
} }

View File

@ -68,16 +68,16 @@ public class BedrockInteractTranslator extends PacketTranslator<InteractPacket>
} }
ServerboundInteractPacket interactPacket = new ServerboundInteractPacket(entity.getEntityId(), ServerboundInteractPacket interactPacket = new ServerboundInteractPacket(entity.getEntityId(),
InteractAction.INTERACT, Hand.MAIN_HAND, session.isSneaking()); InteractAction.INTERACT, Hand.MAIN_HAND, session.isSneaking());
session.sendDownstreamPacket(interactPacket); session.sendDownstreamGamePacket(interactPacket);
break; break;
case DAMAGE: case DAMAGE:
ServerboundInteractPacket attackPacket = new ServerboundInteractPacket(entity.getEntityId(), ServerboundInteractPacket attackPacket = new ServerboundInteractPacket(entity.getEntityId(),
InteractAction.ATTACK, Hand.MAIN_HAND, session.isSneaking()); InteractAction.ATTACK, Hand.MAIN_HAND, session.isSneaking());
session.sendDownstreamPacket(attackPacket); session.sendDownstreamGamePacket(attackPacket);
break; break;
case LEAVE_VEHICLE: case LEAVE_VEHICLE:
ServerboundPlayerCommandPacket sneakPacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.START_SNEAKING); ServerboundPlayerCommandPacket sneakPacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.START_SNEAKING);
session.sendDownstreamPacket(sneakPacket); session.sendDownstreamGamePacket(sneakPacket);
Entity currentVehicle = session.getPlayerEntity().getVehicle(); Entity currentVehicle = session.getPlayerEntity().getVehicle();
if (currentVehicle != null) { if (currentVehicle != null) {
@ -123,7 +123,7 @@ public class BedrockInteractTranslator extends PacketTranslator<InteractPacket>
if (ridingEntity instanceof AbstractHorseEntity || (ridingEntity != null && ridingEntity.getDefinition().entityType() == EntityType.CHEST_BOAT)) { if (ridingEntity instanceof AbstractHorseEntity || (ridingEntity != null && ridingEntity.getDefinition().entityType() == EntityType.CHEST_BOAT)) {
// This mob has an inventory of its own that we should open instead. // This mob has an inventory of its own that we should open instead.
ServerboundPlayerCommandPacket openVehicleWindowPacket = new ServerboundPlayerCommandPacket(session.getPlayerEntity().getEntityId(), PlayerState.OPEN_VEHICLE_INVENTORY); ServerboundPlayerCommandPacket openVehicleWindowPacket = new ServerboundPlayerCommandPacket(session.getPlayerEntity().getEntityId(), PlayerState.OPEN_VEHICLE_INVENTORY);
session.sendDownstreamPacket(openVehicleWindowPacket); session.sendDownstreamGamePacket(openVehicleWindowPacket);
} else { } else {
session.setOpenInventory(session.getPlayerInventory()); session.setOpenInventory(session.getPlayerInventory());

View File

@ -83,7 +83,7 @@ public class BedrockMovePlayerTranslator extends PacketTranslator<MovePlayerPack
entity.setHeadYaw(headYaw); entity.setHeadYaw(headYaw);
entity.setOnGround(packet.isOnGround()); entity.setOnGround(packet.isOnGround());
session.sendDownstreamPacket(playerRotationPacket); session.sendDownstreamGamePacket(playerRotationPacket);
} else { } else {
if (session.getWorldBorder().isPassingIntoBorderBoundaries(packet.getPosition(), true)) { if (session.getWorldBorder().isPassingIntoBorderBoundaries(packet.getPosition(), true)) {
return; return;
@ -130,7 +130,7 @@ public class BedrockMovePlayerTranslator extends PacketTranslator<MovePlayerPack
entity.setOnGround(onGround); entity.setOnGround(onGround);
// Send final movement changes // Send final movement changes
session.sendDownstreamPacket(movePacket); session.sendDownstreamGamePacket(movePacket);
if (teleportThroughVoidFloor) { if (teleportThroughVoidFloor) {
// Work around there being a floor at the bottom of the world and teleport the player below it // Work around there being a floor at the bottom of the world and teleport the player below it

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org * Copyright (c) 2019-2023 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@ -23,33 +23,21 @@
* @link https://github.com/GeyserMC/Geyser * @link https://github.com/GeyserMC/Geyser
*/ */
package org.geysermc.connector.network.session.auth; package org.geysermc.geyser.translator.protocol.bedrock.entity.player;
import java.util.UUID; import org.cloudburstmc.protocol.bedrock.packet.RequestPermissionsPacket;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.protocol.PacketTranslator;
import org.geysermc.geyser.translator.protocol.Translator;
/** /**
* Deprecated, legacy code. Serves as a wrapper around * Sent occasionally by a BDS client when opening the client side server settings menu.
* the class used now.
*
* @deprecated legacy code
*/ */
@Deprecated @Translator(packet = RequestPermissionsPacket.class)
public class AuthData { public class BedrockRequestPermissionsPacket extends PacketTranslator<RequestPermissionsPacket> {
private final org.geysermc.geyser.session.auth.AuthData handle;
public AuthData(org.geysermc.geyser.session.auth.AuthData handle) { @Override
this.handle = handle; public void translate(GeyserSession session, RequestPermissionsPacket packet) {
} session.sendAdventureSettings();
public String getName() {
return this.handle.name();
}
public UUID getUUID() {
return this.handle.uuid();
}
public String getXboxUUID() {
return this.handle.xuid();
} }
} }

View File

@ -41,7 +41,7 @@ public class BedrockRiderJumpTranslator extends PacketTranslator<RiderJumpPacket
Entity vehicle = session.getPlayerEntity().getVehicle(); Entity vehicle = session.getPlayerEntity().getVehicle();
if (vehicle instanceof AbstractHorseEntity) { if (vehicle instanceof AbstractHorseEntity) {
ServerboundPlayerCommandPacket playerCommandPacket = new ServerboundPlayerCommandPacket(vehicle.getEntityId(), PlayerState.START_HORSE_JUMP, packet.getJumpStrength()); ServerboundPlayerCommandPacket playerCommandPacket = new ServerboundPlayerCommandPacket(vehicle.getEntityId(), PlayerState.START_HORSE_JUMP, packet.getJumpStrength());
session.sendDownstreamPacket(playerCommandPacket); session.sendDownstreamGamePacket(playerCommandPacket);
} }
} }
} }

View File

@ -41,7 +41,7 @@ public class BedrockSetDefaultGameTypeTranslator extends PacketTranslator<SetDef
*/ */
@Override @Override
public void translate(GeyserSession session, SetDefaultGameTypePacket packet) { public void translate(GeyserSession session, SetDefaultGameTypePacket packet) {
if (session.getOpPermissionLevel() >= 2 || session.hasPermission("geyser.settings.server")) { if (session.getOpPermissionLevel() >= 2 && session.hasPermission("geyser.settings.server")) {
session.getGeyser().getWorldManager().setDefaultGameMode(session, GameMode.byId(packet.getGamemode())); session.getGeyser().getWorldManager().setDefaultGameMode(session, GameMode.byId(packet.getGamemode()));
} }
// Stop the client from updating their own Gamemode without telling the server // Stop the client from updating their own Gamemode without telling the server

View File

@ -39,7 +39,7 @@ public class BedrockSetDifficultyTranslator extends PacketTranslator<SetDifficul
*/ */
@Override @Override
public void translate(GeyserSession session, SetDifficultyPacket packet) { public void translate(GeyserSession session, SetDifficultyPacket packet) {
if (session.getOpPermissionLevel() >= 2 || session.hasPermission("geyser.settings.server")) { if (session.getOpPermissionLevel() >= 2 && session.hasPermission("geyser.settings.server")) {
if (packet.getDifficulty() != session.getWorldCache().getDifficulty().ordinal()) { if (packet.getDifficulty() != session.getWorldCache().getDifficulty().ordinal()) {
session.getGeyser().getWorldManager().setDifficulty(session, Difficulty.from(packet.getDifficulty())); session.getGeyser().getWorldManager().setDifficulty(session, Difficulty.from(packet.getDifficulty()));
} }

View File

@ -45,7 +45,7 @@ public class BedrockSetPlayerGameTypeTranslator extends PacketTranslator<SetPlay
@Override @Override
public void translate(GeyserSession session, SetPlayerGameTypePacket packet) { public void translate(GeyserSession session, SetPlayerGameTypePacket packet) {
// yes, if you are OP // yes, if you are OP
if (session.getOpPermissionLevel() >= 2 || session.hasPermission("geyser.settings.server")) { if (session.getOpPermissionLevel() >= 2 && session.hasPermission("geyser.settings.server")) {
if (packet.getGamemode() != session.getGameMode().ordinal()) { if (packet.getGamemode() != session.getGameMode().ordinal()) {
// Bedrock has more Gamemodes than Java, leading to cases 5 (for "default") and 6 (for "spectator") being sent // Bedrock has more Gamemodes than Java, leading to cases 5 (for "default") and 6 (for "spectator") being sent
// https://github.com/CloudburstMC/Protocol/blob/3.0/bedrock-codec/src/main/java/org/cloudburstmc/protocol/bedrock/data/GameType.java // https://github.com/CloudburstMC/Protocol/blob/3.0/bedrock-codec/src/main/java/org/cloudburstmc/protocol/bedrock/data/GameType.java

View File

@ -57,7 +57,7 @@ public class BedrockLevelSoundEventTranslator extends PacketTranslator<LevelSoun
// ATTACK_NODAMAGE = player clicked air // ATTACK_NODAMAGE = player clicked air
// This should only be revisited if Bedrock packets get full Java parity, or Bedrock starts sending arm // This should only be revisited if Bedrock packets get full Java parity, or Bedrock starts sending arm
// animation packets after ATTACK_NODAMAGE, OR ATTACK_NODAMAGE gets removed/isn't sent in the same spot // animation packets after ATTACK_NODAMAGE, OR ATTACK_NODAMAGE gets removed/isn't sent in the same spot
session.sendDownstreamPacket(new ServerboundSwingPacket(Hand.MAIN_HAND)); session.sendDownstreamGamePacket(new ServerboundSwingPacket(Hand.MAIN_HAND));
session.activateArmAnimationTicking(); session.activateArmAnimationTicking();
// Send packet to Bedrock so it knows // Send packet to Bedrock so it knows

View File

@ -0,0 +1,48 @@
/*
* Copyright (c) 2019-2023 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.geyser.translator.protocol.java;
import com.github.steveice10.mc.protocol.data.game.ResourcePackStatus;
import com.github.steveice10.mc.protocol.packet.common.clientbound.ClientboundResourcePackPacket;
import com.github.steveice10.mc.protocol.packet.common.serverbound.ServerboundResourcePackPacket;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.protocol.PacketTranslator;
import org.geysermc.geyser.translator.protocol.Translator;
@Translator(packet = ClientboundResourcePackPacket.class)
public class JavaClientboundResourcePacksPacket extends PacketTranslator<ClientboundResourcePackPacket> {
@Override
public void translate(GeyserSession session, ClientboundResourcePackPacket packet) {
// We need to "answer" this to avoid timeout issues related to resource packs
// If packs are required, we need to lie to the server that we accepted them, as we get kicked otherwise.
if (packet.isRequired()) {
session.sendDownstreamPacket(new ServerboundResourcePackPacket(ResourcePackStatus.SUCCESSFULLY_LOADED));
} else {
session.sendDownstreamPacket(new ServerboundResourcePackPacket(ResourcePackStatus.DECLINED));
}
}
}

View File

@ -25,7 +25,7 @@
package org.geysermc.geyser.translator.protocol.java; package org.geysermc.geyser.translator.protocol.java;
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundCustomPayloadPacket; import com.github.steveice10.mc.protocol.packet.common.clientbound.ClientboundCustomPayloadPacket;
import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.GeyserLogger; import org.geysermc.geyser.GeyserLogger;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;

View File

@ -26,7 +26,7 @@
package org.geysermc.geyser.translator.protocol.java; package org.geysermc.geyser.translator.protocol.java;
import com.github.steveice10.mc.protocol.packet.login.clientbound.ClientboundCustomQueryPacket; import com.github.steveice10.mc.protocol.packet.login.clientbound.ClientboundCustomQueryPacket;
import com.github.steveice10.mc.protocol.packet.login.serverbound.ServerboundCustomQueryPacket; import com.github.steveice10.mc.protocol.packet.login.serverbound.ServerboundCustomQueryAnswerPacket;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.PacketTranslator;
import org.geysermc.geyser.translator.protocol.Translator; import org.geysermc.geyser.translator.protocol.Translator;
@ -40,8 +40,8 @@ public class JavaCustomQueryTranslator extends PacketTranslator<ClientboundCusto
public void translate(GeyserSession session, ClientboundCustomQueryPacket packet) { public void translate(GeyserSession session, ClientboundCustomQueryPacket packet) {
// A vanilla client doesn't know any PluginMessage in the Login state, so we don't know any either. // A vanilla client doesn't know any PluginMessage in the Login state, so we don't know any either.
// Note: Fabric Networking API v1 will not let the client log in without sending this // Note: Fabric Networking API v1 will not let the client log in without sending this
session.sendDownstreamPacket( session.sendDownstreamLoginPacket(
new ServerboundCustomQueryPacket(packet.getMessageId(), null) new ServerboundCustomQueryAnswerPacket(packet.getMessageId(), null)
); );
} }
} }

View File

@ -25,7 +25,7 @@
package org.geysermc.geyser.translator.protocol.java; package org.geysermc.geyser.translator.protocol.java;
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundDisconnectPacket; import com.github.steveice10.mc.protocol.packet.common.clientbound.ClientboundDisconnectPacket;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.PacketTranslator;
import org.geysermc.geyser.translator.protocol.Translator; import org.geysermc.geyser.translator.protocol.Translator;

View File

@ -26,6 +26,7 @@
package org.geysermc.geyser.translator.protocol.java; package org.geysermc.geyser.translator.protocol.java;
import com.github.steveice10.mc.auth.data.GameProfile; import com.github.steveice10.mc.auth.data.GameProfile;
import com.github.steveice10.mc.protocol.packet.common.serverbound.ServerboundCustomPayloadPacket;
import com.github.steveice10.mc.protocol.packet.login.clientbound.ClientboundGameProfilePacket; import com.github.steveice10.mc.protocol.packet.login.clientbound.ClientboundGameProfilePacket;
import org.geysermc.geyser.api.network.AuthType; import org.geysermc.geyser.api.network.AuthType;
import org.geysermc.geyser.entity.type.player.PlayerEntity; import org.geysermc.geyser.entity.type.player.PlayerEntity;
@ -33,7 +34,11 @@ import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.skin.SkinManager; import org.geysermc.geyser.skin.SkinManager;
import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.PacketTranslator;
import org.geysermc.geyser.translator.protocol.Translator; import org.geysermc.geyser.translator.protocol.Translator;
import org.geysermc.geyser.util.PluginMessageUtils;
/**
* ClientboundGameProfilePacket triggers protocol change LOGIN -> CONFIGURATION
*/
@Translator(packet = ClientboundGameProfilePacket.class) @Translator(packet = ClientboundGameProfilePacket.class)
public class JavaGameProfileTranslator extends PacketTranslator<ClientboundGameProfilePacket> { public class JavaGameProfileTranslator extends PacketTranslator<ClientboundGameProfilePacket> {
@ -65,5 +70,9 @@ public class JavaGameProfileTranslator extends PacketTranslator<ClientboundGameP
// We no longer need these variables; they're just taking up space in memory now // We no longer need these variables; they're just taking up space in memory now
session.setCertChainData(null); session.setCertChainData(null);
session.getClientData().setOriginalString(null); session.getClientData().setOriginalString(null);
// configuration phase stuff that the vanilla client replies with after receiving the GameProfilePacket
session.sendDownstreamPacket(new ServerboundCustomPayloadPacket("minecraft:brand", PluginMessageUtils.getGeyserBrandData()));
session.sendJavaClientSettings();
} }
} }

View File

@ -25,7 +25,7 @@
package org.geysermc.geyser.translator.protocol.java; package org.geysermc.geyser.translator.protocol.java;
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundKeepAlivePacket; import com.github.steveice10.mc.protocol.packet.common.clientbound.ClientboundKeepAlivePacket;
import org.cloudburstmc.protocol.bedrock.packet.NetworkStackLatencyPacket; import org.cloudburstmc.protocol.bedrock.packet.NetworkStackLatencyPacket;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.PacketTranslator;

View File

@ -25,30 +25,20 @@
package org.geysermc.geyser.translator.protocol.java; package org.geysermc.geyser.translator.protocol.java;
import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerSpawnInfo;
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundLoginPacket; import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundLoginPacket;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundCustomPayloadPacket;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.github.steveice10.opennbt.tag.builtin.IntTag;
import org.cloudburstmc.protocol.bedrock.data.GameRuleData; import org.cloudburstmc.protocol.bedrock.data.GameRuleData;
import org.cloudburstmc.protocol.bedrock.packet.GameRulesChangedPacket; import org.cloudburstmc.protocol.bedrock.packet.GameRulesChangedPacket;
import org.cloudburstmc.protocol.bedrock.packet.SetPlayerGameTypePacket; import org.cloudburstmc.protocol.bedrock.packet.SetPlayerGameTypePacket;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import org.geysermc.geyser.api.network.AuthType; import org.geysermc.geyser.api.network.AuthType;
import org.geysermc.geyser.entity.type.player.SessionPlayerEntity; import org.geysermc.geyser.entity.type.player.SessionPlayerEntity;
import org.geysermc.geyser.erosion.GeyserboundHandshakePacketHandler; import org.geysermc.geyser.erosion.GeyserboundHandshakePacketHandler;
import org.geysermc.geyser.level.JavaDimension;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.text.TextDecoration;
import org.geysermc.geyser.translator.level.BiomeTranslator;
import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.PacketTranslator;
import org.geysermc.geyser.translator.protocol.Translator; import org.geysermc.geyser.translator.protocol.Translator;
import org.geysermc.geyser.util.ChunkUtils; import org.geysermc.geyser.util.ChunkUtils;
import org.geysermc.geyser.util.DimensionUtils; import org.geysermc.geyser.util.DimensionUtils;
import org.geysermc.geyser.util.EntityUtils; import org.geysermc.geyser.util.EntityUtils;
import org.geysermc.geyser.util.JavaCodecUtil;
import org.geysermc.geyser.util.PluginMessageUtils;
import java.util.Map;
@Translator(packet = ClientboundLoginPacket.class) @Translator(packet = ClientboundLoginPacket.class)
public class JavaLoginTranslator extends PacketTranslator<ClientboundLoginPacket> { public class JavaLoginTranslator extends PacketTranslator<ClientboundLoginPacket> {
@ -63,42 +53,22 @@ public class JavaLoginTranslator extends PacketTranslator<ClientboundLoginPacket
session.setErosionHandler(new GeyserboundHandshakePacketHandler(session)); session.setErosionHandler(new GeyserboundHandshakePacketHandler(session));
} }
Map<String, JavaDimension> dimensions = session.getDimensions(); PlayerSpawnInfo spawnInfo = packet.getCommonPlayerSpawnInfo();
dimensions.clear();
JavaDimension.load(packet.getRegistry(), dimensions);
Int2ObjectMap<TextDecoration> chatTypes = session.getChatTypes();
chatTypes.clear();
for (CompoundTag tag : JavaCodecUtil.iterateAsTag(packet.getRegistry().get("minecraft:chat_type"))) {
// The ID is NOT ALWAYS THE SAME! ViaVersion as of 1.19 adds two registry entries that do NOT match vanilla.
int id = ((IntTag) tag.get("id")).getValue();
CompoundTag element = tag.get("element");
CompoundTag chat = element.get("chat");
TextDecoration textDecoration = null;
if (chat != null) {
textDecoration = new TextDecoration(chat);
}
chatTypes.put(id, textDecoration);
}
// If the player is already initialized and a join game packet is sent, they // If the player is already initialized and a join game packet is sent, they
// are swapping servers // are swapping servers
if (session.isSpawned()) { if (session.isSpawned()) {
String fakeDim = DimensionUtils.getTemporaryDimension(session.getDimension(), packet.getDimension()); String fakeDim = DimensionUtils.getTemporaryDimension(session.getDimension(), spawnInfo.getDimension());
DimensionUtils.switchDimension(session, fakeDim); DimensionUtils.switchDimension(session, fakeDim);
session.getWorldCache().removeScoreboard(); session.getWorldCache().removeScoreboard();
} }
session.setWorldName(packet.getWorldName()); session.setWorldName(spawnInfo.getWorldName());
session.setLevels(packet.getWorldNames()); session.setLevels(packet.getWorldNames());
BiomeTranslator.loadServerBiomes(session, packet.getRegistry()); session.setGameMode(spawnInfo.getGameMode());
session.getTagCache().clear();
session.setGameMode(packet.getGameMode()); String newDimension = spawnInfo.getDimension();
String newDimension = packet.getDimension();
boolean needsSpawnPacket = !session.isSentSpawnPacket(); boolean needsSpawnPacket = !session.isSentSpawnPacket();
if (needsSpawnPacket) { if (needsSpawnPacket) {
@ -113,11 +83,11 @@ public class JavaLoginTranslator extends PacketTranslator<ClientboundLoginPacket
if (!needsSpawnPacket) { if (!needsSpawnPacket) {
SetPlayerGameTypePacket playerGameTypePacket = new SetPlayerGameTypePacket(); SetPlayerGameTypePacket playerGameTypePacket = new SetPlayerGameTypePacket();
playerGameTypePacket.setGamemode(EntityUtils.toBedrockGamemode(packet.getGameMode()).ordinal()); playerGameTypePacket.setGamemode(EntityUtils.toBedrockGamemode(spawnInfo.getGameMode()).ordinal());
session.sendUpstreamPacket(playerGameTypePacket); session.sendUpstreamPacket(playerGameTypePacket);
} }
entity.setLastDeathPosition(packet.getLastDeathPos()); entity.setLastDeathPosition(spawnInfo.getLastDeathPos());
entity.updateBedrockMetadata(); entity.updateBedrockMetadata();
@ -130,16 +100,10 @@ public class JavaLoginTranslator extends PacketTranslator<ClientboundLoginPacket
session.setServerRenderDistance(packet.getViewDistance()); session.setServerRenderDistance(packet.getViewDistance());
// TODO customize // send this again now that we know the server render distance
// as the bedrock client isn't required to send a render distance
session.sendJavaClientSettings(); session.sendJavaClientSettings();
session.sendDownstreamPacket(new ServerboundCustomPayloadPacket("minecraft:brand", PluginMessageUtils.getGeyserBrandData()));
// TODO don't send two packets
// if (true) {
// session.sendDownstreamPacket(new ServerboundCustomPayloadPacket("minecraft:register", Constants.PLUGIN_MESSAGE.getBytes(StandardCharsets.UTF_8)));
// }
// register the plugin messaging channels used in Floodgate
if (session.remoteServer().authType() == AuthType.FLOODGATE) { if (session.remoteServer().authType() == AuthType.FLOODGATE) {
//todo //todo
// session.sendDownstreamPacket(new ServerboundCustomPayloadPacket("minecraft:register", PluginMessageChannels.getFloodgateRegisterData())); // session.sendDownstreamPacket(new ServerboundCustomPayloadPacket("minecraft:register", PluginMessageChannels.getFloodgateRegisterData()));

View File

@ -25,8 +25,8 @@
package org.geysermc.geyser.translator.protocol.java; package org.geysermc.geyser.translator.protocol.java;
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundPingPacket; import com.github.steveice10.mc.protocol.packet.common.clientbound.ClientboundPingPacket;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundPongPacket; import com.github.steveice10.mc.protocol.packet.common.serverbound.ServerboundPongPacket;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.PacketTranslator;
import org.geysermc.geyser.translator.protocol.Translator; import org.geysermc.geyser.translator.protocol.Translator;

View File

@ -0,0 +1,67 @@
/*
* Copyright (c) 2019-2023 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.geyser.translator.protocol.java;
import com.github.steveice10.mc.protocol.packet.configuration.clientbound.ClientboundRegistryDataPacket;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.github.steveice10.opennbt.tag.builtin.IntTag;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import org.geysermc.geyser.level.JavaDimension;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.text.TextDecoration;
import org.geysermc.geyser.translator.level.BiomeTranslator;
import org.geysermc.geyser.translator.protocol.PacketTranslator;
import org.geysermc.geyser.translator.protocol.Translator;
import org.geysermc.geyser.util.JavaCodecUtil;
import java.util.Map;
@Translator(packet = ClientboundRegistryDataPacket.class)
public class JavaRegistryDataTranslator extends PacketTranslator<ClientboundRegistryDataPacket> {
@Override
public void translate(GeyserSession session, ClientboundRegistryDataPacket packet) {
Map<String, JavaDimension> dimensions = session.getDimensions();
dimensions.clear();
JavaDimension.load(packet.getRegistry(), dimensions);
Int2ObjectMap<TextDecoration> chatTypes = session.getChatTypes();
chatTypes.clear();
for (CompoundTag tag : JavaCodecUtil.iterateAsTag(packet.getRegistry().get("minecraft:chat_type"))) {
// The ID is NOT ALWAYS THE SAME! ViaVersion as of 1.19 adds two registry entries that do NOT match vanilla.
int id = ((IntTag) tag.get("id")).getValue();
CompoundTag element = tag.get("element");
CompoundTag chat = element.get("chat");
TextDecoration textDecoration = null;
if (chat != null) {
textDecoration = new TextDecoration(chat);
}
chatTypes.put(id, textDecoration);
}
BiomeTranslator.loadServerBiomes(session, packet.getRegistry());
}
}

View File

@ -25,6 +25,7 @@
package org.geysermc.geyser.translator.protocol.java; package org.geysermc.geyser.translator.protocol.java;
import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerSpawnInfo;
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundRespawnPacket; import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundRespawnPacket;
import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.LevelEvent; import org.cloudburstmc.protocol.bedrock.data.LevelEvent;
@ -46,6 +47,7 @@ public class JavaRespawnTranslator extends PacketTranslator<ClientboundRespawnPa
@Override @Override
public void translate(GeyserSession session, ClientboundRespawnPacket packet) { public void translate(GeyserSession session, ClientboundRespawnPacket packet) {
SessionPlayerEntity entity = session.getPlayerEntity(); SessionPlayerEntity entity = session.getPlayerEntity();
PlayerSpawnInfo spawnInfo = packet.getCommonPlayerSpawnInfo();
session.setSpawned(false); session.setSpawned(false);
@ -56,13 +58,13 @@ public class JavaRespawnTranslator extends PacketTranslator<ClientboundRespawnPa
session.setOpenInventory(null); session.setOpenInventory(null);
session.setClosingInventory(false); session.setClosingInventory(false);
entity.setLastDeathPosition(packet.getLastDeathPos()); entity.setLastDeathPosition(spawnInfo.getLastDeathPos());
entity.updateBedrockMetadata(); entity.updateBedrockMetadata();
SetPlayerGameTypePacket playerGameTypePacket = new SetPlayerGameTypePacket(); SetPlayerGameTypePacket playerGameTypePacket = new SetPlayerGameTypePacket();
playerGameTypePacket.setGamemode(EntityUtils.toBedrockGamemode(packet.getGamemode()).ordinal()); playerGameTypePacket.setGamemode(EntityUtils.toBedrockGamemode(spawnInfo.getGameMode()).ordinal());
session.sendUpstreamPacket(playerGameTypePacket); session.sendUpstreamPacket(playerGameTypePacket);
session.setGameMode(packet.getGamemode()); session.setGameMode(spawnInfo.getGameMode());
if (session.isRaining()) { if (session.isRaining()) {
LevelEventPacket stopRainPacket = new LevelEventPacket(); LevelEventPacket stopRainPacket = new LevelEventPacket();
@ -82,14 +84,14 @@ public class JavaRespawnTranslator extends PacketTranslator<ClientboundRespawnPa
session.setThunder(false); session.setThunder(false);
} }
String newDimension = packet.getDimension(); String newDimension = spawnInfo.getDimension();
if (!session.getDimension().equals(newDimension) || !packet.getWorldName().equals(session.getWorldName())) { if (!session.getDimension().equals(newDimension) || !spawnInfo.getWorldName().equals(session.getWorldName())) {
// Switching to a new world (based off the world name change or new dimension); send a fake dimension change // Switching to a new world (based off the world name change or new dimension); send a fake dimension change
if (DimensionUtils.javaToBedrock(session.getDimension()) == DimensionUtils.javaToBedrock(newDimension)) { if (DimensionUtils.javaToBedrock(session.getDimension()) == DimensionUtils.javaToBedrock(newDimension)) {
String fakeDim = DimensionUtils.getTemporaryDimension(session.getDimension(), newDimension); String fakeDim = DimensionUtils.getTemporaryDimension(session.getDimension(), newDimension);
DimensionUtils.switchDimension(session, fakeDim); DimensionUtils.switchDimension(session, fakeDim);
} }
session.setWorldName(packet.getWorldName()); session.setWorldName(spawnInfo.getWorldName());
DimensionUtils.switchDimension(session, newDimension); DimensionUtils.switchDimension(session, newDimension);
ChunkUtils.loadDimension(session); ChunkUtils.loadDimension(session);

View File

@ -25,7 +25,7 @@
package org.geysermc.geyser.translator.protocol.java; package org.geysermc.geyser.translator.protocol.java;
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundUpdateTagsPacket; import com.github.steveice10.mc.protocol.packet.common.clientbound.ClientboundUpdateTagsPacket;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.PacketTranslator;
import org.geysermc.geyser.translator.protocol.Translator; import org.geysermc.geyser.translator.protocol.Translator;

View File

@ -120,7 +120,7 @@ public class JavaEntityEventTranslator extends PacketTranslator<ClientboundEntit
if (fishingHook.getBedrockTargetId() == session.getPlayerEntity().getGeyserId()) { if (fishingHook.getBedrockTargetId() == session.getPlayerEntity().getGeyserId()) {
Entity hookOwner = session.getEntityCache().getEntityByGeyserId(fishingHook.getBedrockOwnerId()); Entity hookOwner = session.getEntityCache().getEntityByGeyserId(fishingHook.getBedrockOwnerId());
if (hookOwner != null) { if (hookOwner != null) {
// https://minecraft.gamepedia.com/Fishing_Rod#Hooking_mobs_and_other_entities // https://minecraft.wiki/w/Fishing_Rod#Hooking_mobs_and_other_entities
SetEntityMotionPacket motionPacket = new SetEntityMotionPacket(); SetEntityMotionPacket motionPacket = new SetEntityMotionPacket();
motionPacket.setRuntimeEntityId(session.getPlayerEntity().getGeyserId()); motionPacket.setRuntimeEntityId(session.getPlayerEntity().getGeyserId());
motionPacket.setMotion(hookOwner.getPosition().sub(session.getPlayerEntity().getPosition()).mul(0.1f)); motionPacket.setMotion(hookOwner.getPosition().sub(session.getPlayerEntity().getPosition()).mul(0.1f));

View File

@ -42,8 +42,9 @@ public class JavaUpdateMobEffectTranslator extends PacketTranslator<ClientboundU
if (entity == session.getPlayerEntity()) { if (entity == session.getPlayerEntity()) {
session.getEffectCache().setEffect(packet.getEffect(), packet.getAmplifier()); session.getEffectCache().setEffect(packet.getEffect(), packet.getAmplifier());
} }
if (entity == null) if (entity == null) {
return; return;
}
int duration = packet.getDuration(); int duration = packet.getDuration();
if (duration < 0) { if (duration < 0) {

View File

@ -29,6 +29,7 @@ import com.github.steveice10.mc.auth.data.GameProfile;
import com.github.steveice10.mc.protocol.data.game.PlayerListEntry; import com.github.steveice10.mc.protocol.data.game.PlayerListEntry;
import com.github.steveice10.mc.protocol.data.game.PlayerListEntryAction; import com.github.steveice10.mc.protocol.data.game.PlayerListEntryAction;
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundPlayerInfoUpdatePacket; import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundPlayerInfoUpdatePacket;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.packet.PlayerListPacket; import org.cloudburstmc.protocol.bedrock.packet.PlayerListPacket;
import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserImpl;
@ -41,6 +42,7 @@ import org.geysermc.geyser.translator.protocol.Translator;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.UUID;
@Translator(packet = ClientboundPlayerInfoUpdatePacket.class) @Translator(packet = ClientboundPlayerInfoUpdatePacket.class)
public class JavaPlayerInfoUpdateTranslator extends PacketTranslator<ClientboundPlayerInfoUpdatePacket> { public class JavaPlayerInfoUpdateTranslator extends PacketTranslator<ClientboundPlayerInfoUpdatePacket> {
@ -50,13 +52,24 @@ public class JavaPlayerInfoUpdateTranslator extends PacketTranslator<Clientbound
if (actions.contains(PlayerListEntryAction.ADD_PLAYER)) { if (actions.contains(PlayerListEntryAction.ADD_PLAYER)) {
for (PlayerListEntry entry : packet.getEntries()) { for (PlayerListEntry entry : packet.getEntries()) {
GameProfile profile = entry.getProfile(); @Nullable GameProfile profile = entry.getProfile();
UUID id = entry.getProfileId();
String name = null;
String texturesProperty = null;
if (profile != null) {
name = profile.getName();
GameProfile.Property textures = profile.getProperty("textures");
if (textures != null) {
texturesProperty = textures.getValue();
}
}
boolean self = id.equals(session.getPlayerEntity().getUuid());
PlayerEntity playerEntity; PlayerEntity playerEntity;
boolean self = profile.getId().equals(session.getPlayerEntity().getUuid());
GameProfile.Property textures = profile.getProperty("textures");
String texturesProperty = textures == null ? null : textures.getValue();
if (self) { if (self) {
// Entity is ourself // Entity is ourself
playerEntity = session.getPlayerEntity(); playerEntity = session.getPlayerEntity();
@ -66,17 +79,17 @@ public class JavaPlayerInfoUpdateTranslator extends PacketTranslator<Clientbound
session, session,
-1, -1,
session.getEntityCache().getNextEntityId().incrementAndGet(), session.getEntityCache().getNextEntityId().incrementAndGet(),
profile.getId(), id,
Vector3f.ZERO, Vector3f.ZERO,
Vector3f.ZERO, Vector3f.ZERO,
0, 0, 0, 0, 0, 0,
profile.getName(), name,
texturesProperty texturesProperty
); );
session.getEntityCache().addPlayerEntity(playerEntity); session.getEntityCache().addPlayerEntity(playerEntity);
} }
playerEntity.setUsername(profile.getName()); playerEntity.setUsername(name);
playerEntity.setTexturesProperty(texturesProperty); playerEntity.setTexturesProperty(texturesProperty);
if (self) { if (self) {

View File

@ -133,9 +133,9 @@ public class JavaPlayerPositionTranslator extends PacketTranslator<ClientboundPl
private void acceptTeleport(GeyserSession session, double x, double y, double z, float yaw, float pitch, int id) { private void acceptTeleport(GeyserSession session, double x, double y, double z, float yaw, float pitch, int id) {
// Confirm the teleport when we receive it to match Java edition // Confirm the teleport when we receive it to match Java edition
ServerboundAcceptTeleportationPacket teleportConfirmPacket = new ServerboundAcceptTeleportationPacket(id); ServerboundAcceptTeleportationPacket teleportConfirmPacket = new ServerboundAcceptTeleportationPacket(id);
session.sendDownstreamPacket(teleportConfirmPacket); session.sendDownstreamGamePacket(teleportConfirmPacket);
// Servers (especially ones like Hypixel) expect exact coordinates given back to them. // Servers (especially ones like Hypixel) expect exact coordinates given back to them.
ServerboundMovePlayerPosRotPacket positionPacket = new ServerboundMovePlayerPosRotPacket(false, x, y, z, yaw, pitch); ServerboundMovePlayerPosRotPacket positionPacket = new ServerboundMovePlayerPosRotPacket(false, x, y, z, yaw, pitch);
session.sendDownstreamPacket(positionPacket); session.sendDownstreamGamePacket(positionPacket);
} }
} }

View File

@ -31,11 +31,14 @@ import com.github.steveice10.mc.protocol.data.game.entity.object.ProjectileData;
import com.github.steveice10.mc.protocol.data.game.entity.type.EntityType; import com.github.steveice10.mc.protocol.data.game.entity.type.EntityType;
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.entity.spawn.ClientboundAddEntityPacket; import com.github.steveice10.mc.protocol.packet.ingame.clientbound.entity.spawn.ClientboundAddEntityPacket;
import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.math.vector.Vector3f;
import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.entity.type.*; import org.geysermc.geyser.entity.type.*;
import org.geysermc.geyser.entity.type.player.PlayerEntity; import org.geysermc.geyser.entity.type.player.PlayerEntity;
import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.registry.Registries;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.skin.SkinManager;
import org.geysermc.geyser.text.GeyserLocale;
import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.PacketTranslator;
import org.geysermc.geyser.translator.protocol.Translator; import org.geysermc.geyser.translator.protocol.Translator;
@ -44,15 +47,44 @@ public class JavaAddEntityTranslator extends PacketTranslator<ClientboundAddEnti
@Override @Override
public void translate(GeyserSession session, ClientboundAddEntityPacket packet) { public void translate(GeyserSession session, ClientboundAddEntityPacket packet) {
EntityDefinition<?> definition = Registries.ENTITY_DEFINITIONS.get(packet.getType());
if (definition == null) {
session.getGeyser().getLogger().warning("Could not find an entity definition with type " + packet.getType());
return;
}
Vector3f position = Vector3f.from(packet.getX(), packet.getY(), packet.getZ()); Vector3f position = Vector3f.from(packet.getX(), packet.getY(), packet.getZ());
Vector3f motion = Vector3f.from(packet.getMotionX(), packet.getMotionY(), packet.getMotionZ()); Vector3f motion = Vector3f.from(packet.getMotionX(), packet.getMotionY(), packet.getMotionZ());
float yaw = packet.getYaw(); float yaw = packet.getYaw();
float pitch = packet.getPitch(); float pitch = packet.getPitch();
float headYaw = packet.getHeadYaw(); float headYaw = packet.getHeadYaw();
EntityDefinition<?> definition = Registries.ENTITY_DEFINITIONS.get(packet.getType()); if (packet.getType() == EntityType.PLAYER) {
if (definition == null) {
session.getGeyser().getLogger().warning("Could not find an entity definition with type " + packet.getType()); PlayerEntity entity;
if (packet.getUuid().equals(session.getPlayerEntity().getUuid())) {
// Server is sending a fake version of the current player
entity = new PlayerEntity(session, packet.getEntityId(), session.getEntityCache().getNextEntityId().incrementAndGet(),
session.getPlayerEntity().getUuid(), position, motion, yaw, pitch, headYaw, session.getPlayerEntity().getUsername(),
session.getPlayerEntity().getTexturesProperty());
} else {
entity = session.getEntityCache().getPlayerEntity(packet.getUuid());
if (entity == null) {
GeyserImpl.getInstance().getLogger().error(GeyserLocale.getLocaleStringLog("geyser.entity.player.failed_list", packet.getUuid()));
return;
}
entity.setEntityId(packet.getEntityId());
entity.setPosition(position);
entity.setYaw(yaw);
entity.setPitch(pitch);
entity.setHeadYaw(headYaw);
entity.setMotion(motion);
}
session.getEntityCache().cacheEntity(entity);
entity.sendPlayer();
SkinManager.requestAndHandleSkinAndCape(entity, session, null);
return; return;
} }

View File

@ -1,72 +0,0 @@
/*
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.geyser.translator.protocol.java.entity.spawn;
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.entity.spawn.ClientboundAddPlayerPacket;
import org.cloudburstmc.math.vector.Vector3f;
import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.entity.type.player.PlayerEntity;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.skin.SkinManager;
import org.geysermc.geyser.text.GeyserLocale;
import org.geysermc.geyser.translator.protocol.PacketTranslator;
import org.geysermc.geyser.translator.protocol.Translator;
@Translator(packet = ClientboundAddPlayerPacket.class)
public class JavaAddPlayerTranslator extends PacketTranslator<ClientboundAddPlayerPacket> {
@Override
public void translate(GeyserSession session, ClientboundAddPlayerPacket packet) {
Vector3f position = Vector3f.from(packet.getX(), packet.getY(), packet.getZ());
float yaw = packet.getYaw();
float pitch = packet.getPitch();
float headYaw = packet.getYaw();
PlayerEntity entity;
if (packet.getUuid().equals(session.getPlayerEntity().getUuid())) {
// Server is sending a fake version of the current player
entity = new PlayerEntity(session, packet.getEntityId(), session.getEntityCache().getNextEntityId().incrementAndGet(),
session.getPlayerEntity().getUuid(), position, Vector3f.ZERO, yaw, pitch, headYaw, session.getPlayerEntity().getUsername(),
session.getPlayerEntity().getTexturesProperty());
} else {
entity = session.getEntityCache().getPlayerEntity(packet.getUuid());
if (entity == null) {
GeyserImpl.getInstance().getLogger().error(GeyserLocale.getLocaleStringLog("geyser.entity.player.failed_list", packet.getUuid()));
return;
}
entity.setEntityId(packet.getEntityId());
entity.setPosition(position);
entity.setYaw(yaw);
entity.setPitch(pitch);
entity.setHeadYaw(headYaw);
}
session.getEntityCache().cacheEntity(entity);
entity.sendPlayer();
SkinManager.requestAndHandleSkinAndCape(entity, session, null);
}
}

View File

@ -63,7 +63,7 @@ public class JavaOpenScreenTranslator extends PacketTranslator<ClientboundOpenSc
InventoryUtils.closeInventory(session, openInventory.getJavaId(), true); InventoryUtils.closeInventory(session, openInventory.getJavaId(), true);
} }
ServerboundContainerClosePacket closeWindowPacket = new ServerboundContainerClosePacket(packet.getContainerId()); ServerboundContainerClosePacket closeWindowPacket = new ServerboundContainerClosePacket(packet.getContainerId());
session.sendDownstreamPacket(closeWindowPacket); session.sendDownstreamGamePacket(closeWindowPacket);
return; return;
} }

View File

@ -0,0 +1,44 @@
/*
* Copyright (c) 2019-2023 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.geyser.translator.protocol.java.level;
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.ClientboundChunkBatchFinishedPacket;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.level.ServerboundChunkBatchReceivedPacket;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.protocol.PacketTranslator;
import org.geysermc.geyser.translator.protocol.Translator;
@Translator(packet = ClientboundChunkBatchFinishedPacket.class)
public class JavaChunkBatchFinishedTranslator extends PacketTranslator<ClientboundChunkBatchFinishedPacket> {
@Override
public void translate(GeyserSession session, ClientboundChunkBatchFinishedPacket packet) {
// server just sent a batch of LevelChunkWithLightPackets
// the vanilla client uses a ChunkBatchSizeCalculator to calculate the desiredChunksPerTick,
// but currently we just send an arbitrary value. server clamps the value between 0.01 and 64.
session.sendDownstreamGamePacket(new ServerboundChunkBatchReceivedPacket(20));
}
}

View File

@ -131,7 +131,7 @@ public class JavaGameEventTranslator extends PacketTranslator<ClientboundGameEve
switch ((EnterCreditsValue) packet.getValue()) { switch ((EnterCreditsValue) packet.getValue()) {
case SEEN_BEFORE -> { case SEEN_BEFORE -> {
ServerboundClientCommandPacket javaRespawnPacket = new ServerboundClientCommandPacket(ClientCommand.RESPAWN); ServerboundClientCommandPacket javaRespawnPacket = new ServerboundClientCommandPacket(ClientCommand.RESPAWN);
session.sendDownstreamPacket(javaRespawnPacket); session.sendDownstreamGamePacket(javaRespawnPacket);
} }
case FIRST_TIME -> { case FIRST_TIME -> {
ShowCreditsPacket showCreditsPacket = new ShowCreditsPacket(); ShowCreditsPacket showCreditsPacket = new ShowCreditsPacket();

View File

@ -31,6 +31,7 @@ import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.Clientb
import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.math.vector.Vector3i;
import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.protocol.bedrock.data.ParticleType;
import org.cloudburstmc.protocol.bedrock.data.SoundEvent; import org.cloudburstmc.protocol.bedrock.data.SoundEvent;
import org.cloudburstmc.protocol.bedrock.packet.LevelEventGenericPacket; import org.cloudburstmc.protocol.bedrock.packet.LevelEventGenericPacket;
import org.cloudburstmc.protocol.bedrock.packet.LevelEventPacket; import org.cloudburstmc.protocol.bedrock.packet.LevelEventPacket;
@ -103,6 +104,10 @@ public class JavaLevelEventTranslator extends PacketTranslator<ClientboundLevelE
effectPacket.setPosition(pos); effectPacket.setPosition(pos);
effectPacket.setData(0); effectPacket.setData(0);
switch (levelEvent) { switch (levelEvent) {
case BRUSH_BLOCK_COMPLETE -> {
effectPacket.setType(ParticleType.BRUSH_DUST);
session.playSoundEvent(SoundEvent.BRUSH_COMPLETED, pos); // todo 1.20.2 verify this
}
case COMPOSTER -> { case COMPOSTER -> {
effectPacket.setType(org.cloudburstmc.protocol.bedrock.data.LevelEvent.PARTICLE_CROP_GROWTH); effectPacket.setType(org.cloudburstmc.protocol.bedrock.data.LevelEvent.PARTICLE_CROP_GROWTH);
@ -224,6 +229,7 @@ public class JavaLevelEventTranslator extends PacketTranslator<ClientboundLevelE
BonemealGrowEventData growEventData = (BonemealGrowEventData) packet.getData(); BonemealGrowEventData growEventData = (BonemealGrowEventData) packet.getData();
effectPacket.setData(growEventData.getParticleCount()); effectPacket.setData(growEventData.getParticleCount());
} }
case EGG_CRACK -> effectPacket.setType(ParticleType.VILLAGER_HAPPY); // both the lil green sparkle
case ENDERDRAGON_FIREBALL_EXPLODE -> { case ENDERDRAGON_FIREBALL_EXPLODE -> {
effectPacket.setType(org.cloudburstmc.protocol.bedrock.data.LevelEvent.PARTICLE_EYE_OF_ENDER_DEATH); // TODO effectPacket.setType(org.cloudburstmc.protocol.bedrock.data.LevelEvent.PARTICLE_EYE_OF_ENDER_DEATH); // TODO

View File

@ -40,7 +40,7 @@ public class JavaSetTimeTranslator extends PacketTranslator<ClientboundSetTimePa
// 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 time = packet.getTime(); long time = packet.getTime();
// https://minecraft.gamepedia.com/Day-night_cycle#24-hour_Minecraft_day // https://minecraft.wiki/w/Day-night_cycle#24-hour_Minecraft_day
SetTimePacket setTimePacket = new SetTimePacket(); SetTimePacket setTimePacket = new SetTimePacket();
// We use modulus to prevent an integer overflow // We use modulus to prevent an integer overflow
// 24000 is the range of ticks that a Minecraft day can be; we times by 8 so all moon phases are visible // 24000 is the range of ticks that a Minecraft day can be; we times by 8 so all moon phases are visible

View File

@ -32,7 +32,7 @@ import com.github.steveice10.mc.protocol.data.game.entity.attribute.ModifierOper
public class AttributeUtils { public class AttributeUtils {
/** /**
* Retrieve the base attribute value with all modifiers applied. * Retrieve the base attribute value with all modifiers applied.
* https://minecraft.gamepedia.com/Attribute#Modifiers * https://minecraft.wiki/w/Attribute#Modifiers
* @param attribute The attribute to calculate the total value. * @param attribute The attribute to calculate the total value.
* @return The finished attribute with all modifiers applied. * @return The finished attribute with all modifiers applied.
*/ */

View File

@ -64,7 +64,7 @@ public final class BlockUtils {
if (toolType.equals("shears")) return isShearsEffective ? 5.0 : 15.0; if (toolType.equals("shears")) return isShearsEffective ? 5.0 : 15.0;
if (toolType.equals("")) return 1.0; if (toolType.equals("")) return 1.0;
return switch (toolTier) { return switch (toolTier) {
// https://minecraft.gamepedia.com/Breaking#Speed // https://minecraft.wiki/w/Breaking#Speed
case "wooden" -> 2.0; case "wooden" -> 2.0;
case "stone" -> 4.0; case "stone" -> 4.0;
case "iron" -> 6.0; case "iron" -> 6.0;
@ -100,7 +100,7 @@ public final class BlockUtils {
return true; return true;
} }
// https://minecraft.gamepedia.com/Breaking // https://minecraft.wiki/w/Breaking
private static double calculateBreakTime(double blockHardness, String toolTier, boolean canHarvestWithHand, boolean correctTool, boolean canTierMineBlock, private static double calculateBreakTime(double blockHardness, String toolTier, boolean canHarvestWithHand, boolean correctTool, boolean canTierMineBlock,
String toolType, boolean isShearsEffective, int toolEfficiencyLevel, int hasteLevel, int miningFatigueLevel, String toolType, boolean isShearsEffective, int toolEfficiencyLevel, int hasteLevel, int miningFatigueLevel,
boolean insideOfWaterWithoutAquaAffinity, boolean onGround) { boolean insideOfWaterWithoutAquaAffinity, boolean onGround) {

View File

@ -25,6 +25,8 @@
package org.geysermc.geyser.util; package org.geysermc.geyser.util;
import com.fasterxml.jackson.annotation.JsonSetter;
import com.fasterxml.jackson.annotation.Nulls;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import org.geysermc.geyser.GeyserBootstrap; import org.geysermc.geyser.GeyserBootstrap;
@ -53,7 +55,8 @@ public class FileUtils {
* @throws IOException if the config could not be loaded * @throws IOException if the config could not be loaded
*/ */
public static <T> T loadConfig(File src, Class<T> valueType) throws IOException { public static <T> T loadConfig(File src, Class<T> valueType) throws IOException {
ObjectMapper objectMapper = new ObjectMapper(new YAMLFactory()); ObjectMapper objectMapper = new ObjectMapper(new YAMLFactory())
.setDefaultSetterInfo(JsonSetter.Value.forValueNulls(Nulls.AS_EMPTY));
return objectMapper.readValue(src, valueType); return objectMapper.readValue(src, valueType);
} }

View File

@ -260,7 +260,7 @@ public class InventoryUtils {
// If this is the item we're looking for // If this is the item we're looking for
if (geyserItem.getJavaId() == itemStack.getId() && Objects.equals(geyserItem.getNbt(), itemStack.getNbt())) { if (geyserItem.getJavaId() == itemStack.getId() && Objects.equals(geyserItem.getNbt(), itemStack.getNbt())) {
ServerboundPickItemPacket packetToSend = new ServerboundPickItemPacket(i); // https://wiki.vg/Protocol#Pick_Item ServerboundPickItemPacket packetToSend = new ServerboundPickItemPacket(i); // https://wiki.vg/Protocol#Pick_Item
session.sendDownstreamPacket(packetToSend); session.sendDownstreamGamePacket(packetToSend);
return; return;
} }
} }
@ -274,7 +274,7 @@ public class InventoryUtils {
if ((slot - 36) != inventory.getHeldItemSlot()) { if ((slot - 36) != inventory.getHeldItemSlot()) {
setHotbarItem(session, slot); setHotbarItem(session, slot);
} }
session.sendDownstreamPacket(actionPacket); session.sendDownstreamGamePacket(actionPacket);
} }
} }
@ -325,7 +325,7 @@ public class InventoryUtils {
} }
ServerboundPickItemPacket packetToSend = new ServerboundPickItemPacket(i); // https://wiki.vg/Protocol#Pick_Item ServerboundPickItemPacket packetToSend = new ServerboundPickItemPacket(i); // https://wiki.vg/Protocol#Pick_Item
session.sendDownstreamPacket(packetToSend); session.sendDownstreamGamePacket(packetToSend);
return; return;
} }
@ -340,7 +340,7 @@ public class InventoryUtils {
if ((slot - 36) != inventory.getHeldItemSlot()) { if ((slot - 36) != inventory.getHeldItemSlot()) {
setHotbarItem(session, slot); setHotbarItem(session, slot);
} }
session.sendDownstreamPacket(actionPacket); session.sendDownstreamGamePacket(actionPacket);
} else { } else {
session.getGeyser().getLogger().debug("Cannot find item for block " + itemName); session.getGeyser().getLogger().debug("Cannot find item for block " + itemName);
} }

View File

@ -34,14 +34,12 @@ import org.cloudburstmc.protocol.bedrock.packet.ServerToClientHandshakePacket;
import org.cloudburstmc.protocol.bedrock.util.ChainValidationResult; import org.cloudburstmc.protocol.bedrock.util.ChainValidationResult;
import org.cloudburstmc.protocol.bedrock.util.ChainValidationResult.IdentityData; import org.cloudburstmc.protocol.bedrock.util.ChainValidationResult.IdentityData;
import org.cloudburstmc.protocol.bedrock.util.EncryptionUtils; import org.cloudburstmc.protocol.bedrock.util.EncryptionUtils;
import org.geysermc.cumulus.form.CustomForm;
import org.geysermc.cumulus.form.ModalForm; import org.geysermc.cumulus.form.ModalForm;
import org.geysermc.cumulus.form.SimpleForm; import org.geysermc.cumulus.form.SimpleForm;
import org.geysermc.cumulus.response.SimpleFormResponse; import org.geysermc.cumulus.response.SimpleFormResponse;
import org.geysermc.cumulus.response.result.FormResponseResult; import org.geysermc.cumulus.response.result.FormResponseResult;
import org.geysermc.cumulus.response.result.ValidFormResponseResult; import org.geysermc.cumulus.response.result.ValidFormResponseResult;
import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.configuration.GeyserConfiguration;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.session.auth.AuthData; import org.geysermc.geyser.session.auth.AuthData;
import org.geysermc.geyser.session.auth.BedrockClientData; import org.geysermc.geyser.session.auth.BedrockClientData;
@ -137,26 +135,16 @@ public class LoginEncryptionUtils {
// Set DoDaylightCycle to false so the time doesn't accelerate while we're here // Set DoDaylightCycle to false so the time doesn't accelerate while we're here
session.setDaylightCycle(false); session.setDaylightCycle(false);
GeyserConfiguration config = session.getGeyser().getConfig();
boolean isPasswordAuthEnabled = config.getRemote().isPasswordAuthentication();
session.sendForm( session.sendForm(
SimpleForm.builder() SimpleForm.builder()
.translator(GeyserLocale::getPlayerLocaleString, session.locale()) .translator(GeyserLocale::getPlayerLocaleString, session.locale())
.title("geyser.auth.login.form.notice.title") .title("geyser.auth.login.form.notice.title")
.content("geyser.auth.login.form.notice.desc") .content("geyser.auth.login.form.notice.desc")
.optionalButton("geyser.auth.login.form.notice.btn_login.mojang", isPasswordAuthEnabled)
.button("geyser.auth.login.form.notice.btn_login.microsoft") .button("geyser.auth.login.form.notice.btn_login.microsoft")
.button("geyser.auth.login.form.notice.btn_disconnect") .button("geyser.auth.login.form.notice.btn_disconnect")
.closedOrInvalidResultHandler(() -> buildAndShowLoginWindow(session)) .closedOrInvalidResultHandler(() -> buildAndShowLoginWindow(session))
.validResultHandler((response) -> { .validResultHandler((response) -> {
if (response.clickedButtonId() == 0) { if (response.clickedButtonId() == 0) {
session.setMicrosoftAccount(false);
buildAndShowLoginDetailsWindow(session);
return;
}
if (response.clickedButtonId() == 1) {
session.authenticateWithMicrosoftCode(); session.authenticateWithMicrosoftCode();
return; return;
} }
@ -212,19 +200,6 @@ public class LoginEncryptionUtils {
}; };
} }
public static void buildAndShowLoginDetailsWindow(GeyserSession session) {
session.sendForm(
CustomForm.builder()
.translator(GeyserLocale::getPlayerLocaleString, session.locale())
.title("geyser.auth.login.form.details.title")
.label("geyser.auth.login.form.details.desc")
.input("geyser.auth.login.form.details.email", "account@geysermc.org", "")
.input("geyser.auth.login.form.details.pass", "123456", "")
.invalidResultHandler(() -> buildAndShowLoginDetailsWindow(session))
.closedResultHandler(() -> buildAndShowLoginWindow(session))
.validResultHandler((response) -> session.authenticate(response.next(), response.next())));
}
/** /**
* Shows the code that a user must input into their browser * Shows the code that a user must input into their browser
*/ */

View File

@ -25,7 +25,7 @@
package org.geysermc.geyser.util; package org.geysermc.geyser.util;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundCustomPayloadPacket; import com.github.steveice10.mc.protocol.packet.common.serverbound.ServerboundCustomPayloadPacket;
import com.google.common.base.Charsets; import com.google.common.base.Charsets;
import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;

View File

@ -145,10 +145,9 @@
{ {
"origin": [ -0.1, 0.0, -2.0 ], "origin": [ -0.1, 0.0, -2.0 ],
"size": [ 4, 12, 4 ], "size": [ 4, 12, 4 ],
"uv": [ 0, 16 ] "uv": [ 16, 48 ]
} }
], ]
"mirror": true
}, },
{ {
@ -219,4 +218,4 @@
} }
} }
] ]
} }

View File

@ -145,10 +145,9 @@
{ {
"origin": [ -0.1, 0.0, -2.0 ], "origin": [ -0.1, 0.0, -2.0 ],
"size": [ 4, 12, 4 ], "size": [ 4, 12, 4 ],
"uv": [ 0, 16 ] "uv": [ 16, 48 ]
} }
], ]
"mirror": true
}, },
{ {
@ -219,4 +218,4 @@
} }
} }
] ]
} }

View File

@ -5,6 +5,10 @@
# #
# GitHub: https://github.com/GeyserMC/Geyser # GitHub: https://github.com/GeyserMC/Geyser
# Discord: https://discord.gg/geysermc # Discord: https://discord.gg/geysermc
# Wiki: https://wiki.geysermc.org/
#
# NOTICE: See https://wiki.geysermc.org/geyser/setup/ for the setup guide. Many video tutorials are outdated.
# In most cases, especially with server hosting providers, further hosting-specific configuration is required.
# -------------------------------- # --------------------------------
bedrock: bedrock:

Some files were not shown because too many files have changed in this diff Show More