net.minecraftforge.gradle.tasks.MergeJarsTask Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of CelestiGradle Show documentation
Show all versions of CelestiGradle Show documentation
Gradle plugin for building Celestibytes projects. ForgeGradle included.
package net.minecraftforge.gradle.tasks;
import groovy.lang.Closure;
import java.io.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map.Entry;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;
import net.minecraftforge.gradle.tasks.abstractutil.CachedTask;
import org.gradle.api.tasks.InputFile;
import org.gradle.api.tasks.OutputFile;
import org.gradle.api.tasks.TaskAction;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.AnnotationNode;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.FieldNode;
import org.objectweb.asm.tree.MethodNode;
import com.google.common.base.Function;
import com.google.common.base.Objects;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.google.common.io.ByteStreams;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
public class MergeJarsTask extends CachedTask
{
@InputFile
private Closure mergeCfg;
@InputFile
private Closure client;
@InputFile
private Closure server;
@OutputFile
@Cached
private Closure outJar;
private static HashSet copyToServer = new HashSet();
private static HashSet copyToClient = new HashSet();
private static HashSet dontAnnotate = new HashSet();
private static HashSet dontProcess = new HashSet();
private static final boolean DEBUG = false;
@TaskAction
public void doTask() throws IOException
{
readConfig(getMergeCfg());
processJar(getClient(), getServer(), getOutJar());
}
private boolean readConfig(File mapFile)
{
try
{
FileInputStream fstream = new FileInputStream(mapFile);
DataInputStream in = new DataInputStream(fstream);
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String line;
while ((line = br.readLine()) != null)
{
line = line.split("#")[0];
char cmd = line.charAt(0);
line = line.substring(1).trim();
switch (cmd)
{
case '!':
dontAnnotate.add(line);
break;
case '<':
copyToClient.add(line);
break;
case '>':
copyToServer.add(line);
break;
case '^':
dontProcess.add(line);
break;
}
}
in.close();
return true;
}
catch (Exception e)
{
getLogger().error("Error: " + e.getMessage());
return false;
}
}
public void processJar(File clientInFile, File serverInFile, File outFile) throws IOException
{
ZipFile cInJar = null;
ZipFile sInJar = null;
ZipOutputStream outJar = null;
try
{
try
{
cInJar = new ZipFile(clientInFile);
sInJar = new ZipFile(serverInFile);
}
catch (FileNotFoundException e)
{
throw new FileNotFoundException("Could not open input file: " + e.getMessage());
}
// different messages.
try
{
outJar = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(outFile)));
}
catch (FileNotFoundException e)
{
throw new FileNotFoundException("Could not open output file: " + e.getMessage());
}
// read in the jars, and initalize some variables
HashSet resources = new HashSet();
HashMap cClasses = getClassEntries(cInJar, outJar, resources);
HashMap sClasses = getClassEntries(sInJar, outJar, resources);
HashSet cAdded = new HashSet();
// start processing
for (Entry entry : cClasses.entrySet())
{
String name = entry.getKey();
ZipEntry cEntry = entry.getValue();
ZipEntry sEntry = sClasses.get(name);
if (sEntry == null)
{
if (!copyToServer.contains(name))
{
copyClass(cInJar, cEntry, outJar, true);
cAdded.add(name);
}
else
{
if (DEBUG)
{
System.out.println("Copy class c->s : " + name);
}
copyClass(cInJar, cEntry, outJar, true);
cAdded.add(name);
}
continue;
}
sClasses.remove(name);
byte[] cData = readEntry(cInJar, entry.getValue());
byte[] sData = readEntry(sInJar, sEntry);
byte[] data = processClass(cData, sData);
ZipEntry newEntry = new ZipEntry(cEntry.getName());
outJar.putNextEntry(newEntry);
outJar.write(data);
cAdded.add(name);
}
for (Entry entry : sClasses.entrySet())
{
if (DEBUG)
{
System.out.println("Copy class s->c : " + entry.getKey());
}
copyClass(sInJar, entry.getValue(), outJar, false);
}
for (String name : new String[] { SideOnly.class.getName(), Side.class.getName() })
{
String eName = name.replace(".", "/");
String classPath = eName + ".class";
ZipEntry newEntry = new ZipEntry(classPath);
System.out.printf("Adding %s\n", classPath);
if (!cAdded.contains(eName))
{
outJar.putNextEntry(newEntry);
outJar.write(getClassBytes(name));
}
}
}
finally
{
if (cInJar != null)
{
try
{
cInJar.close();
}
catch (IOException e)
{}
}
if (sInJar != null)
{
try
{
sInJar.close();
}
catch (IOException e)
{}
}
if (outJar != null)
{
try
{
outJar.close();
}
catch (IOException e)
{}
}
}
}
private void copyClass(ZipFile inJar, ZipEntry entry, ZipOutputStream outJar, boolean isClientOnly) throws IOException
{
ClassReader reader = new ClassReader(readEntry(inJar, entry));
ClassNode classNode = new ClassNode();
reader.accept(classNode, 0);
if (!dontAnnotate.contains(classNode.name))
{
if (classNode.visibleAnnotations == null)
{
classNode.visibleAnnotations = new ArrayList();
}
classNode.visibleAnnotations.add(getSideAnn(isClientOnly));
}
ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS);
classNode.accept(writer);
byte[] data = writer.toByteArray();
ZipEntry newEntry = new ZipEntry(entry.getName());
if (outJar != null)
{
outJar.putNextEntry(newEntry);
outJar.write(data);
}
}
private byte[] readEntry(ZipFile inFile, ZipEntry entry) throws IOException
{
return ByteStreams.toByteArray(inFile.getInputStream(entry));
}
private AnnotationNode getSideAnn(boolean isClientOnly)
{
AnnotationNode ann = new AnnotationNode(Type.getDescriptor(SideOnly.class));
ann.values = new ArrayList