Compare commits

...

102 Commits

Author SHA1 Message Date
Mike Primm f62d46cfbd Add hidebydefault setting to playermarkers component too 2011-08-26 14:23:32 +08:00
Mike Primm bc357dd188 Handle multiple instances of same component type (regions) 2011-08-26 13:57:05 +08:00
Mike Primm c353d9aae6 Add hidebydefault option for regions layers 2011-08-26 13:57:05 +08:00
Mike Primm 106e470898 Add playermarkers to hide/show-able layer group 2011-08-26 06:34:37 +08:00
Mike Primm 59b095628d Add control for hide/show of component layers (only regions for now) 2011-08-26 06:34:37 +08:00
Mike Primm d9ad51edd6 Use towns list in Towny worlds/* files to get valid towns (old towns
still in towns/* directory)
2011-08-26 03:59:35 +08:00
Mike Primm 316440a4e0 Disable IOImage cache use for image loads 2011-08-26 03:59:35 +08:00
Mike Primm 04cc6aba43 Towny fixes - multiple areas on multiple worlds per town 2011-08-25 11:15:26 +08:00
Mike Primm ff4b036c6a Fix accessory face mixing 2011-08-24 14:25:42 +08:00
Mike Primm 76c8bc861d Merge remote branch 'upstream/master' 2011-08-24 01:02:47 -05:00
Mike Primm da32c2f0bd Add server-side generation of faces : fixes face accessory issues, IE8 2011-08-24 00:51:54 -05:00
Mike Primm 9564bd8a89 Add customstyle settings for per-region style, nation style for Towny, lots for Residence 2011-08-23 11:17:40 +08:00
Mike Primm 074952265f Add customstyle settings for per-region style, nation style for Towny, lots for Residence 2011-08-22 22:16:38 -05:00
Mike Primm 669d52f01b Merge remote branch 'upstream/master' 2011-08-22 20:34:34 -05:00
Mike Primm c37680b62c Add support for superperms/PermissionsBukkit/whatever-you-wanna-call-it 2011-08-23 08:21:38 +08:00
Mike Primm fae27f4cea Add support for superperms/PermissionsBukkit/whatever-you-wanna-call-it 2011-08-22 19:21:03 -05:00
Mike Primm 3b7fcc67ad Fix regionstyle attributes for region outlines and fill 2011-08-22 23:32:19 +08:00
Mike Primm 75d7068fbf Fix regionstyle attributes for region outlines and fill 2011-08-22 10:31:27 -05:00
Mike Primm 0ebabf5b61 First pass of Towny region support 2011-08-22 14:19:54 +08:00
Mike Primm d349a76660 First pass of Towny region support 2011-08-22 01:17:28 -05:00
Mike Primm 7e12574bd8 Add support in regions component for 'hiddenregions' (blacklist for regions) 2011-08-22 08:19:38 +08:00
Mike Primm 1284a8a6ed Merge remote branch 'upstream/master' 2011-08-21 19:00:14 -05:00
Mike Primm 8e22e40c16 Add support in regions component for 'hiddenregions' (blacklist for regions) 2011-08-21 18:58:38 -05:00
Mike Primm 929ca8911e Fix naming on Residence regions, make infowindow setting control popup content again 2011-08-22 04:58:21 +08:00
Mike Primm 82b0f2c4cd Fix naming on Residence regions, make infowindow setting control popup content again 2011-08-21 15:57:21 -05:00
Mike Primm 6e5482466d Switch chunkgenerate to onChunkPopulate event: chunk is better "cooked" by then 2011-08-21 10:33:09 +08:00
Mike Primm 45369006c3 Switch chunkgenerate to onChunkPopulate event: chunk is better "cooked" by then 2011-08-20 21:31:14 -05:00
Mike Primm 58d359fc1d Add setting for progressloginterval 2011-08-21 05:46:05 +08:00
Mike Primm c5c136a30d Add setting for progressloginterval 2011-08-20 16:45:21 -05:00
Mike Primm c327b98b97 Add progressloginterval setting - control how often progress messages done 2011-08-21 05:43:43 +08:00
Mike Primm 3f3ccf5344 Add progressloginterval setting - control how often progress messages done 2011-08-20 16:43:18 -05:00
Mike Primm 9b191bb3ab Add 'explosion' update trigger, add updated tile queue accelerator (to speed up processing if queue gets above a given threshold) 2011-08-21 05:31:07 +08:00
Mike Primm 43df59a88c Make sure we can clean up event listeners during reload (make /dynmap reload work) 2011-08-21 05:30:52 +08:00
Mike Primm 972d9b2ab7 Add 'explosion' update trigger, add updated tile queue accelerator (to speed up processing if queue gets above a given threshold) 2011-08-20 16:28:37 -05:00
Mike Primm 5ed6cf830b Make sure we can clean up event listeners during reload (make /dynmap reload work) 2011-08-20 15:21:39 -05:00
Mike Primm e8e4aa67ce Fix boundary condition that was causing some missed tiles on chunk triggers 2011-08-20 11:38:55 +08:00
Mike Primm e643292a7e Fix boundary condition that was causing some missed tiles on chunk triggers 2011-08-19 22:38:08 -05:00
Mike Primm f0a8300632 Merge remote branch 'upstream/master' 2011-08-19 21:36:35 -05:00
Mike Primm f24141587f Fix Residence region output in JSON mode 2011-08-20 00:29:55 +08:00
Mike Primm e2616c9159 Fix Residence region output in JSON mode 2011-08-19 11:27:38 -05:00
Mike Primm 83a9ff80d0 Add 'parallelrendercnt' - multi-core fullrender support (experimental) 2011-08-18 12:14:56 +08:00
Mike Primm fd2085b511 Add 'parallelrendercnt' - multi-core fullrender support (experimental) 2011-08-17 23:14:05 -05:00
Mike Primm ae9d1fde90 Turn off using temp file in ImageIO - our images are too small to do that 2011-08-17 10:26:07 +08:00
Mike Primm 7fd2d5bf10 Turn off using temp file in ImageIO - our images are too small to do that 2011-08-16 21:25:16 -05:00
Mike Primm e479d04c85 Merge remote branch 'origin/master' 2011-08-16 18:19:43 -05:00
Mike Primm 55dc6397e1 Fix logic on scroll buttons 2011-08-17 01:00:32 +08:00
Mike Primm d5d01cf5af Fix logic on scroll buttons 2011-08-16 11:59:08 -05:00
Mike Primm 98b3bdfde3 Add triggered update queue length to /dynmap stats 2011-08-16 13:48:00 +08:00
Mike Primm 4be423cfb8 Add triggered update queue length to /dynmap stats 2011-08-16 00:46:41 -05:00
Mike Primm 477a7d13de Add multiple quality levels for JPG encoding - adjust default to 0.85 2011-08-16 12:32:01 +08:00
Mike Primm 4616f6a5be Fix window resize exception - Leaflet expects 'map' at top level... 2011-08-16 08:08:59 +08:00
Mike Primm 829e1339a8 Change console fullrender to seed from world's center setting, vs 0,0,0 2011-08-15 21:10:44 +08:00
Mike Primm c9494a312d Fix exception if initial update has stale logoff for player+chat 2011-08-15 21:10:44 +08:00
Mike Primm 5b7ad0f4c9 Fix IE exceptions from debug code, canvas calls 2011-08-15 10:10:08 +08:00
Mike Primm 55720cfd4d Avoid exception try-catch on nominal path 2011-08-15 07:25:18 +08:00
Mike Primm 4cb5b9a956 Fix initial zoomout processing (unnecessary updates), extra tile invalidates 2011-08-15 07:25:17 +08:00
Mike Primm 6860d8952f More invalidate tightening up 2011-08-15 04:49:58 +08:00
Mike Primm 1aa3d07e6a Fix break in namedTile during integrate of updated Leaflet 2011-08-15 04:49:42 +08:00
Mike Primm 0c9cfedb6e Handle tile invalidates better for bigger-than-one-block cases (chunks) 2011-08-15 04:49:42 +08:00
Mike Primm 042544f22e Reapply updated Leaflet patch 2011-08-14 14:59:53 +08:00
Mike Primm f5d5171f86 Improve scaling of memory use with large numbers of tiles, prep for suspend/resume support 2011-08-14 14:27:20 +08:00
Mike Primm fb366ce36b Update rail and ladder models - work better with non-default textures 2011-08-14 13:13:24 +08:00
Mike Primm 9f4df9a76e Switch to using continuousWorld option in newer Leaflet - saves on override 2011-08-14 13:12:58 +08:00
Mike Primm 0bc760230f Update Leaflet (lots of fixes) 2011-08-14 13:12:58 +08:00
Mike Primm c524c39901 Add pistonmoved event handling, full rendering for piston and extension 2011-08-14 10:36:47 +08:00
Mike Primm 3da03c978b Add model for redstone repeater 2011-08-13 12:32:09 +08:00
Mike Primm 4316e1f3e4 Add support for single map render via /dynmap fullrender world:map, /dynmap radiusrender radius mapname 2011-08-13 11:48:26 +08:00
Mike Primm b800984e3f Fix alpha-blending on scaled textures, and mask textures 2011-08-13 11:03:16 +08:00
Mike Primm 17c2072b82 Fix armor calculation - bring in line with funky method used in MC UI 2011-08-13 05:36:48 +08:00
Mike Primm d008548306 Add support for JPEG encoding option for HDMaps 2011-08-12 14:48:52 +08:00
mikeprimm 49b38c10b7 Merge pull request #401 from mikeprimm/master
Fix typo in 'sendposition' setting - allow both 'sendposition' and 'sendpositon' in case someone worked around it
2011-08-10 20:38:52 -07:00
Mike Primm 053bd0e561 Fix typo in 'sendposition' setting - allow both 'sendposition' and 'sendpositon' in case someone worked around it 2011-08-10 22:37:41 -05:00
mikeprimm 4d3931709b Merge pull request #400 from mikeprimm/master
Add support for selectively hiding portions of worlds (opposite of visibilitylimits)
2011-08-10 20:18:20 -07:00
Mike Primm 166a5272fb Add support for selectively hiding portions of world (hiddenlimits) 2011-08-10 22:15:18 -05:00
mikeprimm 7e8e0411d9 Merge pull request #399 from mikeprimm/master
Add poly2d region support back to WorldGuard support
2011-08-10 18:48:36 -07:00
Mike Primm 6616b3eae5 Add poly2d region support back to WorldGuard 2011-08-10 20:47:14 -05:00
mikeprimm 0c99a6e7f4 Merge pull request #398 from mikeprimm/master
IE8 doesn't have indexOf, if you can believe that....
2011-08-10 16:10:35 -07:00
Mike Primm a5e3f36d97 Fix IE8 - missing indexOf(), if you can believe that.... fix is per
https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/IndexOf
2011-08-10 18:07:59 -05:00
FrozenCow f5f9c3bb31 Use shift, not pop, for queue. 2011-08-10 23:32:33 +02:00
FrozenCow 91b9b456b5 Added tile queueing. 2011-08-10 22:39:57 +02:00
mikeprimm 0a60c35be0 Merge pull request #395 from mikeprimm/master
Handle texture packs that do not include all required files
2011-08-10 12:58:30 -07:00
Mike Primm 641406a68e Merge remote branch 'upstream/master' 2011-08-10 14:55:07 -05:00
Mike Primm 334f3d983a Add handling for texture packs that don't provide all needed files -
fall through to standard pack when needed
2011-08-10 14:54:25 -05:00
FrozenCow 04c3a432e1 Added extra configuration for maven-assembly to fix directory-permissions. 2011-08-10 15:54:19 +02:00
FrozenCow fdbce8df36 Only handle cuboid regions. 2011-08-10 15:14:48 +02:00
mikeprimm 81d68d5ac9 Merge pull request #391 from mikeprimm/master
Add permissions info to plugin.yml
2011-08-09 22:55:24 -07:00
Mike Primm 6383a7ef22 Add permissions info to plugin.yml 2011-08-10 00:52:55 -05:00
mikeprimm 1fcef60768 Merge pull request #390 from mikeprimm/master
Model for cactus - fix seams on edges, since cactus aren't quite full block
2011-08-09 18:46:19 -07:00
Mike Primm 3a38b44e79 Make model for cactus - they aren't quite full block 2011-08-09 20:45:08 -05:00
mikeprimm 82b7a87a7c Merge pull request #389 from mikeprimm/master
Check for raw biome lookup overflows - prevent array exceptions on some worlds
2011-08-08 22:20:06 -07:00
Mike Primm 48ba43aae5 Check for overflow on biome lookup - prevent exceptions on some worlds 2011-08-09 00:18:38 -05:00
Mike Primm 89525c38d5 Merge remote branch 'origin/master' 2011-08-08 23:41:15 -05:00
mikeprimm d468abe5a1 Merge pull request #387 from mikeprimm/master
Add id=3 leaves: apparently, alpha-map leaves migrated to this value
2011-08-08 07:21:27 -07:00
Mike Primm 9c44843884 Add leaves id=3: apparently alpha-map leaves migrated to this? 2011-08-08 09:20:10 -05:00
mikeprimm 2b26bdd5a4 Merge pull request #384 from mikeprimm/master
Add leafid + 12 values - not sure if needed, but no harm in it (for 0.20.1)
2011-08-07 21:01:13 -07:00
Mike Primm a76a734e16 Add mappings for leaves for +12 - not sure if needed, but can't hurt 2011-08-07 22:58:51 -05:00
mikeprimm 4fd3382493 Merge pull request #383 from mikeprimm/master
Fix subblock rendering of scaled down models (esp flat ones like rails, redstone) (for 0.20.1)
2011-08-07 20:12:43 -07:00
Mike Primm 4209a2c54d Fix subblock rendering of flat, scaled-down models (for 0.20.1) 2011-08-07 22:11:00 -05:00
mikeprimm 154057adcc Merge pull request #381 from mikeprimm/master
Handle leaf fade processing flag values in texture mapping
2011-08-07 08:35:17 -07:00
Mike Primm a641d2d831 Handle fade-processing bit values on leaves (N, N+4, N+8) 2011-08-07 10:29:54 -05:00
FrozenCow cd7e04fec3 Added another data-value (8) for leaves that occurs in parts of the trees in Skylands. 2011-08-07 16:55:22 +02:00
FrozenCow 4381d5838c Changed version to 0.21. 2011-08-06 20:04:53 +02:00
59 changed files with 2877 additions and 828 deletions
+7 -1
View File
@@ -2,7 +2,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.dynmap</groupId>
<artifactId>dynmap</artifactId>
<version>0.20</version>
<version>0.21</version>
<name>dynmap</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
@@ -29,6 +29,12 @@
<descriptors>
<descriptor>src/main/assembly/package.xml</descriptor>
</descriptors>
<!-- Hack for bug in maven-assembly: http://jira.codehaus.org/browse/MASSEMBLY-449 -->
<archiverConfig>
<fileMode>420</fileMode> <!-- 420(dec) = 644(oct) -->
<directoryMode>493</directoryMode> <!-- 493(dec) = 755(oct) -->
<defaultDirectoryMode>493</defaultDirectoryMode>
</archiverConfig>
</configuration>
<executions>
<execution>
+25 -17
View File
@@ -2,6 +2,7 @@ package org.dynmap;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
import org.bukkit.Material;
public class Armor {
@@ -10,27 +11,34 @@ public class Armor {
* We rely on getArmorContents() to return 4 armor pieces in the order
* of: boots, pants, chest, helmet
*/
private static final double armorPoints[] = {1.5, 3.0, 4.0, 1.5};
private static final int armorPoints[] = {3, 6, 8, 3};
public static final int getArmorPoints(Player player) {
int currentDurability = 0;
int baseDurability = 0;
double baseArmorPoints = 0;
ItemStack inventory[] = player.getInventory().getArmorContents();
for(int i=0;i<inventory.length;i++) {
if(inventory[i] == null)
continue;
Material m = inventory[i].getType();
if(m == null)
continue;
final short maxDurability = m.getMaxDurability();
if(maxDurability < 0)
continue;
final short durability = inventory[i].getDurability();
baseDurability += maxDurability;
currentDurability += maxDurability - durability;
baseArmorPoints += armorPoints[i];
int baseArmorPoints = 0;
ItemStack[] itm = new ItemStack[4];
PlayerInventory inv = player.getInventory();
itm[0] = inv.getBoots();
itm[1]= inv.getLeggings();
itm[2] = inv.getChestplate();
itm[3] = inv.getHelmet();
for(int i = 0; i < 4; i++) {
if(itm[i] == null) continue;
int dur = itm[i].getDurability();
int max = itm[i].getType().getMaxDurability();
if(max <= 0) continue;
if(i == 2)
max = max + 1; /* Always 1 too low for chestplate */
else
max = max - 3; /* Always 3 too high, versus how client calculates it */
baseDurability += max;
currentDurability += max - dur;
baseArmorPoints += armorPoints[i];
}
return (int)Math.round(2*baseArmorPoints*currentDurability/baseDurability);
int ap = 0;
if(baseDurability > 0)
ap = ((baseArmorPoints - 1) * currentDurability) / baseDurability + 1;
return ap;
}
}
+14 -12
View File
@@ -12,10 +12,14 @@ public class AsynchronousQueue<T> {
private Set<T> set = new HashSet<T>();
private Handler<T> handler;
private int dequeueTime;
public AsynchronousQueue(Handler<T> handler, int dequeueTime) {
private int accelDequeueTime;
private int accelDequeueThresh;
public AsynchronousQueue(Handler<T> handler, int dequeueTime, int accelDequeueThresh, int accelDequeueTime) {
this.handler = handler;
this.dequeueTime = dequeueTime;
this.accelDequeueTime = accelDequeueTime;
this.accelDequeueThresh = accelDequeueThresh;
}
public boolean push(T t) {
@@ -30,15 +34,10 @@ public class AsynchronousQueue<T> {
private T pop() {
synchronized (lock) {
try {
T t = queue.removeFirst();
if (!set.remove(t)) {
// This should never happen.
}
return t;
} catch (NoSuchElementException e) {
return null;
}
T t = queue.pollFirst();
if(t != null)
set.remove(t);
return t;
}
}
@@ -88,7 +87,10 @@ public class AsynchronousQueue<T> {
if (t != null) {
handler.handle(t);
}
sleep(dequeueTime);
if(set.size() >= accelDequeueThresh)
sleep(accelDequeueTime);
else
sleep(dequeueTime);
}
} catch (Exception ex) {
@@ -42,7 +42,9 @@ public class ClientUpdateComponent extends Component {
s(jp, "account", p.getName());
/* Don't leak player location for world not visible on maps, or if sendposition disbaled */
DynmapWorld pworld = MapManager.mapman.worldsLookup.get(p.getWorld().getName());
if(configuration.getBoolean("sendpositon", true) && (pworld != null) && pworld.sendposition) {
/* Fix typo on 'sendpositon' to 'sendposition', keep bad one in case someone used it */
if(configuration.getBoolean("sendposition", true) && configuration.getBoolean("sendpositon", true) &&
(pworld != null) && pworld.sendposition) {
s(jp, "world", p.getWorld().getName());
s(jp, "x", pl.getX());
s(jp, "y", pl.getY());
File diff suppressed because it is too large Load Diff
+19 -7
View File
@@ -6,7 +6,6 @@ import java.util.List;
import org.bukkit.World;
import org.bukkit.Location;
import org.dynmap.debug.Debug;
import org.dynmap.kzedmap.KzedMap;
import org.dynmap.utils.DynmapBufferedImage;
import org.dynmap.utils.FileLockManager;
import org.dynmap.utils.MapChunkCache;
@@ -32,6 +31,7 @@ public class DynmapWorld {
public ConfigurationNode configuration;
public List<Location> seedloc;
public List<MapChunkCache.VisibilityLimit> visibility_limits;
public List<MapChunkCache.VisibilityLimit> hidden_limits;
public AutoGenerateOption do_autogenerate;
public MapChunkCache.HiddenChunkStyle hiddenchunkstyle;
public int servertime;
@@ -104,11 +104,21 @@ public class DynmapWorld {
}
}
private static final String COORDSTART = "-0123456789";
private static class PNGFileFilter implements FilenameFilter {
String prefix;
public PNGFileFilter(String pre) { prefix = pre; }
String suffix;
public PNGFileFilter(String pre, MapType.ImageFormat fmt) {
if((pre != null) && (pre.length() > 0))
prefix = pre;
suffix = "." + fmt.getFileExt();
}
public boolean accept(File f, String n) {
if(n.endsWith(".png") && n.startsWith(prefix)) {
if(n.endsWith(suffix)) {
if((prefix != null) && (!n.startsWith(prefix)))
return false;
if((prefix == null) && (COORDSTART.indexOf(n.charAt(0)) < 0))
return false;
File fn = new File(f, n);
return fn.isFile();
}
@@ -146,6 +156,7 @@ public class DynmapWorld {
String zfnprefix;
int bigworldshift;
boolean isbigmap;
MapType.ImageFormat fmt;
}
public boolean freshenZoomOutFilesByLevel(int zoomlevel) {
@@ -252,6 +263,7 @@ public class DynmapWorld {
pd.zoomprefix = "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz".substring(0, zoomlevel);
pd.bigworldshift = bigworldshift;
pd.isbigmap = mt.isBigWorldMap(this);
pd.fmt = mt.getImageFormat();
if(pd.isbigmap) {
if(zoomlevel > 0) {
pd.zoomprefix += "_";
@@ -282,15 +294,15 @@ public class DynmapWorld {
private String makeFilePath(PrefixData pd, int x, int y, boolean zoomed) {
if(pd.isbigmap)
return pd.baseprefix + "/" + (x >> pd.bigworldshift) + "_" + (y >> pd.bigworldshift) + "/" + (zoomed?pd.zfnprefix:pd.fnprefix) + x + "_" + y + ".png";
return pd.baseprefix + "/" + (x >> pd.bigworldshift) + "_" + (y >> pd.bigworldshift) + "/" + (zoomed?pd.zfnprefix:pd.fnprefix) + x + "_" + y + "." + pd.fmt.getFileExt();
else
return (zoomed?pd.zfnprefix:pd.fnprefix) + "_" + x + "_" + y + ".png";
return (zoomed?pd.zfnprefix:pd.fnprefix) + "_" + x + "_" + y + "." + pd.fmt.getFileExt();
}
private int processZoomDirectory(File dir, PrefixData pd) {
Debug.debug("processZoomDirectory(" + dir.getPath() + "," + pd.baseprefix + ")");
HashMap<String, ProcessTileRec> toprocess = new HashMap<String, ProcessTileRec>();
String[] files = dir.list(new PNGFileFilter(pd.fnprefix));
String[] files = dir.list(new PNGFileFilter(pd.fnprefix, pd.fmt));
if(files == null)
return 0;
for(String fn : files) {
@@ -434,7 +446,7 @@ public class DynmapWorld {
try {
if(!zf.getParentFile().exists())
zf.getParentFile().mkdirs();
FileLockManager.imageIOWrite(zIm, "png", zf);
FileLockManager.imageIOWrite(zIm, pd.fmt, zf);
Debug.debug("Saved zoom-out tile at " + zf.getPath());
} catch (IOException e) {
Debug.error("Failed to save zoom-out tile: " + zf.getName(), e);
+215 -88
View File
@@ -11,6 +11,7 @@ import java.util.List;
import java.util.Map;
import java.util.TreeSet;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.ScheduledFuture;
@@ -29,6 +30,7 @@ import org.dynmap.utils.LegacyMapChunkCache;
import org.dynmap.utils.MapChunkCache;
import org.dynmap.utils.NewMapChunkCache;
import org.dynmap.utils.SnapshotCache;
import org.dynmap.utils.TileFlags;
public class MapManager {
public AsynchronousQueue<MapTile> tileQueue;
@@ -41,6 +43,8 @@ public class MapManager {
private DynmapPlugin plug_in;
private long timeslice_int = 0; /* In milliseconds */
private int max_chunk_loads_per_tick = DEFAULT_CHUNKS_PER_TICK;
private int parallelrendercnt = 0;
private int progressinterval = 100;
private int zoomout_period = DEFAULT_ZOOMOUT_PERIOD; /* Zoom-out tile processing period, in seconds */
/* Which fullrenders are active */
@@ -95,7 +99,7 @@ public class MapManager {
private class DynmapScheduledThreadPoolExecutor extends ScheduledThreadPoolExecutor {
DynmapScheduledThreadPoolExecutor() {
super(POOL_SIZE);
super(POOL_SIZE + parallelrendercnt);
this.setThreadFactory(new OurThreadFactory());
/* Set shutdown policy to stop everything */
setContinueExistingPeriodicTasksAfterShutdownPolicy(false);
@@ -151,11 +155,10 @@ public class MapManager {
Location loc;
int map_index = -1; /* Which map are we on */
MapType map;
HashSet<MapTile> found = null;
HashSet<MapTile> rendered = null;
TileFlags found = null;
TileFlags rendered = null;
LinkedList<MapTile> renderQueue = null;
MapTile tile0 = null;
MapTile tile = null;
int rendercnt = 0;
CommandSender sender;
long timeaccum;
@@ -166,19 +169,20 @@ public class MapManager {
int cxmin, cxmax, czmin, czmax;
String rendertype;
boolean cancelled;
String mapname;
/* Full world, all maps render */
FullWorldRenderState(DynmapWorld dworld, Location l, CommandSender sender) {
this(dworld, l, sender, -1);
FullWorldRenderState(DynmapWorld dworld, Location l, CommandSender sender, String mapname) {
this(dworld, l, sender, mapname, -1);
rendertype = "Full render";
}
/* Full world, all maps render, with optional render radius */
FullWorldRenderState(DynmapWorld dworld, Location l, CommandSender sender, int radius) {
FullWorldRenderState(DynmapWorld dworld, Location l, CommandSender sender, String mapname, int radius) {
world = dworld;
loc = l;
found = new HashSet<MapTile>();
rendered = new HashSet<MapTile>();
found = new TileFlags();
rendered = new TileFlags();
renderQueue = new LinkedList<MapTile>();
this.sender = sender;
if(radius < 0) {
@@ -193,6 +197,7 @@ public class MapManager {
czmax = (l.getBlockZ() + radius+15)>>4;
rendertype = "Radius render";
}
this.mapname = mapname;
}
/* Single tile render - used for incremental renders */
@@ -204,7 +209,7 @@ public class MapManager {
}
public String toString() {
return "world=" + world.world.getName() + ", map=" + map + " tile=" + tile;
return "world=" + world.world.getName() + ", map=" + map;
}
public void cleanup() {
@@ -216,6 +221,8 @@ public class MapManager {
}
public void run() {
long tstart = System.currentTimeMillis();
MapTile tile = null;
List<MapTile> tileset = null;
if(cancelled) {
cleanup();
@@ -240,8 +247,17 @@ public class MapManager {
/* Advance to next unrendered map */
while(map_index < world.maps.size()) {
map_index++; /* Move to next one */
if((map_index < world.maps.size()) && (renderedmaps.contains(world.maps.get(map_index)) == false))
break;
if(map_index >= world.maps.size()) break;
/* If single map render, see if this is our target */
if(mapname != null) {
if(world.maps.get(map_index).getName().equals(mapname)) {
break;
}
}
else {
if(renderedmaps.contains(world.maps.get(map_index)) == false)
break;
}
}
if(map_index >= world.maps.size()) { /* Last one done? */
sender.sendMessage(rendertype + " of '" + world.world.getName() + "' finished.");
@@ -253,6 +269,8 @@ public class MapManager {
/* Build active map list */
activemaps = "";
for(String n : activemaplist) {
if((mapname != null) && (!mapname.equals(n)))
continue;
if(activemaps.length() > 0)
activemaps += ",";
activemaps += n;
@@ -262,28 +280,96 @@ public class MapManager {
/* Now, prime the render queue */
for (MapTile mt : map.getTiles(loc)) {
if (!found.contains(mt)) {
found.add(mt);
if (!found.getFlag(mt.tileOrdinalX(), mt.tileOrdinalY())) {
found.setFlag(mt.tileOrdinalX(), mt.tileOrdinalY(), true);
renderQueue.add(mt);
}
}
if(world.seedloc != null) {
for(Location seed : world.seedloc) {
for (MapTile mt : map.getTiles(seed)) {
if (!found.contains(mt)) {
found.add(mt);
if (!found.getFlag(mt.tileOrdinalX(),mt.tileOrdinalY())) {
found.setFlag(mt.tileOrdinalX(),mt.tileOrdinalY(), true);
renderQueue.add(mt);
}
}
}
}
}
tile = renderQueue.pollFirst();
if(parallelrendercnt > 1) { /* Doing parallel renders? */
tileset = new ArrayList<MapTile>();
for(int i = 0; i < parallelrendercnt; i++) {
tile = renderQueue.pollFirst();
if(tile != null)
tileset.add(tile);
}
}
else {
tile = renderQueue.pollFirst();
}
}
else { /* Else, single tile render */
tile = tile0;
}
World w = world.world;
boolean notdone = true;
if(tileset != null) {
long save_timeaccum = timeaccum;
List<Future<Boolean>> rslt = new ArrayList<Future<Boolean>>();
final int cnt = tileset.size();
for(int i = 1; i < cnt; i++) { /* Do all but first on other threads */
final MapTile mt = tileset.get(i);
if((mapman != null) && (mapman.render_pool != null)) {
final long ts = tstart;
Future<Boolean> future = mapman.render_pool.submit(new Callable<Boolean>() {
public Boolean call() {
return processTile(mt, mt.world.world, ts, cnt);
}
});
rslt.add(future);
}
}
/* Now, do our render (first one) */
notdone = processTile(tileset.get(0), w, tstart, cnt);
/* Now, join with others */
for(int i = 0; i < rslt.size(); i++) {
try {
notdone = notdone && rslt.get(i).get();
} catch (ExecutionException xx) {
Log.severe(xx);
notdone = false;
} catch (InterruptedException ix) {
notdone = false;
}
}
timeaccum = save_timeaccum + System.currentTimeMillis() - tstart;
}
else {
notdone = processTile(tile, w, tstart, 1);
}
if(notdone) {
if(tile0 == null) { /* fullrender */
long tend = System.currentTimeMillis();
if(timeslice_int > (tend-tstart)) { /* We were fast enough */
scheduleDelayedJob(this, timeslice_int - (tend-tstart));
}
else { /* Schedule to run ASAP */
scheduleDelayedJob(this, 0);
}
}
else {
cleanup();
}
}
else {
cleanup();
}
}
private boolean processTile(MapTile tile, World w, long tstart, int parallelcnt) {
/* Get list of chunks required for tile */
List<DynmapChunk> requiredChunks = tile.getRequiredChunks();
/* If we are doing radius limit render, see if any are inside limits */
@@ -302,55 +388,49 @@ public class MapManager {
tile.isHightestBlockYDataNeeded(), tile.isBiomeDataNeeded(),
tile.isRawBiomeDataNeeded());
if(cache == null) {
cleanup();
return; /* Cancelled/aborted */
return false; /* Cancelled/aborted */
}
if(tile0 != null) { /* Single tile? */
if(cache.isEmpty() == false)
tile.render(cache);
tile.render(cache, null);
}
else {
/* Switch to not checking if rendered tile is blank - breaks us on skylands, where tiles can be nominally blank - just work off chunk cache empty */
/* Switch to not checking if rendered tile is blank - breaks us on skylands, where tiles can be nominally blank - just work off chunk cache empty */
if (cache.isEmpty() == false) {
tile.render(cache);
found.remove(tile);
rendered.add(tile);
for (MapTile adjTile : map.getAdjecentTiles(tile)) {
if (!found.contains(adjTile) && !rendered.contains(adjTile)) {
found.add(adjTile);
renderQueue.add(adjTile);
tile.render(cache, mapname);
synchronized(lock) {
// found.setFlag(tile.tileOrdinalX(),tile.tileOrdinalY(),false);
rendered.setFlag(tile.tileOrdinalX(), tile.tileOrdinalY(), true);
for (MapTile adjTile : map.getAdjecentTiles(tile)) {
if (!found.getFlag(adjTile.tileOrdinalX(),adjTile.tileOrdinalY()) &&
!rendered.getFlag(adjTile.tileOrdinalX(),adjTile.tileOrdinalY())) {
found.setFlag(adjTile.tileOrdinalX(), adjTile.tileOrdinalY(), true);
renderQueue.add(adjTile);
}
}
}
}
found.remove(tile);
if(!cache.isEmpty()) {
rendercnt++;
timeaccum += System.currentTimeMillis() - tstart;
if((rendercnt % 100) == 0) {
double msecpertile = (double)timeaccum / (double)rendercnt / (double)activemaplist.size();
if(activemaplist.size() > 1)
sender.sendMessage(rendertype + " of maps [" + activemaps + "] of '" +
synchronized(lock) {
// found.setFlag(tile.tileOrdinalX(), tile.tileOrdinalY(), false);
if(!cache.isEmpty()) {
rendercnt++;
timeaccum += System.currentTimeMillis() - tstart;
if((rendercnt % progressinterval) == 0) {
double msecpertile = (double)timeaccum / (double)rendercnt / (double)activemaplist.size();
if(activemaplist.size() > 1)
sender.sendMessage(rendertype + " of maps [" + activemaps + "] of '" +
w.getName() + "' in progress - " + rendercnt + " tiles rendered each (" + String.format("%.2f", msecpertile) + " msec/map-tile).");
else
sender.sendMessage(rendertype + " of map '" + activemaps + "' of '" +
else
sender.sendMessage(rendertype + " of map '" + activemaps + "' of '" +
w.getName() + "' in progress - " + rendercnt + " tiles rendered (" + String.format("%.2f", msecpertile) + " msec/tile).");
}
}
}
}
/* And unload what we loaded */
cache.unloadChunks();
if(tile0 == null) { /* fullrender */
long tend = System.currentTimeMillis();
if(timeslice_int > (tend-tstart)) { /* We were fast enough */
scheduleDelayedJob(this, timeslice_int - (tend-tstart));
}
else { /* Schedule to run ASAP */
scheduleDelayedJob(this, 0);
}
}
else {
cleanup();
}
return true;
}
public void cancelRender() {
@@ -407,13 +487,20 @@ public class MapManager {
hdmapman.loadHDPerspectives(plugin);
hdmapman.loadHDLightings(plugin);
sscache = new SnapshotCache(configuration.getInteger("snapshotcachesize", 500));
parallelrendercnt = configuration.getInteger("parallelrendercnt", 0);
progressinterval = configuration.getInteger("progressloginterval", 100);
if(progressinterval < 100) progressinterval = 100;
this.tileQueue = new AsynchronousQueue<MapTile>(new Handler<MapTile>() {
@Override
public void handle(MapTile t) {
scheduleDelayedJob(new FullWorldRenderState(t), 0);
}
}, (int) (configuration.getDouble("renderinterval", 0.5) * 1000));
this.tileQueue = new AsynchronousQueue<MapTile>(
new Handler<MapTile>() {
@Override
public void handle(MapTile t) {
scheduleDelayedJob(new FullWorldRenderState(t), 0);
}
},
(int) (configuration.getDouble("renderinterval", 0.5) * 1000),
configuration.getInteger("renderacceleratethreshold", 30),
(int)(configuration.getDouble("renderaccelerateinterval", 0.2) * 1000));
/* On dedicated thread, so default to no delays */
timeslice_int = (long)(configuration.getDouble("timesliceinterval", 0.0) * 1000);
@@ -434,7 +521,7 @@ public class MapManager {
}
}
void renderFullWorld(Location l, CommandSender sender) {
void renderFullWorld(Location l, CommandSender sender, String mapname) {
DynmapWorld world = getWorld(l.getWorld().getName());
if (world == null) {
sender.sendMessage("Could not render: world '" + l.getWorld().getName() + "' not defined in configuration.");
@@ -448,7 +535,7 @@ public class MapManager {
sender.sendMessage(rndr.rendertype + " of world '" + wname + "' already active.");
return;
}
rndr = new FullWorldRenderState(world,l,sender); /* Make new activation record */
rndr = new FullWorldRenderState(world,l,sender, mapname); /* Make new activation record */
active_renders.put(wname, rndr); /* Add to active table */
}
/* Schedule first tile to be worked */
@@ -457,7 +544,7 @@ public class MapManager {
sender.sendMessage("Full render starting on world '" + wname + "'...");
}
void renderWorldRadius(Location l, CommandSender sender, int radius) {
void renderWorldRadius(Location l, CommandSender sender, String mapname, int radius) {
DynmapWorld world = getWorld(l.getWorld().getName());
if (world == null) {
sender.sendMessage("Could not render: world '" + l.getWorld().getName() + "' not defined in configuration.");
@@ -471,7 +558,7 @@ public class MapManager {
sender.sendMessage(rndr.rendertype + " of world '" + wname + "' already active.");
return;
}
rndr = new FullWorldRenderState(world,l,sender, radius); /* Make new activation record */
rndr = new FullWorldRenderState(world,l,sender, mapname, radius); /* Make new activation record */
active_renders.put(wname, rndr); /* Add to active table */
}
/* Schedule first tile to be worked */
@@ -550,6 +637,19 @@ public class MapManager {
dynmapWorld.seedloc.add(new Location(w, (lim.x0+lim.x1)/2, 64, (lim.z0+lim.z1)/2));
}
}
/* Load hidden limits, if any are defined */
List<ConfigurationNode> hidelimits = worldConfiguration.getNodes("hiddenlimits");
if(hidelimits != null) {
dynmapWorld.hidden_limits = new ArrayList<MapChunkCache.VisibilityLimit>();
for(ConfigurationNode vis : hidelimits) {
MapChunkCache.VisibilityLimit lim = new MapChunkCache.VisibilityLimit();
lim.x0 = vis.getInteger("x0", 0);
lim.x1 = vis.getInteger("x1", 0);
lim.z0 = vis.getInteger("z0", 0);
lim.z1 = vis.getInteger("z1", 0);
dynmapWorld.hidden_limits.add(lim);
}
}
String autogen = worldConfiguration.getString("autogenerate-to-visibilitylimits", "none");
if(autogen.equals("permanent")) {
dynmapWorld.do_autogenerate = AutoGenerateOption.PERMANENT;
@@ -614,9 +714,24 @@ public class MapManager {
return invalidates;
}
public int touchVolume(Location l0, Location l1) {
DynmapWorld world = getWorld(l0.getWorld().getName());
if (world == null)
return 0;
int invalidates = 0;
for (int i = 0; i < world.maps.size(); i++) {
MapTile[] tiles = world.maps.get(i).getTiles(l0, l1);
for (int j = 0; j < tiles.length; j++) {
invalidateTile(tiles[j]);
invalidates++;
}
}
return invalidates;
}
public void invalidateTile(MapTile tile) {
Debug.debug("Invalidating tile " + tile.getFilename());
tileQueue.push(tile);
if(tileQueue.push(tile))
Debug.debug("Invalidating tile " + tile.getFilename());
}
public static void scheduleDelayedJob(Runnable job, long delay_in_msec) {
@@ -707,6 +822,13 @@ public class MapManager {
c.setHiddenFillStyle(w.hiddenchunkstyle);
c.setAutoGenerateVisbileRanges(w.do_autogenerate);
}
if(w.hidden_limits != null) {
for(MapChunkCache.VisibilityLimit limit: w.hidden_limits) {
c.setHiddenRange(limit);
}
c.setHiddenFillStyle(w.hiddenchunkstyle);
}
c.setChunks(w.world, chunks);
if(c.setChunkDataTypes(blockdata, biome, highesty, rawbiome) == false)
Log.severe("CraftBukkit build does not support biome APIs");
@@ -714,33 +836,37 @@ public class MapManager {
return c;
}
synchronized(loadlock) {
final MapChunkCache cc = c;
long now = System.currentTimeMillis();
if(cur_tick != (now/50)) { /* New tick? */
chunks_in_cur_tick = max_chunk_loads_per_tick;
cur_tick = now/50;
}
while(!cc.isDoneLoading()) {
final int cntin = chunks_in_cur_tick;
Future<Integer> f = scheduler.callSyncMethod(plug_in, new Callable<Integer>() {
public Integer call() throws Exception {
return Integer.valueOf(cntin - cc.loadChunks(cntin));
}
});
try {
chunks_in_cur_tick = f.get();
} catch (Exception ix) {
Log.severe(ix);
return null;
}
if(chunks_in_cur_tick == 0) {
chunks_in_cur_tick = max_chunk_loads_per_tick;
try { Thread.sleep(50); } catch (InterruptedException ix) {}
}
final MapChunkCache cc = c;
while(!cc.isDoneLoading()) {
synchronized(loadlock) {
long now = System.currentTimeMillis();
if(cur_tick != (now/50)) { /* New tick? */
chunks_in_cur_tick = max_chunk_loads_per_tick;
cur_tick = now/50;
}
}
Future<Boolean> f = scheduler.callSyncMethod(plug_in, new Callable<Boolean>() {
public Boolean call() throws Exception {
boolean exhausted;
synchronized(loadlock) {
if(chunks_in_cur_tick > 0)
chunks_in_cur_tick -= cc.loadChunks(chunks_in_cur_tick);
exhausted = (chunks_in_cur_tick == 0);
}
return exhausted;
}
});
boolean delay;
try {
delay = f.get();
} catch (Exception ix) {
Log.severe(ix);
return null;
}
if(delay)
try { Thread.sleep(50); } catch (InterruptedException ix) {}
}
return c;
}
@@ -788,6 +914,7 @@ public class MapManager {
sender.sendMessage(" TOTALS: processed=" + tot.loggedcnt + ", rendered=" + tot.renderedcnt +
", updated=" + tot.updatedcnt + ", transparent=" + tot.transparentcnt);
sender.sendMessage(" Cache hit rate: " + sscache.getHitRate() + "%");
sender.sendMessage(" Triggered update queue size: " + tileQueue.size());
}
/**
* Reset statistics
+4 -1
View File
@@ -10,7 +10,7 @@ import org.dynmap.utils.MapChunkCache;
public abstract class MapTile {
protected DynmapWorld world;
public abstract boolean render(MapChunkCache cache);
public abstract boolean render(MapChunkCache cache, String mapname);
public abstract List<DynmapChunk> getRequiredChunks();
public abstract MapTile[] getAdjecentTiles();
@@ -51,4 +51,7 @@ public abstract class MapTile {
public abstract boolean isRawBiomeDataNeeded();
public abstract boolean isBlockTypeDataNeeded();
public abstract int tileOrdinalX();
public abstract int tileOrdinalY();
}
+28 -4
View File
@@ -1,20 +1,41 @@
package org.dynmap;
import java.io.File;
import java.util.List;
import org.bukkit.Location;
import org.dynmap.utils.MapChunkCache;
import org.json.simple.JSONObject;
public abstract class MapType {
public enum ImageFormat {
FORMAT_PNG("png", "png", 0.0f),
FORMAT_JPG75("jpg-q75", "jpg", 0.75f),
FORMAT_JPG80("jpg-q80", "jpg", 0.80f),
FORMAT_JPG85("jpg-q85", "jpg", 0.85f),
FORMAT_JPG("jpg", "jpg", 0.85f),
FORMAT_JPG90("jpg-q90", "jpg", 0.90f),
FORMAT_JPG95("jpg-q95", "jpg", 0.95f),
FORMAT_JPG100("jpg-q100", "jpg", 1.00f);
String id;
String ext;
float qual;
ImageFormat(String id, String ext, float quality) {
this.id = id;
this.ext = ext;
this.qual = quality;
}
public String getID() { return id; }
public String getFileExt() { return ext; }
public float getQuality() { return qual; }
};
public abstract MapTile[] getTiles(Location l);
public abstract MapTile[] getTiles(Location l0, Location l1);
public abstract MapTile[] getAdjecentTiles(MapTile tile);
public abstract List<DynmapChunk> getRequiredChunks(MapTile tile);
public abstract boolean render(MapChunkCache cache, MapTile tile, File outputFile);
public void buildClientConfiguration(JSONObject worldObject, DynmapWorld w) {
}
@@ -41,6 +62,9 @@ public abstract class MapType {
public abstract boolean isBigWorldMap(DynmapWorld w);
/* Return number of zoom levels needed by this map (before extra levels from extrazoomout) */
public int getMapZoomOutLevels() { return 0; }
public ImageFormat getImageFormat() { return ImageFormat.FORMAT_PNG; }
/**
* Step sequence for creating zoomed file: first index is top-left, second top-right, third bottom-left, forth bottom-right
* Values correspond to tile X,Y (0), X+step,Y (1), X,Y+step (2), X+step,Y+step (3)
+139
View File
@@ -0,0 +1,139 @@
package org.dynmap;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import javax.imageio.ImageIO;
import org.bukkit.entity.Player;
import org.bukkit.event.Event.Type;
import org.bukkit.event.player.PlayerListener;
import org.bukkit.event.player.PlayerLoginEvent;
import org.dynmap.MapType.ImageFormat;
import org.dynmap.debug.Debug;
import org.dynmap.utils.DynmapBufferedImage;
import org.dynmap.utils.FileLockManager;
/**
* Listen for player logins, and process player faces by fetching skins *
*/
public class PlayerFaces {
private DynmapPlugin plugin;
private File facesdir;
private File faces8x8dir;
private File faces16x16dir;
private File faces32x32dir;
private class LoadPlayerImages implements Runnable {
public String playername;
public LoadPlayerImages(String playername) {
this.playername = playername;
}
public void run() {
BufferedImage img = null;
try {
URL url = new URL("http://s3.amazonaws.com/MinecraftSkins/" + playername + ".png");
img = ImageIO.read(url); /* Load skin for player */
} catch (IOException iox) {
Debug.debug("Error loading skin for '" + playername + "' - " + iox);
}
if(img == null) {
try {
InputStream in = getClass().getResourceAsStream("/char.png");
img = ImageIO.read(in); /* Load generic skin for player */
in.close();
} catch (IOException iox) {
Debug.debug("Error loading default skin for '" + playername + "' - " + iox);
}
}
if(img == null) { /* No image to process? Quit */
return;
}
int[] faceaccessory = new int[64]; /* 8x8 of face accessory */
/* Get buffered image for face at 8x8 */
DynmapBufferedImage face8x8 = DynmapBufferedImage.allocateBufferedImage(8, 8);
int[] bgcolor = new int[1];
img.getRGB(0, 0, 1, 1, bgcolor, 0, 1); /* Get BG color (for accessory face) */
img.getRGB(8, 8, 8, 8, face8x8.argb_buf, 0, 8); /* Read face from image */
img.getRGB(40, 8, 8, 8, faceaccessory, 0, 8); /* Read face accessory from image */
/* Apply accessory to face: first element is transparency color so only ones not matching it */
for(int i = 0; i < 64; i++) {
if(faceaccessory[i] != bgcolor[0])
face8x8.argb_buf[i] = faceaccessory[i];
else if(face8x8.argb_buf[i] == bgcolor[0])
face8x8.argb_buf[i] = 0;
}
/* Write 8x8 file */
File img_8x8 = new File(faces8x8dir, playername + ".png");
FileLockManager.getWriteLock(img_8x8);
try {
FileLockManager.imageIOWrite(face8x8.buf_img, ImageFormat.FORMAT_PNG, img_8x8);
} catch (IOException iox) {
Log.severe("Cannot write player icon " + img_8x8.getPath());
}
FileLockManager.releaseWriteLock(img_8x8);
/* Make 16x16 version */
DynmapBufferedImage face16x16 = DynmapBufferedImage.allocateBufferedImage(16, 16);
for(int i = 0; i < 16; i++) {
for(int j = 0; j < 16; j++) {
face16x16.argb_buf[i*16+j] = face8x8.argb_buf[(i/2)*8 + (j/2)];
}
}
/* Write 16x16 file */
File img_16x16 = new File(faces16x16dir, playername + ".png");
FileLockManager.getWriteLock(img_16x16);
try {
FileLockManager.imageIOWrite(face16x16.buf_img, ImageFormat.FORMAT_PNG, img_16x16);
} catch (IOException iox) {
Log.severe("Cannot write player icon " + img_16x16.getPath());
}
FileLockManager.releaseWriteLock(img_16x16);
DynmapBufferedImage.freeBufferedImage(face16x16);
/* Make 32x32 version */
DynmapBufferedImage face32x32 = DynmapBufferedImage.allocateBufferedImage(32, 32);
for(int i = 0; i < 32; i++) {
for(int j = 0; j < 32; j++) {
face32x32.argb_buf[i*32+j] = face8x8.argb_buf[(i/4)*8 + (j/4)];
}
}
/* Write 32x32 file */
File img_32x32 = new File(faces32x32dir, playername + ".png");
FileLockManager.getWriteLock(img_32x32);
try {
FileLockManager.imageIOWrite(face32x32.buf_img, ImageFormat.FORMAT_PNG, img_32x32);
} catch (IOException iox) {
Log.severe("Cannot write player icon " + img_32x32.getPath());
}
FileLockManager.releaseWriteLock(img_32x32);
DynmapBufferedImage.freeBufferedImage(face32x32);
DynmapBufferedImage.freeBufferedImage(face8x8);
/* TODO: signal update for player icon to client */
}
}
private class LoginListener extends PlayerListener {
@Override
public void onPlayerLogin(PlayerLoginEvent event) {
MapManager.scheduleDelayedJob(new LoadPlayerImages(event.getPlayer().getName()), 0);
}
}
public PlayerFaces(DynmapPlugin plugin) {
this.plugin = plugin;
plugin.registerEvent(Type.PLAYER_LOGIN, new LoginListener());
facesdir = new File(plugin.tilesDirectory, "faces");
facesdir.mkdirs(); /* Make sure directory exists */
faces8x8dir = new File(facesdir, "8x8");
faces8x8dir.mkdirs();
faces16x16dir = new File(facesdir, "16x16");
faces16x16dir.mkdirs();
faces32x32dir = new File(facesdir, "32x32");
faces32x32dir.mkdirs();
}
}
@@ -32,11 +32,10 @@ public class SimpleWebChatComponent extends Component {
if (configuration.getBoolean("allowchat", false)) {
PlayerChatListener playerListener = new PlayerChatListener();
PluginManager pm = plugin.getServer().getPluginManager();
pm.registerEvent(org.bukkit.event.Event.Type.PLAYER_CHAT, playerListener, org.bukkit.event.Event.Priority.Monitor, plugin);
pm.registerEvent(org.bukkit.event.Event.Type.PLAYER_LOGIN, playerListener, org.bukkit.event.Event.Priority.Monitor, plugin);
pm.registerEvent(org.bukkit.event.Event.Type.PLAYER_JOIN, playerListener, org.bukkit.event.Event.Priority.Monitor, plugin);
pm.registerEvent(org.bukkit.event.Event.Type.PLAYER_QUIT, playerListener, org.bukkit.event.Event.Priority.Monitor, plugin);
plugin.registerEvent(org.bukkit.event.Event.Type.PLAYER_CHAT, playerListener);
plugin.registerEvent(org.bukkit.event.Event.Type.PLAYER_LOGIN, playerListener);
plugin.registerEvent(org.bukkit.event.Event.Type.PLAYER_JOIN, playerListener);
plugin.registerEvent(org.bukkit.event.Event.Type.PLAYER_QUIT, playerListener);
}
}
+53 -9
View File
@@ -9,8 +9,6 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.imageio.ImageIO;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.World.Environment;
@@ -23,9 +21,7 @@ import org.dynmap.MapManager;
import org.dynmap.TileHashManager;
import org.dynmap.MapTile;
import org.dynmap.MapType;
import org.dynmap.MapType.MapStep;
import org.dynmap.debug.Debug;
import org.dynmap.kzedmap.KzedMap;
import org.dynmap.utils.DynmapBufferedImage;
import org.dynmap.utils.FileLockManager;
import org.dynmap.utils.MapChunkCache;
@@ -95,6 +91,35 @@ public class FlatMap extends MapType {
return new MapTile[] { new FlatMapTile(w, this, (int) Math.floor(l.getBlockX() / 128.0), (int) Math.floor(l.getBlockZ() / 128.0), 128) };
}
@Override
public MapTile[] getTiles(Location l0, Location l1) {
DynmapWorld w = MapManager.mapman.getWorld(l0.getWorld().getName());
int xmin, xmax, zmin, zmax;
if(l0.getBlockX() < l1.getBlockX()) {
xmin = l0.getBlockX() >> 7;
xmax = l1.getBlockX() >> 7;
}
else {
xmin = l1.getBlockX() >> 7;
xmax = l0.getBlockX() >> 7;
}
if(l0.getBlockZ() < l1.getBlockZ()) {
zmin = l0.getBlockZ() >> 7;
zmax = l1.getBlockZ() >> 7;
}
else {
zmin = l1.getBlockZ() >> 7;
zmax = l0.getBlockZ() >> 7;
}
ArrayList<MapTile> rslt = new ArrayList<MapTile>();
for(int i = xmin; i <= xmax; i++) {
for(int j = zmin; j < zmax; j++) {
rslt.add(new FlatMapTile(w, this, i, j, 128));
}
}
return rslt.toArray(new MapTile[rslt.size()]);
}
@Override
public MapTile[] getAdjecentTiles(MapTile tile) {
FlatMapTile t = (FlatMapTile) tile;
@@ -124,7 +149,6 @@ public class FlatMap extends MapType {
return result;
}
@Override
public boolean render(MapChunkCache cache, MapTile tile, File outputFile) {
FlatMapTile t = (FlatMapTile) tile;
World w = t.getWorld();
@@ -284,7 +308,7 @@ public class FlatMap extends MapType {
if(!outputFile.getParentFile().exists())
outputFile.getParentFile().mkdirs();
try {
FileLockManager.imageIOWrite(im.buf_img, "png", outputFile);
FileLockManager.imageIOWrite(im.buf_img, ImageFormat.FORMAT_PNG, outputFile);
} catch (IOException e) {
Debug.error("Failed to save image: " + outputFile.getPath(), e);
} catch (java.lang.NullPointerException e) {
@@ -315,7 +339,7 @@ public class FlatMap extends MapType {
if(!dayfile.getParentFile().exists())
dayfile.getParentFile().mkdirs();
try {
FileLockManager.imageIOWrite(im_day.buf_img, "png", dayfile);
FileLockManager.imageIOWrite(im_day.buf_img, ImageFormat.FORMAT_PNG, dayfile);
} catch (IOException e) {
Debug.error("Failed to save image: " + dayfile.getPath(), e);
} catch (java.lang.NullPointerException e) {
@@ -419,7 +443,7 @@ public class FlatMap extends MapType {
public String getPrefix() {
return prefix;
}
/* Get maps rendered concurrently with this map in this world */
public List<MapType> getMapsSharingRender(DynmapWorld w) {
return Collections.singletonList((MapType)this);
@@ -496,7 +520,7 @@ public class FlatMap extends MapType {
}
@Override
public boolean render(MapChunkCache cache) {
public boolean render(MapChunkCache cache, String mapname) {
return map.render(cache, this, MapManager.mapman.getTileFile(this));
}
@@ -510,6 +534,22 @@ public class FlatMap extends MapType {
return map.getAdjecentTiles(this);
}
@Override
public int hashCode() {
return x ^ y ^ size ^ map.getName().hashCode();
}
@Override
public boolean equals(Object x) {
if(x instanceof FlatMapTile) {
return equals((FlatMapTile)x);
}
return false;
}
public boolean equals(FlatMapTile o) {
return (o.x == x) && (o.y == y) && (o.map == map);
}
@Override
public String getKey() {
return world.world.getName() + "." + map.getPrefix();
@@ -519,6 +559,9 @@ public class FlatMap extends MapType {
public boolean isBiomeDataNeeded() { return false; }
public boolean isRawBiomeDataNeeded() { return false; }
public boolean isBlockTypeDataNeeded() { return true; }
public int tileOrdinalX() { return x; }
public int tileOrdinalY() { return y; }
}
@Override
@@ -538,6 +581,7 @@ public class FlatMap extends MapType {
s(o, "mapzoomin", c.getInteger("mapzoomin", 3));
s(o, "mapzoomout", world.getExtraZoomOutLevels());
s(o, "compassview", "S"); /* Always from south */
s(o, "image-format", ImageFormat.FORMAT_PNG.getFileExt());
a(worldObject, "maps", o);
}
}
+27 -9
View File
@@ -19,6 +19,7 @@ import org.dynmap.utils.MapChunkCache;
import org.json.simple.JSONObject;
public class HDMap extends MapType {
private String name;
private String prefix;
private HDPerspective perspective;
@@ -26,6 +27,11 @@ public class HDMap extends MapType {
private HDLighting lighting;
private ConfigurationNode configuration;
private int mapzoomout;
private MapType.ImageFormat imgformat;
public static final String IMGFORMAT_PNG = "png";
public static final String IMGFORMAT_JPG = "jpg";
public HDMap(ConfigurationNode configuration) {
name = configuration.getString("name", null);
@@ -83,7 +89,19 @@ public class HDMap extends MapType {
mapzoomout++;
scale = scale / 2.0;
}
}
String fmt = configuration.getString("image-format", "png");
/* Only allow png or jpg */
for(ImageFormat f : ImageFormat.values()) {
if(fmt.equals(f.getID())) {
imgformat = f;
break;
}
}
if(imgformat == null) {
Log.severe("HDMap '"+name+"' set invalid image-format: " + fmt);
imgformat = ImageFormat.FORMAT_PNG;
}
}
public HDShader getShader() { return shader; }
public HDPerspective getPerspective() { return perspective; }
@@ -94,6 +112,11 @@ public class HDMap extends MapType {
return perspective.getTiles(loc);
}
@Override
public MapTile[] getTiles(Location loc0, Location loc1) {
return perspective.getTiles(loc0, loc1);
}
@Override
public MapTile[] getAdjecentTiles(MapTile tile) {
return perspective.getAdjecentTiles(tile);
@@ -104,14 +127,6 @@ public class HDMap extends MapType {
return perspective.getRequiredChunks(tile);
}
@Override
public boolean render(MapChunkCache cache, MapTile tile, File bogus) {
if(tile instanceof HDMapTile)
return perspective.render(cache, (HDMapTile)tile);
else
return false;
}
@Override
public List<String> baseZoomFilePrefixes() {
ArrayList<String> s = new ArrayList<String>();
@@ -181,6 +196,8 @@ public class HDMap extends MapType {
return lst;
}
@Override
public ImageFormat getImageFormat() { return imgformat; }
@Override
public void buildClientConfiguration(JSONObject worldObject, DynmapWorld world) {
@@ -197,6 +214,7 @@ public class HDMap extends MapType {
s(o, "bigmap", true);
s(o, "mapzoomout", (world.getExtraZoomOutLevels()+mapzoomout));
s(o, "mapzoomin", c.getInteger("mapzoomin", 2));
s(o, "image-format", imgformat.getFileExt());
perspective.addClientConfiguration(o);
shader.addClientConfiguration(o);
lighting.addClientConfiguration(o);
@@ -119,7 +119,7 @@ public class HDMapManager {
/**
* Initialize shader states for all shaders for given tile
*/
public HDShaderState[] getShaderStateForTile(HDMapTile tile, MapChunkCache cache, MapIterator mapiter) {
public HDShaderState[] getShaderStateForTile(HDMapTile tile, MapChunkCache cache, MapIterator mapiter, String mapname) {
DynmapWorld w = MapManager.mapman.worldsLookup.get(tile.getWorld().getName());
if(w == null) return new HDShaderState[0];
ArrayList<HDShaderState> shaders = new ArrayList<HDShaderState>();
@@ -127,6 +127,9 @@ public class HDMapManager {
if(map instanceof HDMap) {
HDMap hdmap = (HDMap)map;
if(hdmap.getPerspective() == tile.perspective) {
/* If limited to one map, and this isn't it, skip */
if((mapname != null) && (!hdmap.getName().equals(mapname)))
continue;
shaders.add(hdmap.getShader().getStateInstance(hdmap, cache, mapiter));
}
}
+16 -11
View File
@@ -3,6 +3,7 @@ package org.dynmap.hdmap;
import org.dynmap.DynmapChunk;
import org.dynmap.DynmapWorld;
import org.dynmap.MapManager;
import org.dynmap.MapType;
import java.util.List;
import org.dynmap.MapTile;
@@ -21,25 +22,25 @@ public class HDMapTile extends MapTile {
@Override
public String getFilename() {
return getFilename("hdmap");
return getFilename("hdmap", MapType.ImageFormat.FORMAT_PNG);
}
public String getFilename(String prefix) {
return prefix + "/" + (tx >> 5) + '_' + (ty >> 5) + '/' + tx + "_" + ty + ".png";
public String getFilename(String prefix, MapType.ImageFormat format) {
return prefix + "/" + (tx >> 5) + '_' + (ty >> 5) + '/' + tx + "_" + ty + "." + format.getFileExt();
}
@Override
public String getDayFilename() {
return getDayFilename("hdmap");
return getDayFilename("hdmap", MapType.ImageFormat.FORMAT_PNG);
}
public String getDayFilename(String prefix) {
return prefix + "_day/" + (tx >> 5) + '_' + (ty >> 5) + '/' + tx + "_" + ty + ".png";
public String getDayFilename(String prefix, MapType.ImageFormat format) {
return prefix + "_day/" + (tx >> 5) + '_' + (ty >> 5) + '/' + tx + "_" + ty + "." + format.getFileExt();
}
@Override
public int hashCode() {
return perspective.getName().hashCode() ^ getWorld().hashCode();
return tx ^ ty ^ perspective.getName().hashCode() ^ getWorld().getName().hashCode();
}
@Override
@@ -47,11 +48,11 @@ public class HDMapTile extends MapTile {
if (obj instanceof HDMapTile) {
return equals((HDMapTile) obj);
}
return super.equals(obj);
return false;
}
public boolean equals(HDMapTile o) {
return o.tx == tx && o.ty == ty && o.getWorld().equals(getWorld()) && (perspective.equals(o.perspective));
return o.tx == tx && o.ty == ty && (perspective == o.perspective) && (o.getWorld() == getWorld());
}
public String getKey() {
@@ -75,8 +76,8 @@ public class HDMapTile extends MapTile {
@Override
public boolean isBlockTypeDataNeeded() { return MapManager.mapman.hdmapman.isBlockTypeDataNeeded(this); }
public boolean render(MapChunkCache cache) {
return perspective.render(cache, this);
public boolean render(MapChunkCache cache, String mapname) {
return perspective.render(cache, this, mapname);
}
public List<DynmapChunk> getRequiredChunks() {
@@ -86,4 +87,8 @@ public class HDMapTile extends MapTile {
public MapTile[] getAdjecentTiles() {
return perspective.getAdjecentTiles(this);
}
public int tileOrdinalX() { return tx; }
public int tileOrdinalY() { return ty; }
}
@@ -13,12 +13,14 @@ public interface HDPerspective {
String getName();
/* Get tiles invalidated by change at given location */
MapTile[] getTiles(Location loc);
/* Get tiles invalidated by change at given volume, defined by 2 opposite corner locations */
MapTile[] getTiles(Location loc0, Location loc1);
/* Get tiles adjacent to given tile */
MapTile[] getAdjecentTiles(MapTile tile);
/* Get chunks needed for given tile */
List<DynmapChunk> getRequiredChunks(MapTile tile);
/* Render given tile */
boolean render(MapChunkCache cache, HDMapTile tile);
boolean render(MapChunkCache cache, HDMapTile tile, String mapname);
public boolean isBiomeDataNeeded();
public boolean isHightestBlockYDataNeeded();
@@ -21,6 +21,7 @@ import org.dynmap.DynmapChunk;
import org.dynmap.Log;
import org.dynmap.MapManager;
import org.dynmap.MapTile;
import org.dynmap.MapType;
import org.dynmap.TileHashManager;
import org.dynmap.debug.Debug;
import org.dynmap.utils.MapIterator.BlockStep;
@@ -242,8 +243,6 @@ public class IsoHDPerspective implements HDPerspective {
t = 0;
/* Compute number of steps and increments for each */
n = 1;
int mxout, myout, mzout;
/* If perpendicular to X axis */
if (dx == 0) {
@@ -552,9 +551,11 @@ public class IsoHDPerspective implements HDPerspective {
}
}
private boolean logit = false;
private boolean raytraceSubblock(short[] model, boolean firsttime) {
if(firsttime) {
mt = t + 0.0000001;
mt = t + 0.00000001;
xx = top.x + mt *(bottom.x - top.x);
yy = top.y + mt *(bottom.y - top.y);
zz = top.z + mt *(bottom.z - top.z);
@@ -583,7 +584,7 @@ public class IsoHDPerspective implements HDPerspective {
}
subalpha = -1;
boolean skip = !firsttime; /* Skip first block on continue */
while(mt < mtend) {
while(mt <= mtend) {
if(!skip) {
try {
int blkalpha = model[modscale*modscale*my + modscale*mz + mx];
@@ -605,8 +606,9 @@ public class IsoHDPerspective implements HDPerspective {
mt = mt_next_x;
mt_next_x += mdt_dx;
laststep = stepx;
if(mx == mxout)
if(mx == mxout) {
return true;
}
}
/* If Y step is next best */
else if((mt_next_y <= mt_next_x) && (mt_next_y <= mt_next_z)) {
@@ -614,8 +616,9 @@ public class IsoHDPerspective implements HDPerspective {
mt = mt_next_y;
mt_next_y += mdt_dy;
laststep = stepy;
if(my == myout)
if(my == myout) {
return true;
}
}
/* Else, Z step is next best */
else {
@@ -623,22 +626,28 @@ public class IsoHDPerspective implements HDPerspective {
mt = mt_next_z;
mt_next_z += mdt_dz;
laststep = stepz;
if(mz == mzout)
if(mz == mzout) {
return true;
}
}
}
return true;
}
public final int[] getSubblockCoord() {
double tt = t + 0.000001;
if(subalpha >= 0)
tt = mt;
double xx = top.x + tt * (bottom.x - top.x);
double yy = top.y + tt * (bottom.y - top.y);
double zz = top.z + tt * (bottom.z - top.z);
subblock_xyz[0] = (int)((xx - Math.floor(xx)) * modscale);
subblock_xyz[1] = (int)((yy - Math.floor(yy)) * modscale);
subblock_xyz[2] = (int)((zz - Math.floor(zz)) * modscale);
if(subalpha < 0) {
double tt = t + 0.0000001;
double xx = top.x + tt * (bottom.x - top.x);
double yy = top.y + tt * (bottom.y - top.y);
double zz = top.z + tt * (bottom.z - top.z);
subblock_xyz[0] = (int)((xx - Math.floor(xx)) * modscale);
subblock_xyz[1] = (int)((yy - Math.floor(yy)) * modscale);
subblock_xyz[2] = (int)((zz - Math.floor(zz)) * modscale);
}
else {
subblock_xyz[0] = mx;
subblock_xyz[1] = my;
subblock_xyz[2] = mz;
}
return subblock_xyz;
}
}
@@ -717,6 +726,68 @@ public class IsoHDPerspective implements HDPerspective {
return tiles.toArray(new MapTile[tiles.size()]);
}
@Override
public MapTile[] getTiles(Location loc0, Location loc1) {
DynmapWorld world = MapManager.mapman.getWorld(loc0.getWorld().getName());
HashSet<MapTile> tiles = new HashSet<MapTile>();
Vector3D blocks[] = new Vector3D[] { new Vector3D(), new Vector3D() };
/* Get ordered point - 0=minX,Y,Z, 1=maxX,Y,Z */
if(loc0.getBlockX() < loc1.getBlockX()) {
blocks[0].x = loc0.getBlockX();
blocks[1].x = loc1.getBlockX() + 1;
}
else {
blocks[0].x = loc1.getBlockX();
blocks[1].x = loc0.getBlockX() + 1;
}
if(loc0.getBlockY() < loc1.getBlockY()) {
blocks[0].y = loc0.getBlockY();
blocks[1].y = loc1.getBlockY() + 1;
}
else {
blocks[0].y = loc1.getBlockY();
blocks[1].y = loc0.getBlockY() + 1;
}
if(loc0.getBlockZ() < loc1.getBlockZ()) {
blocks[0].z = loc0.getBlockZ();
blocks[1].z = loc1.getBlockZ() + 1;
}
else {
blocks[0].z = loc1.getBlockZ();
blocks[1].z = loc0.getBlockZ() + 1;
}
Vector3D corner = new Vector3D();
Vector3D tcorner = new Vector3D();
int mintilex = Integer.MAX_VALUE;
int maxtilex = Integer.MIN_VALUE;
int mintiley = Integer.MAX_VALUE;
int maxtiley = Integer.MIN_VALUE;
/* Loop through corners of the prism */
for(int i = 0; i < 2; i++) {
corner.x = blocks[i].x;
for(int j = 0; j < 2; j++) {
corner.y = blocks[j].y;
for(int k = 0; k < 2; k++) {
corner.z = blocks[k].z;
world_to_map.transform(corner, tcorner); /* Get map coordinate of corner */
int tx = (int)Math.floor(tcorner.x/tileWidth);
int ty = (int)Math.floor(tcorner.y/tileWidth);
if(mintilex > tx) mintilex = tx;
if(maxtilex < tx) maxtilex = tx;
if(mintiley > ty) mintiley = ty;
if(maxtiley < ty) maxtiley = ty;
}
}
}
/* Now, add the tiles for the ranges - not perfect, but it works (some extra tiles on corners possible) */
for(int i = mintilex; i <= maxtilex; i++) {
for(int j = mintiley; j <= maxtiley; j++) {
addTile(tiles, world, i, j);
}
}
return tiles.toArray(new MapTile[tiles.size()]);
}
@Override
public MapTile[] getAdjecentTiles(MapTile tile) {
HDMapTile t = (HDMapTile) tile;
@@ -879,11 +950,11 @@ public class IsoHDPerspective implements HDPerspective {
}
@Override
public boolean render(MapChunkCache cache, HDMapTile tile) {
public boolean render(MapChunkCache cache, HDMapTile tile, String mapname) {
Color rslt = new Color();
MapIterator mapiter = cache.getIterator(0, 0, 0);
/* Build shader state object for each shader */
HDShaderState[] shaderstate = MapManager.mapman.hdmapman.getShaderStateForTile(tile, cache, mapiter);
HDShaderState[] shaderstate = MapManager.mapman.hdmapman.getShaderStateForTile(tile, cache, mapiter, mapname);
int numshaders = shaderstate.length;
if(numshaders == 0)
return false;
@@ -959,7 +1030,8 @@ public class IsoHDPerspective implements HDPerspective {
String prefix = shaderstate[i].getMap().getPrefix();
if(rendered[i]) {
renderone = true;
String fname = tile.getFilename(prefix);
MapType.ImageFormat fmt = shaderstate[i].getMap().getImageFormat();
String fname = tile.getFilename(prefix, fmt);
File f = new File(tile.getDynmapWorld().worldtilepath, fname);
FileLockManager.getWriteLock(f);
try {
@@ -969,7 +1041,7 @@ public class IsoHDPerspective implements HDPerspective {
if(!f.getParentFile().exists())
f.getParentFile().mkdirs();
try {
FileLockManager.imageIOWrite(im[i].buf_img, "png", f);
FileLockManager.imageIOWrite(im[i].buf_img, fmt, f);
} catch (IOException e) {
Debug.error("Failed to save image: " + f.getPath(), e);
} catch (java.lang.NullPointerException e) {
@@ -990,7 +1062,7 @@ public class IsoHDPerspective implements HDPerspective {
MapManager.mapman.updateStatistics(tile, prefix, true, tile_update, !rendered[i]);
/* Handle day image, if needed */
if(dayim[i] != null) {
fname = tile.getDayFilename(prefix);
fname = tile.getDayFilename(prefix, fmt);
f = new File(tile.getDynmapWorld().worldtilepath, fname);
FileLockManager.getWriteLock(f);
prefix = prefix+"_day";
@@ -1002,7 +1074,7 @@ public class IsoHDPerspective implements HDPerspective {
if(!f.getParentFile().exists())
f.getParentFile().mkdirs();
try {
FileLockManager.imageIOWrite(dayim[i].buf_img, "png", f);
FileLockManager.imageIOWrite(dayim[i].buf_img, fmt, f);
} catch (IOException e) {
Debug.error("Failed to save image: " + f.getPath(), e);
} catch (java.lang.NullPointerException e) {
+115 -35
View File
@@ -54,6 +54,7 @@ public class TexturePack {
private static final String CUSTOMWATERSTILL_PNG = "custom_water_still.png";
private static final String CUSTOMWATERFLOWING_PNG = "custom_water_flowing.png";
private static final String STANDARDTP = "standard";
/* Color modifier codes (x1000 for value in mapping code) */
private static final int COLORMOD_NONE = 0;
private static final int COLORMOD_GRASSTONED = 1;
@@ -71,6 +72,8 @@ public class TexturePack {
/* Special tile index values */
private static final int BLOCKINDEX_BLANK = -1;
private static final int BLOCKINDEX_GRASSMASK = 38;
private static final int BLOCKINDEX_PISTONSIDE = 108;
private static final int BLOCKINDEX_REDSTONE_NSEW_TONE = 164;
private static final int BLOCKINDEX_REDSTONE_EW_TONE = 165;
private static final int BLOCKINDEX_REDSTONE_NSEW = 180;
@@ -79,7 +82,9 @@ public class TexturePack {
private static final int BLOCKINDEX_MOVINGWATER = 258;
private static final int BLOCKINDEX_STATIONARYLAVA = 259;
private static final int BLOCKINDEX_MOVINGLAVA = 260;
private static final int MAX_BLOCKINDEX = 260;
private static final int BLOCKINDEX_PISTONEXTSIDE = 261;
private static final int BLOCKINDEX_PISTONSIDE_EXT = 262;
private static final int MAX_BLOCKINDEX = 262;
private static final int BLOCKTABLELEN = MAX_BLOCKINDEX+1;
private static class LoadedImage {
@@ -190,36 +195,57 @@ public class TexturePack {
/* Try to open zip */
zf = new ZipFile(f);
/* Find and load terrain.png */
InputStream is;
ZipEntry ze = zf.getEntry(TERRAIN_PNG); /* Try to find terrain.png */
if(ze == null) {
throw new FileNotFoundException();
/* Check for terrain.png under standard texture pack*/
File ff = new File(texturedir, STANDARDTP + "/" + TERRAIN_PNG);
is = new FileInputStream(ff);
}
else {
is = zf.getInputStream(ze); /* Get input stream for terrain.png */
}
InputStream is = zf.getInputStream(ze); /* Get input stream for terrain.png */
loadTerrainPNG(is);
is.close();
/* Try to find and load misc/grasscolor.png */
ze = zf.getEntry(GRASSCOLOR_PNG);
if(ze == null)
throw new FileNotFoundException();
is = zf.getInputStream(ze);
loadBiomeShadingImage(is, IMG_GRASSCOLOR);
is.close();
if(ze == null) { /* Fall back to standard file */
/* Check for misc/grasscolor.png under standard texture pack*/
File ff = new File(texturedir, STANDARDTP + "/" + GRASSCOLOR_PNG);
is = new FileInputStream(ff);
}
else {
is = zf.getInputStream(ze);
}
loadBiomeShadingImage(is, IMG_GRASSCOLOR);
is.close();
/* Try to find and load misc/foliagecolor.png */
ze = zf.getEntry(FOLIAGECOLOR_PNG);
if(ze == null)
throw new FileNotFoundException();
is = zf.getInputStream(ze);
loadBiomeShadingImage(is, IMG_FOLIAGECOLOR);
is.close();
if(ze == null) {
/* Check for misc/foliagecolor.png under standard texture pack*/
File ff = new File(texturedir, STANDARDTP + "/" + FOLIAGECOLOR_PNG);
is = new FileInputStream(ff);
}
else {
is = zf.getInputStream(ze);
}
loadBiomeShadingImage(is, IMG_FOLIAGECOLOR);
is.close();
/* Try to find and load misc/water.png */
ze = zf.getEntry(WATER_PNG);
if(ze == null)
throw new FileNotFoundException();
is = zf.getInputStream(ze);
loadImage(is, IMG_WATER);
if(ze == null) {
File ff = new File(texturedir, STANDARDTP + "/" + WATER_PNG);
is = new FileInputStream(ff);
}
else {
is = zf.getInputStream(ze);
}
loadImage(is, IMG_WATER);
patchTextureWithImage(IMG_WATER, BLOCKINDEX_STATIONARYWATER);
patchTextureWithImage(IMG_WATER, BLOCKINDEX_MOVINGWATER);
is.close();
is.close();
/* Optional files - process if they exist */
ze = zf.getEntry(CUSTOMLAVAFLOWING_PNG);
if(ze != null) {
@@ -258,21 +284,33 @@ public class TexturePack {
try {
/* Open and load terrain.png */
f = new File(texturedir, tpname + "/" + TERRAIN_PNG);
if(!f.canRead()) {
f = new File(texturedir, STANDARDTP + "/" + TERRAIN_PNG);
}
fis = new FileInputStream(f);
loadTerrainPNG(fis);
fis.close();
/* Check for misc/grasscolor.png */
f = new File(texturedir, tpname + "/" + GRASSCOLOR_PNG);
if(!f.canRead()) {
f = new File(texturedir, STANDARDTP + "/" + GRASSCOLOR_PNG);
}
fis = new FileInputStream(f);
loadBiomeShadingImage(fis, IMG_GRASSCOLOR);
fis.close();
/* Check for misc/foliagecolor.png */
f = new File(texturedir, tpname + "/" + FOLIAGECOLOR_PNG);
if(!f.canRead()) {
f = new File(texturedir, STANDARDTP + "/" + FOLIAGECOLOR_PNG);
}
fis = new FileInputStream(f);
loadBiomeShadingImage(fis, IMG_FOLIAGECOLOR);
fis.close();
/* Check for misc/water.png */
f = new File(texturedir, tpname + "/" + WATER_PNG);
if(!f.canRead()) {
f = new File(texturedir, STANDARDTP + "/" + WATER_PNG);
}
fis = new FileInputStream(f);
loadImage(fis, IMG_WATER);
patchTextureWithImage(IMG_WATER, BLOCKINDEX_STATIONARYWATER);
@@ -329,8 +367,9 @@ public class TexturePack {
/* Load terrain.png */
private void loadTerrainPNG(InputStream is) throws IOException {
int i;
int i, j;
/* Load image */
ImageIO.setUseCache(false);
BufferedImage img = ImageIO.read(is);
if(img == null) { throw new FileNotFoundException(); }
terrain_width = img.getWidth();
@@ -364,12 +403,34 @@ public class TexturePack {
terrain_argb[BLOCKINDEX_REDSTONE_EW][i] = tc.getARGB();
}
}
/* Build extended piston side texture - take top 1/4 of piston side, use to make piston extension */
terrain_argb[BLOCKINDEX_PISTONEXTSIDE] = new int[native_scale*native_scale];
System.arraycopy(terrain_argb[BLOCKINDEX_PISTONSIDE], 0, terrain_argb[BLOCKINDEX_PISTONEXTSIDE], 0,
native_scale * native_scale / 4);
for(i = 0; i < native_scale/4; i++) {
for(j = 0; j < (3*native_scale/4); j++) {
terrain_argb[BLOCKINDEX_PISTONEXTSIDE][native_scale*(native_scale/4 + j) + (3*native_scale/8 + i)] =
terrain_argb[BLOCKINDEX_PISTONSIDE][native_scale*i + j];
}
}
/* Build piston side while extended (cut off top 1/4, replace with rotated top for extension */
terrain_argb[BLOCKINDEX_PISTONSIDE_EXT] = new int[native_scale*native_scale];
System.arraycopy(terrain_argb[BLOCKINDEX_PISTONSIDE], native_scale*native_scale/4,
terrain_argb[BLOCKINDEX_PISTONSIDE_EXT], native_scale*native_scale/4,
3 * native_scale * native_scale / 4); /* Copy bottom 3/4 */
for(i = 0; i < native_scale/4; i++) {
for(j = 3*native_scale/4; j < native_scale; j++) {
terrain_argb[BLOCKINDEX_PISTONSIDE_EXT][native_scale*(j - 3*native_scale/4) + (3*native_scale/8 + i)] =
terrain_argb[BLOCKINDEX_PISTONSIDE][native_scale*i + j];
}
}
img.flush();
}
/* Load image into image array */
private void loadImage(InputStream is, int idx) throws IOException {
/* Load image */
ImageIO.setUseCache(false);
BufferedImage img = ImageIO.read(is);
if(img == null) { throw new FileNotFoundException(); }
imgs[idx] = new LoadedImage();
@@ -451,6 +512,8 @@ public class TexturePack {
tp.terrain_argb[idx] = new int[tp.native_scale*tp.native_scale];
scaleTerrainPNGSubImage(native_scale, tp.native_scale, terrain_argb[idx], tp.terrain_argb[idx]);
}
/* Special case - some textures are used as masks - need pure alpha (00 or FF) */
makeAlphaPure(tp.terrain_argb[BLOCKINDEX_GRASSMASK]); /* Grass side mask */
}
private static void scaleTerrainPNGSubImage(int srcscale, int destscale, int[] src_argb, int[] dest_argb) {
int nativeres = srcscale;
@@ -499,15 +562,18 @@ public class TexturePack {
if(wy == 0) continue;
/* Accumulate */
c.setARGB(src_argb[(ind_y+yy)*nativeres + ind_x + xx]);
accum_red += c.getRed() * wx * wy;
accum_green += c.getGreen() * wx * wy;
accum_blue += c.getBlue() * wx * wy;
accum_alpha += c.getAlpha() * wx * wy;
int a = c.getAlpha();
accum_red += c.getRed() * a * wx * wy;
accum_green += c.getGreen() * a* wx * wy;
accum_blue += c.getBlue() * a * wx * wy;
accum_alpha += a * wx * wy;
}
}
int newalpha = accum_alpha / (nativeres*nativeres);
if(newalpha == 0) newalpha = 1;
/* Generate weighted compnents into color */
c.setRGBA(accum_red / (nativeres*nativeres), accum_green / (nativeres*nativeres),
accum_blue / (nativeres*nativeres), accum_alpha / (nativeres*nativeres));
c.setRGBA(accum_red / (nativeres*nativeres*newalpha), accum_green / (nativeres*nativeres*newalpha),
accum_blue / (nativeres*nativeres*newalpha), accum_alpha / (nativeres*nativeres));
dest_argb[(y*res) + x] = c.getARGB();
}
}
@@ -548,10 +614,11 @@ public class TexturePack {
for(int yy = 0; yy < 2; yy++) {
int wy = (yy==0)?wgt_y:(res-wgt_y);
if(wy == 0) continue;
accum_red[(ind_y+yy)*res + (ind_x+xx)] += c.getRed() * wx * wy;
accum_green[(ind_y+yy)*res + (ind_x+xx)] += c.getGreen() * wx * wy;
accum_blue[(ind_y+yy)*res + (ind_x+xx)] += c.getBlue() * wx * wy;
accum_alpha[(ind_y+yy)*res + (ind_x+xx)] += c.getAlpha() * wx * wy;
int a = c.getAlpha();
accum_red[(ind_y+yy)*res + (ind_x+xx)] += c.getRed() * a * wx * wy;
accum_green[(ind_y+yy)*res + (ind_x+xx)] += c.getGreen() * a * wx * wy;
accum_blue[(ind_y+yy)*res + (ind_x+xx)] += c.getBlue() * a * wx * wy;
accum_alpha[(ind_y+yy)*res + (ind_x+xx)] += a * wx * wy;
}
}
}
@@ -560,8 +627,10 @@ public class TexturePack {
for(int y = 0; y < res; y++) {
for(int x = 0; x < res; x++) {
int off = (y*res) + x;
c.setRGBA(accum_red[off]/(nativeres*nativeres), accum_green[off]/(nativeres*nativeres),
accum_blue[off]/(nativeres*nativeres), accum_alpha[off]/(nativeres*nativeres));
int aa = accum_alpha[off] / (nativeres*nativeres);
if(aa == 0) aa = 1;
c.setRGBA(accum_red[off]/(aa*nativeres*nativeres), accum_green[off]/(aa*nativeres*nativeres),
accum_blue[off]/(aa*nativeres*nativeres), accum_alpha[off] / (nativeres*nativeres));
dest_argb[y*res + x] = c.getARGB();
}
}
@@ -575,6 +644,7 @@ public class TexturePack {
}
}
BufferedImage img = DynmapBufferedImage.createBufferedImage(outbuf, terrain_width, terrain_height);
ImageIO.setUseCache(false);
ImageIO.write(img, "png", f);
}
@@ -847,9 +917,9 @@ public class TexturePack {
textid = 68;
}
else { /* Else, check the grass color overlay */
int ovclr = terrain_argb[38][v*native_scale+u];
int ovclr = terrain_argb[BLOCKINDEX_GRASSMASK][v*native_scale+u];
if((ovclr & 0xFF000000) != 0) { /* Hit? */
texture = terrain_argb[38]; /* Use it */
texture = terrain_argb[BLOCKINDEX_GRASSMASK]; /* Use it */
textop = COLORMOD_GRASSTONED; /* Force grass toning */
}
}
@@ -885,8 +955,18 @@ public class TexturePack {
}
private static final int biomeLookup(int[] argb, int width, double rainfall, double temp) {
int t = (int)((1.0-temp)*(width-1));
int h = width - (int)(temp*rainfall*(width-1)) - 1;
int w = width-1;
int t = (int)((1.0-temp)*w);
int h = (int)((1.0 - (temp*rainfall))*w);
if(h > w) h = w;
if(t > w) t = w;
return argb[width*h + t];
}
private static final void makeAlphaPure(int[] argb) {
for(int i = 0; i < argb.length; i++) {
if((argb[i] & 0xFF000000) != 0)
argb[i] |= 0xFF000000;
}
}
}
@@ -131,6 +131,7 @@ public class TexturePackHDShader implements HDShader {
if(blocktype == 0) {
return false;
}
/* Get color from textures */
scaledtp.readColor(ps, mapiter, c, blocktype, lastblocktype, do_biome_shading);
@@ -155,13 +156,14 @@ public class TexturePackHDShader implements HDShader {
/* Handle light level, if needed */
lighting.applyLighting(ps, this, c, tmpcolor);
/* If we got alpha from subblock model, use it instead if it is lower */
if(subalpha >= 0) {
for(Color clr : tmpcolor) {
int a = clr.getAlpha();
if(subalpha < a)
clr.setAlpha(subalpha);
}
}
/* (disable for now: weighting is wrong, as crosssection is 2D, not 3D based) */
// if(subalpha >= 0) {
// for(Color clr : tmpcolor) {
// int a = clr.getAlpha();
// if(subalpha < a)
// clr.setAlpha(subalpha);
// }
// }
/* If no previous color contribution, use new color */
if(color[0].isTransparent()) {
for(int i = 0; i < color.length; i++)
@@ -258,8 +258,7 @@ public class HeroChatHandler {
}
else {
/* Set up to hear when HeroChat is enabled */
server.getPluginManager().registerEvent(Event.Type.PLUGIN_ENABLE,
new OurPluginListener(), Event.Priority.Normal, plugin);
plugin.registerEvent(Event.Type.PLUGIN_ENABLE, new OurPluginListener());
}
}
@@ -277,8 +276,7 @@ public class HeroChatHandler {
return;
}
/* Register event handler */
plugin.getServer().getPluginManager().registerEvent(Event.Type.CUSTOM_EVENT,
new OurEventListener(), Event.Priority.Monitor, plugin);
plugin.registerEvent(Event.Type.CUSTOM_EVENT, new OurEventListener());
Log.verboseinfo("HeroChat integration active");
}
/**

Some files were not shown because too many files have changed in this diff Show More