mirror of
https://github.com/FalsePattern/FalsePatternLib.git
synced 2026-11-15 21:54:45 +00:00
i was too lazy to sort these changes
This commit is contained in:
15 files changed
+391
-243
No files matched your search
@@ -21,7 +21,6 @@
|
||||
package com.falsepattern.lib.dependencies;
|
||||
|
||||
import com.falsepattern.lib.StableAPI;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NonNull;
|
||||
import lombok.val;
|
||||
@@ -30,23 +29,17 @@ import java.util.Objects;
|
||||
|
||||
@StableAPI(since = "0.6.0")
|
||||
public class SemanticVersion extends Version {
|
||||
@Getter
|
||||
@Getter(onMethod_ = @StableAPI.Expose)
|
||||
private final int majorVersion;
|
||||
@Getter
|
||||
@Getter(onMethod_ = @StableAPI.Expose)
|
||||
private final int minorVersion;
|
||||
@Getter
|
||||
@Getter(onMethod_ = @StableAPI.Expose)
|
||||
private final int patchVersion;
|
||||
@Getter
|
||||
@Getter(onMethod_ = @StableAPI.Expose)
|
||||
private final String preRelease;
|
||||
@Getter
|
||||
@Getter(onMethod_ = @StableAPI.Expose)
|
||||
private final String build;
|
||||
|
||||
@StableAPI.Expose
|
||||
public SemanticVersion(int majorVersion, int minorVersion, int patchVersion, String preRelease) {
|
||||
this(majorVersion, minorVersion, patchVersion, preRelease, null);
|
||||
}
|
||||
|
||||
@Builder
|
||||
@StableAPI.Expose
|
||||
public SemanticVersion(int majorVersion, int minorVersion, int patchVersion, String preRelease, String build) {
|
||||
this.majorVersion = majorVersion;
|
||||
@@ -58,11 +51,31 @@ public class SemanticVersion extends Version {
|
||||
this.build = "".equals(build) ? null : build;
|
||||
}
|
||||
|
||||
@StableAPI.Expose
|
||||
public SemanticVersion(int majorVersion, int minorVersion, int patchVersion, String preRelease) {
|
||||
this(majorVersion, minorVersion, patchVersion, preRelease, null);
|
||||
}
|
||||
|
||||
@StableAPI.Expose
|
||||
public SemanticVersion(int majorVersion, int minorVersion, int patchVersion) {
|
||||
this(majorVersion, minorVersion, patchVersion, null, null);
|
||||
}
|
||||
|
||||
@StableAPI.Expose(since = "0.10.0")
|
||||
public SemanticVersion(int majorVersion, int minorVersion) {
|
||||
this(majorVersion, minorVersion, -1, null, null);
|
||||
}
|
||||
|
||||
@StableAPI.Expose(since = "0.10.0")
|
||||
public SemanticVersion(int majorVersion) {
|
||||
this(majorVersion, -1, -1, null, null);
|
||||
}
|
||||
|
||||
@StableAPI.Expose
|
||||
public static SemanticVersionBuilder builder() {
|
||||
return new SemanticVersionBuilder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(@NonNull Version o) {
|
||||
if (o instanceof ComplexVersion) {
|
||||
@@ -98,7 +111,62 @@ public class SemanticVersion extends Version {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return majorVersion + "." + minorVersion + "." + patchVersion + (preRelease == null ? "" : "-" + preRelease) +
|
||||
return majorVersion + (minorVersion < 0 ? "" : "." + minorVersion) + (patchVersion < 0 ? "" : "." + patchVersion) + (preRelease == null ? "" : "-" + preRelease) +
|
||||
(build == null ? "" : "+" + build);
|
||||
}
|
||||
|
||||
@StableAPI(since = "0.10.0")
|
||||
public static class SemanticVersionBuilder {
|
||||
private int majorVersion;
|
||||
private int minorVersion = -1;
|
||||
private int patchVersion = -1;
|
||||
private String preRelease;
|
||||
private String build;
|
||||
|
||||
@StableAPI.Internal
|
||||
SemanticVersionBuilder() {
|
||||
}
|
||||
|
||||
@StableAPI.Expose
|
||||
public SemanticVersionBuilder majorVersion(int majorVersion) {
|
||||
this.majorVersion = majorVersion;
|
||||
return this;
|
||||
}
|
||||
|
||||
@StableAPI.Expose
|
||||
public SemanticVersionBuilder minorVersion(int minorVersion) {
|
||||
this.minorVersion = minorVersion;
|
||||
return this;
|
||||
}
|
||||
|
||||
@StableAPI.Expose
|
||||
public SemanticVersionBuilder patchVersion(int patchVersion) {
|
||||
this.patchVersion = patchVersion;
|
||||
return this;
|
||||
}
|
||||
|
||||
@StableAPI.Expose
|
||||
public SemanticVersionBuilder preRelease(String preRelease) {
|
||||
this.preRelease = preRelease;
|
||||
return this;
|
||||
}
|
||||
|
||||
@StableAPI.Expose
|
||||
public SemanticVersionBuilder build(String build) {
|
||||
this.build = build;
|
||||
return this;
|
||||
}
|
||||
|
||||
@StableAPI.Expose
|
||||
public SemanticVersion build() {
|
||||
return new SemanticVersion(majorVersion, minorVersion, patchVersion, preRelease, build);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SemanticVersion.SemanticVersionBuilder(majorVersion=" + this.majorVersion + ", minorVersion=" +
|
||||
this.minorVersion + ", patchVersion=" + this.patchVersion + ", preRelease=" + this.preRelease +
|
||||
", build=" + this.build + ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,142 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2022 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice, this permission notice and the word "SNEED"
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* This program 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 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.falsepattern.lib.internal;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
@SuppressWarnings("ALL")
|
||||
@Getter
|
||||
class SRGGen {
|
||||
private static final Map<String, String> class_notch_srg = new HashMap<>();
|
||||
private static final Map<String, String> class_notch_mcp = new HashMap<>();
|
||||
private static final Map<String, String> class_srg_mcp = new HashMap<>();
|
||||
private static final Map<String, String> class_mcp_srg = new HashMap<>();
|
||||
private static final Map<String, String> class_mcp_notch = new HashMap<>();
|
||||
private static final Map<String, String> field_notch_srg = new HashMap<>();
|
||||
private static final Map<String, String> field_notch_mcp = new HashMap<>();
|
||||
private static final Map<String, String> field_srg_mcp = new HashMap<>();
|
||||
private static final Map<String, String> field_mcp_srg = new HashMap<>();
|
||||
private static final Map<String, String> field_mcp_notch = new HashMap<>();
|
||||
private static final Map<StringPair, StringPair> method_notch_srg = new HashMap<>();
|
||||
private static final Map<StringPair, StringPair> method_notch_mcp = new HashMap<>();
|
||||
private static final Map<StringPair, StringPair> method_srg_mcp = new HashMap<>();
|
||||
private static final Map<StringPair, StringPair> method_mcp_srg = new HashMap<>();
|
||||
private static final Map<StringPair, StringPair> method_mcp_notch = new HashMap<>();
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
Path dir = Paths.get(args[0]);
|
||||
parseLines(Files.readAllLines(dir.resolve("notch-srg.srg")), class_notch_srg, field_notch_srg,
|
||||
method_notch_srg);
|
||||
parseLines(Files.readAllLines(dir.resolve("notch-mcp.srg")), class_notch_mcp, field_notch_mcp,
|
||||
method_notch_mcp);
|
||||
parseLines(Files.readAllLines(dir.resolve("srg-mcp.srg")), class_srg_mcp, field_srg_mcp, method_srg_mcp);
|
||||
parseLines(Files.readAllLines(dir.resolve("mcp-srg.srg")), class_mcp_srg, field_mcp_srg, method_mcp_srg);
|
||||
parseLines(Files.readAllLines(dir.resolve("mcp-notch.srg")), class_mcp_notch, field_mcp_notch,
|
||||
method_mcp_notch);
|
||||
try (OutputStream output = Files.newOutputStream(dir.resolve("classes.csv"))) {
|
||||
output.write("notch,srg,mcp\n".getBytes(StandardCharsets.UTF_8));
|
||||
crossValidate(class_notch_srg, class_notch_mcp, class_srg_mcp, class_mcp_srg, class_mcp_notch, output);
|
||||
}
|
||||
try (OutputStream output = Files.newOutputStream(dir.resolve("fields.csv"))) {
|
||||
output.write("notch,srg,mcp\n".getBytes(StandardCharsets.UTF_8));
|
||||
crossValidate(field_notch_srg, field_notch_mcp, field_srg_mcp, field_mcp_srg, field_mcp_notch, output);
|
||||
}
|
||||
|
||||
try (OutputStream output = Files.newOutputStream(dir.resolve("methods.csv"))) {
|
||||
output.write("notch,notchdesc,srg,srgdesc,mcp,mcpdesc\n".getBytes(StandardCharsets.UTF_8));
|
||||
crossValidate(method_notch_srg, method_notch_mcp, method_srg_mcp, method_mcp_srg, method_mcp_notch, output);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean crossValidate(Map<?, ?> notch_srg, Map<?, ?> notch_mcp, Map<?, ?> srg_mcp, Map<?, ?> mcp_srg, Map<?, ?> mcp_notch, OutputStream output)
|
||||
throws IOException {
|
||||
for (Map.Entry<?, ?> notch_srg_entry : notch_srg.entrySet()) {
|
||||
Object notch = notch_srg_entry.getKey();
|
||||
Object srg = notch_srg_entry.getValue();
|
||||
Object mcp = notch_mcp.get(notch);
|
||||
if (!srg_mcp.get(srg).equals(mcp) || !mcp_srg.get(mcp).equals(srg) || !mcp_notch.get(mcp).equals(notch)) {
|
||||
throw new RuntimeException(notch + " - " + srg + " - " + mcp);
|
||||
}
|
||||
output.write((notch + "," + srg + "," + mcp + "\n").getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void parseLines(List<String> lines, Map<String, String> classes, Map<String, String> fields, Map<StringPair, StringPair> methods) {
|
||||
for (String line : lines) {
|
||||
String[] parts = line.split(" ");
|
||||
switch (parts[0]) {
|
||||
case "CL:":
|
||||
classes.put(parts[1], parts[2]);
|
||||
break;
|
||||
case "FD:":
|
||||
fields.put(parts[1], parts[2]);
|
||||
break;
|
||||
case "MD:":
|
||||
methods.put(new StringPair(parts[1], parts[2]), new StringPair(parts[3], parts[4]));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class StringPair {
|
||||
public final String name;
|
||||
public final String desc;
|
||||
|
||||
private StringPair(String name, String desc) {
|
||||
this.name = name;
|
||||
this.desc = desc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
StringPair that = (StringPair) o;
|
||||
return name.equals(that.name) && desc.equals(that.desc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(name, desc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name + "," + desc;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package com.falsepattern.lib.internal.impl.mixin;
|
||||
|
||||
import com.falsepattern.lib.mixin.MinecraftURLClassPath;
|
||||
import lombok.val;
|
||||
|
||||
import net.minecraft.launchwrapper.LaunchClassLoader;
|
||||
import cpw.mods.fml.common.Loader;
|
||||
import cpw.mods.fml.common.ModClassLoader;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
|
||||
public final class UCPImpl {
|
||||
private static final Object ucp;
|
||||
private static final Method addURL;
|
||||
private static final boolean GRIMOIRE;
|
||||
|
||||
static {
|
||||
boolean grimoire = false;
|
||||
String[] knownGrimoireClassNames =
|
||||
new String[]{"io.github.crucible.grimoire.Grimoire", "io.github.crucible.grimoire.common.GrimoireCore"};
|
||||
for (val className : knownGrimoireClassNames) {
|
||||
try {
|
||||
Class.forName(className, false, MinecraftURLClassPath.class.getClassLoader());
|
||||
grimoire = true;
|
||||
break;
|
||||
} catch (ClassNotFoundException ignored) {
|
||||
}
|
||||
}
|
||||
GRIMOIRE = grimoire;
|
||||
if (!GRIMOIRE) {
|
||||
try {
|
||||
val modClassLoaderField = Loader.class.getDeclaredField("modClassLoader");
|
||||
modClassLoaderField.setAccessible(true);
|
||||
|
||||
val loaderInstanceField = Loader.class.getDeclaredField("instance");
|
||||
loaderInstanceField.setAccessible(true);
|
||||
|
||||
val mainClassLoaderField = ModClassLoader.class.getDeclaredField("mainClassLoader");
|
||||
mainClassLoaderField.setAccessible(true);
|
||||
|
||||
val ucpField = LaunchClassLoader.class.getSuperclass().getDeclaredField("ucp");
|
||||
ucpField.setAccessible(true);
|
||||
|
||||
Object loader = loaderInstanceField.get(null);
|
||||
val modClassLoader = (ModClassLoader) modClassLoaderField.get(loader);
|
||||
val mainClassLoader = (LaunchClassLoader) mainClassLoaderField.get(modClassLoader);
|
||||
ucp = ucpField.get(mainClassLoader);
|
||||
addURL = ucp.getClass().getDeclaredMethod("addURL", URL.class);
|
||||
} catch (NoSuchFieldException | IllegalAccessException | NoSuchMethodException e) {
|
||||
throw new RuntimeException(e.getMessage());
|
||||
}
|
||||
} else {
|
||||
ucp = null;
|
||||
addURL = null;
|
||||
System.err.println("Grimoire detected, disabling jar loading utility");
|
||||
}
|
||||
}
|
||||
|
||||
public static void addJar(File pathToJar) throws Exception {
|
||||
if (!GRIMOIRE) {
|
||||
addURL.invoke(ucp, pathToJar.toURI().toURL());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
package com.falsepattern.lib.internal.impl.updates;
|
||||
|
||||
import com.falsepattern.json.node.JsonNode;
|
||||
import com.falsepattern.lib.dependencies.DependencyLoader;
|
||||
import com.falsepattern.lib.dependencies.Library;
|
||||
import com.falsepattern.lib.dependencies.SemanticVersion;
|
||||
import com.falsepattern.lib.internal.Internet;
|
||||
import com.falsepattern.lib.internal.Tags;
|
||||
import com.falsepattern.lib.internal.config.LibraryConfig;
|
||||
import com.falsepattern.lib.text.FormattedText;
|
||||
import com.falsepattern.lib.updates.ModUpdateInfo;
|
||||
import com.falsepattern.lib.updates.UpdateCheckException;
|
||||
import lombok.val;
|
||||
|
||||
import net.minecraft.client.resources.I18n;
|
||||
import net.minecraft.event.ClickEvent;
|
||||
import net.minecraft.util.IChatComponent;
|
||||
|
||||
import cpw.mods.fml.common.Loader;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionException;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
public final class UpdateCheckerImpl {
|
||||
private static final AtomicBoolean jsonLibraryLoaded = new AtomicBoolean(false);
|
||||
|
||||
public static List<IChatComponent> updateListToChatMessages(String initiator, List<ModUpdateInfo> updates) {
|
||||
if (updates == null || updates.size() == 0) {
|
||||
return null;
|
||||
}
|
||||
val updateText = new ArrayList<IChatComponent>(
|
||||
FormattedText.parse(I18n.format("falsepatternlib.chat.updatesavailable", initiator)).toChatText());
|
||||
val mods = Loader.instance().getIndexedModList();
|
||||
for (val update : updates) {
|
||||
val mod = mods.get(update.modID);
|
||||
updateText.addAll(
|
||||
FormattedText.parse(I18n.format("falsepatternlib.chat.modname", mod.getName())).toChatText());
|
||||
updateText.addAll(
|
||||
FormattedText.parse(I18n.format("falsepatternlib.chat.currentversion", update.currentVersion))
|
||||
.toChatText());
|
||||
updateText.addAll(
|
||||
FormattedText.parse(I18n.format("falsepatternlib.chat.latestversion", update.latestVersion))
|
||||
.toChatText());
|
||||
if (!update.updateURL.isEmpty()) {
|
||||
val pre = FormattedText.parse(I18n.format("falsepatternlib.chat.updateurlpre")).toChatText();
|
||||
val link = FormattedText.parse(I18n.format("falsepatternlib.chat.updateurl")).toChatText();
|
||||
val post = FormattedText.parse(I18n.format("falsepatternlib.chat.updateurlpost")).toChatText();
|
||||
pre.get(pre.size() - 1).appendSibling(link.get(0));
|
||||
link.get(link.size() - 1).appendSibling(post.get(0));
|
||||
for (val l : link) {
|
||||
l.getChatStyle().setChatClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, update.updateURL));
|
||||
}
|
||||
link.remove(0);
|
||||
post.remove(0);
|
||||
updateText.addAll(pre);
|
||||
updateText.addAll(link);
|
||||
updateText.addAll(post);
|
||||
}
|
||||
}
|
||||
return updateText;
|
||||
}
|
||||
|
||||
public static CompletableFuture<List<ModUpdateInfo>> fetchUpdatesAsync(String url) {
|
||||
return CompletableFuture.supplyAsync(() -> {
|
||||
if (!LibraryConfig.ENABLE_UPDATE_CHECKER) {
|
||||
throw new CompletionException(new UpdateCheckException("Update checker is disabled in config!"));
|
||||
}
|
||||
URL URL;
|
||||
try {
|
||||
URL = new URL(url);
|
||||
} catch (MalformedURLException e) {
|
||||
throw new CompletionException(new UpdateCheckException("Invalid URL: " + url, e));
|
||||
}
|
||||
if (!jsonLibraryLoaded.get()) {
|
||||
try {
|
||||
DependencyLoader.addMavenRepo("https://maven.falsepattern.com/");
|
||||
DependencyLoader.loadLibraries(Library.builder()
|
||||
.loadingModId(Tags.MODID)
|
||||
.groupId("com.falsepattern")
|
||||
.artifactId("json")
|
||||
.minVersion(new SemanticVersion(0, 4, 0))
|
||||
.maxVersion(new SemanticVersion(0, Integer.MAX_VALUE, Integer.MAX_VALUE))
|
||||
.preferredVersion(new SemanticVersion(0, 4, 1))
|
||||
.build());
|
||||
} catch (Exception e) {
|
||||
throw new CompletionException(
|
||||
new UpdateCheckException("Failed to load json library for update checker!", e));
|
||||
}
|
||||
jsonLibraryLoaded.set(true);
|
||||
}
|
||||
val result = new ArrayList<ModUpdateInfo>();
|
||||
JsonNode parsed;
|
||||
try {
|
||||
parsed = JsonNode.parse(Internet.download(URL).thenApply(String::new).join());
|
||||
} catch (CompletionException e) {
|
||||
throw new CompletionException(new UpdateCheckException("Failed to download update checker JSON file!",
|
||||
e.getCause() == null ? e : e.getCause()));
|
||||
}
|
||||
List<JsonNode> modList;
|
||||
if (parsed.isList()) {
|
||||
modList = parsed.getJavaList();
|
||||
} else {
|
||||
modList = Collections.singletonList(parsed);
|
||||
}
|
||||
val installedMods = Loader.instance().getIndexedModList();
|
||||
for (val node : modList) {
|
||||
if (!node.isObject()) {
|
||||
continue;
|
||||
}
|
||||
if (!node.containsKey("modid")) {
|
||||
continue;
|
||||
}
|
||||
if (!node.containsKey("latestVersion")) {
|
||||
continue;
|
||||
}
|
||||
val modid = node.getString("modid");
|
||||
if (!installedMods.containsKey(modid)) {
|
||||
continue;
|
||||
}
|
||||
val mod = installedMods.get(modid);
|
||||
val latestVersionsNode = node.get("latestVersion");
|
||||
List<String> latestVersions;
|
||||
if (latestVersionsNode.isString()) {
|
||||
latestVersions = Collections.singletonList(latestVersionsNode.stringValue());
|
||||
} else if (latestVersionsNode.isList()) {
|
||||
latestVersions = new ArrayList<>();
|
||||
for (val version : latestVersionsNode.getJavaList()) {
|
||||
if (!version.isString()) {
|
||||
continue;
|
||||
}
|
||||
latestVersions.add(version.stringValue());
|
||||
}
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
val currentVersion = mod.getVersion();
|
||||
if (latestVersions.contains(currentVersion)) {
|
||||
continue;
|
||||
}
|
||||
val updateURL =
|
||||
node.containsKey("updateURL") && node.get("updateURL").isString() ? node.getString("updateURL")
|
||||
: "";
|
||||
result.add(new ModUpdateInfo(modid, currentVersion, latestVersions.get(0), updateURL));
|
||||
}
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
public static List<ModUpdateInfo> fetchUpdates(String url) throws UpdateCheckException {
|
||||
try {
|
||||
return fetchUpdatesAsync(url).join();
|
||||
} catch (CompletionException e) {
|
||||
try {
|
||||
throw e.getCause();
|
||||
} catch (UpdateCheckException e1) {
|
||||
throw e1;
|
||||
} catch (Throwable e1) {
|
||||
throw new UpdateCheckException("Failed to check for updates!", e1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -21,8 +21,10 @@
|
||||
package com.falsepattern.lib.mapping;
|
||||
|
||||
import com.falsepattern.lib.StableAPI;
|
||||
import com.falsepattern.lib.dependencies.DependencyLoader;
|
||||
import com.falsepattern.lib.dependencies.Library;
|
||||
import com.falsepattern.lib.dependencies.SemanticVersion;
|
||||
import com.falsepattern.lib.internal.CoreLoadingPlugin;
|
||||
import com.falsepattern.lib.internal.FalsePatternLib;
|
||||
import com.falsepattern.lib.mapping.storage.Lookup;
|
||||
import com.falsepattern.lib.mapping.types.MappingType;
|
||||
import com.falsepattern.lib.mapping.types.NameType;
|
||||
@@ -32,9 +34,12 @@ import com.falsepattern.lib.mapping.types.UniversalMethod;
|
||||
import com.falsepattern.lib.util.ResourceUtil;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.val;
|
||||
import lombok.var;
|
||||
import org.objectweb.asm.tree.FieldInsnNode;
|
||||
import org.objectweb.asm.tree.MethodInsnNode;
|
||||
import org.tukaani.xz.LZMA2Options;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -51,9 +56,26 @@ public class MappingManager {
|
||||
return;
|
||||
}
|
||||
initialized = true;
|
||||
DependencyLoader.addMavenRepo("https://repo1.maven.org/maven2/");
|
||||
DependencyLoader.loadLibraries(Library.builder()
|
||||
.groupId("org.tukaani")
|
||||
.artifactId("xz")
|
||||
.minVersion(SemanticVersion.builder()
|
||||
.majorVersion(1)
|
||||
.minorVersion(9)
|
||||
.patchVersion(-1)
|
||||
.build())
|
||||
.preferredVersion(SemanticVersion.builder()
|
||||
.majorVersion(1)
|
||||
.minorVersion(9)
|
||||
.patchVersion(-1)
|
||||
.build())
|
||||
.build());
|
||||
val input = new DataInputStream(new LZMA2Options(6).getInputStream(ResourceUtil.getResourceFromJar("/mappings.lzma2", CoreLoadingPlugin.class)));
|
||||
{
|
||||
val classMappings =
|
||||
ResourceUtil.getResourceStringFromJar("/classes.csv", FalsePatternLib.class).split("\n");
|
||||
var classBytes = new byte[input.readInt()];
|
||||
input.readFully(classBytes);
|
||||
val classMappings = new String(classBytes).split("\n");
|
||||
for (int i = 1; i < classMappings.length; i++) {
|
||||
val line = classMappings[i].split(",");
|
||||
val clazz = new UniversalClass(line, stringPool);
|
||||
@@ -62,7 +84,9 @@ public class MappingManager {
|
||||
}
|
||||
}
|
||||
{
|
||||
val fieldMappings = ResourceUtil.getResourceStringFromJar("/fields.csv", FalsePatternLib.class).split("\n");
|
||||
var fieldBytes = new byte[input.readInt()];
|
||||
input.readFully(fieldBytes);
|
||||
var fieldMappings = new String(fieldBytes).split( "\n");
|
||||
for (int i = 1; i < fieldMappings.length; i++) {
|
||||
val line = fieldMappings[i].split(",");
|
||||
val clazz = internalLookup.get(MappingType.Notch, line[0].substring(0, line[0].lastIndexOf('/')));
|
||||
@@ -70,8 +94,9 @@ public class MappingManager {
|
||||
}
|
||||
}
|
||||
{
|
||||
val methodMappings =
|
||||
ResourceUtil.getResourceStringFromJar("/methods.csv", FalsePatternLib.class).split("\n");
|
||||
var methodBytes = new byte[input.readInt()];
|
||||
input.readFully(methodBytes);
|
||||
val methodMappings = new String(methodBytes).split("\n");
|
||||
for (int i = 1; i < methodMappings.length; i++) {
|
||||
val line = methodMappings[i].split(",");
|
||||
val clazz = internalLookup.get(MappingType.Notch, line[0].substring(0, line[0].lastIndexOf('/')));
|
||||
|
||||
@@ -21,17 +21,11 @@
|
||||
package com.falsepattern.lib.mixin;
|
||||
|
||||
import com.falsepattern.lib.StableAPI;
|
||||
import com.falsepattern.lib.internal.impl.mixin.UCPImpl;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.val;
|
||||
|
||||
import net.minecraft.launchwrapper.LaunchClassLoader;
|
||||
import cpw.mods.fml.common.Loader;
|
||||
import cpw.mods.fml.common.ModClassLoader;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
|
||||
/**
|
||||
* Backport from spongemixins 1.3 for compat with the curseforge 1.2.0 version.
|
||||
@@ -41,64 +35,8 @@ import java.net.URL;
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@StableAPI(since = "0.10.0")
|
||||
public final class MinecraftURLClassPath {
|
||||
/**
|
||||
* Utility to manipulate the minecraft URL ClassPath
|
||||
*/
|
||||
|
||||
private static final Object ucp;
|
||||
private static final Method addURL;
|
||||
private static final boolean GRIMOIRE;
|
||||
|
||||
static {
|
||||
boolean grimoire = false;
|
||||
String[] knownGrimoireClassNames =
|
||||
new String[]{"io.github.crucible.grimoire.Grimoire", "io.github.crucible.grimoire.common.GrimoireCore"};
|
||||
for (val className : knownGrimoireClassNames) {
|
||||
try {
|
||||
Class.forName(className, false, MinecraftURLClassPath.class.getClassLoader());
|
||||
grimoire = true;
|
||||
break;
|
||||
} catch (ClassNotFoundException ignored) {
|
||||
}
|
||||
}
|
||||
GRIMOIRE = grimoire;
|
||||
if (!GRIMOIRE) {
|
||||
try {
|
||||
val modClassLoaderField = Loader.class.getDeclaredField("modClassLoader");
|
||||
modClassLoaderField.setAccessible(true);
|
||||
|
||||
val loaderInstanceField = Loader.class.getDeclaredField("instance");
|
||||
loaderInstanceField.setAccessible(true);
|
||||
|
||||
val mainClassLoaderField = ModClassLoader.class.getDeclaredField("mainClassLoader");
|
||||
mainClassLoaderField.setAccessible(true);
|
||||
|
||||
val ucpField = LaunchClassLoader.class.getSuperclass().getDeclaredField("ucp");
|
||||
ucpField.setAccessible(true);
|
||||
|
||||
Object loader = loaderInstanceField.get(null);
|
||||
val modClassLoader = (ModClassLoader) modClassLoaderField.get(loader);
|
||||
val mainClassLoader = (LaunchClassLoader) mainClassLoaderField.get(modClassLoader);
|
||||
ucp = ucpField.get(mainClassLoader);
|
||||
addURL = ucp.getClass().getDeclaredMethod("addURL", URL.class);
|
||||
} catch (NoSuchFieldException | IllegalAccessException | NoSuchMethodException e) {
|
||||
throw new RuntimeException(e.getMessage());
|
||||
}
|
||||
} else {
|
||||
ucp = null;
|
||||
addURL = null;
|
||||
System.err.println("Grimoire detected, disabling jar loading utility");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a Jar to the Minecraft URL ClassPath - Needed when using mixins on classes outside of Minecraft or other
|
||||
* coremods
|
||||
*/
|
||||
@StableAPI.Expose
|
||||
public static void addJar(File pathToJar) throws Exception {
|
||||
if (!GRIMOIRE) {
|
||||
addURL.invoke(ucp, pathToJar.toURI().toURL());
|
||||
}
|
||||
UCPImpl.addJar(pathToJar);
|
||||
}
|
||||
}
|
||||
@@ -24,22 +24,22 @@ import com.falsepattern.lib.StableAPI;
|
||||
|
||||
@StableAPI(since = "0.8.3")
|
||||
public class UpdateCheckException extends Exception {
|
||||
@StableAPI.Expose
|
||||
@StableAPI.Internal
|
||||
public UpdateCheckException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
@StableAPI.Expose
|
||||
@StableAPI.Internal
|
||||
public UpdateCheckException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
@StableAPI.Expose
|
||||
@StableAPI.Internal
|
||||
public UpdateCheckException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
@StableAPI.Expose
|
||||
@StableAPI.Internal
|
||||
protected UpdateCheckException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
|
||||
super(message, cause, enableSuppression, writableStackTrace);
|
||||
}
|
||||
|
||||
@@ -20,36 +20,16 @@
|
||||
*/
|
||||
package com.falsepattern.lib.updates;
|
||||
|
||||
import com.falsepattern.json.node.JsonNode;
|
||||
import com.falsepattern.lib.StableAPI;
|
||||
import com.falsepattern.lib.dependencies.DependencyLoader;
|
||||
import com.falsepattern.lib.dependencies.Library;
|
||||
import com.falsepattern.lib.dependencies.SemanticVersion;
|
||||
import com.falsepattern.lib.internal.Internet;
|
||||
import com.falsepattern.lib.internal.Tags;
|
||||
import com.falsepattern.lib.internal.config.LibraryConfig;
|
||||
import com.falsepattern.lib.text.FormattedText;
|
||||
import lombok.val;
|
||||
import com.falsepattern.lib.internal.impl.updates.UpdateCheckerImpl;
|
||||
|
||||
import net.minecraft.client.resources.I18n;
|
||||
import net.minecraft.event.ClickEvent;
|
||||
import net.minecraft.util.IChatComponent;
|
||||
import cpw.mods.fml.common.Loader;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionException;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
@StableAPI(since = "0.8.0")
|
||||
public class UpdateChecker {
|
||||
private static final AtomicBoolean jsonLibraryLoaded = new AtomicBoolean(false);
|
||||
|
||||
|
||||
public final class UpdateChecker {
|
||||
/**
|
||||
* Checks for updates. The URL should be a JSON file that contains a list of mods, each with a mod ID, one or more
|
||||
* versions, and a URL for the user to check for updates in case the current and latest versions are different.
|
||||
@@ -76,89 +56,7 @@ public class UpdateChecker {
|
||||
*/
|
||||
@StableAPI.Expose
|
||||
public static CompletableFuture<List<ModUpdateInfo>> fetchUpdatesAsync(String url) {
|
||||
return CompletableFuture.supplyAsync(() -> {
|
||||
if (!LibraryConfig.ENABLE_UPDATE_CHECKER) {
|
||||
throw new CompletionException(new UpdateCheckException("Update checker is disabled in config!"));
|
||||
}
|
||||
URL URL;
|
||||
try {
|
||||
URL = new URL(url);
|
||||
} catch (MalformedURLException e) {
|
||||
throw new CompletionException(new UpdateCheckException("Invalid URL: " + url, e));
|
||||
}
|
||||
if (!jsonLibraryLoaded.get()) {
|
||||
try {
|
||||
DependencyLoader.addMavenRepo("https://maven.falsepattern.com/");
|
||||
DependencyLoader.loadLibraries(Library.builder()
|
||||
.loadingModId(Tags.MODID)
|
||||
.groupId("com.falsepattern")
|
||||
.artifactId("json")
|
||||
.minVersion(new SemanticVersion(0, 4, 0))
|
||||
.maxVersion(new SemanticVersion(0, Integer.MAX_VALUE, Integer.MAX_VALUE))
|
||||
.preferredVersion(new SemanticVersion(0, 4, 1))
|
||||
.build());
|
||||
} catch (Exception e) {
|
||||
throw new CompletionException(
|
||||
new UpdateCheckException("Failed to load json library for update checker!", e));
|
||||
}
|
||||
jsonLibraryLoaded.set(true);
|
||||
}
|
||||
val result = new ArrayList<ModUpdateInfo>();
|
||||
JsonNode parsed;
|
||||
try {
|
||||
parsed = JsonNode.parse(Internet.download(URL).thenApply(String::new).join());
|
||||
} catch (CompletionException e) {
|
||||
throw new CompletionException(new UpdateCheckException("Failed to download update checker JSON file!",
|
||||
e.getCause() == null ? e : e.getCause()));
|
||||
}
|
||||
List<JsonNode> modList;
|
||||
if (parsed.isList()) {
|
||||
modList = parsed.getJavaList();
|
||||
} else {
|
||||
modList = Collections.singletonList(parsed);
|
||||
}
|
||||
val installedMods = Loader.instance().getIndexedModList();
|
||||
for (val node : modList) {
|
||||
if (!node.isObject()) {
|
||||
continue;
|
||||
}
|
||||
if (!node.containsKey("modid")) {
|
||||
continue;
|
||||
}
|
||||
if (!node.containsKey("latestVersion")) {
|
||||
continue;
|
||||
}
|
||||
val modid = node.getString("modid");
|
||||
if (!installedMods.containsKey(modid)) {
|
||||
continue;
|
||||
}
|
||||
val mod = installedMods.get(modid);
|
||||
val latestVersionsNode = node.get("latestVersion");
|
||||
List<String> latestVersions;
|
||||
if (latestVersionsNode.isString()) {
|
||||
latestVersions = Collections.singletonList(latestVersionsNode.stringValue());
|
||||
} else if (latestVersionsNode.isList()) {
|
||||
latestVersions = new ArrayList<>();
|
||||
for (val version : latestVersionsNode.getJavaList()) {
|
||||
if (!version.isString()) {
|
||||
continue;
|
||||
}
|
||||
latestVersions.add(version.stringValue());
|
||||
}
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
val currentVersion = mod.getVersion();
|
||||
if (latestVersions.contains(currentVersion)) {
|
||||
continue;
|
||||
}
|
||||
val updateURL =
|
||||
node.containsKey("updateURL") && node.get("updateURL").isString() ? node.getString("updateURL")
|
||||
: "";
|
||||
result.add(new ModUpdateInfo(modid, currentVersion, latestVersions.get(0), updateURL));
|
||||
}
|
||||
return result;
|
||||
});
|
||||
return UpdateCheckerImpl.fetchUpdatesAsync(url);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -172,17 +70,7 @@ public class UpdateChecker {
|
||||
*/
|
||||
@StableAPI.Expose
|
||||
public static List<ModUpdateInfo> fetchUpdates(String url) throws UpdateCheckException {
|
||||
try {
|
||||
return fetchUpdatesAsync(url).join();
|
||||
} catch (CompletionException e) {
|
||||
try {
|
||||
throw e.getCause();
|
||||
} catch (UpdateCheckException e1) {
|
||||
throw e1;
|
||||
} catch (Throwable e1) {
|
||||
throw new UpdateCheckException("Failed to check for updates!", e1);
|
||||
}
|
||||
}
|
||||
return UpdateCheckerImpl.fetchUpdates(url);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -195,38 +83,6 @@ public class UpdateChecker {
|
||||
*/
|
||||
@StableAPI.Expose
|
||||
public static List<IChatComponent> updateListToChatMessages(String initiator, List<ModUpdateInfo> updates) {
|
||||
if (updates == null || updates.size() == 0) {
|
||||
return null;
|
||||
}
|
||||
val updateText = new ArrayList<IChatComponent>(
|
||||
FormattedText.parse(I18n.format("falsepatternlib.chat.updatesavailable", initiator)).toChatText());
|
||||
val mods = Loader.instance().getIndexedModList();
|
||||
for (val update : updates) {
|
||||
val mod = mods.get(update.modID);
|
||||
updateText.addAll(
|
||||
FormattedText.parse(I18n.format("falsepatternlib.chat.modname", mod.getName())).toChatText());
|
||||
updateText.addAll(
|
||||
FormattedText.parse(I18n.format("falsepatternlib.chat.currentversion", update.currentVersion))
|
||||
.toChatText());
|
||||
updateText.addAll(
|
||||
FormattedText.parse(I18n.format("falsepatternlib.chat.latestversion", update.latestVersion))
|
||||
.toChatText());
|
||||
if (!update.updateURL.isEmpty()) {
|
||||
val pre = FormattedText.parse(I18n.format("falsepatternlib.chat.updateurlpre")).toChatText();
|
||||
val link = FormattedText.parse(I18n.format("falsepatternlib.chat.updateurl")).toChatText();
|
||||
val post = FormattedText.parse(I18n.format("falsepatternlib.chat.updateurlpost")).toChatText();
|
||||
pre.get(pre.size() - 1).appendSibling(link.get(0));
|
||||
link.get(link.size() - 1).appendSibling(post.get(0));
|
||||
for (val l : link) {
|
||||
l.getChatStyle().setChatClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, update.updateURL));
|
||||
}
|
||||
link.remove(0);
|
||||
post.remove(0);
|
||||
updateText.addAll(pre);
|
||||
updateText.addAll(link);
|
||||
updateText.addAll(post);
|
||||
}
|
||||
}
|
||||
return updateText;
|
||||
return UpdateCheckerImpl.updateListToChatMessages(initiator, updates);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user