mirror of
https://github.com/ayunami2000/ayunViaProxyEagUtils.git
synced 2024-12-22 06:44:11 -08:00
finish eag1.8-->eag1.5 skin support
also make it work on latest dev viaproxy
This commit is contained in:
parent
5761ac3fb6
commit
1f86cb9d2b
|
@ -8,6 +8,7 @@ import io.netty.buffer.Unpooled;
|
|||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.MessageToMessageCodec;
|
||||
import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame;
|
||||
import net.jodah.expiringmap.ExpiringMap;
|
||||
import net.raphimc.netminecraft.constants.MCPackets;
|
||||
import net.raphimc.netminecraft.netty.connection.NetClient;
|
||||
import net.raphimc.netminecraft.packet.PacketTypes;
|
||||
|
@ -19,16 +20,22 @@ import net.raphimc.viaproxy.proxy.session.LegacyProxyConnection;
|
|||
import net.raphimc.viaproxy.proxy.session.ProxyConnection;
|
||||
import net.raphimc.viaproxy.proxy.util.ExceptionUtil;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class EaglerServerHandler extends MessageToMessageCodec<BinaryWebSocketFrame, ByteBuf> {
|
||||
private final VersionEnum version;
|
||||
private final String password;
|
||||
private final NetClient proxyConnection;
|
||||
private final List<UUID> skinsBeingFetched = new ArrayList<>();
|
||||
private final Map<UUID, String> uuidStringMap = new HashMap<>();
|
||||
private final Map<Integer, UUID> eidUuidMap = new HashMap<>();
|
||||
private final ExpiringMap<Short, UUID> skinsBeingFetched = ExpiringMap.builder().expiration(1, TimeUnit.MINUTES).build();
|
||||
private short skinFetchCounter = 0;
|
||||
private ByteBuf serverBoundPartialPacket = Unpooled.EMPTY_BUFFER;
|
||||
private ByteBuf clientBoundPartialPacket = Unpooled.EMPTY_BUFFER;
|
||||
public EaglerServerHandler(NetClient proxyConnection, String password) {
|
||||
|
@ -47,6 +54,30 @@ public class EaglerServerHandler extends MessageToMessageCodec<BinaryWebSocketFr
|
|||
@Override
|
||||
public void encode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) {
|
||||
if (version.isNewerThan(VersionEnum.r1_6_4)) {
|
||||
if (in.readableBytes() == 2 && in.getUnsignedByte(0) == 0xFE && in.getUnsignedByte(1) == 0x01) {
|
||||
// todo: legacy ping
|
||||
ctx.close();
|
||||
return;
|
||||
}
|
||||
|
||||
int len = PacketTypes.readVarInt(in);
|
||||
ByteBuf bb = ctx.alloc().buffer(len);
|
||||
bb.writeBytes(in);
|
||||
int id = PacketTypes.readVarInt(bb);
|
||||
if (id == 0x00) {
|
||||
PacketTypes.readVarInt(bb);
|
||||
PacketTypes.readString(bb, 32767);
|
||||
bb.readUnsignedShort();
|
||||
int nextState = PacketTypes.readVarInt(bb);
|
||||
if (nextState == 1) {
|
||||
// todo: ping
|
||||
ctx.close();
|
||||
return;
|
||||
}
|
||||
}
|
||||
bb.release();
|
||||
in.resetReaderIndex();
|
||||
|
||||
if (handshakeState == 0) {
|
||||
handshakeState = 1;
|
||||
if (((ProxyConnection) proxyConnection).getGameProfile() == null) {
|
||||
|
@ -80,6 +111,10 @@ public class EaglerServerHandler extends MessageToMessageCodec<BinaryWebSocketFr
|
|||
bb.readerIndex(readerIndex);
|
||||
bb.readBytes(packet, len);
|
||||
encodeOld(ctx, packet, out);
|
||||
if (!ctx.channel().isOpen()) {
|
||||
out.add(Unpooled.EMPTY_BUFFER);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
bb.readerIndex(readerIndex);
|
||||
|
@ -98,18 +133,61 @@ public class EaglerServerHandler extends MessageToMessageCodec<BinaryWebSocketFr
|
|||
}
|
||||
|
||||
public void encodeOld(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) {
|
||||
if (in.readableBytes() == 2 && in.getUnsignedByte(0) == 0xFE && in.getUnsignedByte(1) == 0x01) {
|
||||
// todo: legacy ping
|
||||
ctx.close();
|
||||
return;
|
||||
}
|
||||
if (in.readableBytes() >= 2 && in.getUnsignedByte(0) == 2) {
|
||||
in.setByte(1, in.getUnsignedByte(1) + 8);
|
||||
}
|
||||
if (in.readableBytes() >= 1 && in.getUnsignedByte(0) == 0xFD) {
|
||||
if (in.getUnsignedByte(0) == 0xFD) {
|
||||
return;
|
||||
}
|
||||
if (in.readableBytes() >= 3 && in.getUnsignedByte(0) == 250) {
|
||||
in.skipBytes(1);
|
||||
String tag;
|
||||
byte[] msg;
|
||||
try {
|
||||
tag = Types1_6_4.STRING.read(in);
|
||||
if (tag.equals("EAG|Skins-1.8")) {
|
||||
msg = new byte[in.readShort()];
|
||||
in.readBytes(msg);
|
||||
if (msg.length == 0) {
|
||||
throw new IOException("Zero-length packet recieved");
|
||||
}
|
||||
final int packetId = msg[0] & 0xFF;
|
||||
switch (packetId) {
|
||||
case 3: {
|
||||
if (msg.length != 17) {
|
||||
throw new IOException("Invalid length " + msg.length + " for skin request packet");
|
||||
}
|
||||
final UUID searchUUID = SkinPackets.bytesToUUID(msg, 1);
|
||||
if (uuidStringMap.containsKey(searchUUID)) {
|
||||
short id = skinFetchCounter++;
|
||||
skinsBeingFetched.put(id, searchUUID);
|
||||
String name = uuidStringMap.get(searchUUID);
|
||||
ByteBuf bb = ctx.alloc().buffer();
|
||||
bb.writeByte((byte) 250);
|
||||
Types1_6_4.STRING.write(bb, "EAG|FetchSkin");
|
||||
ByteBuf bbb = ctx.alloc().buffer();
|
||||
bbb.writeByte((byte) ((id >> 8) & 0xFF));
|
||||
bbb.writeByte((byte) (id & 0xFF));
|
||||
bbb.writeBytes(name.getBytes(StandardCharsets.UTF_8));
|
||||
bb.writeShort(bbb.readableBytes());
|
||||
bb.writeBytes(bbb);
|
||||
bbb.release();
|
||||
out.add(new BinaryWebSocketFrame(bb));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 6: {
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
throw new IOException("Unknown packet type " + packetId);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
|
@ -190,26 +268,35 @@ public class EaglerServerHandler extends MessageToMessageCodec<BinaryWebSocketFr
|
|||
}
|
||||
public void decodeOld(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) {
|
||||
if (in.getUnsignedByte(0) == 0x14) {
|
||||
in.skipBytes(5);
|
||||
try {
|
||||
in.skipBytes(1);
|
||||
int eid = in.readInt();
|
||||
String name = Types1_6_4.STRING.read(in);
|
||||
UUID uuid = UUID.nameUUIDFromBytes(("OfflinePlayer:" + name).getBytes(StandardCharsets.UTF_8));
|
||||
skinsBeingFetched.add(uuid);
|
||||
ByteBuf bb = ctx.alloc().buffer();
|
||||
bb.writeByte((byte) 250);
|
||||
Types1_6_4.STRING.write(bb, "EAG|FetchSkin");
|
||||
ByteBuf bbb = ctx.alloc().buffer();
|
||||
bbb.writeByte((byte) 0);
|
||||
bbb.writeByte((byte) 0);
|
||||
bbb.writeBytes(name.getBytes(StandardCharsets.UTF_8));
|
||||
bb.writeShort(bbb.readableBytes());
|
||||
bb.writeBytes(bbb);
|
||||
bbb.release();
|
||||
ctx.writeAndFlush(new BinaryWebSocketFrame(bb));
|
||||
eidUuidMap.put(eid, uuid);
|
||||
uuidStringMap.put(uuid, name);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
in.resetReaderIndex();
|
||||
}
|
||||
if (in.getUnsignedByte(0) == 0x1D) {
|
||||
try {
|
||||
in.skipBytes(1);
|
||||
short count = in.readUnsignedByte();
|
||||
for (short i = 0; i < count; i++) {
|
||||
int eid = in.readInt();
|
||||
if (eidUuidMap.containsKey(eid)) {
|
||||
uuidStringMap.remove(eidUuidMap.remove(eid));
|
||||
}
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
in.resetReaderIndex();
|
||||
}
|
||||
if (in.getUnsignedByte(0) == 0x09) {
|
||||
eidUuidMap.clear();
|
||||
uuidStringMap.clear();
|
||||
}
|
||||
if (in.getUnsignedByte(0) == 0xFD) {
|
||||
in.writerIndex(0);
|
||||
in.writeByte((byte) 0xCD);
|
||||
|
@ -224,19 +311,15 @@ public class EaglerServerHandler extends MessageToMessageCodec<BinaryWebSocketFr
|
|||
try {
|
||||
tag = Types1_6_4.STRING.read(in);
|
||||
if (tag.equals("EAG|UserSkin")) {
|
||||
if (skinsBeingFetched.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
msg = new byte[in.readShort()];
|
||||
in.readBytes(msg);
|
||||
if (msg.length < 8192) {
|
||||
short id = (short) ((msg[0] << 8) + msg[1]);
|
||||
if (!skinsBeingFetched.containsKey(id)) {
|
||||
return;
|
||||
}
|
||||
// TODO: FIX LOL!!
|
||||
// also todo: handle status packets
|
||||
byte[] res = new byte[msg.length > 16384 ? 16384 : 8192];
|
||||
System.arraycopy(msg, 1, res, 0, res.length);
|
||||
if (res.length < 16384) {
|
||||
byte[] res = new byte[msg.length - 3];
|
||||
System.arraycopy(msg, 3, res, 0, res.length);
|
||||
if (res.length == 8192) {
|
||||
final int[] tmp1 = new int[2048];
|
||||
final int[] tmp2 = new int[4096];
|
||||
for (int i = 0; i < tmp1.length; ++i) {
|
||||
|
@ -247,7 +330,7 @@ public class EaglerServerHandler extends MessageToMessageCodec<BinaryWebSocketFr
|
|||
for (int i = 0; i < tmp2.length; ++i) {
|
||||
System.arraycopy(Ints.toByteArray(tmp2[i]), 0, res, i * 4, 4);
|
||||
}
|
||||
} else {
|
||||
} else if (res.length == 16384) {
|
||||
for (int j = 0; j < res.length; j += 4) {
|
||||
final byte tmp3 = res[j + 3];
|
||||
res[j + 3] = res[j + 2];
|
||||
|
@ -255,11 +338,21 @@ public class EaglerServerHandler extends MessageToMessageCodec<BinaryWebSocketFr
|
|||
res[j + 1] = res[j];
|
||||
res[j] = tmp3;
|
||||
}
|
||||
} else {
|
||||
ByteBuf bb = ctx.alloc().buffer();
|
||||
bb.writeByte((byte) 250);
|
||||
Types1_6_4.STRING.write(bb, "EAG|Skins-1.8");
|
||||
byte[] data = SkinPackets.makePresetResponse(skinsBeingFetched.remove(id));
|
||||
bb.writeShort(data.length);
|
||||
bb.writeBytes(data);
|
||||
out.add(bb);
|
||||
return;
|
||||
}
|
||||
UUID uuid = skinsBeingFetched.remove(id);
|
||||
ByteBuf bb = ctx.alloc().buffer();
|
||||
bb.writeByte((byte) 250);
|
||||
Types1_6_4.STRING.write(bb, "EAG|Skins-1.8");
|
||||
byte[] data = SkinPackets.makeCustomResponse(skinsBeingFetched.remove(0), 0, res);
|
||||
byte[] data = SkinPackets.makeCustomResponse(uuid, 0, res);
|
||||
bb.writeShort(data.length);
|
||||
bb.writeBytes(data);
|
||||
out.add(bb);
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
package me.ayunami2000.ayunViaProxyEagUtils;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||
import io.netty.channel.*;
|
||||
import io.netty.handler.codec.http.*;
|
||||
import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame;
|
||||
import io.netty.handler.codec.http.websocketx.WebSocketClientHandshakerFactory;
|
||||
|
@ -25,6 +23,7 @@ import net.raphimc.viaproxy.plugins.events.Proxy2ServerChannelInitializeEvent;
|
|||
import net.raphimc.viaproxy.plugins.events.types.ITyped;
|
||||
import net.raphimc.viaproxy.proxy.session.LegacyProxyConnection;
|
||||
import net.raphimc.viaproxy.proxy.session.ProxyConnection;
|
||||
import net.raphimc.viaproxy.proxy.util.ChannelUtil;
|
||||
import net.raphimc.viaproxy.proxy.util.ExceptionUtil;
|
||||
|
||||
import javax.net.ssl.*;
|
||||
|
@ -94,8 +93,7 @@ public class Main extends ViaProxyPlugin {
|
|||
|
||||
|
||||
|
||||
|
||||
// c2p.attr(secureWs).set(true);
|
||||
c2p.attr(secureWs).set(true); // todo: THIS!!
|
||||
|
||||
|
||||
|
||||
|
@ -103,6 +101,29 @@ public class Main extends ViaProxyPlugin {
|
|||
|
||||
if (c2p.hasAttr(secureWs)) {
|
||||
doWsServerStuff(ch, proxyConnection, c2p, addr);
|
||||
if (!event.isLegacyPassthrough()) {
|
||||
ch.pipeline().addFirst("handshake-waiter", new ChannelOutboundHandlerAdapter() {
|
||||
private boolean hasHandshake = false;
|
||||
|
||||
@Override
|
||||
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
|
||||
if (msg instanceof ByteBuf) {
|
||||
hasHandshake = true;
|
||||
ChannelUtil.restoreAutoRead(c2p);
|
||||
}
|
||||
super.write(ctx, msg, promise);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush(ChannelHandlerContext ctx) throws Exception {
|
||||
super.flush(ctx);
|
||||
if (hasHandshake) {
|
||||
ch.pipeline().remove(this);
|
||||
ChannelUtil.disableAutoRead(c2p);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -114,13 +135,33 @@ public class Main extends ViaProxyPlugin {
|
|||
} else if (ch.pipeline().get(MCPipeline.ENCRYPTION_HANDLER_NAME) != null) {
|
||||
ch.pipeline().remove(MCPipeline.ENCRYPTION_HANDLER_NAME);
|
||||
}
|
||||
if (c2p.pipeline().get("ayun-eag-voice") != null) {
|
||||
c2p.pipeline().remove("ayun-eag-voice");
|
||||
}
|
||||
if (c2p.pipeline().get("ayun-eag-skin") != null) {
|
||||
c2p.pipeline().remove("ayun-eag-skin");
|
||||
}
|
||||
if (c2p.pipeline().get("ayun-eag-x-login") != null) {
|
||||
c2p.pipeline().remove("ayun-eag-x-login");
|
||||
}
|
||||
if (c2p.pipeline().get("ayun-eag-skin-x") != null) {
|
||||
c2p.pipeline().remove("ayun-eag-skin-x");
|
||||
}
|
||||
StringBuilder url = new StringBuilder("ws");
|
||||
boolean secure = c2p.attr(secureWs).get();
|
||||
if (secure) {
|
||||
final SSLEngine sslEngine = sc.createSSLEngine(addr.getAddress(), addr.getPort());
|
||||
sslEngine.setUseClientMode(true);
|
||||
sslEngine.setNeedClientAuth(false);
|
||||
ch.pipeline().addFirst("eag-server-ssl", new SslHandler(sslEngine));
|
||||
ch.pipeline().addFirst("eag-server-ssl", new SslHandler(sslEngine) {
|
||||
@Override
|
||||
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
|
||||
if (this.handshakeFuture().cause() != null) {
|
||||
ExceptionUtil.handleNettyException(ctx, this.handshakeFuture().cause(), null);
|
||||
}
|
||||
super.closeOutbound();
|
||||
}
|
||||
});
|
||||
url.append("s");
|
||||
ch.pipeline().addAfter("eag-server-ssl", "eag-server-http-codec", new HttpClientCodec());
|
||||
} else {
|
||||
|
@ -163,9 +204,7 @@ public class Main extends ViaProxyPlugin {
|
|||
super.userEventTriggered(ctx, evt);
|
||||
if (evt instanceof EaglercraftInitialHandler.EaglercraftClientConnected) {
|
||||
ctx.pipeline().remove("ayun-eag-detector");
|
||||
if (!ctx.channel().hasAttr(secureWs)) {
|
||||
ctx.pipeline().addBefore("eaglercraft-handler", "ayun-eag-utils-init", new EaglerUtilsInitHandler());
|
||||
}
|
||||
ctx.pipeline().addBefore("eaglercraft-handler", "ayun-eag-utils-init", new EaglerUtilsInitHandler());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ import io.netty.channel.ChannelHandlerContext;
|
|||
import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame;
|
||||
import net.raphimc.netminecraft.constants.MCPackets;
|
||||
import net.raphimc.netminecraft.packet.PacketTypes;
|
||||
import net.raphimc.vialegacy.protocols.release.protocol1_7_2_5to1_6_4.types.Types1_6_4;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.image.DataBufferByte;
|
||||
|
@ -50,7 +51,7 @@ public class SkinService {
|
|||
for (int i = 0; i < tmp2.length; ++i) {
|
||||
System.arraycopy(Ints.toByteArray(tmp2[i]), 0, res, i * 4, 4);
|
||||
}
|
||||
} else {
|
||||
} else if (res.length == 16384) {
|
||||
for (int j = 0; j < res.length; j += 4) {
|
||||
final byte tmp3 = res[j + 3];
|
||||
res[j + 3] = res[j + 2];
|
||||
|
@ -58,6 +59,9 @@ public class SkinService {
|
|||
res[j + 1] = res[j];
|
||||
res[j] = tmp3;
|
||||
}
|
||||
} else {
|
||||
sendData(sender, SkinPackets.makePresetResponse(searchUUID));
|
||||
return;
|
||||
}
|
||||
sendData(sender, SkinPackets.makeCustomResponse(searchUUID, 0, res));
|
||||
} else {
|
||||
|
|
Loading…
Reference in New Issue
Block a user