package common.ui;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Frame;
import java.awt.GridLayout;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.io.ByteArrayOutputStream;
import java.io.DataInput;
import java.io.DataInputStream;
import java.io.DataOutput;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.ref.WeakReference;
import java.net.ConnectException;
import java.net.MalformedURLException;
import java.net.Socket;
import java.net.URL;
import java.net.URLConnection;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PublicKey;
import java.security.spec.X509EncodedKeySpec;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import javax.crypto.Cipher;
import javax.crypto.KeyAgreement;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.jnlp.FileContents;
import javax.jnlp.FileOpenService;
import javax.jnlp.ServiceManager;
import javax.jnlp.UnavailableServiceException;
import javax.swing.AbstractListModel;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.JList;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.ScrollPaneConstants;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import javax.swing.border.BevelBorder;
import javax.swing.border.Border;
import javax.swing.border.CompoundBorder;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;
import javax.swing.filechooser.FileFilter;
import common.Face;
import common.PubGroupMember;
import common.PubRoom;
import common.PubRoomEntity;
import common.ScriptType;
import common.TextEditorType;
import common.clientevent.ClientEvent;
import common.clientevent.CommandClientEvent;
import common.clientevent.ExecuteManualScriptClientEvent;
import common.clientevent.ImageUploadClientEvent;
import common.clientevent.SaveScriptClientEvent;
import common.gameevent.GameEvent;
import common.gameevent.StatGameEvent.StatType;
import common.gameevent.StatGameEvent.TableType;
public class GameClient {
private static final String DEFAULT_WINDOW_TITLE = "Aelfengard";
private static JPasswordField chatField;
private static boolean passwordMode = true;
private static JFrame mainFrame;
private static GameMap map;
private static HistoryListModel historyListModel = new HistoryListModel();
private static JList commandList = new JList(historyListModel);
private static JLabel roomLabel;
private static EntityList<PubRoomEntity> roomEntityList =
new EntityList<PubRoomEntity>("Current Room");
private static EntityList<PubGroupMember> groupList =
new EntityList<PubGroupMember>("Current Group");
private static JPanel chatPanel;
private static DisplayPanel displayPanel = new DisplayPanel();
private static JLabel roomImageLabel;
private static JProgressBar loadingBar;
private static JPanel imageOverlayPanel;
private static JLabel gameModeLabel = new JLabel();
private static JCheckBoxMenuItem restoreItem;
private static final Object writeQueueLock = new Object();
private static final Object imageCacheLock = new Object();
private static ArrayList<ClientEvent> writeQueue = new ArrayList<ClientEvent>();
private static boolean loginComplete;
private static int roomImageLoadCount = 0;
private static String extraModeInfo;
private static String currentGameMode;
private static String currentBaseURL;
private static Cipher encipher;
private static Cipher decipher;
private static List<WeakReference<ConsoleWindow>> consoles = new LinkedList<WeakReference<ConsoleWindow>>();
private static int nextConsoleId;
public static void main(String... args) {
try {
int port = 443;
if (args.length < 1 || args.length > 2) {
System.err.println("Usage: java -jar client.jar HOSTNAME [PORT]");
return;
}
String host = args[0];
if (args.length == 2) {
port = Integer.parseInt(args[1]);
}
makeUI(); displayPanel.print("Connecting to " + host + "...");
Socket socket = new Socket(host, port);
println(" @2ZZConnected!");
DataInputStream in = new DataInputStream(socket.getInputStream());
DataOutputStream out = new DataOutputStream(socket.getOutputStream());
negotiateEncryption(in, out);
println("");
new WriterThread(out).start();
while (true) {
int length = in.readInt();
byte[] b = new byte[length];
in.readFully(b);
b = decipher.doFinal(b);
final GameEvent evt = GameEvent.forByteArray(b);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
evt.run();
}
});
}
} catch (ConnectException ex) {
ex.printStackTrace();
println("Couldn't connect to host: " + ex.getMessage());
} catch (EOFException ex) {
ex.printStackTrace();
try { Thread.sleep(1000); } catch (Exception ex2) { }
System.exit(0);
} catch (Throwable t) {
t.printStackTrace();
println(getStackTrace(t));
}
}
private static void makeUI() throws Exception {
mainFrame = new JFrame(DEFAULT_WINDOW_TITLE);
mainFrame.setJMenuBar(makeMenuBar());
ClientUtils.initWindow(mainFrame, 0.80, 0.80);
roomLabel = new JLabel();
map = new GameMap();
JScrollPane mapScroll = new JScrollPane(map);
commandList.setForeground(Color.white);
commandList.setBackground(Color.black);
JLayeredPane roomImagePanel = new JLayeredPane();
roomImagePanel.setPreferredSize(new Dimension(350, 250));
roomImagePanel.setBackground(Color.white);
roomImageLabel = new JLabel();
imageOverlayPanel = new JPanel(new BorderLayout());
roomImagePanel.add(roomImageLabel, new Integer(0));
roomImagePanel.add(imageOverlayPanel, new Integer(1));
JPanel loadingParent = new JPanel(new BorderLayout());
JPanel loadingPanel = new JPanel(new BorderLayout(10, 10));
JLabel loadingLabel = new JLabel("Loading image");
loadingBar = new JProgressBar();
loadingBar.setBorder(new CompoundBorder(new EmptyBorder(10, 10, 10, 10), loadingBar.getBorder()));
loadingBar.setOpaque(false);
loadingPanel.add(loadingLabel, BorderLayout.WEST);
loadingPanel.add(loadingBar, BorderLayout.CENTER);
loadingPanel.setBorder(new CompoundBorder(new LineBorder(Color.black, 1), new EmptyBorder(0, 5, 0, 5)));
loadingPanel.setBackground(Color.white);
loadingPanel.setOpaque(true);
loadingParent.add(loadingPanel, BorderLayout.CENTER);
loadingParent.setBorder(new EmptyBorder(10, 10, 10, 10));
loadingParent.setOpaque(false);
imageOverlayPanel.add(loadingParent, BorderLayout.SOUTH);
imageOverlayPanel.setSize(new Dimension(350, 250));
imageOverlayPanel.setLocation(0, 0);
imageOverlayPanel.setOpaque(false);
imageOverlayPanel.setVisible(false);
chatField = new JPasswordField();
setPasswordMode(false);
chatField.setFont(chatField.getFont().deriveFont(Font.BOLD));
chatPanel = new JPanel(new BorderLayout());
JPanel mapPanel = new JPanel(new BorderLayout());
gameModeLabel.setForeground(Color.red);
JPanel gameModePanel = new JPanel(new BorderLayout());
gameModePanel.add(gameModeLabel, BorderLayout.WEST);
gameModePanel.add(chatField, BorderLayout.CENTER);
chatPanel.add(gameModePanel, BorderLayout.SOUTH);
chatPanel.add(displayPanel, BorderLayout.CENTER);
final JSplitPane mainSplit = new JSplitPane(
JSplitPane.HORIZONTAL_SPLIT, mapPanel, chatPanel);
final JSplitPane topSplit = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
roomEntityList, groupList);
mainSplit.setResizeWeight(0.3);
topSplit.setResizeWeight(0.5);
JPanel topPanel = new JPanel();
topPanel.setLayout(new BorderLayout());
topPanel.add(roomImagePanel, BorderLayout.WEST);
topPanel.add(topSplit, BorderLayout.CENTER);
mainFrame.add(mainSplit, BorderLayout.CENTER);
mainFrame.add(topPanel, BorderLayout.NORTH);
JLabel commandListLabel = new JLabel("=== Recent commands ===");
commandListLabel.setBackground(Color.black);
commandListLabel.setForeground(Color.white);
commandListLabel.setOpaque(true);
Font font = commandListLabel.getFont();
font = font.deriveFont(Font.BOLD, 12.0f);
commandListLabel.setFont(font);
commandListLabel.setHorizontalAlignment(SwingConstants.CENTER);
JScrollPane commandScroll = new JScrollPane(commandList);
commandScroll.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
commandScroll.setPreferredSize(new Dimension(1, 80));
commandScroll.setAutoscrolls(true);
JPanel commandListPanel = new JPanel(new BorderLayout());
commandListPanel.add(commandListLabel, BorderLayout.NORTH);
commandListPanel.add(commandScroll, BorderLayout.CENTER);
mapPanel.add(roomLabel, BorderLayout.NORTH);
mapPanel.add(mapScroll, BorderLayout.CENTER);
mapPanel.add(commandListPanel, BorderLayout.SOUTH);
chatField.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
char[] password = chatField.getPassword();
String cmd = String.valueOf(password);
if (passwordMode) {
historyListModel.add("( password )");
chatField.setText("");
} else {
chatField.setSelectionStart(0);
chatField.setSelectionEnd(cmd.length());
historyListModel.add(cmd);
}
sendCommand(cmd);
}
});
chatField.addKeyListener(new KeyAdapter() {
private int location = KeyEvent.KEY_LOCATION_UNKNOWN;
@Override
public void keyTyped(KeyEvent e) {
if (passwordMode) {
return;
}
if (location != KeyEvent.KEY_LOCATION_NUMPAD) {
return;
}
if (!getLoginComplete()) {
return;
}
e.consume();
String cmd = null;
switch (e.getKeyChar()) {
case '1':
cmd = "southwest";
break;
case '2':
cmd = "south";
break;
case '3':
cmd = "southeast";
break;
case '4':
cmd = "west";
break;
case '5':
cmd = "look";
map.centerCurrentRoom();
break;
case '6':
cmd = "east";
break;
case '7':
cmd = "northwest";
break;
case '8':
cmd = "north";
break;
case '9':
cmd = "northeast";
break;
default:
map.centerCurrentRoom();
}
if (cmd != null) {
historyListModel.add(cmd);
sendCommand(cmd);
}
}
@Override
public void keyPressed(KeyEvent e) {
if (passwordMode) {
return;
}
location = e.getKeyLocation();
if (e.getKeyCode() == KeyEvent.VK_UP || e.getKeyCode() == KeyEvent.VK_DOWN) {
String s = historyListModel.handleScroll(e.getKeyCode() == KeyEvent.VK_UP, String.valueOf(chatField.getPassword()));
chatField.setText(s);
chatField.setSelectionStart(0);
chatField.setSelectionEnd(s.length());
}
}
});
displayPanel.setOnText(new Runnable() {
public void run() {
if ((mainFrame.getExtendedState() & Frame.ICONIFIED) != 0) {
if (restoreItem.isSelected()) {
mainFrame.setExtendedState(mainFrame.getExtendedState()
& ~Frame.ICONIFIED);
}
else {
mainFrame.toFront();
}
}
}
});
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainFrame.setVisible(true);
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
mainFrame.setExtendedState(Frame.MAXIMIZED_BOTH);
mainSplit.setDividerLocation(0.3);
topSplit.setDividerLocation(0.5);
chatField.requestFocusInWindow();
}
});
}
private static class WriterThread extends Thread {
private final DataOutputStream out;
public WriterThread(DataOutputStream out) {
this.out = out;
}
@Override
public void run() {
try {
long nextKeepAlive = 0;
long timeout;
while (true) {
ArrayList<ClientEvent> localQueue;
synchronized (writeQueueLock) {
while (true) {
timeout = nextKeepAlive
- System.currentTimeMillis();
if (timeout <= 0 || writeQueue.size() > 0) {
break;
}
writeQueueLock.wait(timeout);
}
localQueue = writeQueue;
writeQueue = new ArrayList<ClientEvent>();
}
if (timeout <= 0) {
nextKeepAlive = System.currentTimeMillis() + 15000;
synchronized (GameClient.class) {
if (loginComplete) {
localQueue.add(new CommandClientEvent(
"keepalive"));
}
}
}
for (ClientEvent evt : localQueue) {
byte[] b = evt.toByteArray();
b = encipher.doFinal(b);
out.writeInt(b.length);
out.write(b);
}
out.flush();
}
} catch (Throwable t) {
t.printStackTrace();
} finally {
System.exit(-1);
}
}
}
public static GameMap getMap() {
return map;
}
public static void setRoomName(String name) {
roomLabel.setText(name);
}
public static void send(ClientEvent evt) {
synchronized (writeQueueLock) {
writeQueue.add(evt);
writeQueueLock.notifyAll();
}
}
private static String getStackTrace(Throwable t) {
StringWriter sw = new StringWriter();
t.printStackTrace(new PrintWriter(sw, true));
return sw.toString();
}
public static void setPasswordMode(boolean newPasswordMode) {
if (passwordMode == newPasswordMode) {
return; }
passwordMode = newPasswordMode;
if (chatField.getSelectedText() != null || !newPasswordMode) {
chatField.setText("");
}
chatField.setEchoChar(passwordMode ? '*' : 0);
}
public static synchronized void setLoginComplete(boolean loginComplete) {
GameClient.loginComplete = loginComplete;
if (!loginComplete) {
getMap().init(null, 0, 0, 0, 0, new HashMap<Point,PubRoom>());
setRoomImage(null);
roomEntityList.clear();
groupList.clear();
}
}
public static synchronized boolean getLoginComplete() {
return loginComplete;
}
private static void sendCommand(String command) {
send(new CommandClientEvent(command));
}
public static void track(int player, Point p) {
map.track(player, p);
}
public static void launchFaceChooser(Face face) {
JFrame f = new FaceChooser(face);
f.setVisible(true);
}
public static void launchScriptingConsole(ScriptType type, String filename, String text) {
ConsoleWindow f = new ConsoleWindow(nextConsoleId++, type, filename, text);
consoles.add(new WeakReference<ConsoleWindow>(f));
f.setVisible(true);
}
public static void launchRoomEditor(final PubRoom room, String description, String uploadPrefix, String image, boolean isAdmin) {
RoomEditor editor = new RoomEditor(room, description, uploadPrefix, image, isAdmin);
editor.setVisible(true);
}
public static void launchTextEditor(TextEditorType type, int id, String text) {
TextEditor editor = new TextEditor(type, id, text);
editor.setVisible(true);
}
public static void setRoomImage(String filename) {
final Timer timer = new Timer(500, new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (roomImageLoadCount > 0) {
loadingBar.setIndeterminate(true);
imageOverlayPanel.setVisible(true);
}
}
});
timer.setRepeats(false);
timer.start();
roomImageLoadCount++;
ClientUtils.setImage(roomImageLabel, filename, new Runnable() {
public void run() {
if (--roomImageLoadCount == 0) {
imageOverlayPanel.setVisible(false);
loadingBar.setIndeterminate(false);
}
timer.stop();
}
});
}
public static void setCommandLineColor(Color foreground, Color background) {
chatField.setForeground(foreground);
chatField.setBackground(background);
}
private static JMenuBar makeMenuBar() {
JMenuBar menubar = new JMenuBar();
JMenu fileMenu = new JMenu("File");
fileMenu.setMnemonic(KeyEvent.VK_F);
JMenu settingsMenu = new JMenu("Settings");
settingsMenu.setMnemonic(KeyEvent.VK_S);
JMenu helpMenu = new JMenu("Help");
helpMenu.setMnemonic(KeyEvent.VK_H);
JMenuItem exitItem = new JMenuItem("Exit");
exitItem.setMnemonic(KeyEvent.VK_X);
fileMenu.add(exitItem);
restoreItem = new JCheckBoxMenuItem("Automatically unminimize on game output", true);
restoreItem.setMnemonic(KeyEvent.VK_U);
settingsMenu.add(restoreItem);
JMenuItem aboutItem = new JMenuItem("About...");
aboutItem.setMnemonic(KeyEvent.VK_A);
helpMenu.add(aboutItem);
menubar.add(fileMenu);
menubar.add(settingsMenu);
menubar.add(helpMenu);
exitItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
});
restoreItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (restoreItem.isSelected()) {
println("Auto-unminimize is now ON.");
}
else {
println("Auto-unminimize is now OFF.");
}
}
});
aboutItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
showAboutBox();
}
});
return menubar;
}
private static void showAboutBox() {
final JDialog aboutBox = new JDialog(mainFrame, "About", false);
JPanel mainPanel = new JPanel();
JLabel[] lines = new JLabel[] {
new JLabel("Aelfengard"),
new JLabel("Game Design and Crash-Free Code by Thedia"),
new JLabel("Game Design and World-Class Artwork by Tho"),
new JLabel("Game Design by Nisal"),
};
lines[0].setFont(lines[0].getFont().deriveFont(20.0f));
mainPanel.setLayout(new GridLayout(lines.length, 1));
for (JLabel line : lines) {
line.setHorizontalAlignment(SwingConstants.CENTER);
mainPanel.add(line);
}
final JButton okButton = new JButton("Ok");
JPanel buttonPanel = new JPanel();
buttonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT, 5, 5));
buttonPanel.add(okButton);
aboutBox.add(mainPanel, BorderLayout.CENTER);
aboutBox.add(buttonPanel, BorderLayout.SOUTH);
okButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
aboutBox.dispose();
}
});
Border border = new EmptyBorder(10, 10, 10, 10);
border = new CompoundBorder(border, new BevelBorder(BevelBorder.LOWERED));
border = new CompoundBorder(border, new EmptyBorder(10, 30, 10, 30));
mainPanel.setBorder(border);
aboutBox.pack();
aboutBox.setLocationByPlatform(true);
aboutBox.setVisible(true);
}
public static void statUpdate(TableType tableType, int id, StatType statType, int current, int max) {
switch (tableType) {
case ROOM_ENTITY_TABLE: {
roomEntityList.statUpdate(id, statType, current, max);
break;
}
case GROUP_MEMBER_TABLE: {
groupList.statUpdate(id, statType, current, max);
break;
}
default: throw new RuntimeException("Unrecognized table type: " + tableType);
}
}
public static String getBaseURL() {
return currentBaseURL;
}
public static void setCurrentServerInfo(String hostname, String rcSubdir, String gameMode) {
currentBaseURL = null;
try {
currentBaseURL = System.getProperty("aelfengard.baseURL");
}
catch (Exception ex) {
}
if (currentBaseURL == null) {
currentBaseURL = "http://" + hostname + "/" + rcSubdir;
}
if (gameMode == null) {
if (currentGameMode == null) {
return; }
gameModeLabel.setBorder(null);
gameModeLabel.setText("");
mainFrame.setTitle(DEFAULT_WINDOW_TITLE);
}
else {
if (gameMode.equals(currentGameMode)) {
return; }
gameModeLabel.setBorder(new EmptyBorder(0, 5, 0, 5));
if (extraModeInfo != null) {
gameMode = extraModeInfo + " " + gameMode;
}
gameModeLabel.setText(gameMode);
mainFrame.setTitle("AG - " + gameMode);
}
currentGameMode = gameMode;
}
public static void setExtraModeInfo(String extraModeInfo) {
GameClient.extraModeInfo = extraModeInfo;
}
public static EntityList<PubGroupMember> getGroupList() {
return groupList;
}
public static EntityList<PubRoomEntity> getRoomEntityList() {
return roomEntityList;
}
public static void println(String s) {
displayPanel.println(s);
}
public static void clear() {
displayPanel.clear();
}
public static void sendFace(Face face, String... text) {
displayPanel.sendFace(face, text);
}
public static void executeManualScript(int consoleId, ScriptType scriptType, String cmd) {
send(new ExecuteManualScriptClientEvent(consoleId, scriptType, cmd));
}
public static void saveScript(int consoleId, ScriptType type, String filename, String script) {
send(new SaveScriptClientEvent(consoleId, type, filename, script));
}
public static void sendImage(String filename, String... text) {
displayPanel.sendImage(filename, text);
}
public static void printTable(String[][] data, String[] headers, int[] sizes) {
displayPanel.printTable(data, headers, sizes);
}
private static void negotiateEncryption(DataInput in, DataOutput out) throws Exception {
displayPanel.print("Negotiating encryption key...");
KeyPairGenerator kpg = KeyPairGenerator.getInstance("DH");
kpg.initialize(1024);
KeyPair kp = kpg.generateKeyPair();
byte[] keyMaterial = kp.getPublic().getEncoded();
out.writeInt(keyMaterial.length);
out.write(keyMaterial);
keyMaterial = new byte[in.readInt()];
in.readFully(keyMaterial);
KeyFactory kf = KeyFactory.getInstance("DH");
PublicKey serverKey = kf.generatePublic(new X509EncodedKeySpec(keyMaterial));
KeyAgreement dh = KeyAgreement.getInstance("DH");
dh.init(kp.getPrivate());
dh.doPhase(serverKey, true);
SecretKey sharedSecret = dh.generateSecret("DESede");
encipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
encipher.init(Cipher.ENCRYPT_MODE, sharedSecret);
byte[] iv = encipher.getIV();
out.writeInt(iv.length);
out.write(iv);
iv = new byte[in.readInt()];
in.readFully(iv);
decipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
decipher.init(Cipher.DECRYPT_MODE, sharedSecret, new IvParameterSpec(iv));
println(" @2ZZDone!");
}
private static class HistoryListModel extends AbstractListModel {
private static final long serialVersionUID = 3976735852623638577L;
private static String[] history = new String[100];
private static int historyIdx = 0;
private static int historyPtr = 0;
private static int historyMax = 0;
public HistoryListModel() {
history[0] = "";
}
public int getSize() {
return historyMax + 1;
}
public Object getElementAt(int index) {
return history[(historyIdx - historyMax + index + history.length) % history.length];
}
public void add(String cmd) {
if (true) {
history[historyIdx++] = cmd;
historyIdx %= history.length;
history[historyIdx] = "";
if (historyMax < history.length - 1) {
historyMax++;
fireIntervalAdded(this, historyMax, historyMax);
}
else {
fireIntervalAdded(this, historyMax, historyMax);
fireIntervalRemoved(this, 0, 0);
}
commandList.ensureIndexIsVisible(historyMax - 1);
commandList.setSelectedIndex(historyMax - 1);
}
historyPtr = historyMax == 0 ? 0 : 1;
}
public String handleScroll(boolean isUp, String currentCmd) {
if (!String.valueOf(chatField.getPassword()).equals(
history[(history.length + historyIdx - historyPtr)
% history.length])) {
historyPtr = 0;
}
if (isUp) {
if (historyPtr < historyMax) {
historyPtr++;
}
}
else {
if (historyPtr > 0) {
historyPtr--;
}
}
return history[(history.length + historyIdx - historyPtr)
% history.length];
}
}
public static void printTextToScriptingConsole(int consoleId, String text) {
ConsoleWindow window = getConsoleWindow(consoleId);
if (window != null) {
window.write(text);
}
}
public static void consoleSaveResponse(int consoleId, boolean error, String msg) {
ConsoleWindow window = getConsoleWindow(consoleId);
if (window != null) {
window.saveResponse(error, msg);
}
}
public static ImageIcon getImageIcon(String path) {
try {
String baseURL = getBaseURL().replaceAll(":|/", "_");
File finalF = new File(".aelfengard-cache/" + baseURL + "/" + path);
if (!finalF.exists()) {
synchronized(imageCacheLock) {
File f = new File(".aelfengard-cache/" + baseURL + "/" + path + ".new");
byte[] buf = new byte[16384];
URL url = new URL(getBaseURL() + "/" + path);
f.getParentFile().mkdirs();
FileOutputStream out = new FileOutputStream(f);
URLConnection conn = url.openConnection();
InputStream in = conn.getInputStream();
while (true) {
int count = in.read(buf);
if (count < 0) {
break; }
out.write(buf, 0, count);
}
out.flush();
out.close();
f.renameTo(finalF);
}
}
return new ImageIcon(finalF.getAbsolutePath());
}
catch (Exception ex) {
try {
return new ImageIcon(new URL(getBaseURL() + "/" + path));
}
catch (MalformedURLException muex) {
muex.printStackTrace();
return new ImageIcon();
}
}
}
private static ConsoleWindow getConsoleWindow(int consoleId) {
Iterator<WeakReference<ConsoleWindow>> iter = consoles.iterator();
while (iter.hasNext()) {
WeakReference<ConsoleWindow> ref = iter.next();
ConsoleWindow window = ref.get();
if (window == null) {
iter.remove();
}
else if (window.getConsoleId() == consoleId) {
return window;
}
}
return null;
}
public static void doImageUpload(int npcId) {
try {
InputStream in;
String filename;
try {
FileOpenService service = (FileOpenService)
ServiceManager.lookup("javax.jnlp.FileOpenService");
FileContents contents =
service.openFileDialog(null, new String[] {"gif", "jpg", "png"});
if (contents == null) {
return;
}
in = contents.getInputStream();
filename = contents.getName();
} catch (UnavailableServiceException ex) {
JFileChooser chooser = new JFileChooser();
chooser.setFileFilter(new FileFilter() {
@Override
public String getDescription() {
return "Image Files";
}
@Override
public boolean accept(File f) {
return f.isDirectory() ||
f.getName().matches(".*\\.jpg$|.*\\.gif$|.*\\.png$");
}
});
if (chooser.showOpenDialog(mainFrame) != JFileChooser.APPROVE_OPTION) {
return;
}
File f = chooser.getSelectedFile();
if (f.length() > 256 * 1024) {
JOptionPane.showMessageDialog(mainFrame, "Sorry, that file is too large.", "Max Size Exceeded", JOptionPane.ERROR_MESSAGE);
return;
}
in = new FileInputStream(f);
filename = f.getName();
}
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buf = new byte[16384];
while (true) {
int count = in.read(buf);
if (count < 0) {
break; }
baos.write(buf, 0, count);
}
byte[] uploadData = baos.toByteArray();
send(new ImageUploadClientEvent(npcId, filename, uploadData));
}
catch (IOException ex) {
ex.printStackTrace();
JOptionPane.showMessageDialog(mainFrame, ex.toString(), "I/O Error", JOptionPane.ERROR_MESSAGE);
}
}
}