From e043f4bb6632da8de34c0bf3f425cca81688e8af Mon Sep 17 00:00:00 2001 From: Anuken <arnukren@gmail.com> Date: Sat, 14 Dec 2019 18:19:02 -0500 Subject: [PATCH] API cleanup --- .../io/anuke/mindustry/core/NetServer.java | 2 +- core/src/io/anuke/mindustry/mod/Mods.java | 191 +++++------------- .../mindustry/ui/dialogs/ModsDialog.java | 4 +- .../ui/fragments/PlacementFragment.java | 3 +- .../mindustry/desktop/DesktopLauncher.java | 8 +- .../mindustry/tools/ScriptStubGenerator.java | 2 +- 6 files changed, 63 insertions(+), 147 deletions(-) diff --git a/core/src/io/anuke/mindustry/core/NetServer.java b/core/src/io/anuke/mindustry/core/NetServer.java index 72d141576b..218cbd2d83 100644 --- a/core/src/io/anuke/mindustry/core/NetServer.java +++ b/core/src/io/anuke/mindustry/core/NetServer.java @@ -219,7 +219,7 @@ public class NetServer implements ApplicationListener{ @Override public void init(){ - mods.each(mod -> mod.registerClientCommands(clientCommands)); + mods.eachClass(mod -> mod.registerClientCommands(clientCommands)); } private void registerCommands(){ diff --git a/core/src/io/anuke/mindustry/mod/Mods.java b/core/src/io/anuke/mindustry/mod/Mods.java index 737aa0ede6..0a35c0d089 100644 --- a/core/src/io/anuke/mindustry/mod/Mods.java +++ b/core/src/io/anuke/mindustry/mod/Mods.java @@ -33,13 +33,12 @@ public class Mods implements Loadable{ private @Nullable Scripts scripts; private ContentParser parser = new ContentParser(); private ObjectMap<String, Array<FileHandle>> bundles = new ObjectMap<>(); - private ObjectSet<String> specialFolders = ObjectSet.with("bundles", "sprites"); + private ObjectSet<String> specialFolders = ObjectSet.with("bundles", "sprites", "sprites-override"); private int totalSprites; private MultiPacker packer; - private Array<LoadedMod> loaded = new Array<>(); - private Array<LoadedMod> disabled = new Array<>(); + private Array<LoadedMod> mods = new Array<>(); private ObjectMap<Class<?>, ModMeta> metas = new ObjectMap<>(); private boolean requiresReload; @@ -53,19 +52,19 @@ public class Mods implements Loadable{ /** Returns a list of files per mod subdirectory. */ public void listFiles(String directory, Cons2<LoadedMod, FileHandle> cons){ - for(LoadedMod mod : loaded){ + eachEnabled(mod -> { FileHandle file = mod.root.child(directory); if(file.exists()){ for(FileHandle child : file.list()){ cons.get(mod, child); } } - } + }); } /** @return the loaded mod found by class, or null if not found. */ public @Nullable LoadedMod getMod(Class<? extends Mod> type){ - return loaded.find(l -> l.mod != null && l.mod.getClass() == type); + return mods.find(m -> m.enabled() && m.main != null && m.main.getClass() == type);//loaded.find(l -> l.mod != null && l.mod.getClass() == type); } /** Imports an external mod file.*/ @@ -77,7 +76,7 @@ public class Mods implements Loadable{ file.copyTo(dest); try{ - loaded.add(loadMod(dest)); + mods.add(loadMod(dest)); requiresReload = true; }catch(IOException e){ dest.delete(); @@ -91,19 +90,19 @@ public class Mods implements Loadable{ /** Repacks all in-game sprites. */ @Override public void loadAsync(){ - if(loaded.isEmpty()) return; + if(!mods.contains(LoadedMod::enabled)) return; Time.mark(); packer = new MultiPacker(); - for(LoadedMod mod : loaded){ + eachEnabled(mod -> { Array<FileHandle> sprites = mod.root.child("sprites").findAll(f -> f.extension().equals("png")); Array<FileHandle> overrides = mod.root.child("sprites-override").findAll(f -> f.extension().equals("png")); packSprites(sprites, mod, true); packSprites(overrides, mod, false); Log.debug("Packed {0} images for mod '{1}'.", sprites.size + overrides.size, mod.meta.name); totalSprites += sprites.size + overrides.size; - } + }); for(AtlasRegion region : Core.atlas.getRegions()){ PageType type = getPage(region); @@ -198,8 +197,7 @@ public class Mods implements Loadable{ ui.showErrorMessage("$mod.delete.error"); return; } - loaded.remove(mod); - disabled.remove(mod); + mods.remove(mod); requiresReload = true; } @@ -225,11 +223,7 @@ public class Mods implements Loadable{ Log.debug("[Mods] Loading mod {0}", file); try{ LoadedMod mod = loadMod(file); - if(mod.enabled() || headless){ - loaded.add(mod); - }else{ - disabled.add(mod); - } + mods.add(mod); }catch(Exception e){ Log.err("Failed to load mod file {0}. Skipping.", file); Log.err(e); @@ -240,11 +234,7 @@ public class Mods implements Loadable{ for(FileHandle file : platform.getWorkshopContent(LoadedMod.class)){ try{ LoadedMod mod = loadMod(file); - if(mod.enabled()){ - loaded.add(mod); - }else{ - disabled.add(mod); - } + mods.add(mod); mod.addSteamID(file.name()); }catch(Exception e){ Log.err("Failed to load mod workshop file {0}. Skipping.", file); @@ -252,28 +242,24 @@ public class Mods implements Loadable{ } } - resolveDependencies(); + resolveModState(); //sort mods to make sure servers handle them properly. - loaded.sort(Structs.comparing(m -> m.name)); + mods.sort(Structs.comparing(m -> m.name)); buildFiles(); } - private void resolveDependencies(){ - Array<LoadedMod> incompatible = loaded.select(m -> !m.isSupported()); - loaded.removeAll(incompatible); - disabled.addAll(incompatible); + private void resolveModState(){ + mods.each(this::updateDependencies); - for(LoadedMod mod : Array.<LoadedMod>withArrays(loaded, disabled)){ - updateDependencies(mod); + for(LoadedMod mod : mods){ + mod.state = + !mod.isSupported() ? ModState.unsupported : + mod.hasUnmetDependencies() ? ModState.missingDependencies : + !mod.enabled() /*TODO check disabled state!*/ ? ModState.disabled : + ModState.enabled; } - - disabled.addAll(loaded.select(LoadedMod::hasUnmetDependencies)); - loaded.removeAll(LoadedMod::hasUnmetDependencies); - disabled.each(mod -> setEnabled(mod, false)); - disabled.distinct(); - loaded.distinct(); } private void updateDependencies(LoadedMod mod){ @@ -298,16 +284,16 @@ public class Mods implements Loadable{ private Array<LoadedMod> orderedMods(){ ObjectSet<LoadedMod> visited = new ObjectSet<>(); Array<LoadedMod> result = new Array<>(); - for(LoadedMod mod : loaded){ + eachEnabled(mod -> { if(!visited.contains(mod)){ topoSort(mod, result, visited); } - } + }); return result; } private LoadedMod locateMod(String name){ - return loaded.find(mod -> mod.name.equals(name)); + return mods.find(mod -> mod.enabled() && mod.name.equals(name)); } private void buildFiles(){ @@ -357,8 +343,7 @@ public class Mods implements Loadable{ //TODO make it less epic Core.atlas = new TextureAtlas(Core.files.internal("sprites/sprites.atlas")); - loaded.clear(); - disabled.clear(); + mods.clear(); load(); Sounds.dispose(); Sounds.load(); @@ -392,7 +377,7 @@ public class Mods implements Loadable{ Time.mark(); try{ - for(LoadedMod mod : loaded){ + eachEnabled(mod -> { if(mod.root.child("scripts").exists()){ content.setCurrentMod(mod); mod.scripts = mod.root.child("scripts").findAll(f -> f.extension().equals("js")); @@ -414,7 +399,7 @@ public class Mods implements Loadable{ } } } - } + }); }finally{ content.setCurrentMod(null); } @@ -486,41 +471,18 @@ public class Mods implements Loadable{ parser.markError(content, error); } - /** @return all loaded mods. */ - public Array<LoadedMod> all(){ - return loaded; - } - - /** @return all disabled mods. */ - public Array<LoadedMod> disabled(){ - return disabled; - } - - /** @return a list of mod names only, without versions. */ - public Array<String> getModNames(){ - return loaded.select(l -> !l.meta.hidden).map(l -> l.name + ":" + l.meta.version); - } - /** @return a list of mods and versions, in the format name:version. */ public Array<String> getModStrings(){ - return loaded.select(l -> !l.meta.hidden).map(l -> l.name + ":" + l.meta.version); + return mods.select(l -> !l.meta.hidden && l.enabled()).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-" + mod.name + "-enabled", enabled); - Core.settings.save(); requiresReload = true; - if(!enabled){ - loaded.remove(mod); - if(!disabled.contains(mod)) disabled.add(mod); - }else{ - if(!loaded.contains(mod)) loaded.add(mod); - disabled.remove(mod); - } - loaded.each(this::updateDependencies); - disabled.each(this::updateDependencies); + mod.state = enabled ? ModState.enabled : ModState.disabled; + mods.each(this::updateDependencies); } } @@ -537,38 +499,19 @@ public class Mods implements Loadable{ return result; } - /** Iterates through each mod with a main class.*/ - public void each(Cons<Mod> cons){ - loaded.each(p -> p.mod != null, p -> contextRun(p, () -> cons.get(p.mod))); + public Array<LoadedMod> list(){ + return mods; } - /* - public void handleError(Throwable t, LoadedMod mod){ - Array<Throwable> causes = Strings.getCauses(t); - Content content = null; - for(Throwable e : causes){ - if(e instanceof ModLoadException && ((ModLoadException) e).content != null){ - content = ((ModLoadException) e).content; - } - } + /** Iterates through each mod with a main class. */ + public void eachClass(Cons<Mod> cons){ + mods.each(p -> p.main != null, p -> contextRun(p, () -> cons.get(p.main))); + } - String realCause = "<???>"; - for(int i = causes.size -1 ; i >= 0; i--){ - if(causes.get(i).getMessage() != null){ - realCause = causes.get(i).getMessage(); - break; - } - } - - setEnabled(mod, false); - - if(content != null){ - throw new ModLoadException(Strings.format("Error loading '{0}' from mod '{1}' ({2}):\n{3}", - content, mod.meta.name, content.sourceFile == null ? "<unknown file>" : content.sourceFile.name(), realCause), content, t); - }else{ - throw new ModLoadException("Error loading mod " + mod.meta.name, t); - } - }*/ + /** Iterates through each enabled mod. */ + public void eachEnabled(Cons<LoadedMod> cons){ + mods.each(LoadedMod::enabled, cons); + } public void contextRun(LoadedMod mod, Runnable run){ try{ @@ -597,7 +540,7 @@ public class Mods implements Loadable{ String mainClass = meta.main == null ? camelized.toLowerCase() + "." + camelized + "Mod" : meta.main; String baseName = meta.name.toLowerCase().replace(" ", "-"); - if(loaded.contains(m -> m.name.equals(baseName)) || disabled.contains(m -> m.name.equals(baseName))){ + if(mods.contains(m -> m.name.equals(baseName))){ throw new IllegalArgumentException("A mod with the name '" + baseName + "' is already imported."); } @@ -641,7 +584,7 @@ public class Mods implements Loadable{ /** The root zip file; points to the contents of this mod. In the case of folders, this is the same as the mod's file. */ public final FileHandle root; /** The mod's main class; may be null. */ - public final @Nullable Mod mod; + public final @Nullable Mod main; /** Internal mod name. Used for textures. */ public final String name; /** This mod's metadata. */ @@ -652,17 +595,19 @@ public class Mods implements Loadable{ public Array<String> missingDependencies = new Array<>(); /** Script files to run. */ public Array<FileHandle> scripts = new Array<>(); + /** Current state of this mod. */ + public ModState state = ModState.disabled; - public LoadedMod(FileHandle file, FileHandle root, Mod mod, ModMeta meta){ + public LoadedMod(FileHandle file, FileHandle root, Mod main, ModMeta meta){ this.root = root; this.file = file; - this.mod = mod; + this.main = main; this.meta = meta; this.name = meta.name.toLowerCase().replace(" ", "-"); } public boolean enabled(){ - return Core.settings.getBool("mod-" + name + "-enabled", true); + return state == ModState.enabled; } public boolean hasUnmetDependencies(){ @@ -760,37 +705,11 @@ public class Mods implements Loadable{ } } - /** Thrown when an error occurs while loading a mod. - public static class ModLoadException extends RuntimeException{ - public Content content; - public LoadedMod mod; - - public ModLoadException(String message, Throwable cause){ - super(message, cause); - } - - public ModLoadException(String message, @Nullable Content content, Throwable cause){ - super(message, cause); - this.content = content; - if(content != null){ - this.mod = content.mod; - } - } - - public ModLoadException(@Nullable Content content, Throwable cause){ - super(cause); - this.content = content; - if(content != null){ - this.mod = content.mod; - } - } - - public ModLoadException(String message, @Nullable Content content){ - super(message); - this.content = content; - if(content != null){ - this.mod = content.mod; - } - } - }*/ + public enum ModState{ + enabled, + disabled, + missingDependencies, + unsupported, + contentErrors + } } diff --git a/core/src/io/anuke/mindustry/ui/dialogs/ModsDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/ModsDialog.java index efbb02693a..a9a39816fb 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/ModsDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/ModsDialog.java @@ -75,7 +75,7 @@ public class ModsDialog extends FloatingDialog{ hidden(() -> { if(mods.requiresReload()){ ui.loadAnd("$reloading", () -> { - mods.all().each(mod -> { + mods.eachEnabled(mod -> { if(mod.hasUnmetDependencies()){ ui.showErrorMessage(Core.bundle.format("mod.nowdisabled", mod.name, mod.missingDependencies.toString(", "))); } @@ -107,7 +107,7 @@ public class ModsDialog extends FloatingDialog{ cont.defaults().width(mobile ? 500 : 560f).pad(4); cont.add("$mod.reloadrequired").visible(mods::requiresReload).center().get().setAlignment(Align.center); cont.row(); - if(!(mods.all().isEmpty() && mods.disabled().isEmpty())){ + if(!mods.list().isEmpty()){ cont.pane(table -> { table.margin(10f).top(); Array<LoadedMod> all = Array.withArrays(mods.all(), mods.disabled()); diff --git a/core/src/io/anuke/mindustry/ui/fragments/PlacementFragment.java b/core/src/io/anuke/mindustry/ui/fragments/PlacementFragment.java index 5d8e5ff0e5..54ebe7b814 100644 --- a/core/src/io/anuke/mindustry/ui/fragments/PlacementFragment.java +++ b/core/src/io/anuke/mindustry/ui/fragments/PlacementFragment.java @@ -10,6 +10,7 @@ import io.anuke.arc.scene.style.*; import io.anuke.arc.scene.ui.*; import io.anuke.arc.scene.ui.layout.*; import io.anuke.arc.util.*; +import io.anuke.mindustry.content.*; import io.anuke.mindustry.entities.traits.BuilderTrait.*; import io.anuke.mindustry.entities.type.*; import io.anuke.mindustry.game.EventType.*; @@ -461,6 +462,6 @@ public class PlacementFragment extends Fragment{ /** Returns the block currently being hovered over in the world. */ Block tileDisplayBlock(){ - return hoverTile == null ? null : hoverTile.block().synthetic() ? hoverTile.block() : hoverTile.drop() != null ? hoverTile.overlay().itemDrop != null ? hoverTile.overlay() : hoverTile.floor() : null; + return hoverTile == null ? null : hoverTile.block().synthetic() ? hoverTile.block() : hoverTile.drop() != null && hoverTile.block() == Blocks.air ? hoverTile.overlay().itemDrop != null ? hoverTile.overlay() : hoverTile.floor() : null; } } diff --git a/desktop/src/io/anuke/mindustry/desktop/DesktopLauncher.java b/desktop/src/io/anuke/mindustry/desktop/DesktopLauncher.java index 6f63976bf7..1a4b30d37a 100644 --- a/desktop/src/io/anuke/mindustry/desktop/DesktopLauncher.java +++ b/desktop/src/io/anuke/mindustry/desktop/DesktopLauncher.java @@ -17,7 +17,6 @@ import io.anuke.mindustry.core.GameState.*; import io.anuke.mindustry.core.*; import io.anuke.mindustry.desktop.steam.*; import io.anuke.mindustry.game.EventType.*; -import io.anuke.mindustry.mod.Mods.*; import io.anuke.mindustry.net.*; import io.anuke.mindustry.net.Net.*; import io.anuke.mindustry.type.*; @@ -195,12 +194,9 @@ public class DesktopLauncher extends ClientLauncher{ boolean fbgp = badGPU; CrashSender.send(e, file -> { - Array<Throwable> causes = Strings.getCauses(e); - Throwable fc = causes.find(t -> t instanceof ModLoadException); - if(fc == null) fc = Strings.getFinalCause(e); - Throwable cause = fc; + Throwable fc = Strings.getFinalCause(e); if(!fbgp){ - dialog.get(() -> message("A crash has occured. It has been saved in:\n" + file.getAbsolutePath() + "\n" + cause.getClass().getSimpleName().replace("Exception", "") + (cause.getMessage() == null ? "" : ":\n" + cause.getMessage()))); + dialog.get(() -> message("A crash has occured. It has been saved in:\n" + file.getAbsolutePath() + "\n" + fc.getClass().getSimpleName().replace("Exception", "") + (fc.getMessage() == null ? "" : ":\n" + fc.getMessage()))); } }); } diff --git a/tools/src/io/anuke/mindustry/tools/ScriptStubGenerator.java b/tools/src/io/anuke/mindustry/tools/ScriptStubGenerator.java index ac29c6adb4..5a33c507c9 100644 --- a/tools/src/io/anuke/mindustry/tools/ScriptStubGenerator.java +++ b/tools/src/io/anuke/mindustry/tools/ScriptStubGenerator.java @@ -25,7 +25,7 @@ public class ScriptStubGenerator{ Array<String> blacklist = Array.with("plugin", "mod", "net", "io", "tools"); Array<String> nameBlacklist = Array.with("ClientLauncher", "NetClient", "NetServer", "ClassAccess"); Array<Class<?>> whitelist = Array.with(Draw.class, Fill.class, Lines.class, Core.class, TextureAtlas.class, TextureRegion.class, Time.class, System.class, PrintStream.class, - AtlasRegion.class, String.class, Mathf.class, Angles.class, Color.class, Runnable.class, Object.class, Icon.class, Tex.class, Sounds.class, Musics.class, Call.class); + AtlasRegion.class, String.class, Mathf.class, Angles.class, Color.class, Runnable.class, Object.class, Icon.class, Tex.class, Sounds.class, Musics.class, Call.class, Texture.class, TextureData.class, Pixmap.class); Array<String> nopackage = Array.with("java.lang", "java"); String fileTemplate = "package io.anuke.mindustry.mod;\n" +