/* * This file is part of the Haven & Hearth game client. * Copyright (C) 2009 Fredrik Tolf <fredrik@dolda2000.com>, and * Björn Johannessen <johannessen.bjorn@gmail.com> * * Redistribution and/or modification of this file is subject to the * terms of the GNU Lesser General Public License, version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * Other parts of this source tree adhere to other copying * rights. Please see the file `COPYING' in the root directory of the * source tree for details. * * A copy the GNU Lesser General Public License is distributed along * with the source tree of which this file is a part in the file * `doc/LPGL-3'. If it is missing for any reason, please see the Free * Software Foundation's website at <http://www.fsf.org/>, or write * to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, * Boston, MA 02111-1307 USA */ package haven; import java.awt.Color; import java.awt.Graphics; import java.awt.RenderingHints; import java.awt.Toolkit; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.OutputStream; import java.io.PrintWriter; import java.io.UnsupportedEncodingException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.LinkedList; import java.util.Queue; import java.util.prefs.Preferences; public class Utils { private static Preferences prefs = null; public static java.awt.image.ColorModel rgbm = java.awt.image.ColorModel.getRGBdefault(); private static Background bgworker = null; public static Coord imgsz(BufferedImage img) { return(new Coord(img.getWidth(), img.getHeight())); } public static class Background extends HackThread { Queue<Runnable> q = new LinkedList<Runnable>(); public Background() { super("Haven deferred procedure thread"); setDaemon(true); start(); } public void run() { try { while(true) { Runnable cur; synchronized(q) { while((cur = q.poll()) == null) q.wait(); } cur.run(); cur = null; } } catch(InterruptedException e) {} } public void defer(Runnable r) { synchronized(q) { q.add(r); q.notify(); } } } public static String sessdate(long sess) { return (new SimpleDateFormat("yyyy-MM-dd HH.mm.ss")).format(new Date(sess)); } public static String timestamp() { return (new SimpleDateFormat("[HH:mm] ")).format(new Date()); } public static String getClipboard() { Transferable t = Toolkit.getDefaultToolkit().getSystemClipboard().getContents(null); try { if (t != null && t.isDataFlavorSupported(DataFlavor.stringFlavor)) { String text = (String)t.getTransferData(DataFlavor.stringFlavor); return text; } } catch (UnsupportedFlavorException e) { } catch (IOException e) { } return ""; } public static void defer(Runnable r) { synchronized(Utils.class) { if(bgworker == null) bgworker = new Background(); } bgworker.defer(r); } static void drawgay(BufferedImage t, BufferedImage img, Coord c) { Coord sz = imgsz(img); for(int y = 0; y < sz.y; y++) { for(int x = 0; x < sz.x; x++) { int p = img.getRGB(x, y); if(Utils.rgbm.getAlpha(p) > 128) { if((p & 0x00ffffff) == 0x00ff0080) t.setRGB(x + c.x, y + c.y, 0); else t.setRGB(x + c.x, y + c.y, p); } } } } public static int drawtext(Graphics g, String text, Coord c) { java.awt.FontMetrics m = g.getFontMetrics(); g.drawString(text, c.x, c.y + m.getAscent()); return(m.getHeight()); } static Coord textsz(Graphics g, String text) { java.awt.FontMetrics m = g.getFontMetrics(); java.awt.geom.Rectangle2D ts = m.getStringBounds(text, g); return(new Coord((int)ts.getWidth(), (int)ts.getHeight())); } static void aligntext(Graphics g, String text, Coord c, double ax, double ay) { java.awt.FontMetrics m = g.getFontMetrics(); java.awt.geom.Rectangle2D ts = m.getStringBounds(text, g); g.drawString(text, (int)(c.x - ts.getWidth() * ax), (int)(c.y + m.getAscent() - ts.getHeight() * ay)); } static void line(Graphics g, Coord c1, Coord c2) { g.drawLine(c1.x, c1.y, c2.x, c2.y); } static void AA(Graphics g) { java.awt.Graphics2D g2 = (java.awt.Graphics2D)g; g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); } static synchronized String getpref(String prefname, String def) { try { if(prefs == null) prefs = Preferences.userNodeForPackage(Utils.class); return(prefs.get(prefname, def)); } catch(SecurityException e) { return(def); } } static synchronized void setpref(String prefname, String val) { try { if(prefs == null) prefs = Preferences.userNodeForPackage(Utils.class); prefs.put(prefname, val); } catch(SecurityException e) { } } static synchronized byte[] getprefb(String prefname, byte[] def) { try { if(prefs == null) prefs = Preferences.userNodeForPackage(Utils.class); return(prefs.getByteArray(prefname, def)); } catch(SecurityException e) { return(def); } } static synchronized void setprefb(String prefname, byte[] val) { try { if(prefs == null) prefs = Preferences.userNodeForPackage(Utils.class); prefs.putByteArray(prefname, val); } catch(SecurityException e) { } } public static String getprop(String propname, String def) { try { return(System.getProperty(propname, def)); } catch(SecurityException e) { return(def); } } static int ub(byte b) { if(b < 0) return(256 + b); else return(b); } static byte sb(int b) { if(b > 127) return((byte)(-256 + b)); else return((byte)b); } static int uint16d(byte[] buf, int off) { return(ub(buf[off]) + (ub(buf[off + 1]) * 256)); } static int int16d(byte[] buf, int off) { int u = uint16d(buf, off); if(u > 32767) return(-65536 + u); else return(u); } static long uint32d(byte[] buf, int off) { return(ub(buf[off]) + (ub(buf[off + 1]) * 256) + (ub(buf[off + 2]) * 65536) + (ub(buf[off + 3]) * 16777216)); } static void uint32e(long num, byte[] buf, int off) { buf[off] = sb((int)(num & 0xff)); buf[off + 1] = sb((int)((num & 0xff00) >> 8)); buf[off + 2] = sb((int)((num & 0xff0000) >> 16)); buf[off + 3] = sb((int)((num & 0xff000000) >> 24)); } static int int32d(byte[] buf, int off) { long u = uint32d(buf, off); if(u > Integer.MAX_VALUE) return((int)((((long)Integer.MIN_VALUE) * 2) - u)); else return((int)u); } static void int32e(int num, byte[] buf, int off) { if(num < 0) uint32e(0x100000000L + ((long)num), buf, off); else uint32e(num, buf, off); } static void uint16e(int num, byte[] buf, int off) { buf[off] = sb(num & 0xff); buf[off + 1] = sb((num & 0xff00) >> 8); } static String strd(byte[] buf, int[] off) { int i; for(i = off[0]; buf[i] != 0; i++); String ret; try { ret = new String(buf, off[0], i - off[0], "utf-8"); } catch(UnsupportedEncodingException e) { throw(new IllegalArgumentException(e)); } off[0] = i + 1; return(ret); } static char num2hex(int num) { if(num < 10) return((char)('0' + num)); else return((char)('A' + num - 10)); } static int hex2num(char hex) { if((hex >= '0') && (hex <= '9')) return(hex - '0'); else if((hex >= 'a') && (hex <= 'f')) return(hex - 'a' + 10); else if((hex >= 'A') && (hex <= 'F')) return(hex - 'A' + 10); else throw(new IllegalArgumentException()); } static String byte2hex(byte[] in) { StringBuilder buf = new StringBuilder(); for(byte b : in) { buf.append(num2hex((b & 0xf0) >> 4)); buf.append(num2hex(b & 0x0f)); } return(buf.toString()); } static byte[] hex2byte(String hex) { if(hex.length() % 2 != 0) throw(new IllegalArgumentException("Invalid hex-encoded string")); byte[] ret = new byte[hex.length() / 2]; for(int i = 0, o = 0; i < hex.length(); i += 2, o++) ret[o] = (byte)((hex2num(hex.charAt(i)) << 4) | hex2num(hex.charAt(i + 1))); return(ret); } public static String[] splitwords(String text) { ArrayList<String> words = new ArrayList<String>(); StringBuilder buf = new StringBuilder(); String st = "ws"; int i = 0; while(i < text.length()) { char c = text.charAt(i); if(st == "ws") { if(!Character.isWhitespace(c)) st = "word"; else i++; } else if(st == "word") { if(c == '"') { st = "quote"; i++; } else if(c == '\\') { st = "squote"; i++; } else if(Character.isWhitespace(c)) { words.add(buf.toString()); buf = new StringBuilder(); st = "ws"; } else { buf.append(c); i++; } } else if(st == "quote") { if(c == '"') { st = "word"; i++; } else if(c == '\\') { st = "sqquote"; i++; } else { buf.append(c); i++; } } else if(st == "squote") { buf.append(c); i++; st = "word"; } else if(st == "sqquote") { buf.append(c); i++; st = "quote"; } } if(st == "word") words.add(buf.toString()); if((st != "ws") && (st != "word")) return(null); return(words.toArray(new String[0])); } public static String[] splitlines(String text) { ArrayList<String> ret = new ArrayList<String>(); int p = 0; while(true) { int p2 = text.indexOf('\n', p); if(p2 < 0) { ret.add(text.substring(p)); break; } ret.add(text.substring(p, p2)); p = p2 + 1; } return(ret.toArray(new String[0])); } static int atoi(String a) { try { return(Integer.parseInt(a)); } catch(NumberFormatException e) { return(0); } } static void readtileof(InputStream in) throws IOException { byte[] buf = new byte[4096]; while(true) { if(in.read(buf, 0, buf.length) < 0) return; } } static byte[] readall(InputStream in) throws IOException { byte[] buf = new byte[4096]; int off = 0; while(true) { if(off == buf.length) { byte[] n = new byte[buf.length * 2]; System.arraycopy(buf, 0, n, 0, buf.length); buf = n; } int ret = in.read(buf, off, buf.length - off); if(ret < 0) { byte[] n = new byte[off]; System.arraycopy(buf, 0, n, 0, off); return(n); } off += ret; } } private static void dumptg(ThreadGroup tg, PrintWriter out, int indent) { for(int o = 0; o < indent; o++) out.print("\t"); out.println("G: \"" + tg.getName() + "\""); Thread[] ths = new Thread[tg.activeCount() * 2]; ThreadGroup[] tgs = new ThreadGroup[tg.activeGroupCount() * 2]; int nt = tg.enumerate(ths, false); int ng = tg.enumerate(tgs, false); for(int i = 0; i < nt; i++) { Thread ct = ths[i]; for(int o = 0; o < indent + 1; o++) out.print("\t"); out.println("T: \"" + ct.getName() + "\""); } for(int i = 0; i < ng; i++) { ThreadGroup cg = tgs[i]; dumptg(cg, out, indent + 1); } } public static void dumptg(ThreadGroup tg, PrintWriter out) { if(tg == null) { tg = Thread.currentThread().getThreadGroup(); while(tg.getParent() != null) tg = tg.getParent(); } dumptg(tg, out, 0); out.flush(); } public static Resource myres(Class<?> c) { ClassLoader cl = c.getClassLoader(); if(cl instanceof Resource.ResClassLoader) { return(((Resource.ResClassLoader)cl).getres()); } else { return(null); } } public static String titlecase(String str) { return(Character.toTitleCase(str.charAt(0)) + str.substring(1)); } public static Color contrast(Color col) { int max = Math.max(col.getRed(), Math.max(col.getGreen(), col.getBlue())); if(max > 128) { return(new Color(col.getRed() / 4, col.getGreen() / 4, col.getBlue() / 4, col.getAlpha())); } else if(max == 0) { return(Color.WHITE); } else { int f = 128 / max; return(new Color(col.getRed() * f, col.getGreen() * f, col.getBlue() * f, col.getAlpha())); } } public static Color clipcol(int r, int g, int b, int a) { if(r < 0) r = 0; if(r > 255) r = 255; if(g < 0) g = 0; if(g > 255) g = 255; if(b < 0) b = 0; if(b > 255) b = 255; if(a < 0) a = 0; if(a > 255) a = 255; return(new Color(r, g, b, a)); } public static BufferedImage outline(BufferedImage img, Color col) { return outline(img, col, false); } public static BufferedImage outline(BufferedImage img, Color col, boolean thick) { Coord sz = imgsz(img).add(2, 2); BufferedImage ol = TexI.mkbuf(sz); for(int y = 0; y < sz.y; y++) { for(int x = 0; x < sz.x; x++) { boolean t; if((y == 0) || (x == 0) || (y == sz.y - 1) || (x == sz.x - 1)) { t = true; } else { int cl = img.getRGB(x - 1, y - 1); t = Utils.rgbm.getAlpha(cl) < 250; } if(!t) continue; if(((x > 1) && (y > 0) && (y < sz.y - 1) && (Utils.rgbm.getAlpha(img.getRGB(x - 2, y - 1)) >= 250)) || ((x > 0) && (y > 1) && (x < sz.x - 1) && (Utils.rgbm.getAlpha(img.getRGB(x - 1, y - 2)) >= 250)) || ((x < sz.x - 2) && (y > 0) && (y < sz.y - 1) && (Utils.rgbm.getAlpha(img.getRGB(x, y - 1)) >= 250)) || ((x > 0) && (y < sz.y - 2) && (x < sz.x - 1) && (Utils.rgbm.getAlpha(img.getRGB(x - 1, y)) >= 250))) ol.setRGB(x, y, col.getRGB()); if(thick){ if(((x > 1) && (y > 1) && (Utils.rgbm.getAlpha(img.getRGB(x - 2, y - 2)) >= 250)) || ((x < sz.x - 2) && (y < sz.y - 2) && (Utils.rgbm.getAlpha(img.getRGB(x, y)) >= 250)) || ((x < sz.x - 2) && (y > 1) && (Utils.rgbm.getAlpha(img.getRGB(x, y - 2)) >= 250)) || ((x > 1) && (y < sz.y - 2) && (Utils.rgbm.getAlpha(img.getRGB(x - 2, y)) >= 250))) ol.setRGB(x, y, col.getRGB()); } } } return(ol); } public static BufferedImage outline2(BufferedImage img, Color col) { return outline2(img, col, false); } public static BufferedImage outline2(BufferedImage img, Color col, boolean thick) { BufferedImage ol = outline(img, col, thick); Graphics g = ol.getGraphics(); g.drawImage(img, 1, 1, null); g.dispose(); return(ol); } public static int floordiv(int a, int b) { if(a < 0) return(((a + 1) / b) - 1); else return(a / b); } public static int floormod(int a, int b) { int r = a % b; if(r < 0) r += b; return(r); } public static int floordiv(float a, float b) { return((int)Math.floor(a / b)); } public static float floormod(float a, float b) { float r = a % b; if(r < 0) r += b; return(r); } public static double clip(double d, double min, double max) { if(d < min) return(min); if(d > max) return(max); return(d); } public static int clip(int i, int min, int max) { if(i < min) return(min); if(i > max) return(max); return(i); } public static Color blendcol(Color in, Color bl) { int f1 = bl.getAlpha(); int f2 = 255 - bl.getAlpha(); return(new Color(((in.getRed() * f2) + (bl.getRed() * f1)) / 255, ((in.getGreen() * f2) + (bl.getGreen() * f1)) / 255, ((in.getBlue() * f2) + (bl.getBlue() * f1)) / 255, in.getAlpha())); } public static void serialize(Object obj, OutputStream out) throws IOException { ObjectOutputStream oout = new ObjectOutputStream(out); oout.writeObject(obj); oout.flush(); } public static byte[] serialize(Object obj) { ByteArrayOutputStream out = new ByteArrayOutputStream(); try { serialize(obj, out); } catch(IOException e) { throw(new RuntimeException(e)); } return(out.toByteArray()); } public static Object deserialize(InputStream in) throws IOException { ObjectInputStream oin = new ObjectInputStream(in); try { return(oin.readObject()); } catch(ClassNotFoundException e) { return(null); } } public static Object deserialize(byte[] buf) { if(buf == null) return(null); InputStream in = new ByteArrayInputStream(buf); try { return(deserialize(in)); } catch(IOException e) { return(null); } } public static boolean parsebool(String s, boolean def) { if(s == null) return(def); else if(s.equalsIgnoreCase("1") || s.equalsIgnoreCase("on") || s.equalsIgnoreCase("true") || s.equalsIgnoreCase("yes")) return(true); else if(s.equalsIgnoreCase("0") || s.equalsIgnoreCase("off") || s.equalsIgnoreCase("false") || s.equalsIgnoreCase("no")) return(false); return(def); } static { Console.setscmd("die", new Console.Command() { public void run(Console cons, String[] args) { throw(new Error("Triggered death")); } }); Console.setscmd("threads", new Console.Command() { public void run(Console cons, String[] args) { Utils.dumptg(null, cons.out); } }); } }