diff --git a/README.md b/README.md
index db46610..e265728 100644
--- a/README.md
+++ b/README.md
@@ -1,268 +1,5 @@
# ViaMCP
ViaVersion VersionSwitcher for Minecraft Coder Pack (MCP)
-
-* [ViaMCP](#viamcp)
- * [Contact](#contact)
- * [Setup](#setup)
- * [Main-Class](#main-class)
- * [NetworkManager](#networkmanager)
- * [Version Control](#version-control)
- * [Version Slider](#version-slider)
- * [Clientside Fixes](#clientside-fixes)
- * [Attack Order Fixes](#attack-order-fixes)
- * [Block Sound Fixes](#block-sound-fixes)
- * [Transaction Fixes for 1.17+](#transaction-fixes-for-117)
- * [Exporting Without JAR Files](#exporting-without-jar-files)
-
-## Contact
-If you encounter any issues, please report them on the
-[issue tracker](https://github.com/FlorianMichael/ViaMCP/issues).
-If you just want to talk or need help with ViaMCP feel free to join my
-[Discord](https://discord.gg/BwWhCHUKDf).
-
-# Updating notice for existing users (if you are new to ViaMCP, you can ignore this)
-ViaVersion 4.10.0 did some changes to the ProtocolVersion API, you have to update your own code if you ever used the ViaLoadingBase class:
-```java
-// Old
-ViaLoadingBase.getInstance().getTargetVersion().isOlderThan(ProtocolVersion.v1_8);
-ViaLoadingBase.getInstance().getTargetVersion().isNewerThan(ProtocolVersion.v1_8);
-ViaLoadingBase.getInstance().getTargetVersion().isNewerThanOrEqualTo(ProtocolVersion.v1_8);
-ViaLoadingBase.getInstance().getTargetVersion().isOlderThanOrEqualTo(ProtocolVersion.v1_8);
-
-ViaLoadingBase.getInstance().getTargetVersion().getIndex();
-
-// New
-ViaLoadingBase.getInstance().getTargetVersion().olderThan(ProtocolVersion.v1_8);
-ViaLoadingBase.getInstance().getTargetVersion().newerThan(ProtocolVersion.v1_8);
-ViaLoadingBase.getInstance().getTargetVersion().newerThanOrEqualTo(ProtocolVersion.v1_8);
-ViaLoadingBase.getInstance().getTargetVersion().olderThanOrEqualTo(ProtocolVersion.v1_8);
-
-ViaLoadingBase.PROTOCOLS.indexOf(ViaLoadingBase.getInstance().getTargetVersion());
-```
-In addition to that, the *ComparableProtocolVersion* class has been removed and it's methods have been moved to the *ProtocolVersion* class.
-
-## Setup
-Firstly, you will need to add the listed libraries into your dependencies in IntelliJ or Eclipse
-
-Dependencies (Included inside ``libraries`` folder)
-```
-downgraded-ViaVersion-[ver].jar > ViaVersion > https://github.com/ViaVersion/ViaVersion
-downgraded-ViaBackwards-[ver].jar > ViaBackwards > https://github.com/ViaVersion/ViaBackwards
-downgraded-ViaRewind-[ver].jar > ViaRewind > https://github.com/ViaVersion/ViaRewind
-snakeyml-2.2.jar > SnakeYaml > https://bitbucket.org/snakeyaml/snakeyaml
-```
-
-Secondly, you need to add code that allows you to actually use ViaMCP (**Choose the version folder that corresponds with your client version**)
-
-For other versions than 1.8.x and 1.12.2, you will need to modify the code to fit your client version. You can see namings for
-other major versions [here](https://github.com/ViaVersion/ViaForge)
-
-NOTE:
-ViaVersion 5.0.0+ doesn't support Java 8 anymore, therefore when updating the libraries yourself, you need to download
-the -Java8 jar files from the [ci server](https://ci.viaversion.com/) or generate them yourself using [this](https://github.com/ViaVersion/ViaForge/tree/legacy-1.8?tab=readme-ov-file#installation) tool.
-
-### Main-Class
-Add this to the main class of your client (aka injection function)
-
-```java
-try {
- ViaMCP.create();
-
- // In case you want a version slider like in the Minecraft options, you can use this code here, please choose one of those:
-
- ViaMCP.INSTANCE.initAsyncSlider(); // For top left aligned slider
- ViaMCP.INSTANCE.initAsyncSlider(x, y, width (min. 110), height (recommended 20)); // For custom position and size slider
-} catch (Exception e) {
- e.printStackTrace();
-}
-```
-
-### NetworkManager
-You will need to modify 2 methods inside NetworkManager.java
-
-**1. Hook ViaVersion into the Netty Pipeline**
-
-Find the method, that is ``func_181124_a``, ``createNetworkManagerAndConnect`` or contains ``(Bootstrap)((Bootstrap)((Bootstrap)(new Bootstrap()).group((EventLoopGroup)lazyloadbase.getValue())``
-
-Find the vanilla network pipeline call:
-```java
-// 1.8.x client
-p_initChannel_1_.pipeline().addLast((String)"timeout", (ChannelHandler)(new ReadTimeoutHandler(30))).addLast((String)"splitter", (ChannelHandler)(new MessageDeserializer2())).addLast((String)"decoder", (ChannelHandler)(new MessageDeserializer(EnumPacketDirection.CLIENTBOUND))).addLast((String)"prepender", (ChannelHandler)(new MessageSerializer2())).addLast((String)"encoder", (ChannelHandler)(new MessageSerializer(EnumPacketDirection.SERVERBOUND))).addLast((String)"packet_handler", (ChannelHandler)networkmanager);
-
-// 1.12.x client
-p_initChannel_1_.pipeline().addLast("timeout", new ReadTimeoutHandler(30)).addLast("splitter", new NettyVarint21FrameDecoder()).addLast("decoder", new NettyPacketDecoder(EnumPacketDirection.CLIENTBOUND)).addLast("prepender", new NettyVarint21FrameEncoder()).addLast("encoder", new NettyPacketEncoder(EnumPacketDirection.SERVERBOUND)).addLast("packet_handler", networkmanager);
-```
-
-After the vanilla network pipeline call, add the ViaMCP protocol pipeline hook:
-```java
-if (p_initChannel_1_ instanceof SocketChannel && ViaLoadingBase.getInstance().getTargetVersion().getVersion() != ViaMCP.NATIVE_VERSION) {
- final UserConnection user = new UserConnectionImpl(p_initChannel_1_, true);
- new ProtocolPipelineImpl(user);
-
- p_initChannel_1_.pipeline().addLast(new MCPVLBPipeline(user));
-}
-```
-
-Your code should look like this afterwards (1.8.x for example), the vanilla network pipeline call should not be commented out and the ViaMCP protocol pipeline hook should be after the vanilla network pipeline call:
-```java
-p_initChannel_1_.pipeline().addLast((String)"timeout", (ChannelHandler)(new ReadTimeoutHandler(30))).addLast((String)"splitter", (ChannelHandler)(new MessageDeserializer2())).addLast((String)"decoder", (ChannelHandler)(new MessageDeserializer(EnumPacketDirection.CLIENTBOUND))).addLast((String)"prepender", (ChannelHandler)(new MessageSerializer2())).addLast((String)"encoder", (ChannelHandler)(new MessageSerializer(EnumPacketDirection.SERVERBOUND))).addLast((String)"packet_handler", (ChannelHandler)networkmanager);
-
-if (p_initChannel_1_ instanceof SocketChannel && ViaLoadingBase.getInstance().getTargetVersion().getVersion() != ViaMCP.NATIVE_VERSION) {
- final UserConnection user = new UserConnectionImpl(p_initChannel_1_, true);
- new ProtocolPipelineImpl(user);
-
- p_initChannel_1_.pipeline().addLast(new MCPVLBPipeline(user));
-}
-```
-
-### If you want to send custom packets, you have to store the UserConnection instance in a variable for later, it's important that this variable is NOT STATIC since it's also used for pinging servers!
-
-**2. Fix the compression in the NetworkManager#setCompressionTreshold function**
-
-Simply call the following code at the end of the method in Minecraft:
-```java
-this.channel.pipeline().fireUserEventTriggered(new CompressionReorderEvent());
-```
-
-## Version Control
-You will need to add a button to access the protocol switcher (or alternatively use the version slider under this section)
-In ``addSingleplayerMultiplayerButtons()`` function add (if in GuiMainMenu):
-```java
-this.buttonList.add(new GuiButton(69, 5, 5, 90, 20, "Version"));
-```
-In ``actionPerformed()`` function add:
-```java
-if (button.id == 69)
-{
- this.mc.displayGuiScreen(new GuiProtocolSelector(this));
-}
-```
-### Version Slider
-You can also use a version slider to control ViaMCP versions
-```java
-this.buttonList.add(ViaMCP.INSTANCE.getAsyncVersionSlider());
-```
-
-## Clientside Fixes
-### Attack Order Fixes
-**Class: Minecraft.java**
-**Function: clickMouse()**
-
-**1.8.x**
-Replace ``this.thePlayer.swingItem();`` on the 1st line in the if-clause with:
-```java
-AttackOrder.sendConditionalSwing(this.objectMouseOver);
-```
-Replace ``this.playerController.attackEntity(this.thePlayer, this.objectMouseOver.entityHit);`` in the switch in case ``ENTITY`` with:
-```java
-AttackOrder.sendFixedAttack(this.thePlayer, this.objectMouseOver.entityHit);
-```
-
-**1.12.2**
-Replace ``this.player.swingArm(EnumHand.MAIN_HAND);`` at the last line in the else if-clause with:
-```java
-AttackOrder.sendConditionalSwing(this.objectMouseOver, EnumHand.MAIN_HAND);
-```
-Replace ``this.playerController.attackEntity(this.player, this.objectMouseOver.entityHit);`` in the switch in case ``ENTITY`` with:
-```java
-AttackOrder.sendFixedAttack(this.thePlayer, this.objectMouseOver.entityHit, EnumHand.MAIN_HAND);
-```
-
-### Block Sound Fixes
-**Block Placement**
-
-Replace all code in ``onItemUse`` function in the ``ItemBlock`` class with:
-```java
-return FixedSoundEngine.onItemUse(this, stack, playerIn, worldIn, pos, side, hitX, hitY, hitZ);
-```
-
-**Block Breaking**
-
-Replace all code in ``destroyBlock`` function in the ``World`` class with:
-```java
-return FixedSoundEngine.destroyBlock(this, pos, dropBlock);
-```
-
-### Transaction Fixes for 1.17+
-Call the ``fixTransactions();`` in the ``ViaMCP`` class file so ViaVersion doesn't remap anything in transaction packets.
-
-After that, you need to do some changes in the Game code:
-
-**Class: S32PacketConfirmTransaction.java**
-**Function: readPacketData()**
-
-Replace the code with this method:
-```java
-public void readPacketData(PacketBuffer buf) throws IOException {
- if (ViaLoadingBase.getInstance().getTargetVersion().newerThanOrEqualTo(ProtocolVersion.v1_17)) {
- this.windowId = buf.readInt();
- } else {
- this.windowId = buf.readUnsignedByte();
- this.actionNumber = buf.readShort();
- this.accepted = buf.readBoolean();
- }
-}
-```
-
-**Class: C0FPacketConfirmTransaction.java**
-**Function: writePacketData()**
-
-Replace the code with this method:
-```java
-public void writePacketData(PacketBuffer buf) throws IOException {
- if (ViaLoadingBase.getInstance().getTargetVersion().newerThanOrEqualTo(ProtocolVersion.v1_17)) {
- buf.writeInt(this.windowId);
- } else {
- buf.writeByte(this.windowId);
- buf.writeShort(this.uid);
- buf.writeByte(this.accepted ? 1 : 0);
- }
-}
-```
-
-Note: this code can be different depending on your mappings and game version, you just need to make sure
-it only reads the window id and doesn't read the rest of the packet because we previously removed the
-ViaVersion handlers which would have handled the rest of the packet.
-
-**Class: NetHandlerPlayClient.java**
-**Function: handleConfirmTransaction()**
-
-Add this code after the checkThreadAndEnqueue function call:
-```java
-if (ViaLoadingBase.getInstance().getTargetVersion().newerThanOrEqualTo(ProtocolVersion.v1_17)) {
- this.addToSendQueue(new C0FPacketConfirmTransaction(packetIn.getWindowId(), 0, false));
- return;
-}
-```
-
-## Sending raw packets (e.g 1.9 interactions)
-You can send raw packets with ViaMCP, you can use the following code to send raw packets:
-```java
-final PacketWrapper blockPlace = PacketWrapper.create(ServerboundPackets1_9.PLAYER_BLOCK_PLACEMENT, null); // Replace null with your stored UserConnection, see NetworkManager tutorial above
-blockPlace.write(Type.POSITION1_8, new Position(0, 0, 0)); // Replace with the block position
-blockPlace.write(Type.VAR_INT, 0); // Replace with the block face, see https://wiki.vg/index.php?title=Protocol&oldid=7617#Player_Digging
-blockPlace.write(Type.VAR_INT, 0); // Replace with the hand, 0 for main hand, 1 for off hand
-blockPlace.write(Type.UNSIGNED_BYTE, (short) 0); // The x pos of the crosshair, from 0 to 15 increasing from west to east
-blockPlace.write(Type.UNSIGNED_BYTE, (short) 0); // The y pos of the crosshair, from 0 to 15 increasing from bottom to top
-blockPlace.write(Type.UNSIGNED_BYTE, (short) 0); // The z pos of the crosshair, from 0 to 15 increasing from north to south
-
-try {
- blockPlace.sendToServer(Protocol1_9To1_8.class); // Protocol class names are: server -> client version
-} catch (Exception e) {
- // Packet sending failed
- throw new RuntimeException(e);
-}
-```
-
-## Exporting Without JAR Files
-This should fix most peoples issues with dependencies (usually NoClassDefFoundError or ClassNotFoundException)
-
-- First export your client normally
-- Open your client .jar file with an archive program (winrar or 7zip for example)
-- Also open all libraries with the selected archive program (ViaVersion, ViaBackwards, ViaRewind and SnakeYaml)
-- From ViaBackwards drag and drop ``assets`` and ``com`` folders to your client .jar
-- From ViaRewind drag and drop ``assets`` and ``de`` folders to your client .jar
-- From ViaSnakeYaml drag and drop ``org`` folder to your client .jar
-- From ViaVersion drag and drop ``assets``, ``com`` and ``us`` folders to your client .jar
-- Then save and close, now your client should be working correctly ;)
+[if you want to use MCP Reborn >= 1.20.x](/v1.20.x)
+[else if you are using MCP 1.8.x || 1.12.x click here](/v1.8.x)
\ No newline at end of file
diff --git a/v1.20.2/.gitignore b/v1.20.2/.gitignore
new file mode 100644
index 0000000..f68d109
--- /dev/null
+++ b/v1.20.2/.gitignore
@@ -0,0 +1,29 @@
+### IntelliJ IDEA ###
+out/
+!**/src/main/**/out/
+!**/src/test/**/out/
+
+### Eclipse ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+bin/
+!**/src/main/**/bin/
+!**/src/test/**/bin/
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+
+### VS Code ###
+.vscode/
+
+### Mac OS ###
+.DS_Store
\ No newline at end of file
diff --git a/v1.20.2/README.md b/v1.20.2/README.md
new file mode 100644
index 0000000..3b0cf5e
--- /dev/null
+++ b/v1.20.2/README.md
@@ -0,0 +1,54 @@
+
+### Main-Class
+Add this to the main class of your client (aka injection function)
+
+```java
+try {
+ ViaMCP.create();
+} catch (Exception e) {
+ e.printStackTrace();
+}
+```
+
+
+### Connection
+You will need to modify 2 methods inside ``net.minecraft.network.Connection.java``
+
+**1. Hook ViaVersion into the Netty Pipeline**
+
+Find the method, that is ``m_264299_``, ``configureSerialization``
+
+Find the vanilla network pipeline call:
+```java
+p_265436_.addLast("splitter", new Varint21FrameDecoder(p_299297_)).addLast("decoder", new PacketDecoder(attributekey)).addLast("prepender", new Varint21LengthFieldPrepender()).addLast("encoder", new PacketEncoder(attributekey1)).addLast("unbundler", new PacketBundleUnpacker(attributekey1)).addLast("bundler", new PacketBundlePacker(attributekey));
+```
+
+After the vanilla network pipeline call, add the ViaMCP protocol pipeline hook:
+```java
+if(p_265436_.channel() instanceof SocketChannel && ViaLoadingBase.getInstance().getTargetVersion().getVersion() != ViaMCP.NATIVE_VERSION) {
+ final UserConnection user = new UserConnectionImpl(p_265436_.channel(), p_265104_ == PacketFlow.CLIENTBOUND);
+ new ProtocolPipelineImpl(user);
+
+ p_265436_.addLast(new MCPVLBPipeline(user));
+}
+```
+
+**2. Fix the compression in the net.minecraft.network.Connection#setupCompression function**
+
+Simply call the following code at the end of the method in Minecraft:
+```java
+this.channel.pipeline().fireUserEventTriggered(new CompressionReorderEvent());
+```
+
+## Version Control
+You will need to add a button to access the protocol switcher ~~(or alternatively use the version slider under this section)~~
+In ``createNormalMenuOptions()`` function add (if in TitleScreen):
+
+
+add this to the bottom of the method:
+```java
+this.addRenderableWidget(Button.builder(Component.text("Version"), (button) -> {
+ assert this.minecraft != null;
+ this.minecraft.setScreen(new GuiProtocolSelector(Minecraft.getInstance().screen));
+}).bounds(5, 5, 90, 20).build());
+```
\ No newline at end of file
diff --git a/v1.20.2/src/florianmichael/vialoadingbase/ViaLoadingBase.java b/v1.20.2/src/florianmichael/vialoadingbase/ViaLoadingBase.java
new file mode 100644
index 0000000..2cbc7a8
--- /dev/null
+++ b/v1.20.2/src/florianmichael/vialoadingbase/ViaLoadingBase.java
@@ -0,0 +1,252 @@
+/*
+ * This file is part of ViaLoadingBase - https://github.com/FlorianMichael/ViaLoadingBase
+ * Copyright (C) 2020-2024 FlorianMichael/EnZaXD and contributors
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package de.florianmichael.vialoadingbase;
+
+import com.viaversion.viaversion.ViaManagerImpl;
+import com.viaversion.viaversion.api.Via;
+import com.viaversion.viaversion.api.platform.providers.ViaProviders;
+import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
+import com.viaversion.viaversion.libs.gson.JsonObject;
+import com.viaversion.viaversion.protocol.ProtocolManagerImpl;
+import de.florianmichael.vialoadingbase.model.Platform;
+import de.florianmichael.vialoadingbase.platform.ViaBackwardsPlatformImpl;
+import de.florianmichael.vialoadingbase.platform.ViaRewindPlatformImpl;
+import de.florianmichael.vialoadingbase.platform.viaversion.VLBViaCommandHandler;
+import de.florianmichael.vialoadingbase.platform.viaversion.VLBViaProviders;
+import de.florianmichael.vialoadingbase.platform.ViaVersionPlatformImpl;
+import de.florianmichael.vialoadingbase.platform.viaversion.VLBViaInjector;
+import de.florianmichael.vialoadingbase.util.JLoggerToLog4j;
+import org.apache.logging.log4j.LogManager;
+import slice.Slice;
+
+import java.io.File;
+import java.util.*;
+import java.util.function.BooleanSupplier;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+import java.util.logging.Logger;
+
+public class ViaLoadingBase {
+ public final static String VERSION = "${vialoadingbase_version}";
+ public final static Logger LOGGER = new JLoggerToLog4j(LogManager.getLogger("ViaLoadingBase"));
+
+ public final static Platform PSEUDO_VIA_VERSION = new Platform("ViaVersion", () -> true, () -> {
+ // Empty
+ }, protocolVersions -> protocolVersions.addAll(ViaVersionPlatformImpl.createVersionList()));
+ public final static Platform PLATFORM_VIA_BACKWARDS = new Platform("ViaBackwards", () -> inClassPath("com.viaversion.viabackwards.api.ViaBackwardsPlatform"), () -> new ViaBackwardsPlatformImpl(Via.getManager().getPlatform().getDataFolder()));
+ public final static Platform PLATFORM_VIA_REWIND = new Platform("ViaRewind", () -> inClassPath("com.viaversion.viarewind.api.ViaRewindPlatform"), () -> new ViaRewindPlatformImpl(Via.getManager().getPlatform().getDataFolder()));
+
+ public final static List PROTOCOLS = new ArrayList<>();
+
+ private static ViaLoadingBase instance;
+
+ private final LinkedList platforms;
+ private final File runDirectory;
+ private final int nativeVersion;
+ private final BooleanSupplier forceNativeVersionCondition;
+ private final Supplier dumpSupplier;
+ private final Consumer providers;
+ private final Consumer managerBuilderConsumer;
+ private final Consumer onProtocolReload;
+
+ private ProtocolVersion nativeProtocolVersion;
+ private ProtocolVersion targetProtocolVersion;
+
+ public ViaLoadingBase(LinkedList platforms, File runDirectory, int nativeVersion, BooleanSupplier forceNativeVersionCondition, Supplier dumpSupplier, Consumer providers, Consumer managerBuilderConsumer, Consumer onProtocolReload) {
+ this.platforms = platforms;
+
+ this.runDirectory = new File(runDirectory, "ViaLoadingBase");
+ this.nativeVersion = nativeVersion;
+ this.forceNativeVersionCondition = forceNativeVersionCondition;
+ this.dumpSupplier = dumpSupplier;
+ this.providers = providers;
+ this.managerBuilderConsumer = managerBuilderConsumer;
+ this.onProtocolReload = onProtocolReload;
+
+ instance = this;
+ initPlatform();
+ }
+
+ public ProtocolVersion getTargetVersion() {
+ if (forceNativeVersionCondition != null && forceNativeVersionCondition.getAsBoolean()) return nativeProtocolVersion;
+
+ return targetProtocolVersion;
+ }
+
+ public void reload(final ProtocolVersion protocolVersion) {
+ if(protocolVersion == null) return;
+
+ this.targetProtocolVersion = protocolVersion;
+
+ if (this.onProtocolReload != null) this.onProtocolReload.accept(targetProtocolVersion);
+
+ Slice.INSTANCE.logger.info("ViaLoadingBase has reloaded to {} ({})", targetProtocolVersion.getName(), targetProtocolVersion.getVersion());
+ }
+
+ public void initPlatform() {
+ for (Platform platform : platforms) platform.createProtocolPath();
+
+ this.nativeProtocolVersion = ProtocolVersion.getProtocol(this.nativeVersion);
+ this.targetProtocolVersion = this.nativeProtocolVersion;
+
+ final ViaVersionPlatformImpl viaVersionPlatform = new ViaVersionPlatformImpl(ViaLoadingBase.LOGGER);
+ final ViaManagerImpl.ViaManagerBuilder builder = ViaManagerImpl.builder().
+ platform(viaVersionPlatform).
+ loader(new VLBViaProviders()).
+ injector(new VLBViaInjector()).
+ commandHandler(new VLBViaCommandHandler())
+ ;
+
+ if (this.managerBuilderConsumer != null) this.managerBuilderConsumer.accept(builder);
+
+ Via.init(builder.build());
+
+ final ViaManagerImpl manager = (ViaManagerImpl) Via.getManager();
+ manager.addEnableListener(() -> {
+ for (Platform platform : this.platforms) platform.build(ViaLoadingBase.LOGGER);
+ });
+
+ manager.init();
+ manager.onServerLoaded();
+ manager.getProtocolManager().setMaxProtocolPathSize(Integer.MAX_VALUE);
+ manager.getProtocolManager().setMaxPathDeltaIncrease(-1);
+ ((ProtocolManagerImpl) manager.getProtocolManager()).refreshVersions();
+
+ ViaLoadingBase.LOGGER.info("ViaLoadingBase has loaded " + Platform.COUNT + "/" + platforms.size() + " platforms");
+ }
+
+ public static ViaLoadingBase getInstance() {
+ return instance;
+ }
+
+ public List getSubPlatforms() {
+ return platforms;
+ }
+
+ public File getRunDirectory() {
+ return runDirectory;
+ }
+
+ public int getNativeVersion() {
+ return nativeVersion;
+ }
+
+ public Supplier getDumpSupplier() {
+ return dumpSupplier;
+ }
+
+ public Consumer getProviders() {
+ return providers;
+ }
+
+ public static boolean inClassPath(final String name) {
+ try {
+ Class.forName(name);
+ return true;
+ } catch (Exception ignored) {
+ return false;
+ }
+ }
+
+ @Deprecated
+ public static List getProtocols() {
+ return PROTOCOLS;
+ }
+
+ public static class ViaLoadingBaseBuilder {
+ private final LinkedList platforms = new LinkedList<>();
+
+ private File runDirectory;
+ private Integer nativeVersion;
+ private BooleanSupplier forceNativeVersionCondition;
+ private Supplier dumpSupplier;
+ private Consumer providers;
+ private Consumer managerBuilderConsumer;
+ private Consumer onProtocolReload;
+
+ public ViaLoadingBaseBuilder() {
+ platforms.add(PSEUDO_VIA_VERSION);
+
+ platforms.add(PLATFORM_VIA_BACKWARDS);
+ platforms.add(PLATFORM_VIA_REWIND);
+ }
+
+ public static ViaLoadingBaseBuilder create() {
+ return new ViaLoadingBaseBuilder();
+ }
+
+ public ViaLoadingBaseBuilder platform(final Platform platform) {
+ this.platforms.add(platform);
+ return this;
+ }
+
+ public ViaLoadingBaseBuilder platform(final Platform platform, final int position) {
+ this.platforms.add(position, platform);
+ return this;
+ }
+
+ public ViaLoadingBaseBuilder runDirectory(final File runDirectory) {
+ this.runDirectory = runDirectory;
+ return this;
+ }
+
+ public ViaLoadingBaseBuilder nativeVersion(final int nativeVersion) {
+ this.nativeVersion = nativeVersion;
+ return this;
+ }
+
+ public ViaLoadingBaseBuilder forceNativeVersionCondition(final BooleanSupplier forceNativeVersionCondition) {
+ this.forceNativeVersionCondition = forceNativeVersionCondition;
+ return this;
+ }
+
+ public ViaLoadingBaseBuilder dumpSupplier(final Supplier dumpSupplier) {
+ this.dumpSupplier = dumpSupplier;
+ return this;
+ }
+
+ public ViaLoadingBaseBuilder providers(final Consumer providers) {
+ this.providers = providers;
+ return this;
+ }
+
+ public ViaLoadingBaseBuilder managerBuilderConsumer(final Consumer managerBuilderConsumer) {
+ this.managerBuilderConsumer = managerBuilderConsumer;
+ return this;
+ }
+
+ public ViaLoadingBaseBuilder onProtocolReload(final Consumer onProtocolReload) {
+ this.onProtocolReload = onProtocolReload;
+ return this;
+ }
+
+ public void build() {
+ if (ViaLoadingBase.getInstance() != null) {
+ ViaLoadingBase.LOGGER.severe("ViaLoadingBase has already started the platform!");
+ return;
+ }
+ if (runDirectory == null || nativeVersion == null) {
+ ViaLoadingBase.LOGGER.severe("Please check your ViaLoadingBaseBuilder arguments!");
+ return;
+ }
+
+ ViaLoadingBase.instance = new ViaLoadingBase(platforms, runDirectory, nativeVersion, forceNativeVersionCondition, dumpSupplier, providers, managerBuilderConsumer, onProtocolReload);
+ }
+ }
+}
diff --git a/v1.20.2/src/florianmichael/vialoadingbase/command/UserCommandSender.java b/v1.20.2/src/florianmichael/vialoadingbase/command/UserCommandSender.java
new file mode 100644
index 0000000..cf9bd4a
--- /dev/null
+++ b/v1.20.2/src/florianmichael/vialoadingbase/command/UserCommandSender.java
@@ -0,0 +1,53 @@
+/*
+ * This file is part of ViaLoadingBase - https://github.com/FlorianMichael/ViaLoadingBase
+ * Copyright (C) 2020-2024 FlorianMichael/EnZaXD and contributors
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package de.florianmichael.vialoadingbase.command;
+
+import com.viaversion.viaversion.api.Via;
+import com.viaversion.viaversion.api.command.ViaCommandSender;
+import com.viaversion.viaversion.api.connection.UserConnection;
+
+import java.util.UUID;
+
+public class UserCommandSender implements ViaCommandSender {
+ private final UserConnection user;
+
+ public UserCommandSender(UserConnection user) {
+ this.user = user;
+ }
+
+ @Override
+ public boolean hasPermission(String s) {
+ return false;
+ }
+
+ @Override
+ public void sendMessage(String s) {
+ Via.getPlatform().sendMessage(getUUID(), s);
+ }
+
+ @Override
+ public UUID getUUID() {
+ return user.getProtocolInfo().getUuid();
+ }
+
+ @Override
+ public String getName() {
+ return user.getProtocolInfo().getUsername();
+ }
+}
diff --git a/v1.20.2/src/florianmichael/vialoadingbase/model/Platform.java b/v1.20.2/src/florianmichael/vialoadingbase/model/Platform.java
new file mode 100644
index 0000000..e97e59a
--- /dev/null
+++ b/v1.20.2/src/florianmichael/vialoadingbase/model/Platform.java
@@ -0,0 +1,72 @@
+/*
+ * This file is part of ViaLoadingBase - https://github.com/FlorianMichael/ViaLoadingBase
+ * Copyright (C) 2020-2024 FlorianMichael/EnZaXD and contributors
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package de.florianmichael.vialoadingbase.model;
+
+import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
+import de.florianmichael.vialoadingbase.ViaLoadingBase;
+
+import java.util.List;
+import java.util.function.BooleanSupplier;
+import java.util.function.Consumer;
+import java.util.logging.Logger;
+
+public class Platform {
+ public static int COUNT = 0;
+
+ private final String name;
+ private final BooleanSupplier load;
+ private final Runnable executor;
+ private final Consumer> versionCallback;
+
+ public Platform(String name, BooleanSupplier load, Runnable executor) {
+ this(name, load, executor, null);
+ }
+
+ public Platform(String name, BooleanSupplier load, Runnable executor, Consumer> versionCallback) {
+ this.name = name;
+ this.load = load;
+ this.executor = executor;
+ this.versionCallback = versionCallback;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void createProtocolPath() {
+ if (this.versionCallback != null) {
+ this.versionCallback.accept(ViaLoadingBase.PROTOCOLS);
+ }
+ }
+
+ public void build(final Logger logger) {
+ if (this.load.getAsBoolean()) {
+ try {
+ this.executor.run();
+ logger.info("Loaded Platform " + this.name);
+ COUNT++;
+ } catch (Throwable t) {
+ logger.severe("An error occurred while loading Platform " + this.name + ":");
+ t.printStackTrace();
+ }
+ return;
+ }
+ logger.severe("Platform " + this.name + " is not present");
+ }
+}
diff --git a/v1.20.2/src/florianmichael/vialoadingbase/model/ProtocolRange.java b/v1.20.2/src/florianmichael/vialoadingbase/model/ProtocolRange.java
new file mode 100644
index 0000000..7598b07
--- /dev/null
+++ b/v1.20.2/src/florianmichael/vialoadingbase/model/ProtocolRange.java
@@ -0,0 +1,62 @@
+/*
+ * This file is part of ViaLoadingBase - https://github.com/FlorianMichael/ViaLoadingBase
+ * Copyright (C) 2020-2024 FlorianMichael/EnZaXD and contributors
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package de.florianmichael.vialoadingbase.model;
+
+import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
+
+@Deprecated
+public class ProtocolRange {
+ private final ProtocolVersion lowerBound;
+ private final ProtocolVersion upperBound;
+
+ public ProtocolRange(ProtocolVersion lowerBound, ProtocolVersion upperBound) {
+ if (lowerBound == null && upperBound == null) {
+ throw new RuntimeException("Invalid protocol range");
+ }
+ this.lowerBound = lowerBound;
+ this.upperBound = upperBound;
+ }
+
+ public static ProtocolRange andNewer(final ProtocolVersion version) {
+ return new ProtocolRange(null, version);
+ }
+
+ public static ProtocolRange singleton(final ProtocolVersion version) {
+ return new ProtocolRange(version, version);
+ }
+
+ public static ProtocolRange andOlder(final ProtocolVersion version) {
+ return new ProtocolRange(version, null);
+ }
+
+ public boolean contains(final ProtocolVersion protocolVersion) {
+ if (this.lowerBound != null && protocolVersion.olderThan(lowerBound)) return false;
+
+ return this.upperBound == null || protocolVersion.olderThanOrEqualTo(upperBound);
+ }
+
+ @Override
+ public String toString() {
+ if (lowerBound == null) return upperBound.getName() + "+";
+ if (upperBound == null) return lowerBound.getName() + "-";
+ if (lowerBound == upperBound) return lowerBound.getName();
+
+ return lowerBound.getName() + " - " + upperBound.getName();
+ }
+}
diff --git a/v1.20.2/src/florianmichael/vialoadingbase/netty/VLBPipeline.java b/v1.20.2/src/florianmichael/vialoadingbase/netty/VLBPipeline.java
new file mode 100644
index 0000000..5d1e67b
--- /dev/null
+++ b/v1.20.2/src/florianmichael/vialoadingbase/netty/VLBPipeline.java
@@ -0,0 +1,87 @@
+/*
+ * This file is part of ViaLoadingBase - https://github.com/FlorianMichael/ViaLoadingBase
+ * Copyright (C) 2020-2024 FlorianMichael/EnZaXD and contributors
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package de.florianmichael.vialoadingbase.netty;
+
+import com.viaversion.viaversion.api.connection.UserConnection;
+import de.florianmichael.vialoadingbase.netty.event.CompressionReorderEvent;
+import de.florianmichael.vialoadingbase.netty.handler.VLBViaDecodeHandler;
+import de.florianmichael.vialoadingbase.netty.handler.VLBViaEncodeHandler;
+import io.netty.channel.ChannelHandler;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelInboundHandlerAdapter;
+
+public abstract class VLBPipeline extends ChannelInboundHandlerAdapter {
+ public final static String VIA_DECODER_HANDLER_NAME = "via-decoder";
+ public final static String VIA_ENCODER_HANDLER_NAME = "via-encoder";
+
+ private final UserConnection user;
+
+ public VLBPipeline(final UserConnection user) {
+ this.user = user;
+ }
+
+ @Override
+ public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
+ super.handlerAdded(ctx);
+
+ ctx.pipeline().addBefore(getDecoderHandlerName(), VIA_DECODER_HANDLER_NAME, this.createVLBViaDecodeHandler());
+ ctx.pipeline().addBefore(getEncoderHandlerName(), VIA_ENCODER_HANDLER_NAME, this.createVLBViaEncodeHandler());
+ }
+
+ @Override
+ public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
+ super.userEventTriggered(ctx, evt);
+
+ if (evt instanceof CompressionReorderEvent) {
+ final int decoderIndex = ctx.pipeline().names().indexOf(getDecompressionHandlerName());
+ if (decoderIndex == -1) return;
+
+ if (decoderIndex > ctx.pipeline().names().indexOf(VIA_DECODER_HANDLER_NAME)) {
+ final ChannelHandler decoder = ctx.pipeline().get(VIA_DECODER_HANDLER_NAME);
+ final ChannelHandler encoder = ctx.pipeline().get(VIA_ENCODER_HANDLER_NAME);
+
+ ctx.pipeline().remove(decoder);
+ ctx.pipeline().remove(encoder);
+
+ ctx.pipeline().addAfter(getDecompressionHandlerName(), VIA_DECODER_HANDLER_NAME, decoder);
+ ctx.pipeline().addAfter(getCompressionHandlerName(), VIA_ENCODER_HANDLER_NAME, encoder);
+ }
+ }
+ }
+
+ public VLBViaDecodeHandler createVLBViaDecodeHandler() {
+ return new VLBViaDecodeHandler(this.user);
+ }
+
+ public VLBViaEncodeHandler createVLBViaEncodeHandler() {
+ return new VLBViaEncodeHandler(this.user);
+ }
+
+ public abstract String getDecoderHandlerName();
+
+ public abstract String getEncoderHandlerName();
+
+ public abstract String getDecompressionHandlerName();
+
+ public abstract String getCompressionHandlerName();
+
+ public UserConnection getUser() {
+ return user;
+ }
+}
diff --git a/v1.20.2/src/florianmichael/vialoadingbase/netty/event/CompressionReorderEvent.java b/v1.20.2/src/florianmichael/vialoadingbase/netty/event/CompressionReorderEvent.java
new file mode 100644
index 0000000..daa82a6
--- /dev/null
+++ b/v1.20.2/src/florianmichael/vialoadingbase/netty/event/CompressionReorderEvent.java
@@ -0,0 +1,22 @@
+/*
+ * This file is part of ViaLoadingBase - https://github.com/FlorianMichael/ViaLoadingBase
+ * Copyright (C) 2020-2024 FlorianMichael/EnZaXD and contributors
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package de.florianmichael.vialoadingbase.netty.event;
+
+public class CompressionReorderEvent {
+}
diff --git a/v1.20.2/src/florianmichael/vialoadingbase/netty/handler/VLBViaDecodeHandler.java b/v1.20.2/src/florianmichael/vialoadingbase/netty/handler/VLBViaDecodeHandler.java
new file mode 100644
index 0000000..9731a1e
--- /dev/null
+++ b/v1.20.2/src/florianmichael/vialoadingbase/netty/handler/VLBViaDecodeHandler.java
@@ -0,0 +1,71 @@
+/*
+ * This file is part of ViaLoadingBase - https://github.com/FlorianMichael/ViaLoadingBase
+ * Copyright (C) 2020-2024 FlorianMichael/EnZaXD and contributors
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package de.florianmichael.vialoadingbase.netty.handler;
+
+import com.viaversion.viaversion.api.Via;
+import com.viaversion.viaversion.api.connection.UserConnection;
+import com.viaversion.viaversion.api.protocol.packet.State;
+import com.viaversion.viaversion.exception.CancelCodecException;
+import com.viaversion.viaversion.exception.CancelDecoderException;
+import com.viaversion.viaversion.exception.InformativeException;
+import com.viaversion.viaversion.util.PipelineUtil;
+import io.netty.buffer.ByteBuf;
+import io.netty.channel.ChannelHandler;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.handler.codec.MessageToMessageDecoder;
+
+import java.util.List;
+
+@ChannelHandler.Sharable
+public class VLBViaDecodeHandler extends MessageToMessageDecoder {
+ private final UserConnection user;
+
+ public VLBViaDecodeHandler(UserConnection user) {
+ this.user = user;
+ }
+
+ @Override
+ protected void decode(ChannelHandlerContext ctx, ByteBuf bytebuf, List