Skip to content

Commit 0dba9a0

Browse files
committed
open sauce
0 parents  commit 0dba9a0

19 files changed

+1599
-0
lines changed

.gitattributes

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Auto detect text files and perform LF normalization
2+
* text=auto

.gitignore

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
.gradle
2+
.idea
3+
build
4+
gradle
5+
libs
6+
gradlew
7+
gradlew.bat
8+
src/main/resources/*.png

LICENSE

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
BSD 3-Clause License
2+
3+
Copyright (c) 2023, ayunami2000
4+
All rights reserved.
5+
6+
Redistribution and use in source and binary forms, with or without
7+
modification, are permitted provided that the following conditions are met:
8+
9+
1. Redistributions of source code must retain the above copyright notice, this
10+
list of conditions and the following disclaimer.
11+
12+
2. Redistributions in binary form must reproduce the above copyright notice,
13+
this list of conditions and the following disclaimer in the documentation
14+
and/or other materials provided with the distribution.
15+
16+
3. Neither the name of the copyright holder nor the names of its
17+
contributors may be used to endorse or promote products derived from
18+
this software without specific prior written permission.
19+
20+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# ayunViaProxyEagUtils
2+
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)
3+
4+
note: skin files from 1.5.2 are excluded

build.gradle

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
plugins {
2+
id 'java'
3+
}
4+
5+
group 'me.ayunami2000.ayunViaProxyEagUtils'
6+
version '1.0-SNAPSHOT'
7+
8+
repositories {
9+
mavenCentral()
10+
}
11+
12+
dependencies {
13+
implementation files("libs/ViaProxy-3.0.21-SNAPSHOT+java8_PATCHED.jar")
14+
}

settings.gradle

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
rootProject.name = 'ayunViaProxyEagUtils'
2+
Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
package me.ayunami2000.ayunViaProxyEagUtils;
2+
3+
import io.netty.buffer.ByteBuf;
4+
import io.netty.channel.ChannelHandlerContext;
5+
import io.netty.channel.ChannelInboundHandlerAdapter;
6+
import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame;
7+
import net.raphimc.vialegacy.protocols.release.protocol1_7_2_5to1_6_4.types.Types1_6_4;
8+
import net.raphimc.viaproxy.proxy.util.ExceptionUtil;
9+
10+
import java.io.ByteArrayOutputStream;
11+
import java.io.DataOutputStream;
12+
import java.io.IOException;
13+
import java.nio.charset.StandardCharsets;
14+
import java.util.HashMap;
15+
import java.util.UUID;
16+
import java.util.concurrent.ConcurrentHashMap;
17+
18+
public class EaglerSkinHandler extends ChannelInboundHandlerAdapter {
19+
public static final ConcurrentHashMap<UUID, byte[]> skinCollection;
20+
private static final ConcurrentHashMap<UUID, byte[]> capeCollection;
21+
private static final ConcurrentHashMap<UUID, Long> lastSkinLayerUpdate;
22+
private static final int[] SKIN_DATA_SIZE;
23+
private static final int[] CAPE_DATA_SIZE;
24+
private static final ConcurrentHashMap<UUID, ChannelHandlerContext> users;
25+
private final String user;
26+
27+
private static void sendData(final ChannelHandlerContext ctx, final String channel, final byte[] data) throws IOException {
28+
final ByteBuf bb = ctx.alloc().buffer();
29+
bb.writeByte(250);
30+
try {
31+
Types1_6_4.STRING.write(bb, channel);
32+
} catch (Exception e) {
33+
throw new IOException(e);
34+
}
35+
bb.writeShort(data.length);
36+
bb.writeBytes(data);
37+
ctx.writeAndFlush(new BinaryWebSocketFrame(bb));
38+
}
39+
40+
public EaglerSkinHandler(final String username) {
41+
this.user = username;
42+
}
43+
44+
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
45+
ExceptionUtil.handleNettyException(ctx, cause, null);
46+
}
47+
48+
public void channelRead(final ChannelHandlerContext ctx, final Object obj) throws Exception {
49+
final UUID uuid = UUID.nameUUIDFromBytes(("OfflinePlayer:" + this.user).getBytes(StandardCharsets.UTF_8));
50+
if (!EaglerSkinHandler.users.containsKey(uuid) && ctx.channel().isActive()) {
51+
EaglerSkinHandler.users.put(uuid, ctx);
52+
}
53+
if (obj instanceof BinaryWebSocketFrame) {
54+
final ByteBuf bb = ((BinaryWebSocketFrame) obj).content();
55+
if (bb.readableBytes() >= 3 && bb.readByte() == -6) {
56+
String tag;
57+
byte[] msg;
58+
try {
59+
tag = Types1_6_4.STRING.read(bb);
60+
msg = new byte[bb.readShort()];
61+
bb.readBytes(msg);
62+
} catch (Exception e) {
63+
bb.resetReaderIndex();
64+
super.channelRead(ctx, obj);
65+
return;
66+
}
67+
try {
68+
if ("EAG|MySkin".equals(tag)) {
69+
if (!EaglerSkinHandler.skinCollection.containsKey(uuid)) {
70+
final int t = msg[0] & 0xFF;
71+
if (t < EaglerSkinHandler.SKIN_DATA_SIZE.length && msg.length == EaglerSkinHandler.SKIN_DATA_SIZE[t] + 1) {
72+
EaglerSkinHandler.skinCollection.put(uuid, msg);
73+
}
74+
}
75+
bb.release();
76+
return;
77+
}
78+
if ("EAG|MyCape".equals(tag)) {
79+
if (!EaglerSkinHandler.capeCollection.containsKey(uuid)) {
80+
final int t = msg[0] & 0xFF;
81+
if (t < EaglerSkinHandler.CAPE_DATA_SIZE.length && msg.length == EaglerSkinHandler.CAPE_DATA_SIZE[t] + 2) {
82+
EaglerSkinHandler.capeCollection.put(uuid, msg);
83+
}
84+
}
85+
bb.release();
86+
return;
87+
}
88+
if ("EAG|FetchSkin".equals(tag)) {
89+
if (msg.length > 2) {
90+
final String fetch = new String(msg, 2, msg.length - 2, StandardCharsets.UTF_8);
91+
final UUID uuidFetch = UUID.nameUUIDFromBytes(("OfflinePlayer:" + fetch).getBytes(StandardCharsets.UTF_8));
92+
byte[] data;
93+
if ((data = EaglerSkinHandler.skinCollection.get(uuidFetch)) != null) {
94+
byte[] conc = new byte[data.length + 2];
95+
conc[0] = msg[0];
96+
conc[1] = msg[1];
97+
System.arraycopy(data, 0, conc, 2, data.length);
98+
if ((data = EaglerSkinHandler.capeCollection.get(uuidFetch)) != null) {
99+
final byte[] conc2 = new byte[conc.length + data.length];
100+
System.arraycopy(conc, 0, conc2, 0, conc.length);
101+
System.arraycopy(data, 0, conc2, conc.length, data.length);
102+
conc = conc2;
103+
}
104+
sendData(ctx, "EAG|UserSkin", conc);
105+
}
106+
}
107+
bb.release();
108+
return;
109+
}
110+
if ("EAG|SkinLayers".equals(tag)) {
111+
final long millis = System.currentTimeMillis();
112+
final Long lsu = EaglerSkinHandler.lastSkinLayerUpdate.get(uuid);
113+
if (lsu != null && millis - lsu < 700L) {
114+
return;
115+
}
116+
EaglerSkinHandler.lastSkinLayerUpdate.put(uuid, millis);
117+
byte[] conc2;
118+
if ((conc2 = EaglerSkinHandler.capeCollection.get(uuid)) != null) {
119+
conc2[1] = msg[0];
120+
} else {
121+
conc2 = new byte[]{2, msg[0], 0};
122+
EaglerSkinHandler.capeCollection.put(uuid, conc2);
123+
}
124+
final ByteArrayOutputStream bao = new ByteArrayOutputStream();
125+
final DataOutputStream dd = new DataOutputStream(bao);
126+
dd.write(msg[0]);
127+
dd.writeUTF(this.user);
128+
final byte[] bpacket = bao.toByteArray();
129+
for (final UUID pl : EaglerSkinHandler.users.keySet()) {
130+
if (!pl.equals(uuid)) {
131+
sendData(EaglerSkinHandler.users.get(pl), "EAG|SkinLayers", bpacket);
132+
}
133+
}
134+
bb.release();
135+
return;
136+
}
137+
} catch (Throwable var18) {
138+
var18.printStackTrace();
139+
}
140+
}
141+
bb.resetReaderIndex();
142+
}
143+
super.channelRead(ctx, obj);
144+
}
145+
146+
public void channelInactive(final ChannelHandlerContext ctx) throws Exception {
147+
super.channelInactive(ctx);
148+
final UUID uuid = UUID.nameUUIDFromBytes(("OfflinePlayer:" + this.user).getBytes(StandardCharsets.UTF_8));
149+
EaglerSkinHandler.users.remove(uuid);
150+
EaglerSkinHandler.skinCollection.remove(uuid);
151+
EaglerSkinHandler.capeCollection.remove(uuid);
152+
EaglerSkinHandler.lastSkinLayerUpdate.remove(uuid);
153+
}
154+
155+
static {
156+
skinCollection = new ConcurrentHashMap<>();
157+
capeCollection = new ConcurrentHashMap<>();
158+
lastSkinLayerUpdate = new ConcurrentHashMap<>();
159+
SKIN_DATA_SIZE = new int[]{8192, 16384, -9, -9, 1, 16384, -9};
160+
CAPE_DATA_SIZE = new int[]{4096, -9, 1};
161+
users = new ConcurrentHashMap<>();
162+
}
163+
}

0 commit comments

Comments
 (0)