PageRenderTime 3083ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/src/main/java/org/dynmap/kzedmap/KzedMap.java

http://github.com/webbukkit/dynmap
Java | 344 lines | 256 code | 46 blank | 42 comment | 43 complexity | c40b33eede30922555df785d2f53e56c MD5 | raw file
Possible License(s): Apache-2.0
  1. package org.dynmap.kzedmap;
  2. import org.dynmap.DynmapWorld;
  3. import java.io.File;
  4. import java.util.ArrayList;
  5. import java.util.Collections;
  6. import java.util.List;
  7. import java.util.logging.Logger;
  8. import org.bukkit.Location;
  9. import org.dynmap.ConfigurationNode;
  10. import org.dynmap.DynmapChunk;
  11. import org.dynmap.Log;
  12. import org.dynmap.MapManager;
  13. import org.dynmap.MapTile;
  14. import org.dynmap.MapType;
  15. import org.dynmap.utils.MapChunkCache;
  16. import org.json.simple.JSONObject;
  17. public class KzedMap extends MapType {
  18. protected static final Logger log = Logger.getLogger("Minecraft");
  19. protected static final String LOG_PREFIX = "[dynmap] ";
  20. /* dimensions of a map tile */
  21. public static final int tileWidth = 128;
  22. public static final int tileHeight = 128;
  23. /*
  24. * (logical!) dimensions of a zoomed out map tile must be twice the size of
  25. * the normal tile
  26. */
  27. public static final int zTileWidth = 256;
  28. public static final int zTileHeight = 256;
  29. /* map x, y, z for projection origin */
  30. public static final int anchorx = 0;
  31. public static final int anchory = 127;
  32. public static final int anchorz = 0;
  33. MapTileRenderer[] renderers;
  34. private boolean isbigmap;
  35. public KzedMap(ConfigurationNode configuration) {
  36. Log.verboseinfo("Loading renderers for map '" + getClass().toString() + "'...");
  37. List<MapTileRenderer> renderers = configuration.<MapTileRenderer>createInstances("renderers", new Class<?>[0], new Object[0]);
  38. this.renderers = new MapTileRenderer[renderers.size()];
  39. renderers.toArray(this.renderers);
  40. Log.verboseinfo("Loaded " + renderers.size() + " renderers for map '" + getClass().toString() + "'.");
  41. isbigmap = configuration.getBoolean("isbigmap", false);
  42. }
  43. @Override
  44. public MapTile[] getTiles(Location l) {
  45. DynmapWorld world = MapManager.mapman.getWorld(l.getWorld().getName());
  46. int x = l.getBlockX();
  47. int y = l.getBlockY();
  48. int z = l.getBlockZ();
  49. int dx = x - anchorx;
  50. int dy = y - anchory;
  51. int dz = z - anchorz;
  52. int px = dx + dz;
  53. int py = dx - dz - dy;
  54. int tx = tilex(px);
  55. int ty = tiley(py);
  56. ArrayList<MapTile> tiles = new ArrayList<MapTile>();
  57. addTile(tiles, world, tx, ty);
  58. boolean ledge = tilex(px - 4) != tx;
  59. boolean tedge = tiley(py - 4) != ty;
  60. boolean redge = tilex(px + 4) != tx;
  61. boolean bedge = tiley(py + 4) != ty;
  62. if (ledge)
  63. addTile(tiles, world, tx - tileWidth, ty);
  64. if (redge)
  65. addTile(tiles, world, tx + tileWidth, ty);
  66. if (tedge)
  67. addTile(tiles, world, tx, ty - tileHeight);
  68. if (bedge)
  69. addTile(tiles, world, tx, ty + tileHeight);
  70. if (ledge && tedge)
  71. addTile(tiles, world, tx - tileWidth, ty - tileHeight);
  72. if (ledge && bedge)
  73. addTile(tiles, world, tx - tileWidth, ty + tileHeight);
  74. if (redge && tedge)
  75. addTile(tiles, world, tx + tileWidth, ty - tileHeight);
  76. if (redge && bedge)
  77. addTile(tiles, world, tx + tileWidth, ty + tileHeight);
  78. MapTile[] result = new MapTile[tiles.size()];
  79. tiles.toArray(result);
  80. return result;
  81. }
  82. @Override
  83. public MapTile[] getTiles(Location loc0, Location loc1) {
  84. DynmapWorld world = MapManager.mapman.getWorld(loc0.getWorld().getName());
  85. ArrayList<MapTile> tiles = new ArrayList<MapTile>();
  86. /* Transform both to tile coordinates */
  87. int dx = loc0.getBlockX() - anchorx;
  88. int dy = loc0.getBlockY() - anchory;
  89. int dz = loc0.getBlockZ() - anchorz;
  90. int px0 = dx + dz;
  91. int py0 = dx - dz - dy;
  92. dx = loc0.getBlockX() - anchorx;
  93. dy = loc0.getBlockY() - anchory;
  94. dz = loc0.getBlockZ() - anchorz;
  95. int px1 = dx + dz;
  96. int py1 = dx - dz - dy;
  97. /* Compute ranges */
  98. int mintx = (px1<px0)?px0:px1;
  99. int maxtx = (px1<px0)?px1+1:px0+1;
  100. int minty = (py1<py0)?py0:py1;
  101. int maxty = (py1<py0)?py1+1:py0+1;
  102. /* Now, add the tiles for the ranges - not perfect, but it works (some extra tiles on corners possible) */
  103. for(int i = mintx >> 7; i <= maxtx >> 7; i++) {
  104. for(int j = minty >> 7; j < maxty >> 7; j++) {
  105. addTile(tiles, world, i << 7, j << 7);
  106. }
  107. }
  108. return tiles.toArray(new MapTile[tiles.size()]);
  109. }
  110. @Override
  111. public MapTile[] getAdjecentTiles(MapTile tile) {
  112. if (tile instanceof KzedMapTile) {
  113. KzedMapTile t = (KzedMapTile) tile;
  114. DynmapWorld world = tile.getDynmapWorld();
  115. MapTileRenderer renderer = t.renderer;
  116. return new MapTile[] {
  117. new KzedMapTile(world, this, renderer, t.px - tileWidth, t.py + tileHeight),
  118. new KzedMapTile(world, this, renderer, t.px + tileWidth, t.py - tileHeight),
  119. new KzedMapTile(world, this, renderer, t.px - tileWidth, t.py - tileHeight),
  120. new KzedMapTile(world, this, renderer, t.px + tileWidth, t.py + tileHeight),
  121. new KzedMapTile(world, this, renderer, t.px - tileWidth, t.py),
  122. new KzedMapTile(world, this, renderer, t.px + tileWidth, t.py),
  123. new KzedMapTile(world, this, renderer, t.px, t.py - tileHeight),
  124. new KzedMapTile(world, this, renderer, t.px, t.py + tileHeight) };
  125. }
  126. return new MapTile[0];
  127. }
  128. public void addTile(ArrayList<MapTile> tiles, DynmapWorld world, int px, int py) {
  129. for (int i = 0; i < renderers.length; i++) {
  130. tiles.add(new KzedMapTile(world, this, renderers[i], px, py));
  131. }
  132. }
  133. /**
  134. * Test if point x,z is inside rectangle with corner at r0x,r0z and with
  135. * size vectors s1x,s1z and s2x,s2z
  136. *
  137. */
  138. private boolean testPointInRectangle(int x, int z, int r0x, int r0z, int s1x, int s1z,
  139. int s2x, int s2z) {
  140. int xr = x - r0x;
  141. int zr = z - r0z; /* Get position relative to rectangle corner */
  142. int dots1 = xr*s1x + zr*s1z;
  143. int dots2 = xr*s2x + zr*s2z;
  144. /* If dot product of relative point and each side is between zero and dot product
  145. * of each side and itself, we're inside
  146. */
  147. if((dots1 >= 0) && (dots1 <= (s1x*s1x+s1z*s1z)) &&
  148. (dots2 >= 0) && (dots2 <= (s2x*s2x+s2z*s2z))) {
  149. return true;
  150. }
  151. return false;
  152. }
  153. @Override
  154. public List<DynmapChunk> getRequiredChunks(MapTile tile) {
  155. if (tile instanceof KzedMapTile) {
  156. KzedMapTile t = (KzedMapTile) tile;
  157. int ix = KzedMap.anchorx + t.px / 2 + t.py / 2;
  158. //int iy = 127;
  159. int iz = KzedMap.anchorz + t.px / 2 - t.py / 2;
  160. int x1 = ix - KzedMap.tileHeight / 2;
  161. int x2 = ix + KzedMap.tileWidth / 2 + KzedMap.tileHeight / 2;
  162. int z1 = iz - KzedMap.tileHeight / 2;
  163. int z2 = iz + KzedMap.tileWidth / 2 + KzedMap.tileHeight / 2;
  164. int x, z;
  165. /* Actual pattern of chunks needed is create by the slanted
  166. * square prism corresponding to the render path of the tile.
  167. * Top of prism (corresponding to y=127) is diamond shape from
  168. * ix, iz to ix+64,iz+64 to ix+128,iz to ix+64,iz-64
  169. * Bottom is same shape, offset by -64 on x, +64 on z (net
  170. * render path to y=0), correspond to ix-64, iz+64 to
  171. * ix,iz+128 to ix+64,iz+64 to ix,iz. Projection of
  172. * the prism on to the x,z plane (which is all that matters for
  173. * chunks) yields a diagonal rectangular area from ix-64(x1),iz+64
  174. * to ix,iz+128(z2) to ix+128(x2),iz to ix+64,iz-64(z1).
  175. * Chunks outside this are not needed - we scan a simple rectangle
  176. * (chunk grid aligned) and skip adding the ones that are outside.
  177. * This results in 42% less chunks being loaded.
  178. */
  179. ArrayList<DynmapChunk> chunks = new ArrayList<DynmapChunk>();
  180. for (x = x1; x < x2; x += 16) {
  181. for (z = z1; z < z2; z += 16) {
  182. /* If any of the chunk corners are inside the rectangle, we need it */
  183. if((!testPointInRectangle(x, z, x1, iz + KzedMap.tileWidth/2,
  184. KzedMap.tileWidth/2, KzedMap.tileHeight/2,
  185. KzedMap.tileWidth, -KzedMap.tileHeight)) &&
  186. (!testPointInRectangle(x+15, z, x1, iz + KzedMap.tileWidth/2,
  187. KzedMap.tileWidth/2, KzedMap.tileHeight/2,
  188. KzedMap.tileWidth, -KzedMap.tileHeight)) &&
  189. (!testPointInRectangle(x+15, z+15, x1, iz + KzedMap.tileWidth/2,
  190. KzedMap.tileWidth/2, KzedMap.tileHeight/2,
  191. KzedMap.tileWidth, -KzedMap.tileHeight)) &&
  192. (!testPointInRectangle(x, z+15, x1, iz + KzedMap.tileWidth/2,
  193. KzedMap.tileWidth/2, KzedMap.tileHeight/2,
  194. KzedMap.tileWidth, -KzedMap.tileHeight)))
  195. continue;
  196. DynmapChunk chunk = new DynmapChunk(x / 16, z / 16);
  197. chunks.add(chunk);
  198. }
  199. }
  200. return chunks;
  201. } else {
  202. return new ArrayList<DynmapChunk>();
  203. }
  204. }
  205. public boolean render(MapChunkCache cache, MapTile tile, File outputFile) {
  206. if (tile instanceof KzedMapTile) {
  207. return ((KzedMapTile) tile).renderer.render(cache, (KzedMapTile) tile, outputFile);
  208. }
  209. return false;
  210. }
  211. /* tile X for position x */
  212. static int tilex(int x) {
  213. if (x < 0)
  214. return x - (tileWidth + (x % tileWidth));
  215. else
  216. return x - (x % tileWidth);
  217. }
  218. /* tile Y for position y */
  219. static int tiley(int y) {
  220. if (y < 0)
  221. return y - (tileHeight + (y % tileHeight));
  222. else
  223. return y - (y % tileHeight);
  224. }
  225. /* zoomed-out tile X for tile position x */
  226. static int ztilex(int x) {
  227. if (x < 0)
  228. return x + x % zTileWidth;
  229. else
  230. return x - (x % zTileWidth);
  231. }
  232. /* zoomed-out tile Y for tile position y */
  233. static int ztiley(int y) {
  234. if (y < 0)
  235. return y + y % zTileHeight;
  236. // return y - (zTileHeight + (y % zTileHeight));
  237. else
  238. return y - (y % zTileHeight);
  239. }
  240. public boolean isBiomeDataNeeded() {
  241. for(MapTileRenderer r : renderers) {
  242. if(r.isBiomeDataNeeded())
  243. return true;
  244. }
  245. return false;
  246. }
  247. public boolean isRawBiomeDataNeeded() {
  248. for(MapTileRenderer r : renderers) {
  249. if(r.isRawBiomeDataNeeded())
  250. return true;
  251. }
  252. return false;
  253. }
  254. public List<ZoomInfo> baseZoomFileInfo() {
  255. ArrayList<ZoomInfo> s = new ArrayList<ZoomInfo>();
  256. for(MapTileRenderer r : renderers) {
  257. s.add(new ZoomInfo("z" + r.getPrefix(), 0));
  258. if(r.isNightAndDayEnabled())
  259. s.add(new ZoomInfo("z" + r.getPrefix() + "_day", 0));
  260. }
  261. return s;
  262. }
  263. public int baseZoomFileStepSize() { return zTileWidth; }
  264. public MapStep zoomFileMapStep() { return MapStep.X_MINUS_Y_PLUS; }
  265. private static final int[] stepseq = { 0, 2, 1, 3 };
  266. public int[] zoomFileStepSequence() { return stepseq; }
  267. /* How many bits of coordinate are shifted off to make big world directory name */
  268. public int getBigWorldShift() { return 12; }
  269. /* Returns true if big world file structure is in effect for this map */
  270. @Override
  271. public boolean isBigWorldMap(DynmapWorld w) {
  272. return w.bigworld || isbigmap;
  273. }
  274. public String getName() {
  275. return "KzedMap";
  276. }
  277. /* Get maps rendered concurrently with this map in this world */
  278. public List<MapType> getMapsSharingRender(DynmapWorld w) {
  279. return Collections.singletonList((MapType)this);
  280. }
  281. /* Get names of maps rendered concurrently with this map type in this world */
  282. public List<String> getMapNamesSharingRender(DynmapWorld w) {
  283. ArrayList<String> lst = new ArrayList<String>();
  284. for(MapTileRenderer rend : renderers) {
  285. if(rend.isNightAndDayEnabled())
  286. lst.add(rend.getName() + "(night/day)");
  287. else
  288. lst.add(rend.getName());
  289. }
  290. return lst;
  291. }
  292. @Override
  293. public void buildClientConfiguration(JSONObject worldObject, DynmapWorld world) {
  294. for(MapTileRenderer renderer : renderers) {
  295. renderer.buildClientConfiguration(worldObject, world, this);
  296. }
  297. }
  298. }