diff options
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); + } + }); } } |