/* * 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.RenderingHints; import java.io.*; import java.nio.*; import java.net.URL; import java.text.SimpleDateFormat; import java.lang.reflect.*; import java.util.prefs.*; import java.util.*; import java.awt.Graphics; import java.awt.Color; 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.awt.image.*; public class Utils { private static final SimpleDateFormat datef = new SimpleDateFormat("yyyy-MM-dd HH.mm.ss"); public static final java.nio.charset.Charset utf8 = java.nio.charset.Charset.forName("UTF-8"); public static final java.nio.charset.Charset ascii = java.nio.charset.Charset.forName("US-ASCII"); public static final java.awt.image.ColorModel rgbm = java.awt.image.ColorModel.getRGBdefault(); private static Preferences prefs = null; static Coord imgsz(BufferedImage img) { return(new Coord(img.getWidth(), img.getHeight())); } public static void defer(final Runnable r) { Defer.later(new Defer.Callable<Object>() { public Object call() { r.run(); return(null); } }); } 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)); } public static String datef(long time){ return datef.format(new Date(time)); } public static String current_date(){ return datef(System.currentTimeMillis()); } public static String fpformat(int num, int div, int dec) { StringBuilder buf = new StringBuilder(); boolean s = false; if(num < 0) { num = -num; s = true; } for(int i = 0; i < div - dec; i++) num /= 10; for(int i = 0; i < dec; i++) { buf.append((char)('0' + (num % 10))); num /= 10; } buf.append('.'); if(num == 0) { buf.append('0'); } else { while(num > 0) { buf.append((char)('0' + (num % 10))); num /= 10; } } if(s) buf.append('-'); return(buf.reverse().toString()); } 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); } 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 ""; } static synchronized Preferences prefs() { if(prefs == null) { Preferences node = Preferences.userNodeForPackage(Utils.class); if(Config.prefspec != null) node = node.node(Config.prefspec); prefs = node; } return(prefs); } static String getpref(String prefname, String def) { try { return(prefs().get(prefname, def)); } catch(SecurityException e) { return(def); } } static void setpref(String prefname, String val) { try { prefs().put(prefname, val); } catch(SecurityException e) { } } static boolean getprefb(String prefname, boolean def) { try { return(prefs().getBoolean(prefname, def)); } catch(SecurityException e) { return(def); } } static void setprefb(String prefname, boolean val) { try { prefs().putBoolean(prefname, val); } catch(SecurityException e) { } } static void setpreff(String prefname, float val) { try { prefs().putFloat(prefname, val); } catch(SecurityException e) { } } static Coord getprefc(String prefname, Coord def) { try { String val = prefs().get(prefname, null); if(val == null) return(def); int x = val.indexOf('x'); if(x < 0) return(def); return(new Coord(Integer.parseInt(val.substring(0, x)), Integer.parseInt(val.substring(x + 1)))); } catch(SecurityException e) { return(def); } } static void setprefc(String prefname, Coord val) { try { prefs().put(prefname, val.x + "x" + val.y); } catch(SecurityException e) { } } static byte[] getprefb(String prefname, byte[] def) { try { return(prefs().getByteArray(prefname, def)); } catch(SecurityException e) { return(def); } } static void setprefb(String prefname, byte[] val) { try { prefs().putByteArray(prefname, val); } catch(SecurityException e) { } } static float getpreff(String prefname, float def) { try { return(prefs().getFloat(prefname, def)); } catch(SecurityException e) { return(def); } } public static String getprop(String propname, String def) { try { String ret; if((ret = System.getProperty(propname)) != null) return(ret); if((ret = System.getProperty("jnlp." + propname)) != null) return(ret); return(def); } catch(SecurityException e) { return(def); } } public static int ub(byte b) { return(((int)b) & 0xff); } public static byte sb(int b) { return((byte)b); } public static int uint16d(byte[] buf, int off) { return(ub(buf[off]) | (ub(buf[off + 1]) << 8)); } public static int int16d(byte[] buf, int off) { return((int)(short)uint16d(buf, off)); } public static long uint32d(byte[] buf, int off) { return((long)ub(buf[off]) | ((long)ub(buf[off + 1]) << 8) | ((long)ub(buf[off + 2]) << 16) | ((long)ub(buf[off + 3]) << 24)); } public static void uint32e(long num, byte[] buf, int off) { buf[off] = (byte)(num & 0xff); buf[off + 1] = (byte)((num & 0x0000ff00) >> 8); buf[off + 2] = (byte)((num & 0x00ff0000) >> 16); buf[off + 3] = (byte)((num & 0xff000000) >> 24); } public static int int32d(byte[] buf, int off) { return((int)uint32d(buf, off)); } public static long int64d(byte[] buf, int off) { long b = 0; for(int i = 0; i < 8; i++) b |= ((long)ub(buf[i])) << (i * 8); return(b); } public static void int32e(int num, byte[] buf, int off) { uint32e(((long)num) & 0xffffffff, buf, off); } public static void uint16e(int num, byte[] buf, int off) { buf[off] = sb(num & 0xff); buf[off + 1] = sb((num & 0xff00) >> 8); } public 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); } public static double floatd(byte[] buf, int off) { int e = buf[off]; long t = uint32d(buf, off + 1); int m = (int)(t & 0x7fffffffL); boolean s = (t & 0x80000000L) != 0; if(e == -128) { if(m == 0) return(0.0); throw(new RuntimeException("Invalid special float encoded (" + m + ")")); } double v = (((double)m) / 2147483648.0) + 1.0; if(s) v = -v; return(Math.pow(2.0, e) * v); } public static float float32d(byte[] buf, int off) { return(Float.intBitsToFloat(int32d(buf, off))); } public static double float64d(byte[] buf, int off) { return(Double.longBitsToDouble(int64d(buf, off))); } public static float hfdec(short bits) { int b = ((int)bits) & 0xffff; int e = (b & 0x7c00) >> 10; int m = b & 0x03ff; int ee; if(e == 0) { if(m == 0) { ee = 0; } else { int n = Integer.numberOfLeadingZeros(m) - 22; ee = (-15 - n) + 127; m = (m << (n + 1)) & 0x03ff; } } else if(e == 0x1f) { ee = 0xff; } else { ee = e - 15 + 127; } int f32 = ((b & 0x8000) << 16) | (ee << 23) | (m << 13); return(Float.intBitsToFloat(f32)); } public static short hfenc(float f) { int b = Float.floatToIntBits(f); int e = (b & 0x7f800000) >> 23; int m = b & 0x007fffff; int ee; if(e == 0) { ee = 0; m = 0; } else if(e == 0xff) { ee = 0x1f; } else if(e < 113) { ee = 0; m = (m | 0x00800000) >> (113 - e); } else if(e > 142) { return(((b & 0x80000000) == 0)?((short)0x7c00):((short)0xfc00)); } else { ee = e - 127 + 15; } int f16 = ((b >> 16) & 0x8000) | (ee << 10) | (m >> 13); return((short)f16); } 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); } private final static String base64set = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; private final static int[] base64rev; static { int[] rev = new int[128]; for(int i = 0; i < 128; rev[i++] = -1); for(int i = 0; i < base64set.length(); i++) rev[base64set.charAt(i)] = i; base64rev = rev; } public static String base64enc(byte[] in) { StringBuilder buf = new StringBuilder(); int p = 0; while(in.length - p >= 3) { buf.append(base64set.charAt( (in[p + 0] & 0xfc) >> 2)); buf.append(base64set.charAt(((in[p + 0] & 0x03) << 4) | ((in[p + 1] & 0xf0) >> 4))); buf.append(base64set.charAt(((in[p + 1] & 0x0f) << 2) | ((in[p + 2] & 0xc0) >> 6))); buf.append(base64set.charAt( in[p + 2] & 0x3f)); p += 3; } if(in.length == p + 1) { buf.append(base64set.charAt( (in[p + 0] & 0xfc) >> 2)); buf.append(base64set.charAt( (in[p + 0] & 0x03) << 4)); buf.append("=="); } else if(in.length == p + 2) { buf.append(base64set.charAt( (in[p + 0] & 0xfc) >> 2)); buf.append(base64set.charAt(((in[p + 0] & 0x03) << 4) | ((in[p + 1] & 0xf0) >> 4))); buf.append(base64set.charAt( (in[p + 1] & 0x0f) << 2)); buf.append("="); } return(buf.toString()); } public static byte[] base64dec(String in) { ByteArrayOutputStream buf = new ByteArrayOutputStream(); int cur = 0, b = 8; for(int i = 0; i < in.length(); i++) { char c = in.charAt(i); if(c >= 128) throw(new IllegalArgumentException()); if(c == '=') break; int d = base64rev[c]; if(d == -1) throw(new IllegalArgumentException()); b -= 6; if(b <= 0) { cur |= d >> -b; buf.write(cur); b += 8; cur = 0; } cur |= d << b; } return(buf.toByteArray()); } 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(" "); 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(" "); 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() / 2, col.getGreen() / 2, col.getBlue() / 2, 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); Object fcol = ol.getColorModel().getDataElements(col.getRGB(), null); Raster src = img.getRaster(); WritableRaster dst = ol.getRaster(); 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 { t = src.getSample(x - 1, y - 1, 3) < 250; } if(!t) continue; if(((x > 1) && (y > 0) && (y < sz.y - 1) && (src.getSample(x - 2, y - 1, 3) >= 250)) || ((x > 0) && (y > 1) && (x < sz.x - 1) && (src.getSample(x - 1, y - 2, 3) >= 250)) || ((x < sz.x - 2) && (y > 0) && (y < sz.y - 1) && (src.getSample(x, y - 1, 3) >= 250)) || ((x > 0) && (y < sz.y - 2) && (x < sz.x - 1) && (src.getSample(x - 1, y, 3) >= 250))) dst.setDataElements(x, y, fcol); if(thick){ if(((x > 1) && (y > 1) && (src.getSample(x - 2, y - 2, 3)) >= 250) || ((x < sz.x - 2) && (y < sz.y - 2) && (src.getSample(x, y, 3) >= 250)) || ((x < sz.x - 2) && (y > 1) && (src.getSample(x, y - 2, 3) >= 250)) || ((x > 1) && (y < sz.y - 2) && (src.getSample(x - 2, y, 3) >= 250))) dst.setDataElements(x, y, fcol); } } } 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); } /* XXX: These are not actually correct, since an exact integer * will round downwards, but I don't actually expect that to be a * problem given how I use these, and it turns out that * java.lang.Math.floor is actually surprisingly slow (it * delegates for StrictMath.float for some reason). */ public static int floordiv(float a, float b) { float q = a / b; return((q < 0)?(((int)q) - 1):((int)q)); } public static float floormod(float a, float b) { float r = a % b; return((a < 0)?(r + b):r); } public static double cangle(double a) { while(a > Math.PI) a -= Math.PI * 2; while(a < -Math.PI) a += Math.PI * 2; return(a); } public static double cangle2(double a) { while(a > Math.PI * 2) a -= Math.PI * 2; while(a < 0) a += Math.PI * 2; return(a); } public static double clip(double d, double min, double max) { if(d < min) return(min); if(d > max) return(max); return(d); } public static float clip(float d, float min, float 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) { if(s == null) throw(new IllegalArgumentException(s)); 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); throw(new IllegalArgumentException(s)); } public static boolean eq(Object a, Object b) { return(((a == null) && (b == null)) || ((a != null) && (b != null) && a.equals(b))); } public static boolean parsebool(String s, boolean def) { try { return(parsebool(s)); } catch(IllegalArgumentException e) { return(def); } } /* Just in case anyone doubted that Java is stupid. :-/ */ public static FloatBuffer bufcp(float[] a) { FloatBuffer b = mkfbuf(a.length); b.put(a); b.rewind(); return(b); } public static ShortBuffer bufcp(short[] a) { ShortBuffer b = mksbuf(a.length); b.put(a); b.rewind(); return(b); } public static FloatBuffer bufcp(FloatBuffer a) { a.rewind(); FloatBuffer ret = mkfbuf(a.remaining()); ret.put(a).rewind(); return(ret); } public static IntBuffer bufcp(IntBuffer a) { a.rewind(); IntBuffer ret = mkibuf(a.remaining()); ret.put(a).rewind(); return(ret); } public static ByteBuffer mkbbuf(int n) { try { return(ByteBuffer.allocateDirect(n).order(ByteOrder.nativeOrder())); } catch(OutOfMemoryError e) { /* At least Sun's class library doesn't try to collect * garbage if it's out of direct memory, which is pretty * stupid. So do it for it, then. */ System.gc(); return(ByteBuffer.allocateDirect(n).order(ByteOrder.nativeOrder())); } } public static FloatBuffer mkfbuf(int n) { return(mkbbuf(n * 4).asFloatBuffer()); } public static ShortBuffer mksbuf(int n) { return(mkbbuf(n * 2).asShortBuffer()); } public static IntBuffer mkibuf(int n) { return(mkbbuf(n * 4).asIntBuffer()); } /* public static ByteBuffer wbbuf(int n) { return(mkbbuf(n)); } public static IntBuffer wibuf(int n) { return(mkibuf(n)); } public static FloatBuffer wfbuf(int n) { return(mkfbuf(n)); } public static ShortBuffer wsbuf(int n) { return(mksbuf(n)); } */ public static ByteBuffer wbbuf(int n) { return(ByteBuffer.wrap(new byte[n])); } public static IntBuffer wibuf(int n) { return(IntBuffer.wrap(new int[n])); } public static FloatBuffer wfbuf(int n) { return(FloatBuffer.wrap(new float[n])); } public static ShortBuffer wsbuf(int n) { return(ShortBuffer.wrap(new short[n])); } public static float[] c2fa(Color c) { return(new float[] { ((float)c.getRed() / 255.0f), ((float)c.getGreen() / 255.0f), ((float)c.getBlue() / 255.0f), ((float)c.getAlpha() / 255.0f) }); } @SuppressWarnings("unchecked") public static <T> T[] mkarray(Class<T> cl, int len) { return((T[])Array.newInstance(cl, len)); } @SuppressWarnings("unchecked") public static <T> T[] splice(T[] src, int off, int len) { T[] dst = (T[])Array.newInstance(src.getClass().getComponentType(), len); System.arraycopy(src, off, dst, 0, len); return(dst); } public static void rgb2hsl(int r, int g, int b, int hsl[]) { float var_R = ( r / 255f ); float var_G = ( g / 255f ); float var_B = ( b / 255f ); float var_Min; //Min. value of RGB float var_Max; //Max. value of RGB float del_Max; //Delta RGB value if (var_R > var_G) { var_Min = var_G; var_Max = var_R; } else { var_Min = var_R; var_Max = var_G; } if (var_B > var_Max) var_Max = var_B; if (var_B < var_Min) var_Min = var_B; del_Max = var_Max - var_Min; float H = 0, S, L; L = ( var_Max + var_Min ) / 2f; if ( del_Max == 0 ) { H = 0; S = 0; } // gray else { //Chroma if ( L < 0.5 ) S = del_Max / ( var_Max + var_Min ); else S = del_Max / ( 2 - var_Max - var_Min ); float del_R = ( ( ( var_Max - var_R ) / 6f ) + ( del_Max / 2f ) ) / del_Max; float del_G = ( ( ( var_Max - var_G ) / 6f ) + ( del_Max / 2f ) ) / del_Max; float del_B = ( ( ( var_Max - var_B ) / 6f ) + ( del_Max / 2f ) ) / del_Max; if ( var_R == var_Max ) H = del_B - del_G; else if ( var_G == var_Max ) H = ( 1 / 3f ) + del_R - del_B; else if ( var_B == var_Max ) H = ( 2 / 3f ) + del_G - del_R; if ( H < 0 ) H += 1; if ( H > 1 ) H -= 1; } hsl[0] = (int)(360*H); hsl[1] = (int)(S*100); hsl[2] = (int)(L*100); } public static int[] hsl2rgb(final int[] hsl) { double h = hsl[0] / 360d; final double s = hsl[1] / 100d; double l = hsl[2] / 100d; double r = 0d; double g = 0d; double b; if (s > 0d) { if (h >= 1d) { h = 0d; } h = h * 6d; final double f = h - Math.floor(h); final double a = Math.round(l * 255d * (1d - s)); b = Math.round(l * 255d * (1d - (s * f))); final double c = Math.round(l * 255d * (1d - (s * (1d - f)))); l = Math.round(l * 255d); switch ((int) Math.floor(h)) { case 0: r = l; g = c; b = a; break; case 1: r = b; g = l; b = a; break; case 2: r = a; g = l; b = c; break; case 3: r = a; g = b; b = l; break; case 4: r = c; g = a; b = l; break; case 5: r = l; g = a; break; } return new int[] { (int) Math.round(r), (int) Math.round(g), (int) Math.round(b) }; } l = Math.round(l * 255d); return new int[] { (int) l, (int) l, (int) l }; } public static <T> T[] splice(T[] src, int off) { return(splice(src, off, src.length - off)); } @SuppressWarnings("unchecked") public static <T> T[] extend(T[] src, int off, int nl) { T[] dst = (T[])Array.newInstance(src.getClass().getComponentType(), nl); System.arraycopy(src, off, dst, 0, Math.min(src.length - off, dst.length)); return(dst); } public static <T> T[] extend(T[] src, int nl) { return(extend(src, 0, nl)); } public static <T> T el(Iterable<T> c) { return(c.iterator().next()); } public static <T> T construct(Constructor<T> cons, Object... args) { try { return(cons.newInstance(args)); } catch(InstantiationException e) { throw(new RuntimeException(e)); } catch(IllegalAccessException e) { throw(new RuntimeException(e)); } catch(InvocationTargetException e) { if(e.getCause() instanceof RuntimeException) throw((RuntimeException)e.getCause()); throw(new RuntimeException(e.getCause())); } } public static String urlencode(String in) { StringBuilder buf = new StringBuilder(); byte[] enc; try { enc = in.getBytes("utf-8"); } catch(java.io.UnsupportedEncodingException e) { /* ¦] */ throw(new Error(e)); } for(byte c : enc) { if(((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')) || ((c >= '0') && (c <= '9')) || (c == '.')) { buf.append((char)c); } else { buf.append("%" + Utils.num2hex((c & 0xf0) >> 4) + Utils.num2hex(c & 0x0f)); } } return(buf.toString()); } public static URL urlparam(URL base, String... pars) { /* Why is Java so horribly bad? */ String file = base.getFile(); int p = file.indexOf('?'); StringBuilder buf = new StringBuilder(); if(p >= 0) { /* For now, only add; don't augment. Since Java sucks. */ buf.append('&'); } else { buf.append('?'); } for(int i = 0; i < pars.length; i += 2) { if(i > 0) buf.append('&'); buf.append(urlencode(pars[i])); buf.append('='); buf.append(urlencode(pars[i + 1])); } try { return(new URL(base.getProtocol(), base.getHost(), base.getPort(), file + buf.toString())); } catch(java.net.MalformedURLException e) { throw(new RuntimeException(e)); } } 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); } }); Console.setscmd("gc", new Console.Command() { public void run(Console cons, String[] args) { System.gc(); } }); /* Console.setscmd("script", new Console.Command() { public void run(Console cons, String[] args) throws IOException { haven.test.ScriptDebug.start(args[1], Integer.parseInt(args[2]), true); } }); */ Console.setscmd("cscript", new Console.Command() { public void run(Console cons, String[] args) throws IOException { haven.test.ScriptDebug.connect(args[1], Config.defserv, Integer.parseInt(args[2])); } }); } public static String timestamp() { return new SimpleDateFormat("HH:mm").format(new Date()); } public static String timestamp(String text) { return String.format("[%s] %s", timestamp(), text); } public static String stream2str(InputStream is) { Scanner s = new Scanner(is).useDelimiter("\\A"); return s.hasNext() ? s.next() : ""; } public static Color hex2color(String hex, Color def){ Color c = def; if (hex != null) { try { int col = (int) Long.parseLong(hex, 16); boolean hasAlpha = (0xff000000 & col) != 0; c = new Color(col, hasAlpha); } catch (Exception ignored) {} } return c; } public static String color2hex(Color col){ if(col != null){ return Integer.toHexString(col.getRGB()); } return null; } }