mirror of
https://github.com/ayunami2000/ayunViaProxyEagUtils.git
synced 2024-11-22 04:16:04 -08:00
update a LOT
todo: 1.8 capes and fnaw skins
This commit is contained in:
parent
6cc8a79c8b
commit
790b33ad68
|
@ -10,5 +10,5 @@ repositories {
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation files("libs/ViaProxy-3.0.22-SNAPSHOT+java8.jar")
|
implementation files("libs/ViaProxy-3.2.0-SNAPSHOT+java8.jar")
|
||||||
}
|
}
|
|
@ -5,6 +5,7 @@ import com.google.gson.JsonArray;
|
||||||
import com.google.gson.JsonElement;
|
import com.google.gson.JsonElement;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
import com.google.gson.JsonParser;
|
import com.google.gson.JsonParser;
|
||||||
|
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
|
||||||
import com.viaversion.viaversion.util.ChatColorUtil;
|
import com.viaversion.viaversion.util.ChatColorUtil;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import io.netty.buffer.ByteBufUtil;
|
import io.netty.buffer.ByteBufUtil;
|
||||||
|
@ -24,7 +25,6 @@ import net.raphimc.vialegacy.api.LegacyProtocolVersion;
|
||||||
import net.raphimc.vialegacy.protocols.release.protocol1_6_1to1_5_2.ClientboundPackets1_5_2;
|
import net.raphimc.vialegacy.protocols.release.protocol1_6_1to1_5_2.ClientboundPackets1_5_2;
|
||||||
import net.raphimc.vialegacy.protocols.release.protocol1_6_1to1_5_2.ServerboundPackets1_5_2;
|
import net.raphimc.vialegacy.protocols.release.protocol1_6_1to1_5_2.ServerboundPackets1_5_2;
|
||||||
import net.raphimc.vialegacy.protocols.release.protocol1_7_2_5to1_6_4.types.Types1_6_4;
|
import net.raphimc.vialegacy.protocols.release.protocol1_7_2_5to1_6_4.types.Types1_6_4;
|
||||||
import net.raphimc.vialoader.util.VersionEnum;
|
|
||||||
import net.raphimc.viaproxy.proxy.session.LegacyProxyConnection;
|
import net.raphimc.viaproxy.proxy.session.LegacyProxyConnection;
|
||||||
import net.raphimc.viaproxy.proxy.session.ProxyConnection;
|
import net.raphimc.viaproxy.proxy.session.ProxyConnection;
|
||||||
import net.raphimc.viaproxy.proxy.util.ExceptionUtil;
|
import net.raphimc.viaproxy.proxy.util.ExceptionUtil;
|
||||||
|
@ -43,7 +43,7 @@ import java.util.*;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
public class EaglerServerHandler extends MessageToMessageCodec<WebSocketFrame, ByteBuf> {
|
public class EaglerServerHandler extends MessageToMessageCodec<WebSocketFrame, ByteBuf> {
|
||||||
private final VersionEnum version;
|
private final ProtocolVersion version;
|
||||||
private final String password;
|
private final String password;
|
||||||
private final NetClient proxyConnection;
|
private final NetClient proxyConnection;
|
||||||
private final Map<UUID, String> uuidStringMap = new HashMap<>();
|
private final Map<UUID, String> uuidStringMap = new HashMap<>();
|
||||||
|
@ -53,7 +53,7 @@ public class EaglerServerHandler extends MessageToMessageCodec<WebSocketFrame, B
|
||||||
private ByteBuf serverBoundPartialPacket = Unpooled.EMPTY_BUFFER;
|
private ByteBuf serverBoundPartialPacket = Unpooled.EMPTY_BUFFER;
|
||||||
private ByteBuf clientBoundPartialPacket = Unpooled.EMPTY_BUFFER;
|
private ByteBuf clientBoundPartialPacket = Unpooled.EMPTY_BUFFER;
|
||||||
public EaglerServerHandler(NetClient proxyConnection, String password) {
|
public EaglerServerHandler(NetClient proxyConnection, String password) {
|
||||||
this.version = proxyConnection instanceof ProxyConnection ? ((ProxyConnection) proxyConnection).getServerVersion() : VersionEnum.r1_5_2;
|
this.version = proxyConnection instanceof ProxyConnection ? ((ProxyConnection) proxyConnection).getServerVersion() : LegacyProtocolVersion.r1_5_2;
|
||||||
this.password = password;
|
this.password = password;
|
||||||
this.proxyConnection = proxyConnection;
|
this.proxyConnection = proxyConnection;
|
||||||
}
|
}
|
||||||
|
@ -71,7 +71,7 @@ public class EaglerServerHandler extends MessageToMessageCodec<WebSocketFrame, B
|
||||||
out.add(Unpooled.EMPTY_BUFFER);
|
out.add(Unpooled.EMPTY_BUFFER);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (version.isNewerThan(VersionEnum.r1_6_4)) {
|
if (version.newerThanOrEqualTo(ProtocolVersion.v1_7_2)) {
|
||||||
if (in.readableBytes() >= 2 && in.getUnsignedByte(0) == 0xFE && in.getUnsignedByte(1) == 0x01) {
|
if (in.readableBytes() >= 2 && in.getUnsignedByte(0) == 0xFE && in.getUnsignedByte(1) == 0x01) {
|
||||||
handshakeState = -1;
|
handshakeState = -1;
|
||||||
out.add(new TextWebSocketFrame("Accept: MOTD"));
|
out.add(new TextWebSocketFrame("Accept: MOTD"));
|
||||||
|
@ -282,7 +282,7 @@ public class EaglerServerHandler extends MessageToMessageCodec<WebSocketFrame, B
|
||||||
ByteBuf bb = ctx.alloc().buffer();
|
ByteBuf bb = ctx.alloc().buffer();
|
||||||
bb.writeByte((byte) 0xFF);
|
bb.writeByte((byte) 0xFF);
|
||||||
StringBuilder sb = new StringBuilder("\u00A71\0");
|
StringBuilder sb = new StringBuilder("\u00A71\0");
|
||||||
sb.append(LegacyProtocolVersion.getRealProtocolVersion(version.getVersion())).append("\0");
|
sb.append(version.getVersion()).append("\0");
|
||||||
sb.append(version.getName()).append("\0");
|
sb.append(version.getName()).append("\0");
|
||||||
sb.append(motdSb).append("\0");
|
sb.append(motdSb).append("\0");
|
||||||
sb.append(online).append("\0");
|
sb.append(online).append("\0");
|
||||||
|
@ -307,7 +307,7 @@ public class EaglerServerHandler extends MessageToMessageCodec<WebSocketFrame, B
|
||||||
JsonObject resp = new JsonObject();
|
JsonObject resp = new JsonObject();
|
||||||
JsonObject versionObj = new JsonObject();
|
JsonObject versionObj = new JsonObject();
|
||||||
versionObj.addProperty("name", version.getName());
|
versionObj.addProperty("name", version.getName());
|
||||||
versionObj.addProperty("protocol", LegacyProtocolVersion.getRealProtocolVersion(version.getVersion()));
|
versionObj.addProperty("protocol", version.getVersion());
|
||||||
resp.add("version", versionObj);
|
resp.add("version", versionObj);
|
||||||
JsonObject playersObj = new JsonObject();
|
JsonObject playersObj = new JsonObject();
|
||||||
playersObj.addProperty("max", max);
|
playersObj.addProperty("max", max);
|
||||||
|
@ -358,7 +358,7 @@ public class EaglerServerHandler extends MessageToMessageCodec<WebSocketFrame, B
|
||||||
JsonObject resp = new JsonObject();
|
JsonObject resp = new JsonObject();
|
||||||
JsonObject versionObj = new JsonObject();
|
JsonObject versionObj = new JsonObject();
|
||||||
versionObj.addProperty("name", version.getName());
|
versionObj.addProperty("name", version.getName());
|
||||||
versionObj.addProperty("protocol", LegacyProtocolVersion.getRealProtocolVersion(version.getVersion()));
|
versionObj.addProperty("protocol", version.getVersion());
|
||||||
resp.add("version", versionObj);
|
resp.add("version", versionObj);
|
||||||
JsonObject playersObj = new JsonObject();
|
JsonObject playersObj = new JsonObject();
|
||||||
playersObj.addProperty("max", serverInfo.max);
|
playersObj.addProperty("max", serverInfo.max);
|
||||||
|
@ -401,7 +401,7 @@ public class EaglerServerHandler extends MessageToMessageCodec<WebSocketFrame, B
|
||||||
handshakeState = -1;
|
handshakeState = -1;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (version.isNewerThan(VersionEnum.r1_6_4)) {
|
if (version.newerThanOrEqualTo(ProtocolVersion.v1_7_2)) {
|
||||||
if (handshakeState == 0) {
|
if (handshakeState == 0) {
|
||||||
out.add(Unpooled.EMPTY_BUFFER);
|
out.add(Unpooled.EMPTY_BUFFER);
|
||||||
} else if (handshakeState == 1) {
|
} else if (handshakeState == 1) {
|
||||||
|
@ -440,7 +440,7 @@ public class EaglerServerHandler extends MessageToMessageCodec<WebSocketFrame, B
|
||||||
bb.writeBytes(clientBoundPartialPacket);
|
bb.writeBytes(clientBoundPartialPacket);
|
||||||
clientBoundPartialPacket.release();
|
clientBoundPartialPacket.release();
|
||||||
clientBoundPartialPacket = Unpooled.EMPTY_BUFFER;
|
clientBoundPartialPacket = Unpooled.EMPTY_BUFFER;
|
||||||
bb.writeBytes(in.content());
|
bb.writeBytes(in.content()); // todo: do i need to reset this??????
|
||||||
int readerIndex = 0;
|
int readerIndex = 0;
|
||||||
try {
|
try {
|
||||||
while (bb.isReadable()) {
|
while (bb.isReadable()) {
|
||||||
|
|
|
@ -4,38 +4,32 @@ import io.netty.buffer.ByteBuf;
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import io.netty.channel.ChannelInboundHandlerAdapter;
|
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||||
import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame;
|
import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame;
|
||||||
import io.netty.util.AttributeKey;
|
import net.raphimc.netminecraft.packet.PacketTypes;
|
||||||
import net.raphimc.vialegacy.protocols.release.protocol1_7_2_5to1_6_4.types.Types1_6_4;
|
import net.raphimc.vialegacy.protocols.release.protocol1_7_2_5to1_6_4.types.Types1_6_4;
|
||||||
import net.raphimc.viaproxy.proxy.util.ExceptionUtil;
|
import net.raphimc.viaproxy.proxy.util.ExceptionUtil;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import java.util.concurrent.CopyOnWriteArraySet;
|
|
||||||
|
|
||||||
public class EaglerVoiceHandler extends ChannelInboundHandlerAdapter {
|
public class EaglerVoiceHandler extends ChannelInboundHandlerAdapter {
|
||||||
private static final ConcurrentHashMap<String, ChannelHandlerContext> voicePlayers;
|
|
||||||
private static final ConcurrentHashMap<String, ExpiringSet<String>> voiceRequests;
|
|
||||||
private static final CopyOnWriteArraySet<String[]> voicePairs;
|
|
||||||
private final String user;
|
|
||||||
private static final Collection<String> iceServers;
|
|
||||||
private static final AttributeKey<Boolean> VOICE_ENABLED;
|
|
||||||
|
|
||||||
private static void sendData(final ChannelHandlerContext ctx, final byte[] data) throws IOException {
|
public static final VoiceServerImpl voiceService = new VoiceServerImpl();
|
||||||
final ByteBuf bb = ctx.alloc().buffer();
|
|
||||||
bb.writeByte(250);
|
public String user;
|
||||||
try {
|
public UUID uuid;
|
||||||
Types1_6_4.STRING.write(bb, "EAG|Voice");
|
public final boolean old;
|
||||||
} catch (Exception e) {
|
private int pluginMessageId = -1;
|
||||||
throw new IOException(e);
|
|
||||||
}
|
|
||||||
bb.writeShort(data.length);
|
|
||||||
bb.writeBytes(data);
|
|
||||||
ctx.writeAndFlush(new BinaryWebSocketFrame(bb));
|
|
||||||
}
|
|
||||||
|
|
||||||
public EaglerVoiceHandler(final String username) {
|
public EaglerVoiceHandler(final String username) {
|
||||||
this.user = username;
|
this.user = username;
|
||||||
|
if (this.user == null) {
|
||||||
|
this.uuid = null;
|
||||||
|
old = false;
|
||||||
|
} else {
|
||||||
|
old = true;
|
||||||
|
this.uuid = nameToUUID(this.user);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -43,23 +37,29 @@ public class EaglerVoiceHandler extends ChannelInboundHandlerAdapter {
|
||||||
ExceptionUtil.handleNettyException(ctx, cause, null);
|
ExceptionUtil.handleNettyException(ctx, cause, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static UUID nameToUUID(String name) {
|
||||||
|
return UUID.nameUUIDFromBytes(("OfflinePlayer:" + name).getBytes(StandardCharsets.UTF_8));
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean sent = false;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void channelRead(final ChannelHandlerContext ctx, final Object obj) throws Exception {
|
public void channelRead(final ChannelHandlerContext ctx, final Object obj) throws Exception {
|
||||||
if (((EaglercraftHandler) ctx.pipeline().get("eaglercraft-handler")).state == EaglercraftHandler.State.LOGIN_COMPLETE && !ctx.channel().hasAttr(EaglerVoiceHandler.VOICE_ENABLED)) {
|
if (!FunnyConfig.eaglerVoice) {
|
||||||
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
super.channelRead(ctx, obj);
|
||||||
final DataOutputStream dos = new DataOutputStream(baos);
|
return;
|
||||||
dos.write(0);
|
|
||||||
dos.writeBoolean(true);
|
|
||||||
dos.write(EaglerVoiceHandler.iceServers.size());
|
|
||||||
for (final String str : EaglerVoiceHandler.iceServers) {
|
|
||||||
dos.writeUTF(str);
|
|
||||||
}
|
}
|
||||||
sendData(ctx, baos.toByteArray());
|
if (((EaglercraftHandler) ctx.pipeline().get("eaglercraft-handler")).state == EaglercraftHandler.State.LOGIN_COMPLETE && !sent) {
|
||||||
this.sendVoicePlayers(this.user);
|
if (this.user == null) {
|
||||||
ctx.channel().attr(EaglerVoiceHandler.VOICE_ENABLED).set(true);
|
this.user = ((EaglercraftHandler) ctx.pipeline().get("eaglercraft-handler")).username;
|
||||||
|
this.uuid = nameToUUID(this.user);
|
||||||
|
}
|
||||||
|
sent = true;
|
||||||
|
voiceService.handlePlayerLoggedIn(ctx);
|
||||||
}
|
}
|
||||||
if (obj instanceof BinaryWebSocketFrame) {
|
if (obj instanceof BinaryWebSocketFrame) {
|
||||||
final ByteBuf bb = ((BinaryWebSocketFrame) obj).content();
|
final ByteBuf bb = ((BinaryWebSocketFrame) obj).content();
|
||||||
|
if (old) {
|
||||||
if (bb.readableBytes() >= 3 && bb.readByte() == -6) {
|
if (bb.readableBytes() >= 3 && bb.readByte() == -6) {
|
||||||
String tag;
|
String tag;
|
||||||
byte[] msg;
|
byte[] msg;
|
||||||
|
@ -78,135 +78,35 @@ public class EaglerVoiceHandler extends ChannelInboundHandlerAdapter {
|
||||||
super.channelRead(ctx, obj);
|
super.channelRead(ctx, obj);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!FunnyConfig.eaglerVoice) {
|
|
||||||
bb.release();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final DataInputStream streamIn = new DataInputStream(new ByteArrayInputStream(msg));
|
final DataInputStream streamIn = new DataInputStream(new ByteArrayInputStream(msg));
|
||||||
final int sig = streamIn.read();
|
final int sig = streamIn.read();
|
||||||
switch (sig) {
|
switch (sig) {
|
||||||
case 0: {
|
case 0: {
|
||||||
if (!EaglerVoiceHandler.voicePlayers.containsKey(this.user)) {
|
voiceService.handleVoiceSignalPacketTypeRequest(nameToUUID(streamIn.readUTF()), ctx);
|
||||||
bb.release();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final String targetUser = streamIn.readUTF();
|
|
||||||
if (this.user.equals(targetUser)) {
|
|
||||||
bb.release();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (this.checkVoicePair(this.user, targetUser)) {
|
|
||||||
bb.release();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!EaglerVoiceHandler.voicePlayers.containsKey(targetUser)) {
|
|
||||||
bb.release();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!EaglerVoiceHandler.voiceRequests.containsKey(this.user)) {
|
|
||||||
EaglerVoiceHandler.voiceRequests.put(this.user, new ExpiringSet<>(2000L));
|
|
||||||
}
|
|
||||||
if (!EaglerVoiceHandler.voiceRequests.get(this.user).contains(targetUser)) {
|
|
||||||
EaglerVoiceHandler.voiceRequests.get(this.user).add(targetUser);
|
|
||||||
if (EaglerVoiceHandler.voiceRequests.containsKey(targetUser) && EaglerVoiceHandler.voiceRequests.get(targetUser).contains(this.user)) {
|
|
||||||
if (EaglerVoiceHandler.voiceRequests.containsKey(targetUser)) {
|
|
||||||
EaglerVoiceHandler.voiceRequests.get(targetUser).remove(this.user);
|
|
||||||
if (EaglerVoiceHandler.voiceRequests.get(targetUser).isEmpty()) {
|
|
||||||
EaglerVoiceHandler.voiceRequests.remove(targetUser);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (EaglerVoiceHandler.voiceRequests.containsKey(this.user)) {
|
|
||||||
EaglerVoiceHandler.voiceRequests.get(this.user).remove(targetUser);
|
|
||||||
if (EaglerVoiceHandler.voiceRequests.get(this.user).isEmpty()) {
|
|
||||||
EaglerVoiceHandler.voiceRequests.remove(this.user);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
EaglerVoiceHandler.voicePairs.add(new String[]{this.user, targetUser});
|
|
||||||
ByteArrayOutputStream baos2 = new ByteArrayOutputStream();
|
|
||||||
DataOutputStream dos2 = new DataOutputStream(baos2);
|
|
||||||
dos2.write(1);
|
|
||||||
dos2.writeUTF(this.user);
|
|
||||||
dos2.writeBoolean(false);
|
|
||||||
sendData(EaglerVoiceHandler.voicePlayers.get(targetUser), baos2.toByteArray());
|
|
||||||
baos2 = new ByteArrayOutputStream();
|
|
||||||
dos2 = new DataOutputStream(baos2);
|
|
||||||
dos2.write(1);
|
|
||||||
dos2.writeUTF(targetUser);
|
|
||||||
dos2.writeBoolean(true);
|
|
||||||
sendData(ctx, baos2.toByteArray());
|
|
||||||
}
|
|
||||||
bb.release();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
bb.release();
|
bb.release();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case 1: {
|
case 1: {
|
||||||
if (!EaglerVoiceHandler.voicePlayers.containsKey(this.user)) {
|
voiceService.handleVoiceSignalPacketTypeConnect(ctx);
|
||||||
final ByteArrayOutputStream baos3 = new ByteArrayOutputStream();
|
|
||||||
final DataOutputStream dos3 = new DataOutputStream(baos3);
|
|
||||||
dos3.write(1);
|
|
||||||
dos3.writeUTF(this.user);
|
|
||||||
final byte[] out = baos3.toByteArray();
|
|
||||||
for (final ChannelHandlerContext conn : EaglerVoiceHandler.voicePlayers.values()) {
|
|
||||||
sendData(conn, out);
|
|
||||||
}
|
|
||||||
EaglerVoiceHandler.voicePlayers.put(this.user, ctx);
|
|
||||||
for (final String username : EaglerVoiceHandler.voicePlayers.keySet()) {
|
|
||||||
this.sendVoicePlayers(username);
|
|
||||||
}
|
|
||||||
bb.release();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
bb.release();
|
bb.release();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case 2: {
|
case 2: {
|
||||||
if (!EaglerVoiceHandler.voicePlayers.containsKey(this.user)) {
|
|
||||||
bb.release();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
final String targetUser = streamIn.readUTF();
|
voiceService.handleVoiceSignalPacketTypeDisconnect(nameToUUID(streamIn.readUTF()), ctx);
|
||||||
if (!EaglerVoiceHandler.voicePlayers.containsKey(targetUser)) {
|
} catch (EOFException e) {
|
||||||
bb.release();
|
voiceService.handleVoiceSignalPacketTypeDisconnect(null, ctx);
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (EaglerVoiceHandler.voicePairs.removeIf(pair -> (pair[0].equals(this.user) && pair[1].equals(targetUser)) || (pair[0].equals(targetUser) && pair[1].equals(this.user)))) {
|
|
||||||
ByteArrayOutputStream baos2 = new ByteArrayOutputStream();
|
|
||||||
DataOutputStream dos2 = new DataOutputStream(baos2);
|
|
||||||
dos2.write(2);
|
|
||||||
dos2.writeUTF(this.user);
|
|
||||||
sendData(EaglerVoiceHandler.voicePlayers.get(targetUser), baos2.toByteArray());
|
|
||||||
baos2 = new ByteArrayOutputStream();
|
|
||||||
dos2 = new DataOutputStream(baos2);
|
|
||||||
dos2.write(2);
|
|
||||||
dos2.writeUTF(targetUser);
|
|
||||||
sendData(ctx, baos2.toByteArray());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} catch (EOFException var7) {
|
|
||||||
this.removeUser(this.user);
|
|
||||||
}
|
}
|
||||||
bb.release();
|
bb.release();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case 3:
|
case 3: {
|
||||||
|
voiceService.handleVoiceSignalPacketTypeICE(nameToUUID(streamIn.readUTF()), streamIn.readUTF(), ctx);
|
||||||
|
bb.release();
|
||||||
|
return;
|
||||||
|
}
|
||||||
case 4: {
|
case 4: {
|
||||||
if (EaglerVoiceHandler.voicePlayers.containsKey(this.user)) {
|
voiceService.handleVoiceSignalPacketTypeDesc(nameToUUID(streamIn.readUTF()), streamIn.readUTF(), ctx);
|
||||||
final String username = streamIn.readUTF();
|
|
||||||
if (this.checkVoicePair(this.user, username)) {
|
|
||||||
final String data = streamIn.readUTF();
|
|
||||||
final ByteArrayOutputStream baos4 = new ByteArrayOutputStream();
|
|
||||||
final DataOutputStream dos4 = new DataOutputStream(baos4);
|
|
||||||
dos4.write(sig);
|
|
||||||
dos4.writeUTF(this.user);
|
|
||||||
dos4.writeUTF(data);
|
|
||||||
sendData(EaglerVoiceHandler.voicePlayers.get(username), baos4.toByteArray());
|
|
||||||
}
|
|
||||||
bb.release();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
bb.release();
|
bb.release();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -216,14 +116,28 @@ public class EaglerVoiceHandler extends ChannelInboundHandlerAdapter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Throwable var8) {
|
} catch (Throwable var8) {
|
||||||
this.removeUser(this.user);
|
voiceService.handlePlayerLoggedOut(uuid);
|
||||||
bb.release();
|
bb.release();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
bb.release();
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
bb.resetReaderIndex();
|
bb.resetReaderIndex();
|
||||||
|
} else {
|
||||||
|
if (this.pluginMessageId <= 0) {
|
||||||
|
this.pluginMessageId = ((EaglercraftHandler) ctx.pipeline().get("eaglercraft-handler")).pluginMessageId;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
if (PacketTypes.readVarInt(bb) == this.pluginMessageId && PacketTypes.readString(bb, 32767).equals("EAG|Voice-1.8")) {
|
||||||
|
final byte[] data = new byte[bb.readableBytes()];
|
||||||
|
bb.readBytes(data);
|
||||||
|
VoiceSignalPackets.processPacket(data, ctx);
|
||||||
|
bb.release();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
}
|
||||||
|
bb.resetReaderIndex();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
super.channelRead(ctx, obj);
|
super.channelRead(ctx, obj);
|
||||||
}
|
}
|
||||||
|
@ -231,95 +145,6 @@ public class EaglerVoiceHandler extends ChannelInboundHandlerAdapter {
|
||||||
@Override
|
@Override
|
||||||
public void channelInactive(final ChannelHandlerContext ctx) throws Exception {
|
public void channelInactive(final ChannelHandlerContext ctx) throws Exception {
|
||||||
super.channelInactive(ctx);
|
super.channelInactive(ctx);
|
||||||
this.removeUser(this.user);
|
voiceService.handlePlayerLoggedOut(uuid);
|
||||||
}
|
|
||||||
|
|
||||||
public void sendVoicePlayers(final String name) {
|
|
||||||
if (EaglerVoiceHandler.voicePlayers.containsKey(name)) {
|
|
||||||
try {
|
|
||||||
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
|
||||||
final DataOutputStream dos = new DataOutputStream(baos);
|
|
||||||
dos.write(5);
|
|
||||||
final Set<String> mostlyGlobalPlayers = ConcurrentHashMap.newKeySet();
|
|
||||||
for (final String username : EaglerVoiceHandler.voicePlayers.keySet()) {
|
|
||||||
if (!username.equals(name) && EaglerVoiceHandler.voicePairs.stream().noneMatch(pair -> (pair[0].equals(name) && pair[1].equals(username)) || (pair[0].equals(username) && pair[1].equals(name)))) {
|
|
||||||
mostlyGlobalPlayers.add(username);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!mostlyGlobalPlayers.isEmpty()) {
|
|
||||||
dos.writeInt(mostlyGlobalPlayers.size());
|
|
||||||
for (final String username : mostlyGlobalPlayers) {
|
|
||||||
dos.writeUTF(username);
|
|
||||||
}
|
|
||||||
sendData(EaglerVoiceHandler.voicePlayers.get(name), baos.toByteArray());
|
|
||||||
}
|
|
||||||
} catch (IOException ignored) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void removeUser(final String name) {
|
|
||||||
EaglerVoiceHandler.voicePlayers.remove(name);
|
|
||||||
for (final String username : EaglerVoiceHandler.voicePlayers.keySet()) {
|
|
||||||
if (!name.equals(username)) {
|
|
||||||
this.sendVoicePlayers(username);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (final String[] voicePair : EaglerVoiceHandler.voicePairs) {
|
|
||||||
String target = null;
|
|
||||||
if (voicePair[0].equals(name)) {
|
|
||||||
target = voicePair[1];
|
|
||||||
} else if (voicePair[1].equals(name)) {
|
|
||||||
target = voicePair[0];
|
|
||||||
}
|
|
||||||
if (target != null && EaglerVoiceHandler.voicePlayers.containsKey(target)) {
|
|
||||||
try {
|
|
||||||
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
|
||||||
final DataOutputStream dos = new DataOutputStream(baos);
|
|
||||||
dos.write(2);
|
|
||||||
dos.writeUTF(name);
|
|
||||||
sendData(EaglerVoiceHandler.voicePlayers.get(target), baos.toByteArray());
|
|
||||||
} catch (IOException ignored) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
EaglerVoiceHandler.voicePairs.removeIf(pair -> pair[0].equals(name) || pair[1].equals(name));
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean checkVoicePair(final String user1, final String user2) {
|
|
||||||
return EaglerVoiceHandler.voicePairs.stream().anyMatch(pair -> (pair[0].equals(user1) && pair[1].equals(user2)) || (pair[0].equals(user2) && pair[1].equals(user1)));
|
|
||||||
}
|
|
||||||
|
|
||||||
static {
|
|
||||||
voicePlayers = new ConcurrentHashMap<>();
|
|
||||||
voiceRequests = new ConcurrentHashMap<>();
|
|
||||||
voicePairs = new CopyOnWriteArraySet<>();
|
|
||||||
(iceServers = new ArrayList<>()).add("stun:stun.l.google.com:19302");
|
|
||||||
EaglerVoiceHandler.iceServers.add("stun:stun1.l.google.com:19302");
|
|
||||||
EaglerVoiceHandler.iceServers.add("stun:stun2.l.google.com:19302");
|
|
||||||
EaglerVoiceHandler.iceServers.add("stun:stun3.l.google.com:19302");
|
|
||||||
EaglerVoiceHandler.iceServers.add("stun:stun4.l.google.com:19302");
|
|
||||||
EaglerVoiceHandler.iceServers.add("stun:openrelay.metered.ca:80");
|
|
||||||
final Map<String, Map<String, String>> turnServerList = new HashMap<>();
|
|
||||||
HashMap<String, String> n = new HashMap<>();
|
|
||||||
n.put("url", "turn:openrelay.metered.ca:80");
|
|
||||||
n.put("username", "openrelayproject");
|
|
||||||
n.put("password", "openrelayproject");
|
|
||||||
turnServerList.put("openrelay1", n);
|
|
||||||
n = new HashMap<>();
|
|
||||||
n.put("url", "turn:openrelay.metered.ca:443");
|
|
||||||
n.put("username", "openrelayproject");
|
|
||||||
n.put("password", "openrelayproject");
|
|
||||||
turnServerList.put("openrelay2", n);
|
|
||||||
n = new HashMap<>();
|
|
||||||
n.put("url", "turn:openrelay.metered.ca:443?transport=tcp");
|
|
||||||
n.put("username", "openrelayproject");
|
|
||||||
n.put("password", "openrelayproject");
|
|
||||||
turnServerList.put("openrelay3", n);
|
|
||||||
for (final Map.Entry<String, Map<String, String>> trn : turnServerList.entrySet()) {
|
|
||||||
final Map<String, String> o = trn.getValue();
|
|
||||||
EaglerVoiceHandler.iceServers.add(o.get("url") + ";" + o.get("username") + ";" + o.get("password"));
|
|
||||||
}
|
|
||||||
VOICE_ENABLED = AttributeKey.valueOf("ayun-voice-enabled");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package me.ayunami2000.ayunViaProxyEagUtils;
|
package me.ayunami2000.ayunViaProxyEagUtils;
|
||||||
|
|
||||||
import com.google.common.net.HostAndPort;
|
import com.google.common.net.HostAndPort;
|
||||||
|
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
|
||||||
import com.viaversion.viaversion.libs.gson.JsonArray;
|
import com.viaversion.viaversion.libs.gson.JsonArray;
|
||||||
import com.viaversion.viaversion.libs.gson.JsonObject;
|
import com.viaversion.viaversion.libs.gson.JsonObject;
|
||||||
import com.viaversion.viaversion.libs.gson.JsonParser;
|
import com.viaversion.viaversion.libs.gson.JsonParser;
|
||||||
|
@ -22,9 +23,9 @@ import net.raphimc.netminecraft.constants.ConnectionState;
|
||||||
import net.raphimc.netminecraft.constants.MCPackets;
|
import net.raphimc.netminecraft.constants.MCPackets;
|
||||||
import net.raphimc.netminecraft.constants.MCPipeline;
|
import net.raphimc.netminecraft.constants.MCPipeline;
|
||||||
import net.raphimc.netminecraft.packet.PacketTypes;
|
import net.raphimc.netminecraft.packet.PacketTypes;
|
||||||
|
import net.raphimc.vialegacy.api.LegacyProtocolVersion;
|
||||||
import net.raphimc.vialegacy.protocols.release.protocol1_6_1to1_5_2.ServerboundPackets1_5_2;
|
import net.raphimc.vialegacy.protocols.release.protocol1_6_1to1_5_2.ServerboundPackets1_5_2;
|
||||||
import net.raphimc.vialegacy.protocols.release.protocol1_7_2_5to1_6_4.types.Types1_6_4;
|
import net.raphimc.vialegacy.protocols.release.protocol1_7_2_5to1_6_4.types.Types1_6_4;
|
||||||
import net.raphimc.vialoader.util.VersionEnum;
|
|
||||||
import net.raphimc.viaproxy.ViaProxy;
|
import net.raphimc.viaproxy.ViaProxy;
|
||||||
import net.raphimc.viaproxy.proxy.client2proxy.Client2ProxyChannelInitializer;
|
import net.raphimc.viaproxy.proxy.client2proxy.Client2ProxyChannelInitializer;
|
||||||
import net.raphimc.viaproxy.proxy.util.ExceptionUtil;
|
import net.raphimc.viaproxy.proxy.util.ExceptionUtil;
|
||||||
|
@ -53,7 +54,7 @@ public class EaglercraftHandler extends MessageToMessageCodec<WebSocketFrame, By
|
||||||
public static final AttributeKey<HttpHeaders> httpHeadersKey = AttributeKey.newInstance("eag-http-headers");
|
public static final AttributeKey<HttpHeaders> httpHeadersKey = AttributeKey.newInstance("eag-http-headers");
|
||||||
private HostAndPort host;
|
private HostAndPort host;
|
||||||
public State state;
|
public State state;
|
||||||
public VersionEnum version;
|
public ProtocolVersion version;
|
||||||
public int pluginMessageId;
|
public int pluginMessageId;
|
||||||
public String username;
|
public String username;
|
||||||
|
|
||||||
|
@ -143,7 +144,7 @@ public class EaglercraftHandler extends MessageToMessageCodec<WebSocketFrame, By
|
||||||
if (data.readableBytes() >= 2 && data.getByte(0) == 2 && data.getByte(1) == 69) {
|
if (data.readableBytes() >= 2 && data.getByte(0) == 2 && data.getByte(1) == 69) {
|
||||||
data.setByte(1, 61);
|
data.setByte(1, 61);
|
||||||
this.state = State.LOGIN_COMPLETE;
|
this.state = State.LOGIN_COMPLETE;
|
||||||
this.version = VersionEnum.r1_5_2;
|
this.version = LegacyProtocolVersion.r1_5_2;
|
||||||
out.add(data.retain());
|
out.add(data.retain());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -197,8 +198,8 @@ public class EaglercraftHandler extends MessageToMessageCodec<WebSocketFrame, By
|
||||||
}
|
}
|
||||||
Logger.LOGGER.info("Eaglercraft client connected: " + clientBrand + " " + clientVersionString);
|
Logger.LOGGER.info("Eaglercraft client connected: " + clientBrand + " " + clientVersionString);
|
||||||
this.state = State.HANDSHAKE_COMPLETE;
|
this.state = State.HANDSHAKE_COMPLETE;
|
||||||
this.version = VersionEnum.fromProtocolId(minecraftVersion);
|
this.version = ProtocolVersion.getProtocol(minecraftVersion);
|
||||||
if (this.version.equals(VersionEnum.UNKNOWN)) {
|
if (this.version.equals(ProtocolVersion.unknown)) {
|
||||||
Logger.LOGGER.error("Unsupported protocol version: " + minecraftVersion);
|
Logger.LOGGER.error("Unsupported protocol version: " + minecraftVersion);
|
||||||
ctx.close();
|
ctx.close();
|
||||||
return;
|
return;
|
||||||
|
@ -278,7 +279,7 @@ public class EaglercraftHandler extends MessageToMessageCodec<WebSocketFrame, By
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case LOGIN_COMPLETE: {
|
case LOGIN_COMPLETE: {
|
||||||
if (this.version.equals(VersionEnum.r1_5_2)) {
|
if (this.version.equals(LegacyProtocolVersion.r1_5_2)) {
|
||||||
final int packetId = data.readUnsignedByte();
|
final int packetId = data.readUnsignedByte();
|
||||||
if (packetId == ServerboundPackets1_5_2.SHARED_KEY.getId()) {
|
if (packetId == ServerboundPackets1_5_2.SHARED_KEY.getId()) {
|
||||||
ctx.channel().writeAndFlush(new BinaryWebSocketFrame(data.readerIndex(0).retain()));
|
ctx.channel().writeAndFlush(new BinaryWebSocketFrame(data.readerIndex(0).retain()));
|
||||||
|
@ -289,7 +290,7 @@ public class EaglercraftHandler extends MessageToMessageCodec<WebSocketFrame, By
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (this.version.isNewerThanOrEqualTo(VersionEnum.r1_7_2tor1_7_5) && (!ctx.channel().hasAttr(Main.secureWs) || ctx.channel().attr(Main.secureWs) == null)) {
|
} else if (this.version.newerThanOrEqualTo(ProtocolVersion.v1_7_2) && (!ctx.channel().hasAttr(Main.secureWs) || ctx.channel().attr(Main.secureWs) == null)) {
|
||||||
final int packetId = PacketTypes.readVarInt(data);
|
final int packetId = PacketTypes.readVarInt(data);
|
||||||
if (packetId == this.pluginMessageId && PacketTypes.readString(data, 32767).startsWith("EAG|")) {
|
if (packetId == this.pluginMessageId && PacketTypes.readString(data, 32767).startsWith("EAG|")) {
|
||||||
break;
|
break;
|
||||||
|
@ -315,7 +316,7 @@ public class EaglercraftHandler extends MessageToMessageCodec<WebSocketFrame, By
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.state = State.STATUS;
|
this.state = State.STATUS;
|
||||||
this.version = VersionEnum.r1_8;
|
this.version = ProtocolVersion.v1_8;
|
||||||
if (ctx.pipeline().get(Client2ProxyChannelInitializer.LEGACY_PASSTHROUGH_INITIAL_HANDLER_NAME) != null) {
|
if (ctx.pipeline().get(Client2ProxyChannelInitializer.LEGACY_PASSTHROUGH_INITIAL_HANDLER_NAME) != null) {
|
||||||
ctx.pipeline().remove(Client2ProxyChannelInitializer.LEGACY_PASSTHROUGH_INITIAL_HANDLER_NAME);
|
ctx.pipeline().remove(Client2ProxyChannelInitializer.LEGACY_PASSTHROUGH_INITIAL_HANDLER_NAME);
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
|
||||||
import io.netty.handler.codec.http.websocketx.extensions.compression.WebSocketServerCompressionHandler;
|
import io.netty.handler.codec.http.websocketx.extensions.compression.WebSocketServerCompressionHandler;
|
||||||
import io.netty.handler.ssl.SslContext;
|
import io.netty.handler.ssl.SslContext;
|
||||||
import io.netty.handler.ssl.SslContextBuilder;
|
import io.netty.handler.ssl.SslContextBuilder;
|
||||||
import net.raphimc.viaproxy.plugins.PluginManager;
|
import net.raphimc.viaproxy.ViaProxy;
|
||||||
import net.raphimc.viaproxy.plugins.events.Client2ProxyHandlerCreationEvent;
|
import net.raphimc.viaproxy.plugins.events.Client2ProxyHandlerCreationEvent;
|
||||||
import net.raphimc.viaproxy.proxy.client2proxy.Client2ProxyChannelInitializer;
|
import net.raphimc.viaproxy.proxy.client2proxy.Client2ProxyChannelInitializer;
|
||||||
import net.raphimc.viaproxy.proxy.client2proxy.passthrough.LegacyPassthroughInitialHandler;
|
import net.raphimc.viaproxy.proxy.client2proxy.passthrough.LegacyPassthroughInitialHandler;
|
||||||
|
@ -40,8 +40,9 @@ public class EaglercraftInitialHandler extends ByteToMessageDecoder {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (in.readableBytes() >= 3 || in.getByte(0) != 71) {
|
if (in.readableBytes() >= 3 || in.getByte(0) != 71) {
|
||||||
if ((in.readableBytes() >= 3 && in.getCharSequence(0, 3, StandardCharsets.UTF_8).equals("GET")) || (in.readableBytes() >= 4 && in.getCharSequence(0, 4, StandardCharsets.UTF_8).equals("POST"))) {
|
boolean ssl = EaglercraftInitialHandler.sslContext != null && in.readableBytes() >= 3 && in.getByte(0) == 22;
|
||||||
if (EaglercraftInitialHandler.sslContext != null) {
|
if (ssl || (in.readableBytes() >= 3 && in.getCharSequence(0, 3, StandardCharsets.UTF_8).equals("GET")) || (in.readableBytes() >= 4 && in.getCharSequence(0, 4, StandardCharsets.UTF_8).equals("POST"))) {
|
||||||
|
if (ssl) {
|
||||||
ctx.pipeline().addBefore("eaglercraft-initial-handler", "ws-ssl-handler", EaglercraftInitialHandler.sslContext.newHandler(ctx.alloc()));
|
ctx.pipeline().addBefore("eaglercraft-initial-handler", "ws-ssl-handler", EaglercraftInitialHandler.sslContext.newHandler(ctx.alloc()));
|
||||||
}
|
}
|
||||||
ctx.pipeline().addBefore("eaglercraft-initial-handler", "ws-http-codec", new HttpServerCodec());
|
ctx.pipeline().addBefore("eaglercraft-initial-handler", "ws-http-codec", new HttpServerCodec());
|
||||||
|
@ -69,7 +70,7 @@ public class EaglercraftInitialHandler extends ByteToMessageDecoder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Supplier<ChannelHandler> handlerSupplier = () -> PluginManager.EVENT_MANAGER.call(new Client2ProxyHandlerCreationEvent(new PassthroughClient2ProxyHandler(), true)).getHandler();
|
Supplier<ChannelHandler> handlerSupplier = () -> ViaProxy.EVENT_MANAGER.call(new Client2ProxyHandlerCreationEvent(new PassthroughClient2ProxyHandler(), true)).getHandler();
|
||||||
PassthroughClient2ProxyChannelInitializer channelInitializer = new PassthroughClient2ProxyChannelInitializer(handlerSupplier);
|
PassthroughClient2ProxyChannelInitializer channelInitializer = new PassthroughClient2ProxyChannelInitializer(handlerSupplier);
|
||||||
try {
|
try {
|
||||||
initChannelMethod.invoke(channelInitializer, ctx.channel());
|
initChannelMethod.invoke(channelInitializer, ctx.channel());
|
||||||
|
|
|
@ -1,23 +1,25 @@
|
||||||
package me.ayunami2000.ayunViaProxyEagUtils;
|
package me.ayunami2000.ayunViaProxyEagUtils;
|
||||||
|
|
||||||
|
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import io.netty.channel.*;
|
import io.netty.channel.*;
|
||||||
|
import io.netty.handler.codec.compression.ZlibCodecFactory;
|
||||||
import io.netty.handler.codec.http.*;
|
import io.netty.handler.codec.http.*;
|
||||||
import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame;
|
import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame;
|
||||||
import io.netty.handler.codec.http.websocketx.WebSocketClientHandshakerFactory;
|
import io.netty.handler.codec.http.websocketx.WebSocketClientHandshakerFactory;
|
||||||
import io.netty.handler.codec.http.websocketx.WebSocketClientProtocolHandler;
|
import io.netty.handler.codec.http.websocketx.WebSocketClientProtocolHandler;
|
||||||
import io.netty.handler.codec.http.websocketx.WebSocketVersion;
|
import io.netty.handler.codec.http.websocketx.WebSocketVersion;
|
||||||
import io.netty.handler.codec.http.websocketx.extensions.compression.WebSocketClientCompressionHandler;
|
import io.netty.handler.codec.http.websocketx.extensions.WebSocketClientExtensionHandler;
|
||||||
|
import io.netty.handler.codec.http.websocketx.extensions.compression.DeflateFrameClientExtensionHandshaker;
|
||||||
|
import io.netty.handler.codec.http.websocketx.extensions.compression.PerMessageDeflateClientExtensionHandshaker;
|
||||||
import io.netty.handler.ssl.SslHandler;
|
import io.netty.handler.ssl.SslHandler;
|
||||||
import io.netty.util.AsciiString;
|
import io.netty.util.AsciiString;
|
||||||
import io.netty.util.AttributeKey;
|
import io.netty.util.AttributeKey;
|
||||||
import net.lenni0451.lambdaevents.EventHandler;
|
import net.lenni0451.lambdaevents.EventHandler;
|
||||||
import net.raphimc.netminecraft.constants.MCPipeline;
|
import net.raphimc.netminecraft.constants.MCPipeline;
|
||||||
import net.raphimc.netminecraft.netty.connection.NetClient;
|
import net.raphimc.netminecraft.netty.connection.NetClient;
|
||||||
import net.raphimc.netminecraft.util.ServerAddress;
|
|
||||||
import net.raphimc.vialegacy.protocols.release.protocol1_7_2_5to1_6_4.types.Types1_6_4;
|
import net.raphimc.vialegacy.protocols.release.protocol1_7_2_5to1_6_4.types.Types1_6_4;
|
||||||
import net.raphimc.vialoader.util.VersionEnum;
|
import net.raphimc.viaproxy.ViaProxy;
|
||||||
import net.raphimc.viaproxy.plugins.PluginManager;
|
|
||||||
import net.raphimc.viaproxy.plugins.ViaProxyPlugin;
|
import net.raphimc.viaproxy.plugins.ViaProxyPlugin;
|
||||||
import net.raphimc.viaproxy.plugins.events.Client2ProxyChannelInitializeEvent;
|
import net.raphimc.viaproxy.plugins.events.Client2ProxyChannelInitializeEvent;
|
||||||
import net.raphimc.viaproxy.plugins.events.Proxy2ServerChannelInitializeEvent;
|
import net.raphimc.viaproxy.plugins.events.Proxy2ServerChannelInitializeEvent;
|
||||||
|
@ -31,6 +33,8 @@ import javax.net.ssl.*;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.SocketAddress;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.security.KeyManagementException;
|
import java.security.KeyManagementException;
|
||||||
|
@ -70,8 +74,8 @@ public class Main extends ViaProxyPlugin {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onEnable() {
|
public void onEnable() {
|
||||||
PluginManager.EVENT_MANAGER.register(this);
|
ViaProxy.EVENT_MANAGER.register(this);
|
||||||
(new FunnyConfig(new File("ViaLoader", "vpeagutils.yml"))).reloadConfig();
|
(new FunnyConfig(new File("ViaLoader", "vpeagutils.yml"))).reload();
|
||||||
EaglerXSkinHandler.skinService = new SkinService();
|
EaglerXSkinHandler.skinService = new SkinService();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,7 +86,7 @@ public class Main extends ViaProxyPlugin {
|
||||||
|
|
||||||
NetClient proxyConnection;
|
NetClient proxyConnection;
|
||||||
Channel c2p;
|
Channel c2p;
|
||||||
ServerAddress addr;
|
SocketAddress addr;
|
||||||
if (event.isLegacyPassthrough()) {
|
if (event.isLegacyPassthrough()) {
|
||||||
proxyConnection = LegacyProxyConnection.fromChannel(ch);
|
proxyConnection = LegacyProxyConnection.fromChannel(ch);
|
||||||
c2p = ((LegacyProxyConnection) proxyConnection).getC2P();
|
c2p = ((LegacyProxyConnection) proxyConnection).getC2P();
|
||||||
|
@ -99,8 +103,8 @@ public class Main extends ViaProxyPlugin {
|
||||||
c2p.attr(secureWs).set(true);
|
c2p.attr(secureWs).set(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (c2p.hasAttr(secureWs) && c2p.attr(secureWs).get() != null) {
|
if (c2p.hasAttr(secureWs) && c2p.attr(secureWs).get() != null && addr instanceof InetSocketAddress) {
|
||||||
doWsServerStuff(ch, proxyConnection, c2p, addr);
|
doWsServerStuff(ch, proxyConnection, c2p, (InetSocketAddress) addr);
|
||||||
if (!event.isLegacyPassthrough()) {
|
if (!event.isLegacyPassthrough()) {
|
||||||
ch.pipeline().addFirst("handshake-waiter", new ChannelOutboundHandlerAdapter() {
|
ch.pipeline().addFirst("handshake-waiter", new ChannelOutboundHandlerAdapter() {
|
||||||
private boolean hasHandshake = false;
|
private boolean hasHandshake = false;
|
||||||
|
@ -142,9 +146,9 @@ public class Main extends ViaProxyPlugin {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void doWsServerStuff(Channel ch, NetClient proxyConnection, Channel c2p, ServerAddress addr) throws URISyntaxException {
|
private static void doWsServerStuff(Channel ch, NetClient proxyConnection, Channel c2p, InetSocketAddress addr) throws URISyntaxException {
|
||||||
ch.attr(MCPipeline.COMPRESSION_THRESHOLD_ATTRIBUTE_KEY).set(-2);
|
ch.attr(MCPipeline.COMPRESSION_THRESHOLD_ATTRIBUTE_KEY).set(-2);
|
||||||
if (proxyConnection instanceof ProxyConnection && ((ProxyConnection) proxyConnection).getServerVersion().isNewerThan(VersionEnum.r1_6_4)) {
|
if (proxyConnection instanceof ProxyConnection && ((ProxyConnection) proxyConnection).getServerVersion().newerThanOrEqualTo(ProtocolVersion.v1_7_2)) {
|
||||||
ch.pipeline().remove(MCPipeline.SIZER_HANDLER_NAME);
|
ch.pipeline().remove(MCPipeline.SIZER_HANDLER_NAME);
|
||||||
} else if (ch.pipeline().get(MCPipeline.ENCRYPTION_HANDLER_NAME) != null) {
|
} else if (ch.pipeline().get(MCPipeline.ENCRYPTION_HANDLER_NAME) != null) {
|
||||||
ch.pipeline().remove(MCPipeline.ENCRYPTION_HANDLER_NAME);
|
ch.pipeline().remove(MCPipeline.ENCRYPTION_HANDLER_NAME);
|
||||||
|
@ -164,7 +168,7 @@ public class Main extends ViaProxyPlugin {
|
||||||
StringBuilder url = new StringBuilder("ws");
|
StringBuilder url = new StringBuilder("ws");
|
||||||
boolean secure = c2p.attr(secureWs).get();
|
boolean secure = c2p.attr(secureWs).get();
|
||||||
if (secure) {
|
if (secure) {
|
||||||
final SSLEngine sslEngine = sc.createSSLEngine(addr.getAddress(), addr.getPort());
|
final SSLEngine sslEngine = sc.createSSLEngine(addr.getHostString(), addr.getPort());
|
||||||
sslEngine.setUseClientMode(true);
|
sslEngine.setUseClientMode(true);
|
||||||
sslEngine.setNeedClientAuth(false);
|
sslEngine.setNeedClientAuth(false);
|
||||||
ch.pipeline().addFirst("eag-server-ssl", new SslHandler(sslEngine) {
|
ch.pipeline().addFirst("eag-server-ssl", new SslHandler(sslEngine) {
|
||||||
|
@ -181,7 +185,7 @@ public class Main extends ViaProxyPlugin {
|
||||||
} else {
|
} else {
|
||||||
ch.pipeline().addFirst("eag-server-http-codec", new HttpClientCodec());
|
ch.pipeline().addFirst("eag-server-http-codec", new HttpClientCodec());
|
||||||
}
|
}
|
||||||
url.append("://").append(addr.getAddress());
|
url.append("://").append(addr.getHostString());
|
||||||
if ((secure && addr.getPort() != 443) || (!secure && addr.getPort() != 80)) {
|
if ((secure && addr.getPort() != 443) || (!secure && addr.getPort() != 80)) {
|
||||||
url.append(":").append(addr.getPort());
|
url.append(":").append(addr.getPort());
|
||||||
}
|
}
|
||||||
|
@ -193,7 +197,7 @@ public class Main extends ViaProxyPlugin {
|
||||||
URI uri = new URI(url.toString());
|
URI uri = new URI(url.toString());
|
||||||
HttpHeaders headers = c2p.hasAttr(EaglercraftHandler.httpHeadersKey) ? c2p.attr(EaglercraftHandler.httpHeadersKey).get() : new DefaultHttpHeaders().clear().set(HttpHeaderNames.ORIGIN, "https://via.shhnowisnottheti.me");
|
HttpHeaders headers = c2p.hasAttr(EaglercraftHandler.httpHeadersKey) ? c2p.attr(EaglercraftHandler.httpHeadersKey).get() : new DefaultHttpHeaders().clear().set(HttpHeaderNames.ORIGIN, "https://via.shhnowisnottheti.me");
|
||||||
ch.pipeline().addAfter("eag-server-http-codec", "eag-server-http-aggregator", new HttpObjectAggregator(2097152, true));
|
ch.pipeline().addAfter("eag-server-http-codec", "eag-server-http-aggregator", new HttpObjectAggregator(2097152, true));
|
||||||
ch.pipeline().addAfter("eag-server-http-aggregator", "eag-server-ws-compression", WebSocketClientCompressionHandler.INSTANCE);
|
ch.pipeline().addAfter("eag-server-http-aggregator", "eag-server-ws-compression", new WebSocketClientExtensionHandler(new PerMessageDeflateClientExtensionHandshaker(1, ZlibCodecFactory.isSupportingWindowSizeAndMemLevel(), 15, false, false), new DeflateFrameClientExtensionHandshaker(1, false), new DeflateFrameClientExtensionHandshaker(1, true)));
|
||||||
ch.pipeline().addAfter("eag-server-ws-compression", "eag-server-ws-handshaker", new WebSocketClientProtocolHandler(WebSocketClientHandshakerFactory.newHandshaker(uri, WebSocketVersion.V13, null, true, headers, 2097152)));
|
ch.pipeline().addAfter("eag-server-ws-compression", "eag-server-ws-handshaker", new WebSocketClientProtocolHandler(WebSocketClientHandshakerFactory.newHandshaker(uri, WebSocketVersion.V13, null, true, headers, 2097152)));
|
||||||
ch.pipeline().addAfter("eag-server-ws-handshaker", "eag-server-ws-ready", new WebSocketConnectedNotifier());
|
ch.pipeline().addAfter("eag-server-ws-handshaker", "eag-server-ws-ready", new WebSocketConnectedNotifier());
|
||||||
ch.pipeline().addAfter("eag-server-ws-ready", "eag-server-handler", new EaglerServerHandler(proxyConnection, c2p.attr(eagxPass).get()));
|
ch.pipeline().addAfter("eag-server-ws-ready", "eag-server-handler", new EaglerServerHandler(proxyConnection, c2p.attr(eagxPass).get()));
|
||||||
|
@ -239,6 +243,7 @@ public class Main extends ViaProxyPlugin {
|
||||||
} else {
|
} else {
|
||||||
ctx.pipeline().addBefore("eaglercraft-handler", "ayun-eag-x-login", new EaglerXLoginHandler());
|
ctx.pipeline().addBefore("eaglercraft-handler", "ayun-eag-x-login", new EaglerXLoginHandler());
|
||||||
ctx.pipeline().addBefore("eaglercraft-handler", "ayun-eag-skin-x", new EaglerXSkinHandler());
|
ctx.pipeline().addBefore("eaglercraft-handler", "ayun-eag-skin-x", new EaglerXSkinHandler());
|
||||||
|
ctx.pipeline().addBefore("eaglercraft-handler", "ayun-eag-voice", new EaglerVoiceHandler(null));
|
||||||
}
|
}
|
||||||
} catch (Exception ignored) {
|
} catch (Exception ignored) {
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,400 @@
|
||||||
|
package me.ayunami2000.ayunViaProxyEagUtils;
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
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 java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||||
|
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class VoiceServerImpl {
|
||||||
|
|
||||||
|
public static final Map<UUID, String> uuidToUsernameMap = new HashMap<>();
|
||||||
|
|
||||||
|
private static void fuckFuckFuck(ByteBuf out, String str) {
|
||||||
|
int strlen = str.length();
|
||||||
|
int utflen = 0;
|
||||||
|
int c, count = 0;
|
||||||
|
|
||||||
|
/* use charAt instead of copying String to char array */
|
||||||
|
for (int i = 0; i < strlen; i++) {
|
||||||
|
c = str.charAt(i);
|
||||||
|
if ((c >= 0x0001) && (c <= 0x007F)) {
|
||||||
|
utflen++;
|
||||||
|
} else if (c > 0x07FF) {
|
||||||
|
utflen += 3;
|
||||||
|
} else {
|
||||||
|
utflen += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (utflen > 65535)
|
||||||
|
throw new RuntimeException(
|
||||||
|
"encoded string too long: " + utflen + " bytes");
|
||||||
|
|
||||||
|
byte[] bytearr = new byte[utflen+2];
|
||||||
|
|
||||||
|
bytearr[count++] = (byte) ((utflen >>> 8) & 0xFF);
|
||||||
|
bytearr[count++] = (byte) ((utflen >>> 0) & 0xFF);
|
||||||
|
|
||||||
|
int i=0;
|
||||||
|
for (i=0; i<strlen; i++) {
|
||||||
|
c = str.charAt(i);
|
||||||
|
if (!((c >= 0x0001) && (c <= 0x007F))) break;
|
||||||
|
bytearr[count++] = (byte) c;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (;i < strlen; i++){
|
||||||
|
c = str.charAt(i);
|
||||||
|
if ((c >= 0x0001) && (c <= 0x007F)) {
|
||||||
|
bytearr[count++] = (byte) c;
|
||||||
|
|
||||||
|
} else if (c > 0x07FF) {
|
||||||
|
bytearr[count++] = (byte) (0xE0 | ((c >> 12) & 0x0F));
|
||||||
|
bytearr[count++] = (byte) (0x80 | ((c >> 6) & 0x3F));
|
||||||
|
bytearr[count++] = (byte) (0x80 | ((c >> 0) & 0x3F));
|
||||||
|
} else {
|
||||||
|
bytearr[count++] = (byte) (0xC0 | ((c >> 6) & 0x1F));
|
||||||
|
bytearr[count++] = (byte) (0x80 | ((c >> 0) & 0x3F));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out.writeBytes(bytearr, 0, utflen+2);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int pluginMessageId = -1;
|
||||||
|
private void sendData(final ChannelHandlerContext ctx, final byte[] data) {
|
||||||
|
final ByteBuf bb = ctx.alloc().buffer();
|
||||||
|
if (((EaglerVoiceHandler) ctx.pipeline().get("ayun-eag-voice")).old) {
|
||||||
|
bb.writeByte(250);
|
||||||
|
try {
|
||||||
|
Types1_6_4.STRING.write(bb, "EAG|Voice");
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bb.writeShort(data.length);
|
||||||
|
bb.writeBytes(data);
|
||||||
|
bb.readerIndex(23);
|
||||||
|
switch (bb.readByte()) {
|
||||||
|
case 0:
|
||||||
|
if (bb.readableBytes() == 1) break;
|
||||||
|
bb.skipBytes(1);
|
||||||
|
int vi = PacketTypes.readVarInt(bb);
|
||||||
|
String[] fard = new String[vi];
|
||||||
|
for (int i = 0; i < vi; i++) {
|
||||||
|
int xd = PacketTypes.readVarInt(bb);
|
||||||
|
byte[] arr = new byte[xd];
|
||||||
|
bb.readBytes(arr);
|
||||||
|
fard[i] = new String(arr, StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
bb.readerIndex(0);
|
||||||
|
bb.writerIndex(25);
|
||||||
|
bb.writeByte(vi);
|
||||||
|
for (String s : fard) {
|
||||||
|
fuckFuckFuck(bb, s);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
UUID uuid = PacketTypes.readUuid(bb);
|
||||||
|
boolean o = bb.readBoolean();
|
||||||
|
bb.readerIndex(0);
|
||||||
|
bb.writerIndex(24);
|
||||||
|
fuckFuckFuck(bb, uuidToUsernameMap.get(uuid));
|
||||||
|
bb.writeBoolean(o);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
if (bb.readableBytes() == 0) break;
|
||||||
|
uuid = PacketTypes.readUuid(bb);
|
||||||
|
bb.readerIndex(0);
|
||||||
|
bb.writerIndex(24);
|
||||||
|
fuckFuckFuck(bb, uuidToUsernameMap.get(uuid));
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
case 4:
|
||||||
|
uuid = PacketTypes.readUuid(bb);
|
||||||
|
vi = PacketTypes.readVarInt(bb);
|
||||||
|
byte[] arr = new byte[vi];
|
||||||
|
bb.readBytes(arr);
|
||||||
|
bb.readerIndex(0);
|
||||||
|
bb.writerIndex(24);
|
||||||
|
fuckFuckFuck(bb, uuidToUsernameMap.get(uuid));
|
||||||
|
fuckFuckFuck(bb, new String(arr, StandardCharsets.UTF_8));
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
vi = PacketTypes.readVarInt(bb);
|
||||||
|
bb.skipBytes(vi * 16);
|
||||||
|
fard = new String[vi];
|
||||||
|
for (int i = 0; i < vi; i++) {
|
||||||
|
int xd = PacketTypes.readVarInt(bb);
|
||||||
|
arr = new byte[xd];
|
||||||
|
bb.readBytes(arr);
|
||||||
|
fard[i] = new String(arr, StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
bb.readerIndex(0);
|
||||||
|
bb.writerIndex(24);
|
||||||
|
bb.writeInt(vi);
|
||||||
|
for (String s : fard) {
|
||||||
|
fuckFuckFuck(bb, s);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
bb.readerIndex(0);
|
||||||
|
bb.setShort(21, bb.writerIndex() - 23);
|
||||||
|
} else {
|
||||||
|
if (pluginMessageId <= 0) {
|
||||||
|
pluginMessageId = MCPackets.S2C_PLUGIN_MESSAGE.getId((((EaglercraftHandler) ctx.pipeline().get("eaglercraft-handler")).version).getVersion());
|
||||||
|
}
|
||||||
|
PacketTypes.writeVarInt(bb, pluginMessageId);
|
||||||
|
PacketTypes.writeString(bb, "EAG|Voice-1.8");
|
||||||
|
bb.writeBytes(data);
|
||||||
|
}
|
||||||
|
ctx.writeAndFlush(new BinaryWebSocketFrame(bb));
|
||||||
|
}
|
||||||
|
|
||||||
|
private final byte[] iceServersPacket;
|
||||||
|
|
||||||
|
private final Map<UUID, ChannelHandlerContext> voicePlayers = new HashMap<>();
|
||||||
|
private final Map<UUID, ExpiringSet<UUID>> voiceRequests = new HashMap<>();
|
||||||
|
private final Set<VoicePair> voicePairs = new HashSet<>();
|
||||||
|
|
||||||
|
private static class VoicePair {
|
||||||
|
|
||||||
|
private final UUID uuid1;
|
||||||
|
private final UUID uuid2;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return uuid1.hashCode() ^ uuid2.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj)
|
||||||
|
return true;
|
||||||
|
if (obj == null)
|
||||||
|
return false;
|
||||||
|
if (getClass() != obj.getClass())
|
||||||
|
return false;
|
||||||
|
VoicePair other = (VoicePair) obj;
|
||||||
|
return (uuid1.equals(other.uuid1) && uuid2.equals(other.uuid2))
|
||||||
|
|| (uuid1.equals(other.uuid2) && uuid2.equals(other.uuid1));
|
||||||
|
}
|
||||||
|
|
||||||
|
private VoicePair(UUID uuid1, UUID uuid2) {
|
||||||
|
this.uuid1 = uuid1;
|
||||||
|
this.uuid2 = uuid2;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean anyEquals(UUID uuid) {
|
||||||
|
return uuid1.equals(uuid) || uuid2.equals(uuid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VoiceServerImpl() {
|
||||||
|
if (FunnyConfig.eaglerVoice) {
|
||||||
|
Set<String> list = new HashSet<>();
|
||||||
|
list.add("stun:stun.l.google.com:19302");
|
||||||
|
list.add("stun:stun1.l.google.com:19302");
|
||||||
|
list.add("stun:stun2.l.google.com:19302");
|
||||||
|
list.add("stun:stun3.l.google.com:19302");
|
||||||
|
list.add("stun:stun4.l.google.com:19302");
|
||||||
|
list.add("turn:relay1.expressturn.com:3478;ef2KWF55ZPQWCLBMIG;MGn8T66L0GhgDodf");
|
||||||
|
this.iceServersPacket = VoiceSignalPackets.makeVoiceSignalPacketAllowed(true, list.toArray(new String[0]));
|
||||||
|
} else {
|
||||||
|
this.iceServersPacket = VoiceSignalPackets.makeVoiceSignalPacketAllowed(false, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void handlePlayerLoggedIn(ChannelHandlerContext player) {
|
||||||
|
EaglerVoiceHandler evh = (EaglerVoiceHandler) player.pipeline().get("ayun-eag-voice");
|
||||||
|
uuidToUsernameMap.put(evh.uuid, evh.user);
|
||||||
|
sendData(player, iceServersPacket);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void handlePlayerLoggedOut(UUID playerUUID) {
|
||||||
|
removeUser(playerUUID);
|
||||||
|
uuidToUsernameMap.remove(playerUUID);
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleVoiceSignalPacketTypeRequest(UUID player, ChannelHandlerContext sender) {
|
||||||
|
UUID senderUUID = ((EaglerVoiceHandler) sender.pipeline().get("ayun-eag-voice")).uuid;
|
||||||
|
synchronized (voicePlayers) {
|
||||||
|
if (senderUUID.equals(player))
|
||||||
|
return; // prevent duplicates
|
||||||
|
if (!voicePlayers.containsKey(senderUUID))
|
||||||
|
return;
|
||||||
|
ChannelHandlerContext targetPlayerCon = voicePlayers.get(player);
|
||||||
|
if (targetPlayerCon == null)
|
||||||
|
return;
|
||||||
|
VoicePair newPair = new VoicePair(player, senderUUID);
|
||||||
|
if (voicePairs.contains(newPair))
|
||||||
|
return; // already paired
|
||||||
|
ExpiringSet<UUID> senderRequestSet = voiceRequests.get(senderUUID);
|
||||||
|
if (senderRequestSet == null) {
|
||||||
|
voiceRequests.put(senderUUID, senderRequestSet = new ExpiringSet<>(2000));
|
||||||
|
}
|
||||||
|
if (!senderRequestSet.add(player)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if other has requested earlier
|
||||||
|
ExpiringSet<UUID> theSet;
|
||||||
|
if ((theSet = voiceRequests.get(player)) != null && theSet.contains(senderUUID)) {
|
||||||
|
theSet.remove(senderUUID);
|
||||||
|
if (theSet.isEmpty())
|
||||||
|
voiceRequests.remove(player);
|
||||||
|
senderRequestSet.remove(player);
|
||||||
|
if (senderRequestSet.isEmpty())
|
||||||
|
voiceRequests.remove(senderUUID);
|
||||||
|
// send each other add data
|
||||||
|
voicePairs.add(newPair);
|
||||||
|
sendData(targetPlayerCon,
|
||||||
|
VoiceSignalPackets.makeVoiceSignalPacketConnect(senderUUID, false));
|
||||||
|
sendData(sender, VoiceSignalPackets.makeVoiceSignalPacketConnect(player, true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleVoiceSignalPacketTypeConnect(ChannelHandlerContext sender) {
|
||||||
|
UUID senderUUID = ((EaglerVoiceHandler) sender.pipeline().get("ayun-eag-voice")).uuid;
|
||||||
|
synchronized (voicePlayers) {
|
||||||
|
if (voicePlayers.containsKey(senderUUID)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
boolean hasNoOtherPlayers = voicePlayers.isEmpty();
|
||||||
|
voicePlayers.put(senderUUID, sender);
|
||||||
|
if (hasNoOtherPlayers) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
byte[] packetToBroadcast = VoiceSignalPackets.makeVoiceSignalPacketGlobal(voicePlayers.values());
|
||||||
|
for (ChannelHandlerContext userCon : voicePlayers.values()) {
|
||||||
|
sendData(userCon, packetToBroadcast);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleVoiceSignalPacketTypeICE(UUID player, String str, ChannelHandlerContext sender) {
|
||||||
|
UUID senderUUID = ((EaglerVoiceHandler) sender.pipeline().get("ayun-eag-voice")).uuid;
|
||||||
|
ChannelHandlerContext pass;
|
||||||
|
VoicePair pair = new VoicePair(player, senderUUID);
|
||||||
|
synchronized (voicePlayers) {
|
||||||
|
pass = voicePairs.contains(pair) ? voicePlayers.get(player) : null;
|
||||||
|
}
|
||||||
|
if (pass != null) {
|
||||||
|
sendData(pass, VoiceSignalPackets.makeVoiceSignalPacketICE(senderUUID, str));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleVoiceSignalPacketTypeDesc(UUID player, String str, ChannelHandlerContext sender) {
|
||||||
|
UUID senderUUID = ((EaglerVoiceHandler) sender.pipeline().get("ayun-eag-voice")).uuid;
|
||||||
|
ChannelHandlerContext pass;
|
||||||
|
VoicePair pair = new VoicePair(player, senderUUID);
|
||||||
|
synchronized (voicePlayers) {
|
||||||
|
pass = voicePairs.contains(pair) ? voicePlayers.get(player) : null;
|
||||||
|
}
|
||||||
|
if (pass != null) {
|
||||||
|
sendData(pass,
|
||||||
|
VoiceSignalPackets.makeVoiceSignalPacketDesc(senderUUID, str));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleVoiceSignalPacketTypeDisconnect(UUID player, ChannelHandlerContext sender) {
|
||||||
|
UUID senderUUID = ((EaglerVoiceHandler) sender.pipeline().get("ayun-eag-voice")).uuid;
|
||||||
|
if (player != null) {
|
||||||
|
synchronized (voicePlayers) {
|
||||||
|
if (!voicePlayers.containsKey(player)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
byte[] userDisconnectPacket = null;
|
||||||
|
Iterator<VoicePair> pairsItr = voicePairs.iterator();
|
||||||
|
while (pairsItr.hasNext()) {
|
||||||
|
VoicePair voicePair = pairsItr.next();
|
||||||
|
UUID target = null;
|
||||||
|
if (voicePair.uuid1.equals(player)) {
|
||||||
|
target = voicePair.uuid2;
|
||||||
|
} else if (voicePair.uuid2.equals(player)) {
|
||||||
|
target = voicePair.uuid1;
|
||||||
|
}
|
||||||
|
if (target != null) {
|
||||||
|
pairsItr.remove();
|
||||||
|
ChannelHandlerContext conn = voicePlayers.get(target);
|
||||||
|
if (conn != null) {
|
||||||
|
if (userDisconnectPacket == null) {
|
||||||
|
userDisconnectPacket = VoiceSignalPackets.makeVoiceSignalPacketDisconnect(player);
|
||||||
|
}
|
||||||
|
sendData(conn, userDisconnectPacket);
|
||||||
|
}
|
||||||
|
sendData(sender,
|
||||||
|
VoiceSignalPackets.makeVoiceSignalPacketDisconnect(target));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
removeUser(senderUUID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeUser(UUID user) {
|
||||||
|
synchronized (voicePlayers) {
|
||||||
|
if (voicePlayers.remove(user) == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
voiceRequests.remove(user);
|
||||||
|
if (voicePlayers.size() > 0) {
|
||||||
|
byte[] voicePlayersPkt = VoiceSignalPackets.makeVoiceSignalPacketGlobal(voicePlayers.values());
|
||||||
|
for (Map.Entry<UUID, ChannelHandlerContext> userCon : voicePlayers.entrySet()) {
|
||||||
|
if (!user.equals(userCon.getKey())) {
|
||||||
|
sendData(userCon.getValue(), voicePlayersPkt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
byte[] userDisconnectPacket = null;
|
||||||
|
Iterator<VoicePair> pairsItr = voicePairs.iterator();
|
||||||
|
while (pairsItr.hasNext()) {
|
||||||
|
VoicePair voicePair = pairsItr.next();
|
||||||
|
UUID target = null;
|
||||||
|
if (voicePair.uuid1.equals(user)) {
|
||||||
|
target = voicePair.uuid2;
|
||||||
|
} else if (voicePair.uuid2.equals(user)) {
|
||||||
|
target = voicePair.uuid1;
|
||||||
|
}
|
||||||
|
if (target != null) {
|
||||||
|
pairsItr.remove();
|
||||||
|
if (voicePlayers.size() > 0) {
|
||||||
|
ChannelHandlerContext conn = voicePlayers.get(target);
|
||||||
|
if (conn != null) {
|
||||||
|
if (userDisconnectPacket == null) {
|
||||||
|
userDisconnectPacket = VoiceSignalPackets.makeVoiceSignalPacketDisconnect(user);
|
||||||
|
}
|
||||||
|
sendData(conn, userDisconnectPacket);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,186 @@
|
||||||
|
package me.ayunami2000.ayunViaProxyEagUtils;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.buffer.Unpooled;
|
||||||
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
|
import net.raphimc.netminecraft.packet.PacketTypes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2024 lax1dude. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||||
|
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class VoiceSignalPackets {
|
||||||
|
|
||||||
|
static final int VOICE_SIGNAL_ALLOWED = 0;
|
||||||
|
static final int VOICE_SIGNAL_REQUEST = 0;
|
||||||
|
static final int VOICE_SIGNAL_CONNECT = 1;
|
||||||
|
static final int VOICE_SIGNAL_DISCONNECT = 2;
|
||||||
|
static final int VOICE_SIGNAL_ICE = 3;
|
||||||
|
static final int VOICE_SIGNAL_DESC = 4;
|
||||||
|
static final int VOICE_SIGNAL_GLOBAL = 5;
|
||||||
|
|
||||||
|
public static void processPacket(byte[] data, ChannelHandlerContext sender) throws IOException {
|
||||||
|
int packetId = -1;
|
||||||
|
if(data.length == 0) {
|
||||||
|
throw new IOException("Zero-length packet recieved");
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
ByteBuf buffer = Unpooled.wrappedBuffer(data).writerIndex(data.length);
|
||||||
|
packetId = buffer.readUnsignedByte();
|
||||||
|
switch(packetId) {
|
||||||
|
case VOICE_SIGNAL_REQUEST: {
|
||||||
|
EaglerVoiceHandler.voiceService.handleVoiceSignalPacketTypeRequest(PacketTypes.readUuid(buffer), sender);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case VOICE_SIGNAL_CONNECT: {
|
||||||
|
EaglerVoiceHandler.voiceService.handleVoiceSignalPacketTypeConnect(sender);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case VOICE_SIGNAL_ICE: {
|
||||||
|
EaglerVoiceHandler.voiceService.handleVoiceSignalPacketTypeICE(PacketTypes.readUuid(buffer), PacketTypes.readString(buffer, 32767), sender);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case VOICE_SIGNAL_DESC: {
|
||||||
|
EaglerVoiceHandler.voiceService.handleVoiceSignalPacketTypeDesc(PacketTypes.readUuid(buffer), PacketTypes.readString(buffer, 32767), sender);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case VOICE_SIGNAL_DISCONNECT: {
|
||||||
|
EaglerVoiceHandler.voiceService.handleVoiceSignalPacketTypeDisconnect(buffer.readableBytes() > 0 ? PacketTypes.readUuid(buffer) : null, sender);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
throw new IOException("Unknown packet type " + packetId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(buffer.readableBytes() > 0) {
|
||||||
|
throw new IOException("Voice packet is too long!");
|
||||||
|
}
|
||||||
|
}catch(IOException ex) {
|
||||||
|
throw ex;
|
||||||
|
}catch(Throwable t) {
|
||||||
|
throw new IOException("Unhandled exception handling voice packet type " + packetId, t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static byte[] makeVoiceSignalPacketAllowed(boolean allowed, String[] iceServers) {
|
||||||
|
if (iceServers == null) {
|
||||||
|
byte[] ret = new byte[2];
|
||||||
|
ByteBuf wrappedBuffer = Unpooled.wrappedBuffer(ret).writerIndex(0);
|
||||||
|
wrappedBuffer.writeByte(VOICE_SIGNAL_ALLOWED);
|
||||||
|
wrappedBuffer.writeBoolean(allowed);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
byte[][] iceServersBytes = new byte[iceServers.length][];
|
||||||
|
int totalLen = 2 + getVarIntSize(iceServers.length);
|
||||||
|
for(int i = 0; i < iceServers.length; ++i) {
|
||||||
|
byte[] b = iceServersBytes[i] = iceServers[i].getBytes(StandardCharsets.UTF_8);
|
||||||
|
totalLen += getVarIntSize(b.length) + b.length;
|
||||||
|
}
|
||||||
|
byte[] ret = new byte[totalLen];
|
||||||
|
ByteBuf wrappedBuffer = Unpooled.wrappedBuffer(ret).writerIndex(0);
|
||||||
|
wrappedBuffer.writeByte(VOICE_SIGNAL_ALLOWED);
|
||||||
|
wrappedBuffer.writeBoolean(allowed);
|
||||||
|
PacketTypes.writeVarInt(wrappedBuffer, iceServersBytes.length);
|
||||||
|
for(int i = 0; i < iceServersBytes.length; ++i) {
|
||||||
|
byte[] b = iceServersBytes[i];
|
||||||
|
PacketTypes.writeVarInt(wrappedBuffer, b.length);
|
||||||
|
wrappedBuffer.writeBytes(b);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static byte[] makeVoiceSignalPacketGlobal(Collection<ChannelHandlerContext> users) {
|
||||||
|
int cnt = users.size();
|
||||||
|
byte[][] displayNames = new byte[cnt][];
|
||||||
|
int i = 0;
|
||||||
|
for(ChannelHandlerContext user : users) {
|
||||||
|
String name = ((EaglerVoiceHandler) user.pipeline().get("ayun-eag-voice")).user;
|
||||||
|
if(name.length() > 16) name = name.substring(0, 16);
|
||||||
|
displayNames[i++] = name.getBytes(StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
int totalLength = 1 + getVarIntSize(cnt) + (cnt << 4);
|
||||||
|
for(i = 0; i < cnt; ++i) {
|
||||||
|
totalLength += getVarIntSize(displayNames[i].length) + displayNames[i].length;
|
||||||
|
}
|
||||||
|
byte[] ret = new byte[totalLength];
|
||||||
|
ByteBuf wrappedBuffer = Unpooled.wrappedBuffer(ret).writerIndex(0);
|
||||||
|
wrappedBuffer.writeByte(VOICE_SIGNAL_GLOBAL);
|
||||||
|
PacketTypes.writeVarInt(wrappedBuffer, cnt);
|
||||||
|
for(ChannelHandlerContext user : users) {
|
||||||
|
PacketTypes.writeUuid(wrappedBuffer, ((EaglerVoiceHandler) user.pipeline().get("ayun-eag-voice")).uuid);
|
||||||
|
}
|
||||||
|
for(i = 0; i < cnt; ++i) {
|
||||||
|
PacketTypes.writeVarInt(wrappedBuffer, displayNames[i].length);
|
||||||
|
wrappedBuffer.writeBytes(displayNames[i]);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static byte[] makeVoiceSignalPacketConnect(UUID player, boolean offer) {
|
||||||
|
byte[] ret = new byte[18];
|
||||||
|
ByteBuf wrappedBuffer = Unpooled.wrappedBuffer(ret).writerIndex(0);
|
||||||
|
wrappedBuffer.writeByte(VOICE_SIGNAL_CONNECT);
|
||||||
|
PacketTypes.writeUuid(wrappedBuffer, player);
|
||||||
|
wrappedBuffer.writeBoolean(offer);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static byte[] makeVoiceSignalPacketDisconnect(UUID player) {
|
||||||
|
if(player == null) {
|
||||||
|
return new byte[] { (byte)VOICE_SIGNAL_DISCONNECT };
|
||||||
|
}
|
||||||
|
byte[] ret = new byte[17];
|
||||||
|
ByteBuf wrappedBuffer = Unpooled.wrappedBuffer(ret).writerIndex(0);
|
||||||
|
wrappedBuffer.writeByte(VOICE_SIGNAL_DISCONNECT);
|
||||||
|
PacketTypes.writeUuid(wrappedBuffer, player);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static byte[] makeVoiceSignalPacketICE(UUID player, String str) {
|
||||||
|
byte[] strBytes = str.getBytes(StandardCharsets.UTF_8);
|
||||||
|
byte[] ret = new byte[17 + getVarIntSize(strBytes.length) + strBytes.length];
|
||||||
|
ByteBuf wrappedBuffer = Unpooled.wrappedBuffer(ret).writerIndex(0);
|
||||||
|
wrappedBuffer.writeByte(VOICE_SIGNAL_ICE);
|
||||||
|
PacketTypes.writeUuid(wrappedBuffer, player);
|
||||||
|
PacketTypes.writeVarInt(wrappedBuffer, strBytes.length);
|
||||||
|
wrappedBuffer.writeBytes(strBytes);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static byte[] makeVoiceSignalPacketDesc(UUID player, String str) {
|
||||||
|
byte[] strBytes = str.getBytes(StandardCharsets.UTF_8);
|
||||||
|
byte[] ret = new byte[17 + getVarIntSize(strBytes.length) + strBytes.length];
|
||||||
|
ByteBuf wrappedBuffer = Unpooled.wrappedBuffer(ret).writerIndex(0);
|
||||||
|
wrappedBuffer.writeByte(VOICE_SIGNAL_DESC);
|
||||||
|
PacketTypes.writeUuid(wrappedBuffer, player);
|
||||||
|
PacketTypes.writeVarInt(wrappedBuffer, strBytes.length);
|
||||||
|
wrappedBuffer.writeBytes(strBytes);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getVarIntSize(int input) {
|
||||||
|
for (int i = 1; i < 5; ++i) {
|
||||||
|
if ((input & -1 << i * 7) == 0) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user