diff --git a/TODOLIST b/TODOLIST
index 177bbbce7..7186f5903 100644
--- a/TODOLIST
+++ b/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
\ No newline at end of file
diff --git a/bukkit/pom.xml b/bukkit/pom.xml
index a4d179ed1..62680b6dd 100644
--- a/bukkit/pom.xml
+++ b/bukkit/pom.xml
@@ -16,12 +16,25 @@
1.8.8-R0.1-SNAPSHOT
+
+
+
+ .
+ true
+ src/main/resources/
+
+ *
+
+
+
+
+
us.myles
viaversion-common
- ${parent.version}
+ ${project.parent.version}
provided
diff --git a/bukkit/src/main/java/us/myles/ViaVersion/bukkit/BukkitViaBulkChunkTranslator.java b/bukkit/src/main/java/us/myles/ViaVersion/bukkit/BukkitViaBulkChunkTranslator.java
index 66b6ab226..7f9a6bcd2 100644
--- a/bukkit/src/main/java/us/myles/ViaVersion/bukkit/BukkitViaBulkChunkTranslator.java
+++ b/bukkit/src/main/java/us/myles/ViaVersion/bukkit/BukkitViaBulkChunkTranslator.java
@@ -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");
}
}
diff --git a/bukkit/src/main/java/us/myles/ViaVersion/listeners/UpdateListener.java b/bukkit/src/main/java/us/myles/ViaVersion/listeners/UpdateListener.java
index c7c9c044c..dc0942192 100644
--- a/bukkit/src/main/java/us/myles/ViaVersion/listeners/UpdateListener.java
+++ b/bukkit/src/main/java/us/myles/ViaVersion/listeners/UpdateListener.java
@@ -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());
}
}
diff --git a/bukkit/src/main/resources/plugin.yml b/bukkit/src/main/resources/plugin.yml
index 764d152a8..524051b93 100644
--- a/bukkit/src/main/resources/plugin.yml
+++ b/bukkit/src/main/resources/plugin.yml
@@ -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]
diff --git a/bungee/pom.xml b/bungee/pom.xml
index a0dd671ca..bfad5ebd0 100644
--- a/bungee/pom.xml
+++ b/bungee/pom.xml
@@ -11,6 +11,19 @@
viaversion-bungee
+
+
+
+ .
+ true
+ src/main/resources/
+
+ *
+
+
+
+
+
diff --git a/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_9to1_8/Protocol1_9TO1_8.java b/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_9to1_8/Protocol1_9TO1_8.java
index 8926966ff..517ab5acb 100644
--- a/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_9to1_8/Protocol1_9TO1_8.java
+++ b/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_9to1_8/Protocol1_9TO1_8.java
@@ -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
diff --git a/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_9to1_8/providers/BulkChunkTranslatorProvider.java b/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_9to1_8/providers/BulkChunkTranslatorProvider.java
index c84698fdb..aa8982a27 100644
--- a/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_9to1_8/providers/BulkChunkTranslatorProvider.java
+++ b/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_9to1_8/providers/BulkChunkTranslatorProvider.java
@@ -11,7 +11,7 @@ public class BulkChunkTranslatorProvider implements Provider {
return Arrays.asList(packet);
}
- public boolean isEnabled() {
+ public boolean isFiltered(Class> packet) {
return false;
}
}
diff --git a/jar/pom.xml b/jar/pom.xml
index bcfabc952..36f1ac584 100644
--- a/jar/pom.xml
+++ b/jar/pom.xml
@@ -18,7 +18,7 @@
.
false
- .
+ ../
LICENSE
@@ -57,6 +57,10 @@
org.javassist
us.myles.viaversion.libs.javassist
+
+ org.apache
+ us.myles.viaversion.libs.apache
+
@@ -75,17 +79,22 @@
us.myles
viaversion-common
- ${parent.version}
+ ${project.parent.version}
us.myles
viaversion-bukkit
- ${parent.version}
+ ${project.parent.version}
us.myles
viaversion-bungee
- ${parent.version}
+ ${project.parent.version}
+
+
+ us.myles
+ viaversion-sponge
+ ${project.parent.version}
diff --git a/pom.xml b/pom.xml
index 2f923cd7d..3cd69f629 100644
--- a/pom.xml
+++ b/pom.xml
@@ -19,6 +19,7 @@
common
bukkit
bungee
+ sponge
jar
@@ -104,7 +105,7 @@
commons-lang
commons-lang
2.6
- provided
+ compile
diff --git a/sponge/pom.xml b/sponge/pom.xml
new file mode 100644
index 000000000..115e29b0f
--- /dev/null
+++ b/sponge/pom.xml
@@ -0,0 +1,72 @@
+
+
+
+ viaversion-parent
+ us.myles
+ 1.0.0-ALPHA-modules
+
+ 4.0.0
+
+ viaversion-sponge
+
+
+ 1.8
+ 1.8
+
+
+
+
+ sponge
+ http://repo.spongepowered.org/maven
+
+
+
+
+
+
+ .
+ true
+ src/main/resources/
+
+ *
+
+
+
+
+
+ org.codehaus.mojo
+ templating-maven-plugin
+ 1.0.0
+
+
+ filter-src
+
+ filter-sources
+
+
+
+
+
+
+
+
+
+
+ us.myles
+ viaversion-common
+ ${project.parent.version}
+ provided
+
+
+
+
+ org.spongepowered
+ spongeapi
+ 4.1.0
+ provided
+
+
+
+
\ No newline at end of file
diff --git a/sponge/src/main/java-templates/us/myles/ViaVersion/sponge/VersionInfo.java b/sponge/src/main/java-templates/us/myles/ViaVersion/sponge/VersionInfo.java
new file mode 100644
index 000000000..960f6a88d
--- /dev/null
+++ b/sponge/src/main/java-templates/us/myles/ViaVersion/sponge/VersionInfo.java
@@ -0,0 +1,5 @@
+package us.myles.ViaVersion.sponge;
+
+public class VersionInfo {
+ public static final String VERSION = "${project.version}";
+}
diff --git a/sponge/src/main/java/us/myles/ViaVersion/SpongePlugin.java b/sponge/src/main/java/us/myles/ViaVersion/SpongePlugin.java
new file mode 100644
index 000000000..e4567df6c
--- /dev/null
+++ b/sponge/src/main/java/us/myles/ViaVersion/SpongePlugin.java
@@ -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();
+ }
+}
diff --git a/sponge/src/main/java/us/myles/ViaVersion/sponge/LoggerWrapper.java b/sponge/src/main/java/us/myles/ViaVersion/sponge/LoggerWrapper.java
new file mode 100644
index 000000000..63050bf9a
--- /dev/null
+++ b/sponge/src/main/java/us/myles/ViaVersion/sponge/LoggerWrapper.java
@@ -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;
+ }
+
+}
diff --git a/sponge/src/main/java/us/myles/ViaVersion/sponge/SpongeBossBar.java b/sponge/src/main/java/us/myles/ViaVersion/sponge/SpongeBossBar.java
new file mode 100644
index 000000000..ae29531c7
--- /dev/null
+++ b/sponge/src/main/java/us/myles/ViaVersion/sponge/SpongeBossBar.java
@@ -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 {
+
+ 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;
+ }
+}
diff --git a/sponge/src/main/java/us/myles/ViaVersion/sponge/SpongeCommandHandler.java b/sponge/src/main/java/us/myles/ViaVersion/sponge/SpongeCommandHandler.java
new file mode 100644
index 000000000..a87c03805
--- /dev/null
+++ b/sponge/src/main/java/us/myles/ViaVersion/sponge/SpongeCommandHandler.java
@@ -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 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");
+ }
+}
diff --git a/sponge/src/main/java/us/myles/ViaVersion/sponge/SpongeCommandSender.java b/sponge/src/main/java/us/myles/ViaVersion/sponge/SpongeCommandSender.java
new file mode 100644
index 000000000..b4c29a260
--- /dev/null
+++ b/sponge/src/main/java/us/myles/ViaVersion/sponge/SpongeCommandSender.java
@@ -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();
+ }
+}
diff --git a/sponge/src/main/java/us/myles/ViaVersion/sponge/SpongeConfigAPI.java b/sponge/src/main/java/us/myles/ViaVersion/sponge/SpongeConfigAPI.java
new file mode 100644
index 000000000..df02666e9
--- /dev/null
+++ b/sponge/src/main/java/us/myles/ViaVersion/sponge/SpongeConfigAPI.java
@@ -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 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 getValues() {
+ return new HashMap<>();
+ }
+}
diff --git a/sponge/src/main/java/us/myles/ViaVersion/sponge/SpongeViaAPI.java b/sponge/src/main/java/us/myles/ViaVersion/sponge/SpongeViaAPI.java
new file mode 100644
index 000000000..f0628a7f1
--- /dev/null
+++ b/sponge/src/main/java/us/myles/ViaVersion/sponge/SpongeViaAPI.java
@@ -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 {
+
+ @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 getSupportedVersions() {
+ SortedSet outputSet = new TreeSet<>(ProtocolRegistry.getSupportedVersions());
+ outputSet.removeAll(Via.getPlatform().getConf().getBlockedProtocols());
+
+ return outputSet;
+ }
+
+ public Map getPortedPlayers() {
+ return Via.getManager().getPortedPlayers();
+ }
+}
diff --git a/sponge/src/main/java/us/myles/ViaVersion/sponge/SpongeViaInjector.java b/sponge/src/main/java/us/myles/ViaVersion/sponge/SpongeViaInjector.java
new file mode 100644
index 000000000..e704cc356
--- /dev/null
+++ b/sponge/src/main/java/us/myles/ViaVersion/sponge/SpongeViaInjector.java
@@ -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 injectedFutures = new ArrayList<>();
+ private List> 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 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 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 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;
+ }
+
+}
diff --git a/sponge/src/main/java/us/myles/ViaVersion/sponge/SpongeViaLoader.java b/sponge/src/main/java/us/myles/ViaVersion/sponge/SpongeViaLoader.java
new file mode 100644
index 000000000..b11eb5948
--- /dev/null
+++ b/sponge/src/main/java/us/myles/ViaVersion/sponge/SpongeViaLoader.java
@@ -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- () {
+// @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;
+// }
+// }
+// }
+// });
+ }
+}
diff --git a/sponge/src/main/java/us/myles/ViaVersion/sponge/handlers/ViaDecodeHandler.java b/sponge/src/main/java/us/myles/ViaVersion/sponge/handlers/ViaDecodeHandler.java
new file mode 100644
index 000000000..b2bce7c0b
--- /dev/null
+++ b/sponge/src/main/java/us/myles/ViaVersion/sponge/handlers/ViaDecodeHandler.java
@@ -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