ViaMCP
Client-side Implementation of the Via* projects for MCP
Install / Use
/learn @ViaVersionMCP/ViaMCPQuality Score
Category
Development & EngineeringSupported Platforms
README
ViaMCP
ViaVersion VersionSwitcher for Minecraft Coder Pack (MCP)
<!-- TOC --> <!-- TOC -->Contact
If you encounter any issues, please report them on the
issue tracker.
If you just want to talk or need help with ViaMCP feel free to join my
Discord.
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:
// 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)
ViaVersion-[ver]-downgraded.jar > ViaVersion > https://github.com/ViaVersion/ViaVersion
ViaBackwards-[ver]-downgraded.jar > ViaBackwards > https://github.com/ViaVersion/ViaBackwards
ViaRewind-[ver]-downgraded.jar > ViaRewind > https://github.com/ViaVersion/ViaRewind
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
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 or generate them yourself using this tool.
Main-Class
Add this to the main class of your client (aka injection function)
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:
// 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:
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:
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));
}
Side note: 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:
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) <br>
In addSingleplayerMultiplayerButtons() function add (if in GuiMainMenu):
this.buttonList.add(new GuiButton(69, 5, 5, 90, 20, "Version"));
In actionPerformed() function add:
if (button.id == 69)
{
this.mc.displayGuiScreen(new GuiProtocolSelector(this));
}
Version Slider
You can also use a version slider to control ViaMCP versions
this.buttonList.add(ViaMCP.INSTANCE.getAsyncVersionSlider());
Clientside Fixes
Attack Order Fixes
Class: Minecraft.java <br> Function: clickMouse() <br>
1.8.x <br>
Replace this.thePlayer.swingItem(); on the 1st line in the if-clause with:
AttackOrder.sendConditionalSwing(this.objectMouseOver);
Replace this.playerController.attackEntity(this.thePlayer, this.objectMouseOver.entityHit); in the switch in case ENTITY with:
AttackOrder.sendFixedAttack(this.thePlayer, this.objectMouseOver.entityHit);
1.12.2 <br>
Replace this.player.swingArm(EnumHand.MAIN_HAND); at the last line in the else if-clause with:
AttackOrder.sendConditionalSwing(this.objectMouseOver, EnumHand.MAIN_HAND);
Replace this.playerController.attackEntity(this.player, this.objectMouseOver.entityHit); in the switch in case ENTITY with:
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:
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:
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 <br> Function: readPacketData() <br>
Replace the code with this method:
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 <br> Function: writePacketData() <br>
Replace the code with this method:
public void writePacketData(PacketBuffer buf) throws IOException {
if (ViaLoadingBase.getInstance().getTargetVersion().newerThanOrEqualTo(ProtocolVersion.v1_17)) {
buf.writeInt(this.windowId);
