World border improvements (#488)

This commit is contained in:
Camotoy 2020-06-04 16:56:16 -04:00 committed by GitHub
parent 50c4c0b2d8
commit 498b058aba
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
243 changed files with 7471 additions and 1898 deletions

View file

@ -23,6 +23,12 @@
<version>1.14-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>us.myles</groupId>
<artifactId>viaversion</artifactId>
<version>3.0.0-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<finalName>${outputName}-Bukkit</finalName>

View file

@ -87,8 +87,28 @@ public class GeyserBukkitConfiguration implements GeyserConfiguration {
}
@Override
public boolean isPingPassthrough() {
return config.getBoolean("ping-passthrough", false);
public boolean isCommandSuggestions() {
return config.getBoolean("command-suggestions", true);
}
@Override
public boolean isPassthroughMotd() {
return config.getBoolean("passthrough-motd", false);
}
@Override
public boolean isPassthroughPlayerCounts() {
return config.getBoolean("passthrough-player-counts", false);
}
@Override
public boolean isLegacyPingPassthrough() {
return config.getBoolean("legacy-ping-passthrough", false);
}
@Override
public int getPingPassthroughInterval() {
return config.getInt("ping-passthrough-interval", 3);
}
@Override
@ -111,6 +131,11 @@ public class GeyserBukkitConfiguration implements GeyserConfiguration {
return config.getBoolean("allow-third-party-capes", true);
}
@Override
public boolean isAllowThirdPartyEars() {
return config.getBoolean("allow-third-party-ears", false);
}
@Override
public String getDefaultLocale() {
return config.getString("default-locale", "en_us");
@ -126,6 +151,11 @@ public class GeyserBukkitConfiguration implements GeyserConfiguration {
return true; // We override this as with Bukkit, we have direct access to the server implementation
}
@Override
public boolean isAboveBedrockNetherBuilding() {
return config.getBoolean("above-bedrock-nether-building", false);
}
@Override
public IMetricsInfo getMetrics() {
return metricsInfo;
@ -203,4 +233,9 @@ public class GeyserBukkitConfiguration implements GeyserConfiguration {
return config.getString("metrics.uuid", "generateduuid");
}
}
@Override
public int getConfigVersion() {
return config.getInt("config-version", 0);
}
}

View file

@ -0,0 +1,79 @@
/*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*
*/
package org.geysermc.platform.bukkit;
import lombok.AllArgsConstructor;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.server.ServerListPingEvent;
import org.bukkit.util.CachedServerIcon;
import org.geysermc.common.ping.GeyserPingInfo;
import org.geysermc.connector.ping.IGeyserPingPassthrough;
import java.net.InetAddress;
import java.util.Collections;
import java.util.Iterator;
@AllArgsConstructor
public class GeyserBukkitPingPassthrough implements IGeyserPingPassthrough {
private final GeyserBukkitLogger logger;
@Override
public GeyserPingInfo getPingInformation() {
try {
ServerListPingEvent event = new GeyserPingEvent(InetAddress.getLocalHost(), Bukkit.getMotd(), Bukkit.getOnlinePlayers().size(), Bukkit.getMaxPlayers());
Bukkit.getPluginManager().callEvent(event);
GeyserPingInfo geyserPingInfo = new GeyserPingInfo(event.getMotd(), event.getNumPlayers(), event.getMaxPlayers());
Bukkit.getOnlinePlayers().forEach(player -> {
geyserPingInfo.addPlayer(player.getName());
});
return geyserPingInfo;
} catch (Exception e) {
logger.debug("Error while getting Bukkit ping passthrough: " + e.toString());
return new GeyserPingInfo(null, 0, 0);
}
}
// These methods are unimplemented on spigot api by default so we add stubs so plugins don't complain
private static class GeyserPingEvent extends ServerListPingEvent {
public GeyserPingEvent(InetAddress address, String motd, int numPlayers, int maxPlayers) {
super(address, motd, numPlayers, maxPlayers);
}
@Override
public void setServerIcon(CachedServerIcon icon) throws IllegalArgumentException, UnsupportedOperationException {
}
@Override
public Iterator<Player> iterator() throws UnsupportedOperationException {
return Collections.EMPTY_LIST.iterator();
}
}
}

View file

@ -28,13 +28,18 @@ package org.geysermc.platform.bukkit;
import org.bukkit.Bukkit;
import org.bukkit.plugin.java.JavaPlugin;
import org.geysermc.common.PlatformType;
import org.geysermc.connector.GeyserConfiguration;
import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.bootstrap.GeyserBootstrap;
import org.geysermc.connector.command.CommandManager;
import org.geysermc.connector.network.translators.world.WorldManager;
import org.geysermc.connector.ping.GeyserLegacyPingPassthrough;
import org.geysermc.connector.ping.IGeyserPingPassthrough;
import org.geysermc.platform.bukkit.command.GeyserBukkitCommandExecutor;
import org.geysermc.platform.bukkit.command.GeyserBukkitCommandManager;
import org.geysermc.platform.bukkit.world.GeyserBukkitBlockPlaceListener;
import org.geysermc.platform.bukkit.world.GeyserBukkitWorldManager;
import us.myles.ViaVersion.api.Via;
import java.util.UUID;
@ -43,6 +48,8 @@ public class GeyserBukkitPlugin extends JavaPlugin implements GeyserBootstrap {
private GeyserBukkitCommandManager geyserCommandManager;
private GeyserBukkitConfiguration geyserConfig;
private GeyserBukkitLogger geyserLogger;
private IGeyserPingPassthrough geyserBukkitPingPassthrough;
private GeyserBukkitBlockPlaceListener blockPlaceListener;
private GeyserBukkitWorldManager geyserWorldManager;
private GeyserConnector connector;
@ -59,7 +66,7 @@ public class GeyserBukkitPlugin extends JavaPlugin implements GeyserBootstrap {
// Don't change the ip if its listening on all interfaces
// By default this should be 127.0.0.1 but may need to be changed in some circumstances
if (!Bukkit.getIp().equals("0.0.0.0")) {
if (!Bukkit.getIp().equals("0.0.0.0") && !Bukkit.getIp().equals("")) {
getConfig().set("remote.address", Bukkit.getIp());
}
@ -67,13 +74,39 @@ public class GeyserBukkitPlugin extends JavaPlugin implements GeyserBootstrap {
saveConfig();
this.geyserLogger = new GeyserBukkitLogger(getLogger(), geyserConfig.isDebugMode());
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
geyserConfig.loadFloodgate(this);
this.connector = GeyserConnector.start(PlatformType.BUKKIT, this);
if (geyserConfig.isLegacyPingPassthrough()) {
this.geyserBukkitPingPassthrough = GeyserLegacyPingPassthrough.init(connector);
} else {
this.geyserBukkitPingPassthrough = new GeyserBukkitPingPassthrough(geyserLogger);
}
this.geyserCommandManager = new GeyserBukkitCommandManager(this, connector);
this.geyserWorldManager = new GeyserBukkitWorldManager();
boolean isViaVersion = false;
// Used to determine if Block.getBlockData() is present.
boolean isLegacy = !isCompatible(Bukkit.getServer().getVersion(), "1.13.0");
if (isLegacy)
geyserLogger.debug("Legacy version of Minecraft (1.12.2 or older) detected.");
if (Bukkit.getPluginManager().getPlugin("ViaVersion") != null) {
// TODO: Update when ViaVersion updates
// API changes between 2.2.3 and 3.0.0-SNAPSHOT require this check
if (!Via.getAPI().getVersion().equals("3.0.0-SNAPSHOT") && isLegacy) {
geyserLogger.info("ViaVersion detected but not ViaVersion-ABSTRACTION. Please update your ViaVersion plugin for compatibility with Geyser.");
} else {
isViaVersion = true;
}
}
this.geyserWorldManager = new GeyserBukkitWorldManager(isLegacy, isViaVersion);
this.blockPlaceListener = new GeyserBukkitBlockPlaceListener(connector, isLegacy, isViaVersion);
Bukkit.getServer().getPluginManager().registerEvents(blockPlaceListener, this);
this.getCommand("geyser").setExecutor(new GeyserBukkitCommandExecutor(connector));
}
@ -98,8 +131,47 @@ public class GeyserBukkitPlugin extends JavaPlugin implements GeyserBootstrap {
return this.geyserCommandManager;
}
@Override
public IGeyserPingPassthrough getGeyserPingPassthrough() {
return geyserBukkitPingPassthrough;
}
@Override
public WorldManager getWorldManager() {
return this.geyserWorldManager;
}
public boolean isCompatible(String version, String whichVersion) {
int[] currentVersion = parseVersion(version);
int[] otherVersion = parseVersion(whichVersion);
int length = Math.max(currentVersion.length, otherVersion.length);
for (int index = 0; index < length; index = index + 1) {
int self = (index < currentVersion.length) ? currentVersion[index] : 0;
int other = (index < otherVersion.length) ? otherVersion[index] : 0;
if (self != other) {
return (self - other) > 0;
}
}
return true;
}
private int[] parseVersion(String versionParam) {
versionParam = (versionParam == null) ? "" : versionParam;
if (versionParam.contains("(MC: ")) {
versionParam = versionParam.split("\\(MC: ")[1];
versionParam = versionParam.split("\\)")[0];
}
String[] stringArray = versionParam.split("[_.-]");
int[] temp = new int[stringArray.length];
for (int index = 0; index <= (stringArray.length - 1); index = index + 1) {
String t = stringArray[index].replaceAll("\\D", "");
try {
temp[index] = Integer.parseInt(t);
} catch(NumberFormatException ex) {
temp[index] = 0;
}
}
return temp;
}
}

View file

@ -0,0 +1,73 @@
/*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*
*/
package org.geysermc.platform.bukkit.world;
import com.nukkitx.math.vector.Vector3f;
import com.nukkitx.protocol.bedrock.data.SoundEvent;
import com.nukkitx.protocol.bedrock.packet.LevelSoundEventPacket;
import lombok.AllArgsConstructor;
import org.bukkit.Bukkit;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockPlaceEvent;
import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
@AllArgsConstructor
public class GeyserBukkitBlockPlaceListener implements Listener {
private final GeyserConnector connector;
private final boolean isLegacy;
private final boolean isViaVersion;
@EventHandler
public void place(final BlockPlaceEvent event) {
for (GeyserSession session : connector.getPlayers().values()) {
if (event.getPlayer() == Bukkit.getPlayer(session.getPlayerEntity().getUsername())) {
LevelSoundEventPacket placeBlockSoundPacket = new LevelSoundEventPacket();
placeBlockSoundPacket.setSound(SoundEvent.PLACE);
placeBlockSoundPacket.setPosition(Vector3f.from(event.getBlockPlaced().getX(), event.getBlockPlaced().getY(), event.getBlockPlaced().getZ()));
placeBlockSoundPacket.setBabySound(false);
String javaBlockId;
if (isLegacy) {
javaBlockId = BlockTranslator.getJavaIdBlockMap().inverse().get(GeyserBukkitWorldManager.getLegacyBlock(session,
event.getBlockPlaced().getX(), event.getBlockPlaced().getY(), event.getBlockPlaced().getZ(), isViaVersion));
} else {
javaBlockId = event.getBlockPlaced().getBlockData().getAsString();
}
placeBlockSoundPacket.setExtraData(BlockTranslator.getBedrockBlockId(BlockTranslator.getJavaIdBlockMap().get(javaBlockId)));
placeBlockSoundPacket.setIdentifier(":");
session.sendUpstreamPacket(placeBlockSoundPacket);
session.setLastBlockPlacePosition(null);
session.setLastBlockPlacedId(null);
break;
}
}
}
}

View file

@ -28,18 +28,49 @@ package org.geysermc.platform.bukkit.world;
import com.github.steveice10.mc.protocol.data.game.world.block.BlockState;
import lombok.AllArgsConstructor;
import lombok.Getter;
import org.bukkit.Bukkit;
import org.bukkit.block.Block;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.world.WorldManager;
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
import org.geysermc.platform.bukkit.GeyserBukkitPlugin;
import us.myles.ViaVersion.protocols.protocol1_13_1to1_13.Protocol1_13_1To1_13;
import us.myles.ViaVersion.protocols.protocol1_15to1_14_4.data.MappingData;
@AllArgsConstructor
public class GeyserBukkitWorldManager extends WorldManager {
private final boolean isLegacy;
// You need ViaVersion to connect to an older server with Geyser.
// However, we still check for ViaVersion in case there's some other way that gets Geyser on a pre-1.13 Bukkit server
private final boolean isViaVersion;
@Override
public BlockState getBlockAt(GeyserSession session, int x, int y, int z) {
if (session.getPlayerEntity() == null) {
return BlockTranslator.AIR;
}
if (isLegacy) {
return getLegacyBlock(session, x, y, z, isViaVersion);
}
return BlockTranslator.getJavaIdBlockMap().get(Bukkit.getPlayer(session.getPlayerEntity().getUsername()).getWorld().getBlockAt(x, y, z).getBlockData().getAsString());
}
@SuppressWarnings("deprecation")
public static BlockState getLegacyBlock(GeyserSession session, int x, int y, int z, boolean isViaVersion) {
if (isViaVersion) {
Block block = Bukkit.getPlayer(session.getPlayerEntity().getUsername()).getWorld().getBlockAt(x, y, z);
// Black magic that gets the old block state ID
int oldBlockId = (block.getType().getId() << 4) | (block.getData() & 0xF);
// Convert block state from old version -> 1.13 -> 1.13.1 -> 1.14 -> 1.15
int thirteenBlockId = us.myles.ViaVersion.protocols.protocol1_13to1_12_2.data.MappingData.blockMappings.getNewId(oldBlockId);
int thirteenPointOneBlockId = Protocol1_13_1To1_13.getNewBlockStateId(thirteenBlockId);
int fourteenBlockId = us.myles.ViaVersion.protocols.protocol1_14to1_13_2.data.MappingData.blockStateMappings.getNewId(thirteenPointOneBlockId);
return new BlockState(MappingData.blockStateMappings.getNewId(fourteenBlockId));
} else {
return BlockTranslator.AIR;
}
}
}

View file

@ -3,6 +3,8 @@ name: ${outputName}-Bukkit
author: ${project.organization.name}
website: ${project.organization.url}
version: ${project.version}
softdepend: ["ViaVersion"]
api-version: 1.13
commands:
geyser:
description: The main command for Geyser.

View file

@ -20,7 +20,7 @@
<dependency>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-api</artifactId>
<version>1.14-SNAPSHOT</version>
<version>1.15-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
</dependencies>
@ -80,4 +80,4 @@
</plugin>
</plugins>
</build>
</project>
</project>

View file

@ -86,8 +86,28 @@ public class GeyserBungeeConfiguration implements GeyserConfiguration {
}
@Override
public boolean isPingPassthrough() {
return config.getBoolean("ping-passthrough", false);
public boolean isCommandSuggestions() {
return config.getBoolean("command-suggestions", true);
}
@Override
public boolean isPassthroughMotd() {
return config.getBoolean("passthrough-motd", false);
}
@Override
public boolean isPassthroughPlayerCounts() {
return config.getBoolean("passthrough-player-counts", false);
}
@Override
public boolean isLegacyPingPassthrough() {
return config.getBoolean("legacy-ping-passthrough", false);
}
@Override
public int getPingPassthroughInterval() {
return config.getInt("ping-passthrough-interval", 3);
}
@Override
@ -110,6 +130,11 @@ public class GeyserBungeeConfiguration implements GeyserConfiguration {
return config.getBoolean("allow-third-party-capes", true);
}
@Override
public boolean isAllowThirdPartyEars() {
return config.getBoolean("allow-third-party-ears", false);
}
@Override
public String getDefaultLocale() {
return config.getString("default-locale", "en_us");
@ -125,6 +150,11 @@ public class GeyserBungeeConfiguration implements GeyserConfiguration {
return config.getBoolean("cache-chunks", false);
}
@Override
public boolean isAboveBedrockNetherBuilding() {
return config.getBoolean("above-bedrock-nether-building", false);
}
@Override
public BungeeMetricsInfo getMetrics() {
return metricsInfo;
@ -202,4 +232,9 @@ public class GeyserBungeeConfiguration implements GeyserConfiguration {
return config.getString("metrics.uuid", "generateduuid");
}
}
@Override
public int getConfigVersion() {
return config.getInt("config-version", 0);
}
}

View file

@ -0,0 +1,180 @@
/*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*
*/
package org.geysermc.platform.bungeecord;
import lombok.AllArgsConstructor;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.ServerPing;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.config.ListenerInfo;
import net.md_5.bungee.api.connection.PendingConnection;
import net.md_5.bungee.api.event.ProxyPingEvent;
import net.md_5.bungee.api.plugin.Listener;
import net.md_5.bungee.protocol.ProtocolConstants;
import org.geysermc.common.ping.GeyserPingInfo;
import org.geysermc.connector.ping.IGeyserPingPassthrough;
import java.net.Inet4Address;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.Arrays;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
@AllArgsConstructor
public class GeyserBungeePingPassthrough implements IGeyserPingPassthrough, Listener {
private static final GeyserPendingConnection PENDING_CONNECTION = new GeyserPendingConnection();
private final ProxyServer proxyServer;
@Override
public GeyserPingInfo getPingInformation() {
CompletableFuture<ProxyPingEvent> future = new CompletableFuture<>();
proxyServer.getPluginManager().callEvent(new ProxyPingEvent(PENDING_CONNECTION, getPingInfo(), (event, throwable) -> {
if (throwable != null) future.completeExceptionally(throwable);
else future.complete(event);
}));
ProxyPingEvent event = future.join();
GeyserPingInfo geyserPingInfo = new GeyserPingInfo(
event.getResponse().getDescription(),
event.getResponse().getPlayers().getOnline(),
event.getResponse().getPlayers().getMax()
);
if (event.getResponse().getPlayers().getSample() != null) {
Arrays.stream(event.getResponse().getPlayers().getSample()).forEach(proxiedPlayer -> {
geyserPingInfo.addPlayer(proxiedPlayer.getName());
});
}
return geyserPingInfo;
}
// This is static so pending connection can use it
private static ListenerInfo getDefaultListener() {
return ProxyServer.getInstance().getConfig().getListeners().iterator().next();
}
private ServerPing getPingInfo() {
return new ServerPing(
new ServerPing.Protocol(proxyServer.getName() + " " + proxyServer.getGameVersion(), ProtocolConstants.SUPPORTED_VERSION_IDS.get(ProtocolConstants.SUPPORTED_VERSION_IDS.size() - 1)),
new ServerPing.Players(getDefaultListener().getMaxPlayers(), proxyServer.getOnlineCount(), null),
getDefaultListener().getMotd(), proxyServer.getConfig().getFaviconObject()
);
}
private static class GeyserPendingConnection implements PendingConnection {
private static final UUID FAKE_UUID = UUID.nameUUIDFromBytes("geyser!internal".getBytes());
private static final InetSocketAddress FAKE_REMOTE = new InetSocketAddress(Inet4Address.getLoopbackAddress(), 69);
@Override
public String getName() {
throw new UnsupportedOperationException();
}
@Override
public int getVersion() {
return ProtocolConstants.SUPPORTED_VERSION_IDS.get(ProtocolConstants.SUPPORTED_VERSION_IDS.size() - 1);
}
@Override
public InetSocketAddress getVirtualHost() {
return null;
}
@Override
public ListenerInfo getListener() {
return getDefaultListener();
}
@Override
public String getUUID() {
return FAKE_UUID.toString();
}
@Override
public UUID getUniqueId() {
return FAKE_UUID;
}
@Override
public void setUniqueId(UUID uuid) {
throw new UnsupportedOperationException();
}
@Override
public boolean isOnlineMode() {
return true;
}
@Override
public void setOnlineMode(boolean b) {
throw new UnsupportedOperationException();
}
@Override
public boolean isLegacy() {
return false;
}
@Override
public InetSocketAddress getAddress() {
return FAKE_REMOTE;
}
@Override
public SocketAddress getSocketAddress() {
return getAddress();
}
@Override
public void disconnect(String s) {
throw new UnsupportedOperationException();
}
@Override
public void disconnect(BaseComponent... baseComponents) {
throw new UnsupportedOperationException();
}
@Override
public void disconnect(BaseComponent baseComponent) {
throw new UnsupportedOperationException();
}
@Override
public boolean isConnected() {
return false;
}
@Override
public Unsafe unsafe() {
throw new UnsupportedOperationException();
}
}
}

View file

@ -31,9 +31,12 @@ import net.md_5.bungee.config.Configuration;
import net.md_5.bungee.config.ConfigurationProvider;
import net.md_5.bungee.config.YamlConfiguration;
import org.geysermc.common.PlatformType;
import org.geysermc.connector.GeyserConfiguration;
import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.bootstrap.GeyserBootstrap;
import org.geysermc.connector.command.CommandManager;
import org.geysermc.connector.ping.GeyserLegacyPingPassthrough;
import org.geysermc.connector.ping.IGeyserPingPassthrough;
import org.geysermc.platform.bungeecord.command.GeyserBungeeCommandExecutor;
import org.geysermc.platform.bungeecord.command.GeyserBungeeCommandManager;
@ -50,6 +53,7 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap {
private GeyserBungeeCommandManager geyserCommandManager;
private GeyserBungeeConfiguration geyserConfig;
private GeyserBungeeLogger geyserLogger;
private IGeyserPingPassthrough geyserBungeePingPassthrough;
private GeyserConnector connector;
@ -91,7 +95,7 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap {
// Don't change the ip if its listening on all interfaces
// By default this should be 127.0.0.1 but may need to be changed in some circumstances
if (!javaAddr.getHostString().equals("0.0.0.0")) {
if (!javaAddr.getHostString().equals("0.0.0.0") && !javaAddr.getHostString().equals("")) {
configuration.set("remote.address", javaAddr.getHostString());
}
@ -116,6 +120,7 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap {
}
this.geyserLogger = new GeyserBungeeLogger(getLogger(), geyserConfig.isDebugMode());
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
geyserConfig.loadFloodgate(this);
@ -123,6 +128,12 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap {
this.geyserCommandManager = new GeyserBungeeCommandManager(connector);
if (geyserConfig.isLegacyPingPassthrough()) {
this.geyserBungeePingPassthrough = GeyserLegacyPingPassthrough.init(connector);
} else {
this.geyserBungeePingPassthrough = new GeyserBungeePingPassthrough(getProxy());
}
this.getProxy().getPluginManager().registerCommand(this, new GeyserBungeeCommandExecutor(connector));
}
@ -145,4 +156,9 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap {
public CommandManager getGeyserCommandManager() {
return this.geyserCommandManager;
}
@Override
public IGeyserPingPassthrough getGeyserPingPassthrough() {
return geyserBungeePingPassthrough;
}
}

View file

@ -80,8 +80,28 @@ public class GeyserSpongeConfiguration implements GeyserConfiguration {
}
@Override
public boolean isPingPassthrough() {
return node.getNode("ping-passthrough").getBoolean(false);
public boolean isCommandSuggestions() {
return node.getNode("command-suggestions").getBoolean(true);
}
@Override
public boolean isPassthroughMotd() {
return node.getNode("passthrough-motd").getBoolean(false);
}
@Override
public boolean isPassthroughPlayerCounts() {
return node.getNode("passthrough-player-counts").getBoolean(false);
}
@Override
public boolean isLegacyPingPassthrough() {
return node.getNode("legacy-ping-passthrough").getBoolean(false);
}
@Override
public int getPingPassthroughInterval() {
return node.getNode("ping-passthrough-interval").getInt(3);
}
@Override
@ -104,6 +124,11 @@ public class GeyserSpongeConfiguration implements GeyserConfiguration {
return node.getNode("allow-third-party-capes").getBoolean(true);
}
@Override
public boolean isAllowThirdPartyEars() {
return node.getNode("allow-third-party-ears").getBoolean(false);
}
@Override
public String getDefaultLocale() {
return node.getNode("default-locale").getString("en_us");
@ -119,6 +144,11 @@ public class GeyserSpongeConfiguration implements GeyserConfiguration {
return node.getNode("cache-chunks").getBoolean(false);
}
@Override
public boolean isAboveBedrockNetherBuilding() {
return node.getNode("above-bedrock-nether-building").getBoolean(false);
}
@Override
public SpongeMetricsInfo getMetrics() {
return metricsInfo;
@ -202,4 +232,9 @@ public class GeyserSpongeConfiguration implements GeyserConfiguration {
return node.getNode("metrics").getNode("uuid").getString("generateduuid");
}
}
@Override
public int getConfigVersion() {
return node.getNode("config-version").getInt(0);
}
}

View file

@ -0,0 +1,99 @@
/*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*
*/
package org.geysermc.platform.sponge;
import org.geysermc.common.ping.GeyserPingInfo;
import org.geysermc.connector.ping.IGeyserPingPassthrough;
import org.spongepowered.api.MinecraftVersion;
import org.spongepowered.api.Sponge;
import org.spongepowered.api.event.SpongeEventFactory;
import org.spongepowered.api.event.cause.Cause;
import org.spongepowered.api.event.cause.EventContext;
import org.spongepowered.api.event.server.ClientPingServerEvent;
import org.spongepowered.api.network.status.StatusClient;
import java.lang.reflect.Method;
import java.net.Inet4Address;
import java.net.InetSocketAddress;
import java.util.Optional;
public class GeyserSpongePingPassthrough implements IGeyserPingPassthrough {
private static final GeyserStatusClient STATUS_CLIENT = new GeyserStatusClient();
private static final Cause CAUSE = Cause.of(EventContext.empty(), Sponge.getServer());
private static Method SpongeStatusResponse_create;
@SuppressWarnings({"unchecked", "rawtypes"})
@Override
public GeyserPingInfo getPingInformation() {
// come on Sponge, this is in commons, why not expose it :(
ClientPingServerEvent event;
try {
if(SpongeStatusResponse_create == null) {
Class SpongeStatusResponse = Class.forName("org.spongepowered.common.network.status.SpongeStatusResponse");
Class MinecraftServer = Class.forName("net.minecraft.server.MinecraftServer");
SpongeStatusResponse_create = SpongeStatusResponse.getDeclaredMethod("create", MinecraftServer);
}
Object response = SpongeStatusResponse_create.invoke(null, Sponge.getServer());
event = SpongeEventFactory.createClientPingServerEvent(CAUSE, STATUS_CLIENT, (ClientPingServerEvent.Response) response);
} catch (ReflectiveOperationException e) {
throw new RuntimeException(e);
}
Sponge.getEventManager().post(event);
GeyserPingInfo geyserPingInfo = new GeyserPingInfo(
event.getResponse().getDescription().toPlain(),
event.getResponse().getPlayers().orElseThrow(IllegalStateException::new).getOnline(),
event.getResponse().getPlayers().orElseThrow(IllegalStateException::new).getMax());
event.getResponse().getPlayers().get().getProfiles().forEach(player -> {
geyserPingInfo.addPlayer(player.getName().orElseThrow(IllegalStateException::new));
});
return geyserPingInfo;
}
@SuppressWarnings("NullableProblems")
private static class GeyserStatusClient implements StatusClient {
private static final InetSocketAddress FAKE_REMOTE = new InetSocketAddress(Inet4Address.getLoopbackAddress(), 69);
@Override
public InetSocketAddress getAddress() {
return FAKE_REMOTE;
}
@Override
public MinecraftVersion getVersion() {
return Sponge.getPlatform().getMinecraftVersion();
}
@Override
public Optional<InetSocketAddress> getVirtualHost() {
return Optional.empty();
}
}
}

View file

@ -30,9 +30,12 @@ import ninja.leaping.configurate.ConfigurationNode;
import ninja.leaping.configurate.loader.ConfigurationLoader;
import ninja.leaping.configurate.yaml.YAMLConfigurationLoader;
import org.geysermc.common.PlatformType;
import org.geysermc.connector.GeyserConfiguration;
import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.bootstrap.GeyserBootstrap;
import org.geysermc.connector.command.CommandManager;
import org.geysermc.connector.ping.GeyserLegacyPingPassthrough;
import org.geysermc.connector.ping.IGeyserPingPassthrough;
import org.geysermc.connector.utils.FileUtils;
import org.geysermc.platform.sponge.command.GeyserSpongeCommandExecutor;
import org.geysermc.platform.sponge.command.GeyserSpongeCommandManager;
@ -62,6 +65,7 @@ public class GeyserSpongePlugin implements GeyserBootstrap {
private GeyserSpongeCommandManager geyserCommandManager;
private GeyserSpongeConfiguration geyserConfig;
private GeyserSpongeLogger geyserLogger;
private IGeyserPingPassthrough geyserSpongePingPassthrough;
private GeyserConnector connector;
@ -97,7 +101,7 @@ public class GeyserSpongePlugin implements GeyserBootstrap {
// Don't change the ip if its listening on all interfaces
// By default this should be 127.0.0.1 but may need to be changed in some circumstances
if (!javaAddr.getHostString().equals("0.0.0.0")) {
if (!javaAddr.getHostString().equals("0.0.0.0") && !javaAddr.getHostString().equals("")) {
serverIP.setValue("127.0.0.1");
}
@ -105,9 +109,16 @@ public class GeyserSpongePlugin implements GeyserBootstrap {
}
this.geyserLogger = new GeyserSpongeLogger(logger, geyserConfig.isDebugMode());
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
this.connector = GeyserConnector.start(PlatformType.SPONGE, this);
this.geyserCommandManager = new GeyserSpongeCommandManager(Sponge.getCommandManager(), connector);
if (geyserConfig.isLegacyPingPassthrough()) {
this.geyserSpongePingPassthrough = GeyserLegacyPingPassthrough.init(connector);
} else {
this.geyserSpongePingPassthrough = new GeyserSpongePingPassthrough();
}
this.geyserCommandManager = new GeyserSpongeCommandManager(Sponge.getCommandManager(), connector);
Sponge.getCommandManager().register(this, new GeyserSpongeCommandExecutor(connector), "geyser");
}
@ -131,6 +142,11 @@ public class GeyserSpongePlugin implements GeyserBootstrap {
return this.geyserCommandManager;
}
@Override
public IGeyserPingPassthrough getGeyserPingPassthrough() {
return geyserSpongePingPassthrough;
}
@Listener
public void onServerStart(GameStartedServerEvent event) {
onEnable();

View file

@ -26,10 +26,12 @@
package org.geysermc.platform.standalone;
import org.geysermc.common.PlatformType;
import org.geysermc.connector.ping.GeyserLegacyPingPassthrough;
import org.geysermc.connector.GeyserConfiguration;
import org.geysermc.connector.bootstrap.GeyserBootstrap;
import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.command.CommandManager;
import org.geysermc.connector.ping.IGeyserPingPassthrough;
import org.geysermc.connector.utils.FileUtils;
import org.geysermc.platform.standalone.command.GeyserCommandManager;
@ -40,8 +42,9 @@ import java.util.UUID;
public class GeyserStandaloneBootstrap implements GeyserBootstrap {
private GeyserCommandManager geyserCommandManager;
private GeyserConfiguration geyserConfig;
private GeyserStandaloneConfiguration geyserConfig;
private GeyserStandaloneLogger geyserLogger;
private IGeyserPingPassthrough geyserPingPassthrough;
private GeyserConnector connector;
@ -62,9 +65,13 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap {
geyserLogger.severe("Failed to read/create config.yml! Make sure it's up to date and/or readable+writable!", ex);
System.exit(0);
}
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
connector = GeyserConnector.start(PlatformType.STANDALONE, this);
geyserCommandManager = new GeyserCommandManager(connector);
geyserPingPassthrough = GeyserLegacyPingPassthrough.init(connector);
geyserLogger.start();
}
@ -88,4 +95,9 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap {
public CommandManager getGeyserCommandManager() {
return geyserCommandManager;
}
@Override
public IGeyserPingPassthrough getGeyserPingPassthrough() {
return geyserPingPassthrough;
}
}

View file

@ -47,8 +47,20 @@ public class GeyserStandaloneConfiguration implements GeyserConfiguration {
private Map<String, UserAuthenticationInfo> userAuths;
@JsonProperty("ping-passthrough")
private boolean pingPassthrough;
@JsonProperty("command-suggestions")
private boolean isCommandSuggestions;
@JsonProperty("passthrough-motd")
private boolean isPassthroughMotd;
@JsonProperty("passthrough-player-counts")
private boolean isPassthroughPlayerCounts;
@JsonProperty("legacy-ping-passthrough")
private boolean isLegacyPingPassthrough;
@JsonProperty("ping-passthrough-interval")
private int pingPassthroughInterval;
@JsonProperty("max-players")
private int maxPlayers;
@ -62,12 +74,18 @@ public class GeyserStandaloneConfiguration implements GeyserConfiguration {
@JsonProperty("allow-third-party-capes")
private boolean allowThirdPartyCapes;
@JsonProperty("allow-third-party-ears")
private boolean allowThirdPartyEars;
@JsonProperty("default-locale")
private String defaultLocale;
@JsonProperty("cache-chunks")
private boolean cacheChunks;
@JsonProperty("above-bedrock-nether-building")
private boolean isAboveBedrockNetherBuilding;
private MetricsInfo metrics;
@Override
@ -112,4 +130,7 @@ public class GeyserStandaloneConfiguration implements GeyserConfiguration {
@JsonProperty("uuid")
private String uniqueId;
}
@JsonProperty("config-version")
private int configVersion;
}

View file

@ -52,8 +52,20 @@ public class GeyserVelocityConfiguration implements GeyserConfiguration {
private Map<String, UserAuthenticationInfo> userAuths;
@JsonProperty("ping-passthrough")
private boolean pingPassthrough;
@JsonProperty("command-suggestions")
private boolean commandSuggestions;
@JsonProperty("passthrough-motd")
private boolean isPassthroughMotd;
@JsonProperty("passthrough-player-counts")
private boolean isPassthroughPlayerCounts;
@JsonProperty("legacy-ping-passthrough")
private boolean isLegacyPingPassthrough;
@JsonProperty("ping-passthrough-interval")
private int pingPassthroughInterval;
@JsonProperty("max-players")
private int maxPlayers;
@ -67,19 +79,25 @@ public class GeyserVelocityConfiguration implements GeyserConfiguration {
@JsonProperty("allow-third-party-capes")
private boolean allowThirdPartyCapes;
@JsonProperty("allow-third-party-ears")
private boolean allowThirdPartyEars;
@JsonProperty("default-locale")
private String defaultLocale;
@JsonProperty("cache-chunks")
private boolean cacheChunks;
@JsonProperty("above-bedrock-nether-building")
private boolean aboveBedrockNetherBuilding;
private MetricsInfo metrics;
private Path floodgateKey;
public void loadFloodgate(GeyserVelocityPlugin plugin, ProxyServer proxyServer, File dataFolder) {
Optional<PluginContainer> floodgate = proxyServer.getPluginManager().getPlugin("floodgate");
floodgateKey = FloodgateKeyLoader.getKey(plugin.getGeyserLogger(), this, Paths.get(dataFolder.toString(), floodgateKeyFile.isEmpty() ? floodgateKeyFile : "public-key.pem"), floodgate.get(), Paths.get("plugins/floodgate/"));
floodgate.ifPresent(it -> floodgateKey = FloodgateKeyLoader.getKey(plugin.getGeyserLogger(), this, Paths.get(dataFolder.toString(), floodgateKeyFile.isEmpty() ? floodgateKeyFile : "public-key.pem"), it, Paths.get("plugins/floodgate/")));
}
@Override
@ -127,4 +145,7 @@ public class GeyserVelocityConfiguration implements GeyserConfiguration {
@JsonProperty("uuid")
private String uniqueId;
}
@JsonProperty("config-version")
private int configVersion;
}

View file

@ -0,0 +1,98 @@
/*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*
*/
package org.geysermc.platform.velocity;
import com.velocitypowered.api.event.proxy.ProxyPingEvent;
import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.api.proxy.InboundConnection;
import com.velocitypowered.api.proxy.ProxyServer;
import com.velocitypowered.api.proxy.server.ServerPing;
import lombok.AllArgsConstructor;
import net.kyori.text.TextComponent;
import net.kyori.text.serializer.legacy.LegacyComponentSerializer;
import org.geysermc.common.ping.GeyserPingInfo;
import org.geysermc.connector.ping.IGeyserPingPassthrough;
import java.net.Inet4Address;
import java.net.InetSocketAddress;
import java.util.Optional;
import java.util.concurrent.ExecutionException;
@AllArgsConstructor
public class GeyserVelocityPingPassthrough implements IGeyserPingPassthrough {
private static final GeyserInboundConnection FAKE_INBOUND_CONNECTION = new GeyserInboundConnection();
private final ProxyServer server;
@Override
public GeyserPingInfo getPingInformation() {
ProxyPingEvent event;
try {
event = server.getEventManager().fire(new ProxyPingEvent(FAKE_INBOUND_CONNECTION, ServerPing.builder()
.description(server.getConfiguration().getMotdComponent()).onlinePlayers(server.getPlayerCount())
.maximumPlayers(server.getConfiguration().getShowMaxPlayers()).build())).get();
} catch (ExecutionException | InterruptedException e) {
throw new RuntimeException(e);
}
GeyserPingInfo geyserPingInfo = new GeyserPingInfo(
LegacyComponentSerializer.INSTANCE.serialize(event.getPing().getDescription(), '§'),
event.getPing().getPlayers().orElseThrow(IllegalStateException::new).getOnline(),
event.getPing().getPlayers().orElseThrow(IllegalStateException::new).getMax()
);
event.getPing().getPlayers().get().getSample().forEach(player -> {
geyserPingInfo.addPlayer(player.getName());
});
return geyserPingInfo;
}
private static class GeyserInboundConnection implements InboundConnection {
private static final InetSocketAddress FAKE_REMOTE = new InetSocketAddress(Inet4Address.getLoopbackAddress(), 69);
@Override
public InetSocketAddress getRemoteAddress() {
return FAKE_REMOTE;
}
@Override
public Optional<InetSocketAddress> getVirtualHost() {
return Optional.empty();
}
@Override
public boolean isActive() {
return false;
}
@Override
public ProtocolVersion getProtocolVersion() {
return ProtocolVersion.MAXIMUM_VERSION;
}
}
}

View file

@ -35,8 +35,11 @@ import com.velocitypowered.api.plugin.Plugin;
import com.velocitypowered.api.proxy.ProxyServer;
import org.geysermc.common.PlatformType;
import org.geysermc.connector.GeyserConfiguration;
import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.bootstrap.GeyserBootstrap;
import org.geysermc.connector.ping.GeyserLegacyPingPassthrough;
import org.geysermc.connector.ping.IGeyserPingPassthrough;
import org.geysermc.connector.utils.FileUtils;
import org.geysermc.platform.velocity.command.GeyserVelocityCommandExecutor;
import org.geysermc.platform.velocity.command.GeyserVelocityCommandManager;
@ -62,6 +65,7 @@ public class GeyserVelocityPlugin implements GeyserBootstrap {
private GeyserVelocityCommandManager geyserCommandManager;
private GeyserVelocityConfiguration geyserConfig;
private GeyserVelocityLogger geyserLogger;
private IGeyserPingPassthrough geyserPingPassthrough;
private GeyserConnector connector;
@ -83,13 +87,14 @@ public class GeyserVelocityPlugin implements GeyserBootstrap {
// Don't change the ip if its listening on all interfaces
// By default this should be 127.0.0.1 but may need to be changed in some circumstances
if (!javaAddr.getHostString().equals("0.0.0.0")) {
if (!javaAddr.getHostString().equals("0.0.0.0") && !javaAddr.getHostString().equals("")) {
geyserConfig.getRemote().setAddress(javaAddr.getHostString());
}
geyserConfig.getRemote().setPort(javaAddr.getPort());
this.geyserLogger = new GeyserVelocityLogger(logger, geyserConfig.isDebugMode());
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
geyserConfig.loadFloodgate(this, proxyServer, configDir);
@ -97,6 +102,11 @@ public class GeyserVelocityPlugin implements GeyserBootstrap {
this.geyserCommandManager = new GeyserVelocityCommandManager(connector);
this.commandManager.register(new GeyserVelocityCommandExecutor(connector), "geyser");
if (geyserConfig.isLegacyPingPassthrough()) {
this.geyserPingPassthrough = GeyserLegacyPingPassthrough.init(connector);
} else {
this.geyserPingPassthrough = new GeyserVelocityPingPassthrough(proxyServer);
}
}
@Override
@ -119,6 +129,11 @@ public class GeyserVelocityPlugin implements GeyserBootstrap {
return this.geyserCommandManager;
}
@Override
public IGeyserPingPassthrough getGeyserPingPassthrough() {
return geyserPingPassthrough;
}
@Subscribe
public void onInit(ProxyInitializeEvent event) {
onEnable();