Fix yatoclip

This commit is contained in:
ishland 2021-05-16 00:23:11 +08:00
parent 2372955f66
commit fa1bc3890e
7 changed files with 104 additions and 141 deletions

View File

@ -65,8 +65,7 @@ jobs:
- name: Apply Patches
run: |
./gradlew setupUpstream
./gradlew applyPatches
./gradlew setupUpstream applyPatches
- name: Pull Maven Cache
uses: actions/cache@v2
@ -77,11 +76,11 @@ jobs:
- name: Build Yatopia
run: |
./gradlew clean build paperclip
./gradlew clean build yatoclip
- name: Upload Artifact
uses: actions/upload-artifact@v2
with:
name: Yatopia-${{ matrix.java }}
path: yatopia-${{ steps.mcver.outputs.mcver }}-paperclip.jar
path: yatopia-${{ steps.mcver.outputs.mcver }}-yatoclip.jar

View File

@ -1,51 +1,41 @@
package org.yatopiamc.yatoclip;
import java.io.Serializable;
import java.util.Collections;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
public class PatchesMetadata {
public final Set<PatchMetadata> patches;
public final Set<Relocation> relocations;
public final Set<String> copyExcludes;
public final Map<String, String> relocationMapping;
public final Map<String, String> relocationInvertedMapping;
public PatchesMetadata(Set<PatchMetadata> patches, Set<Relocation> relocations, Set<String> copyExcludes) {
public PatchesMetadata(Set<PatchMetadata> patches, Set<String> copyExcludes, Map<String, String> relocationMapping, Map<String, String> relocationInvertedMapping) {
Objects.requireNonNull(copyExcludes);
this.copyExcludes = Collections.unmodifiableSet(copyExcludes);
Objects.requireNonNull(relocations);
this.relocations = Collections.unmodifiableSet(relocations);
Objects.requireNonNull(patches);
this.patches = Collections.unmodifiableSet(patches);
Objects.requireNonNull(relocationMapping);
this.relocationMapping = relocationMapping;
Objects.requireNonNull(relocationInvertedMapping);
this.relocationInvertedMapping = relocationInvertedMapping;
}
public static class PatchMetadata {
public final String name;
public final String originalName;
public final String targetName;
public final String originalHash;
public final String targetHash;
public final String patchHash;
public PatchMetadata(String name, String originalHash, String targetHash, String patchHash) {
this.name = name;
public PatchMetadata(String originalName, String targetName, String originalHash, String targetHash, String patchHash) {
this.originalName = originalName;
this.targetName = targetName;
this.originalHash = originalHash;
this.targetHash = targetHash;
this.patchHash = patchHash;
}
}
public static class Relocation implements Serializable {
public final String from;
public final String to;
public final boolean includeSubPackages;
public Relocation(String from, String to, boolean includeSubPackages) {
Objects.requireNonNull(from);
Objects.requireNonNull(to);
this.from = from.replaceAll("\\.", "/");
this.to = to.replaceAll("\\.", "/");
this.includeSubPackages = includeSubPackages;
}
}
}

View File

@ -70,14 +70,14 @@ public class ServerSetup {
SpecialSourceLauncher.setSpecialSourceJar(buildData.resolve("bin").resolve("SpecialSource-2.jar").toFile());
System.err.println("Applying class mapping...");
SpecialSourceLauncher.runProcess(
"map", "--only", ".", "--only", "net/minecraft", "--auto-lvt", "BASIC", "--auto-member", "SYNTHETIC",
"map", "--only", ".", "--only", "net/minecraft", "--only", "com/mojang/math", "--auto-lvt", "BASIC", "--auto-member", "SYNTHETIC",
"-i", vanillaJar.toAbsolutePath().toString(),
"-m", buildData.resolve("mappings").resolve(buildDataInfo.classMappings).toAbsolutePath().toString(),
"-o", classMappedJar.toAbsolutePath().toString()
);
System.err.println("Applying member mapping...");
SpecialSourceLauncher.runProcess(
"map", "--only", ".", "--only", "net/minecraft", "--auto-member", "LOGGER", "--auto-member", "TOKENS",
"map", "--only", ".", "--only", "net/minecraft", "--only", "com/mojang/math", "--auto-member", "LOGGER", "--auto-member", "TOKENS",
"-i", classMappedJar.toAbsolutePath().toString(),
"-m", buildData.resolve("mappings").resolve(buildDataInfo.memberMappings).toAbsolutePath().toString(),
"-o", memberMappedJar.toAbsolutePath().toString()

View File

@ -57,7 +57,7 @@ public class YatoclipPatcher {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
try (ZipFile patchedZip = new ZipFile(patchedJar.toFile())) {
for (PatchesMetadata.PatchMetadata patchMetadata : patchesMetadata.patches) {
ZipEntry zipEntry = patchedZip.getEntry(patchMetadata.name);
ZipEntry zipEntry = patchedZip.getEntry(patchMetadata.targetName);
if (zipEntry == null || !patchMetadata.targetHash.equals(ServerSetup.toHex(digest.digest(IOUtils.toByteArray(patchedZip.getInputStream(zipEntry))))))
return false;
}
@ -72,10 +72,10 @@ public class YatoclipPatcher {
static void patchJar(Path memberMappedJar, Path patchedJar) {
requireNonNull(memberMappedJar);
requireNonNull(patchedJar);
if(!memberMappedJar.toFile().isFile()) throw new IllegalArgumentException(new FileNotFoundException());
if(!memberMappedJar.toFile().isFile()) throw new IllegalArgumentException(new FileNotFoundException(memberMappedJar.toString()));
try {
patchedJar.toFile().getParentFile().mkdirs();
final ThreadLocal<ZipFile> classMappedZip = ThreadLocal.withInitial(() -> {
final ThreadLocal<ZipFile> memberMappedZip = ThreadLocal.withInitial(() -> {
try {
return new ZipFile(memberMappedJar.toFile());
} catch (IOException e) {
@ -99,7 +99,7 @@ public class YatoclipPatcher {
r.run();
} finally {
try {
classMappedZip.get().close();
memberMappedZip.get().close();
} catch (IOException e) {
e.printStackTrace();
}
@ -113,7 +113,7 @@ public class YatoclipPatcher {
try {
final Set<PatchData> patchDataSet = patchesMetadata.patches.stream().map((PatchesMetadata.PatchMetadata metadata) -> new PatchData(CompletableFuture.supplyAsync(() -> {
try {
return getPatchedBytes(classMappedZip.get(), digest.get(), metadata);
return getPatchedBytes(memberMappedZip.get(), digest.get(), metadata);
} catch (IOException | CompressorException | InvalidHeaderException e) {
throw new RuntimeException(e);
}
@ -123,19 +123,19 @@ public class YatoclipPatcher {
patchedZip.setLevel(Deflater.BEST_SPEED);
Set<String> processed = new HashSet<>();
for (PatchData patchData : patchDataSet) {
putNextEntrySafe(patchedZip, patchData.metadata.name);
putNextEntrySafe(patchedZip, patchData.metadata.targetName);
final byte[] patchedBytes = patchData.patchedBytesFuture.join();
patchedZip.write(patchedBytes);
patchedZip.closeEntry();
processed.add(patchData.metadata.name);
processed.add(patchData.metadata.targetName);
}
((Iterator<ZipEntry>) classMappedZip.get().entries()).forEachRemaining(zipEntry -> {
if (zipEntry.isDirectory() || processed.contains(applyRelocations(zipEntry.getName())) || patchesMetadata.copyExcludes.contains(zipEntry.getName()))
((Iterator<ZipEntry>) memberMappedZip.get().entries()).forEachRemaining(zipEntry -> {
if (zipEntry.isDirectory() || processed.contains(patchesMetadata.relocationMapping.getOrDefault(zipEntry.getName(), zipEntry.getName())) || patchesMetadata.copyExcludes.contains(zipEntry.getName()))
return;
try {
InputStream in = classMappedZip.get().getInputStream(zipEntry);
putNextEntrySafe(patchedZip, zipEntry.getName());
InputStream in = memberMappedZip.get().getInputStream(zipEntry);
putNextEntrySafe(patchedZip, patchesMetadata.relocationMapping.getOrDefault(zipEntry.getName(), zipEntry.getName()));
patchedZip.write(IOUtils.toByteArray(in));
patchedZip.closeEntry();
} catch (Throwable t) {
@ -152,28 +152,31 @@ public class YatoclipPatcher {
}
}
private static byte[] getPatchedBytes(ZipFile classMappedZip, MessageDigest digest, PatchesMetadata.PatchMetadata patchMetadata) throws IOException, CompressorException, InvalidHeaderException {
private static byte[] getPatchedBytes(ZipFile memberMappedZip, MessageDigest digest, PatchesMetadata.PatchMetadata patchMetadata) throws IOException, CompressorException, InvalidHeaderException {
final byte[] originalBytes;
final ZipEntry originalEntry = classMappedZip.getEntry(applyRelocationsReverse(patchMetadata.name));
final ZipEntry originalEntry = memberMappedZip.getEntry(patchMetadata.originalName);
if (originalEntry != null)
try (final InputStream in = classMappedZip.getInputStream(originalEntry)) {
try (final InputStream in = memberMappedZip.getInputStream(originalEntry)) {
originalBytes = IOUtils.toByteArray(in);
}
else originalBytes = new byte[0];
final byte[] patchBytes;
try (final InputStream in = YatoclipPatcher.class.getClassLoader().getResourceAsStream("patches/" + patchMetadata.name + ".patch")) {
try (final InputStream in = YatoclipPatcher.class.getClassLoader().getResourceAsStream("patches/" + patchMetadata.targetName + ".patch")) {
if (in == null)
throw new FileNotFoundException();
throw new FileNotFoundException("patches/" + patchMetadata.targetName + ".patch");
patchBytes = IOUtils.toByteArray(in);
}
if (!patchMetadata.originalHash.equals(ServerSetup.toHex(digest.digest(originalBytes))) || !patchMetadata.patchHash.equals(ServerSetup.toHex(digest.digest(patchBytes))))
throw new FileNotFoundException("Hash do not match");
if (!patchMetadata.originalHash.equals(ServerSetup.toHex(digest.digest(originalBytes))))
throw new FileNotFoundException(String.format("Hash do not match: original file: %s: expected %s but got %s", patchMetadata.originalName, patchMetadata.originalHash, ServerSetup.toHex(digest.digest(originalBytes))));
if (!patchMetadata.patchHash.equals(ServerSetup.toHex(digest.digest(patchBytes))))
throw new FileNotFoundException(String.format("Hash do not match: patch file: %s: expected %s but got %s", patchMetadata.targetName + ".patch", patchMetadata.patchHash, ServerSetup.toHex(digest.digest(patchBytes))));
ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
Patch.patch(originalBytes, patchBytes, byteOut);
final byte[] patchedBytes = byteOut.toByteArray();
if (!patchMetadata.targetHash.equals(ServerSetup.toHex(digest.digest(patchedBytes))))
throw new FileNotFoundException("Hash do not match");
throw new FileNotFoundException(String.format("Hash do not match: target file: %s: expected %s but got %s", patchMetadata.targetName, patchMetadata.targetHash, ServerSetup.toHex(digest.digest(patchedBytes))));
return patchedBytes;
}
@ -195,30 +198,6 @@ public class YatoclipPatcher {
patchedZip.putNextEntry(entry);
}
private static String applyRelocations(String name) {
if (!name.endsWith(".class")) return name;
if (name.indexOf('/') == -1)
name = "/" + name;
for (PatchesMetadata.Relocation relocation : patchesMetadata.relocations) {
if (name.startsWith(relocation.from) && (relocation.includeSubPackages || name.split("/").length == name.split("/").length - 1)) {
return relocation.to + name.substring(relocation.from.length());
}
}
return name;
}
private static String applyRelocationsReverse(String name) {
if (!name.endsWith(".class")) return name;
if (name.indexOf('/') == -1)
name = "/" + name;
for (PatchesMetadata.Relocation relocation : patchesMetadata.relocations) {
if (name.startsWith(relocation.to) && (relocation.includeSubPackages || name.split("/").length == name.split("/").length - 1)) {
return relocation.from + name.substring(relocation.to.length());
}
}
return name;
}
private static class PatchData {
public final CompletableFuture<byte[]> patchedBytesFuture;

View File

@ -1,7 +1,10 @@
package org.yatopiamc.yatoclip.gradle;
import com.github.jengelman.gradle.plugins.shadow.impl.RelocatorRemapper;
import com.google.common.base.Preconditions;
import com.google.common.base.Throwables;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import com.google.common.collect.Sets;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.google.gson.Gson;
@ -13,10 +16,12 @@ import org.gradle.api.internal.project.ProjectInternal;
import org.gradle.api.tasks.Copy;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.InputFile;
import org.gradle.api.tasks.Internal;
import org.gradle.api.tasks.OutputDirectory;
import org.gradle.api.tasks.TaskAction;
import org.gradle.internal.logging.progress.ProgressLogger;
import org.gradle.internal.logging.progress.ProgressLoggerFactory;
import org.gradle.work.DisableCachingByDefault;
import org.gradle.work.Incremental;
import org.gradle.workers.WorkerExecutor;
@ -32,8 +37,10 @@ import java.io.Writer;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@ -42,6 +49,7 @@ import java.util.concurrent.atomic.AtomicInteger;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
@DisableCachingByDefault
public class MakePatchesTask extends DefaultTask {
@OutputDirectory
@ -54,17 +62,17 @@ public class MakePatchesTask extends DefaultTask {
@Incremental
public File targetJar = null;
public Set<PatchesMetadata.Relocation> getRelocations() {
return relocations;
@Internal
public RelocatorRemapper remapper = null;
public RelocatorRemapper getRemapper() {
return remapper;
}
public void setRelocations(Set<PatchesMetadata.Relocation> relocations) {
this.relocations = relocations;
public void setRemapper(RelocatorRemapper remapper) {
this.remapper = remapper;
}
@Input
public Set<PatchesMetadata.Relocation> relocations;
public File getOriginalJar() {
return originalJar;
}
@ -159,11 +167,23 @@ public class MakePatchesTask extends DefaultTask {
}
}
})).build());
BiMap<String, String> relocationMap = HashBiMap.create();
genPatches.progress("Calculating relocations");
((Iterator<ZipEntry>) originalZip.get().entries()).forEachRemaining(zipEntry -> {
if (zipEntry.isDirectory()) return;
relocationMap.put(zipEntry.getName(), remapper.map(zipEntry.getName()));
});
AtomicInteger current = new AtomicInteger(0);
final int size = targetZip.get().size();
HashSet<String> processedEntries = new HashSet<>(size * 2, 0.5f);
((Iterator<ZipEntry>) targetZip.get().entries()).forEachRemaining(zipEntryT -> {
genPatches.progress("Submitting tasks (" + current.incrementAndGet() + "/" + size + ")");
if (zipEntryT.isDirectory()) return;
if (processedEntries.contains(zipEntryT.getName())) {
getLogger().warn("Duplicate entry: " + zipEntryT.getName());
return;
}
processedEntries.add(zipEntryT.getName());
executorService.execute(() -> {
ZipEntry zipEntry = targetZip.get().getEntry(zipEntryT.getName());
final String child = zipEntry.getName();
@ -172,7 +192,7 @@ public class MakePatchesTask extends DefaultTask {
outputFile.getParentFile().mkdirs();
final byte[] originalBytes;
final byte[] targetBytes;
final ZipEntry oEntry = originalZip.get().getEntry(applyRelocationsReverse(child));
final ZipEntry oEntry = originalZip.get().getEntry(relocationMap.inverse().getOrDefault(child, child));
try (
final InputStream oin = oEntry != null ? originalZip.get().getInputStream(oEntry) : null;
final InputStream tin = targetZip.get().getInputStream(zipEntry);
@ -189,7 +209,7 @@ public class MakePatchesTask extends DefaultTask {
try (final OutputStream out = new FileOutputStream(outputFile)) {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
Diff.diff(originalBytes, targetBytes, byteArrayOutputStream);
patchMetadata.add(new PatchesMetadata.PatchMetadata(child, toHex(digestThreadLocal.get().digest(originalBytes)), toHex(digestThreadLocal.get().digest(targetBytes)), toHex(digestThreadLocal.get().digest(byteArrayOutputStream.toByteArray()))));
patchMetadata.add(new PatchesMetadata.PatchMetadata(relocationMap.inverse().getOrDefault(child, child), child, toHex(digestThreadLocal.get().digest(originalBytes)), toHex(digestThreadLocal.get().digest(targetBytes)), toHex(digestThreadLocal.get().digest(byteArrayOutputStream.toByteArray()))));
out.write(byteArrayOutputStream.toByteArray());
} catch (Throwable t) {
Throwables.throwIfUnchecked(t);
@ -202,7 +222,7 @@ public class MakePatchesTask extends DefaultTask {
genPatches.progress("Calculating exclusions");
Set<String> copyExcludes = new HashSet<>();
((Iterator<ZipEntry>) originalZip.get().entries()).forEachRemaining(zipEntry -> {
if(targetZip.get().getEntry(applyRelocations(zipEntry.getName())) == null)
if(targetZip.get().getEntry(relocationMap.getOrDefault(zipEntry.getName(), zipEntry.getName())) == null)
copyExcludes.add(zipEntry.getName());
});
originalZip.get().close();
@ -216,7 +236,7 @@ public class MakePatchesTask extends DefaultTask {
genPatches.progress("Writing patches metadata");
try (final OutputStream out = new FileOutputStream(new File(outputDir, "metadata.json"));
final Writer writer = new OutputStreamWriter(out)) {
new Gson().toJson(new PatchesMetadata(patchMetadata, relocations, copyExcludes), writer);
new Gson().toJson(new PatchesMetadata(patchMetadata, copyExcludes, new HashMap<>(relocationMap), new HashMap<>(relocationMap.inverse())), writer);
}
/*
@ -234,30 +254,6 @@ public class MakePatchesTask extends DefaultTask {
}
private String applyRelocations(String name) {
if(!name.endsWith(".class")) return name;
if (name.indexOf('/') == -1)
name = "/" + name;
for (PatchesMetadata.Relocation relocation : relocations) {
if (name.startsWith(relocation.from) && (relocation.includeSubPackages || name.split("/").length == name.split("/").length - 1)) {
return relocation.to + name.substring(relocation.from.length());
}
}
return name;
}
private String applyRelocationsReverse(String name) {
if(!name.endsWith(".class")) return name;
if (name.indexOf('/') == -1)
name = "/" + name;
for (PatchesMetadata.Relocation relocation : relocations) {
if (name.startsWith(relocation.to) && (relocation.includeSubPackages || name.split("/").length == name.split("/").length - 1)) {
return relocation.from + name.substring(relocation.to.length());
}
}
return name;
}
public static String toHex(final byte[] hash) {
final StringBuilder sb = new StringBuilder(hash.length * 2);
for (byte aHash : hash) {

View File

@ -1,51 +1,41 @@
package org.yatopiamc.yatoclip.gradle;
import java.io.Serializable;
import java.util.Collections;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
public class PatchesMetadata {
public final Set<PatchMetadata> patches;
public final Set<Relocation> relocations;
public final Set<String> copyExcludes;
public final Map<String, String> relocationMapping;
public final Map<String, String> relocationInvertedMapping;
public PatchesMetadata(Set<PatchMetadata> patches, Set<Relocation> relocations, Set<String> copyExcludes) {
public PatchesMetadata(Set<PatchMetadata> patches, Set<String> copyExcludes, Map<String, String> relocationMapping, Map<String, String> relocationInvertedMapping) {
Objects.requireNonNull(copyExcludes);
this.copyExcludes = Collections.unmodifiableSet(copyExcludes);
Objects.requireNonNull(relocations);
this.relocations = Collections.unmodifiableSet(relocations);
Objects.requireNonNull(patches);
this.patches = Collections.unmodifiableSet(patches);
Objects.requireNonNull(relocationMapping);
this.relocationMapping = relocationMapping;
Objects.requireNonNull(relocationInvertedMapping);
this.relocationInvertedMapping = relocationInvertedMapping;
}
public static class PatchMetadata {
public final String name;
public final String originalName;
public final String targetName;
public final String originalHash;
public final String targetHash;
public final String patchHash;
public PatchMetadata(String name, String originalHash, String targetHash, String patchHash) {
this.name = name;
public PatchMetadata(String originalName, String targetName, String originalHash, String targetHash, String patchHash) {
this.originalName = originalName;
this.targetName = targetName;
this.originalHash = originalHash;
this.targetHash = targetHash;
this.patchHash = patchHash;
}
}
public static class Relocation implements Serializable {
public final String from;
public final String to;
public final boolean includeSubPackages;
public Relocation(String from, String to, boolean includeSubPackages) {
Objects.requireNonNull(from);
Objects.requireNonNull(to);
this.from = from.replaceAll("\\.", "/");
this.to = to.replaceAll("\\.", "/");
this.includeSubPackages = includeSubPackages;
}
}
}

View File

@ -1,4 +1,8 @@
import com.github.jengelman.gradle.plugins.shadow.ShadowPlugin
import com.github.jengelman.gradle.plugins.shadow.ShadowStats
import com.github.jengelman.gradle.plugins.shadow.impl.RelocatorRemapper
import com.github.jengelman.gradle.plugins.shadow.relocation.Relocator
import com.github.jengelman.gradle.plugins.shadow.relocation.SimpleRelocator
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
// import com.github.jengelman.gradle.plugins.shadow.transformers.Log4j2PluginsCacheFileTransformer
import transformer.ModifiedLog4j2PluginsCacheFileTransformer
@ -26,6 +30,7 @@ import org.yatopiamc.yatoclip.gradle.PropertiesUtils
import java.nio.charset.StandardCharsets.UTF_8
import java.text.SimpleDateFormat
import java.util.*
import kotlin.collections.ArrayList
import kotlin.collections.HashSet
internal fun Project.configureSubprojects() {
@ -77,7 +82,8 @@ private fun Project.configureYatoclipProject() {
originalJar = rootProject.toothpick.paperDir.resolve("work").resolve("Minecraft")
.resolve(rootProject.toothpick.minecraftVersion).resolve("${rootProject.toothpick.minecraftVersion}-m.jar")
targetJar = rootProject.toothpick.serverProject.project.tasks.getByName("shadowJar").outputs.files.singleFile
setRelocations(rootProject.toothpick.serverProject.project.extensions.getByName("relocations") as HashSet<PatchesMetadata.Relocation>)
// not sure why idea mark this as invalid
setRemapper(rootProject.toothpick.serverProject.project.extensions.getByName("relocations") as RelocatorRemapper?)
dependsOn(rootProject.toothpick.serverProject.project.tasks.getByName("shadowJar"))
doLast {
val prop = Properties()
@ -174,13 +180,17 @@ private fun Project.configureServerProject() {
into("META-INF/maven/io.papermc.paper/paper")
}
val relocationSet = HashSet<PatchesMetadata.Relocation>()
val relocationSet = ArrayList<Relocator>()
// Don't like to do this but sadly have to do this for compatibility reasons
relocate("org.bukkit.craftbukkit", "org.bukkit.craftbukkit.v${toothpick.nmsPackage}") {
exclude("org.bukkit.craftbukkit.Main*")
}
relocationSet.add(PatchesMetadata.Relocation("", "net.minecraft.server.v${toothpick.nmsPackage}", false))
val simpleRelocator = SimpleRelocator(
"org.bukkit.craftbukkit",
"org.bukkit.craftbukkit.v${toothpick.nmsPackage}",
listOf(),
listOf("org.bukkit.craftbukkit.Main*")
)
relocate(simpleRelocator)
relocationSet.add(simpleRelocator)
// Make sure we relocate deps the same as Paper et al.
val dom = project.parsePom() ?: return@getting
@ -200,19 +210,18 @@ private fun Project.configureServerProject() {
val rawString = relocation.search("rawString").firstOrNull()?.textContent?.toBoolean() ?: false
if (pattern != "org.bukkit.craftbukkit") { // We handle cb ourselves
val excludes = if (rawString) listOf("net/minecraft/data/Main*") else emptyList()
relocate(
ToothpickRelocator(
val toothpickRelocator = ToothpickRelocator(
pattern,
shadedPattern.replace("\${minecraft_version}", toothpick.nmsPackage),
rawString,
excludes = excludes
)
)
relocationSet.add(PatchesMetadata.Relocation(pattern, shadedPattern, true))
relocate(toothpickRelocator)
relocationSet.add(toothpickRelocator)
}
}
}
project.extensions.add("relocations", relocationSet)
project.extensions.add("relocations", RelocatorRemapper(relocationSet, ShadowStats()))
}
tasks.getByName("build") {
dependsOn(shadowJar)