diff --git a/MapManager.java b/MapManager.java index e5720003..0155dde9 100644 --- a/MapManager.java +++ b/MapManager.java @@ -52,6 +52,8 @@ public class MapManager extends Thread { /* a list of MapTiles to be updated */ private LinkedList staleTiles; + /* a list of MapTiles for which the cave tile is to be updated */ + private LinkedList staleCaveTiles; /* whether the worker thread should be running now */ private boolean running = false; @@ -84,6 +86,8 @@ public class MapManager extends Thread { /* this list stores the tile updates */ public LinkedList tileUpdates = null; + /* this list stores the cave tile updates */ + public LinkedList caveTileUpdates = null; /* map debugging mode (send debugging messages to this player) */ public String debugPlayer = null; @@ -138,7 +142,9 @@ public class MapManager extends Thread { tileStore = new HashMap(); staleTiles = new LinkedList(); + staleCaveTiles = new LinkedList(); tileUpdates = new LinkedList(); + caveTileUpdates = new LinkedList(); zoomCache = new Cache(zoomCacheSize); signs = new HashMap(); @@ -254,37 +260,62 @@ public class MapManager extends Thread { } } + /* update tile update list */ + private void updateUpdates(MapTile t, LinkedList lst) + { + long now = System.currentTimeMillis(); + long deadline = now - maxTileAge; + + synchronized(lock) { + ListIterator it = lst.listIterator(0); + while(it.hasNext()) { + TileUpdate tu = it.next(); + if(tu.at < deadline || tu.tile == t) + it.remove(); + } + lst.addLast(new TileUpdate(now, t)); + } + } + /* the worker/renderer thread */ public void run() { log.info("Map renderer has started."); while(running) { + boolean found = false; + MapTile t = this.popStaleTile(); if(t != null) { t.render(this); - long now = System.currentTimeMillis(); - long deadline = now - maxTileAge; - - /* update the tileupdate list */ - synchronized(lock) { - ListIterator it = tileUpdates.listIterator(0); - while(it.hasNext()) { - TileUpdate tu = it.next(); - if(tu.at < deadline || tu.tile == t) - it.remove(); - } - tileUpdates.addLast(new TileUpdate(now, t)); - } + updateUpdates(t, tileUpdates); try { this.sleep(renderWait); } catch(InterruptedException e) { } - } else { + + found = true; + } + + MapTile ct = this.popStaleCaveTile(); + if(ct != null) { + ct.renderCave(this); + + updateUpdates(ct, caveTileUpdates); + try { - this.sleep(1000); + this.sleep(renderWait); + } catch(InterruptedException e) { + } + + found = true; + } + + if(!found) { + try { + this.sleep(500); } catch(InterruptedException e) { } } @@ -350,18 +381,47 @@ public class MapManager extends Thread { } } + /* get next MapTile for which the cave map needs to be + * regenerated, or null + * the mapTile is removed from the list of stale cave tiles */ + public MapTile popStaleCaveTile() + { + synchronized(lock) { + try { + MapTile t = staleCaveTiles.removeFirst(); + t.staleCave = false; + return t; + } catch(NoSuchElementException e) { + return null; + } + } + } + /* put a MapTile that needs to be regenerated on the list of stale tiles */ public boolean pushStaleTile(MapTile m) { synchronized(lock) { - if(m.stale) return false; + boolean ret = false; - m.stale = true; - staleTiles.addLast(m); + if(!m.stale) { + m.stale = true; + staleTiles.addLast(m); - debug(m.toString() + " is now stale"); + debug(m.toString() + " is now stale"); - return true; + ret = true; + } + + if(!m.staleCave) { + m.staleCave = true; + staleCaveTiles.addLast(m); + + debug(m.toString() + " cave is now stale"); + + ret = true; + } + + return ret; } } @@ -393,7 +453,7 @@ public class MapManager extends Thread { public int getStaleCount() { synchronized(lock) { - return staleTiles.size(); + return staleTiles.size() + staleCaveTiles.size(); } } @@ -401,7 +461,7 @@ public class MapManager extends Thread { public int getRecentUpdateCount() { synchronized(lock) { - return tileUpdates.size(); + return tileUpdates.size() + caveTileUpdates.size(); } } diff --git a/MapTile.java b/MapTile.java index a7ca15e5..804edf2a 100644 --- a/MapTile.java +++ b/MapTile.java @@ -24,6 +24,9 @@ public class MapTile { /* whether this tile needs to be updated */ boolean stale = false; + /* whether the cave map of this tile needs to be updated */ + boolean staleCave = false; + /* create new MapTile */ public MapTile(int px, int py, int zpx, int zpy) { @@ -37,6 +40,57 @@ public class MapTile { mz = MapManager.anchorz + px / 2 - py / 2; } + /* try to get the server to load the relevant chunks */ + public void loadChunks() + { + int x1 = mx - 64; + int x2 = mx + MapManager.tileWidth / 2 + MapManager.tileHeight / 2; + + int z1 = mz - MapManager.tileHeight / 2; + int z2 = mz + MapManager.tileWidth / 2 + 64; + + int x, z; + Server s = etc.getServer(); + + for(x=x1; x=0; x-=2) { + Color c1 = caveScan(mgr, jx, iy, jz, 0); + Color c2 = caveScan(mgr, jx, iy, jz, 2); + + r.setPixel(x, y, new int[] { c1.getRed(), c1.getGreen(), c1.getBlue() }); + r.setPixel(x-1, y, new int[] { c2.getRed(), c2.getGreen(), c2.getBlue() }); + + jx++; + jz++; + + } + + y ++; + + jx = ix; + jz = iz - 1; + + for(x=MapManager.tileWidth-1; x>=0; x-=2) { + Color c1 = caveScan(mgr, jx, iy, jz, 2); + jx++; + jz++; + Color c2 = caveScan(mgr, jx, iy, jz, 0); + + r.setPixel(x, y, new int[] { c1.getRed(), c1.getGreen(), c1.getBlue() }); + r.setPixel(x-1, y, new int[] { c2.getRed(), c2.getGreen(), c2.getBlue() }); + } + + y ++; + + ix ++; + iz --; + } + + /* save the generated tile */ + saveTile(getCavePath(mgr), im, getZoomCavePath(mgr), mgr); + } + + /* save rendered tile, update zoom-out tile */ + public void saveTile(String tilePath, BufferedImage im, String zoomPath, MapManager mgr) + { /* save image */ try { - String path = getPath(mgr); - File file = new File(path); + File file = new File(tilePath); ImageIO.write(im, "png", file); } catch(IOException e) { - log.log(Level.SEVERE, "Failed to save tile: " + getPath(mgr), e); + log.log(Level.SEVERE, "Failed to save tile: " + tilePath, e); } catch(java.lang.NullPointerException e) { - log.log(Level.SEVERE, "Failed to save tile (NullPointerException): " + getPath(mgr), e); + log.log(Level.SEVERE, "Failed to save tile (NullPointerException): " + tilePath, e); } /* now update zoom-out tile */ - String zPath = getZoomPath(mgr); - BufferedImage zIm = mgr.zoomCache.get(zPath); + BufferedImage zIm = mgr.zoomCache.get(zoomPath); if(zIm == null) { /* zoom-out tile doesn't exist - try to load it from disk */ - mgr.debug("Trying to load zoom-out tile: " + zPath); + mgr.debug("Trying to load zoom-out tile: " + zoomPath); try { - File file = new File(zPath); + File file = new File(zoomPath); zIm = ImageIO.read(file); } catch(IOException e) { } - if(zIm == null) { - mgr.debug("Failed to load zoom-out tile: " + zPath); - + mgr.debug("Failed to load zoom-out tile: " + zoomPath); /* create new one */ /* TODO: we might use existing tiles that we could load * to fill the zoomed out tile in... */ zIm = new BufferedImage(MapManager.tileWidth, MapManager.tileHeight, BufferedImage.TYPE_INT_RGB); } else { - mgr.debug("Loaded zoom-out tile from " + zPath); + mgr.debug("Loaded zoom-out tile from " + zoomPath); } } else { - mgr.debug("Using zoom-out tile from cache: " + zPath); + mgr.debug("Using zoom-out tile from cache: " + zoomPath); } /* update zoom-out tile */ @@ -179,22 +302,22 @@ public class MapTile { g2.drawImage(im, ox, oy, scw, sch, null); /* update zoom-out tile cache */ - BufferedImage oldIm = mgr.zoomCache.put(zPath, zIm); + BufferedImage oldIm = mgr.zoomCache.put(zoomPath, zIm); if(oldIm != null && oldIm != zIm) { oldIm.flush(); } /* save zoom-out tile */ try { - File file = new File(zPath); + File file = new File(zoomPath); ImageIO.write(zIm, "png", file); - mgr.debug("saved zoom-out tile at " + zPath); + mgr.debug("saved zoom-out tile at " + zoomPath); //log.info("Saved tile: " + path); } catch(IOException e) { - log.log(Level.SEVERE, "Failed to save zoom-out tile: " + zPath, e); + log.log(Level.SEVERE, "Failed to save zoom-out tile: " + zoomPath, e); } catch(java.lang.NullPointerException e) { - log.log(Level.SEVERE, "Failed to save zoom-out tile (NullPointerException): " + zPath, e); + log.log(Level.SEVERE, "Failed to save zoom-out tile (NullPointerException): " + zoomPath, e); } } @@ -210,6 +333,18 @@ public class MapTile { return mgr.tilepath + "zt_" + zpx + "_" + zpy + ".png"; } + /* generate a path name for this cave map tile */ + public String getCavePath(MapManager mgr) + { + return mgr.tilepath + "ct_" + px + "_" + py + ".png"; + } + + /* generate a path name for the zoomed-out cave tile */ + public String getZoomCavePath(MapManager mgr) + { + return mgr.tilepath + "czt_" + zpx + "_" + zpy + ".png"; + } + /* try to load already generated image */ public BufferedImage loadTile(MapManager mgr) { @@ -284,4 +419,87 @@ public class MapTile { } } } + + /* cast a ray into the caves */ + private Color caveScan(MapManager mgr, int x, int y, int z, int seq) + { + Server s = etc.getServer(); + boolean air = true; + + for(;;) { + if(y < 0) + return Color.BLACK; + + int id = s.getBlockIdAt(x, y, z); + + switch(seq) { + case 0: + x--; + break; + case 1: + y--; + break; + case 2: + z++; + break; + case 3: + y--; + break; + } + + seq = (seq + 1) & 3; + + switch(id) { + case 20: + case 18: + case 17: + case 78: + case 79: + id = 0; + break; + default: + } + + if(id != 0) { + air = false; + continue; + } + + if(id == 0 && !air) { + int cr, cg, cb; + int mult = 256; + + if(y < 64) { + cr = 0; + cg = 64 + y * 3; + cb = 255 - y * 4; + } else { + cr = (y-64) * 4; + cg = 255; + cb = 0; + } + + switch(seq) { + case 0: + mult = 224; + break; + case 1: + mult = 256; + break; + case 2: + mult = 192; + break; + case 3: + mult = 160; + break; + } + + cr = cr * mult / 256; + cg = cg * mult / 256; + cb = cb * mult / 256; + + return new Color(cr, cg, cb); + } + } + } } diff --git a/WebServerRequest.java b/WebServerRequest.java index bcf2f6d5..61ba8bad 100644 --- a/WebServerRequest.java +++ b/WebServerRequest.java @@ -60,6 +60,7 @@ public class WebServerRequest extends Thread { int current = (int) (System.currentTimeMillis() / 1000); long cutoff = 0; + if(path.charAt(0) == '/') { try { cutoff = ((long) Integer.parseInt(path.substring(1))) * 1000; @@ -114,7 +115,13 @@ public class WebServerRequest extends Thread { synchronized(mgr.lock) { for(TileUpdate tu : mgr.tileUpdates) { if(tu.at >= cutoff) { - sb.append(tu.tile.px + "_" + tu.tile.py + " " + tu.tile.zpx + "_" + tu.tile.zpy + "\n"); + sb.append(tu.tile.px + "_" + tu.tile.py + " " + tu.tile.zpx + "_" + tu.tile.zpy + " t\n"); + } + } + + for(TileUpdate tu : mgr.caveTileUpdates) { + if(tu.at >= cutoff) { + sb.append(tu.tile.px + "_" + tu.tile.py + " " + tu.tile.zpx + "_" + tu.tile.zpy + " c\n"); } } } diff --git a/dist/DynamicMap.rar b/dist/DynamicMap.rar index 1e85c2dd..b37895cd 100644 Binary files a/dist/DynamicMap.rar and b/dist/DynamicMap.rar differ diff --git a/web/book.png b/web/book.png new file mode 100644 index 00000000..727dcdae Binary files /dev/null and b/web/book.png differ diff --git a/web/cave_off.png b/web/cave_off.png new file mode 100644 index 00000000..500d9872 Binary files /dev/null and b/web/cave_off.png differ diff --git a/web/cave_on.png b/web/cave_on.png new file mode 100644 index 00000000..06395767 Binary files /dev/null and b/web/cave_on.png differ diff --git a/web/index.html b/web/index.html index 4a579481..f48964f4 100644 --- a/web/index.html +++ b/web/index.html @@ -16,7 +16,9 @@
-