Skip to content

Commit

Permalink
Implement Forge FML2 protocol (MC 1.13+) (#1184)
Browse files Browse the repository at this point in the history
Forge uses a different handshake scheme in FML2 protocol.
This handshake scheme uses LoginPluginRequest/Response packets.
  • Loading branch information
ORelio committed Aug 11, 2020
1 parent aeac568 commit a284090
Show file tree
Hide file tree
Showing 5 changed files with 348 additions and 93 deletions.
1 change: 1 addition & 0 deletions MinecraftClient/MinecraftClient.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@
<Compile Include="Mapping\MaterialExtensions.cs" />
<Compile Include="Protocol\EntityActionType.cs" />
<Compile Include="Protocol\Handlers\DataTypes.cs" />
<Compile Include="Protocol\Handlers\Forge\FMLVersion.cs" />
<Compile Include="Protocol\Handlers\PacketIncomingType.cs" />
<Compile Include="Protocol\Handlers\PacketOutgoingType.cs" />
<Compile Include="Protocol\Handlers\Protocol18Forge.cs" />
Expand Down
17 changes: 17 additions & 0 deletions MinecraftClient/Protocol/Handlers/Forge/FMLVersion.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MinecraftClient.Protocol.Handlers.Forge
{
/// <summary>
/// Version of the FML protocol
/// </summary>
/// <seealso href="https://github.com/MinecraftForge/MinecraftForge/blob/master/src/main/java/net/minecraftforge/fml/network/FMLNetworkConstants.java"/>
enum FMLVersion
{
FML,
FML2
}
}
154 changes: 78 additions & 76 deletions MinecraftClient/Protocol/Handlers/Forge/ForgeInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,92 +31,94 @@ public override string ToString()
}

public List<ForgeMod> Mods;
internal FMLVersion Version;

