/** * Get scaled set of models for all modelled blocks * * @param scale * @return */ public static HDScaledBlockModels getModelsForScale(int scale) { HDScaledBlockModels model = scaled_models_by_scale.get(Integer.valueOf(scale)); if (model == null) { model = new HDScaledBlockModels(); short[][][] blockmodels = new short[256][][]; for (HDBlockModels m : models_by_id_data.values()) { short[][] row = blockmodels[m.blockid]; if (row == null) { row = new short[16][]; blockmodels[m.blockid] = row; } short[] smod = null; for (int i = 0; i < 16; i++) { if ((m.databits & (1 << i)) != 0) { if (smod == null) smod = m.getScaledMap(scale); row[i] = smod; } } } model.modelvectors = blockmodels; scaled_models_by_scale.put(scale, model); } return model; }
public IsoHDPerspective(ConfigurationNode configuration) { name = configuration.getString("name", null); if (name == null) { Log.severe("Perspective definition missing name - must be defined and unique"); return; } azimuth = configuration.getDouble("azimuth", 135.0); /* Get azimuth (default to classic kzed POV */ inclination = configuration.getDouble("inclination", 60.0); if (inclination > MAX_INCLINATION) inclination = MAX_INCLINATION; if (inclination < MIN_INCLINATION) inclination = MIN_INCLINATION; scale = configuration.getDouble("scale", MIN_SCALE); if (scale < MIN_SCALE) scale = MIN_SCALE; if (scale > MAX_SCALE) scale = MAX_SCALE; /* Get max and min height */ maxheight = configuration.getInteger("maximumheight", 127); if (maxheight > 127) maxheight = 127; minheight = configuration.getInteger("minimumheight", 0); if (minheight < 0) minheight = 0; /* Generate transform matrix for world-to-tile coordinate mapping */ /* First, need to fix basic coordinate mismatches before rotation - we want zero azimuth to have north to top * (world -X -> tile +Y) and east to right (world -Z to tile +X), with height being up (world +Y -> tile +Z) */ Matrix3D transform = new Matrix3D(0.0, 0.0, -1.0, -1.0, 0.0, 0.0, 0.0, 1.0, 0.0); /* Next, rotate world counterclockwise around Z axis by azumuth angle */ transform.rotateXY(180 - azimuth); /* Next, rotate world by (90-inclination) degrees clockwise around +X axis */ transform.rotateYZ(90.0 - inclination); /* Finally, shear along Z axis to normalize Z to be height above map plane */ transform.shearZ(0, Math.tan(Math.toRadians(90.0 - inclination))); /* And scale Z to be same scale as world coordinates, and scale X and Y based on setting */ transform.scale(scale, scale, Math.sin(Math.toRadians(inclination))); world_to_map = transform; /* Now, generate map to world tranform, by doing opposite actions in reverse order */ transform = new Matrix3D(); transform.scale(1.0 / scale, 1.0 / scale, 1 / Math.sin(Math.toRadians(inclination))); transform.shearZ(0, -Math.tan(Math.toRadians(90.0 - inclination))); transform.rotateYZ(-(90.0 - inclination)); transform.rotateXY(-180 + azimuth); Matrix3D coordswap = new Matrix3D(0.0, -1.0, 0.0, 0.0, 0.0, 1.0, -1.0, 0.0, 0.0); transform.multiply(coordswap); map_to_world = transform; /* Scaled models for non-cube blocks */ modscale = (int) Math.ceil(scale); scalemodels = HDBlockModels.getModelsForScale(modscale); ; }
@Override public void onEnable() { /* Start with clean events */ events = new Events(); permissions = NijikokunPermissions.create(getServer(), "dynmap"); if (permissions == null) permissions = BukkitPermissions.create("dynmap"); if (permissions == null) permissions = new OpPermissions( new String[] { "fullrender", "cancelrender", "radiusrender", "resetstats", "reload", "purgequeue" }); dataDirectory = this.getDataFolder(); if (dataDirectory.exists() == false) dataDirectory.mkdirs(); /* Initialize confguration.txt if needed */ File f = new File(this.getDataFolder(), "configuration.txt"); if (!createDefaultFileFromResource("/configuration.txt", f)) { this.setEnabled(false); return; } /* Load configuration.txt */ org.bukkit.util.config.Configuration bukkitConfiguration = new org.bukkit.util.config.Configuration(f); bukkitConfiguration.load(); configuration = new ConfigurationNode(bukkitConfiguration); /* Load block models */ HDBlockModels.loadModels(dataDirectory, configuration); /* Load texture mappings */ TexturePack.loadTextureMapping(dataDirectory, configuration); /* Now, process worlds.txt - merge it in as an override of existing values (since it is only user supplied values) */ f = new File(this.getDataFolder(), "worlds.txt"); if (!createDefaultFileFromResource("/worlds.txt", f)) { this.setEnabled(false); return; } org.bukkit.util.config.Configuration cfg = new org.bukkit.util.config.Configuration(f); cfg.load(); ConfigurationNode cn = new ConfigurationNode(cfg); mergeConfigurationBranch(cn, "worlds", true, true); /* Now, process templates */ loadTemplates(); Log.verbose = configuration.getBoolean("verbose", true); deftemplatesuffix = configuration.getString("deftemplatesuffix", ""); /* Default swamp shading off for 1.8, on after */ swampshading = configuration.getBoolean("swampshaded", !getServer().getVersion().contains("(MC: 1.8")); /* Default water biome shading off for 1.8, on after */ waterbiomeshading = configuration.getBoolean( "waterbiomeshaded", !getServer().getVersion().contains("(MC: 1.8")); /* Default fence-to-block-join off for 1.8, on after */ fencejoin = configuration.getBoolean( "fence-to-block-join", !getServer().getVersion().contains("(MC: 1.8")); /* Default compassmode to pre19, to newrose after */ String cmode = configuration.getString( "compass-mode", getServer().getVersion().contains("(MC: 1.8") ? "pre19" : "newrose"); if (cmode.equals("newnorth")) compassmode = CompassMode.NEWNORTH; else if (cmode.equals("newrose")) compassmode = CompassMode.NEWROSE; else compassmode = CompassMode.PRE19; loadDebuggers(); tilesDirectory = getFile(configuration.getString("tilespath", "web/tiles")); if (!tilesDirectory.isDirectory() && !tilesDirectory.mkdirs()) { Log.warning("Could not create directory for tiles ('" + tilesDirectory + "')."); } playerList = new PlayerList(getServer(), getFile("hiddenplayers.txt"), configuration); playerList.load(); PlayerListener pl = new PlayerListener() { public void onPlayerJoin(PlayerJoinEvent evt) { playerList.updateOnlinePlayers(null); } public void onPlayerQuit(PlayerQuitEvent evt) { playerList.updateOnlinePlayers(evt.getPlayer()); } }; registerEvent(Type.PLAYER_JOIN, pl); registerEvent(Type.PLAYER_QUIT, pl); mapManager = new MapManager(this, configuration); mapManager.startRendering(); playerfacemgr = new PlayerFaces(this); loadWebserver(); enabledTriggers.clear(); List<String> triggers = configuration.getStrings("render-triggers", new ArrayList<String>()); if (triggers != null) { for (Object trigger : triggers) { enabledTriggers.add((String) trigger); } } // Load components. for (Component component : configuration.<Component>createInstances( "components", new Class<?>[] {DynmapPlugin.class}, new Object[] {this})) { componentManager.add(component); } Log.verboseinfo("Loaded " + componentManager.components.size() + " components."); registerEvents(); if (!configuration.getBoolean("disable-webserver", false)) { startWebserver(); } /* Print version info */ PluginDescriptionFile pdfFile = this.getDescription(); Log.info("version " + pdfFile.getVersion() + " is enabled"); events.<Object>trigger("initialized", null); }
@Override public RenderPatchFactory getPatchFactory() { return HDBlockModels.getPatchDefinitionFactory(); }
/** Load models from file */ private static void loadModelFile(InputStream in, String fname) { LineNumberReader rdr = null; int cnt = 0; try { String line; ArrayList<HDBlockModels> modlist = new ArrayList<HDBlockModels>(); int layerbits = 0; int rownum = 0; int scale = 0; rdr = new LineNumberReader(new InputStreamReader(in)); while ((line = rdr.readLine()) != null) { if (line.startsWith("block:")) { ArrayList<Integer> blkids = new ArrayList<Integer>(); int databits = 0; scale = 0; line = line.substring(6); String[] args = line.split(","); for (String a : args) { String[] av = a.split("="); if (av.length < 2) continue; if (av[0].equals("id")) { blkids.add(Integer.parseInt(av[1])); } else if (av[0].equals("data")) { if (av[1].equals("*")) databits = 0xFFFF; else databits |= (1 << Integer.parseInt(av[1])); } else if (av[0].equals("scale")) { scale = Integer.parseInt(av[1]); } } /* If we have everything, build block */ if ((blkids.size() > 0) && (databits != 0) && (scale > 0)) { modlist.clear(); for (Integer id : blkids) { modlist.add(new HDBlockModels(id.intValue(), databits, scale, new long[0])); cnt++; } } else { Log.severe( "Block model missing required parameters = line " + rdr.getLineNumber() + " of " + fname); } layerbits = 0; } else if (line.startsWith("layer:")) { line = line.substring(6); String args[] = line.split(","); layerbits = 0; rownum = 0; for (String a : args) { layerbits |= (1 << Integer.parseInt(a)); } } else if (line.startsWith("rotate:")) { line = line.substring(7); String args[] = line.split(","); int id = -1; int data = -1; int rot = -1; for (String a : args) { String[] av = a.split("="); if (av.length < 2) continue; if (av[0].equals("id")) { id = Integer.parseInt(av[1]); } if (av[0].equals("data")) { data = Integer.parseInt(av[1]); } if (av[0].equals("rot")) { rot = Integer.parseInt(av[1]); } } /* get old model to be rotated */ HDBlockModels mod = models_by_id_data.get((id << 4) + data); if ((mod != null) && ((rot % 90) == 0)) { for (int x = 0; x < scale; x++) { for (int y = 0; y < scale; y++) { for (int z = 0; z < scale; z++) { if (mod.isSubblockSet(x, y, z) == false) continue; switch (rot) { case 0: for (HDBlockModels bm : modlist) bm.setSubblock(x, y, z, true); break; case 90: for (HDBlockModels bm : modlist) bm.setSubblock(scale - z - 1, y, x, true); break; case 180: for (HDBlockModels bm : modlist) bm.setSubblock(scale - x - 1, y, scale - z - 1, true); break; case 270: for (HDBlockModels bm : modlist) bm.setSubblock(z, y, scale - x - 1, true); break; } } } } } } else if (line.startsWith("#") || line.startsWith(";")) { } else if (layerbits != 0) { /* If we're working pattern lines */ /* Layerbits determine Y, rows count from North to South (X=0 to X=N-1), columns Z are West to East (N-1 to 0) */ for (int i = 0; (i < scale) && (i < line.length()); i++) { if (line.charAt(i) == '*') { /* If an asterix, set flag */ for (int y = 0; y < scale; y++) { if ((layerbits & (1 << y)) != 0) { for (HDBlockModels mod : modlist) { mod.setSubblock(rownum, y, scale - i - 1, true); } } } } } /* See if we're done with layer */ rownum++; if (rownum >= scale) { rownum = 0; layerbits = 0; } } } Log.verboseinfo("Loaded " + cnt + " block models from " + fname); } catch (IOException iox) { Log.severe("Error reading models.txt - " + iox.toString()); } catch (NumberFormatException nfx) { Log.severe("Format error - line " + rdr.getLineNumber() + " of " + fname); } finally { if (rdr != null) { try { rdr.close(); rdr = null; } catch (IOException e) { } } } }
public int loadChunks(int max_to_load) { if (dw.isLoaded() == false) return 0; long t0 = System.nanoTime(); Object queue = helper.getUnloadQueue(helper.getNMSWorld(w)); int cnt = 0; if (iterator == null) iterator = chunks.listIterator(); DynmapCore.setIgnoreChunkLoads(true); // boolean isnormral = w.getEnvironment() == Environment.NORMAL; // Load the required chunks. while ((cnt < max_to_load) && iterator.hasNext()) { DynmapChunk chunk = iterator.next(); boolean vis = true; if (visible_limits != null) { vis = false; for (VisibilityLimit limit : visible_limits) { if ((chunk.x >= limit.x0) && (chunk.x <= limit.x1) && (chunk.z >= limit.z0) && (chunk.z <= limit.z1)) { vis = true; break; } } } if (vis && (hidden_limits != null)) { for (VisibilityLimit limit : hidden_limits) { if ((chunk.x >= limit.x0) && (chunk.x <= limit.x1) && (chunk.z >= limit.z0) && (chunk.z <= limit.z1)) { vis = false; break; } } } /* Check if cached chunk snapshot found */ ChunkSnapshot ss = null; DynIntHashMap tileData = null; SnapshotRec ssr = DynmapPlugin.plugin.sscache.getSnapshot( dw.getName(), chunk.x, chunk.z, blockdata, biome, biomeraw, highesty); if (ssr != null) { ss = ssr.ss; if (!vis) { if (hidestyle == HiddenChunkStyle.FILL_STONE_PLAIN) ss = STONE; else if (hidestyle == HiddenChunkStyle.FILL_OCEAN) ss = OCEAN; else ss = EMPTY; } int idx = (chunk.x - x_min) + (chunk.z - z_min) * x_dim; snaparray[idx] = ss; snaptile[idx] = ssr.tileData; continue; } chunks_attempted++; boolean wasLoaded = w.isChunkLoaded(chunk.x, chunk.z); boolean didload = false; boolean isunloadpending = false; if (queue != null) { isunloadpending = helper.isInUnloadQueue(queue, chunk.x, chunk.z); } if (isunloadpending) { /* Workaround: can't be pending if not loaded */ wasLoaded = true; } try { if (!wasLoaded) { didload = w.loadChunk(chunk.x, chunk.z, false); } else { /* If already was loaded, no need to load */ didload = true; } } catch (Throwable t) { /* Catch chunk error from Bukkit */ Log.warning("Bukkit error loading chunk " + chunk.x + "," + chunk.z + " on " + w.getName()); if (!wasLoaded) { /* If wasn't loaded, we loaded it if it now is */ didload = w.isChunkLoaded(chunk.x, chunk.z); } } boolean didgenerate = false; /* If we didn't load, and we're supposed to generate, do it */ if ((!didload) && do_generate && vis) didgenerate = didload = w.loadChunk(chunk.x, chunk.z, true); /* If it did load, make cache of it */ if (didload) { tileData = new DynIntHashMap(); Chunk c = w.getChunkAt(chunk.x, chunk.z); /* Get the chunk */ /* Test if chunk isn't populated */ boolean populated = true; // TODO: figure out why this doesn't appear to be reliable in Bukkit // if((nmschunk != null) && (doneflag != null)) { // try { // populated = doneflag.getBoolean(nmschunk); // } catch (IllegalArgumentException e) { // } catch (IllegalAccessException e) { // } // } if (!vis) { if (hidestyle == HiddenChunkStyle.FILL_STONE_PLAIN) ss = STONE; else if (hidestyle == HiddenChunkStyle.FILL_OCEAN) ss = OCEAN; else ss = EMPTY; } else if (!populated) { /* If not populated, treat as empty */ ss = EMPTY; } else { if (blockdata || highesty) { ss = c.getChunkSnapshot(highesty, biome, biomeraw); if (use_spout) { ss = checkSpoutData(c, ss); } /* Get tile entity data */ List<Object> vals = new ArrayList<Object>(); Map tileents = helper.getTileEntitiesForChunk(c); for (Object t : tileents.values()) { int te_x = helper.getTileEntityX(t); int te_y = helper.getTileEntityY(t); int te_z = helper.getTileEntityZ(t); int cx = te_x & 0xF; int cz = te_z & 0xF; int blkid = ss.getBlockTypeId(cx, te_y, cz); int blkdat = ss.getBlockData(cx, te_y, cz); String[] te_fields = HDBlockModels.getTileEntityFieldsNeeded(blkid, blkdat); if (te_fields != null) { Object nbtcompound = helper.readTileEntityNBT(t); vals.clear(); for (String id : te_fields) { Object val = helper.getFieldValue(nbtcompound, id); if (val != null) { vals.add(id); vals.add(val); } } if (vals.size() > 0) { Object[] vlist = vals.toArray(new Object[vals.size()]); tileData.put(getIndexInChunk(cx, te_y, cz), vlist); } } } } else ss = w.getEmptyChunkSnapshot(chunk.x, chunk.z, biome, biomeraw); if (ss != null) { ssr = new SnapshotRec(); ssr.ss = ss; ssr.tileData = tileData; DynmapPlugin.plugin.sscache.putSnapshot( dw.getName(), chunk.x, chunk.z, ssr, blockdata, biome, biomeraw, highesty); } } snaparray[(chunk.x - x_min) + (chunk.z - z_min) * x_dim] = ss; snaptile[(chunk.x - x_min) + (chunk.z - z_min) * x_dim] = tileData; /* If wasn't loaded before, we need to do unload */ if (!wasLoaded) { chunks_read++; /* It looks like bukkit "leaks" entities - they don't get removed from the world-level table * when chunks are unloaded but not saved - removing them seems to do the trick */ if (!(didgenerate && do_save)) { helper.removeEntitiesFromChunk(c); } /* Since we only remember ones we loaded, and we're synchronous, no player has * moved, so it must be safe (also prevent chunk leak, which appears to happen * because isChunkInUse defined "in use" as being within 256 blocks of a player, * while the actual in-use chunk area for a player where the chunks are managed * by the MC base server is 21x21 (or about a 160 block radius). * Also, if we did generate it, need to save it */ w.unloadChunk(chunk.x, chunk.z, didgenerate && do_save, false); } else if (isunloadpending) { /* Else, if loaded and unload is pending */ w.unloadChunkRequest(chunk.x, chunk.z); /* Request new unload */ } } cnt++; } DynmapCore.setIgnoreChunkLoads(false); if (iterator.hasNext() == false) { /* If we're done */ isempty = true; /* Fill missing chunks with empty dummy chunk */ for (int i = 0; i < snaparray.length; i++) { if (snaparray[i] == null) snaparray[i] = EMPTY; else if (snaparray[i] != EMPTY) isempty = false; } } total_loadtime += System.nanoTime() - t0; return cnt; }