mirror of
https://github.com/GeyserMC/Geyser.git
synced 2024-08-14 23:57:35 +00:00
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:
commit
dab61ac41a
102 changed files with 678 additions and 837 deletions
9
.github/workflows/pullrequest.yml
vendored
9
.github/workflows/pullrequest.yml
vendored
|
@ -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:
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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}.
|
||||
|
|
|
@ -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(" / \\");
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
"depends": {
|
||||
"fabricloader": ">=0.14.21",
|
||||
"fabric": "*",
|
||||
"minecraft": ">=1.20",
|
||||
"minecraft": ">=1.20.2",
|
||||
"fabric-permissions-api-v0": "*"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"));
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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<>();
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
// Try to find class in current extension
|
||||
try {
|
||||
result = super.findClass(name);
|
||||
if (result == null && checkGlobal) {
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -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,8 +148,8 @@ 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 -> {
|
||||
List<Path> extensionPaths = Files.walk(extensionsDirectory).toList();
|
||||
extensionPaths.forEach(path -> {
|
||||
if (Files.isDirectory(path)) {
|
||||
return;
|
||||
}
|
||||
|
@ -152,7 +164,8 @@ public class GeyserExtensionLoader extends ExtensionLoader {
|
|||
GeyserExtensionDescription description = this.extensionDescription(path);
|
||||
|
||||
String name = description.name();
|
||||
if (extensions.containsKey(name) || extensionManager.extension(name) != null) {
|
||||
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;
|
||||
}
|
||||
|
@ -169,13 +182,12 @@ public class GeyserExtensionLoader extends ExtensionLoader {
|
|||
return;
|
||||
}
|
||||
|
||||
extensions.put(name, path);
|
||||
loadedExtensions.put(name, this.loadExtension(path, description));
|
||||
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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -152,7 +152,7 @@ public final class ClickPlan {
|
|||
changedItems
|
||||
);
|
||||
|
||||
session.sendDownstreamPacket(clickPacket);
|
||||
session.sendDownstreamGamePacket(clickPacket);
|
||||
}
|
||||
|
||||
session.getPlayerInventory().setCursor(simulatedCursor, session);
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
// 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;
|
||||
}
|
||||
// Always replace spaces with underscores to avoid illegal nicknames, e.g. with GeyserConnect
|
||||
protocol = new MinecraftProtocol(username.replace(' ', '_'));
|
||||
|
||||
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,9 +1817,12 @@ 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 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
|
||||
private static final List<SkinPart> SKIN_PARTS = Arrays.asList(SkinPart.values());
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -68,7 +68,7 @@ public class BookEditCache {
|
|||
packet = null;
|
||||
return;
|
||||
}
|
||||
session.sendDownstreamPacket(packet);
|
||||
session.sendDownstreamGamePacket(packet);
|
||||
packet = null;
|
||||
lastBookUpdate = System.currentTimeMillis();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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";
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()));
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()));
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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()));
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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();
|
||||
PlayerEntity playerEntity;
|
||||
boolean self = profile.getId().equals(session.getPlayerEntity().getUuid());
|
||||
@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");
|
||||
String texturesProperty = textures == null ? null : textures.getValue();
|
||||
if (textures != null) {
|
||||
texturesProperty = textures.getValue();
|
||||
}
|
||||
}
|
||||
|
||||
boolean self = id.equals(session.getPlayerEntity().getUuid());
|
||||
|
||||
PlayerEntity playerEntity;
|
||||
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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -145,10 +145,9 @@
|
|||
{
|
||||
"origin": [ -0.1, 0.0, -2.0 ],
|
||||
"size": [ 4, 12, 4 ],
|
||||
"uv": [ 0, 16 ]
|
||||
"uv": [ 16, 48 ]
|
||||
}
|
||||
],
|
||||
"mirror": true
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
|
|
|
@ -145,10 +145,9 @@
|
|||
{
|
||||
"origin": [ -0.1, 0.0, -2.0 ],
|
||||
"size": [ 4, 12, 4 ],
|
||||
"uv": [ 0, 16 ]
|
||||
"uv": [ 16, 48 ]
|
||||
}
|
||||
],
|
||||
"mirror": true
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
|
|
|
@ -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
Loading…
Reference in a new issue