EndMinecraftPlusV2/src/cn/serendipityr/EndMinecraftPlusV2/VersionControl/NewVersion/ForgeProtocol/MCForgeHandShakeV2.java

252 lines
10 KiB
Java

package cn.serendipityr.EndMinecraftPlusV2.VersionControl.NewVersion.ForgeProtocol;
import com.github.steveice10.mc.protocol.packet.login.client.LoginPluginResponsePacket;
import com.github.steveice10.mc.protocol.packet.login.clientbound.ClientboundCustomQueryPacket;
import com.github.steveice10.mc.protocol.packet.login.server.LoginPluginRequestPacket;
import com.github.steveice10.mc.protocol.packet.login.serverbound.ServerboundCustomQueryPacket;
import com.github.steveice10.packetlib.io.buffer.ByteBufferNetInput;
import com.github.steveice10.packetlib.io.stream.StreamNetOutput;
import com.github.steveice10.packetlib.packet.Packet;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class MCForgeHandShakeV2 extends MCForgeHandShake {
private final int Packet_S2CModList = 1;
private final int Packet_C2SModListReply = 2;
private final int Packet_S2CRegistry = 3;
private final int Packet_S2CConfigData = 4;
private final int Packet_C2SAcknowledge = 99;
public MCForgeHandShakeV2(MCForge forge) {
super(forge);
}
public void handle(Packet recvPacket) {
LoginPluginRequestPacket packet = (LoginPluginRequestPacket) recvPacket;
if (!packet.getChannel().equals("fml:loginwrapper")) return;
try {
LoginWrapper loginWrapper = new LoginWrapper().fromBytes(packet.getData());
String targetNetworkReceiver = loginWrapper.getTargetNetworkReceiver();
ByteBufferNetInput in = new ByteBufferNetInput(ByteBuffer.wrap(loginWrapper.getPayload()));
int packetID = in.readByte();
switch (packetID) {
case Packet_S2CModList: {
// recv: S2CModList
final List<String> mods = new ArrayList<>();
int len = in.readVarInt();
for (int x = 0; x < len; x++)
mods.add(in.readString());
final Map<String, String> channels = new HashMap<>();
len = in.readVarInt();
for (int x = 0; x < len; x++)
channels.put(in.readString(), in.readString());
final List<String> registries = new ArrayList<>();
len = in.readVarInt();
for (int x = 0; x < len; x++)
registries.add(in.readString());
// send: C2SModListReply
ByteArrayOutputStream buf = new ByteArrayOutputStream();
StreamNetOutput out = new StreamNetOutput(buf);
out.writeByte(Packet_C2SModListReply);
out.writeVarInt(mods.size());
mods.forEach(m -> {
try {
out.writeString(m);
} catch (IOException e) {
e.printStackTrace();
}
});
out.writeVarInt(channels.size());
channels.forEach((k, v) -> {
try {
out.writeString(k);
out.writeString(v);
} catch (IOException e) {
e.printStackTrace();
}
});
// TODO: Fill with known hashes, which requires keeping a file cache (FMLHandshakeMessages.java)
out.writeVarInt(0); // empty map
/*
out.writeVarInt(registries.size());
registries.forEach(r -> {
try {
out.writeString(r);
out.writeString("");
} catch (IOException e) {
e.printStackTrace();
}
});
*/
reply(packet.getMessageId(), targetNetworkReceiver, buf.toByteArray());
break;
}
case Packet_S2CRegistry:
case Packet_S2CConfigData: {
// recv: S2CRegistry
// send: C2SAcknowledge
ByteArrayOutputStream buf = new ByteArrayOutputStream();
StreamNetOutput out = new StreamNetOutput(buf);
out.writeByte(Packet_C2SAcknowledge);
reply(packet.getMessageId(), targetNetworkReceiver, buf.toByteArray());
break;
}// recv: S2CConfigData
}
} catch (Exception ex) {
forge.session.disconnect("Failure to handshake", ex);
}
}
public void newHandle(Packet recvPacket) {
ClientboundCustomQueryPacket packet = (ClientboundCustomQueryPacket) recvPacket;
if (!packet.getChannel().equals("fml:loginwrapper")) return;
try {
LoginWrapper loginWrapper = new LoginWrapper().fromBytes(packet.getData());
String targetNetworkReceiver = loginWrapper.getTargetNetworkReceiver();
ByteBufferNetInput in = new ByteBufferNetInput(ByteBuffer.wrap(loginWrapper.getPayload()));
int packetID = in.readByte();
switch (packetID) {
case Packet_S2CModList: {
// recv: S2CModList
final List<String> mods = new ArrayList<>();
int len = in.readVarInt();
for (int x = 0; x < len; x++)
mods.add(in.readString());
final Map<String, String> channels = new HashMap<>();
len = in.readVarInt();
for (int x = 0; x < len; x++)
channels.put(in.readString(), in.readString());
final List<String> registries = new ArrayList<>();
len = in.readVarInt();
for (int x = 0; x < len; x++)
registries.add(in.readString());
// send: C2SModListReply
ByteArrayOutputStream buf = new ByteArrayOutputStream();
StreamNetOutput out = new StreamNetOutput(buf);
out.writeByte(Packet_C2SModListReply);
out.writeVarInt(mods.size());
mods.forEach(m -> {
try {
out.writeString(m);
} catch (IOException e) {
e.printStackTrace();
}
});
out.writeVarInt(channels.size());
channels.forEach((k, v) -> {
try {
out.writeString(k);
out.writeString(v);
} catch (IOException e) {
e.printStackTrace();
}
});
// TODO: Fill with known hashes, which requires keeping a file cache (FMLHandshakeMessages.java)
out.writeVarInt(0); // empty map
/*
out.writeVarInt(registries.size());
registries.forEach(r -> {
try {
out.writeString(r);
out.writeString("");
} catch (IOException e) {
e.printStackTrace();
}
});
*/
newReply(packet.getMessageId(), targetNetworkReceiver, buf.toByteArray());
break;
}
case Packet_S2CRegistry:
case Packet_S2CConfigData: {
// recv: S2CRegistry
// send: C2SAcknowledge
ByteArrayOutputStream buf = new ByteArrayOutputStream();
StreamNetOutput out = new StreamNetOutput(buf);
out.writeByte(Packet_C2SAcknowledge);
newReply(packet.getMessageId(), targetNetworkReceiver, buf.toByteArray());
break;
}// recv: S2CConfigData
}
} catch (Exception ex) {
forge.session.disconnect("Failure to handshake", ex);
}
}
public String getFMLVersion() {
return "FML2";
}
private void reply(int id, String targetNetworkReceiver, byte[] payload) throws IOException {
forge.session.send(new LoginPluginResponsePacket(id, new LoginWrapper(targetNetworkReceiver, payload).toBytes()));
}
private void newReply(int id, String targetNetworkReceiver, byte[] payload) throws IOException {
forge.session.send(new ServerboundCustomQueryPacket(id, new LoginWrapper(targetNetworkReceiver, payload).toBytes()));
}
static class LoginWrapper {
private String targetNetworkReceiver;
private byte[] payload;
public LoginWrapper() {}
public LoginWrapper(String targetNetworkReceiver, byte[] payload) {
this.targetNetworkReceiver = targetNetworkReceiver;
this.payload = payload;
}
public LoginWrapper fromBytes(byte[] bytes) throws IOException {
ByteBufferNetInput in = new ByteBufferNetInput(ByteBuffer.wrap(bytes));
this.targetNetworkReceiver = in.readString();
this.payload = in.readBytes(in.readVarInt());
return this;
}
public byte[] toBytes() throws IOException {
ByteArrayOutputStream buf = new ByteArrayOutputStream();
StreamNetOutput pb = new StreamNetOutput(buf);
pb.writeString(targetNetworkReceiver);
pb.writeVarInt(payload.length);
pb.writeBytes(payload);
return buf.toByteArray();
}
public String getTargetNetworkReceiver() {
return this.targetNetworkReceiver;
}
public byte[] getPayload() {
return this.payload;
}
}
}