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:
pull_request:
paths-ignore:
- '.github/ISSUE_TEMPLATE/*.yml'
- '.idea/copyright/*.xml'
- '.gitignore'
- 'CONTRIBUTING.md'
- 'LICENSE'
- 'Jenkinsfile '
- 'README.md'
- 'licenseheader.txt'
jobs:
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!
### 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
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 {
/**
* Gets an extension with the given name.
* Gets an extension by the given ID.
*
* @param name the name of the extension
* @return an extension with the given name
* @param id the ID of the extension
* @return an extension with the given ID
*/
@Nullable
public abstract Extension extension(@NonNull String name);
public abstract Extension extension(@NonNull String id);
/**
* Enables the given {@link Extension}.

View File

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

View File

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

View File

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

View File

@ -199,7 +199,7 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
commandMap.register(extension.description().id(), "geyserext", pluginCommand);
} 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);
// 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()) {
// geyserLogger.severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.not_installed") + " "
// + 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.Nullable;
import org.geysermc.api.Geyser;
import org.geysermc.geyser.api.util.PlatformType;
import org.geysermc.cumulus.form.Form;
import org.geysermc.cumulus.form.util.FormBuilder;
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.BedrockListener;
import org.geysermc.geyser.api.network.RemoteServer;
import org.geysermc.geyser.api.util.PlatformType;
import org.geysermc.geyser.command.GeyserCommandManager;
import org.geysermc.geyser.configuration.GeyserConfiguration;
import org.geysermc.geyser.entity.EntityDefinitions;
@ -485,12 +485,6 @@ public class GeyserImpl implements GeyserApi {
}
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
savedRefreshTokens = new ConcurrentHashMap<>();

View File

@ -28,6 +28,7 @@ package org.geysermc.geyser;
import javax.swing.*;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
import java.util.Locale;
import java.util.Scanner;
@ -60,7 +61,7 @@ public class GeyserMain {
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 = "";
while (help.hasNext()) {
line = help.next();

View File

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

View File

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

View File

@ -44,7 +44,6 @@ import java.io.IOException;
import java.nio.file.Path;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;
@ -79,8 +78,6 @@ public abstract class GeyserJacksonConfiguration implements GeyserConfiguration
public abstract Path getFloodgateKeyPath();
private Map<String, UserAuthenticationInfo> userAuths;
@JsonProperty("command-suggestions")
private boolean commandSuggestions = true;
@ -287,10 +284,6 @@ public abstract class GeyserJacksonConfiguration implements GeyserConfiguration
return false;
}
@Getter
@JsonProperty("allow-password-authentication")
private boolean passwordAuthentication = true;
@Getter
@JsonProperty("use-proxy-protocol")
private boolean useProxyProtocol = false;
@ -300,19 +293,6 @@ public abstract class GeyserJacksonConfiguration implements GeyserConfiguration
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
@JsonIgnoreProperties(ignoreUnknown = true)
public static class MetricsInfo implements IMetricsInfo {

View File

@ -68,7 +68,7 @@ public class InteractionEntity extends Entity {
animatePacket.setAction(AnimatePacket.Action.SWING_ARM);
session.sendUpstreamPacket(animatePacket);
session.sendDownstreamPacket(new ServerboundSwingPacket(hand));
session.sendDownstreamGamePacket(new ServerboundSwingPacket(hand));
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.Object2ObjectOpenHashMap;
import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.api.extension.Extension;
import org.geysermc.geyser.api.extension.ExtensionDescription;
import org.geysermc.geyser.api.extension.exception.InvalidExtensionException;
@ -39,14 +40,17 @@ import java.nio.file.Path;
public class GeyserExtensionClassLoader extends URLClassLoader {
private final GeyserExtensionLoader loader;
private final ExtensionDescription description;
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);
this.loader = loader;
this.description = description;
}
public Extension load(ExtensionDescription description) throws InvalidExtensionException {
public Extension load() throws InvalidExtensionException {
try {
Class<?> jarClass;
try {
@ -76,22 +80,32 @@ public class GeyserExtensionClassLoader extends URLClassLoader {
}
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);
if (result == null) {
result = super.findClass(name);
if (result == null && checkGlobal) {
result = this.loader.classByName(name);
// Try to find class in current extension
try {
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 class is found, cache it
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;
}

View File

@ -43,9 +43,9 @@ import java.io.Reader;
import java.nio.file.*;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import java.util.stream.Stream;
@RequiredArgsConstructor
public class GeyserExtensionLoader extends ExtensionLoader {
@ -66,26 +66,38 @@ public class GeyserExtensionLoader extends ExtensionLoader {
}
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)) {
throw new InvalidExtensionException("The folder " + dataFolder + " is not a directory and is the data folder for the extension " + description.name() + "!");
}
final GeyserExtensionClassLoader loader;
try {
loader = new GeyserExtensionClassLoader(this, getClass().getClassLoader(), path);
loader = new GeyserExtensionClassLoader(this, getClass().getClassLoader(), path, description);
} catch (Throwable 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));
}
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);
}
@ -136,46 +148,46 @@ public class GeyserExtensionLoader extends ExtensionLoader {
Map<String, GeyserExtensionContainer> loadedExtensions = new LinkedHashMap<>();
Pattern[] extensionFilters = this.extensionFilters();
try (Stream<Path> entries = Files.walk(extensionsDirectory)) {
entries.forEach(path -> {
if (Files.isDirectory(path)) {
List<Path> extensionPaths = Files.walk(extensionsDirectory).toList();
extensionPaths.forEach(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;
}
for (Pattern filter : extensionFilters) {
if (!filter.matcher(path.getFileName().toString()).matches()) {
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;
}
try {
GeyserExtensionDescription description = this.extensionDescription(path);
String name = description.name();
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);
// 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(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()) {
this.extensionContainers.put(container.extension(), container);

View File

@ -52,8 +52,8 @@ public class GeyserExtensionManager extends ExtensionManager {
}
@Override
public Extension extension(@NonNull String name) {
return this.extensions.get(name);
public Extension extension(@NonNull String id) {
return this.extensions.get(id);
}
@Override
@ -83,7 +83,7 @@ public class GeyserExtensionManager extends ExtensionManager {
if (!extension.isEnabled()) {
extension.setEnabled(true);
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);
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
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;
// 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);
session.sendDownstreamPacket(renameItemPacket);
session.sendDownstreamGamePacket(renameItemPacket);
} else {
// Restore formatting for item since we're not renaming
correctRename = MessageTranslator.convertMessageLenient(originalName);
// Java Edition sends the original custom name when not renaming,
// if there isn't a custom name an empty string is sent
ServerboundRenameItemPacket renameItemPacket = new ServerboundRenameItemPacket(plainOriginalName);
session.sendDownstreamPacket(renameItemPacket);
session.sendDownstreamGamePacket(renameItemPacket);
}
useJavaLevelCost = false;

View File

@ -152,7 +152,7 @@ public final class ClickPlan {
changedItems
);
session.sendDownstreamPacket(clickPacket);
session.sendDownstreamGamePacket(clickPacket);
}
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.
* https://minecraft.gamepedia.com/Arrow#Item_Data
* https://minecraft.wiki/w/Arrow#Data_values
*/
@Getter
public enum TippedArrowPotion {

View File

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

View File

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

View File

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

View File

@ -46,7 +46,9 @@ public final class GameProtocol {
* Default Bedrock codec that should act as a fallback. Should represent the latest available
* release of the game that Geyser supports.
*/
public static final BedrockCodec DEFAULT_BEDROCK_CODEC = 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
@ -66,7 +68,9 @@ public final class GameProtocol {
SUPPORTED_BEDROCK_CODECS.add(Bedrock_v594.CODEC.toBuilder()
.minecraftVersion("1.20.10/1.20.15")
.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;
}
public DefaultEventLoopGroup getEventLoopGroup() {
return eventLoopGroup;
}
@Override
public void initSession(@Nonnull BedrockServerSession bedrockServerSession) {
try {

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.ResourcePack;
import org.geysermc.geyser.api.pack.ResourcePackManifest;
import org.geysermc.geyser.configuration.GeyserConfiguration;
import org.geysermc.geyser.event.type.SessionLoadResourcePacksEventImpl;
import org.geysermc.geyser.pack.GeyserResourcePack;
import org.geysermc.geyser.registry.BlockRegistries;
@ -257,21 +256,9 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
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());
if (task != null) {
if (task.getAuthentication().isDone() && session.onMicrosoftLoginComplete(task)) {
return true;
}
return task.getAuthentication().isDone() && session.onMicrosoftLoginComplete(task);
}
return false;

View File

@ -39,6 +39,7 @@ import io.netty.channel.kqueue.KQueueEventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.DatagramChannel;
import io.netty.channel.socket.nio.NioDatagramChannel;
import io.netty.util.concurrent.Future;
import lombok.Getter;
import net.jodah.expiringmap.ExpirationPolicy;
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.ping.GeyserPingInfo;
import org.geysermc.geyser.ping.IGeyserPingPassthrough;
import org.geysermc.geyser.skin.SkinProvider;
import org.geysermc.geyser.text.GeyserLocale;
import org.geysermc.geyser.translator.text.MessageTranslator;
@ -83,14 +85,21 @@ public final class GeyserServer {
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 EventLoopGroup group;
private EventLoopGroup group;
private final ServerBootstrap bootstrap;
private EventLoopGroup playerGroup;
@Getter
private final ExpiringMap<InetSocketAddress, InetSocketAddress> proxiedAddresses;
private ChannelFuture future;
private ChannelFuture bootstrapFuture;
public GeyserServer(GeyserImpl geyser, int threadCount) {
this.geyser = geyser;
@ -109,7 +118,7 @@ public final class GeyserServer {
public CompletableFuture<Void> bind(InetSocketAddress address) {
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) {
future.completeExceptionally(bindResult.cause());
return;
@ -117,7 +126,7 @@ public final class GeyserServer {
future.complete(null);
});
Channel channel = this.future.channel();
Channel channel = this.bootstrapFuture.channel();
// Add our ping handler
channel.pipeline()
@ -132,8 +141,19 @@ public final class GeyserServer {
}
public void shutdown() {
this.group.shutdownGracefully();
this.future.channel().closeFuture().syncUninterruptibly();
try {
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) {
@ -149,11 +169,13 @@ public final class GeyserServer {
}
}
GeyserServerInitializer serverInitializer = new GeyserServerInitializer(this.geyser);
playerGroup = serverInitializer.getEventLoopGroup();
return new ServerBootstrap()
.channelFactory(RakChannelFactory.server(TRANSPORT.datagramChannel()))
.group(group)
.option(RakChannelOption.RAK_HANDLE_PING, true)
.childHandler(new GeyserServerInitializer(this.geyser));
.childHandler(serverInitializer);
}
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.
.ipv4Port(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) {
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.ClientboundTabListPacket;
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.ClientboundChunkBatchStartPacket;
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.ClientboundLightUpdatePacket;
import io.netty.channel.EventLoop;
import org.cloudburstmc.protocol.bedrock.packet.RequestPermissionsPacket;
import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.registry.loader.RegistryLoaders;
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<>());
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(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() {

View File

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

View File

@ -26,10 +26,7 @@
package org.geysermc.geyser.session;
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.service.AuthenticationService;
import com.github.steveice10.mc.auth.service.MojangAuthenticationService;
import com.github.steveice10.mc.auth.service.MsaAuthenticationService;
import com.github.steveice10.mc.protocol.MinecraftConstants;
import com.github.steveice10.mc.protocol.MinecraftProtocol;
@ -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.statistic.CustomStatistic;
import com.github.steveice10.mc.protocol.data.game.statistic.Statistic;
import com.github.steveice10.mc.protocol.packet.common.serverbound.ServerboundClientInformationPacket;
import com.github.steveice10.mc.protocol.packet.handshake.serverbound.ClientIntentionPacket;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundChatCommandPacket;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundChatPacket;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundClientInformationPacket;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundMovePlayerPosPacket;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundPlayerAbilitiesPacket;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundPlayerActionPacket;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundUseItemPacket;
import com.github.steveice10.mc.protocol.packet.login.serverbound.ServerboundCustomQueryPacket;
import com.github.steveice10.mc.protocol.packet.login.serverbound.ServerboundCustomQueryAnswerPacket;
import com.github.steveice10.packetlib.BuiltinFlags;
import com.github.steveice10.packetlib.Session;
import com.github.steveice10.packetlib.event.session.ConnectedEvent;
@ -253,10 +250,6 @@ public class GeyserSession extends FloodgateConnection implements GeyserConnecti
@Setter
private RemoteServer remoteServer;
@Deprecated
@Setter
private boolean microsoftAccount;
private final SessionPlayerEntity playerEntity;
private final AdvancementsCache advancementsCache;
@ -355,7 +348,7 @@ public class GeyserSession extends FloodgateConnection implements GeyserConnecti
private Vector2i lastChunkPosition = null;
@Setter
private int clientRenderDistance = -1;
private int serverRenderDistance;
private int serverRenderDistance = -1;
// Exposed for GeyserConnect usage
protected boolean sentSpawnPacket;
@ -764,76 +757,20 @@ public class GeyserSession extends FloodgateConnection implements GeyserConnecti
}
public void authenticate(String username) {
authenticate(username, "");
}
public void authenticate(String username, String password) {
if (loggedIn) {
geyser.getLogger().severe(GeyserLocale.getLocaleStringLog("geyser.auth.already_loggedin", username));
return;
}
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
CompletableFuture.supplyAsync(() -> {
try {
if (password != null && !password.isEmpty()) {
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();
}
});
try {
connectDownstream();
} catch (Throwable t) {
t.printStackTrace();
}
}
public void authenticateWithRefreshToken(String refreshToken) {
@ -1240,7 +1177,7 @@ public class GeyserSession extends FloodgateConnection implements GeyserConnecti
if (position != null) {
ServerboundMovePlayerPosPacket packet = new ServerboundMovePlayerPosPacket(playerEntity.isOnGround(),
position.getX(), position.getY(), position.getZ());
sendDownstreamPacket(packet);
sendDownstreamGamePacket(packet);
}
lastMovementTimestamp = System.currentTimeMillis();
}
@ -1422,7 +1359,7 @@ public class GeyserSession extends FloodgateConnection implements GeyserConnecti
return false;
}
sendDownstreamPacket(useItemPacket);
sendDownstreamGamePacket(useItemPacket);
playerEntity.setFlag(EntityFlag.BLOCKING, true);
// Metadata should be updated later
return true;
@ -1456,7 +1393,7 @@ public class GeyserSession extends FloodgateConnection implements GeyserConnecti
if (playerEntity.getFlag(EntityFlag.BLOCKING)) {
ServerboundPlayerActionPacket releaseItemPacket = new ServerboundPlayerActionPacket(PlayerAction.RELEASE_USE_ITEM,
Vector3i.ZERO, Direction.DOWN, 0);
sendDownstreamPacket(releaseItemPacket);
sendDownstreamGamePacket(releaseItemPacket);
playerEntity.setFlag(EntityFlag.BLOCKING, false);
return true;
}
@ -1466,7 +1403,7 @@ public class GeyserSession extends FloodgateConnection implements GeyserConnecti
public void requestOffhandSwap() {
ServerboundPlayerActionPacket swapHandsPacket = new ServerboundPlayerActionPacket(PlayerAction.SWAP_HANDS, Vector3i.ZERO,
Direction.DOWN, 0);
sendDownstreamPacket(swapHandsPacket);
sendDownstreamGamePacket(swapHandsPacket);
}
@Override
@ -1501,14 +1438,14 @@ public class GeyserSession extends FloodgateConnection implements GeyserConnecti
* Sends a chat message to the Java server.
*/
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.
*/
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) {
@ -1660,6 +1597,39 @@ public class GeyserSession extends FloodgateConnection implements GeyserConnecti
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.
*
@ -1687,7 +1657,8 @@ public class GeyserSession extends FloodgateConnection implements GeyserConnecti
}
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);
} else {
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
flying = true;
ServerboundPlayerAbilitiesPacket abilitiesPacket = new ServerboundPlayerAbilitiesPacket(true);
sendDownstreamPacket(abilitiesPacket);
sendDownstreamGamePacket(abilitiesPacket);
}
abilities.add(Ability.FLYING);
}
@ -1846,8 +1817,11 @@ public class GeyserSession extends FloodgateConnection implements GeyserConnecti
if (clientRenderDistance != -1) {
// The client has sent a render distance
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

View File

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

View File

@ -25,9 +25,10 @@
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.IntLists;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.geysermc.geyser.GeyserLogger;
import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.item.type.Item;
@ -112,7 +113,7 @@ public class TagCache {
}
}
private IntList load(int[] tags) {
private IntList load(int @Nullable[] tags) {
if (tags == null) {
return IntLists.EMPTY_LIST;
}

View File

@ -58,7 +58,7 @@ import java.util.function.Predicate;
public class SkinProvider {
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 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);
}
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) {
// Schedule Daily Image Expiry if we are caching them
if (geyser.getConfig().getCacheImages() > 0) {
@ -302,7 +316,7 @@ public class SkinProvider {
GeyserImpl.getInstance().getLogger().debug("Took " + (System.currentTimeMillis() - time) + "ms for " + playerId);
return skinAndCape;
}, EXECUTOR_SERVICE);
}, getExecutorService());
}
static CompletableFuture<Skin> requestSkin(UUID playerId, String textureUrl, boolean newThread) {
@ -320,7 +334,7 @@ public class SkinProvider {
CompletableFuture<Skin> future;
if (newThread) {
future = CompletableFuture.supplyAsync(() -> supplySkin(playerId, textureUrl), EXECUTOR_SERVICE)
future = CompletableFuture.supplyAsync(() -> supplySkin(playerId, textureUrl), getExecutorService())
.whenCompleteAsync((skin, throwable) -> {
skin.updated = true;
CACHED_JAVA_SKINS.put(textureUrl, skin);
@ -349,7 +363,7 @@ public class SkinProvider {
CompletableFuture<Cape> future;
if (newThread) {
future = CompletableFuture.supplyAsync(() -> supplyCape(capeUrl, provider), EXECUTOR_SERVICE)
future = CompletableFuture.supplyAsync(() -> supplyCape(capeUrl, provider), getExecutorService())
.whenCompleteAsync((cape, throwable) -> {
CACHED_JAVA_CAPES.put(capeUrl, cape);
requestedCapes.remove(capeUrl);
@ -388,7 +402,7 @@ public class SkinProvider {
CompletableFuture<Skin> future;
if (newThread) {
future = CompletableFuture.supplyAsync(() -> supplyEars(skin, earsUrl), EXECUTOR_SERVICE)
future = CompletableFuture.supplyAsync(() -> supplyEars(skin, earsUrl), getExecutorService())
.whenCompleteAsync((outSkin, throwable) -> { });
} else {
Skin ears = supplyEars(skin, earsUrl); // blocking
@ -620,7 +634,7 @@ public class SkinProvider {
}
return null;
}
}, EXECUTOR_SERVICE);
}, getExecutorService());
}
/**
@ -646,7 +660,7 @@ public class SkinProvider {
}
return null;
}
}, EXECUTOR_SERVICE).thenCompose(uuid -> {
}, getExecutorService()).thenCompose(uuid -> {
if (uuid == null) {
return CompletableFuture.completedFuture(null);
}

View File

@ -76,7 +76,7 @@ public class MinecraftLocale {
public static void downloadAndLoadLocale(String locale) {
locale = locale.toLowerCase(Locale.ROOT);
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";
}

View File

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

View File

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

View File

@ -102,7 +102,7 @@ public class LecternInventoryTranslator extends BaseInventoryTranslator {
if (session.isDroppingLecternBook()) {
// We have to enter the inventory GUI to eject the book
ServerboundContainerButtonClickPacket packet = new ServerboundContainerButtonClickPacket(inventory.getJavaId(), 3);
session.sendDownstreamPacket(packet);
session.sendDownstreamGamePacket(packet);
session.setDroppingLecternBook(false);
InventoryUtils.closeInventory(session, inventory.getJavaId(), false);
} else if (lecternContainer.getBlockEntityTag() == null) {
@ -153,7 +153,7 @@ public class LecternInventoryTranslator extends BaseInventoryTranslator {
session.getLecternCache().add(position);
// Close the window - we will reopen it once the client has this data synced
ServerboundContainerClosePacket closeWindowPacket = new ServerboundContainerClosePacket(lecternContainer.getJavaId());
session.sendDownstreamPacket(closeWindowPacket);
session.sendDownstreamGamePacket(closeWindowPacket);
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
// 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);
session.sendDownstreamPacket(packet);
session.sendDownstreamGamePacket(packet);
GeyserItemStack inputCopy = inventory.getItem(0).copy(1);
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) {
ServerboundSelectTradePacket packet = new ServerboundSelectTradePacket(tradeChoice);
session.sendDownstreamPacket(packet);
session.sendDownstreamGamePacket(packet);
if (session.isEmulatePost1_13Logic()) {
// 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()));
session.sendDownstreamPacket(creativeDropPacket);
session.sendDownstreamGamePacket(creativeDropPacket);
sourceItem.sub(dropAction.getCount());
}
@ -494,7 +494,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator {
dropStack = new ItemStack(javaCreativeItem.getId(), dropAction.getCount(), javaCreativeItem.getNbt());
}
ServerboundSetCreativeModeSlotPacket creativeDropPacket = new ServerboundSetCreativeModeSlotPacket(-1, dropStack);
session.sendDownstreamPacket(creativeDropPacket);
session.sendDownstreamGamePacket(creativeDropPacket);
break;
}
default:
@ -515,7 +515,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator {
ItemStack itemStack = item.isEmpty() ? new ItemStack(-1, 0, null) : item.getItemStack();
ServerboundSetCreativeModeSlotPacket creativePacket = new ServerboundSetCreativeModeSlotPacket(slot, itemStack);
session.sendDownstreamPacket(creativePacket);
session.sendDownstreamGamePacket(creativePacket);
}
private static boolean isCraftingGrid(ItemStackRequestSlotData slotInfoData) {

View File

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

View File

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

View File

@ -64,7 +64,7 @@ public class BedrockAnimateTranslator extends PacketTranslator<AnimatePacket> {
// and Bedrock 1.19.51.
// Note for the future: we should probably largely ignore this packet and instead replicate
// all actions on our end, and send swings where needed.
session.sendDownstreamPacket(new ServerboundSwingPacket(Hand.MAIN_HAND));
session.sendDownstreamGamePacket(new ServerboundSwingPacket(Hand.MAIN_HAND));
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
session.setSteeringLeft(packet.getRowingTime() > 0.0);
ServerboundPaddleBoatPacket steerLeftPacket = new ServerboundPaddleBoatPacket(session.isSteeringLeft(), session.isSteeringRight());
session.sendDownstreamPacket(steerLeftPacket);
session.sendDownstreamGamePacket(steerLeftPacket);
}
case ROW_RIGHT -> {
session.setSteeringRight(packet.getRowingTime() > 0.0);
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();
Vector3i pos = Vector3i.from(tag.getInt("x"), tag.getInt("y"), tag.getInt("z"));
ServerboundSignUpdatePacket signUpdatePacket = new ServerboundSignUpdatePacket(pos, lines, session.getWorldCache().isEditingSignOnFront());
session.sendDownstreamPacket(signUpdatePacket);
session.sendDownstreamGamePacket(signUpdatePacket);
} else if (id.equals("JigsawBlock")) {
// Client has just sent a jigsaw block update
@ -120,7 +120,7 @@ public class BedrockBlockEntityDataTranslator extends PacketTranslator<BlockEnti
String joint = tag.getString("joint");
ServerboundSetJigsawBlockPacket jigsawPacket = new ServerboundSetJigsawBlockPacket(pos, name, target, pool,
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
ServerboundSetCommandBlockPacket commandBlockPacket = new ServerboundSetCommandBlockPacket(
packet.getBlockPosition(), command, mode, outputTracked, isConditional, automatic);
session.sendDownstreamPacket(commandBlockPacket);
session.sendDownstreamGamePacket(commandBlockPacket);
} else {
ServerboundSetCommandMinecartPacket commandMinecartPacket = new ServerboundSetCommandMinecartPacket(
session.getEntityCache().getEntityByGeyserId(packet.getMinecartRuntimeEntityId()).getEntityId(),
command, outputTracked
);
session.sendDownstreamPacket(commandMinecartPacket);
session.sendDownstreamGamePacket(commandMinecartPacket);
}
}
}

View File

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

View File

@ -137,7 +137,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
ServerboundContainerClickPacket dropPacket = new ServerboundContainerClickPacket(
inventory.getJavaId(), inventory.getStateId(), hotbarSlot, clickType.actionType, clickType.action,
inventory.getCursor().getItemStack(), changedItem);
session.sendDownstreamPacket(dropPacket);
session.sendDownstreamGamePacket(dropPacket);
return;
}
if (session.getPlayerInventory().getItemInHand().isEmpty()) {
@ -150,7 +150,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
Direction.DOWN,
0
);
session.sendDownstreamPacket(dropPacket);
session.sendDownstreamGamePacket(dropPacket);
if (dropAll) {
session.getPlayerInventory().setItemInHand(GeyserItemStack.EMPTY);
@ -309,7 +309,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
packet.getClickPosition().getX(), packet.getClickPosition().getY(), packet.getClickPosition().getZ(),
false,
session.getWorldCache().nextPredictionSequence());
session.sendDownstreamPacket(blockPacket);
session.sendDownstreamGamePacket(blockPacket);
Item item = session.getPlayerInventory().getItemInHand().asItem();
if (packet.getItemInHand() != null) {
@ -384,7 +384,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
}
ServerboundUseItemPacket useItemPacket = new ServerboundUseItemPacket(Hand.MAIN_HAND, session.getWorldCache().nextPredictionSequence());
session.sendDownstreamPacket(useItemPacket);
session.sendDownstreamGamePacket(useItemPacket);
List<LegacySetItemSlotData> legacySlots = packet.getLegacySlots();
if (packet.getActions().size() == 1 && legacySlots.size() > 0) {
@ -453,13 +453,13 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
if (itemFrameEntity != null) {
ServerboundInteractPacket attackPacket = new ServerboundInteractPacket(itemFrameEntity.getEntityId(),
InteractAction.ATTACK, session.isSneaking());
session.sendDownstreamPacket(attackPacket);
session.sendDownstreamGamePacket(attackPacket);
break;
}
PlayerAction action = session.getGameMode() == GameMode.CREATIVE ? PlayerAction.START_DIGGING : PlayerAction.FINISH_DIGGING;
ServerboundPlayerActionPacket breakPacket = new ServerboundPlayerActionPacket(action, packet.getBlockPosition(), Direction.VALUES[packet.getBlockFace()], sequence);
session.sendDownstreamPacket(breakPacket);
session.sendDownstreamGamePacket(breakPacket);
}
}
break;
@ -468,7 +468,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
// Followed to the Minecraft Protocol specification outlined at wiki.vg
ServerboundPlayerActionPacket releaseItemPacket = new ServerboundPlayerActionPacket(PlayerAction.RELEASE_USE_ITEM, Vector3i.ZERO,
Direction.DOWN, 0);
session.sendDownstreamPacket(releaseItemPacket);
session.sendDownstreamGamePacket(releaseItemPacket);
}
break;
case ITEM_USE_ON_ENTITY:
@ -490,7 +490,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
}
ServerboundInteractPacket attackPacket = new ServerboundInteractPacket(entityId,
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
CooldownUtils.sendCooldown(session);
@ -510,7 +510,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
Vector3f clickPosition = packet.getClickPosition().sub(entityPosition);
boolean isSpectator = session.getGameMode() == GameMode.SPECTATOR;
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(),
hand, session.isSneaking()));
@ -522,7 +522,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
}
if (!result.consumesAction()) {
session.sendDownstreamPacket(new ServerboundInteractPacket(entity.getEntityId(),
session.sendDownstreamGamePacket(new ServerboundInteractPacket(entity.getEntityId(),
InteractAction.INTERACT, hand, session.isSneaking()));
if (!isSpectator) {
result = entity.interact(hand);
@ -532,7 +532,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
if (result.consumesAction()) {
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.
session.sendDownstreamPacket(new ServerboundSwingPacket(hand));
session.sendDownstreamGamePacket(new ServerboundSwingPacket(hand));
// Note here to look into sending the animation packet back to Bedrock
}
return;
@ -629,7 +629,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
lookAt(session, target);
ServerboundUseItemPacket itemPacket = new ServerboundUseItemPacket(Hand.MAIN_HAND, session.getWorldCache().nextPredictionSequence());
session.sendDownstreamPacket(itemPacket);
session.sendDownstreamGamePacket(itemPacket);
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());
// This matches Java edition behavior
ServerboundMovePlayerPosRotPacket movementPacket = new ServerboundMovePlayerPosRotPacket(entity.isOnGround(), playerPosition.getX(), playerPosition.getY(), playerPosition.getZ(), yaw, pitch);
session.sendDownstreamPacket(movementPacket);
session.sendDownstreamGamePacket(movementPacket);
if (session.getLookBackScheduledFuture() != null) {
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
return;
}
session.sendDownstreamPacket(returnPacket);
session.sendDownstreamGamePacket(returnPacket);
}, 150, TimeUnit.MILLISECONDS));
}
}

View File

@ -49,7 +49,7 @@ public class BedrockItemFrameDropItemTranslator extends PacketTranslator<ItemFra
if (entity != null) {
ServerboundInteractPacket interactPacket = new ServerboundInteractPacket(entity.getEntityId(),
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
false,
session.getWorldCache().nextPredictionSequence());
session.sendDownstreamPacket(blockPacket);
session.sendDownstreamGamePacket(blockPacket);
} else {
// Bedrock wants to either move a page or exit
if (!(session.getOpenInventory() instanceof LecternContainer lecternContainer)) {
@ -69,7 +69,7 @@ public class BedrockLecternUpdateTranslator extends PacketTranslator<LecternUpda
if (lecternContainer.getCurrentBedrockPage() == packet.getPage()) {
// The same page means Bedrock is closing the window
ServerboundContainerClosePacket closeWindowPacket = new ServerboundContainerClosePacket(lecternContainer.getJavaId());
session.sendDownstreamPacket(closeWindowPacket);
session.sendDownstreamGamePacket(closeWindowPacket);
InventoryUtils.closeInventory(session, lecternContainer.getJavaId(), false);
} else {
// 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) {
for (int i = currentJavaPage; i < newJavaPage; i++) {
ServerboundContainerButtonClickPacket clickButtonPacket = new ServerboundContainerButtonClickPacket(session.getOpenInventory().getJavaId(), 2);
session.sendDownstreamPacket(clickButtonPacket);
session.sendDownstreamGamePacket(clickButtonPacket);
}
} else {
for (int i = currentJavaPage; i > newJavaPage; i--) {
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);
ServerboundSetCarriedItemPacket setCarriedItemPacket = new ServerboundSetCarriedItemPacket(newSlot);
session.sendDownstreamPacket(setCarriedItemPacket);
session.sendDownstreamGamePacket(setCarriedItemPacket);
GeyserItemStack newItem = session.getPlayerInventory().getItemInHand();
@ -66,7 +66,7 @@ public class BedrockMobEquipmentTranslator extends PacketTranslator<MobEquipment
// Activate shield since we are already sneaking
// (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
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);
}

View File

@ -72,6 +72,6 @@ public class BedrockMoveEntityAbsoluteTranslator extends PacketTranslator<MoveEn
packet.getPosition().getX(), y, packet.getPosition().getZ(),
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;
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.packet.NetworkStackLatencyPacket;
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()
);
session.sendDownstreamPacket(playerInputPacket);
session.sendDownstreamGamePacket(playerInputPacket);
// Bedrock only sends movement vehicle packets while moving
// 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(),
vehicle.getYaw() - 90, vehicle.getPitch()
);
session.sendDownstreamPacket(moveVehiclePacket);
session.sendDownstreamGamePacket(moveVehiclePacket);
}
}
}

View File

@ -42,6 +42,7 @@ public class BedrockRequestAbilityTranslator extends PacketTranslator<RequestAbi
@Override
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) {
boolean isFlying = packet.isBoolValue();
if (!isFlying && session.getGameMode() == GameMode.SPECTATOR) {
@ -57,7 +58,7 @@ public class BedrockRequestAbilityTranslator extends PacketTranslator<RequestAbi
session.setFlying(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) {
if (packet.getState() == RespawnPacket.State.CLIENT_READY) {
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) {
if (packet.getStatus() == ShowCreditsPacket.Status.END_CREDITS) {
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 -> {
// Not sent as of 1.18.10
ServerboundSelectTradePacket selectTradePacket = new ServerboundSelectTradePacket(packet.getData());
session.sendDownstreamPacket(selectTradePacket);
session.sendDownstreamGamePacket(selectTradePacket);
session.scheduleInEventLoop(() -> {
Inventory openInventory = session.getOpenInventory();

View File

@ -26,10 +26,6 @@
package org.geysermc.geyser.translator.protocol.bedrock.entity.player;
import com.github.steveice10.mc.protocol.data.game.entity.object.Direction;
import com.github.steveice10.mc.protocol.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.Hand;
import com.github.steveice10.mc.protocol.data.game.entity.player.InteractAction;
@ -97,7 +93,7 @@ public class BedrockActionTranslator extends PacketTranslator<PlayerActionPacket
case START_SWIMMING:
if (!entity.getFlag(EntityFlag.SWIMMING)) {
ServerboundPlayerCommandPacket startSwimPacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.START_SPRINTING);
session.sendDownstreamPacket(startSwimPacket);
session.sendDownstreamGamePacket(startSwimPacket);
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
if (!session.getCollisionManager().mustPlayerCrawlHere()) {
ServerboundPlayerCommandPacket stopSwimPacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.STOP_SPRINTING);
session.sendDownstreamPacket(stopSwimPacket);
session.sendDownstreamGamePacket(stopSwimPacket);
session.setSwimming(false);
}
@ -114,45 +110,45 @@ public class BedrockActionTranslator extends PacketTranslator<PlayerActionPacket
case START_GLIDE:
// Otherwise gliding will not work in creative
ServerboundPlayerAbilitiesPacket playerAbilitiesPacket = new ServerboundPlayerAbilitiesPacket(false);
session.sendDownstreamPacket(playerAbilitiesPacket);
session.sendDownstreamGamePacket(playerAbilitiesPacket);
case STOP_GLIDE:
ServerboundPlayerCommandPacket glidePacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.START_ELYTRA_FLYING);
session.sendDownstreamPacket(glidePacket);
session.sendDownstreamGamePacket(glidePacket);
break;
case START_SNEAK:
ServerboundPlayerCommandPacket startSneakPacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.START_SNEAKING);
session.sendDownstreamPacket(startSneakPacket);
session.sendDownstreamGamePacket(startSneakPacket);
session.startSneaking();
break;
case STOP_SNEAK:
ServerboundPlayerCommandPacket stopSneakPacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.STOP_SNEAKING);
session.sendDownstreamPacket(stopSneakPacket);
session.sendDownstreamGamePacket(stopSneakPacket);
session.stopSneaking();
break;
case START_SPRINT:
if (!entity.getFlag(EntityFlag.SWIMMING)) {
ServerboundPlayerCommandPacket startSprintPacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.START_SPRINTING);
session.sendDownstreamPacket(startSprintPacket);
session.sendDownstreamGamePacket(startSprintPacket);
session.setSprinting(true);
}
break;
case STOP_SPRINT:
if (!entity.getFlag(EntityFlag.SWIMMING)) {
ServerboundPlayerCommandPacket stopSprintPacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.STOP_SPRINTING);
session.sendDownstreamPacket(stopSprintPacket);
session.sendDownstreamGamePacket(stopSprintPacket);
}
session.setSprinting(false);
break;
case DROP_ITEM:
ServerboundPlayerActionPacket dropItemPacket = new ServerboundPlayerActionPacket(PlayerAction.DROP_ITEM,
vector, Direction.VALUES[packet.getFace()], 0);
session.sendDownstreamPacket(dropItemPacket);
session.sendDownstreamGamePacket(dropItemPacket);
break;
case STOP_SLEEP:
ServerboundPlayerCommandPacket stopSleepingPacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.LEAVE_BED);
session.sendDownstreamPacket(stopSleepingPacket);
session.sendDownstreamGamePacket(stopSleepingPacket);
break;
case START_BREAK: {
// Ignore START_BREAK when the player is CREATIVE to avoid Spigot receiving 2 packets it interpets as block breaking. https://github.com/GeyserMC/Geyser/issues/4021
@ -189,12 +185,12 @@ public class BedrockActionTranslator extends PacketTranslator<PlayerActionPacket
if (identifier.startsWith("minecraft:fire") || identifier.startsWith("minecraft:soul_fire")) {
ServerboundPlayerActionPacket startBreakingPacket = new ServerboundPlayerActionPacket(PlayerAction.START_DIGGING, fireBlockPos,
Direction.VALUES[packet.getFace()], session.getWorldCache().nextPredictionSequence());
session.sendDownstreamPacket(startBreakingPacket);
session.sendDownstreamGamePacket(startBreakingPacket);
}
ServerboundPlayerActionPacket startBreakingPacket = new ServerboundPlayerActionPacket(PlayerAction.START_DIGGING,
vector, Direction.VALUES[packet.getFace()], session.getWorldCache().nextPredictionSequence());
session.sendDownstreamPacket(startBreakingPacket);
session.sendDownstreamGamePacket(startBreakingPacket);
break;
}
case CONTINUE_BREAK:
@ -236,7 +232,7 @@ public class BedrockActionTranslator extends PacketTranslator<PlayerActionPacket
// Break the block
ServerboundPlayerActionPacket finishBreakingPacket = new ServerboundPlayerActionPacket(PlayerAction.FINISH_DIGGING,
vector, Direction.VALUES[packet.getFace()], session.getWorldCache().nextPredictionSequence());
session.sendDownstreamPacket(finishBreakingPacket);
session.sendDownstreamGamePacket(finishBreakingPacket);
session.setBlockBreakStartTime(0);
break;
}
@ -253,13 +249,13 @@ public class BedrockActionTranslator extends PacketTranslator<PlayerActionPacket
if (itemFrameEntity != null) {
ServerboundInteractPacket interactPacket = new ServerboundInteractPacket(itemFrameEntity.getEntityId(),
InteractAction.ATTACK, Hand.MAIN_HAND, session.isSneaking());
session.sendDownstreamPacket(interactPacket);
session.sendDownstreamGamePacket(interactPacket);
break;
}
}
ServerboundPlayerActionPacket abortBreakingPacket = new ServerboundPlayerActionPacket(PlayerAction.CANCEL_DIGGING, vector, Direction.DOWN, 0);
session.sendDownstreamPacket(abortBreakingPacket);
session.sendDownstreamGamePacket(abortBreakingPacket);
LevelEventPacket stopBreak = new LevelEventPacket();
stopBreak.setType(LevelEvent.BLOCK_STOP_BREAK);
stopBreak.setPosition(vector.toFloat());
@ -287,7 +283,7 @@ public class BedrockActionTranslator extends PacketTranslator<PlayerActionPacket
case MISSED_SWING:
// TODO Re-evaluate after pre-1.20.10 is no longer supported?
if (session.getArmAnimationTicks() == -1) {
session.sendDownstreamPacket(new ServerboundSwingPacket(Hand.MAIN_HAND));
session.sendDownstreamGamePacket(new ServerboundSwingPacket(Hand.MAIN_HAND));
session.activateArmAnimationTicking();
// Send packet to Bedrock so it knows
@ -297,6 +293,40 @@ public class BedrockActionTranslator extends PacketTranslator<PlayerActionPacket
session.sendUpstreamPacket(animatePacket);
}
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(),
InteractAction.INTERACT, Hand.MAIN_HAND, session.isSneaking());
session.sendDownstreamPacket(interactPacket);
session.sendDownstreamGamePacket(interactPacket);
break;
case DAMAGE:
ServerboundInteractPacket attackPacket = new ServerboundInteractPacket(entity.getEntityId(),
InteractAction.ATTACK, Hand.MAIN_HAND, session.isSneaking());
session.sendDownstreamPacket(attackPacket);
session.sendDownstreamGamePacket(attackPacket);
break;
case LEAVE_VEHICLE:
ServerboundPlayerCommandPacket sneakPacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.START_SNEAKING);
session.sendDownstreamPacket(sneakPacket);
session.sendDownstreamGamePacket(sneakPacket);
Entity currentVehicle = session.getPlayerEntity().getVehicle();
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)) {
// This mob has an inventory of its own that we should open instead.
ServerboundPlayerCommandPacket openVehicleWindowPacket = new ServerboundPlayerCommandPacket(session.getPlayerEntity().getEntityId(), PlayerState.OPEN_VEHICLE_INVENTORY);
session.sendDownstreamPacket(openVehicleWindowPacket);
session.sendDownstreamGamePacket(openVehicleWindowPacket);
} else {
session.setOpenInventory(session.getPlayerInventory());

View File

@ -83,7 +83,7 @@ public class BedrockMovePlayerTranslator extends PacketTranslator<MovePlayerPack
entity.setHeadYaw(headYaw);
entity.setOnGround(packet.isOnGround());
session.sendDownstreamPacket(playerRotationPacket);
session.sendDownstreamGamePacket(playerRotationPacket);
} else {
if (session.getWorldBorder().isPassingIntoBorderBoundaries(packet.getPosition(), true)) {
return;
@ -130,7 +130,7 @@ public class BedrockMovePlayerTranslator extends PacketTranslator<MovePlayerPack
entity.setOnGround(onGround);
// Send final movement changes
session.sendDownstreamPacket(movePacket);
session.sendDownstreamGamePacket(movePacket);
if (teleportThroughVoidFloor) {
// 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
* of this software and associated documentation files (the "Software"), to deal
@ -23,33 +23,21 @@
* @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
* the class used now.
*
* @deprecated legacy code
* Sent occasionally by a BDS client when opening the client side server settings menu.
*/
@Deprecated
public class AuthData {
private final org.geysermc.geyser.session.auth.AuthData handle;
@Translator(packet = RequestPermissionsPacket.class)
public class BedrockRequestPermissionsPacket extends PacketTranslator<RequestPermissionsPacket> {
public AuthData(org.geysermc.geyser.session.auth.AuthData handle) {
this.handle = handle;
}
public String getName() {
return this.handle.name();
}
public UUID getUUID() {
return this.handle.uuid();
}
public String getXboxUUID() {
return this.handle.xuid();
@Override
public void translate(GeyserSession session, RequestPermissionsPacket packet) {
session.sendAdventureSettings();
}
}

View File

@ -41,7 +41,7 @@ public class BedrockRiderJumpTranslator extends PacketTranslator<RiderJumpPacket
Entity vehicle = session.getPlayerEntity().getVehicle();
if (vehicle instanceof AbstractHorseEntity) {
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
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()));
}
// 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
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()) {
session.getGeyser().getWorldManager().setDifficulty(session, Difficulty.from(packet.getDifficulty()));
}

View File

@ -45,7 +45,7 @@ public class BedrockSetPlayerGameTypeTranslator extends PacketTranslator<SetPlay
@Override
public void translate(GeyserSession session, SetPlayerGameTypePacket packet) {
// 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()) {
// 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

View File

@ -57,7 +57,7 @@ public class BedrockLevelSoundEventTranslator extends PacketTranslator<LevelSoun
// ATTACK_NODAMAGE = player clicked air
// 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
session.sendDownstreamPacket(new ServerboundSwingPacket(Hand.MAIN_HAND));
session.sendDownstreamGamePacket(new ServerboundSwingPacket(Hand.MAIN_HAND));
session.activateArmAnimationTicking();
// 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;
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.GeyserLogger;
import org.geysermc.geyser.session.GeyserSession;

View File

@ -26,7 +26,7 @@
package org.geysermc.geyser.translator.protocol.java;
import com.github.steveice10.mc.protocol.packet.login.clientbound.ClientboundCustomQueryPacket;
import com.github.steveice10.mc.protocol.packet.login.serverbound.ServerboundCustomQueryPacket;
import com.github.steveice10.mc.protocol.packet.login.serverbound.ServerboundCustomQueryAnswerPacket;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.protocol.PacketTranslator;
import org.geysermc.geyser.translator.protocol.Translator;
@ -40,8 +40,8 @@ public class JavaCustomQueryTranslator extends PacketTranslator<ClientboundCusto
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.
// Note: Fabric Networking API v1 will not let the client log in without sending this
session.sendDownstreamPacket(
new ServerboundCustomQueryPacket(packet.getMessageId(), null)
session.sendDownstreamLoginPacket(
new ServerboundCustomQueryAnswerPacket(packet.getMessageId(), null)
);
}
}

View File

@ -25,7 +25,7 @@
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.translator.protocol.PacketTranslator;
import org.geysermc.geyser.translator.protocol.Translator;

View File

@ -26,6 +26,7 @@
package org.geysermc.geyser.translator.protocol.java;
import com.github.steveice10.mc.auth.data.GameProfile;
import com.github.steveice10.mc.protocol.packet.common.serverbound.ServerboundCustomPayloadPacket;
import com.github.steveice10.mc.protocol.packet.login.clientbound.ClientboundGameProfilePacket;
import org.geysermc.geyser.api.network.AuthType;
import org.geysermc.geyser.entity.type.player.PlayerEntity;
@ -33,7 +34,11 @@ import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.skin.SkinManager;
import org.geysermc.geyser.translator.protocol.PacketTranslator;
import org.geysermc.geyser.translator.protocol.Translator;
import org.geysermc.geyser.util.PluginMessageUtils;
/**
* ClientboundGameProfilePacket triggers protocol change LOGIN -> CONFIGURATION
*/
@Translator(packet = ClientboundGameProfilePacket.class)
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
session.setCertChainData(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;
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.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.protocol.PacketTranslator;

View File

@ -25,30 +25,20 @@
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.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.packet.GameRulesChangedPacket;
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.entity.type.player.SessionPlayerEntity;
import org.geysermc.geyser.erosion.GeyserboundHandshakePacketHandler;
import org.geysermc.geyser.level.JavaDimension;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.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.ChunkUtils;
import org.geysermc.geyser.util.DimensionUtils;
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)
public class JavaLoginTranslator extends PacketTranslator<ClientboundLoginPacket> {
@ -63,42 +53,22 @@ public class JavaLoginTranslator extends PacketTranslator<ClientboundLoginPacket
session.setErosionHandler(new GeyserboundHandshakePacketHandler(session));
}
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);
}
PlayerSpawnInfo spawnInfo = packet.getCommonPlayerSpawnInfo();
// If the player is already initialized and a join game packet is sent, they
// are swapping servers
if (session.isSpawned()) {
String fakeDim = DimensionUtils.getTemporaryDimension(session.getDimension(), packet.getDimension());
String fakeDim = DimensionUtils.getTemporaryDimension(session.getDimension(), spawnInfo.getDimension());
DimensionUtils.switchDimension(session, fakeDim);
session.getWorldCache().removeScoreboard();
}
session.setWorldName(packet.getWorldName());
session.setWorldName(spawnInfo.getWorldName());
session.setLevels(packet.getWorldNames());
BiomeTranslator.loadServerBiomes(session, packet.getRegistry());
session.getTagCache().clear();
session.setGameMode(spawnInfo.getGameMode());
session.setGameMode(packet.getGameMode());
String newDimension = packet.getDimension();
String newDimension = spawnInfo.getDimension();
boolean needsSpawnPacket = !session.isSentSpawnPacket();
if (needsSpawnPacket) {
@ -113,11 +83,11 @@ public class JavaLoginTranslator extends PacketTranslator<ClientboundLoginPacket
if (!needsSpawnPacket) {
SetPlayerGameTypePacket playerGameTypePacket = new SetPlayerGameTypePacket();
playerGameTypePacket.setGamemode(EntityUtils.toBedrockGamemode(packet.getGameMode()).ordinal());
playerGameTypePacket.setGamemode(EntityUtils.toBedrockGamemode(spawnInfo.getGameMode()).ordinal());
session.sendUpstreamPacket(playerGameTypePacket);
}
entity.setLastDeathPosition(packet.getLastDeathPos());
entity.setLastDeathPosition(spawnInfo.getLastDeathPos());
entity.updateBedrockMetadata();
@ -130,16 +100,10 @@ public class JavaLoginTranslator extends PacketTranslator<ClientboundLoginPacket
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.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) {
//todo
// session.sendDownstreamPacket(new ServerboundCustomPayloadPacket("minecraft:register", PluginMessageChannels.getFloodgateRegisterData()));

View File

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

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

View File

@ -25,7 +25,7 @@
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.translator.protocol.PacketTranslator;
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()) {
Entity hookOwner = session.getEntityCache().getEntityByGeyserId(fishingHook.getBedrockOwnerId());
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();
motionPacket.setRuntimeEntityId(session.getPlayerEntity().getGeyserId());
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()) {
session.getEffectCache().setEffect(packet.getEffect(), packet.getAmplifier());
}
if (entity == null)
if (entity == null) {
return;
}
int duration = packet.getDuration();
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.PlayerListEntryAction;
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundPlayerInfoUpdatePacket;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.packet.PlayerListPacket;
import org.geysermc.geyser.GeyserImpl;
@ -41,6 +42,7 @@ import org.geysermc.geyser.translator.protocol.Translator;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.UUID;
@Translator(packet = ClientboundPlayerInfoUpdatePacket.class)
public class JavaPlayerInfoUpdateTranslator extends PacketTranslator<ClientboundPlayerInfoUpdatePacket> {
@ -50,13 +52,24 @@ public class JavaPlayerInfoUpdateTranslator extends PacketTranslator<Clientbound
if (actions.contains(PlayerListEntryAction.ADD_PLAYER)) {
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;
boolean self = profile.getId().equals(session.getPlayerEntity().getUuid());
GameProfile.Property textures = profile.getProperty("textures");
String texturesProperty = textures == null ? null : textures.getValue();
if (self) {
// Entity is ourself
playerEntity = session.getPlayerEntity();
@ -66,17 +79,17 @@ public class JavaPlayerInfoUpdateTranslator extends PacketTranslator<Clientbound
session,
-1,
session.getEntityCache().getNextEntityId().incrementAndGet(),
profile.getId(),
id,
Vector3f.ZERO,
Vector3f.ZERO,
0, 0, 0,
profile.getName(),
name,
texturesProperty
);
session.getEntityCache().addPlayerEntity(playerEntity);
}
playerEntity.setUsername(profile.getName());
playerEntity.setUsername(name);
playerEntity.setTexturesProperty(texturesProperty);
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) {
// Confirm the teleport when we receive it to match Java edition
ServerboundAcceptTeleportationPacket teleportConfirmPacket = new ServerboundAcceptTeleportationPacket(id);
session.sendDownstreamPacket(teleportConfirmPacket);
session.sendDownstreamGamePacket(teleportConfirmPacket);
// Servers (especially ones like Hypixel) expect exact coordinates given back to them.
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.packet.ingame.clientbound.entity.spawn.ClientboundAddEntityPacket;
import org.cloudburstmc.math.vector.Vector3f;
import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.entity.type.*;
import org.geysermc.geyser.entity.type.player.PlayerEntity;
import org.geysermc.geyser.registry.Registries;
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;
@ -44,15 +47,44 @@ public class JavaAddEntityTranslator extends PacketTranslator<ClientboundAddEnti
@Override
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 motion = Vector3f.from(packet.getMotionX(), packet.getMotionY(), packet.getMotionZ());
float yaw = packet.getYaw();
float pitch = packet.getPitch();
float headYaw = packet.getHeadYaw();
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());
if (packet.getType() == EntityType.PLAYER) {
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;
}

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);
}
ServerboundContainerClosePacket closeWindowPacket = new ServerboundContainerClosePacket(packet.getContainerId());
session.sendDownstreamPacket(closeWindowPacket);
session.sendDownstreamGamePacket(closeWindowPacket);
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()) {
case SEEN_BEFORE -> {
ServerboundClientCommandPacket javaRespawnPacket = new ServerboundClientCommandPacket(ClientCommand.RESPAWN);
session.sendDownstreamPacket(javaRespawnPacket);
session.sendDownstreamGamePacket(javaRespawnPacket);
}
case FIRST_TIME -> {
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.Vector3i;
import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.protocol.bedrock.data.ParticleType;
import org.cloudburstmc.protocol.bedrock.data.SoundEvent;
import org.cloudburstmc.protocol.bedrock.packet.LevelEventGenericPacket;
import org.cloudburstmc.protocol.bedrock.packet.LevelEventPacket;
@ -103,6 +104,10 @@ public class JavaLevelEventTranslator extends PacketTranslator<ClientboundLevelE
effectPacket.setPosition(pos);
effectPacket.setData(0);
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 -> {
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();
effectPacket.setData(growEventData.getParticleCount());
}
case EGG_CRACK -> effectPacket.setType(ParticleType.VILLAGER_HAPPY); // both the lil green sparkle
case ENDERDRAGON_FIREBALL_EXPLODE -> {
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
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();
// 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

View File

@ -32,7 +32,7 @@ import com.github.steveice10.mc.protocol.data.game.entity.attribute.ModifierOper
public class AttributeUtils {
/**
* 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.
* @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("")) return 1.0;
return switch (toolTier) {
// https://minecraft.gamepedia.com/Breaking#Speed
// https://minecraft.wiki/w/Breaking#Speed
case "wooden" -> 2.0;
case "stone" -> 4.0;
case "iron" -> 6.0;
@ -100,7 +100,7 @@ public final class BlockUtils {
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,
String toolType, boolean isShearsEffective, int toolEfficiencyLevel, int hasteLevel, int miningFatigueLevel,
boolean insideOfWaterWithoutAquaAffinity, boolean onGround) {

View File

@ -25,6 +25,8 @@
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.dataformat.yaml.YAMLFactory;
import org.geysermc.geyser.GeyserBootstrap;
@ -53,7 +55,8 @@ public class FileUtils {
* @throws IOException if the config could not be loaded
*/
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);
}

View File

@ -260,7 +260,7 @@ public class InventoryUtils {
// If this is the item we're looking for
if (geyserItem.getJavaId() == itemStack.getId() && Objects.equals(geyserItem.getNbt(), itemStack.getNbt())) {
ServerboundPickItemPacket packetToSend = new ServerboundPickItemPacket(i); // https://wiki.vg/Protocol#Pick_Item
session.sendDownstreamPacket(packetToSend);
session.sendDownstreamGamePacket(packetToSend);
return;
}
}
@ -274,7 +274,7 @@ public class InventoryUtils {
if ((slot - 36) != inventory.getHeldItemSlot()) {
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
session.sendDownstreamPacket(packetToSend);
session.sendDownstreamGamePacket(packetToSend);
return;
}
@ -340,7 +340,7 @@ public class InventoryUtils {
if ((slot - 36) != inventory.getHeldItemSlot()) {
setHotbarItem(session, slot);
}
session.sendDownstreamPacket(actionPacket);
session.sendDownstreamGamePacket(actionPacket);
} else {
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.IdentityData;
import org.cloudburstmc.protocol.bedrock.util.EncryptionUtils;
import org.geysermc.cumulus.form.CustomForm;
import org.geysermc.cumulus.form.ModalForm;
import org.geysermc.cumulus.form.SimpleForm;
import org.geysermc.cumulus.response.SimpleFormResponse;
import org.geysermc.cumulus.response.result.FormResponseResult;
import org.geysermc.cumulus.response.result.ValidFormResponseResult;
import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.configuration.GeyserConfiguration;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.session.auth.AuthData;
import org.geysermc.geyser.session.auth.BedrockClientData;
@ -137,26 +135,16 @@ public class LoginEncryptionUtils {
// Set DoDaylightCycle to false so the time doesn't accelerate while we're here
session.setDaylightCycle(false);
GeyserConfiguration config = session.getGeyser().getConfig();
boolean isPasswordAuthEnabled = config.getRemote().isPasswordAuthentication();
session.sendForm(
SimpleForm.builder()
.translator(GeyserLocale::getPlayerLocaleString, session.locale())
.title("geyser.auth.login.form.notice.title")
.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_disconnect")
.closedOrInvalidResultHandler(() -> buildAndShowLoginWindow(session))
.validResultHandler((response) -> {
if (response.clickedButtonId() == 0) {
session.setMicrosoftAccount(false);
buildAndShowLoginDetailsWindow(session);
return;
}
if (response.clickedButtonId() == 1) {
session.authenticateWithMicrosoftCode();
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
*/

View File

@ -25,7 +25,7 @@
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 org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.session.GeyserSession;

View File

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

View File

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

View File

@ -5,6 +5,10 @@
#
# GitHub: https://github.com/GeyserMC/Geyser
# 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:

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