mirror of
https://github.com/GTNewHorizons/CodeChickenCore.git
synced 2026-11-15 17:44:42 +00:00
Added command line tool frontend.
This commit is contained in:
1 parent
7450370d99
commit
ae652f51c2
9 files changed
+396
-23
No files matched your search
@@ -0,0 +1,2 @@
|
||||
Manifest-Version: 1.0
|
||||
Main-Class: codechicken.lib.tool.Main
|
||||
@@ -239,7 +239,6 @@ public class QBImporter
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static final int[][] vertOrder = new int[][] {//clockwise because MC is left handed
|
||||
{3, 0},
|
||||
{1, 0},
|
||||
@@ -577,8 +576,6 @@ public class QBImporter
|
||||
public QBMatrix[] matrices;
|
||||
public boolean rightHanded;
|
||||
|
||||
|
||||
|
||||
public RasterisedModel toRasterisedModel(int flags) {
|
||||
List<QBImage> qbImages = new ArrayList<QBImage>();
|
||||
List<List<QBQuad>> modelQuads = new ArrayList<List<QBQuad>>();
|
||||
@@ -727,29 +724,23 @@ public class QBImporter
|
||||
}
|
||||
|
||||
public static QBModel loadQB(ResourceLocation res) {
|
||||
try
|
||||
{
|
||||
try {
|
||||
return loadQB(Minecraft.getMinecraft().getResourceManager().getResource(res).getInputStream());
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
} catch(Exception e) {
|
||||
throw new RuntimeException("failed to load model: "+res, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* try {
|
||||
File dump = new File("packed.png");
|
||||
if(!dump.exists()) dump.createNewFile();
|
||||
ImageIO.write(img, "PNG", dump);
|
||||
|
||||
File dump2 = new File("packed.obj");
|
||||
if(!dump2.exists()) dump2.createNewFile();
|
||||
PrintWriter p = new PrintWriter(dump2);
|
||||
CCModel.exportObj(Collections.singletonMap(name, m), p);
|
||||
p.close();
|
||||
} catch(IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
*/
|
||||
public static QBModel loadQB(File file) {
|
||||
try {
|
||||
FileInputStream fin = new FileInputStream(file);
|
||||
try {
|
||||
return loadQB(fin);
|
||||
} finally {
|
||||
fin.close();
|
||||
}
|
||||
} catch(Exception e) {
|
||||
throw new RuntimeException("failed to load model: "+file.getPath(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
package codechicken.lib.tool;
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.net.URLConnection;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
public class LibDownloader
|
||||
{
|
||||
private static String[] libs = new String[] {
|
||||
"org/ow2/asm/asm-debug-all/4.1/asm-debug-all-4.1.jar",
|
||||
"com/google/guava/guava/14.0/guava-14.0.jar",
|
||||
"net/sf/jopt-simple/jopt-simple/4.5/jopt-simple-4.5.jar"};
|
||||
private static File libDir = new File("lib");
|
||||
|
||||
private static ByteBuffer downloadBuffer = ByteBuffer.allocateDirect(1 << 23);
|
||||
|
||||
public static void load() {
|
||||
if(!libDir.exists())
|
||||
libDir.mkdir();
|
||||
if(!libDir.isDirectory())
|
||||
throw new RuntimeException("/lib is not a directory");
|
||||
|
||||
List<String> missing = checkExists();
|
||||
for(String lib : missing)
|
||||
download(lib);
|
||||
addPaths(libs);
|
||||
}
|
||||
|
||||
private static void addPaths(String[] libs) {
|
||||
try {
|
||||
URLClassLoader cl = (URLClassLoader) ClassLoader.getSystemClassLoader();
|
||||
Method m_addURL = URLClassLoader.class.getDeclaredMethod("addURL", new Class[]{URL.class});
|
||||
m_addURL.setAccessible(true);
|
||||
for(String lib : libs)
|
||||
m_addURL.invoke(cl, new File(libDir, fileName(lib)).toURI().toURL());
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException("Failed to add libraries to classpath", e);
|
||||
}
|
||||
}
|
||||
|
||||
private static void download(String lib) {
|
||||
File libFile = new File(libDir, fileName(lib));
|
||||
try
|
||||
{
|
||||
URL libDownload = new URL("http://repo1.maven.org/maven2/"+lib);
|
||||
URLConnection connection = libDownload.openConnection();
|
||||
connection.setConnectTimeout(5000);
|
||||
connection.setReadTimeout(5000);
|
||||
connection.setRequestProperty("User-Agent", "CodeChickenLib Downloader");
|
||||
int sizeGuess = connection.getContentLength();
|
||||
download(connection.getInputStream(), sizeGuess, libFile);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
libFile.delete();
|
||||
throw new RuntimeException("A download error occured", e);
|
||||
}
|
||||
}
|
||||
|
||||
private static void download(InputStream is, int sizeGuess, File target) throws Exception
|
||||
{
|
||||
String name = target.getName();
|
||||
if (sizeGuess > downloadBuffer.capacity())
|
||||
throw new Exception(String.format("The file %s is too large to be downloaded", name));
|
||||
|
||||
downloadBuffer.clear();
|
||||
|
||||
int bytesRead, fullLength = 0;
|
||||
|
||||
System.out.format("Downloading lib %s", name);
|
||||
byte[] smallBuffer = new byte[1024];
|
||||
while ((bytesRead = is.read(smallBuffer)) >= 0) {
|
||||
downloadBuffer.put(smallBuffer, 0, bytesRead);
|
||||
fullLength += bytesRead;
|
||||
System.out.format("\rDownloading lib %s %d%%", name, (int) (fullLength * 100 / sizeGuess));
|
||||
}
|
||||
System.out.format("\rDownloaded lib %s \n", name);
|
||||
is.close();
|
||||
downloadBuffer.limit(fullLength);
|
||||
|
||||
if(!target.exists())
|
||||
target.createNewFile();
|
||||
|
||||
downloadBuffer.position(0);
|
||||
FileOutputStream fos = new FileOutputStream(target);
|
||||
fos.getChannel().write(downloadBuffer);
|
||||
fos.close();
|
||||
}
|
||||
|
||||
private static String fileName(String lib) {
|
||||
return lib.replaceAll(".+/", "");
|
||||
}
|
||||
|
||||
private static List<String> checkExists() {
|
||||
LinkedList<String> list = new LinkedList<String>();
|
||||
for(String lib : libs) {
|
||||
File file = new File(libDir, fileName(lib));
|
||||
if(!file.exists())
|
||||
list.add(lib);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package codechicken.lib.tool;
|
||||
|
||||
import codechicken.lib.asm.ASMHelper;
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.commons.Remapper;
|
||||
import org.objectweb.asm.commons.RemappingMethodAdapter;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import org.objectweb.asm.tree.MethodNode;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
public class MCStripTransformer {
|
||||
public static class ReferenceDetector extends Remapper {
|
||||
boolean found = false;
|
||||
|
||||
@Override
|
||||
public String map(String typeName) {
|
||||
if(typeName.startsWith("net/minecraft"))
|
||||
found = true;
|
||||
return typeName;
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] transform(byte[] bytes) {
|
||||
ClassNode cnode = ASMHelper.createClassNode(bytes, ClassReader.EXPAND_FRAMES);
|
||||
|
||||
boolean changed = false;
|
||||
Iterator<MethodNode> it = cnode.methods.iterator();
|
||||
while(it.hasNext()) {
|
||||
MethodNode mnode = it.next();
|
||||
ReferenceDetector r = new ReferenceDetector();
|
||||
mnode.accept(new RemappingMethodAdapter(mnode.access, mnode.desc, new MethodVisitor(Opcodes.ASM4) {}, r));
|
||||
if(r.found) {
|
||||
it.remove();
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
if(changed)
|
||||
bytes = ASMHelper.createBytes(cnode, 0);
|
||||
return bytes;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package codechicken.lib.tool;
|
||||
|
||||
public class Main
|
||||
{
|
||||
public static void main(String[] args) {
|
||||
LibDownloader.load();
|
||||
try {
|
||||
Class<?> c_toolMain = new StripClassLoader().loadClass("codechicken.lib.tool.ToolMain");
|
||||
c_toolMain.getDeclaredMethod("main", String[].class).invoke(null, new Object[]{args});
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package codechicken.lib.tool;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
|
||||
public class StripClassLoader extends URLClassLoader
|
||||
{
|
||||
public StripClassLoader() {
|
||||
super(new URL[0], StripClassLoader.class.getClassLoader());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> loadClass(String name) throws ClassNotFoundException {
|
||||
if(!name.startsWith("codechicken.lib"))
|
||||
return super.loadClass(name);
|
||||
|
||||
try {
|
||||
String resName = name.replace('.', '/')+".class";
|
||||
InputStream res = getResourceAsStream(resName);
|
||||
if(res == null)
|
||||
throw new ClassNotFoundException("Could not find resource: "+resName);
|
||||
byte[] bytes = readFully(res);
|
||||
bytes = transform(bytes);
|
||||
return defineClass(name, bytes, 0, bytes.length);
|
||||
|
||||
} catch(IOException e) {
|
||||
throw new ClassNotFoundException(name, e);
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] readFully(InputStream is) throws IOException {
|
||||
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||
|
||||
int read;
|
||||
byte[] data = new byte[16384];
|
||||
while ((read = is.read(data, 0, data.length)) > 0)
|
||||
buffer.write(data, 0, read);
|
||||
|
||||
return buffer.toByteArray();
|
||||
}
|
||||
|
||||
private byte[] transform(byte[] bytes) {
|
||||
|
||||
bytes = MCStripTransformer.transform(bytes);
|
||||
return bytes;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package codechicken.lib.tool;
|
||||
|
||||
import codechicken.lib.tool.module.ModuleQBConverter;
|
||||
|
||||
public class ToolMain
|
||||
{
|
||||
public static interface Module {
|
||||
public void main(String[] args);
|
||||
public String name();
|
||||
public void printHelp();
|
||||
}
|
||||
|
||||
public static Module[] modules = new Module[]{
|
||||
new ModuleQBConverter()
|
||||
};
|
||||
|
||||
private static void printHelp() {
|
||||
System.out.println("Usage: [module] [args]");
|
||||
System.out.println(" Modules: ");
|
||||
for(Module m : modules)
|
||||
System.out.println(" - "+m.name());
|
||||
System.out.println("-h [module] for module help");
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
if(args.length > 0) {
|
||||
for(Module m : modules)
|
||||
if(args[0].equals(m.name())) {
|
||||
String[] args2 = new String[args.length-1];
|
||||
System.arraycopy(args, 1, args2, 0, args2.length);
|
||||
m.main(args2);
|
||||
return;
|
||||
}
|
||||
if(args[0].equals("-h") && args.length >= 2) {
|
||||
for(Module m : modules)
|
||||
if(args[1].equals(m.name())) {
|
||||
m.printHelp();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
printHelp();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package codechicken.lib.tool.module;
|
||||
|
||||
import codechicken.lib.tool.ToolMain;
|
||||
import joptsimple.OptionException;
|
||||
import joptsimple.OptionParser;
|
||||
import joptsimple.OptionSet;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public abstract class JOptModule implements ToolMain.Module
|
||||
{
|
||||
OptionParser parser = new OptionParser();
|
||||
|
||||
@Override
|
||||
public void main(String[] args) {
|
||||
OptionSet options;
|
||||
try
|
||||
{
|
||||
options = parser.parse(args);
|
||||
}
|
||||
catch(OptionException ex)
|
||||
{
|
||||
System.err.println(ex.getLocalizedMessage());
|
||||
System.exit(-1);
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
main(parser, options);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void main(OptionParser parser, OptionSet options);
|
||||
|
||||
@Override
|
||||
public void printHelp() {
|
||||
try {
|
||||
parser.printHelpOn(System.out);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
package codechicken.lib.tool.module;
|
||||
|
||||
import codechicken.lib.render.QBImporter;
|
||||
import joptsimple.OptionParser;
|
||||
import joptsimple.OptionSet;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
public class ModuleQBConverter extends JOptModule
|
||||
{
|
||||
public ModuleQBConverter() {
|
||||
parser.acceptsAll(asList("?", "h", "help"), "Show the help");
|
||||
parser.acceptsAll(asList("i", "input"), "comma separated list of paths to models (.qb or directories)")
|
||||
.withRequiredArg().ofType(File.class).withValuesSeparatedBy(',').required();
|
||||
parser.acceptsAll(asList("o", "out"), "Output Directory")
|
||||
.withRequiredArg().ofType(File.class);
|
||||
parser.acceptsAll(asList("o2", "textureplanes"), "2nd level optimisation. Merges coplanar polygons. Increases texture size");
|
||||
parser.acceptsAll(asList("s", "squaretextures"), "Produce square textures");
|
||||
parser.acceptsAll(asList("t", "mergetextures"), "Use the same texture for all models");
|
||||
parser.acceptsAll(asList("r", "scalemc"), "Resize model to mc standard (shrink by factor of 16)");
|
||||
}
|
||||
|
||||
protected void main(OptionParser parser, OptionSet options) {
|
||||
int flags = 0;
|
||||
if(options.has("o2")) flags |= QBImporter.TEXTUREPLANES;
|
||||
if(options.has("s")) flags |= QBImporter.SQUARETEXTURE;
|
||||
if(options.has("t")) flags |= QBImporter.MERGETEXTURES;
|
||||
if(options.has("r")) flags |= QBImporter.SCALEMC;
|
||||
|
||||
File[] input = options.valuesOf("input").toArray(new File[0]);
|
||||
File[] outDir = new File[input.length];
|
||||
if(options.has("out")) {
|
||||
File output = (File)options.valueOf("out");
|
||||
if(output.isFile())
|
||||
throw new RuntimeException("Output Path is not a directory");
|
||||
if(!output.exists())
|
||||
output.mkdirs();
|
||||
|
||||
for(int i = 0; i < input.length; i++)
|
||||
outDir[i] = output;
|
||||
} else {
|
||||
for(int i = 0; i < input.length; i++)
|
||||
outDir[i] = input[i].isDirectory() ? input[i] : input[i].getParentFile();
|
||||
}
|
||||
|
||||
for(int i = 0; i < input.length; i++) {
|
||||
File file = input[i];
|
||||
if(file.isDirectory()) {
|
||||
for(File file2 : file.listFiles())
|
||||
if(file2.getName().endsWith(".qb"))
|
||||
convert(file2, outDir[i], flags);
|
||||
}
|
||||
else
|
||||
convert(file, outDir[i], flags);
|
||||
}
|
||||
}
|
||||
|
||||
private void convert(File in, File outDir, int flags) {
|
||||
System.out.println("Converting: "+in.getName());
|
||||
QBImporter.RasterisedModel m = QBImporter.loadQB(in).toRasterisedModel(flags);
|
||||
m.export(new File(outDir, in.getName().replace(".qb", ".obj")), outDir);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return "QBConverter";
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user