Skip to content

Commit f2a6185

Browse files
committed
ADD FULL SKIN PASSTHROUGH
1 parent 1dc04f3 commit f2a6185

File tree

3 files changed

+143
-74
lines changed

3 files changed

+143
-74
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
# ayunViaProxyEagUtils
22
eaglercraft support for viaproxy. ws:// on same port as java. supports both 1.5.2 and 1.8.8 eaglercraft depending on the configuration (e.g. use legacy passthrough & protocolsupport if the backend server doesn't support 1.5.2)
33

4-
note: skin files from 1.5.2 are excluded
4+
note: skin files are excluded

src/main/java/me/ayunami2000/ayunViaProxyEagUtils/EaglerServerHandler.java

Lines changed: 120 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import io.netty.buffer.ByteBuf;
1010
import io.netty.buffer.ByteBufUtil;
1111
import io.netty.buffer.Unpooled;
12+
import io.netty.channel.Channel;
1213
import io.netty.channel.ChannelHandlerContext;
1314
import io.netty.handler.codec.MessageToMessageCodec;
1415
import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame;
@@ -35,6 +36,7 @@
3536
import java.awt.image.Raster;
3637
import java.io.ByteArrayOutputStream;
3738
import java.io.IOException;
39+
import java.io.InputStream;
3840
import java.nio.charset.StandardCharsets;
3941
import java.util.List;
4042
import java.util.*;
@@ -153,59 +155,88 @@ public void encodeOld(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) {
153155
}
154156
if (in.readableBytes() >= 2 && in.getUnsignedByte(0) == 2) {
155157
in.setByte(1, in.getUnsignedByte(1) + 8);
158+
out.add(new BinaryWebSocketFrame(in.retain()));
159+
160+
Channel c2p;
161+
if (proxyConnection instanceof ProxyConnection) {
162+
c2p = ((ProxyConnection) proxyConnection).getC2P();
163+
} else {
164+
c2p = ((LegacyProxyConnection) proxyConnection).getC2P();
165+
}
166+
if (c2p.hasAttr(EaglercraftHandler.profileDataKey)) {
167+
EaglercraftHandler.ProfileData profileData = c2p.attr(EaglercraftHandler.profileDataKey).get();
168+
if (profileData.type.equals("skin_v1")) {
169+
int packetType = profileData.data[0] & 0xFF;
170+
if (packetType == 1 || packetType == 2) {
171+
try {
172+
byte[] res = SkinService.newToOldSkin(profileData.data);
173+
ByteBuf bb = ctx.alloc().buffer();
174+
bb.writeByte((byte) 250);
175+
Types1_6_4.STRING.write(bb, "EAG|MySkin");
176+
bb.writeShort(res.length);
177+
bb.writeBytes(res);
178+
out.add(new BinaryWebSocketFrame(bb));
179+
} catch (Exception ignored) {}
180+
}
181+
182+
}
183+
}
184+
return;
156185
}
157186
if (in.getUnsignedByte(0) == 0xFD) {
158187
return;
159188
}
160-
if (in.readableBytes() >= 3 && in.getUnsignedByte(0) == 250) {
161-
in.skipBytes(1);
162-
String tag;
163-
byte[] msg;
164-
try {
165-
tag = Types1_6_4.STRING.read(in);
166-
if (tag.equals("EAG|Skins-1.8")) {
167-
msg = new byte[in.readShort()];
168-
in.readBytes(msg);
169-
if (msg.length == 0) {
170-
throw new IOException("Zero-length packet recieved");
171-
}
172-
final int packetId = msg[0] & 0xFF;
173-
switch (packetId) {
174-
case 3: {
175-
if (msg.length != 17) {
176-
throw new IOException("Invalid length " + msg.length + " for skin request packet");
189+
if (proxyConnection instanceof ProxyConnection) {
190+
if (in.readableBytes() >= 3 && in.getUnsignedByte(0) == 250) {
191+
in.skipBytes(1);
192+
String tag;
193+
byte[] msg;
194+
try {
195+
tag = Types1_6_4.STRING.read(in);
196+
if (tag.equals("EAG|Skins-1.8")) {
197+
msg = new byte[in.readShort()];
198+
in.readBytes(msg);
199+
if (msg.length == 0) {
200+
throw new IOException("Zero-length packet recieved");
201+
}
202+
final int packetId = msg[0] & 0xFF;
203+
switch (packetId) {
204+
case 3: {
205+
if (msg.length != 17) {
206+
throw new IOException("Invalid length " + msg.length + " for skin request packet");
207+
}
208+
final UUID searchUUID = SkinPackets.bytesToUUID(msg, 1);
209+
if (uuidStringMap.containsKey(searchUUID)) {
210+
short id = skinFetchCounter++;
211+
skinsBeingFetched.put(id, searchUUID);
212+
String name = uuidStringMap.get(searchUUID);
213+
ByteBuf bb = ctx.alloc().buffer();
214+
bb.writeByte((byte) 250);
215+
Types1_6_4.STRING.write(bb, "EAG|FetchSkin");
216+
ByteBuf bbb = ctx.alloc().buffer();
217+
bbb.writeByte((byte) ((id >> 8) & 0xFF));
218+
bbb.writeByte((byte) (id & 0xFF));
219+
bbb.writeBytes(name.getBytes(StandardCharsets.UTF_8));
220+
bb.writeShort(bbb.readableBytes());
221+
bb.writeBytes(bbb);
222+
bbb.release();
223+
out.add(new BinaryWebSocketFrame(bb));
224+
}
225+
break;
177226
}
178-
final UUID searchUUID = SkinPackets.bytesToUUID(msg, 1);
179-
if (uuidStringMap.containsKey(searchUUID)) {
180-
short id = skinFetchCounter++;
181-
skinsBeingFetched.put(id, searchUUID);
182-
String name = uuidStringMap.get(searchUUID);
183-
ByteBuf bb = ctx.alloc().buffer();
184-
bb.writeByte((byte) 250);
185-
Types1_6_4.STRING.write(bb, "EAG|FetchSkin");
186-
ByteBuf bbb = ctx.alloc().buffer();
187-
bbb.writeByte((byte) ((id >> 8) & 0xFF));
188-
bbb.writeByte((byte) (id & 0xFF));
189-
bbb.writeBytes(name.getBytes(StandardCharsets.UTF_8));
190-
bb.writeShort(bbb.readableBytes());
191-
bb.writeBytes(bbb);
192-
bbb.release();
193-
out.add(new BinaryWebSocketFrame(bb));
227+
case 6: {
228+
break;
229+
}
230+
default: {
231+
throw new IOException("Unknown packet type " + packetId);
194232
}
195-
break;
196-
}
197-
case 6: {
198-
break;
199-
}
200-
default: {
201-
throw new IOException("Unknown packet type " + packetId);
202233
}
234+
return;
203235
}
204-
return;
236+
} catch (Exception ignored) {
205237
}
206-
} catch (Exception ignored) {
238+
in.resetReaderIndex();
207239
}
208-
in.resetReaderIndex();
209240
}
210241
out.add(new BinaryWebSocketFrame(in.retain()));
211242
}
@@ -438,35 +469,37 @@ public void decode(ChannelHandlerContext ctx, WebSocketFrame in, List<Object> ou
438469
}
439470
}
440471
public void decodeOld(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) {
441-
if (in.getUnsignedByte(0) == 0x14) {
442-
try {
443-
in.skipBytes(1);
444-
int eid = in.readInt();
445-
String name = Types1_6_4.STRING.read(in);
446-
UUID uuid = UUID.nameUUIDFromBytes(("OfflinePlayer:" + name).getBytes(StandardCharsets.UTF_8));
447-
eidUuidMap.put(eid, uuid);
448-
uuidStringMap.put(uuid, name);
449-
} catch (Exception ignored) {
450-
}
451-
in.resetReaderIndex();
452-
}
453-
if (in.getUnsignedByte(0) == 0x1D) {
454-
try {
455-
in.skipBytes(1);
456-
short count = in.readUnsignedByte();
457-
for (short i = 0; i < count; i++) {
472+
if (proxyConnection instanceof ProxyConnection) {
473+
if (in.getUnsignedByte(0) == 0x14) {
474+
try {
475+
in.skipBytes(1);
458476
int eid = in.readInt();
459-
if (eidUuidMap.containsKey(eid)) {
460-
uuidStringMap.remove(eidUuidMap.remove(eid));
477+
String name = Types1_6_4.STRING.read(in);
478+
UUID uuid = UUID.nameUUIDFromBytes(("OfflinePlayer:" + name).getBytes(StandardCharsets.UTF_8));
479+
eidUuidMap.put(eid, uuid);
480+
uuidStringMap.put(uuid, name);
481+
} catch (Exception ignored) {
482+
}
483+
in.resetReaderIndex();
484+
}
485+
if (in.getUnsignedByte(0) == 0x1D) {
486+
try {
487+
in.skipBytes(1);
488+
short count = in.readUnsignedByte();
489+
for (short i = 0; i < count; i++) {
490+
int eid = in.readInt();
491+
if (eidUuidMap.containsKey(eid)) {
492+
uuidStringMap.remove(eidUuidMap.remove(eid));
493+
}
461494
}
495+
} catch (Exception ignored) {
462496
}
463-
} catch (Exception ignored) {
497+
in.resetReaderIndex();
498+
}
499+
if (in.getUnsignedByte(0) == 0x09) {
500+
eidUuidMap.clear();
501+
uuidStringMap.clear();
464502
}
465-
in.resetReaderIndex();
466-
}
467-
if (in.getUnsignedByte(0) == 0x09) {
468-
eidUuidMap.clear();
469-
uuidStringMap.clear();
470503
}
471504
if (in.getUnsignedByte(0) == 0xFD) {
472505
in.writerIndex(0);
@@ -481,16 +514,32 @@ public void decodeOld(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) {
481514
byte[] msg;
482515
try {
483516
tag = Types1_6_4.STRING.read(in);
484-
if (tag.equals("EAG|UserSkin")) {
517+
if (proxyConnection instanceof ProxyConnection && tag.equals("EAG|UserSkin")) {
485518
msg = new byte[in.readShort()];
486519
in.readBytes(msg);
487520
short id = (short) ((msg[0] << 8) + msg[1]);
488521
if (!skinsBeingFetched.containsKey(id)) {
489522
return;
490523
}
491-
byte[] res = new byte[msg.length - 3];
524+
byte[] res = new byte[Math.min(16384, msg.length - 3)];
492525
System.arraycopy(msg, 3, res, 0, res.length);
493-
if (res.length == 8192) {
526+
if (res.length <= 16) {
527+
int presetId = res[0] & 0xFF;
528+
InputStream stream = Main.class.getResourceAsStream("/n" + presetId + ".png");
529+
if (stream != null) {
530+
try {
531+
res = ((DataBufferByte) ImageIO.read(stream).getRaster().getDataBuffer()).getData();
532+
for (int i = 0; i < res.length; i += 4) {
533+
final byte tmp = res[i];
534+
res[i] = res[i + 1];
535+
res[i + 1] = res[i + 2];
536+
res[i + 2] = res[i + 3];
537+
res[i + 3] = tmp;
538+
}
539+
} catch (IOException ignored) {}
540+
}
541+
}
542+
if (res.length >= 8192 && res.length < 16384) {
494543
final int[] tmp1 = new int[2048];
495544
final int[] tmp2 = new int[4096];
496545
for (int i = 0; i < tmp1.length; ++i) {

src/main/java/me/ayunami2000/ayunViaProxyEagUtils/SkinService.java

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,22 @@ public void processGetOtherSkin(final UUID searchUUID, final ChannelHandlerConte
3939
final byte[] src = EaglerSkinHandler.skinCollection.get(searchUUID);
4040
byte[] res = new byte[src.length - 1];
4141
System.arraycopy(src, 1, res, 0, res.length);
42+
if (res.length <= 16) {
43+
int presetId = res[0] & 0xFF;
44+
InputStream stream = Main.class.getResourceAsStream("/n" + presetId + ".png");
45+
if (stream != null) {
46+
try {
47+
res = ((DataBufferByte) ImageIO.read(stream).getRaster().getDataBuffer()).getData();
48+
for (int i = 0; i < res.length; i += 4) {
49+
final byte tmp = res[i];
50+
res[i] = res[i + 1];
51+
res[i + 1] = res[i + 2];
52+
res[i + 2] = res[i + 3];
53+
res[i + 3] = tmp;
54+
}
55+
} catch (IOException ignored) {}
56+
}
57+
}
4258
if (res.length == 8192) {
4359
final int[] tmp1 = new int[2048];
4460
final int[] tmp2 = new int[4096];
@@ -122,10 +138,12 @@ public static byte[] newToOldSkin(final byte[] packet) throws IOException {
122138
final byte type = packet[0];
123139
byte[] res;
124140
switch (type) {
141+
case 1:
125142
case 4: {
126143
res = new byte[16385];
127144
res[0] = 1;
128-
final int presetId = packet[17] << 24 | packet[18] << 16 | packet[19] << 8 | packet[20];
145+
final int o = type == 1 ? 16 : 0;
146+
final int presetId = packet[17 - o] << 24 | packet[18 - o] << 16 | packet[19 - o] << 8 | packet[20 - o];
129147
final InputStream stream = Main.class.getResourceAsStream("/" + presetId + ".png");
130148
if (stream == null) {
131149
throw new IOException("Invalid skin preset: " + presetId);
@@ -140,10 +158,12 @@ public static byte[] newToOldSkin(final byte[] packet) throws IOException {
140158
}
141159
break;
142160
}
161+
case 2:
143162
case 5: {
144163
res = new byte[16385];
145164
res[0] = 1;
146-
System.arraycopy(packet, 18, res, 1, 16384);
165+
final int o = type == 2 ? 16 : 0;
166+
System.arraycopy(packet, 18 - o, res, 1, 16384);
147167
for (int i = 1; i < 16385; i += 4) {
148168
final byte tmp = res[i];
149169
res[i] = res[i + 1];

0 commit comments

Comments
 (0)