package org.dynmap;
import org.dynmap.hdmap.*;
import org.pepsoft.util.Version;
import org.pepsoft.worldpainter.Configuration;
import org.pepsoft.worldpainter.biomeschemes.BiomeSchemeManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.SortedMap;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarOutputStream;
/**
* An alternative implementation of {@link HDMapManager} which creates a hard
* coded perspective, shader and lighting instead of instantiating them from a
* configuration file. Used by this module's private implementation of
* {@link MapManager}.
*
* <p>Created by Pepijn Schmitz on 08-06-15.
*/
class WPHDMapManager extends HDMapManager {
void init(ConfigurationNode configNode) {
DynmapCore core = new DynmapCore();
perspectives.put("default", new IsoHDPerspective(core, configNode));
SortedMap<Version, File> minecraftJars = BiomeSchemeManager.getAllMinecraftJars();
if (minecraftJars.isEmpty()) {
logger.info("No Minecraft jars found; falling back to solid shading for 3D dynmap previews");
shaders.put("default", new DefaultHDShader(core, configNode));
} else {
Version latestVersion = minecraftJars.lastKey();
if (checkDynmapResources(latestVersion, minecraftJars.get(latestVersion))) {
// Note that technically we're reporting the wrong version number
// here and theoretically it could be wrong. In practice it
// should usually be right though:
logger.info("Using textures from Minecraft " + latestVersion + " for 3D dynmap previews");
configNode.put("texturepack", "standard");
TexturePack.loadTextureMapping(core, configNode);
// Force initialisation of texture pack to get early errors:
TexturePack.getTexturePack(core, "standard");
shaders.put("default", new TexturePackHDShader(core, configNode));
} else {
// Could not copy the textures for dynmap for whatever reason;
// fall back to solid colours
logger.error("Error copying textures from Minecraft; falling back to solid shading for 3D dynmap previews");
shaders.put("default", new DefaultHDShader(core, configNode));
}
}
shaders.put("caves", new CaveHDShader(core, configNode));
lightings.put("default", new DefaultHDLighting(core, configNode));
}
/**
* Dynmap is tightly coupled to certain resources existing on the
* filesystem. Check that they are there and if not create them.
*/
@SuppressWarnings("ResultOfMethodCallIgnored") // Implicitly checked later
private boolean checkDynmapResources(Version latestVersion, File latestJar) {
File texPackDir = new File(Configuration.getConfigDir(), "dynmap/texturepacks");
if (! texPackDir.isDirectory()) {
texPackDir.mkdirs();
}
File existingJar = new File(texPackDir, "standard");
if ((! existingJar.isFile()) || (latestJar.lastModified() > existingJar.lastModified())) {
logger.info("Copying textures from Minecraft " + latestVersion + " for dynmap previews");
return createDynmapResources(latestJar, existingJar);
} else {
return true;
}
}
/**
* Create the filesystem resources dynmap needs in order to operate
* correctly.
*/
private boolean createDynmapResources(File latestJar, File existingJar) {
try {
try (JarFile jarFile = new JarFile(latestJar, false); JarOutputStream out = new JarOutputStream(new FileOutputStream(existingJar))) {
byte[] buffer = new byte[BUFFER_SIZE];
int bytesRead;
// Dynmap needs the terrain.png file to exist, otherwise it doesn't
// work correctly, even though resource packs don't in fact contain
// a terrain.png file
if (logger.isDebugEnabled()) {
logger.debug("Writing terrain.png to " + existingJar);
}
out.putNextEntry(new JarEntry("terrain.png"));
try (InputStream in = ClassLoader.getSystemResourceAsStream("terrain.png")) {
while ((bytesRead = in.read(buffer)) != -1) {
out.write(buffer, 0, bytesRead);
}
}
// Copy the rest, leaving out unnecessary files
for (Enumeration<JarEntry> e = jarFile.entries(); e.hasMoreElements(); ) {
JarEntry entry = e.nextElement();
if (entry.getName().endsWith(".png")) {
if (logger.isDebugEnabled()) {
logger.debug("Copying " + entry + " from " + latestJar + " to " + existingJar);
}
out.putNextEntry(entry);
try (InputStream in = jarFile.getInputStream(entry)) {
while ((bytesRead = in.read(buffer)) != -1) {
out.write(buffer, 0, bytesRead);
}
}
} else if (logger.isDebugEnabled()) {
logger.debug("Skipping " + entry + " from " + latestJar);
}
}
}
return true;
} catch (IOException e) {
// The file may be corrupt at this point, so delete it and try again
// next time
existingJar.delete();
logger.error("I/O error copying Minecraft jar to WorldPainter config directory to serve as dynmap texture pack", e);
return false;
}
}
private static final int BUFFER_SIZE = 32768;
private static final Logger logger = LoggerFactory.getLogger(WPHDMapManager.class);
}