mirror of
https://github.com/sirjonasxx/G-Earth.git
synced 2024-11-30 04:00:50 +01:00
Shockwave progress
This commit is contained in:
parent
7964aaabbb
commit
ab263a6cfd
38
G-Earth/src/main/java/gearth/encoding/Base64Encoding.java
Normal file
38
G-Earth/src/main/java/gearth/encoding/Base64Encoding.java
Normal file
@ -0,0 +1,38 @@
|
||||
package gearth.encoding;
|
||||
|
||||
/**
|
||||
* Kepler Copyright (C) 2018 Quackster
|
||||
* <a href="https://github.com/Quackster/Kepler">Kepler</a>
|
||||
*/
|
||||
public class Base64Encoding {
|
||||
public byte NEGATIVE = 64;
|
||||
public byte POSITIVE = 65;
|
||||
|
||||
public static byte[] encode(int i, int numBytes) {
|
||||
byte[] bzRes = new byte[numBytes];
|
||||
for (int j = 1; j <= numBytes; j++)
|
||||
{
|
||||
int k = ((numBytes - j) * 6);
|
||||
bzRes[j - 1] = (byte)(0x40 + ((i >> k) & 0x3f));
|
||||
}
|
||||
|
||||
return bzRes;
|
||||
}
|
||||
|
||||
public static int decode(byte[] bzData) {
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
for (int k = bzData.length - 1; k >= 0; k--)
|
||||
{
|
||||
int x = bzData[k] - 0x40;
|
||||
if (j > 0)
|
||||
x *= (int)Math.pow(64.0, (double)j);
|
||||
|
||||
i += x;
|
||||
j++;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
63
G-Earth/src/main/java/gearth/encoding/VL64Encoding.java
Normal file
63
G-Earth/src/main/java/gearth/encoding/VL64Encoding.java
Normal file
@ -0,0 +1,63 @@
|
||||
package gearth.encoding;
|
||||
|
||||
/**
|
||||
* Kepler Copyright (C) 2018 Quackster
|
||||
* <a href="https://github.com/Quackster/Kepler">Kepler</a>
|
||||
*/
|
||||
public class VL64Encoding {
|
||||
public static byte NEGATIVE = 72;
|
||||
public static byte POSITIVE = 73;
|
||||
public static int MAX_INTEGER_BYTE_AMOUNT = 6;
|
||||
|
||||
public static byte[] encode(int i) {
|
||||
byte[] wf = new byte[VL64Encoding.MAX_INTEGER_BYTE_AMOUNT];
|
||||
|
||||
int pos = 0;
|
||||
int numBytes = 1;
|
||||
int startPos = pos;
|
||||
int negativeMask = i >= 0 ? 0 : 4;
|
||||
|
||||
i = Math.abs(i);
|
||||
|
||||
wf[pos++] = (byte)(64 + (i & 3));
|
||||
|
||||
for (i >>= 2; i != 0; i >>= VL64Encoding.MAX_INTEGER_BYTE_AMOUNT)
|
||||
{
|
||||
numBytes++;
|
||||
wf[pos++] = (byte)(64 + (i & 0x3f));
|
||||
}
|
||||
wf[startPos] = (byte)(wf[startPos] | numBytes << 3 | negativeMask);
|
||||
|
||||
byte[] bzData = new byte[numBytes];
|
||||
|
||||
System.arraycopy(wf, 0, bzData, 0, numBytes);
|
||||
return bzData;
|
||||
}
|
||||
|
||||
public static int decode(byte[] bzData) {
|
||||
int pos = 0;
|
||||
int v = 0;
|
||||
|
||||
boolean negative = (bzData[pos] & 4) == 4;
|
||||
int totalBytes = bzData[pos] >> 3 & 7;
|
||||
|
||||
v = bzData[pos] & 3;
|
||||
|
||||
pos++;
|
||||
|
||||
int shiftAmount = 2;
|
||||
|
||||
for (int b = 1; b < totalBytes; b++)
|
||||
{
|
||||
v |= (bzData[pos] & 0x3f) << shiftAmount;
|
||||
shiftAmount = 2 + 6 * b;
|
||||
pos++;
|
||||
}
|
||||
|
||||
if (negative) {
|
||||
v *= -1;
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
}
|
@ -20,7 +20,7 @@ import java.util.function.Consumer;
|
||||
public class HConnection {
|
||||
|
||||
public static volatile boolean DECRYPTPACKETS = true;
|
||||
public static volatile boolean DEBUG = false;
|
||||
public static volatile boolean DEBUG = true;
|
||||
|
||||
private volatile ExtensionHandler extensionHandler = null;
|
||||
|
||||
@ -60,14 +60,14 @@ public class HConnection {
|
||||
}
|
||||
|
||||
// autodetect mode
|
||||
public void start() {
|
||||
proxyProvider = proxyProviderFactory.provide();
|
||||
public void start(HClient client) {
|
||||
proxyProvider = proxyProviderFactory.provide(client);
|
||||
startMITM();
|
||||
}
|
||||
|
||||
// manual input mode
|
||||
public void start(String host, int port) {
|
||||
proxyProvider = proxyProviderFactory.provide(host, port);
|
||||
public void start(HClient client, String host, int port) {
|
||||
proxyProvider = proxyProviderFactory.provide(client, host, port);
|
||||
startMITM();
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,11 @@
|
||||
package gearth.protocol;
|
||||
|
||||
import gearth.protocol.format.shockwave.ShockMessage;
|
||||
|
||||
public interface TrafficListener {
|
||||
|
||||
void onCapture(HMessage message);
|
||||
|
||||
void onCapture(ShockMessage message);
|
||||
|
||||
}
|
||||
|
@ -3,5 +3,6 @@ package gearth.protocol.connection;
|
||||
public enum HClient {
|
||||
UNITY,
|
||||
FLASH,
|
||||
NITRO
|
||||
NITRO,
|
||||
SHOCKWAVE
|
||||
}
|
||||
|
@ -3,20 +3,20 @@ package gearth.protocol.connection.proxy;
|
||||
import gearth.misc.Cacher;
|
||||
import gearth.misc.OSValidator;
|
||||
import gearth.protocol.HConnection;
|
||||
import gearth.protocol.connection.HClient;
|
||||
import gearth.protocol.connection.HProxySetter;
|
||||
import gearth.protocol.connection.HStateSetter;
|
||||
import gearth.protocol.connection.proxy.flash.NormalFlashProxyProvider;
|
||||
import gearth.protocol.connection.proxy.flash.FlashProxy;
|
||||
import gearth.protocol.connection.proxy.flash.unix.LinuxRawIpFlashProxyProvider;
|
||||
import gearth.protocol.connection.proxy.flash.windows.WindowsRawIpFlashProxyProvider;
|
||||
import gearth.protocol.connection.proxy.shockwave.ShockwaveProxy;
|
||||
import gearth.ui.titlebar.TitleBarController;
|
||||
import gearth.ui.translations.LanguageBundle;
|
||||
import javafx.application.Platform;
|
||||
import javafx.scene.control.Alert;
|
||||
import javafx.scene.control.ButtonType;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.image.Image;
|
||||
import javafx.scene.layout.Region;
|
||||
import javafx.stage.Stage;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
@ -41,6 +41,8 @@ public class ProxyProviderFactory {
|
||||
autoDetectHosts.add("game-us.habbo.com:30000");
|
||||
autoDetectHosts.add("game-s2.habbo.com:30000");
|
||||
|
||||
autoDetectHosts.add("game-ous.habbo.com:40001");
|
||||
|
||||
List<Object> additionalCachedHotels = Cacher.getList(HOTELS_CACHE_KEY);
|
||||
if (additionalCachedHotels != null) {
|
||||
for (Object additionalHotel : additionalCachedHotels) {
|
||||
@ -83,10 +85,11 @@ public class ProxyProviderFactory {
|
||||
return true;
|
||||
}
|
||||
|
||||
public ProxyProvider provide() {
|
||||
return provide(autoDetectHosts);
|
||||
public ProxyProvider provide(HClient client) {
|
||||
return provide(client, autoDetectHosts);
|
||||
}
|
||||
public ProxyProvider provide(String domain, int port) {
|
||||
|
||||
public ProxyProvider provide(HClient client, String domain, int port) {
|
||||
List<Object> additionalCachedHotels = Cacher.getList(HOTELS_CACHE_KEY);
|
||||
if (additionalCachedHotels == null) {
|
||||
additionalCachedHotels = new ArrayList<>();
|
||||
@ -129,11 +132,14 @@ public class ProxyProviderFactory {
|
||||
else {
|
||||
List<String> potentialHost = new ArrayList<>();
|
||||
potentialHost.add(domain+":"+port);
|
||||
return provide(potentialHost);
|
||||
return provide(client, potentialHost);
|
||||
}
|
||||
}
|
||||
private ProxyProvider provide(List<String> potentialHosts) {
|
||||
return new NormalFlashProxyProvider(proxySetter, stateSetter, hConnection, potentialHosts, socksConfig.useSocks() && !socksConfig.onlyUseIfNeeded());
|
||||
|
||||
private ProxyProvider provide(HClient client, List<String> potentialHosts) {
|
||||
return client == HClient.FLASH
|
||||
? new FlashProxy(proxySetter, stateSetter, hConnection, potentialHosts, socksConfig.useSocks() && !socksConfig.onlyUseIfNeeded())
|
||||
: new ShockwaveProxy(proxySetter, stateSetter, hConnection, potentialHosts);
|
||||
}
|
||||
|
||||
public static void setSocksConfig(SocksConfiguration configuration) {
|
||||
|
@ -0,0 +1,53 @@
|
||||
package gearth.protocol.connection.proxy.flash;
|
||||
|
||||
import gearth.protocol.HConnection;
|
||||
import gearth.protocol.connection.*;
|
||||
import gearth.protocol.interceptor.ConnectionInterceptor;
|
||||
import gearth.protocol.interceptor.ConnectionInterceptorCallbacks;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.Socket;
|
||||
import java.util.List;
|
||||
|
||||
public class FlashProxy extends FlashProxyProvider implements ConnectionInterceptorCallbacks {
|
||||
|
||||
private final ConnectionInterceptor interceptor;
|
||||
|
||||
public FlashProxy(HProxySetter proxySetter, HStateSetter stateSetter, HConnection hConnection, List<String> potentialHosts, boolean useSocks) {
|
||||
super(proxySetter, stateSetter, hConnection);
|
||||
this.interceptor = new ConnectionInterceptor(HClient.FLASH, stateSetter, hConnection, this, potentialHosts, useSocks);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() throws IOException {
|
||||
if (hConnection.getState() != HState.NOT_CONNECTED) {
|
||||
return;
|
||||
}
|
||||
|
||||
interceptor.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void abort() {
|
||||
stateSetter.setState(HState.ABORTING);
|
||||
interceptor.stop(false);
|
||||
super.abort();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onConnect() {
|
||||
super.onConnect();
|
||||
interceptor.stop(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInterceptorConnected(Socket client, Socket server, HProxy proxy) throws IOException, InterruptedException {
|
||||
startProxyThread(client, server, proxy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInterceptorError() {
|
||||
showInvalidConnectionError();
|
||||
abort();
|
||||
}
|
||||
}
|
@ -0,0 +1,142 @@
|
||||
package gearth.protocol.connection.proxy.shockwave;
|
||||
|
||||
import gearth.protocol.HConnection;
|
||||
import gearth.protocol.connection.HClient;
|
||||
import gearth.protocol.connection.HProxy;
|
||||
import gearth.protocol.connection.HProxySetter;
|
||||
import gearth.protocol.connection.HState;
|
||||
import gearth.protocol.connection.HStateSetter;
|
||||
import gearth.protocol.connection.proxy.ProxyProvider;
|
||||
import gearth.protocol.interceptor.ConnectionInterceptor;
|
||||
import gearth.protocol.interceptor.ConnectionInterceptorCallbacks;
|
||||
import gearth.protocol.packethandler.PacketHandler;
|
||||
import gearth.protocol.packethandler.shockwave.ShockwavePacketIncomingHandler;
|
||||
import gearth.protocol.packethandler.shockwave.ShockwavePacketOutgoingHandler;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.Socket;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Semaphore;
|
||||
|
||||
public class ShockwaveProxy implements ProxyProvider, ConnectionInterceptorCallbacks {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(ShockwaveProxy.class);
|
||||
|
||||
private final HProxySetter hProxySetter;
|
||||
private final HStateSetter hStateSetter;
|
||||
private final HConnection hConnection;
|
||||
private final ConnectionInterceptor interceptor;
|
||||
private final Semaphore abortSemaphore;
|
||||
|
||||
public ShockwaveProxy(HProxySetter hProxySetter, HStateSetter hStateSetter, HConnection hConnection, List<String> potentialHosts) {
|
||||
this.hProxySetter = hProxySetter;
|
||||
this.hStateSetter = hStateSetter;
|
||||
this.hConnection = hConnection;
|
||||
this.interceptor = new ConnectionInterceptor(HClient.SHOCKWAVE, hStateSetter, hConnection, this, potentialHosts, false);
|
||||
this.abortSemaphore = new Semaphore(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() throws IOException {
|
||||
if (hConnection.getState() != HState.NOT_CONNECTED) {
|
||||
return;
|
||||
}
|
||||
|
||||
interceptor.start();
|
||||
logger.info("Intercepting shockwave connection.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void abort() {
|
||||
logger.warn("Aborting shockwave proxy.");
|
||||
hStateSetter.setState(HState.ABORTING);
|
||||
interceptor.stop(false);
|
||||
abortSemaphore.release();
|
||||
|
||||
// Let the stopProxyThread handle the rest of the aborting.
|
||||
if (hConnection.getState() != HState.CONNECTED) {
|
||||
hStateSetter.setState(HState.NOT_CONNECTED);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInterceptorConnected(Socket client, Socket server, HProxy proxy) throws IOException, InterruptedException {
|
||||
logger.info("Shockwave connection has been intercepted.");
|
||||
|
||||
startProxyThread(client, server, proxy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInterceptorError() {
|
||||
logger.error("Error occurred while intercepting shockwave connection. Aborting.");
|
||||
|
||||
abort();
|
||||
}
|
||||
|
||||
private void startProxyThread(Socket client, Socket server, HProxy proxy) throws IOException, InterruptedException {
|
||||
server.setSoTimeout(0);
|
||||
server.setTcpNoDelay(true);
|
||||
|
||||
client.setSoTimeout(0);
|
||||
client.setTcpNoDelay(true);
|
||||
|
||||
logger.info("Connected to shockwave server {}:{}", server.getRemoteSocketAddress(), server.getPort());
|
||||
|
||||
final Semaphore abort = new Semaphore(0);
|
||||
|
||||
final ShockwavePacketOutgoingHandler outgoingHandler = new ShockwavePacketOutgoingHandler(server.getOutputStream(), hConnection.getExtensionHandler(), hConnection.getTrafficObservables());
|
||||
final ShockwavePacketIncomingHandler incomingHandler = new ShockwavePacketIncomingHandler(client.getOutputStream(), hConnection.getExtensionHandler(), hConnection.getTrafficObservables());
|
||||
|
||||
// TODO: Non hardcoded version "20". Not exactly sure yet how to deal with this for now.
|
||||
// Lets revisit when origins is more mature.
|
||||
proxy.verifyProxy(incomingHandler, outgoingHandler, "20", "SHOCKWAVE");
|
||||
hProxySetter.setProxy(proxy);
|
||||
onConnect();
|
||||
|
||||
handleInputStream(client, outgoingHandler, abort);
|
||||
handleInputStream(server, incomingHandler, abort);
|
||||
|
||||
// abort can be acquired as soon as one of the sockets is closed
|
||||
abort.acquire();
|
||||
|
||||
try {
|
||||
if (!server.isClosed()) server.close();
|
||||
if (!client.isClosed()) client.close();
|
||||
if (HConnection.DEBUG) System.out.println("STOP");
|
||||
onConnectEnd();
|
||||
} catch (IOException e) {
|
||||
logger.error("Error occurred while closing sockets.", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleInputStream(Socket socket, PacketHandler packetHandler, Semaphore abort) {
|
||||
new Thread(() -> {
|
||||
try {
|
||||
int readLength;
|
||||
byte[] buffer = new byte[8192];
|
||||
while (!socket.isClosed() &&
|
||||
(hConnection.getState() == HState.WAITING_FOR_CLIENT || hConnection.getState() == HState.CONNECTED) &&
|
||||
(readLength = socket.getInputStream().read(buffer)) != -1) {
|
||||
packetHandler.act(Arrays.copyOf(buffer, readLength));
|
||||
}
|
||||
} catch (IOException ignore) {
|
||||
// ignore
|
||||
} finally {
|
||||
abort.release();
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
private void onConnect() {
|
||||
interceptor.stop(true);
|
||||
hStateSetter.setState(HState.CONNECTED);
|
||||
}
|
||||
|
||||
private void onConnectEnd() {
|
||||
hProxySetter.setProxy(null);
|
||||
hStateSetter.setState(HState.NOT_CONNECTED);
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package gearth.protocol.format.shockwave;
|
||||
|
||||
import gearth.protocol.HMessage;
|
||||
|
||||
public class ShockMessage {
|
||||
|
||||
private final ShockPacket packet;
|
||||
private final HMessage.Direction direction;
|
||||
private final int index;
|
||||
|
||||
private boolean isBlocked;
|
||||
|
||||
public ShockMessage(ShockPacket packet, HMessage.Direction direction, int index) {
|
||||
this.packet = packet;
|
||||
this.direction = direction;
|
||||
this.index = index;
|
||||
this.isBlocked = false;
|
||||
}
|
||||
|
||||
public ShockPacket getPacket() {
|
||||
return packet;
|
||||
}
|
||||
|
||||
public HMessage.Direction getDirection() {
|
||||
return direction;
|
||||
}
|
||||
|
||||
public int getIndex() {
|
||||
return index;
|
||||
}
|
||||
|
||||
public boolean isBlocked() {
|
||||
return isBlocked;
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package gearth.protocol.format.shockwave;
|
||||
|
||||
import gearth.protocol.HMessage;
|
||||
|
||||
public class ShockPacket {
|
||||
|
||||
public ShockPacket(HMessage.Direction direction, byte[] data) {
|
||||
|
||||
}
|
||||
|
||||
public void resetReadIndex() {
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
package gearth.protocol.format.shockwave;
|
||||
|
||||
public class ShockPacketIn {
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
package gearth.protocol.format.shockwave;
|
||||
|
||||
public class ShockPacketOut {
|
||||
}
|
@ -1,9 +1,11 @@
|
||||
package gearth.protocol.connection.proxy.flash;
|
||||
package gearth.protocol.interceptor;
|
||||
|
||||
import gearth.GEarth;
|
||||
import gearth.misc.Cacher;
|
||||
import gearth.protocol.HConnection;
|
||||
import gearth.protocol.connection.*;
|
||||
import gearth.protocol.connection.HClient;
|
||||
import gearth.protocol.connection.HProxy;
|
||||
import gearth.protocol.connection.HState;
|
||||
import gearth.protocol.connection.HStateSetter;
|
||||
import gearth.protocol.connection.proxy.ProxyProviderFactory;
|
||||
import gearth.protocol.connection.proxy.SocksConfiguration;
|
||||
import gearth.protocol.hostreplacer.hostsfile.HostReplacer;
|
||||
@ -14,20 +16,30 @@ import gearth.ui.titlebar.TitleBarController;
|
||||
import javafx.application.Platform;
|
||||
import javafx.scene.control.Alert;
|
||||
import javafx.scene.control.ButtonType;
|
||||
import javafx.scene.image.Image;
|
||||
import javafx.stage.Stage;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.*;
|
||||
import java.net.BindException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class NormalFlashProxyProvider extends FlashProxyProvider {
|
||||
|
||||
private List<String> potentialHosts;
|
||||
|
||||
public class ConnectionInterceptor {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(ConnectionInterceptor.class);
|
||||
private static final HostReplacer hostsReplacer = HostReplacerFactory.get();
|
||||
|
||||
private final HClient hClient;
|
||||
private final HStateSetter hStateSetter;
|
||||
private final HConnection hConnection;
|
||||
private final ConnectionInterceptorCallbacks callbacks;
|
||||
private final List<String> potentialHosts;
|
||||
|
||||
private volatile boolean hostRedirected = false;
|
||||
|
||||
private volatile List<HProxy> potentialProxies = new ArrayList<>();
|
||||
@ -35,28 +47,31 @@ public class NormalFlashProxyProvider extends FlashProxyProvider {
|
||||
|
||||
private boolean useSocks;
|
||||
|
||||
|
||||
public NormalFlashProxyProvider(HProxySetter proxySetter, HStateSetter stateSetter, HConnection hConnection, List<String> potentialHosts, boolean useSocks) {
|
||||
super(proxySetter, stateSetter, hConnection);
|
||||
public ConnectionInterceptor(HClient client, HStateSetter stateSetter, HConnection hConnection, ConnectionInterceptorCallbacks callbacks, List<String> potentialHosts, boolean useSocks) {
|
||||
this.hClient = client;
|
||||
this.hStateSetter = stateSetter;
|
||||
this.hConnection = hConnection;
|
||||
this.callbacks = callbacks;
|
||||
this.potentialHosts = potentialHosts;
|
||||
this.useSocks = useSocks;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void start() throws IOException {
|
||||
if (hConnection.getState() != HState.NOT_CONNECTED) {
|
||||
return;
|
||||
}
|
||||
|
||||
prepare();
|
||||
addToHosts();
|
||||
launchProxy();
|
||||
}
|
||||
|
||||
public void stop(boolean forceRemoveFromHosts) {
|
||||
if (forceRemoveFromHosts || hostRedirected) {
|
||||
removeFromHosts();
|
||||
}
|
||||
|
||||
clearAllProxies();
|
||||
}
|
||||
|
||||
private void prepare() {
|
||||
stateSetter.setState(HState.PREPARING);
|
||||
hStateSetter.setState(HState.PREPARING);
|
||||
|
||||
List<String> willremove = new ArrayList<>();
|
||||
int c = 0;
|
||||
@ -79,7 +94,7 @@ public class NormalFlashProxyProvider extends FlashProxyProvider {
|
||||
|
||||
int intercept_port = port;
|
||||
String intercept_host = "127.0." + (c / 254) + "." + (1 + c % 254);
|
||||
potentialProxies.add(new HProxy(HClient.FLASH, input_dom, actual_dom, port, intercept_port, intercept_host));
|
||||
potentialProxies.add(new HProxy(hClient, input_dom, actual_dom, port, intercept_port, intercept_host));
|
||||
c++;
|
||||
}
|
||||
}
|
||||
@ -92,11 +107,11 @@ public class NormalFlashProxyProvider extends FlashProxyProvider {
|
||||
Cacher.put(ProxyProviderFactory.HOTELS_CACHE_KEY, additionalCachedHotels);
|
||||
}
|
||||
|
||||
stateSetter.setState(HState.PREPARED);
|
||||
hStateSetter.setState(HState.PREPARED);
|
||||
}
|
||||
|
||||
private void launchProxy() throws IOException {
|
||||
stateSetter.setState(HState.WAITING_FOR_CLIENT);
|
||||
hStateSetter.setState(HState.WAITING_FOR_CLIENT);
|
||||
|
||||
for (int c = 0; c < potentialProxies.size(); c++) {
|
||||
HProxy potentialProxy = potentialProxies.get(c);
|
||||
@ -128,46 +143,37 @@ public class NormalFlashProxyProvider extends FlashProxyProvider {
|
||||
Socket client = proxy_server.accept();
|
||||
proxy = potentialProxy;
|
||||
closeAllProxies(proxy);
|
||||
if (HConnection.DEBUG) System.out.println("accepted a proxy");
|
||||
if (HConnection.DEBUG) logger.debug("Accepted a proxy");
|
||||
|
||||
new Thread(() -> {
|
||||
try {
|
||||
Socket server;
|
||||
if (!useSocks) {
|
||||
server = new Socket(proxy.getActual_domain(), proxy.getActual_port());
|
||||
server = new Socket(proxy.getActual_domain(), proxy.getActual_port());
|
||||
}
|
||||
else {
|
||||
SocksConfiguration configuration = ProxyProviderFactory.getSocksConfig();
|
||||
if (configuration == null) {
|
||||
showInvalidConnectionError();
|
||||
abort();
|
||||
callbacks.onInterceptorError();
|
||||
return;
|
||||
}
|
||||
server = configuration.createSocket();
|
||||
server.connect(new InetSocketAddress(proxy.getActual_domain(), proxy.getActual_port()), 5000);
|
||||
}
|
||||
|
||||
startProxyThread(client, server, proxy);
|
||||
} catch (SocketException | SocketTimeoutException e) {
|
||||
callbacks.onInterceptorConnected(client, server, proxy);
|
||||
} catch (Exception e) {
|
||||
// should only happen when SOCKS configured badly
|
||||
showInvalidConnectionError();
|
||||
abort();
|
||||
e.printStackTrace();
|
||||
}
|
||||
catch (InterruptedException | IOException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
callbacks.onInterceptorError();
|
||||
logger.error("Error occurred while intercepting connection", e);
|
||||
}
|
||||
}).start();
|
||||
|
||||
|
||||
} catch (IOException e1) {
|
||||
// TODO Auto-generated catch block
|
||||
// e1.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
logger.error("Proxy server thread error", e);
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
@ -177,24 +183,6 @@ public class NormalFlashProxyProvider extends FlashProxyProvider {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void abort() {
|
||||
stateSetter.setState(HState.ABORTING);
|
||||
if (hostRedirected) {
|
||||
removeFromHosts();
|
||||
}
|
||||
|
||||
clearAllProxies();
|
||||
super.abort();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onConnect() {
|
||||
super.onConnect();
|
||||
removeFromHosts();
|
||||
clearAllProxies();
|
||||
}
|
||||
|
||||
private void addToHosts() {
|
||||
List<String> linesTemp = new ArrayList<>();
|
||||
for (HProxy proxy : potentialProxies) {
|
||||
@ -208,6 +196,7 @@ public class NormalFlashProxyProvider extends FlashProxyProvider {
|
||||
hostsReplacer.addRedirect(lines);
|
||||
hostRedirected = true;
|
||||
}
|
||||
|
||||
private void removeFromHosts(){
|
||||
List<String> linesTemp = new ArrayList<>();
|
||||
for (HProxy proxy : potentialProxies) {
|
||||
@ -226,6 +215,7 @@ public class NormalFlashProxyProvider extends FlashProxyProvider {
|
||||
closeAllProxies(null);
|
||||
// potentialProxies = new ArrayList<>();
|
||||
}
|
||||
|
||||
private void closeAllProxies(HProxy except) {
|
||||
for (HProxy proxy : potentialProxies) {
|
||||
if (except != proxy) {
|
||||
@ -241,4 +231,5 @@ public class NormalFlashProxyProvider extends FlashProxyProvider {
|
||||
}
|
||||
// potentialProxies = Collections.singletonList(except);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package gearth.protocol.interceptor;
|
||||
|
||||
import gearth.protocol.connection.HProxy;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.Socket;
|
||||
|
||||
public interface ConnectionInterceptorCallbacks {
|
||||
|
||||
void onInterceptorConnected(Socket client, Socket server, HProxy proxy) throws IOException, InterruptedException;
|
||||
|
||||
void onInterceptorError();
|
||||
|
||||
}
|
@ -3,6 +3,7 @@ package gearth.protocol.packethandler;
|
||||
import gearth.misc.listenerpattern.Observable;
|
||||
import gearth.protocol.HMessage;
|
||||
import gearth.protocol.TrafficListener;
|
||||
import gearth.protocol.format.shockwave.ShockMessage;
|
||||
import gearth.services.extension_handler.ExtensionHandler;
|
||||
|
||||
import java.io.IOException;
|
||||
@ -32,6 +33,14 @@ public abstract class PacketHandler {
|
||||
message.getPacket().resetReadIndex();
|
||||
}
|
||||
|
||||
protected void notifyListeners(int i, ShockMessage message) {
|
||||
((Observable<TrafficListener>) trafficObservables[i]).fireEvent(trafficListener -> {
|
||||
message.getPacket().resetReadIndex();
|
||||
trafficListener.onCapture(message);
|
||||
});
|
||||
message.getPacket().resetReadIndex();
|
||||
}
|
||||
|
||||
protected void awaitListeners(HMessage message, PacketSender packetSender) {
|
||||
notifyListeners(0, message);
|
||||
notifyListeners(1, message);
|
||||
@ -43,4 +52,15 @@ public abstract class PacketHandler {
|
||||
});
|
||||
}
|
||||
|
||||
protected void awaitListeners(ShockMessage message, PacketSender packetSender) {
|
||||
notifyListeners(0, message);
|
||||
notifyListeners(1, message);
|
||||
extensionHandler.handle(message, message2 -> {
|
||||
notifyListeners(2, message2);
|
||||
if (!message2.isBlocked()) {
|
||||
packetSender.send(message2);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,65 @@
|
||||
package gearth.protocol.packethandler.shockwave;
|
||||
|
||||
import gearth.protocol.HMessage;
|
||||
import gearth.protocol.format.shockwave.ShockMessage;
|
||||
import gearth.protocol.format.shockwave.ShockPacket;
|
||||
import gearth.protocol.packethandler.PacketHandler;
|
||||
import gearth.protocol.packethandler.shockwave.buffers.ShockwaveBuffer;
|
||||
import gearth.services.extension_handler.ExtensionHandler;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
public abstract class ShockwavePacketHandler extends PacketHandler {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(ShockwavePacketHandler.class);
|
||||
|
||||
private final HMessage.Direction direction;
|
||||
private final ShockwaveBuffer payloadBuffer;
|
||||
private final OutputStream outputStream;
|
||||
private final Object flushLock;
|
||||
|
||||
ShockwavePacketHandler(HMessage.Direction direction, ShockwaveBuffer payloadBuffer, OutputStream outputStream, ExtensionHandler extensionHandler, Object[] trafficObservables) {
|
||||
super(extensionHandler, trafficObservables);
|
||||
this.direction = direction;
|
||||
this.payloadBuffer = payloadBuffer;
|
||||
this.outputStream = outputStream;
|
||||
this.flushLock = new Object();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean sendToStream(byte[] buffer) {
|
||||
synchronized (sendLock) {
|
||||
try {
|
||||
outputStream.write(buffer);
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
logger.error("Error while sending packet to stream.", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void act(byte[] buffer) throws IOException {
|
||||
payloadBuffer.push(buffer);
|
||||
|
||||
flush();
|
||||
}
|
||||
|
||||
public void flush() throws IOException {
|
||||
synchronized (flushLock) {
|
||||
final ShockPacket[] packets = payloadBuffer.receive();
|
||||
|
||||
for (final ShockPacket packet : packets){
|
||||
final ShockMessage message = new ShockMessage(packet, direction, currentIndex);
|
||||
|
||||
awaitListeners(message, x -> sendToStream(x.getPacket().toBytes()));
|
||||
|
||||
currentIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package gearth.protocol.packethandler.shockwave;
|
||||
|
||||
import gearth.protocol.HMessage;
|
||||
import gearth.protocol.packethandler.shockwave.buffers.ShockwaveInBuffer;
|
||||
import gearth.services.extension_handler.ExtensionHandler;
|
||||
|
||||
import java.io.OutputStream;
|
||||
|
||||
public class ShockwavePacketIncomingHandler extends ShockwavePacketHandler {
|
||||
public ShockwavePacketIncomingHandler(OutputStream outputStream, ExtensionHandler extensionHandler, Object[] trafficObservables) {
|
||||
super(HMessage.Direction.TOCLIENT, new ShockwaveInBuffer(), outputStream, extensionHandler, trafficObservables);
|
||||
}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package gearth.protocol.packethandler.shockwave;
|
||||
|
||||
import gearth.protocol.HMessage;
|
||||
import gearth.protocol.packethandler.shockwave.buffers.ShockwaveOutBuffer;
|
||||
import gearth.services.extension_handler.ExtensionHandler;
|
||||
|
||||
import java.io.OutputStream;
|
||||
|
||||
public class ShockwavePacketOutgoingHandler extends ShockwavePacketHandler {
|
||||
public ShockwavePacketOutgoingHandler(OutputStream outputStream, ExtensionHandler extensionHandler, Object[] trafficObservables) {
|
||||
super(HMessage.Direction.TOSERVER, new ShockwaveOutBuffer(), outputStream, extensionHandler, trafficObservables);
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package gearth.protocol.packethandler.shockwave.buffers;
|
||||
|
||||
import gearth.protocol.format.shockwave.ShockPacket;
|
||||
|
||||
public interface ShockwaveBuffer {
|
||||
|
||||
void push(byte[] data);
|
||||
|
||||
ShockPacket[] receive();
|
||||
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
package gearth.protocol.packethandler.shockwave.buffers;
|
||||
|
||||
import gearth.protocol.format.shockwave.ShockPacket;
|
||||
import gearth.protocol.packethandler.ByteArrayUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class ShockwaveInBuffer implements ShockwaveBuffer {
|
||||
|
||||
private byte[] buffer = new byte[0];
|
||||
|
||||
@Override
|
||||
public void push(byte[] data) {
|
||||
buffer = buffer.length == 0 ? data.clone() : ByteArrayUtils.combineByteArrays(buffer, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShockPacket[] receive() {
|
||||
if (buffer.length < 3) {
|
||||
return new ShockPacket[0];
|
||||
}
|
||||
|
||||
// Incoming packets are delimited by chr(1).
|
||||
// We need to split the buffer by chr(1) and then parse each packet.
|
||||
ArrayList<ShockPacket> packets = new ArrayList<>();
|
||||
|
||||
int curPos = 0;
|
||||
|
||||
for (int i = 0; i < buffer.length; i++) {
|
||||
if (buffer[i] == 1) {
|
||||
byte[] packetData = Arrays.copyOfRange(buffer, curPos, i);
|
||||
packets.add(new ShockPacket(packetData));
|
||||
curPos = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
buffer = Arrays.copyOfRange(buffer, curPos, buffer.length);
|
||||
|
||||
return packets.toArray(new ShockPacket[0]);
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package gearth.protocol.packethandler.shockwave.buffers;
|
||||
|
||||
import gearth.protocol.HPacket;
|
||||
import gearth.protocol.format.shockwave.ShockPacket;
|
||||
import gearth.protocol.packethandler.ByteArrayUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class ShockwaveOutBuffer implements ShockwaveBuffer {
|
||||
|
||||
private byte[] buffer = new byte[0];
|
||||
|
||||
@Override
|
||||
public void push(byte[] data) {
|
||||
buffer = buffer.length == 0 ? data.clone() : ByteArrayUtils.combineByteArrays(buffer, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShockPacket[] receive() {
|
||||
if (buffer.length < 5) {
|
||||
return new ShockPacket[0];
|
||||
}
|
||||
|
||||
ArrayList<HPacket> all = new ArrayList<>();
|
||||
|
||||
return all.toArray(new ShockPacket[all.size()]);
|
||||
}
|
||||
}
|
@ -7,6 +7,7 @@ import gearth.protocol.HConnection;
|
||||
import gearth.protocol.HMessage;
|
||||
import gearth.protocol.HPacket;
|
||||
import gearth.protocol.connection.HState;
|
||||
import gearth.protocol.format.shockwave.ShockMessage;
|
||||
import gearth.services.extension_handler.extensions.ExtensionListener;
|
||||
import gearth.services.extension_handler.extensions.GEarthExtension;
|
||||
import gearth.services.extension_handler.extensions.extensionproducers.ExtensionProducer;
|
||||
@ -160,6 +161,7 @@ public class ExtensionHandler {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void handle(HMessage hMessage, OnHMessageHandled callback) {
|
||||
synchronized (hMessageStuffLock) {
|
||||
Pair<HMessage.Direction, Integer> msgDirectionAndId = new Pair<>(hMessage.getDestination(), hMessage.getIndex());
|
||||
@ -177,11 +179,28 @@ public class ExtensionHandler {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
maybeFinishHmessage(hMessage);
|
||||
}
|
||||
|
||||
public void handle(ShockMessage hMessage, OnHMessageHandled callback) {
|
||||
synchronized (hMessageStuffLock) {
|
||||
Pair<HMessage.Direction, Integer> msgDirectionAndId = new Pair<>(hMessage.getDirection(), hMessage.getIndex());
|
||||
originalMessages.put(msgDirectionAndId, hMessage);
|
||||
finishManipulationCallback.put(hMessage, callback);
|
||||
editedMessages.put(hMessage, null);
|
||||
allAwaitingMessages.add(hMessage);
|
||||
|
||||
synchronized (gEarthExtensions) {
|
||||
awaitManipulation.put(hMessage, new HashSet<>(gEarthExtensions));
|
||||
|
||||
for (GEarthExtension extension : gEarthExtensions) {
|
||||
extension.packetIntercept(new HMessage(hMessage));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
maybeFinishHmessage(hMessage);
|
||||
}
|
||||
|
||||
private ExtensionProducerObserver createExtensionProducerObserver() {
|
||||
return new ExtensionProducerObserver() {
|
||||
|
@ -114,11 +114,11 @@ public class PacketInfoManager {
|
||||
|
||||
if (clientType == HClient.UNITY) {
|
||||
result.addAll(new GEarthUnityPacketInfoProvider(hotelversion).provide());
|
||||
} else if (clientType == HClient.FLASH || clientType == HClient.NITRO) {
|
||||
} else if (clientType == HClient.FLASH || clientType == HClient.NITRO || clientType == HClient.SHOCKWAVE) {
|
||||
try {
|
||||
List<RemotePacketInfoProvider> providers = new ArrayList<>();
|
||||
providers.add(new HarblePacketInfoProvider(hotelversion));
|
||||
providers.add(new SulekPacketInfoProvider(hotelversion));
|
||||
providers.add(new SulekPacketInfoProvider(clientType, hotelversion));
|
||||
|
||||
Semaphore blockUntilComplete = new Semaphore(providers.size());
|
||||
blockUntilComplete.acquire(providers.size());
|
||||
|
@ -1,5 +1,6 @@
|
||||
package gearth.services.packet_info.providers.implementations;
|
||||
|
||||
import gearth.protocol.connection.HClient;
|
||||
import gearth.services.packet_info.PacketInfo;
|
||||
import gearth.services.packet_info.providers.RemotePacketInfoProvider;
|
||||
import gearth.protocol.HMessage;
|
||||
@ -12,15 +13,23 @@ import java.util.List;
|
||||
public class SulekPacketInfoProvider extends RemotePacketInfoProvider {
|
||||
|
||||
public static final String CACHE_PREFIX = "SULEK_API-";
|
||||
public static final String SULEK_API_URL = "https://api.sulek.dev/releases/$hotelversion$/messages";
|
||||
public static final String SULEK_API_URL_GLOBAL = "https://api.sulek.dev/releases/$hotelversion$/messages";
|
||||
public static final String SULEK_API_URL_VARIANT = "https://api.sulek.dev/releases/$variant$/$hotelversion$/messages";
|
||||
|
||||
public SulekPacketInfoProvider(String hotelVersion) {
|
||||
private final HClient client;
|
||||
|
||||
public SulekPacketInfoProvider(HClient client, String hotelVersion) {
|
||||
super(hotelVersion);
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getRemoteUrl() {
|
||||
return SULEK_API_URL.replace("$hotelversion$", hotelVersion);
|
||||
if (client == HClient.SHOCKWAVE) {
|
||||
return SULEK_API_URL_VARIANT.replace("$variant$", "shockwave-windows").replace("$hotelversion$", hotelVersion);
|
||||
}
|
||||
|
||||
return SULEK_API_URL_GLOBAL.replace("$hotelversion$", hotelVersion);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -43,6 +43,7 @@ public class ConnectionController extends SubForm {
|
||||
public static final String CLIENT_CACHE_KEY = "last_client_mode";
|
||||
public ToggleGroup tgl_clientMode;
|
||||
public RadioButton rd_unity;
|
||||
public RadioButton rd_origins;
|
||||
public RadioButton rd_flash;
|
||||
public RadioButton rd_nitro;
|
||||
public GridPane grd_clientSelection;
|
||||
@ -64,6 +65,9 @@ public class ConnectionController extends SubForm {
|
||||
case FLASH:
|
||||
rd_flash.setSelected(true);
|
||||
break;
|
||||
case SHOCKWAVE:
|
||||
rd_origins.setSelected(true);
|
||||
break;
|
||||
case UNITY:
|
||||
rd_unity.setSelected(true);
|
||||
break;
|
||||
@ -240,13 +244,17 @@ public class ConnectionController extends SubForm {
|
||||
inpPort.getSelectionModel().select(port);
|
||||
cbx_autodetect.setSelected(false);
|
||||
});
|
||||
getHConnection().start(host, Integer.parseInt(port));
|
||||
getHConnection().start(HClient.FLASH, host, Integer.parseInt(port));
|
||||
}
|
||||
else {
|
||||
Platform.runLater(() -> cbx_autodetect.setSelected(true));
|
||||
getHConnection().start();
|
||||
getHConnection().start(HClient.FLASH);
|
||||
}
|
||||
}
|
||||
else if (connectMode.equals("origins")) {
|
||||
Platform.runLater(() -> rd_origins.setSelected(true));
|
||||
getHConnection().start(HClient.SHOCKWAVE);
|
||||
}
|
||||
else if (connectMode.equals("unity")) {
|
||||
Platform.runLater(() -> rd_unity.setSelected(true));
|
||||
getHConnection().startUnity();
|
||||
@ -266,10 +274,12 @@ public class ConnectionController extends SubForm {
|
||||
new Thread(() -> {
|
||||
if (isClientMode(HClient.FLASH)) {
|
||||
if (cbx_autodetect.isSelected()) {
|
||||
getHConnection().start();
|
||||
getHConnection().start(HClient.FLASH);
|
||||
} else {
|
||||
getHConnection().start(inpHost.getEditor().getText(), Integer.parseInt(inpPort.getEditor().getText()));
|
||||
getHConnection().start(HClient.FLASH, inpHost.getEditor().getText(), Integer.parseInt(inpPort.getEditor().getText()));
|
||||
}
|
||||
} else if (isClientMode(HClient.SHOCKWAVE)) {
|
||||
getHConnection().start(HClient.SHOCKWAVE);
|
||||
} else if (isClientMode(HClient.UNITY)) {
|
||||
getHConnection().startUnity();
|
||||
} else if (isClientMode(HClient.NITRO)) {
|
||||
@ -291,6 +301,8 @@ public class ConnectionController extends SubForm {
|
||||
protected void onExit() {
|
||||
if (rd_flash.isSelected()) {
|
||||
Cacher.put(CLIENT_CACHE_KEY, HClient.FLASH);
|
||||
} else if (rd_origins.isSelected()) {
|
||||
Cacher.put(CLIENT_CACHE_KEY, HClient.SHOCKWAVE);
|
||||
} else if (rd_unity.isSelected()) {
|
||||
Cacher.put(CLIENT_CACHE_KEY, HClient.UNITY);
|
||||
} else if (rd_nitro.isSelected()) {
|
||||
@ -311,6 +323,8 @@ public class ConnectionController extends SubForm {
|
||||
switch (client) {
|
||||
case FLASH:
|
||||
return rd_flash.isSelected();
|
||||
case SHOCKWAVE:
|
||||
return rd_origins.isSelected();
|
||||
case UNITY:
|
||||
return rd_unity.isSelected();
|
||||
case NITRO:
|
||||
@ -333,6 +347,7 @@ public class ConnectionController extends SubForm {
|
||||
lblHotelVersion.textProperty().bind(new TranslatableString("%s", "tab.connection.version"));
|
||||
lblClient.textProperty().bind(new TranslatableString("%s", "tab.connection.client"));
|
||||
rd_unity.textProperty().bind(new TranslatableString("%s", "tab.connection.client.unity"));
|
||||
rd_origins.textProperty().bind(new TranslatableString("%s", "tab.connection.client.origins"));
|
||||
rd_flash.textProperty().bind(new TranslatableString("%s", "tab.connection.client.flash"));
|
||||
rd_nitro.textProperty().bind(new TranslatableString("%s", "tab.connection.client.nitro"));
|
||||
lblStateHead.textProperty().bind(new TranslatableString("%s", "tab.connection.state"));
|
||||
|
@ -5,7 +5,7 @@
|
||||
<?import javafx.scene.layout.*?>
|
||||
<?import javafx.scene.text.*?>
|
||||
|
||||
<GridPane alignment="CENTER" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="258.0" prefWidth="650.0" xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml/1" fx:controller="gearth.ui.subforms.connection.ConnectionController">
|
||||
<GridPane alignment="CENTER" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="258.0" prefWidth="650.0" xmlns="http://javafx.com/javafx/17.0.2-ea" xmlns:fx="http://javafx.com/fxml/1" fx:controller="gearth.ui.subforms.connection.ConnectionController">
|
||||
<columnConstraints>
|
||||
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
|
||||
</columnConstraints>
|
||||
@ -128,10 +128,10 @@
|
||||
<GridPane fx:id="grd_clientSelection" prefHeight="26.0" prefWidth="286.0" style="-fx-border-color: #888888; -fx-border-width: 0 0 1 0;">
|
||||
<columnConstraints>
|
||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="149.0" minWidth="10.0" prefWidth="76.0" />
|
||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="149.0" minWidth="10.0" prefWidth="25.0" />
|
||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="177.0" minWidth="66.0" prefWidth="90.0" />
|
||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="133.0" minWidth="8.0" prefWidth="70.0" />
|
||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="242.0" minWidth="10.0" prefWidth="70.0" />
|
||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="177.0" minWidth="44.0" prefWidth="57.0" />
|
||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="133.0" minWidth="8.0" prefWidth="65.0" />
|
||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="242.0" minWidth="10.0" prefWidth="54.0" />
|
||||
<ColumnConstraints />
|
||||
</columnConstraints>
|
||||
<rowConstraints>
|
||||
<RowConstraints minHeight="20.0" prefHeight="34.0" vgrow="SOMETIMES" />
|
||||
@ -145,7 +145,7 @@
|
||||
<Insets right="-20.0" />
|
||||
</GridPane.margin>
|
||||
</Label>
|
||||
<RadioButton fx:id="rd_unity" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" text="Unity" GridPane.columnIndex="3" GridPane.hgrow="ALWAYS" GridPane.vgrow="ALWAYS">
|
||||
<RadioButton fx:id="rd_unity" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" prefHeight="22.0" prefWidth="54.0" text="Unity" GridPane.columnIndex="3" GridPane.hgrow="ALWAYS" GridPane.vgrow="ALWAYS">
|
||||
<toggleGroup>
|
||||
<ToggleGroup fx:id="tgl_clientMode" />
|
||||
</toggleGroup>
|
||||
@ -153,12 +153,17 @@
|
||||
<Insets />
|
||||
</GridPane.margin>
|
||||
</RadioButton>
|
||||
<RadioButton fx:id="rd_flash" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" prefHeight="35.0" prefWidth="111.0" selected="true" text="Flash / Air" toggleGroup="$tgl_clientMode" GridPane.columnIndex="2">
|
||||
<RadioButton fx:id="rd_flash" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" prefHeight="35.0" prefWidth="54.0" selected="true" text="Flash" toggleGroup="$tgl_clientMode" GridPane.columnIndex="1">
|
||||
<GridPane.margin>
|
||||
<Insets />
|
||||
</GridPane.margin>
|
||||
</RadioButton>
|
||||
<RadioButton fx:id="rd_nitro" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" prefHeight="22.0" prefWidth="54.0" text="Nitro" toggleGroup="$tgl_clientMode" GridPane.columnIndex="4">
|
||||
<RadioButton fx:id="rd_origins" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" prefHeight="22.0" prefWidth="71.0" text="Origins" toggleGroup="$tgl_clientMode" GridPane.columnIndex="2">
|
||||
<GridPane.margin>
|
||||
<Insets />
|
||||
</GridPane.margin>
|
||||
</RadioButton>
|
||||
<RadioButton fx:id="rd_nitro" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" prefHeight="22.0" prefWidth="74.0" text="Nitro" toggleGroup="$tgl_clientMode" GridPane.columnIndex="4">
|
||||
<GridPane.margin>
|
||||
<Insets />
|
||||
</GridPane.margin>
|
||||
|
@ -5,7 +5,8 @@
|
||||
### Tab - Connection
|
||||
tab.connection=Connection
|
||||
tab.connection.client=Client type:
|
||||
tab.connection.client.flash=Flash / Air
|
||||
tab.connection.client.flash=Flash
|
||||
tab.connection.client.origins=Origins
|
||||
tab.connection.client.unity=Unity
|
||||
tab.connection.client.nitro=Nitro
|
||||
tab.connection.version=Hotel version:
|
||||
|
Loading…
Reference in New Issue
Block a user