mirror of
https://github.com/ViaVersion/ViaVersion.git
synced 2024-11-26 03:55:28 +01:00
Add Sponge Support
This commit is contained in:
parent
a1fbca11f0
commit
b371c14a27
3
TODOLIST
3
TODOLIST
@ -1 +1,2 @@
|
||||
Handle injector errors
|
||||
PORT STUFF TO GUAVA :D (so we dont need to include commons)
|
||||
Test on SpongeForge, only tested SpongeVanilla
|
@ -16,12 +16,25 @@
|
||||
<bukkitVersion>1.8.8-R0.1-SNAPSHOT</bukkitVersion>
|
||||
</properties>
|
||||
|
||||
<build>
|
||||
<resources>
|
||||
<resource>
|
||||
<targetPath>.</targetPath>
|
||||
<filtering>true</filtering>
|
||||
<directory>src/main/resources/</directory>
|
||||
<includes>
|
||||
<include>*</include>
|
||||
</includes>
|
||||
</resource>
|
||||
</resources>
|
||||
</build>
|
||||
|
||||
<dependencies>
|
||||
<!-- Common Module -->
|
||||
<dependency>
|
||||
<groupId>us.myles</groupId>
|
||||
<artifactId>viaversion-common</artifactId>
|
||||
<version>${parent.version}</version>
|
||||
<version>${project.parent.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
|
@ -19,7 +19,6 @@ public class BukkitViaBulkChunkTranslator extends BulkChunkTranslatorProvider {
|
||||
|
||||
static {
|
||||
try {
|
||||
// TODO: Abstract this ?
|
||||
mapChunkBulkRef = new ReflectionUtil.ClassReflection(ReflectionUtil.nms("PacketPlayOutMapChunkBulk"));
|
||||
mapChunkRef = new ReflectionUtil.ClassReflection(ReflectionUtil.nms("PacketPlayOutMapChunk"));
|
||||
if (((ViaVersionPlugin) Via.getPlatform()).isSpigot()) {
|
||||
@ -74,7 +73,7 @@ public class BukkitViaBulkChunkTranslator extends BulkChunkTranslatorProvider {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return true;
|
||||
public boolean isFiltered(Class<?> packetClass) {
|
||||
return packetClass.getName().endsWith("PacketPlayOutMapChunkBulk");
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ package us.myles.ViaVersion.listeners;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import us.myles.ViaVersion.api.ViaVersion;
|
||||
import us.myles.ViaVersion.api.Via;
|
||||
import us.myles.ViaVersion.update.UpdateUtil;
|
||||
|
||||
public class UpdateListener implements Listener {
|
||||
@ -11,7 +11,7 @@ public class UpdateListener implements Listener {
|
||||
@EventHandler
|
||||
public void onJoin(PlayerJoinEvent e) {
|
||||
if (e.getPlayer().hasPermission("viaversion.update")
|
||||
&& ViaVersion.getConfig().isCheckForUpdates()) {
|
||||
&& Via.getConfig().isCheckForUpdates()) {
|
||||
UpdateUtil.sendUpdateMessage(e.getPlayer().getUniqueId());
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ name: ViaVersion
|
||||
main: us.myles.ViaVersion.ViaVersionPlugin
|
||||
authors: [_MylesC, Matsv]
|
||||
version: ${project.version}
|
||||
description: Allow newer Minecraft versions to connect to an older server version.
|
||||
load: postworld
|
||||
loadbefore: [ProtocolLib, ProxyPipe, SpigotLib, SkinRestorer]
|
||||
softdepend: [ProtocolSupport, PacketListenerApi]
|
||||
|
@ -11,6 +11,19 @@
|
||||
|
||||
<artifactId>viaversion-bungee</artifactId>
|
||||
|
||||
<build>
|
||||
<resources>
|
||||
<resource>
|
||||
<targetPath>.</targetPath>
|
||||
<filtering>true</filtering>
|
||||
<directory>src/main/resources/</directory>
|
||||
<includes>
|
||||
<include>*</include>
|
||||
</includes>
|
||||
</resource>
|
||||
</resources>
|
||||
</build>
|
||||
|
||||
<dependencies>
|
||||
<!-- BungeeCord -->
|
||||
<dependency>
|
||||
|
@ -91,9 +91,8 @@ public class Protocol1_9TO1_8 extends Protocol {
|
||||
|
||||
@Override
|
||||
public boolean isFiltered(Class packetClass) {
|
||||
if (!Via.getManager().getProviders().get(BulkChunkTranslatorProvider.class).isEnabled())
|
||||
return false;
|
||||
return packetClass.getName().endsWith("PacketPlayOutMapChunkBulk");
|
||||
return Via.getManager().getProviders().get(BulkChunkTranslatorProvider.class).isFiltered(packetClass);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -11,7 +11,7 @@ public class BulkChunkTranslatorProvider implements Provider {
|
||||
return Arrays.asList(packet);
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
public boolean isFiltered(Class<?> packet) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
17
jar/pom.xml
17
jar/pom.xml
@ -18,7 +18,7 @@
|
||||
<resource>
|
||||
<targetPath>.</targetPath>
|
||||
<filtering>false</filtering>
|
||||
<directory>.</directory>
|
||||
<directory>../</directory>
|
||||
<includes>
|
||||
<include>LICENSE</include>
|
||||
</includes>
|
||||
@ -57,6 +57,10 @@
|
||||
<pattern>org.javassist</pattern>
|
||||
<shadedPattern>us.myles.viaversion.libs.javassist</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>org.apache</pattern>
|
||||
<shadedPattern>us.myles.viaversion.libs.apache</shadedPattern>
|
||||
</relocation>
|
||||
</relocations>
|
||||
</configuration>
|
||||
<executions>
|
||||
@ -75,17 +79,22 @@
|
||||
<dependency>
|
||||
<groupId>us.myles</groupId>
|
||||
<artifactId>viaversion-common</artifactId>
|
||||
<version>${parent.version}</version>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>us.myles</groupId>
|
||||
<artifactId>viaversion-bukkit</artifactId>
|
||||
<version>${parent.version}</version>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>us.myles</groupId>
|
||||
<artifactId>viaversion-bungee</artifactId>
|
||||
<version>${parent.version}</version>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>us.myles</groupId>
|
||||
<artifactId>viaversion-sponge</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
3
pom.xml
3
pom.xml
@ -19,6 +19,7 @@
|
||||
<module>common</module>
|
||||
<module>bukkit</module>
|
||||
<module>bungee</module>
|
||||
<module>sponge</module>
|
||||
<module>jar</module>
|
||||
</modules>
|
||||
|
||||
@ -104,7 +105,7 @@
|
||||
<groupId>commons-lang</groupId>
|
||||
<artifactId>commons-lang</artifactId>
|
||||
<version>2.6</version>
|
||||
<scope>provided</scope>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- ChatColour API -->
|
||||
|
72
sponge/pom.xml
Normal file
72
sponge/pom.xml
Normal file
@ -0,0 +1,72 @@
|
||||
<?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.0.0-ALPHA-modules</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>viaversion-sponge</artifactId>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>1.8</maven.compiler.source>
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>sponge</id>
|
||||
<url>http://repo.spongepowered.org/maven</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<build>
|
||||
<resources>
|
||||
<resource>
|
||||
<targetPath>.</targetPath>
|
||||
<filtering>true</filtering>
|
||||
<directory>src/main/resources/</directory>
|
||||
<includes>
|
||||
<include>*</include>
|
||||
</includes>
|
||||
</resource>
|
||||
</resources>
|
||||
<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>
|
||||
|
||||
<!-- Sponge API -->
|
||||
<dependency>
|
||||
<groupId>org.spongepowered</groupId>
|
||||
<artifactId>spongeapi</artifactId>
|
||||
<version>4.1.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
@ -0,0 +1,5 @@
|
||||
package us.myles.ViaVersion.sponge;
|
||||
|
||||
public class VersionInfo {
|
||||
public static final String VERSION = "${project.version}";
|
||||
}
|
163
sponge/src/main/java/us/myles/ViaVersion/SpongePlugin.java
Normal file
163
sponge/src/main/java/us/myles/ViaVersion/SpongePlugin.java
Normal file
@ -0,0 +1,163 @@
|
||||
package us.myles.ViaVersion;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.inject.Inject;
|
||||
import org.spongepowered.api.Game;
|
||||
import org.spongepowered.api.entity.living.player.Player;
|
||||
import org.spongepowered.api.event.Listener;
|
||||
import org.spongepowered.api.event.game.state.GameStartedServerEvent;
|
||||
import org.spongepowered.api.plugin.Plugin;
|
||||
import org.spongepowered.api.plugin.PluginContainer;
|
||||
import org.spongepowered.api.scheduler.SpongeExecutorService;
|
||||
import org.spongepowered.api.text.serializer.TextSerializers;
|
||||
import us.myles.ViaVersion.api.Via;
|
||||
import us.myles.ViaVersion.api.ViaAPI;
|
||||
import us.myles.ViaVersion.api.ViaVersionConfig;
|
||||
import us.myles.ViaVersion.api.command.ViaCommandSender;
|
||||
import us.myles.ViaVersion.api.configuration.ConfigurationProvider;
|
||||
import us.myles.ViaVersion.api.platform.ViaPlatform;
|
||||
import us.myles.ViaVersion.sponge.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
@Plugin(id = "viaversion",
|
||||
name = "ViaVersion",
|
||||
version = VersionInfo.VERSION,
|
||||
authors = {"_MylesC", "Matsv"},
|
||||
description = "Allow newer Minecraft versions to connect to an older server version."
|
||||
)
|
||||
public class SpongePlugin implements ViaPlatform {
|
||||
@Inject
|
||||
private Game game;
|
||||
@Inject
|
||||
private PluginContainer container;
|
||||
|
||||
private SpongeExecutorService asyncExecutor;
|
||||
private SpongeExecutorService syncExecutor;
|
||||
private SpongeConfigAPI conf = new SpongeConfigAPI(this);
|
||||
private SpongeViaAPI api = new SpongeViaAPI();
|
||||
private Logger logger;
|
||||
|
||||
@Listener
|
||||
public void onServerStart(GameStartedServerEvent event) {
|
||||
// Setup Logger
|
||||
logger = new LoggerWrapper(container.getLogger());
|
||||
// Setup Plugin
|
||||
syncExecutor = game.getScheduler().createSyncExecutor(this);
|
||||
asyncExecutor = game.getScheduler().createAsyncExecutor(this);
|
||||
SpongeCommandHandler commandHandler = new SpongeCommandHandler();
|
||||
game.getCommandManager().register(this, commandHandler, Arrays.asList("viaversion", "viaver"));
|
||||
// Init platform
|
||||
Via.init(ViaManager.builder()
|
||||
.platform(this)
|
||||
.commandHandler(commandHandler)
|
||||
.injector(new SpongeViaInjector())
|
||||
.loader(new SpongeViaLoader(this))
|
||||
.build());
|
||||
|
||||
// Inject!
|
||||
Via.getManager().init();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Logger getLogger() {
|
||||
return logger;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPlatformName() {
|
||||
return "Sponge";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPluginVersion() {
|
||||
return container.getVersion().orElse("Unknown Version");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int runAsync(Runnable runnable) {
|
||||
asyncExecutor.execute(runnable);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int runSync(Runnable runnable) {
|
||||
syncExecutor.execute(runnable);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int runRepeatingSync(Runnable runnable, Long ticks) {
|
||||
Long time = ticks * 50L;
|
||||
syncExecutor.scheduleAtFixedRate(runnable, time, time, TimeUnit.MILLISECONDS);
|
||||
// use id?
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancelTask(int taskId) {
|
||||
// oh.
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViaCommandSender[] getOnlinePlayers() {
|
||||
ViaCommandSender[] array = new ViaCommandSender[game.getServer().getOnlinePlayers().size()];
|
||||
int i = 0;
|
||||
for (Player player : game.getServer().getOnlinePlayers()) {
|
||||
array[i++] = new SpongeCommandSender(player);
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMessage(UUID uuid, String message) {
|
||||
for (Player player : game.getServer().getOnlinePlayers()) {
|
||||
if (player.getUniqueId().equals(uuid))
|
||||
player.sendMessage(TextSerializers.LEGACY_FORMATTING_CODE.deserialize(message));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean kickPlayer(UUID uuid, String message) {
|
||||
for (Player player : game.getServer().getOnlinePlayers()) {
|
||||
if (player.getUniqueId().equals(uuid)) {
|
||||
player.kick(TextSerializers.LEGACY_FORMATTING_CODE.deserialize(message));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPluginEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViaAPI getApi() {
|
||||
return api;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViaVersionConfig getConf() {
|
||||
return conf;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigurationProvider getConfigurationProvider() {
|
||||
return conf;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReload() {
|
||||
// TODO: Warning?
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonObject getDump() {
|
||||
return new JsonObject();
|
||||
}
|
||||
}
|
@ -0,0 +1,125 @@
|
||||
package us.myles.ViaVersion.sponge;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
|
||||
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.FINEST) {
|
||||
base.trace(msg);
|
||||
return;
|
||||
}
|
||||
if (level == Level.FINE) {
|
||||
base.debug(msg);
|
||||
return;
|
||||
}
|
||||
if (level == Level.WARNING) {
|
||||
base.warn(msg);
|
||||
return;
|
||||
}
|
||||
if (level == Level.SEVERE) {
|
||||
base.error(msg);
|
||||
return;
|
||||
}
|
||||
if (level == Level.INFO) {
|
||||
base.info(msg);
|
||||
return;
|
||||
}
|
||||
base.trace(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(Level level, String msg, Object param1) {
|
||||
if (level == Level.FINEST) {
|
||||
base.trace(msg, param1);
|
||||
return;
|
||||
}
|
||||
if (level == Level.FINE) {
|
||||
base.debug(msg, param1);
|
||||
return;
|
||||
}
|
||||
if (level == Level.WARNING) {
|
||||
base.warn(msg, param1);
|
||||
return;
|
||||
}
|
||||
if (level == Level.SEVERE) {
|
||||
base.error(msg, param1);
|
||||
return;
|
||||
}
|
||||
if (level == Level.INFO) {
|
||||
base.info(msg, param1);
|
||||
return;
|
||||
}
|
||||
base.trace(msg, param1);
|
||||
return;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(Level level, String msg, Object[] params) {
|
||||
if (level == Level.FINEST) {
|
||||
base.trace(msg, params);
|
||||
return;
|
||||
}
|
||||
if (level == Level.FINE) {
|
||||
base.debug(msg, params);
|
||||
return;
|
||||
}
|
||||
if (level == Level.WARNING) {
|
||||
base.warn(msg, params);
|
||||
return;
|
||||
}
|
||||
if (level == Level.SEVERE) {
|
||||
base.error(msg, params);
|
||||
return;
|
||||
}
|
||||
if (level == Level.INFO) {
|
||||
base.info(msg, params);
|
||||
return;
|
||||
}
|
||||
base.trace(msg, params);
|
||||
return;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(Level level, String msg, Throwable params) {
|
||||
if (level == Level.FINEST) {
|
||||
base.trace(msg, params);
|
||||
return;
|
||||
}
|
||||
if (level == Level.FINE) {
|
||||
base.debug(msg, params);
|
||||
return;
|
||||
}
|
||||
if (level == Level.WARNING) {
|
||||
base.warn(msg, params);
|
||||
return;
|
||||
}
|
||||
if (level == Level.SEVERE) {
|
||||
base.error(msg, params);
|
||||
return;
|
||||
}
|
||||
if (level == Level.INFO) {
|
||||
base.info(msg, params);
|
||||
return;
|
||||
}
|
||||
base.trace(msg, params);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package us.myles.ViaVersion.sponge;
|
||||
|
||||
import lombok.Getter;
|
||||
import org.spongepowered.api.entity.living.player.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;
|
||||
|
||||
@Getter
|
||||
public class SpongeBossBar extends CommonBoss<Player> {
|
||||
|
||||
public SpongeBossBar(String title, float health, BossColor color, BossStyle style) {
|
||||
super(title, health, color, style);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BossBar addPlayer(Player player) {
|
||||
addPlayer(player.getUniqueId());
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BossBar addPlayers(Player... players) {
|
||||
for (Player p : players)
|
||||
addPlayer(p);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BossBar removePlayer(Player player) {
|
||||
removePlayer(player.getUniqueId());
|
||||
return this;
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
package us.myles.ViaVersion.sponge;
|
||||
|
||||
import org.spongepowered.api.command.CommandCallable;
|
||||
import org.spongepowered.api.command.CommandException;
|
||||
import org.spongepowered.api.command.CommandResult;
|
||||
import org.spongepowered.api.command.CommandSource;
|
||||
import org.spongepowered.api.text.Text;
|
||||
import us.myles.ViaVersion.commands.ViaCommandHandler;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public class SpongeCommandHandler extends ViaCommandHandler implements CommandCallable {
|
||||
|
||||
@Override
|
||||
public CommandResult process(CommandSource source, String arguments) throws CommandException {
|
||||
String[] args = arguments.length() > 0 ? arguments.split(" ") : new String[0];
|
||||
onCommand(new SpongeCommandSender(source), args);
|
||||
return CommandResult.success();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getSuggestions(CommandSource source, String arguments) throws CommandException {
|
||||
String[] args = arguments.length() > 0 ? arguments.split(" ") : new String[0];
|
||||
return onTabComplete(new SpongeCommandSender(source), args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean testPermission(CommandSource source) {
|
||||
return source.hasPermission("viaversion.admin");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<? extends Text> getShortDescription(CommandSource source) {
|
||||
return Optional.of(Text.of("Shows ViaVersion Version and more."));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<? extends Text> getHelp(CommandSource source) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Text getUsage(CommandSource source) {
|
||||
return Text.of("Usage /viaversion");
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
package us.myles.ViaVersion.sponge;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.spongepowered.api.command.CommandSource;
|
||||
import org.spongepowered.api.entity.living.player.Player;
|
||||
import org.spongepowered.api.text.serializer.TextSerializer;
|
||||
import org.spongepowered.api.text.serializer.TextSerializers;
|
||||
import us.myles.ViaVersion.api.command.ViaCommandSender;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
@AllArgsConstructor
|
||||
public class SpongeCommandSender implements ViaCommandSender {
|
||||
private CommandSource source;
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(String permission) {
|
||||
return source.hasPermission(permission);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMessage(String msg) {
|
||||
source.sendMessage(TextSerializers.LEGACY_FORMATTING_CODE.deserialize(msg));
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID getUUID() {
|
||||
if (source instanceof Player) {
|
||||
return ((Player) source).getUniqueId();
|
||||
} else {
|
||||
return UUID.fromString(getName());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return source.getName();
|
||||
}
|
||||
}
|
@ -0,0 +1,183 @@
|
||||
package us.myles.ViaVersion.sponge;
|
||||
|
||||
import us.myles.ViaVersion.SpongePlugin;
|
||||
import us.myles.ViaVersion.api.ViaVersionConfig;
|
||||
import us.myles.ViaVersion.api.configuration.ConfigurationProvider;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class SpongeConfigAPI implements ViaVersionConfig, ConfigurationProvider{
|
||||
private final SpongePlugin spongePlugin;
|
||||
|
||||
public SpongeConfigAPI(SpongePlugin spongePlugin) {
|
||||
this.spongePlugin = spongePlugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCheckForUpdates() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPreventCollision() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNewEffectIndicator() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isShowNewDeathMessages() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSuppressMetadataErrors() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isShieldBlocking() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isHologramPatch() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBossbarPatch() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBossbarAntiflicker() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUnknownEntitiesSuppressed() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getHologramYOffset() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAutoTeam() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBlockBreakPatch() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxPPS() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMaxPPSKickMessage() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTrackingPeriod() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWarningPPS() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxWarnings() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMaxWarningsKickMessage() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAntiXRay() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSendSupportedVersions() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isStimulatePlayerTick() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isItemCache() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNMSPlayerTicking() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReplacePistons() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPistonReplacementId() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isForceJsonTransform() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Integer> getBlockedProtocols() {
|
||||
return Arrays.asList(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBlockedDisconnectMsg() {
|
||||
return "Boop";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getReloadDisconnectMsg() {
|
||||
return "Beep";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(String path, Object value) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveConfig() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getValues() {
|
||||
return new HashMap<>();
|
||||
}
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
package us.myles.ViaVersion.sponge;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.NonNull;
|
||||
import org.spongepowered.api.entity.living.player.Player;
|
||||
import us.myles.ViaVersion.SpongePlugin;
|
||||
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 SpongeViaAPI 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 SpongeBossBar(title, 1F, color, style);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BossBar createBossBar(String title, float health, BossColor color, BossStyle style) {
|
||||
return new SpongeBossBar(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,197 @@
|
||||
package us.myles.ViaVersion.sponge;
|
||||
|
||||
import io.netty.channel.ChannelFuture;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
import us.myles.ViaVersion.api.Pair;
|
||||
import us.myles.ViaVersion.api.Via;
|
||||
import us.myles.ViaVersion.api.platform.ViaInjector;
|
||||
import us.myles.ViaVersion.sponge.handlers.ViaVersionInitializer;
|
||||
import us.myles.ViaVersion.sponge.util.ReflectionUtil;
|
||||
import us.myles.ViaVersion.util.ListWrapper;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class SpongeViaInjector implements ViaInjector {
|
||||
private List<ChannelFuture> injectedFutures = new ArrayList<>();
|
||||
private List<Pair<Field, Object>> injectedLists = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public void inject() throws Exception {
|
||||
try {
|
||||
Object connection = getServerConnection();
|
||||
if (connection == null) {
|
||||
throw new Exception("We failed to find the core component 'ServerConnection', please file an issue on our GitHub.");
|
||||
}
|
||||
for (Field field : connection.getClass().getDeclaredFields()) {
|
||||
field.setAccessible(true);
|
||||
final Object value = field.get(connection);
|
||||
if (value instanceof List) {
|
||||
// Inject the list
|
||||
List wrapper = new ListWrapper((List) value) {
|
||||
@Override
|
||||
public synchronized void handleAdd(Object o) {
|
||||
synchronized (this) {
|
||||
if (o instanceof ChannelFuture) {
|
||||
try {
|
||||
injectChannelFuture((ChannelFuture) o);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
injectedLists.add(new Pair<>(field, connection));
|
||||
field.set(connection, wrapper);
|
||||
// Iterate through current list
|
||||
synchronized (wrapper) {
|
||||
for (Object o : (List) value) {
|
||||
if (o instanceof ChannelFuture) {
|
||||
injectChannelFuture((ChannelFuture) o);
|
||||
} else {
|
||||
break; // not the right list.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
Via.getPlatform().getLogger().severe("Unable to inject ViaVersion, please post these details on our GitHub and ensure you're using a compatible server version.");
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
private void injectChannelFuture(ChannelFuture future) throws Exception {
|
||||
try {
|
||||
ChannelHandler bootstrapAcceptor = future.channel().pipeline().first();
|
||||
try {
|
||||
ChannelInitializer<SocketChannel> oldInit = ReflectionUtil.get(bootstrapAcceptor, "childHandler", ChannelInitializer.class);
|
||||
ChannelInitializer newInit = new ViaVersionInitializer(oldInit);
|
||||
|
||||
ReflectionUtil.set(bootstrapAcceptor, "childHandler", newInit);
|
||||
injectedFutures.add(future);
|
||||
} catch (NoSuchFieldException e) {
|
||||
throw new Exception("Unable to find core component 'childHandler', please check your plugins. issue: " + bootstrapAcceptor.getClass().getName());
|
||||
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Via.getPlatform().getLogger().severe("We failed to inject ViaVersion, have you got late-bind enabled with something else?");
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void uninject() {
|
||||
// TODO: Uninject from players currently online
|
||||
for (ChannelFuture future : injectedFutures) {
|
||||
ChannelHandler bootstrapAcceptor = future.channel().pipeline().first();
|
||||
try {
|
||||
ChannelInitializer<SocketChannel> oldInit = ReflectionUtil.get(bootstrapAcceptor, "childHandler", ChannelInitializer.class);
|
||||
if (oldInit instanceof ViaVersionInitializer) {
|
||||
ReflectionUtil.set(bootstrapAcceptor, "childHandler", ((ViaVersionInitializer) oldInit).getOriginal());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.out.println("Failed to remove injection handler, reload won't work with connections, please reboot!");
|
||||
}
|
||||
}
|
||||
injectedFutures.clear();
|
||||
|
||||
for (Pair<Field, Object> pair : injectedLists) {
|
||||
try {
|
||||
Object o = pair.getKey().get(pair.getValue());
|
||||
if (o instanceof ListWrapper) {
|
||||
pair.getKey().set(pair.getValue(), ((ListWrapper) o).getOriginalList());
|
||||
}
|
||||
} catch (IllegalAccessException e) {
|
||||
System.out.println("Failed to remove injection, reload won't work with connections, please reboot!");
|
||||
}
|
||||
}
|
||||
|
||||
injectedLists.clear();
|
||||
}
|
||||
|
||||
public static Object getServer() throws Exception {
|
||||
Class<?> serverClazz = Class.forName("net.minecraft.server.MinecraftServer");
|
||||
for (Method m : serverClazz.getDeclaredMethods()) {
|
||||
if (m.getParameterCount() == 0) {
|
||||
if ((m.getModifiers() & Modifier.STATIC) == Modifier.STATIC) {
|
||||
if (m.getReturnType().equals(serverClazz)) {
|
||||
return m.invoke(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new Exception("Could not find MinecraftServer static field!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getServerProtocolVersion() throws Exception {
|
||||
try {
|
||||
Class<?> serverClazz = Class.forName("net.minecraft.server.MinecraftServer");
|
||||
Object server = getServer();
|
||||
Class<?> pingClazz = Class.forName("net.minecraft.network.ServerStatusResponse");
|
||||
Object ping = null;
|
||||
// Search for ping method
|
||||
for (Field f : serverClazz.getDeclaredFields()) {
|
||||
if (f.getType() != null) {
|
||||
if (f.getType().getSimpleName().equals("ServerStatusResponse")) {
|
||||
f.setAccessible(true);
|
||||
ping = f.get(server);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ping != null) {
|
||||
Object serverData = null;
|
||||
for (Field f : pingClazz.getDeclaredFields()) {
|
||||
if (f.getType() != null) {
|
||||
if (f.getType().getSimpleName().endsWith("MinecraftProtocolVersionIdentifier")) {
|
||||
f.setAccessible(true);
|
||||
serverData = f.get(ping);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (serverData != null) {
|
||||
int protocolVersion = -1;
|
||||
for (Field f : serverData.getClass().getDeclaredFields()) {
|
||||
if (f.getType() != null) {
|
||||
if (f.getType() == int.class) {
|
||||
f.setAccessible(true);
|
||||
protocolVersion = (int) f.get(serverData);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (protocolVersion != -1) {
|
||||
return protocolVersion;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new Exception("Failed to get server", e);
|
||||
}
|
||||
throw new Exception("Failed to get server");
|
||||
}
|
||||
|
||||
public static Object getServerConnection() throws Exception {
|
||||
Class<?> serverClazz = Class.forName("net.minecraft.server.MinecraftServer");
|
||||
Object server = getServer();
|
||||
Object connection = null;
|
||||
for (Method m : serverClazz.getDeclaredMethods()) {
|
||||
if (m.getReturnType() != null) {
|
||||
if (m.getReturnType().getSimpleName().equals("NetworkSystem")) {
|
||||
if (m.getParameterTypes().length == 0) {
|
||||
connection = m.invoke(server);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return connection;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
package us.myles.ViaVersion.sponge;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.spongepowered.api.Sponge;
|
||||
import us.myles.ViaVersion.SpongePlugin;
|
||||
import us.myles.ViaVersion.api.Via;
|
||||
import us.myles.ViaVersion.api.platform.ViaPlatformLoader;
|
||||
import us.myles.ViaVersion.protocols.protocol1_9to1_8.providers.BulkChunkTranslatorProvider;
|
||||
import us.myles.ViaVersion.protocols.protocol1_9to1_8.providers.MovementTransmitterProvider;
|
||||
import us.myles.ViaVersion.sponge.listeners.ClientLeaveListener;
|
||||
import us.myles.ViaVersion.sponge.listeners.UpdateListener;
|
||||
import us.myles.ViaVersion.sponge.providers.SpongeViaBulkChunkTranslator;
|
||||
import us.myles.ViaVersion.sponge.providers.SpongeViaMovementTransmitter;
|
||||
|
||||
@AllArgsConstructor
|
||||
public class SpongeViaLoader implements ViaPlatformLoader {
|
||||
private SpongePlugin plugin;
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
// Update Listener
|
||||
Sponge.getEventManager().registerListeners(plugin, new UpdateListener());
|
||||
//
|
||||
/* Base Protocol */
|
||||
Sponge.getEventManager().registerListeners(plugin, new ClientLeaveListener());
|
||||
// /* 1.9 client to 1.8 server */
|
||||
//
|
||||
// new ArmorListener(plugin).register();
|
||||
// new CommandBlockListener(plugin).register();
|
||||
// new DeathListener(plugin).register();
|
||||
// new BlockListener(plugin).register();
|
||||
//
|
||||
// if (Bukkit.getVersion().toLowerCase().contains("paper") || Bukkit.getVersion().toLowerCase().contains("taco")) {
|
||||
// plugin.getLogger().info("Enabling PaperSpigot/TacoSpigot patch: Fixes block placement.");
|
||||
// new PaperPatch(plugin).register();
|
||||
// }
|
||||
// if (plugin.getConf().isItemCache()) {
|
||||
// new HandItemCache().runTaskTimerAsynchronously(plugin, 2L, 2L); // Updates player's items :)
|
||||
// HandItemCache.CACHE = true;
|
||||
// }
|
||||
//
|
||||
// /* Providers */
|
||||
Via.getManager().getProviders().use(BulkChunkTranslatorProvider.class, new SpongeViaBulkChunkTranslator());
|
||||
Via.getManager().getProviders().use(MovementTransmitterProvider.class, new SpongeViaMovementTransmitter());
|
||||
// Via.getManager().getProviders().use(HandItemProvider.class, new HandItemProvider() {
|
||||
// @Override
|
||||
// public Item getHandItem(final UserConnection info) {
|
||||
// if (HandItemCache.CACHE) {
|
||||
// return HandItemCache.getHandItem(info.get(ProtocolInfo.class).getUuid());
|
||||
// } else {
|
||||
// try {
|
||||
// return Bukkit.getScheduler().callSyncMethod(Bukkit.getPluginManager().getPlugin("ViaVersion"), new Callable<Item>() {
|
||||
// @Override
|
||||
// public Item call() throws Exception {
|
||||
// UUID playerUUID = info.get(ProtocolInfo.class).getUuid();
|
||||
// if (Bukkit.getPlayer(playerUUID) != null) {
|
||||
// return HandItemCache.convert(Bukkit.getPlayer(playerUUID).getItemInHand());
|
||||
// }
|
||||
// return null;
|
||||
// }
|
||||
// }).get(10, TimeUnit.SECONDS);
|
||||
// } catch (Exception e) {
|
||||
// System.out.println("Error fetching hand item: " + e.getClass().getName());
|
||||
// if (Via.getManager().isDebug())
|
||||
// e.printStackTrace();
|
||||
// return null;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
}
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
package us.myles.ViaVersion.sponge.handlers;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.ByteToMessageDecoder;
|
||||
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.lang.reflect.InvocationTargetException;
|
||||
import java.util.List;
|
||||
|
||||
public class ViaDecodeHandler extends ByteToMessageDecoder {
|
||||
|
||||
private final ByteToMessageDecoder minecraftDecoder;
|
||||
private final UserConnection info;
|
||||
|
||||
public ViaDecodeHandler(UserConnection info, ByteToMessageDecoder minecraftDecoder) {
|
||||
this.info = info;
|
||||
this.minecraftDecoder = minecraftDecoder;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void decode(ChannelHandlerContext ctx, ByteBuf bytebuf, List<Object> list) throws Exception {
|
||||
// use transformers
|
||||
if (bytebuf.readableBytes() > 0) {
|
||||
// Ignore if pending disconnect
|
||||
if (info.isPendingDisconnect()) {
|
||||
return;
|
||||
}
|
||||
// Increment received
|
||||
boolean second = info.incrementReceived();
|
||||
// Check PPS
|
||||
// TODO implement pps
|
||||
// if (second) {
|
||||
// if (((ViaVersionPlugin) Via.getPlatform()).handlePPS(info))
|
||||
// return;
|
||||
// }
|
||||
|
||||
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();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
// call minecraft decoder
|
||||
try {
|
||||
list.addAll(PipelineUtil.callDecode(this.minecraftDecoder, ctx, bytebuf));
|
||||
} catch (InvocationTargetException e) {
|
||||
if (e.getCause() instanceof Exception) {
|
||||
throw (Exception) e.getCause();
|
||||
}
|
||||
} finally {
|
||||
if (info.isActive()) {
|
||||
bytebuf.release();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
||||
if (PipelineUtil.containsCause(cause, CancelException.class)) return;
|
||||
super.exceptionCaught(ctx, cause);
|
||||
}
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
package us.myles.ViaVersion.sponge.handlers;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.MessageToByteEncoder;
|
||||
import us.myles.ViaVersion.api.PacketWrapper;
|
||||
import us.myles.ViaVersion.api.Via;
|
||||
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.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
public class ViaEncodeHandler extends MessageToByteEncoder {
|
||||
private final UserConnection info;
|
||||
private final MessageToByteEncoder minecraftEncoder;
|
||||
|
||||
public ViaEncodeHandler(UserConnection info, MessageToByteEncoder minecraftEncoder) {
|
||||
this.info = info;
|
||||
this.minecraftEncoder = minecraftEncoder;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void encode(final ChannelHandlerContext ctx, Object o, final ByteBuf bytebuf) throws Exception {
|
||||
// handle the packet type
|
||||
if (!(o instanceof ByteBuf)) {
|
||||
// call minecraft encoder
|
||||
try {
|
||||
PipelineUtil.callEncode(this.minecraftEncoder, ctx, o, bytebuf);
|
||||
} catch (InvocationTargetException e) {
|
||||
if (e.getCause() instanceof Exception) {
|
||||
throw (Exception) e.getCause();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (bytebuf.readableBytes() == 0) {
|
||||
throw new CancelException();
|
||||
}
|
||||
// Increment sent
|
||||
info.incrementSent();
|
||||
if (info.isActive()) {
|
||||
// Handle ID
|
||||
int id = Type.VAR_INT.read(bytebuf);
|
||||
// Transform
|
||||
ByteBuf oldPacket = bytebuf.copy();
|
||||
bytebuf.clear();
|
||||
|
||||
try {
|
||||
PacketWrapper wrapper = new PacketWrapper(id, oldPacket, info);
|
||||
ProtocolInfo protInfo = info.get(ProtocolInfo.class);
|
||||
protInfo.getPipeline().transform(Direction.OUTGOING, protInfo.getState(), wrapper);
|
||||
wrapper.writeToBuffer(bytebuf);
|
||||
} catch (Exception e) {
|
||||
bytebuf.clear();
|
||||
throw e;
|
||||
} finally {
|
||||
oldPacket.release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
||||
if (PipelineUtil.containsCause(cause, CancelException.class)) return;
|
||||
super.exceptionCaught(ctx, cause);
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package us.myles.ViaVersion.sponge.handlers;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.MessageToMessageEncoder;
|
||||
import us.myles.ViaVersion.api.data.UserConnection;
|
||||
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ViaPacketHandler extends MessageToMessageEncoder {
|
||||
private final UserConnection info;
|
||||
|
||||
public ViaPacketHandler(UserConnection info) {
|
||||
this.info = info;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void encode(ChannelHandlerContext ctx, Object o, List list) throws Exception {
|
||||
// Split chunks bulk packet up in to single chunks packets before it reached the encoder.
|
||||
// This will prevent issues with several plugins and other protocol handlers due to the chunks being sent twice.
|
||||
// It also sends the chunks in the right order possible resolving some issues with added chunks/block/entity data.
|
||||
if (!(o instanceof ByteBuf)) {
|
||||
info.setLastPacket(o);
|
||||
/* This transformer is more for fixing issues which we find hard at packet level :) */
|
||||
if (info.isActive()) {
|
||||
if (info.get(ProtocolInfo.class).getPipeline().filter(o, list)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
list.add(o);
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
package us.myles.ViaVersion.sponge.handlers;
|
||||
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
import io.netty.handler.codec.ByteToMessageDecoder;
|
||||
import io.netty.handler.codec.MessageToByteEncoder;
|
||||
import us.myles.ViaVersion.api.data.UserConnection;
|
||||
import us.myles.ViaVersion.api.protocol.ProtocolPipeline;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public class ViaVersionInitializer extends ChannelInitializer<SocketChannel> {
|
||||
|
||||
private final ChannelInitializer<SocketChannel> original;
|
||||
private Method method;
|
||||
|
||||
public ViaVersionInitializer(ChannelInitializer<SocketChannel> oldInit) {
|
||||
this.original = oldInit;
|
||||
try {
|
||||
this.method = ChannelInitializer.class.getDeclaredMethod("initChannel", Channel.class);
|
||||
this.method.setAccessible(true);
|
||||
} catch (NoSuchMethodException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public ChannelInitializer<SocketChannel> getOriginal() {
|
||||
return original;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initChannel(SocketChannel socketChannel) throws Exception {
|
||||
UserConnection info = new UserConnection(socketChannel);
|
||||
// init protocol
|
||||
new ProtocolPipeline(info);
|
||||
// Add originals
|
||||
this.method.invoke(this.original, socketChannel);
|
||||
// Add our transformers
|
||||
MessageToByteEncoder encoder = new ViaEncodeHandler(info, (MessageToByteEncoder) socketChannel.pipeline().get("encoder"));
|
||||
ByteToMessageDecoder decoder = new ViaDecodeHandler(info, (ByteToMessageDecoder) socketChannel.pipeline().get("decoder"));
|
||||
ViaPacketHandler chunkHandler = new ViaPacketHandler(info);
|
||||
|
||||
socketChannel.pipeline().replace("encoder", "encoder", encoder);
|
||||
socketChannel.pipeline().replace("decoder", "decoder", decoder);
|
||||
socketChannel.pipeline().addAfter("packet_handler", "viaversion_packet_handler", chunkHandler);
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package us.myles.ViaVersion.sponge.listeners;
|
||||
|
||||
import org.spongepowered.api.event.Listener;
|
||||
import org.spongepowered.api.event.network.ClientConnectionEvent;
|
||||
import us.myles.ViaVersion.api.Via;
|
||||
|
||||
public class ClientLeaveListener {
|
||||
@Listener
|
||||
public void onDisconnect(ClientConnectionEvent.Disconnect disconnect) {
|
||||
Via.getManager().removePortedClient(disconnect.getTargetEntity().getUniqueId());
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package us.myles.ViaVersion.sponge.listeners;
|
||||
|
||||
import org.spongepowered.api.event.Listener;
|
||||
import org.spongepowered.api.event.network.ClientConnectionEvent;
|
||||
import us.myles.ViaVersion.api.Via;
|
||||
import us.myles.ViaVersion.update.UpdateUtil;
|
||||
|
||||
public class UpdateListener {
|
||||
@Listener
|
||||
public void onJoin(ClientConnectionEvent.Join join) {
|
||||
if (join.getTargetEntity().hasPermission("viaversion.update")
|
||||
&& Via.getConfig().isCheckForUpdates()) {
|
||||
UpdateUtil.sendUpdateMessage(join.getTargetEntity().getUniqueId());
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
package us.myles.ViaVersion.sponge.providers;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import us.myles.ViaVersion.api.Via;
|
||||
import us.myles.ViaVersion.protocols.protocol1_9to1_8.providers.BulkChunkTranslatorProvider;
|
||||
import us.myles.ViaVersion.protocols.protocol1_9to1_8.storage.ClientChunks;
|
||||
import us.myles.ViaVersion.sponge.util.ReflectionUtil;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
|
||||
public class SpongeViaBulkChunkTranslator extends BulkChunkTranslatorProvider {
|
||||
// Reflection
|
||||
private static ReflectionUtil.ClassReflection mapChunkBulkRef;
|
||||
private static ReflectionUtil.ClassReflection mapChunkRef;
|
||||
|
||||
static {
|
||||
try {
|
||||
mapChunkBulkRef = new ReflectionUtil.ClassReflection(Class.forName("net.minecraft.network.play.server.S26PacketMapChunkBulk"));
|
||||
mapChunkRef = new ReflectionUtil.ClassReflection(Class.forName("net.minecraft.network.play.server.S21PacketChunkData"));
|
||||
} catch (Exception e) {
|
||||
Via.getPlatform().getLogger().log(Level.WARNING, "Failed to initialise chunks reflection", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Object> transformMapChunkBulk(Object packet, ClientChunks clientChunks) {
|
||||
List<Object> list = Lists.newArrayList();
|
||||
try {
|
||||
int[] xcoords = mapChunkBulkRef.getFieldValue("field_149266_a", packet, int[].class);
|
||||
int[] zcoords = mapChunkBulkRef.getFieldValue("field_149264_b", packet, int[].class);
|
||||
Object[] chunkMaps = mapChunkBulkRef.getFieldValue("field_179755_c", packet, Object[].class);
|
||||
for (int i = 0; i < chunkMaps.length; i++) {
|
||||
int x = xcoords[i];
|
||||
int z = zcoords[i];
|
||||
Object chunkMap = chunkMaps[i];
|
||||
Object chunkPacket = mapChunkRef.newInstance();
|
||||
mapChunkRef.setFieldValue("field_149284_a", chunkPacket, x);
|
||||
mapChunkRef.setFieldValue("field_149282_b", chunkPacket, z);
|
||||
mapChunkRef.setFieldValue("field_179758_c", chunkPacket, chunkMap);
|
||||
mapChunkRef.setFieldValue("field_149279_g", chunkPacket, true); // Chunk bulk chunks are always ground-up
|
||||
clientChunks.getBulkChunks().add(ClientChunks.toLong(x, z)); // Store for later
|
||||
list.add(chunkPacket);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Via.getPlatform().getLogger().log(Level.WARNING, "Failed to transform chunks bulk", e);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFiltered(Class<?> packetClass) {
|
||||
return packetClass.getName().endsWith("S26PacketMapChunkBulk");
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
package us.myles.ViaVersion.sponge.providers;
|
||||
|
||||
import us.myles.ViaVersion.protocols.protocol1_9to1_8.providers.MovementTransmitterProvider;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
public class SpongeViaMovementTransmitter extends MovementTransmitterProvider {
|
||||
// Used for packet mode
|
||||
private Object idlePacket;
|
||||
private Object idlePacket2;
|
||||
|
||||
public SpongeViaMovementTransmitter() {
|
||||
Class<?> idlePacketClass;
|
||||
try {
|
||||
idlePacketClass = Class.forName("net.minecraft.network.play.client.C03PacketPlayer");
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new RuntimeException("Couldn't find idle packet, help!", e);
|
||||
}
|
||||
try {
|
||||
idlePacket = idlePacketClass.newInstance();
|
||||
idlePacket2 = idlePacketClass.newInstance();
|
||||
|
||||
Field flying = idlePacketClass.getDeclaredField("field_149474_g");
|
||||
flying.setAccessible(true);
|
||||
|
||||
flying.set(idlePacket2, true);
|
||||
} catch (NoSuchFieldException | InstantiationException | IllegalArgumentException | IllegalAccessException e) {
|
||||
throw new RuntimeException("Couldn't make player idle packet, help!", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getFlyingPacket() {
|
||||
return idlePacket2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getGroundPacket() {
|
||||
return idlePacket;
|
||||
}
|
||||
}
|
@ -0,0 +1,130 @@
|
||||
package us.myles.ViaVersion.sponge.util;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
public class ReflectionUtil {
|
||||
|
||||
public static Object invokeStatic(Class<?> clazz, String method) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
|
||||
Method m = clazz.getDeclaredMethod(method);
|
||||
return m.invoke(null);
|
||||
}
|
||||
|
||||
public static Object invoke(Object o, String method) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
|
||||
Method m = o.getClass().getDeclaredMethod(method);
|
||||
return m.invoke(o);
|
||||
}
|
||||
|
||||
public static <T> T getStatic(Class<?> clazz, String f, Class<T> t) throws NoSuchFieldException, IllegalAccessException {
|
||||
Field field = clazz.getDeclaredField(f);
|
||||
field.setAccessible(true);
|
||||
return (T) field.get(null);
|
||||
}
|
||||
|
||||
public static <T> T getSuper(Object o, String f, Class<T> t) throws NoSuchFieldException, IllegalAccessException {
|
||||
Field field = o.getClass().getSuperclass().getDeclaredField(f);
|
||||
field.setAccessible(true);
|
||||
return (T) field.get(o);
|
||||
}
|
||||
|
||||
public static <T> T get(Object instance, Class<?> clazz, String f, Class<T> t) throws NoSuchFieldException, IllegalAccessException {
|
||||
Field field = clazz.getDeclaredField(f);
|
||||
field.setAccessible(true);
|
||||
return (T) field.get(instance);
|
||||
}
|
||||
|
||||
public static <T> T get(Object o, String f, Class<T> t) throws NoSuchFieldException, IllegalAccessException {
|
||||
Field field = o.getClass().getDeclaredField(f);
|
||||
field.setAccessible(true);
|
||||
return (T) field.get(o);
|
||||
}
|
||||
|
||||
public static <T> T getPublic(Object o, String f, Class<T> t) throws NoSuchFieldException, IllegalAccessException {
|
||||
Field field = o.getClass().getField(f);
|
||||
field.setAccessible(true);
|
||||
return (T) field.get(o);
|
||||
}
|
||||
|
||||
|
||||
public static void set(Object o, String f, Object value) throws NoSuchFieldException, IllegalAccessException {
|
||||
Field field = o.getClass().getDeclaredField(f);
|
||||
field.setAccessible(true);
|
||||
field.set(o, value);
|
||||
}
|
||||
|
||||
public static final class ClassReflection {
|
||||
private final Class<?> handle;
|
||||
private final Map<String, Field> fields = Maps.newConcurrentMap();
|
||||
private final Map<String, Method> methods = Maps.newConcurrentMap();
|
||||
|
||||
public ClassReflection(Class<?> handle) {
|
||||
this(handle, true);
|
||||
}
|
||||
|
||||
public ClassReflection(Class<?> handle, boolean recursive) {
|
||||
this.handle = handle;
|
||||
scanFields(handle, recursive);
|
||||
scanMethods(handle, recursive);
|
||||
}
|
||||
|
||||
private void scanFields(Class<?> host, boolean recursive) {
|
||||
if (host.getSuperclass() != null && recursive) {
|
||||
scanFields(host.getSuperclass(), true);
|
||||
}
|
||||
|
||||
for (Field field : host.getDeclaredFields()) {
|
||||
field.setAccessible(true);
|
||||
fields.put(field.getName(), field);
|
||||
}
|
||||
}
|
||||
|
||||
private void scanMethods(Class<?> host, boolean recursive) {
|
||||
if (host.getSuperclass() != null && recursive) {
|
||||
scanMethods(host.getSuperclass(), true);
|
||||
}
|
||||
|
||||
for (Method method : host.getDeclaredMethods()) {
|
||||
method.setAccessible(true);
|
||||
methods.put(method.getName(), method);
|
||||
}
|
||||
}
|
||||
|
||||
public Object newInstance() throws IllegalAccessException, InstantiationException {
|
||||
return handle.newInstance();
|
||||
}
|
||||
|
||||
public Field getField(String name) {
|
||||
return fields.get(name);
|
||||
}
|
||||
|
||||
public void setFieldValue(String fieldName, Object instance, Object value) throws IllegalAccessException {
|
||||
getField(fieldName).set(instance, value);
|
||||
}
|
||||
|
||||
public <T> T getFieldValue(String fieldName, Object instance, Class<T> type) throws IllegalAccessException {
|
||||
return type.cast(getField(fieldName).get(instance));
|
||||
}
|
||||
|
||||
public <T> T invokeMethod(Class<T> type, String methodName, Object instance, Object... args) throws InvocationTargetException, IllegalAccessException {
|
||||
return type.cast(getMethod(methodName).invoke(instance, args));
|
||||
}
|
||||
|
||||
public Method getMethod(String name) {
|
||||
return methods.get(name);
|
||||
}
|
||||
|
||||
public Collection<Field> getFields() {
|
||||
return Collections.unmodifiableCollection(fields.values());
|
||||
}
|
||||
|
||||
public Collection<Method> getMethods() {
|
||||
return Collections.unmodifiableCollection(methods.values());
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user