/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package org.pepsoft.worldpainter.biomeschemes;
import org.pepsoft.util.Checksum;
import org.pepsoft.util.FileUtils;
import org.pepsoft.worldpainter.BiomeScheme;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Map;
/**
* An abstract base class for {@link BiomeScheme}s which can invoke Minecraft
* code from a Minecraft jar file for version 1.1 to calculate biomes.
*
* @author pepijn
*/
public abstract class MinecraftJarBiomeScheme extends AbstractMinecraft1_1BiomeScheme {
public MinecraftJarBiomeScheme(File minecraftJar, Checksum md5Sum, Map<Checksum, String[]> hashesToClassNames, String version) {
if (logger.isDebugEnabled()) {
logger.debug("Creating biome scheme using Minecraft jar {}", minecraftJar);
}
if (md5Sum == null) {
try {
md5Sum = FileUtils.getMD5(minecraftJar);
} catch (IOException e) {
throw new RuntimeException("I/O error calculating hash for " + minecraftJar, e);
}
}
String[] classNames = hashesToClassNames.get(md5Sum);
String landscapeClassName = classNames[0];
String bufferManagerClassName = classNames[1];
try {
ClassLoader classLoader = new URLClassLoader(new URL[] {minecraftJar.toURI().toURL()});
Class<?> landscapeClass = classLoader.loadClass(landscapeClassName);
getLandscapesMethod = landscapeClass.getMethod("a", long.class);
getBiomesMethod = landscapeClass.getMethod("a", int.class, int.class, int.class, int.class);
Class<?> bufferManagerClass = classLoader.loadClass(bufferManagerClassName);
clearBuffersMethod = bufferManagerClass.getMethod("a");
} catch (MalformedURLException e) {
throw new RuntimeException("Malformed URL exception while loading minecraft.jar", e);
} catch (ClassNotFoundException | NoSuchMethodException e) {
throw new RuntimeException("Not a valid " + version + " minecraft.jar", e);
}
}
@Override
public final void setSeed(long seed) {
if ((seed != this.seed) || (landscape == null)) {
try {
landscape = ((Object[]) getLandscapesMethod.invoke(null, seed))[1];
this.seed = seed;
} catch (IllegalAccessException e) {
throw new RuntimeException("Access denied while trying to set the seed", e);
} catch (InvocationTargetException e) {
throw new RuntimeException("Exception thrown while trying to set the seed", e);
}
}
}
@Override
public final synchronized void getBiomes(int x, int y, int width, int height, int[] buffer) {
try {
int[] biomes = (int[]) getBiomesMethod.invoke(landscape, x, y, width, height);
clearBuffersMethod.invoke(null);
System.arraycopy(biomes, 0, buffer, 0, Math.min(biomes.length, buffer.length));
} catch (IllegalAccessException e) {
throw new RuntimeException("Access denied while trying to calculate biomes", e);
} catch (InvocationTargetException e) {
throw new RuntimeException("Exception thrown while trying to calculate biomes", e);
}
}
private final Method getLandscapesMethod, getBiomesMethod, clearBuffersMethod;
private Object landscape;
private long seed = Long.MIN_VALUE;
private static final Logger logger = LoggerFactory.getLogger(MinecraftJarBiomeScheme.class);
}