From 532926a9e34803ec509f7d2b93bb9585bcca74cf Mon Sep 17 00:00:00 2001 From: Anuken Date: Wed, 2 Oct 2019 23:09:35 -0400 Subject: [PATCH] Mod reloading that works for some ridiculous reason? --- core/assets/bundles/bundle.properties | 3 + .../anuke/mindustry/core/ContentLoader.java | 8 +++ .../src/io/anuke/mindustry/core/FileTree.java | 5 ++ .../io/anuke/mindustry/game/EventType.java | 4 ++ core/src/io/anuke/mindustry/mod/Mods.java | 65 ++++++++++++++++--- .../io/anuke/mindustry/ui/ItemsDisplay.java | 2 +- .../mindustry/ui/dialogs/ModsDialog.java | 28 ++++++-- 7 files changed, 99 insertions(+), 16 deletions(-) diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index f384c8a86d..e0cefd28c1 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -72,6 +72,8 @@ mods = Mods mods.none = [LIGHT_GRAY]No mods found! mod.enabled = [lightgray]Enabled mod.disabled = [scarlet]Disabled +mod.disable = Disable +mod.enable = Enable mod.requiresrestart = The game will now close to apply the mod changes. mod.import = Import Mod mod.remove.confirm = This mod will be deleted. @@ -210,6 +212,7 @@ classic.export.text = [accent]Mindustry[] has just had a major update.\nClassic quit.confirm = Are you sure you want to quit? quit.confirm.tutorial = Are you sure you know what you're doing?\nThe tutorial can be re-taken in[accent] Settings->Game->Re-Take Tutorial.[] loading = [accent]Loading... +reloading = [accent]Reloading Mods... saving = [accent]Saving... wave = [accent]Wave {0} wave.waiting = [lightgray]Wave in {0} diff --git a/core/src/io/anuke/mindustry/core/ContentLoader.java b/core/src/io/anuke/mindustry/core/ContentLoader.java index c302eb912d..77ed6f219f 100644 --- a/core/src/io/anuke/mindustry/core/ContentLoader.java +++ b/core/src/io/anuke/mindustry/core/ContentLoader.java @@ -42,6 +42,14 @@ public class ContentLoader{ new LegacyColorMapper(), }; + /** Clears all initialized content.*/ + public void clear(){ + contentNameMap = new ObjectMap[ContentType.values().length]; + contentMap = new Array[ContentType.values().length]; + initialization = new ObjectSet<>(); + loaded = false; + } + /** Creates all content types. */ public void createContent(){ if(loaded){ diff --git a/core/src/io/anuke/mindustry/core/FileTree.java b/core/src/io/anuke/mindustry/core/FileTree.java index 1537c73da3..e6d7e78086 100644 --- a/core/src/io/anuke/mindustry/core/FileTree.java +++ b/core/src/io/anuke/mindustry/core/FileTree.java @@ -22,6 +22,11 @@ public class FileTree implements FileHandleResolver{ } } + /** Clears all mod files.*/ + public void clear(){ + files.clear(); + } + @Override public FileHandle resolve(String fileName){ return get(fileName); diff --git a/core/src/io/anuke/mindustry/game/EventType.java b/core/src/io/anuke/mindustry/game/EventType.java index 30817303a0..f26dc08970 100644 --- a/core/src/io/anuke/mindustry/game/EventType.java +++ b/core/src/io/anuke/mindustry/game/EventType.java @@ -83,6 +83,10 @@ public class EventType{ } + public static class ContentReloadEvent{ + + } + public static class DisposeEvent{ } diff --git a/core/src/io/anuke/mindustry/mod/Mods.java b/core/src/io/anuke/mindustry/mod/Mods.java index fb55a8142f..295ece2f85 100644 --- a/core/src/io/anuke/mindustry/mod/Mods.java +++ b/core/src/io/anuke/mindustry/mod/Mods.java @@ -15,8 +15,10 @@ import io.anuke.arc.util.*; import io.anuke.arc.util.io.*; import io.anuke.arc.util.serialization.*; import io.anuke.mindustry.game.*; +import io.anuke.mindustry.gen.*; import io.anuke.mindustry.plugin.*; import io.anuke.mindustry.type.*; +import io.anuke.mindustry.ui.*; import java.io.*; import java.net.*; @@ -33,8 +35,9 @@ public class Mods implements Loadable{ private PixmapPacker packer; private Array loaded = new Array<>(); + private Array disabled = new Array<>(); private ObjectMap, ModMeta> metas = new ObjectMap<>(); - private boolean requiresRestart; + private boolean requiresReload; /** Returns a file named 'config.json' in a special folder for the specified plugin. * Call this in init(). */ @@ -60,7 +63,7 @@ public class Mods implements Loadable{ file.copyTo(dest); try{ loaded.add(loadMod(file)); - requiresRestart = true; + requiresReload = true; }catch(IOException e){ dest.delete(); throw e; @@ -137,6 +140,7 @@ public class Mods implements Loadable{ } packer.dispose(); + packer = null; } /** Removes a mod file and marks it for requiring a restart. */ @@ -147,11 +151,11 @@ public class Mods implements Loadable{ mod.file.delete(); } loaded.remove(mod); - requiresRestart = true; + requiresReload = true; } - public boolean requiresRestart(){ - return requiresRestart; + public boolean requiresReload(){ + return requiresReload; } /** Loads all mods from the folder, but does call any methods on them.*/ @@ -160,7 +164,12 @@ public class Mods implements Loadable{ if(!file.extension().equals("jar") && !file.extension().equals("zip") && !(file.isDirectory() && file.child("mod.json").exists())) continue; try{ - loaded.add(loadMod(file)); + LoadedMod mod = loadMod(file); + if(mod.enabled()){ + loaded.add(mod); + }else{ + disabled.add(mod); + } }catch(IllegalArgumentException ignored){ }catch(Exception e){ Log.err("Failed to load plugin file {0}. Skipping.", file); @@ -212,6 +221,23 @@ public class Mods implements Loadable{ } } + /** Reloads all mod content.*/ + public void reloadContent(){ + //epic memory leak + Core.atlas = new TextureAtlas(Core.files.internal("sprites/sprites.atlas")); + Tex.load(); + Tex.loadStyles(); + Styles.load(); + content.clear(); + content.createContent(); + loadAsync(); + loadSync(); + buildFiles(); + content.init(); + content.load(); + content.loadColors(); + } + /** Creates all the content found in mod files. */ public void loadContent(){ for(LoadedMod mod : loaded){ @@ -247,6 +273,11 @@ public class Mods implements Loadable{ return loaded; } + /** @return all disabled mods. */ + public Array disabled(){ + return disabled; + } + /** @return a list of mod names only, without versions. */ public Array getModNames(){ return loaded.select(l -> !l.meta.hidden).map(l -> l.name + ":" + l.meta.version); @@ -257,6 +288,21 @@ public class Mods implements Loadable{ return loaded.select(l -> !l.meta.hidden).map(l -> l.name + ":" + l.meta.version); } + /** Makes a mod enabled or disabled. shifts it.*/ + public void setEnabled(LoadedMod mod, boolean enabled){ + if(mod.enabled() != enabled){ + Core.settings.putSave(mod.name + "-enabled", enabled); + requiresReload = true; + if(!enabled){ + loaded.remove(mod); + disabled.add(mod); + }else{ + loaded.add(mod); + disabled.remove(mod); + } + } + } + /** @return the mods that the client is missing. * The inputted array is changed to contain the extra mods that the client has but the server doesn't.*/ public Array getIncompatibility(Array out){ @@ -335,9 +381,6 @@ public class Mods implements Loadable{ /** This mod's metadata. */ public final ModMeta meta; - //TODO implement - protected boolean enabled; - public LoadedMod(FileHandle file, FileHandle root, Mod mod, ModMeta meta){ this.root = root; this.file = file; @@ -345,6 +388,10 @@ public class Mods implements Loadable{ this.meta = meta; this.name = meta.name.toLowerCase().replace(" ", "-"); } + + public boolean enabled(){ + return Core.settings.getBool(name + "-enabled", true); + } } /** Plugin metadata information.*/ diff --git a/core/src/io/anuke/mindustry/ui/ItemsDisplay.java b/core/src/io/anuke/mindustry/ui/ItemsDisplay.java index 628fb27023..5e820ba459 100644 --- a/core/src/io/anuke/mindustry/ui/ItemsDisplay.java +++ b/core/src/io/anuke/mindustry/ui/ItemsDisplay.java @@ -40,7 +40,7 @@ public class ItemsDisplay extends Table{ private String format(Item item){ builder.setLength(0); builder.append(ui.formatAmount(data.items().get(item, 0))); - if(!state.teams.get(player.getTeam()).cores.isEmpty() && state.teams.get(player.getTeam()).cores.first().entity != null && state.teams.get(player.getTeam()).cores.first().entity.items.get(item) > 0){ + if(!state.is(State.menu) && !state.teams.get(player.getTeam()).cores.isEmpty() && state.teams.get(player.getTeam()).cores.first().entity != null && state.teams.get(player.getTeam()).cores.first().entity.items.get(item) > 0){ builder.append(" [unlaunched]+ "); builder.append(ui.formatAmount(state.teams.get(player.getTeam()).cores.first().entity.items.get(item))); } diff --git a/core/src/io/anuke/mindustry/ui/dialogs/ModsDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/ModsDialog.java index d89d0f70b2..664e06ab09 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/ModsDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/ModsDialog.java @@ -1,7 +1,9 @@ package io.anuke.mindustry.ui.dialogs; import io.anuke.arc.*; +import io.anuke.arc.collection.*; import io.anuke.mindustry.gen.*; +import io.anuke.mindustry.graphics.*; import io.anuke.mindustry.mod.Mods.*; import io.anuke.mindustry.ui.*; @@ -17,9 +19,9 @@ public class ModsDialog extends FloatingDialog{ shown(this::setup); hidden(() -> { - if(mods.requiresRestart()){ - ui.showOkText("$mods", "$mod.requiresrestart", () -> { - Core.app.exit(); + if(mods.requiresReload()){ + ui.loadAnd("$reloading", () -> { + mods.reloadContent(); }); } }); @@ -34,18 +36,32 @@ public class ModsDialog extends FloatingDialog{ void setup(){ cont.clear(); cont.defaults().width(520f).pad(4); - if(!mods.all().isEmpty()){ + if(!(mods.all().isEmpty() && mods.disabled().isEmpty())){ cont.pane(table -> { table.margin(10f).top(); - for(LoadedMod mod : mods.all()){ + Array all = Array.withArrays(mods.all(), mods.disabled()); + + boolean anyDisabled = false; + for(LoadedMod mod : all){ + if(!mod.enabled() && !anyDisabled && mods.all().size > 0){ + anyDisabled = true; + table.row(); + table.addImage().growX().height(4f).pad(6f).color(Pal.gray); + } + table.table(Styles.black6, t -> { t.defaults().pad(2).left().top(); t.margin(14f).left(); t.table(title -> { title.left(); - title.add("[accent]" + mod.meta.name + "[lightgray] v" + mod.meta.version); + title.add("[accent]" + mod.meta.name + "[lightgray] v" + mod.meta.version + (" | " + Core.bundle.get(mod.enabled() ? "mod.enabled" : "mod.disabled"))); title.add().growX(); + title.addButton(mod.enabled() ? "$mod.disable" : "$mod.enable", Styles.cleart, () -> { + mods.setEnabled(mod, !mod.enabled()); + setup(); + }).height(50f).margin(8f).width(100f); + title.addImageButton(Icon.trash16Small, Styles.cleari, () -> ui.showConfirm("$confirm", "$mod.remove.confirm", () -> { mods.removeMod(mod); setup();