Bom, eu achei um programa em java que simula LAN virtualmente, queria intender esse código para fazer o mesmo em delphi.
Primeira Parte :
JLanCraft.Java
Segunda Parte :
JLancraftGUI.java:
Alguém que entenda de java poderia me explicar as partes de packets e as funções que as DUAS partes faz?
Primeira Parte :
JLanCraft.Java
Código:
import java.io.IOException;
import java.io.InputStream;
import java.io.InterruptedIOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
public class JLancraft implements Runnable {
public static final int WAR3_UDP_PORT = 6112;
public static final int WAR3_DEFAULT_VERSION = 24;
// These threads must only be started/stopped while the current thread
// holds the lock on the JLancraft object.
private Thread jlancraftThread;
private Thread hostCheckerThread;
private Thread datagramSenderThread;
private Map<Integer, Thread> proxyListeners;
private Thread[] proxyPipes;
// incomingGameinfos maps the hash of an incoming GAMEINFO packet an index
// in the outgoingGameinfos list. It is used to determine whether a
// received GAMEINFO has been seen already and to remove GAMEINFOS that
// are no longer being sent by the host. NOTE: The actual packet data
// stored in outgoingGameinfos may not have the same hash as is used as
// a key in incomingGameinfos due to port changes in the packet data.
private Map<Integer, Integer> incomingGameinfos;
// This list contains a set of byte arrays to send as datagrams to
// Warcraft (that is, to localhost:6112). This list should only be
// accessed by the thread that holds its lock.
private List<byte[]> outgoingGameinfos;
private PrintStream out;
private boolean error;
private String hostname;
private int[] checkPorts;
private int gameVersion;
private Map<Integer, Integer> portMappings;
public static void main(String args[]) {
// JLancraft jlc2 = new JLancraft("67.9.159.140", 24, new int[] {6112, 6111});
JLancraft jlc2 = new JLancraft("localhost", 24, new int[] {6112, 6111});
// jlc2.portMappings.put(6113, 14333);
jlc2.run();
}
public JLancraft(String hostname) {
this(hostname, WAR3_DEFAULT_VERSION, new int[] {WAR3_UDP_PORT}, System.out, null);
}
public JLancraft(String hostname, int gameVersion) {
this(hostname, gameVersion, new int[] {WAR3_UDP_PORT}, System.out, null);
}
public JLancraft(String hostname, int gameVersion, int[] checkPorts) {
this(hostname, gameVersion, checkPorts, System.out, null);
}
public JLancraft(String hostname, int gameVersion, int[] checkPorts,
PrintStream out) {
this(hostname, gameVersion, checkPorts, out, null);
}
public JLancraft(String hostname, int gameVersion, int[] checkPorts,
PrintStream out, int[][] portMappings) {
super();
this.hostname = hostname;
this.gameVersion = gameVersion;
if (checkPorts != null)
this.checkPorts = Arrays.copyOf(checkPorts, checkPorts.length);
else
this.checkPorts = new int[0];
this.out = out;
this.portMappings = new HashMap<Integer, Integer>();
if (portMappings != null) {
for (int[] mapping : portMappings) {
this.portMappings.put(mapping[0], mapping[1]);
}
}
this.incomingGameinfos = new HashMap<Integer, Integer>();
this.outgoingGameinfos = new LinkedList<byte[]>();
this.proxyListeners = new HashMap<Integer, Thread>();
this.proxyPipes = new Thread[2];
}
public void run() {
println("Running...");
if (jlancraftThread != null) {
println("Error: Cannot run multiple threads using the same JLancraft object");
println("Exiting with error");
return;
}
jlancraftThread = Thread.currentThread();
InetAddress hostAddr;
try {
hostAddr = InetAddress.getByName(hostname);
} catch (UnknownHostException e) {
println("Error: Unknown host: " + hostname);
return;
}
while (!Thread.currentThread().isInterrupted() && !error) {
out.println();
println("Starting host checker and datagram sender...");
stopAllThreads();
synchronized (outgoingGameinfos) {
incomingGameinfos.clear();
outgoingGameinfos.clear();
}
startHostChecker(hostAddr);
startDatagramSender();
println("Waiting for threads to exit...");
try {
hostCheckerThread.join();
if (datagramSenderThread != null)
datagramSenderThread.join();
if (proxyPipes != null) {
if (proxyPipes[0] != null)
proxyPipes[0].join();
if (proxyPipes[1] != null)
proxyPipes[1].join();
}
} catch (InterruptedException e) {
println("Interrupted");
break;
}
println("All threads have exited");
println("Restarting...");
}
if (error) {
println("Exiting with error");
} else {
println("Exiting normally");
}
stopAllThreads();
}
private synchronized void startHostChecker(InetAddress addr) {
if (Thread.currentThread().isInterrupted())
return;
if (hostCheckerThread != null && hostCheckerThread.isAlive())
stopHostChecker();
Runnable r = new HostChecker(addr);
hostCheckerThread = new Thread(r, "HostChecker");
hostCheckerThread.start();
}
private synchronized void startDatagramSender() {
if (Thread.currentThread().isInterrupted())
return;
if (datagramSenderThread != null && datagramSenderThread.isAlive())
stopDatagramSender();
Runnable r = new DatagramSender();
datagramSenderThread = new Thread(r, "DatagramSender");
datagramSenderThread.start();
}
private synchronized void startProxyListener(ServerSocket socket, InetSocketAddress dest) {
if (Thread.currentThread().isInterrupted())
return;
int port = socket.getLocalPort();
if (proxyListeners.containsKey(port)) {
Thread t = proxyListeners.get(port);
if (t != null && t.isAlive())
stopProxyListener(port);
}
Runnable r = new ProxyListener(socket, dest);
Thread t = new Thread(r, "ProxyListener-" + port + "-" + dest.getPort());
proxyListeners.put(port, t);
t.start();
}
private synchronized void startProxyPipes(InputStream in1, OutputStream out1, InputStream in2, OutputStream out2) {
if (Thread.currentThread().isInterrupted())
return;
stopProxyPipes();
Runnable a = new ProxyPipe(in1, out2);
Runnable b = new ProxyPipe(in2, out1);
proxyPipes[0] = new Thread(a, "ProxyPipeA");
proxyPipes[1] = new Thread(b, "ProxyPipeB");
proxyPipes[0].start();
proxyPipes[1].start();
}
private synchronized void stopHostChecker() {
if (hostCheckerThread != null)
hostCheckerThread.interrupt();
}
private synchronized void stopDatagramSender() {
if (datagramSenderThread != null)
datagramSenderThread.interrupt();
}
private synchronized void stopProxyListener(int port) {
Thread t = proxyListeners.get(port);
if (t != null) {
t.interrupt();
proxyListeners.remove(port);
}
}
private synchronized void stopAllProxyListeners() {
for (Thread t : proxyListeners.values()) {
t.interrupt();
}
proxyListeners.clear();
}
private synchronized void stopProxyPipes() {
if (proxyPipes[0] != null)
proxyPipes[0].interrupt();
if (proxyPipes[1] != null)
proxyPipes[1].interrupt();
}
private synchronized void stopAllThreads() {
stopHostChecker();
stopDatagramSender();
stopAllProxyListeners();
stopProxyPipes();
}
private synchronized boolean setupProxy(Socket a, Socket b) {
InputStream inA, inB;
OutputStream outA, outB;
try {
inA = a.getInputStream();
outA = a.getOutputStream();
inB = b.getInputStream();
outB = b.getOutputStream();
} catch (IOException e) {
println("Error: Received IOException while setting up proxy");
println(e.toString());
return false;
}
startProxyPipes(inA, outA, inB, outB);
stopHostChecker();
stopDatagramSender();
stopAllProxyListeners();
return true;
}
private void println(String s) {
out.println("[" + Thread.currentThread().getName() + "] " + s);
}
private void printf(String fmt, Object... params) {
out.print("[" + Thread.currentThread().getName() + "] ");
out.printf(fmt, params);
}
private void abortWithError() {
println("Exiting with error");
error = true;
jlancraftThread.interrupt();
}
private int getGamePort(byte[] data) {
int len = data.length;
int ret = ((data[len - 1] & 0xFF) << 8) | (data[len - 2] & 0xFF);
return ret;
}
private void setGamePort(byte[] data, int port) {
int len = data.length;
data[len-1] = (byte)((port >> 8) & 0xFF);
data[len-2] = (byte)(port & 0xFF);
}
private byte[] getSearchgameData() {
byte[] ret = {
(byte)247, // W3GS_HEADER_CONSTANT
47, // W3GS_SEARCHGAME
16, 0, // total packet length (little-endian)
80, 88, 51, 87, // product ID ("W3XP", reversed);
(byte)gameVersion, 0, 0, 0, // warcraft minor version (little-endian)
0, 0, 0, 0, // unknown
};
return ret;
}
private class HostChecker implements Runnable {
private InetAddress hostAddr;
public static final int MAX_SEND_FAILURES = 2;
public static final int MAX_RECV_FAILURES = 2;
public static final int CHECK_INTERVAL = 5000;
public HostChecker(InetAddress hostAddr) {
super();
this.hostAddr = hostAddr;
}
public void run() {
println("Running...");
DatagramSocket sock;
try {
sock = new DatagramSocket();
} catch (IOException e) {
println("Error: Caught exception when creating DatagramSocket");
println(e.toString());
abortWithError();
return;
}
byte[] data = getSearchgameData();
DatagramPacket pkt = new DatagramPacket(data, data.length);
pkt.setAddress(hostAddr);
byte[] buf = new byte[2048];
DatagramPacket pktIn = new DatagramPacket(buf, buf.length);
int sendFailCount = 0;
int recvFailCount = 0;
int remainingTime;
long startTime, endTime;
println("Checking for games every " + CHECK_INTERVAL + " ms...");
while (!Thread.currentThread().isInterrupted()) {
if (!sendSearchgames(sock, pkt)) {
sendFailCount++;
if (sendFailCount > MAX_SEND_FAILURES) {
println("Error: Failed to send any SEARCHGAMEs in the past " + sendFailCount + " attempts");
sock.close();
abortWithError();
return;
}
} else {
sendFailCount = 0;
}
remainingTime = CHECK_INTERVAL;
while (remainingTime > 0) {
try {
sock.setSoTimeout(remainingTime);
startTime = System.currentTimeMillis();
sock.receive(pktIn);
handleReply(pktIn);
endTime = System.currentTimeMillis();
remainingTime -= (endTime - startTime);
recvFailCount = 0;
} catch (SocketTimeoutException e) {
remainingTime = 0;
recvFailCount = 0;
} catch (InterruptedIOException e) {
remainingTime = 0;
Thread.currentThread().interrupt();
break;
} catch (IOException e) {
println("Warning: Exception occurred while waiting for GAMEINFO replies");
println(e.toString());
recvFailCount++;
if (recvFailCount > MAX_RECV_FAILURES) {
println("Error: Failed to listen for packets for the past " + recvFailCount + " attempts");
sock.close();
abortWithError();
return;
}
}
}
if (remainingTime > 0) {
try {
Thread.sleep(remainingTime);
} catch (InterruptedException e) {
break;
}
}
}
sock.close();
println("Exiting normally");
}
private boolean sendSearchgames(DatagramSocket sock, DatagramPacket pkt) {
boolean success = false;
for (int i=0;i<checkPorts.length;i++) {
pkt.setPort(checkPorts[i]);
try {
sock.send(pkt);
success = true;
} catch (IOException e) {
println("Warning: Failed to send SEARCHGAME to port " + checkPorts[i]);
}
}
return success;
}
private void handleReply(DatagramPacket pkt) {
if (!pkt.getAddress().equals(hostAddr)) {
println("Warning: Ignoring incoming packet from host " + pkt.getAddress() + " (expected " + hostAddr + ")");
return;
}
if (pkt.getLength() < 6) {
println("Warning: Packet from " + pkt.getAddress() + " is too short");
return;
}
// Get the packet data
byte[] data = new byte[pkt.getLength()];
System.arraycopy(pkt.getData(), pkt.getOffset(), data, 0, pkt.getLength());
// Check if this GAMEINFO has been seen before
// Zero the uptime field because it changes from one GAMEINFO to
// the next.
byte[] uptime = new byte[4];
System.arraycopy(data, data.length-6, uptime, 0, 4);
Arrays.fill(data, data.length-6, data.length-2, (byte)0);
int hash = Arrays.hashCode(data);
System.arraycopy(uptime, 0, data, data.length-6, 4);
// Add this packet's info to incomingGameinfos/outgoingGameinfos
synchronized (outgoingGameinfos) {
if (incomingGameinfos.containsKey(hash))
return;
String hashStr = Integer.toHexString(hash);
println("Found new game with GAMEINFO hash 0x" + Integer.toHexString(hash));
// Get the game port
int gamePort = getGamePort(data);
int listenPort = gamePort;
println("Game 0x" + hashStr + ": GAMEINFO specifies gameport " + gamePort);
if (portMappings.containsKey(gamePort) && portMappings.get(gamePort) != null) {
println("Gameport " + gamePort + " has been redirected to port " + portMappings.get(gamePort));
gamePort = portMappings.get(gamePort);
}
// Start a ServerSocket for a ProxyListener to listen on
ServerSocket server = null;
try {
server = new ServerSocket(0, 0, InetAddress.getLocalHost());
} catch (IOException e) {
println("Error: Unable to bind to any TCP port");
abortWithError();
return;
}
listenPort = server.getLocalPort();
println("Game 0x" + hashStr + ": Listening on TCP port " + listenPort);
setGamePort(data, listenPort);
println("Game 0x" + hashStr + ": Starting proxy listener for TCP port " + listenPort);
println("Game 0x" + hashStr + ": Connections will be forwarded to remote port " + gamePort);
// Start the ProxyListener for this game
startProxyListener(server, new InetSocketAddress(hostAddr, gamePort));
int idx = outgoingGameinfos.size();
outgoingGameinfos.add(data);
incomingGameinfos.put(hash, idx);
}
}
}
private class DatagramSender implements Runnable {
public static final int MAX_SEND_FAILURES = 2;
public static final int DATAGRAM_INTERVAL = 1000;
public void run() {
println("Running...");
DatagramSocket sock;
try {
sock = new DatagramSocket();
} catch (IOException e) {
println("Error: Caught exception while creating DatagramSocket");
println(e.toString());
abortWithError();
return;
}
println("Running on UDP port " + sock.getLocalPort());
byte[] buf = new byte[0];
DatagramPacket pkt = new DatagramPacket(buf, 0);
try {
pkt.setAddress(InetAddress.getLocalHost());
} catch (UnknownHostException e) {
println("Error: Unable to set datagram destination to local host");
println(e.toString());
sock.close();
abortWithError();
return;
}
pkt.setPort(WAR3_UDP_PORT);
boolean success;
int failCount = 0;
while (!Thread.currentThread().isInterrupted()) {
success = false;
synchronized (outgoingGameinfos) {
if (outgoingGameinfos.size() == 0)
success = true;
for (byte[] data : outgoingGameinfos) {
pkt.setData(data);
try {
sock.send(pkt);
success = true;
} catch (IOException e) {
println("Warning: Failed to send datagram");
println(e.toString());
}
}
}
if (!success) {
failCount++;
if (failCount > MAX_SEND_FAILURES) {
println("Error: Unable to send any datagrams in the past " + failCount + " attempts");
abortWithError();
sock.close();
return;
}
} else {
failCount = 0;
}
try {
Thread.sleep(DATAGRAM_INTERVAL);
} catch (InterruptedException e) {
break;
}
}
sock.close();
println("Exiting normally");
}
}
private class ProxyListener implements Runnable {
public static final int ACCEPT_TIMEOUT = 5000;
ServerSocket server;
InetSocketAddress dest;
public ProxyListener(ServerSocket server, InetSocketAddress dest) {
super();
this.server = server;
this.dest = dest;
}
public void run() {
println("Running...");
try {
server.setSoTimeout(ACCEPT_TIMEOUT);
} catch (IOException e) {
println("Caught exception when setting accept timeout");
println(e.toString());
printErrorAndRespawn();
}
Socket incoming = null;
while (!Thread.currentThread().isInterrupted() && incoming == null) {
try {
incoming = server.accept();
} catch (SocketTimeoutException e) {
// try again
} catch (IOException e) {
println("Error: Failed to accept connection");
println(e.toString());
printErrorAndRespawn();
return;
}
}
if (Thread.currentThread().isInterrupted()) {
println("Exiting normally");
return;
}
println("Received incoming connection from " + incoming.getRemoteSocketAddress());
Socket outgoing;
try {
outgoing = new Socket(dest.getAddress(), dest.getPort());
} catch (IOException e) {
println("Error: Failed to connect to destination: " + dest);
println(e.toString());
println("Closing incoming connection...");
try {
incoming.close();
} catch (IOException e2) {
println("Caught exception while closing incoming connection");
println(e2.toString());
}
printErrorAndRespawn();
return;
}
println("Created outgoing connection to " + outgoing.getRemoteSocketAddress());
if (setupProxy(incoming, outgoing))
println("Exiting normally");
else
printErrorAndRespawn();
}
private void printErrorAndRespawn() {
println("Exiting with error");
println("Respawning...");
startProxyListener(server, dest);
}
}
private class ProxyPipe implements Runnable {
private InputStream inStream;
private OutputStream outStream;
public ProxyPipe(InputStream inStream, OutputStream outStream) {
super();
this.inStream = inStream;
this.outStream = outStream;
}
public void run() {
println("Running...");
byte[] buf = new byte[4096];
int len;
boolean error = false;
while (!Thread.currentThread().isInterrupted()) {
try {
len = inStream.read(buf);
if (len == -1)
break;
outStream.write(buf, 0, len);
} catch (InterruptedIOException e) {
break;
} catch (IOException e) {
println("Warning: Caught exception while transferring data");
println(e.toString());
error = true;
break;
}
}
try {
outStream.close();
} catch (IOException e) {
}
try {
inStream.close();
} catch (IOException e) {
}
if (error)
println("Exiting due to exception");
else
println("Exiting normally");
}
}
}
Segunda Parte :
JLancraftGUI.java:
Código:
import java.awt.Dimension;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.io.InputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.List;
import java.util.prefs.Preferences;
import javax.swing.GroupLayout;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.GroupLayout.Alignment;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableColumn;
public class JLancraftGUI extends JFrame implements ActionListener {
private static final String VERSION = "0.3.0";
private static final int MAX_HISTORY = 10;
private static final Preferences PREFS = Preferences.userRoot().node("JLancraftGUI");
private JDialog advancedSettingsDialog;
private JComboBox hostnameCombo;
private JTextArea outputArea;
private JScrollPane outputScroller;
private JButton startButton;
private JButton stopButton;
private JButton helpButton;
private JButton advancedSettingsButton;
private JTextField udpPortsField;
private JTextField gameVersionField;
private JTable portRedirectTable;
private JScrollPane portRedirectScroller;
private JButton addRedirectButton;
private JButton removeRedirectButton;
private JButton okButton;
private JButton cancelButton;
private PortRedirectTableModel portRedirectTableModel;
private PrintStream out;
private Thread pipeReaderThread;
private Thread jlancraftThread;
private String hostname;
private int gameVersion = 24;
private int[] udpPorts = { 6112 };
private int[][] portRedirects = new int[0][];
public static void main(String[] args) {
Runnable r = new Runnable() {
public void run() {
JFrame f = new JLancraftGUI();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setLocationByPlatform(true);
f.setVisible(true);
}
};
SwingUtilities.invokeLater(r);
}
public JLancraftGUI() {
super("JLancraft " + VERSION);
buildMainGUI();
buildSettingsGUI();
startPipeThread();
loadSettings();
}
private void startPipeThread() {
PipedInputStream pipeIn;
PipedOutputStream pipeOut;
try {
pipeIn = new PipedInputStream();
pipeOut = new PipedOutputStream(pipeIn);
} catch (IOException e) {
appendOutput("[" + Thread.currentThread().getName() + "] Error: Unable to create pipes for output\n");
appendOutput("[" + Thread.currentThread().getName() + "] " + e + "\n");
return;
}
Runnable r = new PipeReader(pipeIn);
pipeReaderThread = new Thread(r, "OutputPrinter");
pipeReaderThread.start();
out = new PrintStream(pipeOut);
}
private void buildMainGUI() {
JLabel hostnameLabel = new JLabel("Hostname:");
hostnameCombo = new JComboBox();
startButton = new JButton("Start");
stopButton = new JButton("Stop");
helpButton = new JButton("Help");
advancedSettingsButton = new JButton("Advanced Settings...");
outputArea = new JTextArea(15, 40);
outputScroller = new JScrollPane(outputArea, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
startButton.addActionListener(this);
stopButton.addActionListener(this);
helpButton.addActionListener(this);
advancedSettingsButton.addActionListener(this);
advancedSettingsButton.setActionCommand("Settings");
hostnameCombo.setEditable(true);
stopButton.setEnabled(false);
GroupLayout layout = new GroupLayout(getContentPane());
setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup()
.addGroup(
layout.createSequentialGroup()
.addGap(5)
.addComponent(hostnameLabel)
.addGap(5)
.addComponent(hostnameCombo)
.addGap(5)
.addComponent(startButton)
.addGap(5)
.addComponent(stopButton)
.addGap(5)
)
.addGroup(
layout.createSequentialGroup()
.addGap(0, 5, Short.MAX_VALUE)
.addComponent(advancedSettingsButton)
.addGap(5)
.addComponent(helpButton)
.addGap(0, 5, Short.MAX_VALUE)
)
.addComponent(outputScroller)
);
layout.setVerticalGroup(
layout.createSequentialGroup()
.addGap(5)
.addGroup(
layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
.addComponent(hostnameLabel)
.addComponent(hostnameCombo)
.addComponent(startButton)
.addComponent(stopButton)
)
.addGap(5)
.addGroup(
layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
.addComponent(advancedSettingsButton)
.addComponent(helpButton)
)
.addGap(5)
.addComponent(outputScroller)
);
pack();
}
private void buildSettingsGUI() {
advancedSettingsDialog = new JDialog(this, "Advanced Settings", true);
JLabel udpPortsLabel = new JLabel("UDP Port(s):");
JLabel gameVersionLabel = new JLabel("Game Minor Version:");
JLabel portRedirectLabel = new JLabel("Game Port Redirections:");
udpPortsField = new JTextField("6112", 10);
gameVersionField = new JTextField("24", 2);
addRedirectButton = new JButton("Add");
removeRedirectButton = new JButton("Remove");
okButton = new JButton("OK");
cancelButton = new JButton("Cancel");
createPortRedirectTable();
portRedirectScroller = new JScrollPane(portRedirectTable);
portRedirectScroller.setPreferredSize(new Dimension(300,200));
addRedirectButton.addActionListener(this);
removeRedirectButton.addActionListener(this);
okButton.addActionListener(this);
cancelButton.addActionListener(this);
GroupLayout layout = new GroupLayout(advancedSettingsDialog.getContentPane());
advancedSettingsDialog.getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup()
.addGroup(
layout.createSequentialGroup()
.addGap(5)
.addGroup(
layout.createParallelGroup()
.addComponent(udpPortsLabel)
.addComponent(gameVersionLabel)
)
.addGap(5)
.addGroup(
layout.createParallelGroup()
.addComponent(udpPortsField)
.addComponent(gameVersionField)
)
.addGap(5)
)
.addGroup(
layout.createSequentialGroup()
.addGap(5)
.addGroup(
layout.createParallelGroup()
.addComponent(portRedirectLabel)
.addGroup(
layout.createSequentialGroup()
.addComponent(portRedirectScroller)
.addGap(5)
.addGroup(
layout.createParallelGroup()
.addComponent(addRedirectButton)
.addComponent(removeRedirectButton)
)
)
)
.addGap(5)
)
.addGroup(
layout.createSequentialGroup()
.addGap(5, 5, Short.MAX_VALUE)
.addComponent(okButton)
.addGap(5)
.addComponent(cancelButton)
.addGap(5)
)
);
layout.setVerticalGroup(
layout.createSequentialGroup()
.addGap(5)
.addGroup(
layout.createParallelGroup(Alignment.BASELINE)
.addComponent(udpPortsLabel)
.addComponent(udpPortsField)
)
.addGap(5)
.addGroup(
layout.createParallelGroup(Alignment.BASELINE)
.addComponent(gameVersionLabel)
.addComponent(gameVersionField)
)
.addGap(15)
.addComponent(portRedirectLabel)
.addGap(5)
.addGroup(
layout.createParallelGroup()
.addComponent(portRedirectScroller)
.addGroup(
layout.createSequentialGroup()
.addComponent(addRedirectButton)
.addGap(5)
.addComponent(removeRedirectButton)
)
)
.addGap(10)
.addGroup(
layout.createParallelGroup()
.addComponent(okButton)
.addComponent(cancelButton)
)
.addGap(5)
);
advancedSettingsDialog.pack();
}
private void createPortRedirectTable() {
portRedirectTableModel = new PortRedirectTableModel();
portRedirectTable = new JTable(portRedirectTableModel);
}
private class PortRedirectTableModel extends AbstractTableModel {
private static final long serialVersionUID = -9125638713537846044L;
private List<int[]> redirs = new ArrayList<int[]>();
public String getColumnName(int columnIndex) {
if (columnIndex == 0)
return "Game Port";
if (columnIndex == 1)
return "Redirected Port";
return "";
}
public Class<?> getColumnClass(int columnIndex) {
if (columnIndex == 0 || columnIndex == 1)
return Integer.class;
return null;
}
public boolean isCellEditable(int rowIndex, int columnIndex) {
return rowIndex >= 0 && rowIndex < redirs.size()
&& columnIndex >= 0 && columnIndex < 2;
}
public void setValueAt(Object value, int rowIndex, int columnIndex) {
if (!isCellEditable(rowIndex, columnIndex))
return;
if (!(value instanceof Integer))
return;
redirs.get(rowIndex)[columnIndex] = (Integer)value;
fireTableCellUpdated(rowIndex, columnIndex);
}
public int getRowCount() {
return redirs.size();
}
public int getColumnCount() {
return 2;
}
public Object getValueAt(int rowIndex, int columnIndex) {
return redirs.get(rowIndex)[columnIndex];
}
public int[] getMapping(int index) {
return Arrays.copyOf(redirs.get(index), 2);
}
public void addMapping(int from, int to) {
redirs.add(new int[] { from, to });
fireTableRowsInserted(redirs.size()-1, redirs.size()-1);
}
public void removeMapping(int rowIdx) {
redirs.remove(rowIdx);
fireTableRowsDeleted(rowIdx, rowIdx);
}
public void removeMappings(int[] rowIdxs) {
for (int i = rowIdxs.length - 1; i >= 0; i--) {
removeMapping(rowIdxs[i]);
}
}
public void clearMappings() {
int size = redirs.size();
redirs.clear();
if (size > 0)
fireTableRowsDeleted(0, size - 1);
}
}
@Override
public void actionPerformed(ActionEvent e) {
String cmd = e.getActionCommand();
if (cmd.equals("Start")) {
startJLancraft();
} else if (cmd.equals("Stop")) {
stopJLancraft();
} else if (cmd.equals("Settings")) {
displayAdvancedSettingsDialog();
} else if (cmd.equals("Help")) {
displayHelp();
} else if (cmd.equals("Add")) {
addPortRedirect();
} else if (cmd.equals("Remove")) {
removePortRedirect();
} else if (cmd.equals("OK")) {
closeAdvancedSettingsDialog(true);
} else if (cmd.equals("Cancel")) {
closeAdvancedSettingsDialog(false);
}
}
private synchronized void startJLancraft() {
if (jlancraftThread != null) {
out.println("[" + Thread.currentThread().getName() + "] Error: A JLancraft thread is already running\n");
return;
}
hostname = (String)hostnameCombo.getSelectedItem();
saveSettings();
Runnable r = new JLancraft(hostname, gameVersion, Arrays.copyOf(udpPorts, udpPorts.length), out, portRedirects);
jlancraftThread = new Thread(r, "JLancraft");
out.println("[" + Thread.currentThread().getName() + "] Starting JLancraft thread...\n");
jlancraftThread.start();
Runnable r2 = new Runnable() {
public void run() {
try {
jlancraftThread.join();
} catch (InterruptedException e) {}
stopJLancraft();
}
};
new Thread(r2).start();
startButton.setEnabled(false);
stopButton.setEnabled(true);
}
private synchronized void stopJLancraft() {
if (jlancraftThread == null) {
return;
}
out.println("[" + Thread.currentThread().getName() + "] Stopping JLancraft thread...\n");
jlancraftThread.interrupt();
jlancraftThread = null;
startButton.setEnabled(true);
stopButton.setEnabled(false);
}
private void displayAdvancedSettingsDialog() {
StringBuffer sb = new StringBuffer();
for (int port : udpPorts) {
sb.append(port);
sb.append(", ");
}
sb.delete(sb.length() - 2, sb.length());
udpPortsField.setText(sb.toString());
gameVersionField.setText("" + gameVersion);
portRedirectTableModel.clearMappings();
for (int[] redir : portRedirects) {
portRedirectTableModel.addMapping(redir[0], redir[1]);
}
Rectangle mainWinBounds = this.getBounds();
int centerX = mainWinBounds.x + mainWinBounds.width / 2;
int centerY = mainWinBounds.y + mainWinBounds.height / 2;
Rectangle advSetWinBounds = advancedSettingsDialog.getBounds();
advSetWinBounds.x = centerX - advSetWinBounds.width / 2;
advSetWinBounds.y = centerY - advSetWinBounds.height / 2;
advancedSettingsDialog.setBounds(advSetWinBounds);
advancedSettingsDialog.setVisible(true);
}
private void displayHelp() {
clearOutput();
appendOutput("No help available in this version");
}
private void addPortRedirect() {
portRedirectTableModel.addMapping(JLancraft.WAR3_UDP_PORT, JLancraft.WAR3_UDP_PORT);
int rowIdx = portRedirectTableModel.getRowCount() - 1;
portRedirectTable.editCellAt(rowIdx, 0);
}
private void removePortRedirect() {
portRedirectTableModel.removeMappings(portRedirectTable.getSelectedRows());
}
private void closeAdvancedSettingsDialog(boolean save) {
if (save) {
if (!validateAdvancedSettings())
return;
copyAdvancedSettings();
saveAdvancedSettings();
}
advancedSettingsDialog.setVisible(false);
}
private boolean validateAdvancedSettings() {
String portStr = udpPortsField.getText();
String[] portArr = portStr.split(",");
int port;
for (String str : portArr) {
str = str.trim();
try {
port = Integer.parseInt(str);
} catch (NumberFormatException e) {
JOptionPane.showMessageDialog(advancedSettingsDialog, "Invalid UDP port: \"" + str + "\" is not a number", "Error", JOptionPane.ERROR_MESSAGE);
udpPortsField.requestFocus();
return false;
}
if (port <= 0 || port >= 65536) {
JOptionPane.showMessageDialog(advancedSettingsDialog, "Invalid UDP port: " + port + " is not within the range 1-65535", "Error", JOptionPane.ERROR_MESSAGE);
udpPortsField.requestFocus();
return false;
}
}
int version;
String versionStr = gameVersionField.getText();
try {
version = Integer.parseInt(versionStr);
} catch (NumberFormatException e) {
JOptionPane.showMessageDialog(advancedSettingsDialog, "Invalid game minor version: \"" + versionStr + "\" is not a number", "Error", JOptionPane.ERROR_MESSAGE);
gameVersionField.requestFocus();
return false;
}
return true;
}
private void copyAdvancedSettings() {
String[] portStrArray = udpPortsField.getText().split(",");
udpPorts = new int[portStrArray.length];
for (int i=0;i<portStrArray.length;i++) {
udpPorts[i] = Integer.parseInt(portStrArray[i].trim());
}
gameVersion = Integer.parseInt(gameVersionField.getText());
int numRedirs = portRedirectTableModel.getRowCount();
portRedirects = new int[numRedirs][2];
for (int i=0;i<numRedirs;i++) {
portRedirects[i] = Arrays.copyOf(portRedirectTableModel.getMapping(i), 2);
}
}
private void saveSettings() {
PREFS.put("lastHostname", hostname);
if (hostnameCombo.getSelectedIndex() != -1)
hostnameCombo.removeItemAt(hostnameCombo.getSelectedIndex());
hostnameCombo.insertItemAt(hostname, 0);
hostnameCombo.setSelectedIndex(0);
int hostnameCount = Math.min(hostnameCombo.getItemCount(), MAX_HISTORY);
PREFS.putInt("hostnameCount", hostnameCount);
for (int i = 0; i < hostnameCount; i++) {
PREFS.put("hostname" + i, (String)hostnameCombo.getItemAt(i));
}
saveAdvancedSettings();
}
private void saveAdvancedSettings() {
StringBuffer sb = new StringBuffer();
for (int port : udpPorts) {
sb.append(port);
sb.append(',');
}
PREFS.put("udpPorts", sb.toString());
PREFS.putInt("gameVersion", gameVersion);
sb = new StringBuffer();
for (int[] redir : portRedirects) {
sb.append(redir[0]);
sb.append(':');
sb.append(redir[1]);
sb.append(',');
}
PREFS.put("portRedirects", sb.toString());
}
private void loadSettings() {
hostname = PREFS.get("lastHostname", "localhost");
int hostnameCount = PREFS.getInt("hostnameCount", 0);
hostnameCombo.removeAllItems();
for (int i=0;i<hostnameCount;i++) {
String currentHost = PREFS.get("hostname" + i, "");
if (currentHost.length() > 0)
hostnameCombo.addItem(currentHost);
}
hostnameCombo.setSelectedItem(hostname);
// remaining fields will be set in displayAdvancedSettingsDialog()
String[] udpPortStrArray = PREFS.get("udpPorts", "" + JLancraft.WAR3_UDP_PORT).split(",");
int[] tempUDPPorts = new int[udpPortStrArray.length];
try {
for (int i=0;i<tempUDPPorts.length;i++) {
tempUDPPorts[i] = Integer.parseInt(udpPortStrArray[i].trim());
}
udpPorts = tempUDPPorts;
} catch (NumberFormatException e) {
// use default for udpPorts
out.println("[" + Thread.currentThread().getName() + "] Warning: Unable to load UDP Ports setting");
}
gameVersion = PREFS.getInt("gameVersion", JLancraft.WAR3_DEFAULT_VERSION);
String redirStr = PREFS.get("portRedirects", "");
if (redirStr.trim().length() > 0) {
String[] redirStrArray = redirStr.split(",");
int[][] tempPortRedirects = new int[redirStrArray.length][2];
try {
String[] redirPorts;
for (int i=0;i<tempPortRedirects.length;i++) {
redirPorts = redirStrArray[i].split(":");
for (int j=0;j<2;j++) {
tempPortRedirects[i][j] = Integer.parseInt(redirPorts[j].trim());
}
}
portRedirects = tempPortRedirects;
} catch (NumberFormatException e) {
// use default for portRedirects
out.println("[" + Thread.currentThread().getName() + "] Warning: Unable to load Port Redirects setting");
} catch (ArrayIndexOutOfBoundsException e) {
// use default for portRedirects
out.println("[" + Thread.currentThread().getName() + "] Warning: Unable to load Port Redirects setting");
}
}
}
private void appendOutput(final String str) {
Runnable r = new Runnable() {
public void run() {
outputArea.append(str);
outputArea.setCaretPosition(outputArea.getText().length());
}
};
if (SwingUtilities.isEventDispatchThread()) {
r.run();
} else {
SwingUtilities.invokeLater(r);
}
}
private void clearOutput() {
Runnable r = new Runnable() {
public void run() {
outputArea.setText("");
}
};
if (SwingUtilities.isEventDispatchThread()) {
r.run();
} else {
SwingUtilities.invokeLater(r);
}
}
private class PipeReader implements Runnable {
private InputStream in;
public PipeReader(InputStream in) {
this.in = in;
}
public void run() {
appendOutput("[" + Thread.currentThread().getName() + "] Running...\n");
int len;
byte[] buf = new byte[4096];
while (!Thread.currentThread().isInterrupted()) {
try {
len = in.read(buf);
} catch (IOException e) {
if (e.getMessage() != null && e.getMessage().equals("Write end dead")) {
try {
Thread.sleep(50);
} catch (InterruptedException e2) {
break;
}
continue;
} else {
appendOutput("[" + Thread.currentThread().getName() + "] Error: Received exception while handling output\n");
appendOutput("[" + Thread.currentThread().getName() + "] " + e + "\n");
appendOutput("[" + Thread.currentThread().getName() + "] Exiting with error\n");
return;
}
}
if (len == -1)
break;
appendOutput(new String(buf, 0, len));
}
appendOutput("[" + Thread.currentThread().getName() + "] Exiting normally\n");
}
}
}
Alguém que entenda de java poderia me explicar as partes de packets e as funções que as DUAS partes faz?