/// <summary>
/// Create a new ForgeInfo from the given data.
/// </summary>
/// <param name="data">The modinfo JSON tag.</param>
/// <exception cref="System.ArgumentException">Thrown on missing mod list in JSON data</exception>
internal ForgeInfo(Json.JSONData data)
/// <param name="fmlVersion">Forge protocol version</param>
internal ForgeInfo(Json.JSONData data, FMLVersion fmlVersion)
{
this.Mods = new List<ForgeMod>();
bool listFound = false;

// Example ModInfo for Minecraft 1.12 and lower (FML)

// "modinfo": {
// "type": "FML",
// "modList": [{
// "modid": "mcp",
// "version": "9.05"
// }, {
// "modid": "FML",
// "version": "8.0.99.99"
// }, {
// "modid": "Forge",
// "version": "11.14.3.1512"
// }, {
// "modid": "rpcraft",
// "version": "Beta 1.3 - 1.8.0"
// }]
// }

if (data.Properties.ContainsKey("modList") && data.Properties["modList"].Type == Json.JSONData.DataType.Array)
{
listFound = true;

foreach (Json.JSONData mod in data.Properties["modList"].DataArray)
{
String modid = mod.Properties["modid"].StringValue;
String version = mod.Properties["version"].StringValue;

this.Mods.Add(new ForgeMod(modid, version));
}
}
this.Version = fmlVersion;

// Example ModInfo for Minecraft 1.13 and greater (FML2)

// "forgeData": {
// "channels": [{
// "res": "minecraft:unregister",
// "version": "FML2",
// "required": true
// }, {
// "res": "minecraft:register",
// "version": "FML2",
// "required": true
// }],
// "mods": [{
// "modId": "minecraft",
// "modmarker": "1.15.2"
// }, {
// "modId": "forge",
// "modmarker": "ANY"
// }, {
// "modId": "rats",
// "modmarker": "5.3.2"
// }, {
// "modId": "citadel",
// "modmarker": "1.1.11"
// }],
// "fmlNetworkVersion": 2
// }

if (data.Properties.ContainsKey("mods") && data.Properties["mods"].Type == Json.JSONData.DataType.Array)
switch (fmlVersion)
{
listFound = true;

foreach (Json.JSONData mod in data.Properties["mods"].DataArray)
{
String modid = mod.Properties["modId"].StringValue;
String version = mod.Properties["modmarker"].StringValue;

this.Mods.Add(new ForgeMod(modid, version));
}
case FMLVersion.FML:

// Example ModInfo for Minecraft 1.12 and lower (FML)

// "modinfo": {
// "type": "FML",
// "modList": [{
// "modid": "mcp",
// "version": "9.05"
// }, {
// "modid": "FML",
// "version": "8.0.99.99"
// }, {
// "modid": "Forge",
// "version": "11.14.3.1512"
// }, {
// "modid": "rpcraft",
// "version": "Beta 1.3 - 1.8.0"
// }]
// }

foreach (Json.JSONData mod in data.Properties["modList"].DataArray)
{
String modid = mod.Properties["modid"].StringValue;
String modversion = mod.Properties["version"].StringValue;

this.Mods.Add(new ForgeMod(modid, modversion));
}

break;

case FMLVersion.FML2:

// Example ModInfo for Minecraft 1.13 and greater (FML2)

// "forgeData": {
// "channels": [{
// "res": "minecraft:unregister",
// "version": "FML2",
// "required": true
// }, {
// "res": "minecraft:register",
// "version": "FML2",
// "required": true
// }],
// "mods": [{
// "modId": "minecraft",
// "modmarker": "1.15.2"
// }, {
// "modId": "forge",
// "modmarker": "ANY"
// }, {
// "modId": "rats",
// "modmarker": "5.3.2"
// }, {
// "modId": "citadel",
// "modmarker": "1.1.11"
// }],
// "fmlNetworkVersion": 2
// }

foreach (Json.JSONData mod in data.Properties["mods"].DataArray)
{
String modid = mod.Properties["modId"].StringValue;
String modmarker = mod.Properties["modmarker"].StringValue;

this.Mods.Add(new ForgeMod(modid, modmarker));
}

break;

default:
throw new NotImplementedException("FMLVersion '" + fmlVersion + "' not implemented!");
}

if (!listFound)
throw new ArgumentException("Missing mod list", "data");
}
}
}
30 changes: 28 additions & 2 deletions MinecraftClient/Protocol/Handlers/Protocol18.cs
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ internal void ReadNextPacket(ref int packetID, Queue<byte> packetData)
{
packetData.Clear();
int size = dataTypes.ReadNextVarIntRAW(socketWrapper); //Packet size
byte[] rawpacket = socketWrapper.ReadDataRAW(size);//Packet contents
byte[] rawpacket = socketWrapper.ReadDataRAW(size); //Packet contents
for (int i = 0; i < rawpacket.Length; i++)
packetData.Enqueue(rawpacket[i]);

Expand Down Expand Up @@ -209,6 +209,13 @@ internal bool HandlePacket(int packetID, Queue<byte> packetData)
if (protocolversion >= MC18Version)
compression_treshold = dataTypes.ReadNextVarInt(packetData);
break;
case 0x04:
int messageId = dataTypes.ReadNextVarInt(packetData);
string channel = dataTypes.ReadNextString(packetData);
List<byte> responseData = new List<byte>();
bool understood = pForge.HandleLoginPluginRequest(channel, packetData, ref responseData);
SendLoginPluginResponse(messageId, understood, responseData.ToArray());
return understood;
default:
return false; //Ignored packet
}
Expand Down Expand Up @@ -1012,7 +1019,7 @@ public bool Login()
{
byte[] protocol_version = dataTypes.GetVarInt(protocolversion);
string server_address = pForge.GetServerAddress(handler.GetServerHost());
byte[] server_port = BitConverter.GetBytes((ushort)handler.GetServerPort()); Array.Reverse(server_port);
byte[] server_port = dataTypes.GetUShort((ushort)handler.GetServerPort());
byte[] next_state = dataTypes.GetVarInt(2);
byte[] handshake_packet = dataTypes.ConcatBytes(protocol_version, dataTypes.GetString(server_address), server_port, next_state);

Expand Down Expand Up @@ -1445,6 +1452,25 @@ public bool SendPluginChannelPacket(string channel, byte[] data)
catch (ObjectDisposedException) { return false; }
}

/// <summary>
/// Send a Login Plugin Response packet (0x02)
/// </summary>
/// <param name="messageId">Login Plugin Request message Id </param>
/// <param name="understood">TRUE if the request was understood</param>
/// <param name="data">Response to the request</param>
/// <returns>TRUE if successfully sent</returns>
public bool SendLoginPluginResponse(int messageId, bool understood, byte[] data)
{
try
{
SendPacket(0x02, dataTypes.ConcatBytes(dataTypes.GetVarInt(messageId), dataTypes.GetBool(understood), data));
return true;
}
catch (SocketException) { return false; }
catch (System.IO.IOException) { return false; }
catch (ObjectDisposedException) { return false; }
}

/// <summary>
/// Send an Interact Entity Packet to server
/// </summary>
Expand Down
Loading

0 comments on commit a284090

Please sign in to comment.