aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java5
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/killswitch/ConfigDirective.java39
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/killswitch/CrashDirective.java41
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/killswitch/FeedbackDirective.java38
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/killswitch/IfConfigEqualsDirective.java40
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/killswitch/Killswitch.java232
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/killswitch/KillswitchChain.java34
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/killswitch/KillswitchCondition.java23
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/killswitch/KillswitchDirective.java24
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/killswitch/ModAtLeastDirective.java35
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/killswitch/ModAtMostDirective.java36
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/killswitch/ModversionDirective.java25
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/killswitch/NOPDirective.java28
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/killswitch/SetConfigDirective.java37
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/killswitch/Shimmy.java99
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/util/DelayedChatSender.java59
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/util/MinecraftExecutor.java9
17 files changed, 803 insertions, 1 deletions
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java b/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java
index b06f2ab2..41689329 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java
@@ -59,6 +59,7 @@ import io.github.moulberry.notenoughupdates.miscfeatures.SunTzu;
import io.github.moulberry.notenoughupdates.miscfeatures.customblockzones.CustomBiomes;
import io.github.moulberry.notenoughupdates.miscfeatures.customblockzones.CustomBlockSounds;
import io.github.moulberry.notenoughupdates.miscfeatures.customblockzones.DwarvenMinesTextures;
+import io.github.moulberry.notenoughupdates.miscfeatures.killswitch.Killswitch;
import io.github.moulberry.notenoughupdates.miscfeatures.updater.AutoUpdater;
import io.github.moulberry.notenoughupdates.miscgui.CalendarOverlay;
import io.github.moulberry.notenoughupdates.miscgui.InventoryStorageSelector;
@@ -72,6 +73,7 @@ import io.github.moulberry.notenoughupdates.overlays.OverlayManager;
import io.github.moulberry.notenoughupdates.profileviewer.ProfileViewer;
import io.github.moulberry.notenoughupdates.recipes.RecipeGenerator;
import io.github.moulberry.notenoughupdates.util.Constants;
+import io.github.moulberry.notenoughupdates.util.DelayedChatSender;
import io.github.moulberry.notenoughupdates.util.SBInfo;
import io.github.moulberry.notenoughupdates.util.Utils;
import io.github.moulberry.notenoughupdates.util.XPInformation;
@@ -260,6 +262,7 @@ public class NotEnoughUpdates {
}
MinecraftForge.EVENT_BUS.register(this);
+ MinecraftForge.EVENT_BUS.register(new DelayedChatSender());
MinecraftForge.EVENT_BUS.register(new NEUEventListener(this));
MinecraftForge.EVENT_BUS.register(new RecipeGenerator(this));
MinecraftForge.EVENT_BUS.register(CapeManager.getInstance());
@@ -332,9 +335,11 @@ public class NotEnoughUpdates {
tmp.delete();
}
}));
+ Killswitch.initializeKillswitches();
}
public void saveConfig() {
+ Killswitch.runKillswitchChains();
try {
configFile.createNewFile();
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/killswitch/ConfigDirective.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/killswitch/ConfigDirective.java
new file mode 100644
index 00000000..7ede01d5
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/killswitch/ConfigDirective.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates 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.
+ *
+ * NotEnoughUpdates 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 NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.miscfeatures.killswitch;
+
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+
+import java.util.Optional;
+
+public abstract class ConfigDirective implements KillswitchDirective {
+ final String path;
+
+ protected ConfigDirective(String path) {this.path = path;}
+
+ protected Optional<Shimmy> getShimmy() {
+ NotEnoughUpdates instance = NotEnoughUpdates.INSTANCE;
+ if (instance == null) {
+ return Optional.empty();
+ }
+ return Shimmy.of(instance.config, path.split("\\."));
+ }
+
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/killswitch/CrashDirective.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/killswitch/CrashDirective.java
new file mode 100644
index 00000000..d4782bf6
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/killswitch/CrashDirective.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates 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.
+ *
+ * NotEnoughUpdates 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 NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.miscfeatures.killswitch;
+
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import net.minecraftforge.fml.common.FMLCommonHandler;
+
+import javax.swing.*;
+
+public class CrashDirective
+ implements KillswitchDirective {
+ public final String message;
+
+ public CrashDirective(String message) {this.message = message;}
+
+ @Override
+ public boolean matches() {
+ JOptionPane.showMessageDialog(null, message, "NEU Shutdown", JOptionPane.ERROR_MESSAGE);
+ NotEnoughUpdates.LOGGER.fatal("NEU has to crash due to a killswitch: " + message);
+ FMLCommonHandler.instance().exitJava(1, false);
+ System.exit(1);
+ return false;
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/killswitch/FeedbackDirective.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/killswitch/FeedbackDirective.java
new file mode 100644
index 00000000..7a254efc
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/killswitch/FeedbackDirective.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates 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.
+ *
+ * NotEnoughUpdates 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 NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.miscfeatures.killswitch;
+
+import io.github.moulberry.notenoughupdates.util.DelayedChatSender;
+import net.minecraft.util.ChatComponentText;
+
+public class FeedbackDirective
+ implements KillswitchDirective {
+ private String string;
+
+ public FeedbackDirective(String string) {
+ this.string = string;
+ }
+
+ @Override
+ public boolean matches() {
+ DelayedChatSender.sendChatMessage(new ChatComponentText(string));
+ return true;
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/killswitch/IfConfigEqualsDirective.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/killswitch/IfConfigEqualsDirective.java
new file mode 100644
index 00000000..809b008c
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/killswitch/IfConfigEqualsDirective.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates 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.
+ *
+ * NotEnoughUpdates 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 NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.miscfeatures.killswitch;
+
+import com.google.gson.JsonElement;
+
+import java.util.Objects;
+
+public class IfConfigEqualsDirective extends ConfigDirective {
+ private final JsonElement expected;
+
+ public IfConfigEqualsDirective(String path, JsonElement expected) {
+ super(path);
+ this.expected = expected;
+ }
+
+ @Override
+ public boolean matches() {
+ return getShimmy().map(shimmy ->
+ Objects.equals(shimmy.getJson(), expected)
+ ).orElse(false);
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/killswitch/Killswitch.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/killswitch/Killswitch.java
new file mode 100644
index 00000000..7f623809
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/killswitch/Killswitch.java
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates 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.
+ *
+ * NotEnoughUpdates 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 NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.miscfeatures.killswitch;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonParseException;
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import io.github.moulberry.notenoughupdates.util.MinecraftExecutor;
+import org.apache.commons.io.IOUtils;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Function;
+import java.util.function.Predicate;
+
+public class Killswitch {
+ private static Map<String, Function<List<String>, KillswitchDirective>> directives =
+ new HashMap<String, Function<List<String>, KillswitchDirective>>() {{
+ put("if_mod_at_least", args -> new ModAtLeastDirective(getJson(args, 0, Integer.class)));
+ put("if_mod_at_most", args -> new ModAtMostDirective(getJson(args, 0, Integer.class)));
+ put("crash", args -> new CrashDirective(getString(args, 0)));
+ put(
+ "if_config_equals",
+ args -> new IfConfigEqualsDirective(getString(args, 0), getJson(args, 1, JsonElement.class))
+ );
+ put(
+ "set_config",
+ args -> new SetConfigDirective(getString(args, 0), getJson(args, 1, JsonElement.class))
+ );
+ put("comment", args -> new NOPDirective());
+ put("feedback", args -> new FeedbackDirective(getString(args, 0)));
+ }};
+
+ private static final String KILLSWITCH_URL = System.getProperty(
+ "notenoughupdates.killswitchurl",
+ "https://raw.githubusercontent.com/NotEnoughUpdates/NotEnoughUpdates-REPO/master/killswitches.txt"
+ );
+
+ static final Gson GSON = new GsonBuilder()
+ .create();
+ private static Timer timer = new Timer(true);
+
+ private static String getKillswitchSource() {
+ try {
+ URL url = new URL(KILLSWITCH_URL);
+ return IOUtils.toString(url, StandardCharsets.UTF_8);
+ } catch (Exception e) {
+ NotEnoughUpdates.LOGGER.error("Failed to refresh killswitch data", e);
+ return "";
+ }
+ }
+
+ public static volatile List<KillswitchChain> killswitches = new ArrayList<>();
+
+ public static void loadKillswitchData() {
+ CompletableFuture
+ .supplyAsync(Killswitch::getKillswitchData)
+ .thenAcceptAsync(chain -> killswitches = chain, MinecraftExecutor.INSTANCE)
+ .thenAccept(x -> runKillswitchChains());
+ }
+
+ public static void runKillswitchChains() {
+ MinecraftExecutor.INSTANCE.execute(() -> {
+ for (KillswitchChain killswitch : killswitches) {
+ killswitch.run();
+ }
+ });
+ }
+
+ private static List<KillswitchChain> getKillswitchData() {
+ StringReader reader = new StringReader(getKillswitchSource());
+ try {
+ List<KillswitchChain> list = new ArrayList<>();
+ while (true) {
+ skipWhitespaces(reader);
+ reader.mark(1);
+ if (reader.read() == -1) break;
+ reader.reset();
+ try {
+ KillswitchChain killswitchChain = readChain(reader);
+ if (killswitchChain != null) {
+ list.add(killswitchChain);
+ }
+ } catch (Exception e) {
+ NotEnoughUpdates.LOGGER.error("Ran into exception while parsing killswitch chain", e);
+ }
+ }
+ return list;
+ } catch (Exception e) {
+ NotEnoughUpdates.LOGGER.error("Ran into exception while parsing killswitch file", e);
+ return Collections.emptyList();
+ }
+ }
+
+ private static KillswitchChain readChain(StringReader reader) throws IOException {
+ KillswitchChain killswitchChain = new KillswitchChain();
+ boolean bogus = false;
+ while (true) {
+ skipWhitespaces(reader);
+ if (tryConsume(reader, ';')) break;
+ KillswitchDirective directive = readDirective(reader);
+ if (directive == null) {
+ bogus = true;
+ }
+ killswitchChain.directives.add(directive);
+ }
+ if (bogus) return null;
+ return killswitchChain;
+ }
+
+ private static boolean tryConsume(StringReader reader, int c) throws IOException {
+ reader.mark(1);
+ boolean charFound = reader.read() == c;
+ if (!charFound)
+ reader.reset();
+ return charFound;
+ }
+
+ private static <T> T getJson(List<String> s, int i, Class<T> t) {
+ return GSON.fromJson(s.get(i), t);
+ }
+
+ private static String getString(List<String> s, int i) {
+ String j = s.get(i);
+ try {
+ return GSON.fromJson(j, String.class);
+ } catch (JsonParseException e) {
+ return j;
+ }
+ }
+
+ private static KillswitchDirective readDirective(StringReader reader) throws IOException {
+ skipWhitespaces(reader);
+ String name = readUntil(reader, c -> c == '(').trim();
+ if (name.length() == 0 && tryConsume(reader, -1)) return new NOPDirective();
+ List<String> arguments = new ArrayList<>();
+ if (tryConsume(reader, '(')) {
+ skipWhitespaces(reader);
+ while (!tryConsume(reader, ')')) {
+ skipWhitespaces(reader);
+ arguments.add(readArgument(reader).trim());
+ skipWhitespaces(reader);
+ }
+ } else {
+ throw new IOException("Expected (");
+ }
+ skipWhitespaces(reader);
+ Function<List<String>, KillswitchDirective> genDir = directives.get(name);
+ if (genDir == null) return null;
+ return genDir.apply(arguments);
+ }
+
+ private static String readArgument(StringReader reader) throws IOException {
+ skipWhitespaces(reader);
+ String s = readUntil(reader, c -> c == ';');
+ tryConsume(reader, ';');
+ return s;
+ }
+
+ private static void skipWhitespaces(StringReader reader) throws IOException {
+ while (true) {
+ reader.mark(1);
+ int read = reader.read();
+ if (read != ' ' && read != '\n') {
+ reader.reset();
+ break;
+ }
+ }
+ }
+
+ private static String readUntil(StringReader reader, Predicate<Character> c) throws IOException {
+ reader.mark(1);
+ char[] buf = new char[128];
+ StringBuilder sb = new StringBuilder();
+ loop:
+ while (true) {
+ int read = reader.read(buf);
+ if (read == -1) break;
+ for (int i = 0; i < read; i++) {
+ if (c.test(buf[i])) {
+ sb.append(buf, 0, i);
+ break loop;
+ }
+ }
+ sb.append(buf, 0, read);
+ }
+ reader.reset();
+ reader.skip(sb.length());
+ return sb.toString().intern();
+ }
+
+ public static void initializeKillswitches() {
+ loadKillswitchData();
+ long THIRTY_MINUTES = TimeUnit.MINUTES.toMillis(30); // Oh my god thirty virus reference
+ timer.schedule(new TimerTask() {
+ @Override
+ public void run() {
+ loadKillswitchData();
+ }
+ }, THIRTY_MINUTES, THIRTY_MINUTES);
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/killswitch/KillswitchChain.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/killswitch/KillswitchChain.java
new file mode 100644
index 00000000..4fe9a672
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/killswitch/KillswitchChain.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates 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.
+ *
+ * NotEnoughUpdates 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 NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.miscfeatures.killswitch;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class KillswitchChain {
+ public List<KillswitchDirective> directives = new ArrayList<>();
+
+ public void run() {
+ for (KillswitchDirective directive : directives) {
+ if (!directive.matches()) return;
+ }
+ }
+
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/killswitch/KillswitchCondition.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/killswitch/KillswitchCondition.java
new file mode 100644
index 00000000..ddc0141a
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/killswitch/KillswitchCondition.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates 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.
+ *
+ * NotEnoughUpdates 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 NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.miscfeatures.killswitch;
+
+public class KillswitchCondition {
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/killswitch/KillswitchDirective.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/killswitch/KillswitchDirective.java
new file mode 100644
index 00000000..543b79ff
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/killswitch/KillswitchDirective.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates 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.
+ *
+ * NotEnoughUpdates 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 NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.miscfeatures.killswitch;
+
+public interface KillswitchDirective {
+ boolean matches();
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/killswitch/ModAtLeastDirective.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/killswitch/ModAtLeastDirective.java
new file mode 100644
index 00000000..3d872fc0
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/killswitch/ModAtLeastDirective.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates 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.
+ *
+ * NotEnoughUpdates 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 NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.miscfeatures.killswitch;
+
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+
+public class ModAtLeastDirective implements KillswitchDirective {
+ public final int atLeast;
+
+ public ModAtLeastDirective(int i) {
+ this.atLeast = i;
+ }
+
+ @Override
+ public boolean matches() {
+ return NotEnoughUpdates.VERSION_ID >= atLeast;
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/killswitch/ModAtMostDirective.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/killswitch/ModAtMostDirective.java
new file mode 100644
index 00000000..1ff7d7b8
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/killswitch/ModAtMostDirective.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates 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.
+ *
+ * NotEnoughUpdates 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 NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.miscfeatures.killswitch;
+
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+
+public class ModAtMostDirective
+ implements KillswitchDirective {
+ private final int atMost;
+
+ public ModAtMostDirective(int i) {
+ this.atMost = i;
+ }
+
+ @Override
+ public boolean matches() {
+ return NotEnoughUpdates.VERSION_ID <= atMost;
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/killswitch/ModversionDirective.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/killswitch/ModversionDirective.java
new file mode 100644
index 00000000..77bb0eef
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/killswitch/ModversionDirective.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates 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.
+ *
+ * NotEnoughUpdates 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 NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.miscfeatures.killswitch;
+
+public class ModversionDirective {
+ int modVersionMax; // Kill all mods with this version, or below
+ String message;
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/killswitch/NOPDirective.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/killswitch/NOPDirective.java
new file mode 100644
index 00000000..3487eb58
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/killswitch/NOPDirective.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates 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.
+ *
+ * NotEnoughUpdates 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 NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.miscfeatures.killswitch;
+
+public class NOPDirective
+ implements KillswitchDirective {
+ @Override
+ public boolean matches() {
+ return true;
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/killswitch/SetConfigDirective.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/killswitch/SetConfigDirective.java
new file mode 100644
index 00000000..9dcd58a4
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/killswitch/SetConfigDirective.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates 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.
+ *
+ * NotEnoughUpdates 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 NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.miscfeatures.killswitch;
+
+import com.google.gson.JsonElement;
+
+public class SetConfigDirective extends ConfigDirective {
+ private final JsonElement setTo;
+
+ public SetConfigDirective(String path, JsonElement setTo) {
+ super(path);
+ this.setTo = setTo;
+ }
+
+ @Override
+ public boolean matches() {
+ getShimmy().ifPresent(shimmy -> shimmy.setJson(setTo));
+ return true;
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/killswitch/Shimmy.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/killswitch/Shimmy.java
new file mode 100644
index 00000000..e7e1059f
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/killswitch/Shimmy.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates 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.
+ *
+ * NotEnoughUpdates 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 NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.miscfeatures.killswitch;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonElement;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.reflect.Field;
+import java.util.Optional;
+
+public class Shimmy {
+
+ static final Gson gson = new Gson();
+ final MethodHandle getter, setter;
+ final Class<?> clazz;
+
+ public Shimmy(MethodHandle getter, MethodHandle setter, Class<?> clazz) {
+ this.getter = getter;
+ this.setter = setter;
+ this.clazz = clazz;
+ }
+
+ public Object get() {
+ try {
+ return getter.invoke();
+ } catch (Throwable e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public void set(Object value) {
+ try {
+ setter.invoke(value);
+ } catch (Throwable e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public JsonElement getJson() {
+ return gson.toJsonTree(get());
+ }
+
+ public void setJson(JsonElement element) {
+ set(gson.fromJson(element, clazz));
+ }
+
+ private static Object shimmy(Object source, String path) {
+ if (source == null) return null;
+ Class<?> aClass = source.getClass();
+ try {
+ Field declaredField = aClass.getDeclaredField(path);
+ return declaredField.get(source);
+ } catch (NoSuchFieldException | IllegalAccessException e) {
+ return null;
+ }
+ }
+
+ public static Optional<Shimmy> of(Object source, String... path) {
+ if (path.length == 0)
+ return Optional.empty();
+ for (int i = 0; i < path.length - 1; i++) {
+ source = shimmy(source, path[i]);
+ }
+ if (source == null)
+ return Optional.empty();
+ MethodHandles.Lookup lookup = MethodHandles.publicLookup();
+ try {
+ String lastName = path[path.length - 1];
+ Field field = source.getClass().getDeclaredField(lastName);
+ return Optional.of(new Shimmy(
+ lookup.unreflectGetter(field).bindTo(source),
+ lookup.unreflectSetter(field).bindTo(source),
+ field.getType()
+ ));
+ } catch (NoSuchFieldException | IllegalAccessException e) {
+ return Optional.empty();
+ }
+ }
+
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/DelayedChatSender.java b/src/main/java/io/github/moulberry/notenoughupdates/util/DelayedChatSender.java
new file mode 100644
index 00000000..a979c958
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/util/DelayedChatSender.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates 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.
+ *
+ * NotEnoughUpdates 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 NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.util;
+
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.entity.EntityPlayerSP;
+import net.minecraft.util.IChatComponent;
+import net.minecraftforge.event.entity.EntityJoinWorldEvent;
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+public class DelayedChatSender {
+
+ private static final List<IChatComponent> delayedMessages = new ArrayList<>();
+
+ public static void sendChatMessage(IChatComponent comp) {
+ MinecraftExecutor.INSTANCE.execute(() -> {
+ NotEnoughUpdates.LOGGER.info("Enqueuing chat message: " + comp.getUnformattedText());
+ EntityPlayerSP thePlayer = Minecraft.getMinecraft().thePlayer;
+ if (thePlayer != null) {
+ thePlayer.addChatMessage(comp);
+ } else {
+ delayedMessages.add(comp);
+ }
+ });
+ }
+
+ @SubscribeEvent
+ public void onPlayerJoinWorld(EntityJoinWorldEvent event) {
+ EntityPlayerSP thePlayer = Minecraft.getMinecraft().thePlayer;
+ if (thePlayer == null) return;
+ for (Iterator<IChatComponent> iterator = delayedMessages.iterator(); iterator.hasNext(); ) {
+ thePlayer.addChatMessage(iterator.next());
+ iterator.remove();
+ }
+ }
+
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/MinecraftExecutor.java b/src/main/java/io/github/moulberry/notenoughupdates/util/MinecraftExecutor.java
index bf973b76..bea1add5 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/util/MinecraftExecutor.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/util/MinecraftExecutor.java
@@ -19,6 +19,7 @@
package io.github.moulberry.notenoughupdates.util;
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
import net.minecraft.client.Minecraft;
import org.jetbrains.annotations.NotNull;
@@ -32,6 +33,12 @@ public class MinecraftExecutor implements Executor {
@Override
public void execute(@NotNull Runnable runnable) {
- Minecraft.getMinecraft().addScheduledTask(runnable);
+ Minecraft.getMinecraft().addScheduledTask(() -> {
+ try {
+ runnable.run();
+ } catch (Throwable t) {
+ NotEnoughUpdates.LOGGER.error("Unexpected error in NEU main thread execution", t);
+ }
+ });
}
}