mirror of
https://github.com/ViaVersion/ViaVersion.git
synced 2024-11-22 18:15:39 +01:00
Squash Velocity platform commits
incomplete velocity code untested velocity version detector update velocity module version Injecting, but not working facepalm Fix handler type Should work now will it work now? it works!!! fix npe in command tab completion Do not forward command to server implement server changing with different versions thanks @Leymooo Fix memory leaks maybe cleaner code? trying to port mainhandpatch, added todo fix version Use separated protocol version, add todo Trying to mitigate UserConnection#toServer concurrent issue port elytrapatch it works but horribly and needs a modification in velocity replace with a semaphore and EventLoop#submit Lock for incoming packets fix version remove some TODOs Listen to DisconnectEvent Relocate snakeyaml
This commit is contained in:
parent
7f77cbfd74
commit
4c07b6d28d
@ -12,7 +12,7 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public class BukkitConfigAPI extends Config implements ViaVersionConfig {
|
public class BukkitConfigAPI extends Config implements ViaVersionConfig {
|
||||||
private static List<String> UNSUPPORTED = Arrays.asList("bungee-ping-interval", "bungee-ping-save", "bungee-servers");
|
private static List<String> UNSUPPORTED = Arrays.asList("bungee-ping-interval", "bungee-ping-save", "bungee-servers", "velocity-ping-interval", "velocity-ping-save", "velocity-servers");
|
||||||
|
|
||||||
public BukkitConfigAPI() {
|
public BukkitConfigAPI() {
|
||||||
super(new File(((ViaVersionPlugin) Via.getPlatform()).getDataFolder(), "config.yml"));
|
super(new File(((ViaVersionPlugin) Via.getPlatform()).getDataFolder(), "config.yml"));
|
||||||
|
@ -10,7 +10,7 @@ import java.net.URL;
|
|||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
public class BungeeConfigAPI extends Config implements ViaVersionConfig {
|
public class BungeeConfigAPI extends Config implements ViaVersionConfig {
|
||||||
private static List<String> UNSUPPORTED = Arrays.asList("nms-player-ticking", "item-cache", "anti-xray-patch", "quick-move-action-fix");
|
private static List<String> UNSUPPORTED = Arrays.asList("nms-player-ticking", "item-cache", "anti-xray-patch", "quick-move-action-fix", "velocity-ping-interval", "velocity-ping-save", "velocity-servers");
|
||||||
|
|
||||||
public BungeeConfigAPI(File configFile) {
|
public BungeeConfigAPI(File configFile) {
|
||||||
super(new File(configFile, "config.yml"));
|
super(new File(configFile, "config.yml"));
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
<groupId>org.yaml</groupId>
|
<groupId>org.yaml</groupId>
|
||||||
<artifactId>snakeyaml</artifactId>
|
<artifactId>snakeyaml</artifactId>
|
||||||
<version>1.18</version>
|
<version>1.18</version>
|
||||||
<scope>provided</scope>
|
<scope>compile</scope> <!-- Velocity doesn't have snakeyaml -->
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
@ -18,6 +18,8 @@ import us.myles.ViaVersion.util.PipelineUtil;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.locks.ReadWriteLock;
|
||||||
|
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class UserConnection {
|
public class UserConnection {
|
||||||
@ -36,7 +38,7 @@ public class UserConnection {
|
|||||||
// Used for handling warnings (over time)
|
// Used for handling warnings (over time)
|
||||||
private int secondsObserved = 0;
|
private int secondsObserved = 0;
|
||||||
private int warnings = 0;
|
private int warnings = 0;
|
||||||
|
private ReadWriteLock velocityLock = new ReentrantReadWriteLock();
|
||||||
|
|
||||||
public UserConnection(Channel channel) {
|
public UserConnection(Channel channel) {
|
||||||
this.channel = channel;
|
this.channel = channel;
|
||||||
@ -108,7 +110,8 @@ public class UserConnection {
|
|||||||
*/
|
*/
|
||||||
public ChannelFuture sendRawPacketFuture(final ByteBuf packet) {
|
public ChannelFuture sendRawPacketFuture(final ByteBuf packet) {
|
||||||
final ChannelHandler handler = channel.pipeline().get(Via.getManager().getInjector().getEncoderName());
|
final ChannelHandler handler = channel.pipeline().get(Via.getManager().getInjector().getEncoderName());
|
||||||
return channel.pipeline().context(handler).writeAndFlush(packet);
|
ChannelFuture future = channel.pipeline().context(handler).writeAndFlush(packet);
|
||||||
|
return future;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -218,7 +221,8 @@ public class UserConnection {
|
|||||||
}
|
}
|
||||||
buf.writeBytes(packet);
|
buf.writeBytes(packet);
|
||||||
packet.release();
|
packet.release();
|
||||||
final ChannelHandlerContext context = PipelineUtil.getPreviousContext(Via.getManager().getInjector().getDecoderName(), getChannel().pipeline());
|
final ChannelHandlerContext context = PipelineUtil
|
||||||
|
.getPreviousContext(Via.getManager().getInjector().getDecoderName(), getChannel().pipeline());
|
||||||
if (currentThread) {
|
if (currentThread) {
|
||||||
if (context != null) {
|
if (context != null) {
|
||||||
context.fireChannelRead(buf);
|
context.fireChannelRead(buf);
|
||||||
|
@ -74,7 +74,7 @@ public abstract class ViaCommandHandler implements ViaVersionCommand {
|
|||||||
|
|
||||||
//SubCommands tabcomplete
|
//SubCommands tabcomplete
|
||||||
if (args.length == 1) {
|
if (args.length == 1) {
|
||||||
if (!args[0].equals("")) {
|
if (!args[0].isEmpty()) {
|
||||||
for (ViaSubCommand sub : allowed)
|
for (ViaSubCommand sub : allowed)
|
||||||
if (sub.name().toLowerCase().startsWith(args[0].toLowerCase()))
|
if (sub.name().toLowerCase().startsWith(args[0].toLowerCase()))
|
||||||
output.add(sub.name());
|
output.add(sub.name());
|
||||||
|
@ -5,6 +5,8 @@ import io.netty.channel.ChannelHandlerContext;
|
|||||||
import io.netty.channel.ChannelPipeline;
|
import io.netty.channel.ChannelPipeline;
|
||||||
import io.netty.handler.codec.ByteToMessageDecoder;
|
import io.netty.handler.codec.ByteToMessageDecoder;
|
||||||
import io.netty.handler.codec.MessageToByteEncoder;
|
import io.netty.handler.codec.MessageToByteEncoder;
|
||||||
|
import io.netty.handler.codec.MessageToMessageDecoder;
|
||||||
|
import io.netty.handler.codec.MessageToMessageEncoder;
|
||||||
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
@ -14,6 +16,7 @@ import java.util.List;
|
|||||||
public class PipelineUtil {
|
public class PipelineUtil {
|
||||||
private static Method DECODE_METHOD;
|
private static Method DECODE_METHOD;
|
||||||
private static Method ENCODE_METHOD;
|
private static Method ENCODE_METHOD;
|
||||||
|
private static Method MTM_DECODE;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
try {
|
try {
|
||||||
@ -28,6 +31,12 @@ public class PipelineUtil {
|
|||||||
} catch (NoSuchMethodException e) {
|
} catch (NoSuchMethodException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
|
MTM_DECODE = MessageToMessageDecoder.class.getDeclaredMethod("decode", ChannelHandlerContext.class, Object.class, List.class);
|
||||||
|
MTM_DECODE.setAccessible(true);
|
||||||
|
} catch (NoSuchMethodException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -66,6 +75,16 @@ public class PipelineUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static List<Object> callDecode(MessageToMessageDecoder decoder, ChannelHandlerContext ctx, Object msg) throws InvocationTargetException {
|
||||||
|
List<Object> output = new ArrayList<>();
|
||||||
|
try {
|
||||||
|
MTM_DECODE.invoke(decoder, ctx, msg, output);
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if a stack trace contains a certain exception
|
* Check if a stack trace contains a certain exception
|
||||||
*
|
*
|
||||||
|
@ -46,6 +46,28 @@ bungee-ping-save: true
|
|||||||
bungee-servers: {}
|
bungee-servers: {}
|
||||||
#
|
#
|
||||||
#----------------------------------------------------------#
|
#----------------------------------------------------------#
|
||||||
|
# VELOCITY OPTIONS #
|
||||||
|
#----------------------------------------------------------#
|
||||||
|
#
|
||||||
|
# Velocity allows you to have different server versions inside.
|
||||||
|
# Instead of you entering all the versions of these servers, we can ping them.
|
||||||
|
#
|
||||||
|
# What interval would you like us to ping at? (in seconds)
|
||||||
|
# Use -1 to disable.
|
||||||
|
velocity-ping-interval: 60
|
||||||
|
# If the above is enabled, should we save the info to the config (in the section below)
|
||||||
|
velocity-ping-save: true
|
||||||
|
# To get a servers protocol, ViaVersion will do the following:
|
||||||
|
# Look for the server in the following section, then look for the last ping if velocity-ping is enabled
|
||||||
|
# otherwise use default.
|
||||||
|
#
|
||||||
|
# The format for the following is:
|
||||||
|
# servername: protocolversion
|
||||||
|
# You can find protocol ids on http://wiki.vg/Protocol_version_numbers
|
||||||
|
# It will fallback to the default option if none found.
|
||||||
|
velocity-servers: {}
|
||||||
|
#
|
||||||
|
#----------------------------------------------------------#
|
||||||
# GLOBAL PACKET LIMITER #
|
# GLOBAL PACKET LIMITER #
|
||||||
#----------------------------------------------------------#
|
#----------------------------------------------------------#
|
||||||
#
|
#
|
||||||
|
@ -57,6 +57,10 @@
|
|||||||
<pattern>org.javassist</pattern>
|
<pattern>org.javassist</pattern>
|
||||||
<shadedPattern>us.myles.viaversion.libs.javassist</shadedPattern>
|
<shadedPattern>us.myles.viaversion.libs.javassist</shadedPattern>
|
||||||
</relocation>
|
</relocation>
|
||||||
|
<relocation>
|
||||||
|
<pattern>org.yaml.snakeyaml</pattern>
|
||||||
|
<shadedPattern>us.myles.viaversion.libs.snakeyaml</shadedPattern>
|
||||||
|
</relocation>
|
||||||
</relocations>
|
</relocations>
|
||||||
</configuration>
|
</configuration>
|
||||||
<executions>
|
<executions>
|
||||||
@ -92,6 +96,11 @@
|
|||||||
<artifactId>viaversion-sponge</artifactId>
|
<artifactId>viaversion-sponge</artifactId>
|
||||||
<version>${project.parent.version}</version>
|
<version>${project.parent.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>us.myles</groupId>
|
||||||
|
<artifactId>viaversion-velocity</artifactId>
|
||||||
|
<version>${project.parent.version}</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
</project>
|
</project>
|
1
pom.xml
1
pom.xml
@ -21,6 +21,7 @@
|
|||||||
<module>bungee</module>
|
<module>bungee</module>
|
||||||
<module>sponge</module>
|
<module>sponge</module>
|
||||||
<module>sponge-legacy</module>
|
<module>sponge-legacy</module>
|
||||||
|
<module>velocity</module>
|
||||||
<module>jar</module>
|
<module>jar</module>
|
||||||
</modules>
|
</modules>
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ import java.util.Map;
|
|||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
public class SpongeConfigAPI extends Config implements ViaVersionConfig {
|
public class SpongeConfigAPI extends Config implements ViaVersionConfig {
|
||||||
private static List<String> UNSUPPORTED = Arrays.asList("anti-xray-patch", "bungee-ping-interval", "bungee-ping-save", "bungee-servers", "quick-move-action-fix");
|
private static List<String> UNSUPPORTED = Arrays.asList("anti-xray-patch", "bungee-ping-interval", "bungee-ping-save", "bungee-servers", "velocity-ping-interval", "velocity-ping-save", "velocity-servers", "quick-move-action-fix");
|
||||||
private final PluginContainer pluginContainer;
|
private final PluginContainer pluginContainer;
|
||||||
|
|
||||||
public SpongeConfigAPI(PluginContainer pluginContainer, File configFile) {
|
public SpongeConfigAPI(PluginContainer pluginContainer, File configFile) {
|
||||||
|
62
velocity/pom.xml
Normal file
62
velocity/pom.xml
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<parent>
|
||||||
|
<artifactId>viaversion-parent</artifactId>
|
||||||
|
<groupId>us.myles</groupId>
|
||||||
|
<version>1.6.1-18w43c</version>
|
||||||
|
</parent>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<artifactId>viaversion-velocity</artifactId>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<maven.compiler.source>1.8</maven.compiler.source>
|
||||||
|
<maven.compiler.target>1.8</maven.compiler.target>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<repositories>
|
||||||
|
<repository>
|
||||||
|
<id>velocity</id>
|
||||||
|
<url>https://repo.velocitypowered.com/snapshots</url>
|
||||||
|
</repository>
|
||||||
|
</repositories>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.codehaus.mojo</groupId>
|
||||||
|
<artifactId>templating-maven-plugin</artifactId>
|
||||||
|
<version>1.0.0</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>filter-src</id>
|
||||||
|
<goals>
|
||||||
|
<goal>filter-sources</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<!-- Common Module -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>us.myles</groupId>
|
||||||
|
<artifactId>viaversion-common</artifactId>
|
||||||
|
<version>${project.parent.version}</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Velocity API 1.0 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.velocitypowered</groupId>
|
||||||
|
<artifactId>velocity-api</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
</project>
|
@ -0,0 +1,5 @@
|
|||||||
|
package us.myles.ViaVersion.velocity;
|
||||||
|
|
||||||
|
public class VersionInfo {
|
||||||
|
public static final String VERSION = "${project.version}";
|
||||||
|
}
|
203
velocity/src/main/java/us/myles/ViaVersion/VelocityPlugin.java
Normal file
203
velocity/src/main/java/us/myles/ViaVersion/VelocityPlugin.java
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
package us.myles.ViaVersion;
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
import com.velocitypowered.api.event.Subscribe;
|
||||||
|
import com.velocitypowered.api.event.connection.DisconnectEvent;
|
||||||
|
import com.velocitypowered.api.event.proxy.ProxyInitializeEvent;
|
||||||
|
import com.velocitypowered.api.plugin.Plugin;
|
||||||
|
import com.velocitypowered.api.plugin.PluginContainer;
|
||||||
|
import com.velocitypowered.api.plugin.annotation.DataDirectory;
|
||||||
|
import com.velocitypowered.api.proxy.Player;
|
||||||
|
import com.velocitypowered.api.proxy.ProxyServer;
|
||||||
|
import lombok.Getter;
|
||||||
|
import net.kyori.text.serializer.ComponentSerializers;
|
||||||
|
import net.md_5.bungee.api.chat.TextComponent;
|
||||||
|
import net.md_5.bungee.chat.ComponentSerializer;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import us.myles.ViaVersion.api.Via;
|
||||||
|
import us.myles.ViaVersion.api.command.ViaCommandSender;
|
||||||
|
import us.myles.ViaVersion.api.configuration.ConfigurationProvider;
|
||||||
|
import us.myles.ViaVersion.api.data.UserConnection;
|
||||||
|
import us.myles.ViaVersion.api.platform.TaskId;
|
||||||
|
import us.myles.ViaVersion.api.platform.ViaPlatform;
|
||||||
|
import us.myles.ViaVersion.dump.PluginInfo;
|
||||||
|
import us.myles.ViaVersion.util.GsonUtil;
|
||||||
|
import us.myles.ViaVersion.velocity.VersionInfo;
|
||||||
|
import us.myles.ViaVersion.velocity.command.VelocityCommandHandler;
|
||||||
|
import us.myles.ViaVersion.velocity.command.VelocityCommandSender;
|
||||||
|
import us.myles.ViaVersion.velocity.platform.*;
|
||||||
|
import us.myles.ViaVersion.velocity.service.ProtocolDetectorService;
|
||||||
|
import us.myles.ViaVersion.velocity.util.LoggerWrapper;
|
||||||
|
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
@Plugin(
|
||||||
|
id = "viaversion",
|
||||||
|
name = "ViaVersion",
|
||||||
|
version = VersionInfo.VERSION,
|
||||||
|
authors = {"_MylesC", "Matsv"},
|
||||||
|
description = "Allow newer Minecraft versions to connect to an older server version.",
|
||||||
|
url = "https://viaversion.com"
|
||||||
|
)
|
||||||
|
@Getter
|
||||||
|
public class VelocityPlugin implements ViaPlatform<Player> {
|
||||||
|
@Inject
|
||||||
|
private ProxyServer proxy;
|
||||||
|
@Inject
|
||||||
|
public static ProxyServer PROXY;
|
||||||
|
@Inject
|
||||||
|
private Logger loggerslf4j;
|
||||||
|
private java.util.logging.Logger logger;
|
||||||
|
@Inject
|
||||||
|
@DataDirectory
|
||||||
|
private Path configDir;
|
||||||
|
private VelocityViaAPI api = new VelocityViaAPI();
|
||||||
|
private VelocityViaConfig conf;
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
public void onProxyInit(ProxyInitializeEvent e) {
|
||||||
|
PROXY = proxy;
|
||||||
|
VelocityCommandHandler commandHandler = new VelocityCommandHandler();
|
||||||
|
PROXY.getCommandManager().register(commandHandler, "viaver", "vvvelocity", "viaversion");
|
||||||
|
conf = new VelocityViaConfig(configDir.toFile());
|
||||||
|
logger = new LoggerWrapper(loggerslf4j);
|
||||||
|
Via.init(ViaManager.builder()
|
||||||
|
.platform(this)
|
||||||
|
.commandHandler(commandHandler)
|
||||||
|
.loader(new VelocityViaLoader())
|
||||||
|
.injector(new VelocityViaInjector()).build());
|
||||||
|
Via.getManager().init();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
public void onQuit(DisconnectEvent e) {
|
||||||
|
UserConnection userConnection = Via.getManager().getPortedPlayers().get(e.getPlayer().getUniqueId());
|
||||||
|
if (userConnection != null) {
|
||||||
|
// Only remove if the connection is disconnected (eg. relogin)
|
||||||
|
if (userConnection.getChannel() == null || !userConnection.getChannel().isOpen()) {
|
||||||
|
Via.getManager().removePortedClient(e.getPlayer().getUniqueId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPlatformName() {
|
||||||
|
return "Velocity";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPlatformVersion() {
|
||||||
|
return ProxyServer.class.getPackage().getImplementationVersion();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPluginVersion() {
|
||||||
|
return VersionInfo.VERSION;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TaskId runAsync(Runnable runnable) {
|
||||||
|
return runSync(runnable);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TaskId runSync(Runnable runnable) {
|
||||||
|
return runSync(runnable, 0L);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TaskId runSync(Runnable runnable, Long ticks) {
|
||||||
|
return new VelocityTaskId(
|
||||||
|
PROXY.getScheduler()
|
||||||
|
.buildTask(this, runnable)
|
||||||
|
.delay(ticks * 50, TimeUnit.MILLISECONDS).schedule()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TaskId runRepeatingSync(Runnable runnable, Long ticks) {
|
||||||
|
return new VelocityTaskId(
|
||||||
|
PROXY.getScheduler()
|
||||||
|
.buildTask(this, runnable)
|
||||||
|
.repeat(ticks * 50, TimeUnit.MILLISECONDS).schedule()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cancelTask(TaskId taskId) {
|
||||||
|
if (taskId instanceof VelocityTaskId) {
|
||||||
|
((VelocityTaskId) taskId).getObject().cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ViaCommandSender[] getOnlinePlayers() {
|
||||||
|
return PROXY.getAllPlayers().stream()
|
||||||
|
.map(VelocityCommandSender::new)
|
||||||
|
.toArray(ViaCommandSender[]::new);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendMessage(UUID uuid, String message) {
|
||||||
|
PROXY.getPlayer(uuid).ifPresent(it -> it.sendMessage(
|
||||||
|
ComponentSerializers.JSON.deserialize(
|
||||||
|
ComponentSerializer.toString(TextComponent.fromLegacyText(message)) // Fixes links
|
||||||
|
)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean kickPlayer(UUID uuid, String message) {
|
||||||
|
return PROXY.getPlayer(uuid).map(it -> {
|
||||||
|
it.disconnect(
|
||||||
|
ComponentSerializers.JSON.deserialize(
|
||||||
|
ComponentSerializer.toString(TextComponent.fromLegacyText(message)) // ComponentSerializers.LEGACY is deprecated
|
||||||
|
)
|
||||||
|
);
|
||||||
|
return true;
|
||||||
|
}).orElse(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isPluginEnabled() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConfigurationProvider getConfigurationProvider() {
|
||||||
|
return conf;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onReload() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JsonObject getDump() {
|
||||||
|
JsonObject extra = new JsonObject();
|
||||||
|
List<PluginInfo> plugins = new ArrayList<>();
|
||||||
|
for (PluginContainer p : PROXY.getPluginManager().getPlugins()) {
|
||||||
|
plugins.add(new PluginInfo(
|
||||||
|
true,
|
||||||
|
p.getDescription().getName().orElse(p.getDescription().getId()),
|
||||||
|
p.getDescription().getVersion().orElse("Unknown Version"),
|
||||||
|
p.getInstance().isPresent() ? p.getInstance().get().getClass().getCanonicalName() : "Unknown",
|
||||||
|
p.getDescription().getAuthors()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
extra.add("plugins", GsonUtil.getGson().toJsonTree(plugins));
|
||||||
|
extra.add("servers", GsonUtil.getGson().toJsonTree(ProtocolDetectorService.getDetectedIds()));
|
||||||
|
return extra;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isOldClientsAllowed() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
package us.myles.ViaVersion.velocity.command;
|
||||||
|
|
||||||
|
import com.velocitypowered.api.command.Command;
|
||||||
|
import com.velocitypowered.api.command.CommandSource;
|
||||||
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
import us.myles.ViaVersion.commands.ViaCommandHandler;
|
||||||
|
import us.myles.ViaVersion.velocity.command.subs.ProbeSubCmd;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class VelocityCommandHandler extends ViaCommandHandler implements Command {
|
||||||
|
public VelocityCommandHandler() {
|
||||||
|
try {
|
||||||
|
registerSubCommand(new ProbeSubCmd());
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(@NonNull CommandSource source, String[] args) {
|
||||||
|
onCommand(new VelocityCommandSender(source), args);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> suggest(@NonNull CommandSource source, String[] currentArgs) {
|
||||||
|
return onTabComplete(new VelocityCommandSender(source), currentArgs);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,46 @@
|
|||||||
|
package us.myles.ViaVersion.velocity.command;
|
||||||
|
|
||||||
|
import com.velocitypowered.api.command.CommandSource;
|
||||||
|
import com.velocitypowered.api.proxy.Player;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import net.kyori.text.serializer.ComponentSerializers;
|
||||||
|
import net.md_5.bungee.api.chat.TextComponent;
|
||||||
|
import net.md_5.bungee.chat.ComponentSerializer;
|
||||||
|
import us.myles.ViaVersion.api.command.ViaCommandSender;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class VelocityCommandSender implements ViaCommandSender {
|
||||||
|
private CommandSource source;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasPermission(String permission) {
|
||||||
|
return source.hasPermission(permission);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendMessage(String msg) {
|
||||||
|
source.sendMessage(
|
||||||
|
ComponentSerializers.JSON.deserialize(
|
||||||
|
ComponentSerializer.toString(TextComponent.fromLegacyText(msg)) // Fixes links
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UUID getUUID() {
|
||||||
|
if (source instanceof Player) {
|
||||||
|
return ((Player) source).getUniqueId();
|
||||||
|
}
|
||||||
|
return UUID.fromString(getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
if (source instanceof Player) {
|
||||||
|
return ((Player) source).getUsername();
|
||||||
|
}
|
||||||
|
return "?"; // :(
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
package us.myles.ViaVersion.velocity.command.subs;
|
||||||
|
|
||||||
|
import us.myles.ViaVersion.api.Via;
|
||||||
|
import us.myles.ViaVersion.api.command.ViaCommandSender;
|
||||||
|
import us.myles.ViaVersion.api.command.ViaSubCommand;
|
||||||
|
import us.myles.ViaVersion.velocity.platform.VelocityViaConfig;
|
||||||
|
import us.myles.ViaVersion.velocity.service.ProtocolDetectorService;
|
||||||
|
|
||||||
|
public class ProbeSubCmd extends ViaSubCommand {
|
||||||
|
@Override
|
||||||
|
public String name() {
|
||||||
|
return "probe";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String description() {
|
||||||
|
return "Forces ViaVersion to scan server protocol versions " +
|
||||||
|
(((VelocityViaConfig) Via.getConfig()).getVelocityPingInterval() == -1 ?
|
||||||
|
"" : "(Also happens at an interval)");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean execute(ViaCommandSender sender, String[] args) {
|
||||||
|
ProtocolDetectorService.getInstance().run();
|
||||||
|
sendMessage(sender, "&6Started searching for protocol versions");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
package us.myles.ViaVersion.velocity.handlers;
|
||||||
|
|
||||||
|
import io.netty.channel.Channel;
|
||||||
|
import io.netty.channel.ChannelInitializer;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import us.myles.ViaVersion.api.data.UserConnection;
|
||||||
|
import us.myles.ViaVersion.api.protocol.ProtocolPipeline;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class VelocityChannelInitializer extends ChannelInitializer {
|
||||||
|
@NonNull
|
||||||
|
private ChannelInitializer original;
|
||||||
|
private Method initChannel;
|
||||||
|
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
initChannel = ChannelInitializer.class.getDeclaredMethod("initChannel", Channel.class);
|
||||||
|
initChannel.setAccessible(true);
|
||||||
|
} catch (NoSuchMethodException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void initChannel(Channel channel) throws Exception {
|
||||||
|
initChannel.invoke(original, channel);
|
||||||
|
|
||||||
|
UserConnection user = new UserConnection(channel);
|
||||||
|
new ProtocolPipeline(user);
|
||||||
|
|
||||||
|
// We need to add a separated handler because Velocity uses pipeline().get(MINECRAFT_DECODER)
|
||||||
|
channel.pipeline().addBefore("minecraft-encoder", "via-encoder", new VelocityEncodeHandler(user));
|
||||||
|
channel.pipeline().addBefore("minecraft-decoder", "via-decoder", new VelocityDecodeHandler(user));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,78 @@
|
|||||||
|
package us.myles.ViaVersion.velocity.handlers;
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.channel.ChannelHandler;
|
||||||
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
|
import io.netty.handler.codec.MessageToMessageDecoder;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import us.myles.ViaVersion.api.PacketWrapper;
|
||||||
|
import us.myles.ViaVersion.api.data.UserConnection;
|
||||||
|
import us.myles.ViaVersion.api.type.Type;
|
||||||
|
import us.myles.ViaVersion.exception.CancelException;
|
||||||
|
import us.myles.ViaVersion.packets.Direction;
|
||||||
|
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
|
||||||
|
import us.myles.ViaVersion.util.PipelineUtil;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@ChannelHandler.Sharable
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class VelocityDecodeHandler extends MessageToMessageDecoder<ByteBuf> {
|
||||||
|
private final UserConnection info;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void decode(ChannelHandlerContext ctx, ByteBuf bytebuf, List<Object> out) throws Exception {
|
||||||
|
// use transformers
|
||||||
|
if (bytebuf.readableBytes() > 0) {
|
||||||
|
// Ignore if pending disconnect
|
||||||
|
if (info.isPendingDisconnect()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Increment received
|
||||||
|
boolean second = info.incrementReceived();
|
||||||
|
// Check PPS
|
||||||
|
if (second) {
|
||||||
|
if (info.handlePPS())
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
info.getVelocityLock().readLock().lock();
|
||||||
|
if (info.isActive()) {
|
||||||
|
// Handle ID
|
||||||
|
int id = Type.VAR_INT.read(bytebuf);
|
||||||
|
// Transform
|
||||||
|
ByteBuf newPacket = ctx.alloc().buffer();
|
||||||
|
try {
|
||||||
|
if (id == PacketWrapper.PASSTHROUGH_ID) {
|
||||||
|
newPacket.writeBytes(bytebuf);
|
||||||
|
} else {
|
||||||
|
PacketWrapper wrapper = new PacketWrapper(id, bytebuf, info);
|
||||||
|
ProtocolInfo protInfo = info.get(ProtocolInfo.class);
|
||||||
|
protInfo.getPipeline().transform(Direction.INCOMING, protInfo.getState(), wrapper);
|
||||||
|
wrapper.writeToBuffer(newPacket);
|
||||||
|
}
|
||||||
|
|
||||||
|
bytebuf.clear();
|
||||||
|
bytebuf = newPacket;
|
||||||
|
} catch (Exception e) {
|
||||||
|
// Clear Buffer
|
||||||
|
bytebuf.clear();
|
||||||
|
// Release Packet, be free!
|
||||||
|
newPacket.release();
|
||||||
|
info.getVelocityLock().readLock().unlock();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
bytebuf.retain();
|
||||||
|
}
|
||||||
|
info.getVelocityLock().readLock().unlock();
|
||||||
|
|
||||||
|
out.add(bytebuf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
||||||
|
if (PipelineUtil.containsCause(cause, CancelException.class)) return;
|
||||||
|
super.exceptionCaught(ctx, cause);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,90 @@
|
|||||||
|
package us.myles.ViaVersion.velocity.handlers;
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.channel.ChannelHandler;
|
||||||
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
|
import io.netty.handler.codec.MessageToByteEncoder;
|
||||||
|
import io.netty.handler.codec.MessageToMessageDecoder;
|
||||||
|
import io.netty.handler.codec.MessageToMessageEncoder;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import us.myles.ViaVersion.api.PacketWrapper;
|
||||||
|
import us.myles.ViaVersion.api.data.UserConnection;
|
||||||
|
import us.myles.ViaVersion.api.type.Type;
|
||||||
|
import us.myles.ViaVersion.exception.CancelException;
|
||||||
|
import us.myles.ViaVersion.packets.Direction;
|
||||||
|
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
|
||||||
|
import us.myles.ViaVersion.util.PipelineUtil;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@ChannelHandler.Sharable
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class VelocityEncodeHandler extends MessageToMessageEncoder<ByteBuf> {
|
||||||
|
@NonNull
|
||||||
|
private final UserConnection info;
|
||||||
|
private boolean handledCompression = false;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void encode(final ChannelHandlerContext ctx, ByteBuf bytebuf, List<Object> out) throws Exception {
|
||||||
|
if (bytebuf.readableBytes() == 0) {
|
||||||
|
throw new CancelException();
|
||||||
|
}
|
||||||
|
boolean needsCompress = false;
|
||||||
|
if (!handledCompression
|
||||||
|
&& ctx.pipeline().names().indexOf("compression-encoder") > ctx.pipeline().names().indexOf("via-encoder")) {
|
||||||
|
// Need to decompress this packet due to bad order
|
||||||
|
bytebuf = (ByteBuf) PipelineUtil.callDecode((MessageToMessageDecoder) ctx.pipeline().get("compression-decoder"), ctx, bytebuf).get(0);
|
||||||
|
ChannelHandler encoder = ctx.pipeline().get("via-encoder");
|
||||||
|
ChannelHandler decoder = ctx.pipeline().get("via-decoder");
|
||||||
|
ctx.pipeline().remove(encoder);
|
||||||
|
ctx.pipeline().remove(decoder);
|
||||||
|
ctx.pipeline().addAfter("compression-encoder", "via-encoder", encoder);
|
||||||
|
ctx.pipeline().addAfter("compression-decoder", "via-decoder", decoder);
|
||||||
|
needsCompress = true;
|
||||||
|
handledCompression = true;
|
||||||
|
} else {
|
||||||
|
bytebuf.retain();
|
||||||
|
}
|
||||||
|
// Increment sent
|
||||||
|
info.incrementSent();
|
||||||
|
|
||||||
|
|
||||||
|
if (info.isActive()) {
|
||||||
|
// Handle ID
|
||||||
|
int id = Type.VAR_INT.read(bytebuf);
|
||||||
|
// Transform
|
||||||
|
ByteBuf newPacket = bytebuf.alloc().buffer();
|
||||||
|
try {
|
||||||
|
PacketWrapper wrapper = new PacketWrapper(id, bytebuf, info);
|
||||||
|
ProtocolInfo protInfo = info.get(ProtocolInfo.class);
|
||||||
|
protInfo.getPipeline().transform(Direction.OUTGOING, protInfo.getState(), wrapper);
|
||||||
|
|
||||||
|
wrapper.writeToBuffer(newPacket);
|
||||||
|
|
||||||
|
bytebuf.clear();
|
||||||
|
bytebuf.release();
|
||||||
|
bytebuf = newPacket;
|
||||||
|
} catch (Exception e) {
|
||||||
|
bytebuf.clear();
|
||||||
|
bytebuf.release();
|
||||||
|
newPacket.release();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (needsCompress) {
|
||||||
|
ByteBuf old = bytebuf;
|
||||||
|
bytebuf = ctx.alloc().buffer();
|
||||||
|
PipelineUtil.callEncode((MessageToByteEncoder) ctx.pipeline().get("compression-encoder"), ctx, old, bytebuf);
|
||||||
|
old.release();
|
||||||
|
}
|
||||||
|
out.add(bytebuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
||||||
|
if (PipelineUtil.containsCause(cause, CancelException.class)) return;
|
||||||
|
super.exceptionCaught(ctx, cause);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,138 @@
|
|||||||
|
package us.myles.ViaVersion.velocity.handlers;
|
||||||
|
|
||||||
|
import com.velocitypowered.api.event.PostOrder;
|
||||||
|
import com.velocitypowered.api.event.Subscribe;
|
||||||
|
import com.velocitypowered.api.event.player.ServerConnectedEvent;
|
||||||
|
import com.velocitypowered.api.event.player.ServerPreConnectEvent;
|
||||||
|
import us.myles.ViaVersion.api.Pair;
|
||||||
|
import us.myles.ViaVersion.api.Via;
|
||||||
|
import us.myles.ViaVersion.api.boss.BossBar;
|
||||||
|
import us.myles.ViaVersion.api.data.UserConnection;
|
||||||
|
import us.myles.ViaVersion.api.protocol.Protocol;
|
||||||
|
import us.myles.ViaVersion.api.protocol.ProtocolPipeline;
|
||||||
|
import us.myles.ViaVersion.api.protocol.ProtocolRegistry;
|
||||||
|
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
|
||||||
|
import us.myles.ViaVersion.protocols.protocol1_9to1_8.storage.EntityTracker;
|
||||||
|
import us.myles.ViaVersion.util.ReflectionUtil;
|
||||||
|
import us.myles.ViaVersion.velocity.service.ProtocolDetectorService;
|
||||||
|
import us.myles.ViaVersion.velocity.storage.VelocityStorage;
|
||||||
|
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.Semaphore;
|
||||||
|
|
||||||
|
public class VelocityServerHandler {
|
||||||
|
private static Method setProtocolVersion;
|
||||||
|
private static Method setNextProtocolVersion;
|
||||||
|
|
||||||
|
static {
|
||||||
|
try {
|
||||||
|
setProtocolVersion = Class.forName("com.velocitypowered.proxy.connection.MinecraftConnection").getDeclaredMethod("setProtocolVersion", int.class);
|
||||||
|
setNextProtocolVersion = Class.forName("com.velocitypowered.proxy.connection.MinecraftConnection").getDeclaredMethod("setNextProtocolVersion", int.class);
|
||||||
|
} catch (NoSuchMethodException | ClassNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
public void preServerConnect(ServerPreConnectEvent e) {
|
||||||
|
try {
|
||||||
|
UserConnection user = Via.getManager().getConnection(e.getPlayer().getUniqueId());
|
||||||
|
if (user == null) return;
|
||||||
|
if (!user.has(VelocityStorage.class)) {
|
||||||
|
user.put(new VelocityStorage(user, e.getPlayer()));
|
||||||
|
}
|
||||||
|
|
||||||
|
int protocolId = ProtocolDetectorService.getProtocolId(e.getOriginalServer().getServerInfo().getName());
|
||||||
|
List<Pair<Integer, Protocol>> protocols = ProtocolRegistry.getProtocolPath(user.get(ProtocolInfo.class).getProtocolVersion(), protocolId);
|
||||||
|
|
||||||
|
// Check if ViaVersion can support that version
|
||||||
|
Object connection = ReflectionUtil.invoke(e.getPlayer(), "getConnection");
|
||||||
|
setNextProtocolVersion.invoke(connection, protocols == null ? user.get(ProtocolInfo.class).getProtocolVersion() : protocolId);
|
||||||
|
|
||||||
|
} catch (IllegalAccessException | NoSuchMethodException | InvocationTargetException e1) {
|
||||||
|
e1.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Subscribe(order = PostOrder.LATE)
|
||||||
|
public void connectedEvent(ServerConnectedEvent e) {
|
||||||
|
UserConnection user = Via.getManager().getConnection(e.getPlayer().getUniqueId());
|
||||||
|
try {
|
||||||
|
checkServerChange(e, Via.getManager().getConnection(e.getPlayer().getUniqueId()));
|
||||||
|
} catch (Exception e1) {
|
||||||
|
e1.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void checkServerChange(ServerConnectedEvent e, UserConnection user) throws Exception {
|
||||||
|
if (user == null) return;
|
||||||
|
// Manually hide ViaVersion-created BossBars if the childserver was version 1.8.x (#666)
|
||||||
|
if (user.has(EntityTracker.class)) {
|
||||||
|
EntityTracker tracker = user.get(EntityTracker.class);
|
||||||
|
|
||||||
|
if (tracker.getBossBarMap() != null)
|
||||||
|
for (BossBar bar : tracker.getBossBarMap().values())
|
||||||
|
bar.hide();
|
||||||
|
}
|
||||||
|
// Handle server/version change
|
||||||
|
if (user.has(VelocityStorage.class)) {
|
||||||
|
// Wait all the scheduled packets be sent
|
||||||
|
Semaphore semaphore = new Semaphore(1);
|
||||||
|
semaphore.acquireUninterruptibly();
|
||||||
|
user.getChannel().eventLoop().submit((Runnable) semaphore::release);
|
||||||
|
semaphore.acquireUninterruptibly();
|
||||||
|
semaphore.release();
|
||||||
|
|
||||||
|
user.getVelocityLock().writeLock().lock();
|
||||||
|
|
||||||
|
VelocityStorage storage = user.get(VelocityStorage.class);
|
||||||
|
|
||||||
|
if (e.getServer() != null) {
|
||||||
|
if (!e.getServer().getServerInfo().getName().equals(storage.getCurrentServer())) {
|
||||||
|
String serverName = e.getServer().getServerInfo().getName();
|
||||||
|
|
||||||
|
storage.setCurrentServer(serverName);
|
||||||
|
|
||||||
|
int protocolId = ProtocolDetectorService.getProtocolId(serverName);
|
||||||
|
|
||||||
|
ProtocolInfo info = user.get(ProtocolInfo.class);
|
||||||
|
|
||||||
|
// Refresh the pipes
|
||||||
|
List<Pair<Integer, Protocol>> protocols = ProtocolRegistry.getProtocolPath(info.getProtocolVersion(), protocolId);
|
||||||
|
ProtocolPipeline pipeline = user.get(ProtocolInfo.class).getPipeline();
|
||||||
|
user.clearStoredObjects();
|
||||||
|
pipeline.cleanPipes();
|
||||||
|
if (protocols == null) {
|
||||||
|
// TODO Check Bungee Supported Protocols? *shrugs*
|
||||||
|
protocolId = info.getProtocolVersion();
|
||||||
|
} else {
|
||||||
|
for (Pair<Integer, Protocol> prot : protocols) {
|
||||||
|
pipeline.add(prot.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
info.setServerProtocolVersion(protocolId);
|
||||||
|
// Add version-specific base Protocol
|
||||||
|
pipeline.add(ProtocolRegistry.getBaseProtocol(protocolId));
|
||||||
|
|
||||||
|
user.put(info);
|
||||||
|
user.put(storage);
|
||||||
|
|
||||||
|
user.setActive(protocols != null);
|
||||||
|
|
||||||
|
// Init all protocols TODO check if this can get moved up to the previous for loop, and doesn't require the pipeline to already exist.
|
||||||
|
for (Protocol protocol : pipeline.pipes()) {
|
||||||
|
protocol.init(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
Object connection = ReflectionUtil.invoke(e.getPlayer(), "getConnection");
|
||||||
|
int version = (int) ReflectionUtil.invoke(connection,"getNextProtocolVersion");
|
||||||
|
setProtocolVersion.invoke(ReflectionUtil.invoke(e.getPlayer(), "getConnection"), version);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
user.getVelocityLock().writeLock().unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,44 @@
|
|||||||
|
package us.myles.ViaVersion.velocity.listeners;
|
||||||
|
|
||||||
|
import com.velocitypowered.api.event.PostOrder;
|
||||||
|
import com.velocitypowered.api.event.Subscribe;
|
||||||
|
import com.velocitypowered.api.event.player.ServerConnectedEvent;
|
||||||
|
import us.myles.ViaVersion.api.PacketWrapper;
|
||||||
|
import us.myles.ViaVersion.api.Via;
|
||||||
|
import us.myles.ViaVersion.api.data.UserConnection;
|
||||||
|
import us.myles.ViaVersion.api.minecraft.metadata.Metadata;
|
||||||
|
import us.myles.ViaVersion.api.minecraft.metadata.types.MetaType1_9;
|
||||||
|
import us.myles.ViaVersion.api.type.Type;
|
||||||
|
import us.myles.ViaVersion.api.type.types.version.Types1_9;
|
||||||
|
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
|
||||||
|
import us.myles.ViaVersion.protocols.protocol1_9to1_8.Protocol1_9TO1_8;
|
||||||
|
import us.myles.ViaVersion.protocols.protocol1_9to1_8.storage.EntityTracker;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This patches https://github.com/MylesIsCool/ViaVersion/issues/555
|
||||||
|
*/
|
||||||
|
public class ElytraPatch {
|
||||||
|
|
||||||
|
@Subscribe(order = PostOrder.LAST)
|
||||||
|
public void onServerConnected(ServerConnectedEvent event) {
|
||||||
|
UserConnection user = Via.getManager().getConnection(event.getPlayer().getUniqueId());
|
||||||
|
if (user == null) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (user.get(ProtocolInfo.class).getPipeline().contains(Protocol1_9TO1_8.class)) {
|
||||||
|
int entityId = user.get(EntityTracker.class).getProvidedEntityId();
|
||||||
|
|
||||||
|
PacketWrapper wrapper = new PacketWrapper(0x39, null, user);
|
||||||
|
|
||||||
|
wrapper.write(Type.VAR_INT, entityId);
|
||||||
|
wrapper.write(Types1_9.METADATA_LIST, Collections.singletonList(new Metadata(0, MetaType1_9.Byte, (byte) 0)));
|
||||||
|
|
||||||
|
wrapper.send(Protocol1_9TO1_8.class);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,49 @@
|
|||||||
|
package us.myles.ViaVersion.velocity.listeners;
|
||||||
|
|
||||||
|
import com.velocitypowered.api.event.Subscribe;
|
||||||
|
import com.velocitypowered.api.event.player.ServerConnectedEvent;
|
||||||
|
import com.velocitypowered.api.proxy.player.PlayerSettings;
|
||||||
|
import us.myles.ViaVersion.api.Via;
|
||||||
|
import us.myles.ViaVersion.api.data.UserConnection;
|
||||||
|
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
|
||||||
|
import us.myles.ViaVersion.protocols.protocol1_9to1_8.Protocol1_9TO1_8;
|
||||||
|
import us.myles.ViaVersion.protocols.protocol1_9to1_8.storage.EntityTracker;
|
||||||
|
import us.myles.ViaVersion.util.ReflectionUtil;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
|
/*
|
||||||
|
This solves the wrong mainhand issue when you join with BungeeCord on a 1.8 server, and switch to a 1.9 or higher.
|
||||||
|
*/
|
||||||
|
public class MainHandPatch {
|
||||||
|
private static Method setSettings;
|
||||||
|
|
||||||
|
static {
|
||||||
|
try {
|
||||||
|
Class clientSettings = Class.forName("com.velocitypowered.proxy.protocol.packet.ClientSettings");
|
||||||
|
setSettings = Class.forName("com.velocitypowered.proxy.connection.client.ConnectedPlayer").getDeclaredMethod("setPlayerSettings", clientSettings);
|
||||||
|
setSettings.setAccessible(true);
|
||||||
|
} catch (ClassNotFoundException | NoSuchMethodException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
public void onServerConnect(ServerConnectedEvent event) {
|
||||||
|
UserConnection user = Via.getManager().getConnection(event.getPlayer().getUniqueId());
|
||||||
|
if (user == null || setSettings == null) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (user.get(ProtocolInfo.class).getPipeline().contains(Protocol1_9TO1_8.class)) {
|
||||||
|
PlayerSettings settings = event.getPlayer().getPlayerSettings();
|
||||||
|
if (user.has(EntityTracker.class)) {
|
||||||
|
Object clientSettings = ReflectionUtil.get(settings, "settings", Object.class);
|
||||||
|
ReflectionUtil.set(clientSettings, "mainHand", user.get(EntityTracker.class).getMainHand());
|
||||||
|
setSettings.invoke(event.getPlayer(), clientSettings);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
package us.myles.ViaVersion.velocity.listeners;
|
||||||
|
|
||||||
|
import com.velocitypowered.api.event.Subscribe;
|
||||||
|
import com.velocitypowered.api.event.connection.PostLoginEvent;
|
||||||
|
import us.myles.ViaVersion.api.Via;
|
||||||
|
import us.myles.ViaVersion.update.UpdateUtil;
|
||||||
|
|
||||||
|
public class UpdateListener {
|
||||||
|
@Subscribe
|
||||||
|
public void onJoin(PostLoginEvent e) {
|
||||||
|
if (e.getPlayer().hasPermission("viaversion.update")
|
||||||
|
&& Via.getConfig().isCheckForUpdates()) {
|
||||||
|
UpdateUtil.sendUpdateMessage(e.getPlayer().getUniqueId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
package us.myles.ViaVersion.velocity.platform;
|
||||||
|
|
||||||
|
import com.velocitypowered.api.proxy.Player;
|
||||||
|
import us.myles.ViaVersion.api.boss.BossBar;
|
||||||
|
import us.myles.ViaVersion.api.boss.BossColor;
|
||||||
|
import us.myles.ViaVersion.api.boss.BossStyle;
|
||||||
|
import us.myles.ViaVersion.boss.CommonBoss;
|
||||||
|
|
||||||
|
public class VelocityBossBar extends CommonBoss<Player> {
|
||||||
|
public VelocityBossBar(String title, float health, BossColor color, BossStyle style) {
|
||||||
|
super(title, health, color, style);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
package us.myles.ViaVersion.velocity.platform;
|
||||||
|
|
||||||
|
import com.velocitypowered.api.scheduler.ScheduledTask;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
import us.myles.ViaVersion.api.platform.TaskId;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class VelocityTaskId implements TaskId {
|
||||||
|
private ScheduledTask object;
|
||||||
|
}
|
@ -0,0 +1,78 @@
|
|||||||
|
package us.myles.ViaVersion.velocity.platform;
|
||||||
|
|
||||||
|
import com.velocitypowered.api.proxy.Player;
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import us.myles.ViaVersion.api.Via;
|
||||||
|
import us.myles.ViaVersion.api.ViaAPI;
|
||||||
|
import us.myles.ViaVersion.api.boss.BossBar;
|
||||||
|
import us.myles.ViaVersion.api.boss.BossColor;
|
||||||
|
import us.myles.ViaVersion.api.boss.BossStyle;
|
||||||
|
import us.myles.ViaVersion.api.data.UserConnection;
|
||||||
|
import us.myles.ViaVersion.api.protocol.ProtocolRegistry;
|
||||||
|
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.SortedSet;
|
||||||
|
import java.util.TreeSet;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class VelocityViaAPI implements ViaAPI<Player> {
|
||||||
|
@Override
|
||||||
|
public int getPlayerVersion(@NonNull Player player) {
|
||||||
|
if (!isPorted(player.getUniqueId()))
|
||||||
|
return ProtocolRegistry.SERVER_PROTOCOL;
|
||||||
|
return getPortedPlayers().get(player.getUniqueId()).get(ProtocolInfo.class).getProtocolVersion();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getPlayerVersion(@NonNull UUID uuid) {
|
||||||
|
if (!isPorted(uuid))
|
||||||
|
return ProtocolRegistry.SERVER_PROTOCOL;
|
||||||
|
return getPortedPlayers().get(uuid).get(ProtocolInfo.class).getProtocolVersion();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isPorted(UUID playerUUID) {
|
||||||
|
return getPortedPlayers().containsKey(playerUUID);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getVersion() {
|
||||||
|
return Via.getPlatform().getPluginVersion();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendRawPacket(UUID uuid, ByteBuf packet) throws IllegalArgumentException {
|
||||||
|
if (!isPorted(uuid)) throw new IllegalArgumentException("This player is not controlled by ViaVersion!");
|
||||||
|
UserConnection ci = getPortedPlayers().get(uuid);
|
||||||
|
ci.sendRawPacket(packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendRawPacket(Player player, ByteBuf packet) throws IllegalArgumentException {
|
||||||
|
sendRawPacket(player.getUniqueId(), packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BossBar createBossBar(String title, BossColor color, BossStyle style) {
|
||||||
|
return new VelocityBossBar(title, 1F, color, style);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BossBar createBossBar(String title, float health, BossColor color, BossStyle style) {
|
||||||
|
return new VelocityBossBar(title, health, color, style);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SortedSet<Integer> getSupportedVersions() {
|
||||||
|
SortedSet<Integer> outputSet = new TreeSet<>(ProtocolRegistry.getSupportedVersions());
|
||||||
|
outputSet.removeAll(Via.getPlatform().getConf().getBlockedProtocols());
|
||||||
|
|
||||||
|
return outputSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<UUID, UserConnection> getPortedPlayers() {
|
||||||
|
return Via.getManager().getPortedPlayers();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,275 @@
|
|||||||
|
package us.myles.ViaVersion.velocity.platform;
|
||||||
|
|
||||||
|
import us.myles.ViaVersion.api.ViaVersionConfig;
|
||||||
|
import us.myles.ViaVersion.api.protocol.ProtocolRegistry;
|
||||||
|
import us.myles.ViaVersion.api.protocol.ProtocolVersion;
|
||||||
|
import us.myles.ViaVersion.util.Config;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class VelocityViaConfig extends Config implements ViaVersionConfig {
|
||||||
|
private static List<String> UNSUPPORTED = Arrays.asList("nms-player-ticking", "item-cache", "anti-xray-patch", "quick-move-action-fix", "bungee-ping-interval", "bungee-ping-save", "bungee-servers");
|
||||||
|
|
||||||
|
public VelocityViaConfig(File configFile) {
|
||||||
|
super(new File(configFile, "config.yml"));
|
||||||
|
// Load config
|
||||||
|
reloadConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public URL getDefaultConfigURL() {
|
||||||
|
return getClass().getClassLoader().getResource("assets/viaversion/config.yml");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void handleConfig(Map<String, Object> config) {
|
||||||
|
// Parse servers
|
||||||
|
Map<String, Object> servers;
|
||||||
|
if (!(config.get("velocity-servers") instanceof Map)) {
|
||||||
|
servers = new HashMap<>();
|
||||||
|
} else {
|
||||||
|
servers = (Map) config.get("velocity-servers");
|
||||||
|
}
|
||||||
|
// Convert any bad Protocol Ids
|
||||||
|
for (Map.Entry<String, Object> entry : new HashSet<>(servers.entrySet())) {
|
||||||
|
if (!(entry.getValue() instanceof Integer)) {
|
||||||
|
if (entry.getValue() instanceof String) {
|
||||||
|
ProtocolVersion found = ProtocolVersion.getClosest((String) entry.getValue());
|
||||||
|
if (found != null) {
|
||||||
|
servers.put(entry.getKey(), found.getId());
|
||||||
|
} else {
|
||||||
|
servers.remove(entry.getKey()); // Remove!
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
servers.remove(entry.getKey()); // Remove!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Ensure default exists
|
||||||
|
if (!servers.containsKey("default")) {
|
||||||
|
servers.put("default", ProtocolRegistry.SERVER_PROTOCOL);
|
||||||
|
}
|
||||||
|
// Put back
|
||||||
|
config.put("velocity-servers", servers);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getUnsupportedOptions() {
|
||||||
|
return UNSUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isCheckForUpdates() {
|
||||||
|
return getBoolean("checkforupdates", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isPreventCollision() {
|
||||||
|
return getBoolean("prevent-collision", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isNewEffectIndicator() {
|
||||||
|
return getBoolean("use-new-effect-indicator", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isShowNewDeathMessages() {
|
||||||
|
return getBoolean("use-new-deathmessages", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSuppressMetadataErrors() {
|
||||||
|
return getBoolean("suppress-metadata-errors", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isShieldBlocking() {
|
||||||
|
return getBoolean("shield-blocking", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isHologramPatch() {
|
||||||
|
return getBoolean("hologram-patch", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isPistonAnimationPatch() {
|
||||||
|
return getBoolean("piston-animation-patch", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isBossbarPatch() {
|
||||||
|
return getBoolean("bossbar-patch", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isBossbarAntiflicker() {
|
||||||
|
return getBoolean("bossbar-anti-flicker", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isUnknownEntitiesSuppressed() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getHologramYOffset() {
|
||||||
|
return getDouble("hologram-y", -0.96D);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isBlockBreakPatch() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMaxPPS() {
|
||||||
|
return getInt("max-pps", 800);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getMaxPPSKickMessage() {
|
||||||
|
return getString("max-pps-kick-msg", "Sending packets too fast? lag?");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getTrackingPeriod() {
|
||||||
|
return getInt("tracking-period", 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getWarningPPS() {
|
||||||
|
return getInt("tracking-warning-pps", 120);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMaxWarnings() {
|
||||||
|
return getInt("tracking-max-warnings", 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getMaxWarningsKickMessage() {
|
||||||
|
return getString("tracking-max-kick-msg", "You are sending too many packets, :(");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAntiXRay() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSendSupportedVersions() {
|
||||||
|
return getBoolean("send-supported-versions", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isStimulatePlayerTick() {
|
||||||
|
return getBoolean("simulate-pt", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isItemCache() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isNMSPlayerTicking() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isReplacePistons() {
|
||||||
|
return getBoolean("replace-pistons", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getPistonReplacementId() {
|
||||||
|
return getInt("replacement-piston-id", 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isAutoTeam() {
|
||||||
|
// Collision has to be enabled first
|
||||||
|
return isPreventCollision() && getBoolean("auto-team", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isForceJsonTransform() {
|
||||||
|
return getBoolean("force-json-transform", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean is1_12NBTArrayFix() {
|
||||||
|
return getBoolean("chat-nbt-fix", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean is1_12QuickMoveActionFix() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Integer> getBlockedProtocols() {
|
||||||
|
return getIntegerList("block-protocols");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getBlockedDisconnectMsg() {
|
||||||
|
return getString("block-disconnect-msg", "You are using an unsupported Minecraft version!");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getReloadDisconnectMsg() {
|
||||||
|
return getString("reload-disconnect-msg", "Server reload, please rejoin!");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isMinimizeCooldown() {
|
||||||
|
return getBoolean("minimize-cooldown", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* What is the interval for checking servers via ping
|
||||||
|
* -1 for disabled
|
||||||
|
*
|
||||||
|
* @return Ping interval in seconds
|
||||||
|
*/
|
||||||
|
public int getVelocityPingInterval() {
|
||||||
|
return getInt("velocity-ping-interval", 60);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Should the velocity ping be saved to the config on change.
|
||||||
|
*
|
||||||
|
* @return True if it should save
|
||||||
|
*/
|
||||||
|
public boolean isVelocityPingSave() {
|
||||||
|
return getBoolean("velocity-ping-save", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the listed server protocols in the config.
|
||||||
|
* default will be listed as default.
|
||||||
|
*
|
||||||
|
* @return Map of String, Integer
|
||||||
|
*/
|
||||||
|
public Map<String, Integer> getVelocityServerProtocols() {
|
||||||
|
return get("velocity-servers", Map.class, new HashMap<>());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean is1_13TeamColourFix() {
|
||||||
|
return getBoolean("team-colour-fix", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSuppress1_13ConversionErrors() {
|
||||||
|
return getBoolean("suppress-1_13-conversion-errors", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isDisable1_13AutoComplete() {
|
||||||
|
return getBoolean("disable-1_13-auto-complete", false);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,41 @@
|
|||||||
|
package us.myles.ViaVersion.velocity.platform;
|
||||||
|
|
||||||
|
import io.netty.channel.ChannelInitializer;
|
||||||
|
import us.myles.ViaVersion.VelocityPlugin;
|
||||||
|
import us.myles.ViaVersion.api.Via;
|
||||||
|
import us.myles.ViaVersion.api.platform.ViaInjector;
|
||||||
|
import us.myles.ViaVersion.util.ReflectionUtil;
|
||||||
|
import us.myles.ViaVersion.velocity.handlers.VelocityChannelInitializer;
|
||||||
|
|
||||||
|
|
||||||
|
public class VelocityViaInjector implements ViaInjector {
|
||||||
|
@Override
|
||||||
|
public void inject() throws Exception {
|
||||||
|
Object connectionManager = ReflectionUtil.get(VelocityPlugin.PROXY, "cm", Object.class);
|
||||||
|
Object channelInitializerHolder = ReflectionUtil.invoke(connectionManager, "getServerChannelInitializer");
|
||||||
|
ChannelInitializer originalIntializer = (ChannelInitializer) ReflectionUtil.invoke(channelInitializerHolder, "get");
|
||||||
|
channelInitializerHolder.getClass().getMethod("set", ChannelInitializer.class)
|
||||||
|
.invoke(channelInitializerHolder, new VelocityChannelInitializer(originalIntializer));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void uninject() {
|
||||||
|
Via.getPlatform().getLogger().severe("ViaVersion cannot remove itself from Velocity without a reboot!");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getServerProtocolVersion() throws Exception {
|
||||||
|
return ReflectionUtil.getStatic(Class.forName("com.velocitypowered.proxy.protocol.ProtocolConstants"), "MINIMUM_GENERIC_VERSION", int.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getEncoderName() {
|
||||||
|
return "via-encoder";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDecoderName() {
|
||||||
|
return "via-decoder";
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,45 @@
|
|||||||
|
package us.myles.ViaVersion.velocity.platform;
|
||||||
|
|
||||||
|
import com.velocitypowered.api.plugin.PluginContainer;
|
||||||
|
import us.myles.ViaVersion.VelocityPlugin;
|
||||||
|
import us.myles.ViaVersion.api.Via;
|
||||||
|
import us.myles.ViaVersion.api.platform.ViaPlatformLoader;
|
||||||
|
import us.myles.ViaVersion.protocols.base.VersionProvider;
|
||||||
|
import us.myles.ViaVersion.protocols.protocol1_9to1_8.providers.BossBarProvider;
|
||||||
|
import us.myles.ViaVersion.protocols.protocol1_9to1_8.providers.MovementTransmitterProvider;
|
||||||
|
import us.myles.ViaVersion.velocity.handlers.VelocityServerHandler;
|
||||||
|
import us.myles.ViaVersion.velocity.listeners.ElytraPatch;
|
||||||
|
import us.myles.ViaVersion.velocity.listeners.MainHandPatch;
|
||||||
|
import us.myles.ViaVersion.velocity.listeners.UpdateListener;
|
||||||
|
import us.myles.ViaVersion.velocity.providers.VelocityBossBarProvider;
|
||||||
|
import us.myles.ViaVersion.velocity.providers.VelocityMovementTransmitter;
|
||||||
|
import us.myles.ViaVersion.velocity.providers.VelocityVersionProvider;
|
||||||
|
import us.myles.ViaVersion.velocity.service.ProtocolDetectorService;
|
||||||
|
|
||||||
|
public class VelocityViaLoader implements ViaPlatformLoader {
|
||||||
|
@Override
|
||||||
|
public void load() {
|
||||||
|
Object plugin = VelocityPlugin.PROXY.getPluginManager()
|
||||||
|
.getPlugin("viaversion").flatMap(PluginContainer::getInstance).get();
|
||||||
|
|
||||||
|
Via.getManager().getProviders().use(MovementTransmitterProvider.class, new VelocityMovementTransmitter());
|
||||||
|
Via.getManager().getProviders().use(BossBarProvider.class, new VelocityBossBarProvider());
|
||||||
|
Via.getManager().getProviders().use(VersionProvider.class, new VelocityVersionProvider());
|
||||||
|
// We probably don't need a EntityIdProvider because velocity sends a Join packet on server change
|
||||||
|
|
||||||
|
VelocityPlugin.PROXY.getEventManager().register(
|
||||||
|
plugin,
|
||||||
|
new UpdateListener());
|
||||||
|
Via.getPlatform().runRepeatingSync(
|
||||||
|
new ProtocolDetectorService(),
|
||||||
|
((VelocityViaConfig) Via.getPlatform().getConf()).getVelocityPingInterval() * 50L);
|
||||||
|
VelocityPlugin.PROXY.getEventManager().register(plugin, new VelocityServerHandler());
|
||||||
|
VelocityPlugin.PROXY.getEventManager().register(plugin, new MainHandPatch());
|
||||||
|
VelocityPlugin.PROXY.getEventManager().register(plugin, new ElytraPatch());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void unload() {
|
||||||
|
// Probably not useful, there's no ProxyReloadEvent
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
package us.myles.ViaVersion.velocity.providers;
|
||||||
|
|
||||||
|
import us.myles.ViaVersion.api.data.UserConnection;
|
||||||
|
import us.myles.ViaVersion.protocols.protocol1_9to1_8.providers.BossBarProvider;
|
||||||
|
import us.myles.ViaVersion.velocity.storage.VelocityStorage;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class VelocityBossBarProvider extends BossBarProvider {
|
||||||
|
@Override
|
||||||
|
public void handleAdd(UserConnection user, UUID barUUID) {
|
||||||
|
if (user.has(VelocityStorage.class)) {
|
||||||
|
VelocityStorage storage = user.get(VelocityStorage.class);
|
||||||
|
// Check if bossbars are supported by bungee, static maybe
|
||||||
|
if (storage.getBossbar() != null) {
|
||||||
|
storage.getBossbar().add(barUUID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleRemove(UserConnection user, UUID barUUID) {
|
||||||
|
if (user.has(VelocityStorage.class)) {
|
||||||
|
VelocityStorage storage = user.get(VelocityStorage.class);
|
||||||
|
if (storage.getBossbar() != null) {
|
||||||
|
storage.getBossbar().remove(barUUID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
package us.myles.ViaVersion.velocity.providers;
|
||||||
|
|
||||||
|
import us.myles.ViaVersion.api.PacketWrapper;
|
||||||
|
import us.myles.ViaVersion.api.data.UserConnection;
|
||||||
|
import us.myles.ViaVersion.api.type.Type;
|
||||||
|
import us.myles.ViaVersion.packets.State;
|
||||||
|
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
|
||||||
|
import us.myles.ViaVersion.protocols.protocol1_9to1_8.Protocol1_9TO1_8;
|
||||||
|
import us.myles.ViaVersion.protocols.protocol1_9to1_8.providers.MovementTransmitterProvider;
|
||||||
|
import us.myles.ViaVersion.protocols.protocol1_9to1_8.storage.MovementTracker;
|
||||||
|
|
||||||
|
public class VelocityMovementTransmitter extends MovementTransmitterProvider {
|
||||||
|
@Override
|
||||||
|
public Object getFlyingPacket() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getGroundPacket() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sendPlayer(UserConnection userConnection) {
|
||||||
|
if (userConnection.get(ProtocolInfo.class).getState() == State.PLAY) {
|
||||||
|
PacketWrapper wrapper = new PacketWrapper(0x03, null, userConnection);
|
||||||
|
wrapper.write(Type.BOOLEAN, userConnection.get(MovementTracker.class).isGround());
|
||||||
|
try {
|
||||||
|
wrapper.sendToServer(Protocol1_9TO1_8.class);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
// PlayerPackets will increment idle
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,73 @@
|
|||||||
|
package us.myles.ViaVersion.velocity.providers;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
import us.myles.ViaVersion.api.Via;
|
||||||
|
import us.myles.ViaVersion.api.data.UserConnection;
|
||||||
|
import us.myles.ViaVersion.api.protocol.ProtocolVersion;
|
||||||
|
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
|
||||||
|
import us.myles.ViaVersion.protocols.base.VersionProvider;
|
||||||
|
import us.myles.ViaVersion.util.ReflectionUtil;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class VelocityVersionProvider extends VersionProvider {
|
||||||
|
private static Class<?> ref ;
|
||||||
|
|
||||||
|
static {
|
||||||
|
try {
|
||||||
|
ref = Class.forName("com.velocitypowered.proxy.protocol.ProtocolConstants");
|
||||||
|
} catch (Exception e) {
|
||||||
|
Via.getPlatform().getLogger().severe("Could not detect the ProtocolConstants class");
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getServerProtocol(UserConnection user) throws Exception {
|
||||||
|
if (ref == null)
|
||||||
|
return super.getServerProtocol(user);
|
||||||
|
// TODO Have one constant list forever until restart? (Might limit plugins if they change this)
|
||||||
|
Object list = ReflectionUtil.getStatic(ref, "SUPPORTED_VERSIONS", Object.class);
|
||||||
|
List<Integer> sorted = new ArrayList<Integer>((List) ReflectionUtil.invoke(list, "asList"));
|
||||||
|
Collections.sort(sorted);
|
||||||
|
|
||||||
|
ProtocolInfo info = user.get(ProtocolInfo.class);
|
||||||
|
|
||||||
|
// Bungee supports it
|
||||||
|
if (sorted.contains(info.getProtocolVersion()))
|
||||||
|
return info.getProtocolVersion();
|
||||||
|
|
||||||
|
// Older than bungee supports, get the lowest version
|
||||||
|
if (info.getProtocolVersion() < sorted.get(0)) {
|
||||||
|
return getLowestSupportedVersion();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loop through all protocols to get the closest protocol id that bungee supports (and that viaversion does too)
|
||||||
|
|
||||||
|
// TODO: This needs a better fix, i.e checking ProtocolRegistry to see if it would work.
|
||||||
|
// This is more of a workaround for snapshot support by bungee.
|
||||||
|
for (Integer protocol : Lists.reverse(sorted)) {
|
||||||
|
if (info.getProtocolVersion() > protocol && ProtocolVersion.isRegistered(protocol))
|
||||||
|
return protocol;
|
||||||
|
}
|
||||||
|
|
||||||
|
Via.getPlatform().getLogger().severe("Panic, no protocol id found for " + info.getProtocolVersion());
|
||||||
|
return info.getProtocolVersion();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getLowestSupportedVersion() {
|
||||||
|
List<Integer> list;
|
||||||
|
try {
|
||||||
|
return ReflectionUtil.getStatic(
|
||||||
|
Class.forName("com.velocitypowered.proxy.protocol.ProtocolConstants"),
|
||||||
|
"MINIMUM_GENERIC_VERSION",
|
||||||
|
int.class);
|
||||||
|
} catch (NoSuchFieldException | IllegalAccessException | ClassNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
// Fallback
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,82 @@
|
|||||||
|
package us.myles.ViaVersion.velocity.service;
|
||||||
|
|
||||||
|
import com.velocitypowered.api.proxy.server.RegisteredServer;
|
||||||
|
import lombok.Getter;
|
||||||
|
import us.myles.ViaVersion.VelocityPlugin;
|
||||||
|
import us.myles.ViaVersion.api.Via;
|
||||||
|
import us.myles.ViaVersion.api.protocol.ProtocolVersion;
|
||||||
|
import us.myles.ViaVersion.velocity.platform.VelocityViaConfig;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
public class ProtocolDetectorService implements Runnable {
|
||||||
|
private static final Map<String, Integer> detectedProtocolIds = new ConcurrentHashMap<>();
|
||||||
|
@Getter
|
||||||
|
private static ProtocolDetectorService instance;
|
||||||
|
|
||||||
|
public ProtocolDetectorService() {
|
||||||
|
instance = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Integer getProtocolId(String serverName) {
|
||||||
|
// Step 1. Check Config
|
||||||
|
Map<String, Integer> servers = ((VelocityViaConfig) Via.getConfig()).getVelocityServerProtocols();
|
||||||
|
Integer protocol = servers.get(serverName);
|
||||||
|
if (protocol != null) {
|
||||||
|
return protocol;
|
||||||
|
}
|
||||||
|
// Step 2. Check Detected
|
||||||
|
Integer detectedProtocol = detectedProtocolIds.get(serverName);
|
||||||
|
if (detectedProtocol != null) {
|
||||||
|
return detectedProtocol;
|
||||||
|
}
|
||||||
|
// Step 3. Use Default
|
||||||
|
Integer defaultProtocol = servers.get("default");
|
||||||
|
if (defaultProtocol != null) {
|
||||||
|
return defaultProtocol;
|
||||||
|
}
|
||||||
|
// Step 4: Use bungee lowest supported... *cries*
|
||||||
|
try {
|
||||||
|
return Via.getManager().getInjector().getServerProtocolVersion();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return ProtocolVersion.v1_8.getId();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
for (final RegisteredServer serv : VelocityPlugin.PROXY.getAllServers()) {
|
||||||
|
probeServer(serv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void probeServer(final RegisteredServer serverInfo) {
|
||||||
|
final String key = serverInfo.getServerInfo().getName();
|
||||||
|
serverInfo.ping().thenAccept((serverPing) -> {
|
||||||
|
if (serverPing != null && serverPing.getVersion() != null) {
|
||||||
|
detectedProtocolIds.put(key, serverPing.getVersion().getProtocol());
|
||||||
|
if (((VelocityViaConfig) Via.getConfig()).isVelocityPingSave()) {
|
||||||
|
Map<String, Integer> servers = ((VelocityViaConfig) Via.getConfig()).getVelocityServerProtocols();
|
||||||
|
Integer protocol = servers.get(key);
|
||||||
|
if (protocol != null && protocol == serverPing.getVersion().getProtocol()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Ensure we're the only ones writing to the config
|
||||||
|
synchronized (Via.getPlatform().getConfigurationProvider()) {
|
||||||
|
servers.put(key, serverPing.getVersion().getProtocol());
|
||||||
|
}
|
||||||
|
// Save
|
||||||
|
Via.getPlatform().getConfigurationProvider().saveConfig();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Map<String, Integer> getDetectedIds() {
|
||||||
|
return new HashMap<>(detectedProtocolIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
package us.myles.ViaVersion.velocity.storage;
|
||||||
|
|
||||||
|
import com.velocitypowered.api.proxy.Player;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import us.myles.ViaVersion.api.data.StoredObject;
|
||||||
|
import us.myles.ViaVersion.api.data.UserConnection;
|
||||||
|
import us.myles.ViaVersion.util.ReflectionUtil;
|
||||||
|
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class VelocityStorage extends StoredObject {
|
||||||
|
private Player player;
|
||||||
|
private String currentServer;
|
||||||
|
private Set<UUID> bossbar;
|
||||||
|
|
||||||
|
public VelocityStorage(UserConnection user, Player player) {
|
||||||
|
super(user);
|
||||||
|
this.player = player;
|
||||||
|
this.currentServer = "";
|
||||||
|
|
||||||
|
// Get bossbar list if it's supported
|
||||||
|
try {
|
||||||
|
Object connection = ReflectionUtil.invoke(player, "getConnection");
|
||||||
|
Object sessionHandler = ReflectionUtil.invoke(connection, "getSessionHandler");
|
||||||
|
if (sessionHandler.getClass().getSimpleName().contains("Play")) {
|
||||||
|
bossbar = (Set<UUID>) ReflectionUtil.invoke(sessionHandler, "getServerBossBars");
|
||||||
|
// TODO make this work
|
||||||
|
}
|
||||||
|
} catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,69 @@
|
|||||||
|
package us.myles.ViaVersion.velocity.util;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
|
||||||
|
import java.text.MessageFormat;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.LogRecord;
|
||||||
|
|
||||||
|
public class LoggerWrapper extends java.util.logging.Logger {
|
||||||
|
private final Logger base;
|
||||||
|
|
||||||
|
public LoggerWrapper(Logger logger) {
|
||||||
|
super("logger", null);
|
||||||
|
this.base = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void log(LogRecord record) {
|
||||||
|
log(record.getLevel(), record.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void log(Level level, String msg) {
|
||||||
|
if (level == Level.FINE)
|
||||||
|
base.debug(msg);
|
||||||
|
else if (level == Level.WARNING)
|
||||||
|
base.warn(msg);
|
||||||
|
else if (level == Level.SEVERE)
|
||||||
|
base.error(msg);
|
||||||
|
else if (level == Level.INFO)
|
||||||
|
base.info(msg);
|
||||||
|
else
|
||||||
|
base.trace(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void log(Level level, String msg, Object param1) {
|
||||||
|
if (level == Level.FINE)
|
||||||
|
base.debug(msg, param1);
|
||||||
|
else if (level == Level.WARNING)
|
||||||
|
base.warn(msg, param1);
|
||||||
|
else if (level == Level.SEVERE)
|
||||||
|
base.error(msg, param1);
|
||||||
|
else if (level == Level.INFO)
|
||||||
|
base.info(msg, param1);
|
||||||
|
else
|
||||||
|
base.trace(msg, param1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void log(Level level, String msg, Object[] params) {
|
||||||
|
log(level, MessageFormat.format(msg, params)); // workaround not formatting correctly
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void log(Level level, String msg, Throwable params) {
|
||||||
|
if (level == Level.FINE)
|
||||||
|
base.debug(msg, params);
|
||||||
|
else if (level == Level.WARNING)
|
||||||
|
base.warn(msg, params);
|
||||||
|
else if (level == Level.SEVERE)
|
||||||
|
base.error(msg, params);
|
||||||
|
else if (level == Level.INFO)
|
||||||
|
base.info(msg, params);
|
||||||
|
else
|
||||||
|
base.trace(msg, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user