Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* A Gradle plugin for the creation of Minecraft mods and MinecraftForge plugins.
* Copyright (C) 2013-2019 Minecraft Forge
* Copyright (C) 2020-2021 anatawa12 and other contributors
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
* USA
*/
package net.minecraftforge.gradle.tasks;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
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 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 org.objectweb.asm.tree.InnerClassNode;
import com.google.common.base.Function;
import com.google.common.base.MoreObjects;
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 groovy.lang.Closure;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import net.minecraftforge.gradle.util.caching.Cached;
import net.minecraftforge.gradle.util.caching.CachedTask;
public class MergeJars extends CachedTask
{
@InputFile
private Object client;
@InputFile
private Object server;
@OutputFile
@Cached
private Object outJar;
private final Class sideClass = net.minecraftforge.fml.relauncher.Side.class;
private final Class sideOnlyClass = net.minecraftforge.fml.relauncher.SideOnly.class;
private static final boolean DEBUG = false;
@TaskAction
public void doTask() throws IOException
{
processJar(getClient(), getServer(), getOutJar());
}
private void processJar(File clientInFile, File serverInFile, File outFile) throws IOException
{
try (ZipFile cInJar = new ZipFile(clientInFile);
ZipFile sInJar = new ZipFile(serverInFile);
ZipOutputStream outJar = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(outFile))))
{
// 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)
{
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());
try {
outJar.putNextEntry(newEntry);
outJar.write(data);
} finally {
outJar.closeEntry();
}
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[] { sideOnlyClass.getName(), sideClass.getName() })
{
String eName = name.replace(".", "/");
String classPath = eName + ".class";
ZipEntry newEntry = new ZipEntry(classPath);
if (!cAdded.contains(eName))
{
try {
outJar.putNextEntry(newEntry);
outJar.write(getClassBytes(name));
} finally {
outJar.closeEntry();
}
}
}
}
catch (FileNotFoundException e)
{
throw new FileNotFoundException("Could not open input/output file: " + e.getMessage());
}
}
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 (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
{
try (InputStream is = inFile.getInputStream(entry))
{
return ByteStreams.toByteArray(is);
}
}
private AnnotationNode getSideAnn(boolean isClientOnly)
{
AnnotationNode ann = new AnnotationNode(Type.getDescriptor(sideOnlyClass));
ann.values = new ArrayList