From 58e3143e2aba768c1d73fcabd5e1856b8dd0f08b Mon Sep 17 00:00:00 2001 From: Anuken Date: Sat, 14 Dec 2019 09:33:07 -0500 Subject: [PATCH 1/6] Content cleaning --- core/assets/bundles/bundle.properties | 2 +- .../anuke/mindustry/core/ContentLoader.java | 19 ++++++++++++++++++- .../src/io/anuke/mindustry/ctype/Content.java | 15 +++++++++------ .../mindustry/entities/bullet/BulletType.java | 2 +- .../io/anuke/mindustry/mod/ContentParser.java | 12 ++++++++++++ .../anuke/mindustry/mod/ModContentInfo.java | 14 ++++++++++++++ core/src/io/anuke/mindustry/mod/Mods.java | 13 ++++++------- .../mindustry/world/blocks/BuildBlock.java | 4 ++++ .../metadata/android/en-US/changelogs/101.txt | 7 +++++++ .../android/en-US/changelogs/29553.txt | 7 +++++++ .../android/en-US/changelogs/29556.txt | 7 +++++++ .../{pl => pl-PL}/changelogs/100.1.txt | 0 .../android/{pl => pl-PL}/changelogs/100.txt | 0 .../{pl => pl-PL}/full_description.txt | 0 .../{pl => pl-PL}/short_description.txt | 0 .../android/{pl => pl-PL}/summary.txt | 0 .../metadata/android/{pl => pl-PL}/title.txt | 0 17 files changed, 86 insertions(+), 16 deletions(-) create mode 100644 core/src/io/anuke/mindustry/mod/ModContentInfo.java create mode 100644 fastlane/metadata/android/en-US/changelogs/101.txt create mode 100644 fastlane/metadata/android/en-US/changelogs/29553.txt create mode 100644 fastlane/metadata/android/en-US/changelogs/29556.txt rename fastlane/metadata/android/{pl => pl-PL}/changelogs/100.1.txt (100%) rename fastlane/metadata/android/{pl => pl-PL}/changelogs/100.txt (100%) rename fastlane/metadata/android/{pl => pl-PL}/full_description.txt (100%) rename fastlane/metadata/android/{pl => pl-PL}/short_description.txt (100%) rename fastlane/metadata/android/{pl => pl-PL}/summary.txt (100%) rename fastlane/metadata/android/{pl => pl-PL}/title.txt (100%) diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index a42c94141a..a6dae07fef 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -100,7 +100,7 @@ mod.enabled = [lightgray]Enabled mod.disabled = [scarlet]Disabled mod.disable = Disable mod.delete.error = Unable to delete mod. File may be in use. -mod.requiresversion = [scarlet]Requires game version: [accent]{0} +mod.requiresversion = [scarlet]Requires min game version: [accent]{0} mod.missingdependencies = [scarlet]Missing dependencies: {0} mod.nowdisabled = [scarlet]Mod '{0}' is missing dependencies:[accent] {1}\n[lightgray]These mods need to be downloaded first.\nThis mod will be automatically disabled. mod.enable = Enable diff --git a/core/src/io/anuke/mindustry/core/ContentLoader.java b/core/src/io/anuke/mindustry/core/ContentLoader.java index a744b032e1..52c2c865e0 100644 --- a/core/src/io/anuke/mindustry/core/ContentLoader.java +++ b/core/src/io/anuke/mindustry/core/ContentLoader.java @@ -25,6 +25,7 @@ public class ContentLoader{ private Array[] contentMap = new Array[ContentType.values().length]; private MappableContent[][] temporaryMapper; private @Nullable LoadedMod currentMod; + private @Nullable Content lastAdded; private ObjectSet> initialization = new ObjectSet<>(); private ContentList[] content = { new Fx(), @@ -146,11 +147,27 @@ public class ContentLoader{ //clear all content, currently not used } + /** Get last piece of content created for error-handling purposes. */ + public @Nullable Content getLastAdded(){ + return lastAdded; + } + + /** Remove last content added in case of an exception. */ + public void removeLast(){ + if(lastAdded != null && contentMap[lastAdded.getContentType().ordinal()].peek() == lastAdded){ + contentMap[lastAdded.getContentType().ordinal()].pop(); + if(lastAdded instanceof MappableContent){ + contentNameMap[lastAdded.getContentType().ordinal()].remove(((MappableContent)lastAdded).name); + } + } + } + public void handleContent(Content content){ + this.lastAdded = content; contentMap[content.getContentType().ordinal()].add(content); } - public void setCurrentMod(LoadedMod mod){ + public void setCurrentMod(@Nullable LoadedMod mod){ this.currentMod = mod; } diff --git a/core/src/io/anuke/mindustry/ctype/Content.java b/core/src/io/anuke/mindustry/ctype/Content.java index ab6f20d305..0e3706746b 100644 --- a/core/src/io/anuke/mindustry/ctype/Content.java +++ b/core/src/io/anuke/mindustry/ctype/Content.java @@ -1,19 +1,17 @@ package io.anuke.mindustry.ctype; -import io.anuke.arc.files.*; import io.anuke.arc.util.ArcAnnotate.*; import io.anuke.mindustry.*; -import io.anuke.mindustry.mod.Mods.*; +import io.anuke.mindustry.mod.*; import io.anuke.mindustry.type.*; /** Base class for a content type that is loaded in {@link io.anuke.mindustry.core.ContentLoader}. */ public abstract class Content implements Comparable{ public final short id; - /** The mod that loaded this piece of content. */ - public @Nullable LoadedMod mod; - /** File that this content was loaded from. */ - public @Nullable FileHandle sourceFile; + /** Info on which mod this content was loaded from. */ + public @Nullable ModContentInfo minfo; + public Content(){ this.id = (short)Vars.content.getBy(getContentType()).size; @@ -37,6 +35,11 @@ public abstract class Content implements Comparable{ public void load(){ } + /** @return whether an error ocurred during mod loading. */ + public boolean hasErrored(){ + return minfo != null && minfo.error != null; + } + @Override public int compareTo(Content c){ return Integer.compare(id, c.id); diff --git a/core/src/io/anuke/mindustry/entities/bullet/BulletType.java b/core/src/io/anuke/mindustry/entities/bullet/BulletType.java index 807218cd85..5bca990c81 100644 --- a/core/src/io/anuke/mindustry/entities/bullet/BulletType.java +++ b/core/src/io/anuke/mindustry/entities/bullet/BulletType.java @@ -150,7 +150,7 @@ public abstract class BulletType extends Content{ public void update(Bullet b){ if(homingPower > 0.0001f){ - TargetTrait target = Units.closestTarget(b.getTeam(), b.x, b.y, homingRange); + TargetTrait target = Units.closestTarget(b.getTeam(), b.x, b.y, homingRange, e -> !e.isFlying() || collidesAir); if(target != null){ b.velocity().setAngle(Mathf.slerpDelta(b.velocity().angle(), b.angleTo(target), 0.08f)); } diff --git a/core/src/io/anuke/mindustry/mod/ContentParser.java b/core/src/io/anuke/mindustry/mod/ContentParser.java index c4c9b1064c..4280dd3f24 100644 --- a/core/src/io/anuke/mindustry/mod/ContentParser.java +++ b/core/src/io/anuke/mindustry/mod/ContentParser.java @@ -258,8 +258,12 @@ public class ContentParser{ if(research[0] != null){ Block parent = find(ContentType.block, research[0]); TechNode baseNode = TechTree.create(parent, block); + LoadedMod cur = currentMod; postreads.add(() -> { + currentContent = block; + currentMod = cur; + TechNode parnode = TechTree.all.find(t -> t.block == parent); if(parnode == null){ throw new ModLoadException("Block '" + parent.name + "' isn't in the tech tree, but '" + block.name + "' requires it to be researched.", block); @@ -383,6 +387,14 @@ public class ContentParser{ } public void finishParsing(){ + reads.each(c -> { + try{ + c.run(); + }catch(Throwable t){ + + } + }); + try{ reads.each(Runnable::run); postreads.each(Runnable::run); diff --git a/core/src/io/anuke/mindustry/mod/ModContentInfo.java b/core/src/io/anuke/mindustry/mod/ModContentInfo.java new file mode 100644 index 0000000000..5e0ce32904 --- /dev/null +++ b/core/src/io/anuke/mindustry/mod/ModContentInfo.java @@ -0,0 +1,14 @@ +package io.anuke.mindustry.mod; + +import io.anuke.arc.files.*; +import io.anuke.arc.util.ArcAnnotate.*; +import io.anuke.mindustry.mod.Mods.*; + +public class ModContentInfo{ + /** The mod that loaded this piece of content. */ + public LoadedMod mod; + /** File that this content was loaded from. */ + public FileHandle sourceFile; + /** The error that occurred during loading, if applicable. Null if no error occurred. */ + public @Nullable String error; +} diff --git a/core/src/io/anuke/mindustry/mod/Mods.java b/core/src/io/anuke/mindustry/mod/Mods.java index 0030d65721..98ceba586c 100644 --- a/core/src/io/anuke/mindustry/mod/Mods.java +++ b/core/src/io/anuke/mindustry/mod/Mods.java @@ -464,16 +464,15 @@ public class Mods implements Loadable{ //make sure mod content is in proper order runs.sort(); - runs.each(l -> safeRun(l.mod, () -> { + for(LoadRun l : runs){ try{ //this binds the content but does not load it entirely Content loaded = parser.parse(l.mod, l.file.nameWithoutExtension(), l.file.readString("UTF-8"), l.file, l.type); - Log.debug("[{0}] Loaded '{1}'.", l.mod.meta.name, - (loaded instanceof UnlockableContent ? ((UnlockableContent)loaded).localizedName : loaded)); - }catch(Exception e){ + Log.debug("[{0}] Loaded '{1}'.", l.mod.meta.name, (loaded instanceof UnlockableContent ? ((UnlockableContent)loaded).localizedName : loaded)); + }catch(Throwable e){ throw new RuntimeException("Failed to parse content file '" + l.file + "' for mod '" + l.mod.meta.name + "'.", e); } - })); + } //this finishes parsing content fields parser.finishParsing(); @@ -532,7 +531,7 @@ public class Mods implements Loadable{ /** Iterates through each mod with a main class.*/ public void each(Cons cons){ - loaded.each(p -> p.mod != null, p -> safeRun(p, () -> cons.get(p.mod))); + loaded.each(p -> p.mod != null, p -> contextRun(p, () -> cons.get(p.mod))); } public void handleError(Throwable t, LoadedMod mod){ @@ -562,7 +561,7 @@ public class Mods implements Loadable{ } } - public void safeRun(LoadedMod mod, Runnable run){ + public void contextRun(LoadedMod mod, Runnable run){ try{ run.run(); }catch(Throwable t){ diff --git a/core/src/io/anuke/mindustry/world/blocks/BuildBlock.java b/core/src/io/anuke/mindustry/world/blocks/BuildBlock.java index 60d99e730c..4623857790 100644 --- a/core/src/io/anuke/mindustry/world/blocks/BuildBlock.java +++ b/core/src/io/anuke/mindustry/world/blocks/BuildBlock.java @@ -224,6 +224,10 @@ public class BuildBlock extends Block{ return false; } + if(cblock.requirements.length != accumulator.length || totalAccumulator.length != cblock.requirements.length){ + setConstruct(previous, cblock); + } + float maxProgress = core == null ? amount : checkRequired(core.items, amount, false); for(int i = 0; i < cblock.requirements.length; i++){ diff --git a/fastlane/metadata/android/en-US/changelogs/101.txt b/fastlane/metadata/android/en-US/changelogs/101.txt new file mode 100644 index 0000000000..d53a88571c --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/101.txt @@ -0,0 +1,7 @@ +- Added various new features for modding - see documentation +- Added server block state autosync +- Added support for Thai font +- Added JS scripting - unstable, not well tested +- Fixed liquid junction to item bridge crash +- Fixed launch items not saving +- General maintenance bugfixes and translation updates diff --git a/fastlane/metadata/android/en-US/changelogs/29553.txt b/fastlane/metadata/android/en-US/changelogs/29553.txt new file mode 100644 index 0000000000..d53a88571c --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/29553.txt @@ -0,0 +1,7 @@ +- Added various new features for modding - see documentation +- Added server block state autosync +- Added support for Thai font +- Added JS scripting - unstable, not well tested +- Fixed liquid junction to item bridge crash +- Fixed launch items not saving +- General maintenance bugfixes and translation updates diff --git a/fastlane/metadata/android/en-US/changelogs/29556.txt b/fastlane/metadata/android/en-US/changelogs/29556.txt new file mode 100644 index 0000000000..d53a88571c --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/29556.txt @@ -0,0 +1,7 @@ +- Added various new features for modding - see documentation +- Added server block state autosync +- Added support for Thai font +- Added JS scripting - unstable, not well tested +- Fixed liquid junction to item bridge crash +- Fixed launch items not saving +- General maintenance bugfixes and translation updates diff --git a/fastlane/metadata/android/pl/changelogs/100.1.txt b/fastlane/metadata/android/pl-PL/changelogs/100.1.txt similarity index 100% rename from fastlane/metadata/android/pl/changelogs/100.1.txt rename to fastlane/metadata/android/pl-PL/changelogs/100.1.txt diff --git a/fastlane/metadata/android/pl/changelogs/100.txt b/fastlane/metadata/android/pl-PL/changelogs/100.txt similarity index 100% rename from fastlane/metadata/android/pl/changelogs/100.txt rename to fastlane/metadata/android/pl-PL/changelogs/100.txt diff --git a/fastlane/metadata/android/pl/full_description.txt b/fastlane/metadata/android/pl-PL/full_description.txt similarity index 100% rename from fastlane/metadata/android/pl/full_description.txt rename to fastlane/metadata/android/pl-PL/full_description.txt diff --git a/fastlane/metadata/android/pl/short_description.txt b/fastlane/metadata/android/pl-PL/short_description.txt similarity index 100% rename from fastlane/metadata/android/pl/short_description.txt rename to fastlane/metadata/android/pl-PL/short_description.txt diff --git a/fastlane/metadata/android/pl/summary.txt b/fastlane/metadata/android/pl-PL/summary.txt similarity index 100% rename from fastlane/metadata/android/pl/summary.txt rename to fastlane/metadata/android/pl-PL/summary.txt diff --git a/fastlane/metadata/android/pl/title.txt b/fastlane/metadata/android/pl-PL/title.txt similarity index 100% rename from fastlane/metadata/android/pl/title.txt rename to fastlane/metadata/android/pl-PL/title.txt From 1f5a6e1bf81bab22e6bd7c23cfb76529c4cec75c Mon Sep 17 00:00:00 2001 From: Anuken Date: Sat, 14 Dec 2019 10:06:09 -0500 Subject: [PATCH 2/6] Compile error fixes --- .../mindustry/entities/bullet/BulletType.java | 2 +- .../mindustry/entities/effect/Lightning.java | 6 +++++- .../io/anuke/mindustry/mod/ContentParser.java | 18 +++++++++++++++--- .../io/anuke/mindustry/mod/ModContentInfo.java | 2 +- core/src/io/anuke/mindustry/mod/Mods.java | 11 ++++++----- 5 files changed, 28 insertions(+), 11 deletions(-) diff --git a/core/src/io/anuke/mindustry/entities/bullet/BulletType.java b/core/src/io/anuke/mindustry/entities/bullet/BulletType.java index 5bca990c81..38923955e9 100644 --- a/core/src/io/anuke/mindustry/entities/bullet/BulletType.java +++ b/core/src/io/anuke/mindustry/entities/bullet/BulletType.java @@ -137,7 +137,7 @@ public abstract class BulletType extends Content{ } for(int i = 0; i < lightining; i++){ - Lightning.create(b.getTeam(), Pal.surge, damage, b.x, b.y, Mathf.random(360f), lightningLength); + Lightning.createLighting(Lightning.nextSeed(), b.getTeam(), Pal.surge, damage, b.x, b.y, Mathf.random(360f), lightningLength); } } diff --git a/core/src/io/anuke/mindustry/entities/effect/Lightning.java b/core/src/io/anuke/mindustry/entities/effect/Lightning.java index 44bc54d1cb..8d28f33d65 100644 --- a/core/src/io/anuke/mindustry/entities/effect/Lightning.java +++ b/core/src/io/anuke/mindustry/entities/effect/Lightning.java @@ -44,7 +44,11 @@ public class Lightning extends TimedEntity implements DrawTrait, TimeTrait{ /** Create a lighting branch at a location. Use Team.none to damage everyone. */ public static void create(Team team, Color color, float damage, float x, float y, float targetAngle, int length){ - Call.createLighting(lastSeed++, team, color, damage, x, y, targetAngle, length); + Call.createLighting(nextSeed(), team, color, damage, x, y, targetAngle, length); + } + + public static int nextSeed(){ + return lastSeed++; } /** Do not invoke! */ diff --git a/core/src/io/anuke/mindustry/mod/ContentParser.java b/core/src/io/anuke/mindustry/mod/ContentParser.java index 4280dd3f24..99def211c7 100644 --- a/core/src/io/anuke/mindustry/mod/ContentParser.java +++ b/core/src/io/anuke/mindustry/mod/ContentParser.java @@ -308,7 +308,7 @@ public class ContentParser{ if(value.has(key)){ return value.getString(key); }else{ - throw new IllegalArgumentException((currentContent == null ? "" : currentContent.sourceFile + ": ") + "You are missing a \"" + key + "\". It must be added before the file can be parsed."); + throw new IllegalArgumentException("You are missing a \"" + key + "\". It must be added before the file can be parsed."); } } @@ -433,14 +433,26 @@ public class ContentParser{ currentMod = mod; boolean located = locate(type, name) != null; Content c = parsers.get(type).parse(mod.name, name, value); + c.minfo = new ModContentInfo(); + c.minfo.sourceFile = file; toBeParsed.add(c); + if(!located){ - c.sourceFile = file; - c.mod = mod; + c.minfo.mod = mod; } return c; } + public void markError(Content content, LoadedMod mod, FileHandle file, Throwable error){ + if(content.minfo == null){ + content.minfo = new ModContentInfo(); + } + + content.minfo.mod = mod; + content.minfo.sourceFile = file; + content.minfo.error = Strings.parseException(error, true); + } + private T locate(ContentType type, String name){ T first = Vars.content.getByName(type, name); //try vanilla replacement return first != null ? first : Vars.content.getByName(type, currentMod.name + "-" + name); diff --git a/core/src/io/anuke/mindustry/mod/ModContentInfo.java b/core/src/io/anuke/mindustry/mod/ModContentInfo.java index 5e0ce32904..7d1fd105ca 100644 --- a/core/src/io/anuke/mindustry/mod/ModContentInfo.java +++ b/core/src/io/anuke/mindustry/mod/ModContentInfo.java @@ -6,7 +6,7 @@ import io.anuke.mindustry.mod.Mods.*; public class ModContentInfo{ /** The mod that loaded this piece of content. */ - public LoadedMod mod; + public @Nullable LoadedMod mod; /** File that this content was loaded from. */ public FileHandle sourceFile; /** The error that occurred during loading, if applicable. Null if no error occurred. */ diff --git a/core/src/io/anuke/mindustry/mod/Mods.java b/core/src/io/anuke/mindustry/mod/Mods.java index 98ceba586c..7aa5fa21ea 100644 --- a/core/src/io/anuke/mindustry/mod/Mods.java +++ b/core/src/io/anuke/mindustry/mod/Mods.java @@ -149,7 +149,7 @@ public class Mods implements Loadable{ //generate new icons for(Array arr : content.getContentMap()){ arr.each(c -> { - if(c instanceof UnlockableContent && c.mod != null){ + if(c instanceof UnlockableContent && c.minfo != null && c.minfo.mod != null){ UnlockableContent u = (UnlockableContent)c; u.createIcons(packer); } @@ -534,6 +534,7 @@ public class Mods implements Loadable{ loaded.each(p -> p.mod != null, p -> contextRun(p, () -> cons.get(p.mod))); } + /* public void handleError(Throwable t, LoadedMod mod){ Array causes = Strings.getCauses(t); Content content = null; @@ -559,13 +560,13 @@ public class Mods implements Loadable{ }else{ throw new ModLoadException("Error loading mod " + mod.meta.name, t); } - } + }*/ public void contextRun(LoadedMod mod, Runnable run){ try{ run.run(); }catch(Throwable t){ - handleError(t, mod); + throw new RuntimeException("Error loading mod " + mod.meta.name, t); } } @@ -751,7 +752,7 @@ public class Mods implements Loadable{ } } - /** Thrown when an error occurs while loading a mod.*/ + /** Thrown when an error occurs while loading a mod. public static class ModLoadException extends RuntimeException{ public Content content; public LoadedMod mod; @@ -783,5 +784,5 @@ public class Mods implements Loadable{ this.mod = content.mod; } } - } + }*/ } From 9d3dda035c2fc2d9fdf9614a99194b78e8aff44a Mon Sep 17 00:00:00 2001 From: Anuken Date: Sat, 14 Dec 2019 12:53:37 -0500 Subject: [PATCH 3/6] Compile fixes --- .../io/anuke/mindustry/AndroidLauncher.java | 3 +- .../anuke/mindustry/core/ContentLoader.java | 6 ++-- .../src/io/anuke/mindustry/ctype/Content.java | 16 +++++++-- .../io/anuke/mindustry/mod/ContentParser.java | 36 +++++++++---------- .../anuke/mindustry/mod/ModContentInfo.java | 14 -------- .../anuke/mindustry/mod/ModCrashHandler.java | 14 ++------ core/src/io/anuke/mindustry/mod/Mods.java | 12 +++++-- core/src/io/anuke/mindustry/type/Zone.java | 4 +-- ios/src/io/anuke/mindustry/IOSLauncher.java | 3 +- 9 files changed, 49 insertions(+), 59 deletions(-) delete mode 100644 core/src/io/anuke/mindustry/mod/ModContentInfo.java diff --git a/android/src/io/anuke/mindustry/AndroidLauncher.java b/android/src/io/anuke/mindustry/AndroidLauncher.java index 24c223d2d6..e34e7ee1c4 100644 --- a/android/src/io/anuke/mindustry/AndroidLauncher.java +++ b/android/src/io/anuke/mindustry/AndroidLauncher.java @@ -18,7 +18,6 @@ import io.anuke.arc.util.*; import io.anuke.arc.util.serialization.*; import io.anuke.mindustry.game.Saves.*; import io.anuke.mindustry.io.*; -import io.anuke.mindustry.mod.*; import io.anuke.mindustry.ui.dialogs.*; import java.io.*; @@ -144,7 +143,7 @@ public class AndroidLauncher extends AndroidApplication{ useImmersiveMode = true; depth = 0; hideStatusBar = true; - errorHandler = ModCrashHandler::handle; + //errorHandler = ModCrashHandler::handle; }}); checkFiles(getIntent()); } diff --git a/core/src/io/anuke/mindustry/core/ContentLoader.java b/core/src/io/anuke/mindustry/core/ContentLoader.java index 52c2c865e0..25f425c8f9 100644 --- a/core/src/io/anuke/mindustry/core/ContentLoader.java +++ b/core/src/io/anuke/mindustry/core/ContentLoader.java @@ -115,8 +115,8 @@ public class ContentLoader{ try{ callable.get(content); }catch(Throwable e){ - if(content.mod != null){ - mods.handleError(new ModLoadException(content, e), content.mod); + if(content.minfo.mod != null){ + mods.handleContentError(content, e); }else{ throw new RuntimeException(e); } @@ -180,7 +180,7 @@ public class ContentLoader{ throw new IllegalArgumentException("Two content objects cannot have the same name! (issue: '" + content.name + "')"); } if(currentMod != null){ - content.mod = currentMod; + content.minfo.mod = currentMod; } contentNameMap[content.getContentType().ordinal()].put(content.name, content); } diff --git a/core/src/io/anuke/mindustry/ctype/Content.java b/core/src/io/anuke/mindustry/ctype/Content.java index 0e3706746b..0bcc89af14 100644 --- a/core/src/io/anuke/mindustry/ctype/Content.java +++ b/core/src/io/anuke/mindustry/ctype/Content.java @@ -1,8 +1,9 @@ package io.anuke.mindustry.ctype; +import io.anuke.arc.files.*; import io.anuke.arc.util.ArcAnnotate.*; import io.anuke.mindustry.*; -import io.anuke.mindustry.mod.*; +import io.anuke.mindustry.mod.Mods.*; import io.anuke.mindustry.type.*; @@ -10,7 +11,7 @@ import io.anuke.mindustry.type.*; public abstract class Content implements Comparable{ public final short id; /** Info on which mod this content was loaded from. */ - public @Nullable ModContentInfo minfo; + public @NonNull ModContentInfo minfo = new ModContentInfo(); public Content(){ @@ -37,7 +38,7 @@ public abstract class Content implements Comparable{ /** @return whether an error ocurred during mod loading. */ public boolean hasErrored(){ - return minfo != null && minfo.error != null; + return minfo.error != null; } @Override @@ -49,4 +50,13 @@ public abstract class Content implements Comparable{ public String toString(){ return getContentType().name() + "#" + id; } + + public static class ModContentInfo{ + /** The mod that loaded this piece of content. */ + public @Nullable LoadedMod mod; + /** File that this content was loaded from. */ + public @Nullable FileHandle sourceFile; + /** The error that occurred during loading, if applicable. Null if no error occurred. */ + public @Nullable String error; + } } diff --git a/core/src/io/anuke/mindustry/mod/ContentParser.java b/core/src/io/anuke/mindustry/mod/ContentParser.java index 99def211c7..09a030e1e6 100644 --- a/core/src/io/anuke/mindustry/mod/ContentParser.java +++ b/core/src/io/anuke/mindustry/mod/ContentParser.java @@ -266,7 +266,7 @@ public class ContentParser{ TechNode parnode = TechTree.all.find(t -> t.block == parent); if(parnode == null){ - throw new ModLoadException("Block '" + parent.name + "' isn't in the tech tree, but '" + block.name + "' requires it to be researched.", block); + throw new IllegalArgumentException("Block '" + parent.name + "' isn't in the tech tree, but '" + block.name + "' requires it to be researched."); } if(!parnode.children.contains(baseNode)){ parnode.children.add(baseNode); @@ -386,21 +386,18 @@ public class ContentParser{ } } - public void finishParsing(){ - reads.each(c -> { - try{ - c.run(); - }catch(Throwable t){ - - } - }); - + private void attempt(Runnable run){ try{ - reads.each(Runnable::run); - postreads.each(Runnable::run); - }catch(Exception e){ - Vars.mods.handleError(new ModLoadException("Error occurred parsing content: " + currentContent, currentContent, e), currentMod); + run.run(); + }catch(Throwable t){ + //don't overwrite double errors + markError(currentContent, t); } + } + + public void finishParsing(){ + reads.each(this::attempt); + postreads.each(this::attempt); reads.clear(); postreads.clear(); toBeParsed.clear(); @@ -433,7 +430,6 @@ public class ContentParser{ currentMod = mod; boolean located = locate(type, name) != null; Content c = parsers.get(type).parse(mod.name, name, value); - c.minfo = new ModContentInfo(); c.minfo.sourceFile = file; toBeParsed.add(c); @@ -444,15 +440,17 @@ public class ContentParser{ } public void markError(Content content, LoadedMod mod, FileHandle file, Throwable error){ - if(content.minfo == null){ - content.minfo = new ModContentInfo(); - } - content.minfo.mod = mod; content.minfo.sourceFile = file; content.minfo.error = Strings.parseException(error, true); } + public void markError(Content content, Throwable error){ + if(content.minfo != null && !content.hasErrored()){ + markError(content, content.minfo.mod, content.minfo.sourceFile, error); + } + } + private T locate(ContentType type, String name){ T first = Vars.content.getByName(type, name); //try vanilla replacement return first != null ? first : Vars.content.getByName(type, currentMod.name + "-" + name); diff --git a/core/src/io/anuke/mindustry/mod/ModContentInfo.java b/core/src/io/anuke/mindustry/mod/ModContentInfo.java deleted file mode 100644 index 7d1fd105ca..0000000000 --- a/core/src/io/anuke/mindustry/mod/ModContentInfo.java +++ /dev/null @@ -1,14 +0,0 @@ -package io.anuke.mindustry.mod; - -import io.anuke.arc.files.*; -import io.anuke.arc.util.ArcAnnotate.*; -import io.anuke.mindustry.mod.Mods.*; - -public class ModContentInfo{ - /** The mod that loaded this piece of content. */ - public @Nullable LoadedMod mod; - /** File that this content was loaded from. */ - public FileHandle sourceFile; - /** The error that occurred during loading, if applicable. Null if no error occurred. */ - public @Nullable String error; -} diff --git a/core/src/io/anuke/mindustry/mod/ModCrashHandler.java b/core/src/io/anuke/mindustry/mod/ModCrashHandler.java index 77f3c68aba..507057acad 100644 --- a/core/src/io/anuke/mindustry/mod/ModCrashHandler.java +++ b/core/src/io/anuke/mindustry/mod/ModCrashHandler.java @@ -1,19 +1,9 @@ package io.anuke.mindustry.mod; -import io.anuke.arc.*; -import io.anuke.arc.collection.*; -import io.anuke.arc.graphics.*; -import io.anuke.arc.graphics.g2d.*; -import io.anuke.arc.math.*; -import io.anuke.arc.scene.ui.layout.*; -import io.anuke.arc.util.*; -import io.anuke.mindustry.graphics.*; -import io.anuke.mindustry.mod.Mods.*; -import io.anuke.mindustry.ui.*; - public class ModCrashHandler{ public static void handle(Throwable t){ + /* Array list = Strings.getCauses(t); Throwable modCause = list.find(e -> e instanceof ModLoadException); @@ -62,6 +52,6 @@ public class ModCrashHandler{ }); }else{ throw new RuntimeException(t); - } + }*/ } } diff --git a/core/src/io/anuke/mindustry/mod/Mods.java b/core/src/io/anuke/mindustry/mod/Mods.java index 7aa5fa21ea..737aa0ede6 100644 --- a/core/src/io/anuke/mindustry/mod/Mods.java +++ b/core/src/io/anuke/mindustry/mod/Mods.java @@ -149,7 +149,7 @@ public class Mods implements Loadable{ //generate new icons for(Array arr : content.getContentMap()){ arr.each(c -> { - if(c instanceof UnlockableContent && c.minfo != null && c.minfo.mod != null){ + if(c instanceof UnlockableContent && c.minfo.mod != null){ UnlockableContent u = (UnlockableContent)c; u.createIcons(packer); } @@ -465,12 +465,16 @@ public class Mods implements Loadable{ //make sure mod content is in proper order runs.sort(); for(LoadRun l : runs){ + Content current = content.getLastAdded(); try{ //this binds the content but does not load it entirely Content loaded = parser.parse(l.mod, l.file.nameWithoutExtension(), l.file.readString("UTF-8"), l.file, l.type); Log.debug("[{0}] Loaded '{1}'.", l.mod.meta.name, (loaded instanceof UnlockableContent ? ((UnlockableContent)loaded).localizedName : loaded)); }catch(Throwable e){ - throw new RuntimeException("Failed to parse content file '" + l.file + "' for mod '" + l.mod.meta.name + "'.", e); + if(current != content.getLastAdded() && content.getLastAdded() != null){ + parser.markError(content.getLastAdded(), l.mod, l.file, e); + } + //throw new RuntimeException("Failed to parse content file '" + l.file + "' for mod '" + l.mod.meta.name + "'.", e); } } @@ -478,6 +482,10 @@ public class Mods implements Loadable{ parser.finishParsing(); } + public void handleContentError(Content content, Throwable error){ + parser.markError(content, error); + } + /** @return all loaded mods. */ public Array all(){ return loaded; diff --git a/core/src/io/anuke/mindustry/type/Zone.java b/core/src/io/anuke/mindustry/type/Zone.java index c60249b223..12686bb3da 100644 --- a/core/src/io/anuke/mindustry/type/Zone.java +++ b/core/src/io/anuke/mindustry/type/Zone.java @@ -172,8 +172,8 @@ public class Zone extends UnlockableContent{ @Override public void init(){ - if(generator instanceof MapGenerator && mod != null){ - ((MapGenerator)generator).removePrefix(mod.name); + if(generator instanceof MapGenerator && minfo.mod != null){ + ((MapGenerator)generator).removePrefix(minfo.mod.name); } generator.init(loadout); diff --git a/ios/src/io/anuke/mindustry/IOSLauncher.java b/ios/src/io/anuke/mindustry/IOSLauncher.java index 7f4783d1a8..50b1732892 100644 --- a/ios/src/io/anuke/mindustry/IOSLauncher.java +++ b/ios/src/io/anuke/mindustry/IOSLauncher.java @@ -10,7 +10,6 @@ import io.anuke.arc.util.io.*; import io.anuke.mindustry.game.EventType.*; import io.anuke.mindustry.game.Saves.*; import io.anuke.mindustry.io.*; -import io.anuke.mindustry.mod.*; import io.anuke.mindustry.ui.*; import org.robovm.apple.coregraphics.*; import org.robovm.apple.foundation.*; @@ -153,7 +152,7 @@ public class IOSLauncher extends IOSApplication.Delegate{ UINavigationController.attemptRotationToDeviceOrientation(); } }, new IOSApplicationConfiguration(){{ - errorHandler = ModCrashHandler::handle; + //errorHandler = ModCrashHandler::handle; }}); } From e043f4bb6632da8de34c0bf3f425cca81688e8af Mon Sep 17 00:00:00 2001 From: Anuken Date: Sat, 14 Dec 2019 18:19:02 -0500 Subject: [PATCH 4/6] 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> bundles = new ObjectMap<>(); - private ObjectSet specialFolders = ObjectSet.with("bundles", "sprites"); + private ObjectSet specialFolders = ObjectSet.with("bundles", "sprites", "sprites-override"); private int totalSprites; private MultiPacker packer; - private Array loaded = new Array<>(); - private Array disabled = new Array<>(); + private Array mods = new Array<>(); private ObjectMap, 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 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 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 sprites = mod.root.child("sprites").findAll(f -> f.extension().equals("png")); Array 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 incompatible = loaded.select(m -> !m.isSupported()); - loaded.removeAll(incompatible); - disabled.addAll(incompatible); + private void resolveModState(){ + mods.each(this::updateDependencies); - for(LoadedMod mod : Array.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 orderedMods(){ ObjectSet visited = new ObjectSet<>(); Array 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 all(){ - 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); - } - /** @return a list of mods and versions, in the format name:version. */ public Array 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 cons){ - loaded.each(p -> p.mod != null, p -> contextRun(p, () -> cons.get(p.mod))); + public Array list(){ + return mods; } - /* - public void handleError(Throwable t, LoadedMod mod){ - Array 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 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 ? "" : 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 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 missingDependencies = new Array<>(); /** Script files to run. */ public Array 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 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 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 blacklist = Array.with("plugin", "mod", "net", "io", "tools"); Array nameBlacklist = Array.with("ClientLauncher", "NetClient", "NetServer", "ClassAccess"); Array> 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 nopackage = Array.with("java.lang", "java"); String fileTemplate = "package io.anuke.mindustry.mod;\n" + From bcc8f65ac8fb7d9cd14bdfe920a141754c9d4dd9 Mon Sep 17 00:00:00 2001 From: Anuken Date: Sat, 14 Dec 2019 20:49:55 -0500 Subject: [PATCH 5/6] More cleanup --- core/src/io/anuke/mindustry/ClientLauncher.java | 2 +- core/src/io/anuke/mindustry/mod/Mods.java | 10 +++++++--- core/src/io/anuke/mindustry/ui/dialogs/ModsDialog.java | 6 ++---- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/core/src/io/anuke/mindustry/ClientLauncher.java b/core/src/io/anuke/mindustry/ClientLauncher.java index 08363a67be..5d04c44010 100644 --- a/core/src/io/anuke/mindustry/ClientLauncher.java +++ b/core/src/io/anuke/mindustry/ClientLauncher.java @@ -123,7 +123,7 @@ public abstract class ClientLauncher extends ApplicationCore implements Platform for(ApplicationListener listener : modules){ listener.init(); } - mods.each(Mod::init); + mods.eachClass(Mod::init); finished = true; Events.fire(new ClientLoadEvent()); super.resize(graphics.getWidth(), graphics.getHeight()); diff --git a/core/src/io/anuke/mindustry/mod/Mods.java b/core/src/io/anuke/mindustry/mod/Mods.java index 0a35c0d089..7f2ef573f6 100644 --- a/core/src/io/anuke/mindustry/mod/Mods.java +++ b/core/src/io/anuke/mindustry/mod/Mods.java @@ -243,13 +243,16 @@ public class Mods implements Loadable{ } resolveModState(); - - //sort mods to make sure servers handle them properly. - mods.sort(Structs.comparing(m -> m.name)); + sortMods(); buildFiles(); } + private void sortMods(){ + //sort mods to make sure servers handle them properly. + mods.sort(Structs.comps(Structs.comparingInt(m -> -m.state.ordinal()), Structs.comparing(m -> m.name))); + } + private void resolveModState(){ mods.each(this::updateDependencies); @@ -483,6 +486,7 @@ public class Mods implements Loadable{ requiresReload = true; mod.state = enabled ? ModState.enabled : ModState.disabled; mods.each(this::updateDependencies); + sortMods(); } } diff --git a/core/src/io/anuke/mindustry/ui/dialogs/ModsDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/ModsDialog.java index a9a39816fb..a2e1f8b168 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/ModsDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/ModsDialog.java @@ -2,7 +2,6 @@ package io.anuke.mindustry.ui.dialogs; import io.anuke.arc.*; import io.anuke.arc.Net.*; -import io.anuke.arc.collection.*; import io.anuke.arc.files.*; import io.anuke.arc.util.*; import io.anuke.arc.util.io.*; @@ -110,11 +109,10 @@ public class ModsDialog extends FloatingDialog{ if(!mods.list().isEmpty()){ cont.pane(table -> { table.margin(10f).top(); - Array all = Array.withArrays(mods.all(), mods.disabled()); boolean anyDisabled = false; - for(LoadedMod mod : all){ - if(!mod.enabled() && !anyDisabled && mods.all().size > 0){ + for(LoadedMod mod : mods.list()){ + if(!mod.enabled() && !anyDisabled && mods.list().size > 0){ anyDisabled = true; table.row(); table.addImage().growX().height(4f).pad(6f).color(Pal.gray); From 1c1db3990f07912e170e315529f893dc7f018df7 Mon Sep 17 00:00:00 2001 From: Anuken Date: Sun, 15 Dec 2019 13:54:51 -0500 Subject: [PATCH 6/6] Fully implemented safe content loading --- core/assets/bundles/bundle.properties | 3 + core/assets/bundles/bundle_ru.properties | 2 +- core/src/io/anuke/mindustry/Vars.java | 2 + .../anuke/mindustry/core/ContentLoader.java | 1 + .../io/anuke/mindustry/core/NetClient.java | 2 +- core/src/io/anuke/mindustry/core/UI.java | 31 ++++++ .../src/io/anuke/mindustry/ctype/Content.java | 1 - .../{type => ctype}/ContentType.java | 5 +- .../mindustry/editor/WaveInfoDialog.java | 1 + .../mindustry/entities/bullet/BulletType.java | 1 + .../mindustry/entities/type/BaseUnit.java | 1 + .../anuke/mindustry/entities/type/Player.java | 1 + .../mindustry/entities/units/Statuses.java | 1 + .../io/anuke/mindustry/game/GlobalData.java | 2 +- .../io/anuke/mindustry/game/Schematics.java | 2 +- .../io/anuke/mindustry/game/SpawnGroup.java | 1 + core/src/io/anuke/mindustry/io/JsonIO.java | 1 + .../io/anuke/mindustry/io/LegacyMapIO.java | 2 +- .../io/anuke/mindustry/io/SaveVersion.java | 1 + core/src/io/anuke/mindustry/io/TypeIO.java | 1 + .../io/anuke/mindustry/io/versions/Save2.java | 2 +- .../mindustry/maps/filters/FilterOption.java | 14 +-- .../io/anuke/mindustry/mod/ClassAccess.java | 2 +- .../io/anuke/mindustry/mod/ContentParser.java | 49 ++++++---- core/src/io/anuke/mindustry/mod/Mods.java | 94 ++++++++++++++++--- .../io/anuke/mindustry/type/ErrorContent.java | 12 +++ core/src/io/anuke/mindustry/type/Item.java | 1 + core/src/io/anuke/mindustry/type/Liquid.java | 1 + core/src/io/anuke/mindustry/type/Mech.java | 1 + .../io/anuke/mindustry/type/StatusEffect.java | 1 + core/src/io/anuke/mindustry/type/TypeID.java | 1 + .../src/io/anuke/mindustry/type/UnitType.java | 1 + .../io/anuke/mindustry/type/WeatherEvent.java | 1 + core/src/io/anuke/mindustry/type/Zone.java | 1 + core/src/io/anuke/mindustry/ui/Styles.java | 10 +- .../mindustry/ui/dialogs/DatabaseDialog.java | 2 +- .../mindustry/ui/dialogs/ModsDialog.java | 3 + .../mindustry/ui/fragments/HudFragment.java | 1 + .../mindustry/ui/fragments/MenuFragment.java | 30 +++--- core/src/io/anuke/mindustry/world/Block.java | 1 + .../mindustry/world/blocks/units/MechPad.java | 2 +- gradle.properties | 2 +- tests/src/test/java/ApplicationTests.java | 2 +- 43 files changed, 234 insertions(+), 62 deletions(-) rename core/src/io/anuke/mindustry/{type => ctype}/ContentType.java (80%) create mode 100644 core/src/io/anuke/mindustry/type/ErrorContent.java diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index a6dae07fef..8512c307bc 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -102,6 +102,9 @@ mod.disable = Disable mod.delete.error = Unable to delete mod. File may be in use. mod.requiresversion = [scarlet]Requires min game version: [accent]{0} mod.missingdependencies = [scarlet]Missing dependencies: {0} +mod.erroredcontent = [scarlet]Content Errors +mod.errors = Errors have occurred loading content. +mod.noerrorplay = [scarlet]You have mods with errors.[] Either disable the affected mods or fix the errors before playing. mod.nowdisabled = [scarlet]Mod '{0}' is missing dependencies:[accent] {1}\n[lightgray]These mods need to be downloaded first.\nThis mod will be automatically disabled. mod.enable = Enable mod.requiresrestart = The game will now close to apply the mod changes. diff --git a/core/assets/bundles/bundle_ru.properties b/core/assets/bundles/bundle_ru.properties index e1d2308ae7..5fa4556b8c 100644 --- a/core/assets/bundles/bundle_ru.properties +++ b/core/assets/bundles/bundle_ru.properties @@ -315,7 +315,7 @@ waves.invalid = Неверные волны в буфере обмена. waves.copied = Волны скопированы. waves.none = Враги не были определены.\nОбратите внимание, что пустые волны будут автоматически заменены обычной волной. editor.default = [lightgray]<По умолчанию> -details = Подробная информация… +details = Подробности… edit = Редактировать… editor.name = Название: editor.spawn = Создать боевую единицу diff --git a/core/src/io/anuke/mindustry/Vars.java b/core/src/io/anuke/mindustry/Vars.java index 8d9f04d045..ef6f1acd7a 100644 --- a/core/src/io/anuke/mindustry/Vars.java +++ b/core/src/io/anuke/mindustry/Vars.java @@ -8,6 +8,7 @@ import io.anuke.arc.files.*; import io.anuke.arc.graphics.*; import io.anuke.arc.scene.ui.layout.*; import io.anuke.arc.util.*; +import io.anuke.arc.util.io.*; import io.anuke.mindustry.ai.*; import io.anuke.mindustry.core.*; import io.anuke.mindustry.entities.*; @@ -195,6 +196,7 @@ public class Vars implements Loadable{ public static void init(){ Serialization.init(); + DefaultSerializers.typeMappings.put("io.anuke.mindustry.type.ContentType", "io.anuke.mindustry.ctype.ContentType"); if(loadLocales){ //load locales diff --git a/core/src/io/anuke/mindustry/core/ContentLoader.java b/core/src/io/anuke/mindustry/core/ContentLoader.java index 25f425c8f9..274139b206 100644 --- a/core/src/io/anuke/mindustry/core/ContentLoader.java +++ b/core/src/io/anuke/mindustry/core/ContentLoader.java @@ -7,6 +7,7 @@ import io.anuke.arc.util.ArcAnnotate.*; import io.anuke.arc.util.*; import io.anuke.mindustry.content.*; import io.anuke.mindustry.ctype.*; +import io.anuke.mindustry.ctype.ContentType; import io.anuke.mindustry.entities.bullet.*; import io.anuke.mindustry.mod.Mods.*; import io.anuke.mindustry.type.*; diff --git a/core/src/io/anuke/mindustry/core/NetClient.java b/core/src/io/anuke/mindustry/core/NetClient.java index f4cc17693b..6a0f0428e3 100644 --- a/core/src/io/anuke/mindustry/core/NetClient.java +++ b/core/src/io/anuke/mindustry/core/NetClient.java @@ -11,6 +11,7 @@ import io.anuke.arc.util.io.*; import io.anuke.arc.util.serialization.*; import io.anuke.mindustry.*; import io.anuke.mindustry.core.GameState.*; +import io.anuke.mindustry.ctype.ContentType; import io.anuke.mindustry.entities.*; import io.anuke.mindustry.entities.traits.BuilderTrait.*; import io.anuke.mindustry.entities.traits.*; @@ -22,7 +23,6 @@ import io.anuke.mindustry.net.Administration.*; import io.anuke.mindustry.net.Net.*; import io.anuke.mindustry.net.*; import io.anuke.mindustry.net.Packets.*; -import io.anuke.mindustry.type.*; import io.anuke.mindustry.type.TypeID; import io.anuke.mindustry.world.*; import io.anuke.mindustry.world.modules.*; diff --git a/core/src/io/anuke/mindustry/core/UI.java b/core/src/io/anuke/mindustry/core/UI.java index 3eb530ac7f..f8d5774dd6 100644 --- a/core/src/io/anuke/mindustry/core/UI.java +++ b/core/src/io/anuke/mindustry/core/UI.java @@ -374,6 +374,37 @@ public class UI implements ApplicationListener, Loadable{ }}.show(); } + public void showExceptions(String text, String... messages){ + loadfrag.hide(); + new Dialog(""){{ + + setFillParent(true); + cont.margin(15); + cont.add("$error.title").colspan(2); + cont.row(); + cont.addImage().width(300f).pad(2).colspan(2).height(4f).color(Color.scarlet); + cont.row(); + cont.add(text).colspan(2).wrap().growX().center().get().setAlignment(Align.center); + cont.row(); + + //cont.pane(p -> { + for(int i = 0; i < messages.length; i += 2){ + String btext = messages[i]; + String details = messages[i + 1]; + Collapser col = new Collapser(base -> base.pane(t -> t.margin(14f).add(details).color(Color.lightGray).left()), true); + + cont.add(btext).right(); + cont.addButton("$details", Styles.togglet, col::toggle).size(180f, 50f).checked(b -> !col.isCollapsed()).fillX().left(); + cont.row(); + cont.add(col).colspan(2).pad(2); + cont.row(); + } + //}).colspan(2); + + cont.addButton("$ok", this::hide).size(300, 50).fillX().colspan(2); + }}.show(); + } + public void showText(String titleText, String text){ showText(titleText, text, Align.center); } diff --git a/core/src/io/anuke/mindustry/ctype/Content.java b/core/src/io/anuke/mindustry/ctype/Content.java index 0bcc89af14..a4aa945443 100644 --- a/core/src/io/anuke/mindustry/ctype/Content.java +++ b/core/src/io/anuke/mindustry/ctype/Content.java @@ -4,7 +4,6 @@ import io.anuke.arc.files.*; import io.anuke.arc.util.ArcAnnotate.*; import io.anuke.mindustry.*; import io.anuke.mindustry.mod.Mods.*; -import io.anuke.mindustry.type.*; /** Base class for a content type that is loaded in {@link io.anuke.mindustry.core.ContentLoader}. */ diff --git a/core/src/io/anuke/mindustry/type/ContentType.java b/core/src/io/anuke/mindustry/ctype/ContentType.java similarity index 80% rename from core/src/io/anuke/mindustry/type/ContentType.java rename to core/src/io/anuke/mindustry/ctype/ContentType.java index f6b980a5d5..5b2e1bdb3b 100644 --- a/core/src/io/anuke/mindustry/type/ContentType.java +++ b/core/src/io/anuke/mindustry/ctype/ContentType.java @@ -1,4 +1,4 @@ -package io.anuke.mindustry.type; +package io.anuke.mindustry.ctype; /** Do not rearrange, ever! */ public enum ContentType{ @@ -13,7 +13,8 @@ public enum ContentType{ effect, zone, loadout, - typeid; + typeid, + error; public static final ContentType[] all = values(); } diff --git a/core/src/io/anuke/mindustry/editor/WaveInfoDialog.java b/core/src/io/anuke/mindustry/editor/WaveInfoDialog.java index 37f55cb775..187d8a7fc2 100644 --- a/core/src/io/anuke/mindustry/editor/WaveInfoDialog.java +++ b/core/src/io/anuke/mindustry/editor/WaveInfoDialog.java @@ -12,6 +12,7 @@ import io.anuke.arc.scene.ui.layout.*; import io.anuke.arc.util.*; import io.anuke.mindustry.*; import io.anuke.mindustry.content.*; +import io.anuke.mindustry.ctype.ContentType; import io.anuke.mindustry.game.*; import io.anuke.mindustry.gen.*; import io.anuke.mindustry.graphics.*; diff --git a/core/src/io/anuke/mindustry/entities/bullet/BulletType.java b/core/src/io/anuke/mindustry/entities/bullet/BulletType.java index 38923955e9..bc401c6d6d 100644 --- a/core/src/io/anuke/mindustry/entities/bullet/BulletType.java +++ b/core/src/io/anuke/mindustry/entities/bullet/BulletType.java @@ -4,6 +4,7 @@ import io.anuke.arc.audio.*; import io.anuke.arc.math.*; import io.anuke.mindustry.content.*; import io.anuke.mindustry.ctype.Content; +import io.anuke.mindustry.ctype.ContentType; import io.anuke.mindustry.entities.*; import io.anuke.mindustry.entities.Effects.*; import io.anuke.mindustry.entities.effect.*; diff --git a/core/src/io/anuke/mindustry/entities/type/BaseUnit.java b/core/src/io/anuke/mindustry/entities/type/BaseUnit.java index b0b741bacb..6dfa7baa84 100644 --- a/core/src/io/anuke/mindustry/entities/type/BaseUnit.java +++ b/core/src/io/anuke/mindustry/entities/type/BaseUnit.java @@ -9,6 +9,7 @@ import io.anuke.arc.util.*; import io.anuke.arc.util.ArcAnnotate.*; import io.anuke.mindustry.*; import io.anuke.mindustry.content.*; +import io.anuke.mindustry.ctype.ContentType; import io.anuke.mindustry.entities.*; import io.anuke.mindustry.entities.traits.*; import io.anuke.mindustry.entities.units.*; diff --git a/core/src/io/anuke/mindustry/entities/type/Player.java b/core/src/io/anuke/mindustry/entities/type/Player.java index 73c0fc4dc0..45405aad70 100644 --- a/core/src/io/anuke/mindustry/entities/type/Player.java +++ b/core/src/io/anuke/mindustry/entities/type/Player.java @@ -15,6 +15,7 @@ import io.anuke.arc.util.pooling.*; import io.anuke.mindustry.*; import io.anuke.mindustry.content.*; import io.anuke.mindustry.core.*; +import io.anuke.mindustry.ctype.ContentType; import io.anuke.mindustry.entities.*; import io.anuke.mindustry.entities.traits.*; import io.anuke.mindustry.game.*; diff --git a/core/src/io/anuke/mindustry/entities/units/Statuses.java b/core/src/io/anuke/mindustry/entities/units/Statuses.java index b96937bfcb..2d2da40f1f 100644 --- a/core/src/io/anuke/mindustry/entities/units/Statuses.java +++ b/core/src/io/anuke/mindustry/entities/units/Statuses.java @@ -6,6 +6,7 @@ import io.anuke.arc.graphics.*; import io.anuke.arc.util.*; import io.anuke.arc.util.pooling.*; import io.anuke.mindustry.content.*; +import io.anuke.mindustry.ctype.ContentType; import io.anuke.mindustry.entities.traits.*; import io.anuke.mindustry.entities.type.*; import io.anuke.mindustry.type.*; diff --git a/core/src/io/anuke/mindustry/game/GlobalData.java b/core/src/io/anuke/mindustry/game/GlobalData.java index 908173e751..999df06713 100644 --- a/core/src/io/anuke/mindustry/game/GlobalData.java +++ b/core/src/io/anuke/mindustry/game/GlobalData.java @@ -6,7 +6,7 @@ import io.anuke.arc.files.*; import io.anuke.arc.util.io.*; import io.anuke.mindustry.*; import io.anuke.mindustry.content.*; -import io.anuke.mindustry.ctype.UnlockableContent; +import io.anuke.mindustry.ctype.*; import io.anuke.mindustry.game.EventType.*; import io.anuke.mindustry.type.*; diff --git a/core/src/io/anuke/mindustry/game/Schematics.java b/core/src/io/anuke/mindustry/game/Schematics.java index 078300bc52..51753333bb 100644 --- a/core/src/io/anuke/mindustry/game/Schematics.java +++ b/core/src/io/anuke/mindustry/game/Schematics.java @@ -13,12 +13,12 @@ import io.anuke.arc.util.io.Streams.*; import io.anuke.arc.util.serialization.*; import io.anuke.mindustry.*; import io.anuke.mindustry.content.*; +import io.anuke.mindustry.ctype.ContentType; import io.anuke.mindustry.entities.traits.BuilderTrait.*; import io.anuke.mindustry.game.EventType.*; import io.anuke.mindustry.game.Schematic.*; import io.anuke.mindustry.input.*; import io.anuke.mindustry.input.Placement.*; -import io.anuke.mindustry.type.*; import io.anuke.mindustry.world.*; import io.anuke.mindustry.world.blocks.*; import io.anuke.mindustry.world.blocks.production.*; diff --git a/core/src/io/anuke/mindustry/game/SpawnGroup.java b/core/src/io/anuke/mindustry/game/SpawnGroup.java index e799e26c40..50443f153e 100644 --- a/core/src/io/anuke/mindustry/game/SpawnGroup.java +++ b/core/src/io/anuke/mindustry/game/SpawnGroup.java @@ -4,6 +4,7 @@ import io.anuke.arc.util.serialization.Json; import io.anuke.arc.util.serialization.Json.Serializable; import io.anuke.arc.util.serialization.JsonValue; import io.anuke.mindustry.content.*; +import io.anuke.mindustry.ctype.ContentType; import io.anuke.mindustry.entities.type.BaseUnit; import io.anuke.mindustry.type.*; diff --git a/core/src/io/anuke/mindustry/io/JsonIO.java b/core/src/io/anuke/mindustry/io/JsonIO.java index 3635c25bc0..5d91106ea2 100644 --- a/core/src/io/anuke/mindustry/io/JsonIO.java +++ b/core/src/io/anuke/mindustry/io/JsonIO.java @@ -5,6 +5,7 @@ import io.anuke.arc.util.serialization.Json.*; import io.anuke.mindustry.*; import io.anuke.mindustry.content.*; import io.anuke.mindustry.ctype.*; +import io.anuke.mindustry.ctype.ContentType; import io.anuke.mindustry.game.*; import io.anuke.mindustry.type.*; import io.anuke.mindustry.world.*; diff --git a/core/src/io/anuke/mindustry/io/LegacyMapIO.java b/core/src/io/anuke/mindustry/io/LegacyMapIO.java index 4d62f6b63d..650b58c22d 100644 --- a/core/src/io/anuke/mindustry/io/LegacyMapIO.java +++ b/core/src/io/anuke/mindustry/io/LegacyMapIO.java @@ -6,10 +6,10 @@ import io.anuke.arc.graphics.*; import io.anuke.arc.util.*; import io.anuke.arc.util.serialization.*; import io.anuke.mindustry.content.*; +import io.anuke.mindustry.ctype.ContentType; import io.anuke.mindustry.game.*; import io.anuke.mindustry.io.MapIO.*; import io.anuke.mindustry.maps.*; -import io.anuke.mindustry.type.*; import io.anuke.mindustry.world.*; import io.anuke.mindustry.world.LegacyColorMapper.*; import io.anuke.mindustry.world.blocks.*; diff --git a/core/src/io/anuke/mindustry/io/SaveVersion.java b/core/src/io/anuke/mindustry/io/SaveVersion.java index 6e0157e51b..cab3c55250 100644 --- a/core/src/io/anuke/mindustry/io/SaveVersion.java +++ b/core/src/io/anuke/mindustry/io/SaveVersion.java @@ -6,6 +6,7 @@ import io.anuke.arc.util.io.*; import io.anuke.mindustry.content.*; import io.anuke.mindustry.core.*; import io.anuke.mindustry.ctype.*; +import io.anuke.mindustry.ctype.ContentType; import io.anuke.mindustry.entities.*; import io.anuke.mindustry.entities.traits.*; import io.anuke.mindustry.game.*; diff --git a/core/src/io/anuke/mindustry/io/TypeIO.java b/core/src/io/anuke/mindustry/io/TypeIO.java index b5864b5e5b..be5161659b 100644 --- a/core/src/io/anuke/mindustry/io/TypeIO.java +++ b/core/src/io/anuke/mindustry/io/TypeIO.java @@ -3,6 +3,7 @@ package io.anuke.mindustry.io; import io.anuke.annotations.Annotations.ReadClass; import io.anuke.annotations.Annotations.WriteClass; import io.anuke.arc.graphics.Color; +import io.anuke.mindustry.ctype.ContentType; import io.anuke.mindustry.entities.Effects; import io.anuke.mindustry.entities.Effects.Effect; import io.anuke.mindustry.entities.type.Bullet; diff --git a/core/src/io/anuke/mindustry/io/versions/Save2.java b/core/src/io/anuke/mindustry/io/versions/Save2.java index 65c531c66e..bcf0fb8366 100644 --- a/core/src/io/anuke/mindustry/io/versions/Save2.java +++ b/core/src/io/anuke/mindustry/io/versions/Save2.java @@ -1,8 +1,8 @@ package io.anuke.mindustry.io.versions; +import io.anuke.mindustry.ctype.ContentType; import io.anuke.mindustry.entities.traits.*; import io.anuke.mindustry.io.*; -import io.anuke.mindustry.type.*; import io.anuke.mindustry.type.TypeID; import java.io.*; diff --git a/core/src/io/anuke/mindustry/maps/filters/FilterOption.java b/core/src/io/anuke/mindustry/maps/filters/FilterOption.java index f1a63c0a37..df75282eb2 100644 --- a/core/src/io/anuke/mindustry/maps/filters/FilterOption.java +++ b/core/src/io/anuke/mindustry/maps/filters/FilterOption.java @@ -13,15 +13,15 @@ import io.anuke.mindustry.ui.dialogs.*; import io.anuke.mindustry.world.*; import io.anuke.mindustry.world.blocks.*; -import static io.anuke.mindustry.Vars.updateEditorOnChange; +import static io.anuke.mindustry.Vars.*; public abstract class FilterOption{ - public static final Boolf floorsOnly = b -> (b instanceof Floor && !(b instanceof OverlayFloor)) && Core.atlas.isFound(b.icon(io.anuke.mindustry.ui.Cicon.full)); - public static final Boolf wallsOnly = b -> (!b.synthetic() && !(b instanceof Floor)) && Core.atlas.isFound(b.icon(io.anuke.mindustry.ui.Cicon.full)); - public static final Boolf floorsOptional = b -> b == Blocks.air || ((b instanceof Floor && !(b instanceof OverlayFloor)) && Core.atlas.isFound(b.icon(io.anuke.mindustry.ui.Cicon.full))); - public static final Boolf wallsOptional = b -> b == Blocks.air || ((!b.synthetic() && !(b instanceof Floor)) && Core.atlas.isFound(b.icon(io.anuke.mindustry.ui.Cicon.full))); - public static final Boolf wallsOresOptional = b -> b == Blocks.air || (((!b.synthetic() && !(b instanceof Floor)) || (b instanceof OverlayFloor)) && Core.atlas.isFound(b.icon(io.anuke.mindustry.ui.Cicon.full))); - public static final Boolf oresOnly = b -> b instanceof OverlayFloor && Core.atlas.isFound(b.icon(io.anuke.mindustry.ui.Cicon.full)); + public static final Boolf floorsOnly = b -> (b instanceof Floor && !(b instanceof OverlayFloor)) && !headless && Core.atlas.isFound(b.icon(io.anuke.mindustry.ui.Cicon.full)); + public static final Boolf wallsOnly = b -> (!b.synthetic() && !(b instanceof Floor)) && !headless && Core.atlas.isFound(b.icon(io.anuke.mindustry.ui.Cicon.full)); + public static final Boolf floorsOptional = b -> b == Blocks.air || ((b instanceof Floor && !(b instanceof OverlayFloor)) && !headless && Core.atlas.isFound(b.icon(io.anuke.mindustry.ui.Cicon.full))); + public static final Boolf wallsOptional = b -> b == Blocks.air || ((!b.synthetic() && !(b instanceof Floor)) && !headless && Core.atlas.isFound(b.icon(io.anuke.mindustry.ui.Cicon.full))); + public static final Boolf wallsOresOptional = b -> b == Blocks.air || (((!b.synthetic() && !(b instanceof Floor)) || (b instanceof OverlayFloor)) && !headless && Core.atlas.isFound(b.icon(io.anuke.mindustry.ui.Cicon.full))); + public static final Boolf oresOnly = b -> b instanceof OverlayFloor && !headless && Core.atlas.isFound(b.icon(io.anuke.mindustry.ui.Cicon.full)); public static final Boolf anyOptional = b -> floorsOnly.get(b) || wallsOnly.get(b) || oresOnly.get(b) || b == Blocks.air; public abstract void build(Table table); diff --git a/core/src/io/anuke/mindustry/mod/ClassAccess.java b/core/src/io/anuke/mindustry/mod/ClassAccess.java index d126af792c..5e11142fea 100644 --- a/core/src/io/anuke/mindustry/mod/ClassAccess.java +++ b/core/src/io/anuke/mindustry/mod/ClassAccess.java @@ -3,5 +3,5 @@ package io.anuke.mindustry.mod; import io.anuke.arc.collection.*; //obviously autogenerated, do not touch public class ClassAccess{ - public static final ObjectSet allowedClassNames = ObjectSet.with("io.anuke.arc.Core", "io.anuke.arc.collection.Array", "io.anuke.arc.collection.Array$ArrayIterable", "io.anuke.arc.collection.ArrayMap", "io.anuke.arc.collection.ArrayMap$Entries", "io.anuke.arc.collection.ArrayMap$Keys", "io.anuke.arc.collection.ArrayMap$Values", "io.anuke.arc.collection.AtomicQueue", "io.anuke.arc.collection.BinaryHeap", "io.anuke.arc.collection.BinaryHeap$Node", "io.anuke.arc.collection.Bits", "io.anuke.arc.collection.BooleanArray", "io.anuke.arc.collection.ByteArray", "io.anuke.arc.collection.CharArray", "io.anuke.arc.collection.ComparableTimSort", "io.anuke.arc.collection.DelayedRemovalArray", "io.anuke.arc.collection.EnumSet", "io.anuke.arc.collection.EnumSet$EnumSetIterator", "io.anuke.arc.collection.FloatArray", "io.anuke.arc.collection.GridBits", "io.anuke.arc.collection.GridMap", "io.anuke.arc.collection.IdentityMap", "io.anuke.arc.collection.IdentityMap$Entries", "io.anuke.arc.collection.IdentityMap$Entry", "io.anuke.arc.collection.IdentityMap$Keys", "io.anuke.arc.collection.IdentityMap$Values", "io.anuke.arc.collection.IntArray", "io.anuke.arc.collection.IntFloatMap", "io.anuke.arc.collection.IntFloatMap$Entries", "io.anuke.arc.collection.IntFloatMap$Entry", "io.anuke.arc.collection.IntFloatMap$Keys", "io.anuke.arc.collection.IntFloatMap$Values", "io.anuke.arc.collection.IntIntMap", "io.anuke.arc.collection.IntIntMap$Entries", "io.anuke.arc.collection.IntIntMap$Entry", "io.anuke.arc.collection.IntIntMap$Keys", "io.anuke.arc.collection.IntIntMap$Values", "io.anuke.arc.collection.IntMap", "io.anuke.arc.collection.IntMap$Entries", "io.anuke.arc.collection.IntMap$Entry", "io.anuke.arc.collection.IntMap$Keys", "io.anuke.arc.collection.IntMap$Values", "io.anuke.arc.collection.IntQueue", "io.anuke.arc.collection.IntSet", "io.anuke.arc.collection.IntSet$IntSetIterator", "io.anuke.arc.collection.LongArray", "io.anuke.arc.collection.LongMap", "io.anuke.arc.collection.LongMap$Entries", "io.anuke.arc.collection.LongMap$Entry", "io.anuke.arc.collection.LongMap$Keys", "io.anuke.arc.collection.LongMap$Values", "io.anuke.arc.collection.LongQueue", "io.anuke.arc.collection.ObjectFloatMap", "io.anuke.arc.collection.ObjectFloatMap$Entries", "io.anuke.arc.collection.ObjectFloatMap$Entry", "io.anuke.arc.collection.ObjectFloatMap$Keys", "io.anuke.arc.collection.ObjectFloatMap$Values", "io.anuke.arc.collection.ObjectIntMap", "io.anuke.arc.collection.ObjectIntMap$Entries", "io.anuke.arc.collection.ObjectIntMap$Entry", "io.anuke.arc.collection.ObjectIntMap$Keys", "io.anuke.arc.collection.ObjectIntMap$Values", "io.anuke.arc.collection.ObjectMap", "io.anuke.arc.collection.ObjectMap$Entries", "io.anuke.arc.collection.ObjectMap$Entry", "io.anuke.arc.collection.ObjectMap$Keys", "io.anuke.arc.collection.ObjectMap$Values", "io.anuke.arc.collection.ObjectSet", "io.anuke.arc.collection.ObjectSet$ObjectSetIterator", "io.anuke.arc.collection.OrderedMap", "io.anuke.arc.collection.OrderedMap$OrderedMapEntries", "io.anuke.arc.collection.OrderedMap$OrderedMapKeys", "io.anuke.arc.collection.OrderedMap$OrderedMapValues", "io.anuke.arc.collection.OrderedSet", "io.anuke.arc.collection.OrderedSet$OrderedSetIterator", "io.anuke.arc.collection.PooledLinkedList", "io.anuke.arc.collection.PooledLinkedList$Item", "io.anuke.arc.collection.Queue", "io.anuke.arc.collection.Queue$QueueIterable", "io.anuke.arc.collection.ShortArray", "io.anuke.arc.collection.SnapshotArray", "io.anuke.arc.collection.Sort", "io.anuke.arc.collection.SortedIntList", "io.anuke.arc.collection.SortedIntList$Iterator", "io.anuke.arc.collection.SortedIntList$Node", "io.anuke.arc.collection.StringMap", "io.anuke.arc.collection.TimSort", "io.anuke.arc.func.Boolc", "io.anuke.arc.func.Boolf", "io.anuke.arc.func.Boolf2", "io.anuke.arc.func.Boolp", "io.anuke.arc.func.Cons", "io.anuke.arc.func.Cons2", "io.anuke.arc.func.Floatc", "io.anuke.arc.func.Floatc2", "io.anuke.arc.func.Floatc4", "io.anuke.arc.func.Floatf", "io.anuke.arc.func.Floatp", "io.anuke.arc.func.Func", "io.anuke.arc.func.Func2", "io.anuke.arc.func.Func3", "io.anuke.arc.func.Intc", "io.anuke.arc.func.Intc2", "io.anuke.arc.func.Intc4", "io.anuke.arc.func.Intf", "io.anuke.arc.func.Intp", "io.anuke.arc.func.Prov", "io.anuke.arc.graphics.Color", "io.anuke.arc.graphics.g2d.Draw", "io.anuke.arc.graphics.g2d.Fill", "io.anuke.arc.graphics.g2d.Lines", "io.anuke.arc.graphics.g2d.TextureAtlas", "io.anuke.arc.graphics.g2d.TextureAtlas$AtlasRegion", "io.anuke.arc.graphics.g2d.TextureRegion", "io.anuke.arc.math.Angles", "io.anuke.arc.math.Mathf", "io.anuke.arc.scene.Action", "io.anuke.arc.scene.Element", "io.anuke.arc.scene.Group", "io.anuke.arc.scene.Scene", "io.anuke.arc.scene.Scene$TouchFocus", "io.anuke.arc.scene.actions.Actions", "io.anuke.arc.scene.actions.AddAction", "io.anuke.arc.scene.actions.AddListenerAction", "io.anuke.arc.scene.actions.AfterAction", "io.anuke.arc.scene.actions.AlphaAction", "io.anuke.arc.scene.actions.ColorAction", "io.anuke.arc.scene.actions.DelayAction", "io.anuke.arc.scene.actions.DelegateAction", "io.anuke.arc.scene.actions.FloatAction", "io.anuke.arc.scene.actions.IntAction", "io.anuke.arc.scene.actions.LayoutAction", "io.anuke.arc.scene.actions.MoveByAction", "io.anuke.arc.scene.actions.MoveToAction", "io.anuke.arc.scene.actions.OriginAction", "io.anuke.arc.scene.actions.ParallelAction", "io.anuke.arc.scene.actions.RelativeTemporalAction", "io.anuke.arc.scene.actions.RemoveAction", "io.anuke.arc.scene.actions.RemoveActorAction", "io.anuke.arc.scene.actions.RemoveListenerAction", "io.anuke.arc.scene.actions.RepeatAction", "io.anuke.arc.scene.actions.RotateByAction", "io.anuke.arc.scene.actions.RotateToAction", "io.anuke.arc.scene.actions.RunnableAction", "io.anuke.arc.scene.actions.ScaleByAction", "io.anuke.arc.scene.actions.ScaleToAction", "io.anuke.arc.scene.actions.SequenceAction", "io.anuke.arc.scene.actions.SizeByAction", "io.anuke.arc.scene.actions.SizeToAction", "io.anuke.arc.scene.actions.TemporalAction", "io.anuke.arc.scene.actions.TimeScaleAction", "io.anuke.arc.scene.actions.TouchableAction", "io.anuke.arc.scene.actions.TranslateByAction", "io.anuke.arc.scene.actions.VisibleAction", "io.anuke.arc.scene.event.ChangeListener", "io.anuke.arc.scene.event.ChangeListener$ChangeEvent", "io.anuke.arc.scene.event.ClickListener", "io.anuke.arc.scene.event.DragListener", "io.anuke.arc.scene.event.DragScrollListener", "io.anuke.arc.scene.event.ElementGestureListener", "io.anuke.arc.scene.event.EventListener", "io.anuke.arc.scene.event.FocusListener", "io.anuke.arc.scene.event.FocusListener$FocusEvent", "io.anuke.arc.scene.event.FocusListener$FocusEvent$Type", "io.anuke.arc.scene.event.HandCursorListener", "io.anuke.arc.scene.event.IbeamCursorListener", "io.anuke.arc.scene.event.InputEvent", "io.anuke.arc.scene.event.InputEvent$Type", "io.anuke.arc.scene.event.InputListener", "io.anuke.arc.scene.event.SceneEvent", "io.anuke.arc.scene.event.Touchable", "io.anuke.arc.scene.event.VisibilityEvent", "io.anuke.arc.scene.event.VisibilityListener", "io.anuke.arc.scene.style.BaseDrawable", "io.anuke.arc.scene.style.Drawable", "io.anuke.arc.scene.style.NinePatchDrawable", "io.anuke.arc.scene.style.ScaledNinePatchDrawable", "io.anuke.arc.scene.style.Style", "io.anuke.arc.scene.style.TextureRegionDrawable", "io.anuke.arc.scene.style.TiledDrawable", "io.anuke.arc.scene.style.TransformDrawable", "io.anuke.arc.scene.ui.Button", "io.anuke.arc.scene.ui.Button$ButtonStyle", "io.anuke.arc.scene.ui.ButtonGroup", "io.anuke.arc.scene.ui.CheckBox", "io.anuke.arc.scene.ui.CheckBox$CheckBoxStyle", "io.anuke.arc.scene.ui.ColorImage", "io.anuke.arc.scene.ui.Dialog", "io.anuke.arc.scene.ui.Dialog$DialogStyle", "io.anuke.arc.scene.ui.Image", "io.anuke.arc.scene.ui.ImageButton", "io.anuke.arc.scene.ui.ImageButton$ImageButtonStyle", "io.anuke.arc.scene.ui.KeybindDialog", "io.anuke.arc.scene.ui.KeybindDialog$KeybindDialogStyle", "io.anuke.arc.scene.ui.Label", "io.anuke.arc.scene.ui.Label$LabelStyle", "io.anuke.arc.scene.ui.ProgressBar", "io.anuke.arc.scene.ui.ProgressBar$ProgressBarStyle", "io.anuke.arc.scene.ui.ScrollPane", "io.anuke.arc.scene.ui.ScrollPane$ScrollPaneStyle", "io.anuke.arc.scene.ui.SettingsDialog", "io.anuke.arc.scene.ui.SettingsDialog$SettingsTable", "io.anuke.arc.scene.ui.SettingsDialog$SettingsTable$CheckSetting", "io.anuke.arc.scene.ui.SettingsDialog$SettingsTable$Setting", "io.anuke.arc.scene.ui.SettingsDialog$SettingsTable$SliderSetting", "io.anuke.arc.scene.ui.SettingsDialog$StringProcessor", "io.anuke.arc.scene.ui.Slider", "io.anuke.arc.scene.ui.Slider$SliderStyle", "io.anuke.arc.scene.ui.TextArea", "io.anuke.arc.scene.ui.TextArea$TextAreaListener", "io.anuke.arc.scene.ui.TextButton", "io.anuke.arc.scene.ui.TextButton$TextButtonStyle", "io.anuke.arc.scene.ui.TextField", "io.anuke.arc.scene.ui.TextField$DefaultOnscreenKeyboard", "io.anuke.arc.scene.ui.TextField$OnscreenKeyboard", "io.anuke.arc.scene.ui.TextField$TextFieldClickListener", "io.anuke.arc.scene.ui.TextField$TextFieldFilter", "io.anuke.arc.scene.ui.TextField$TextFieldListener", "io.anuke.arc.scene.ui.TextField$TextFieldStyle", "io.anuke.arc.scene.ui.TextField$TextFieldValidator", "io.anuke.arc.scene.ui.Tooltip", "io.anuke.arc.scene.ui.Tooltip$Tooltips", "io.anuke.arc.scene.ui.Touchpad", "io.anuke.arc.scene.ui.Touchpad$TouchpadStyle", "io.anuke.arc.scene.ui.TreeElement", "io.anuke.arc.scene.ui.TreeElement$Node", "io.anuke.arc.scene.ui.TreeElement$TreeStyle", "io.anuke.arc.scene.ui.layout.Cell", "io.anuke.arc.scene.ui.layout.Collapser", "io.anuke.arc.scene.ui.layout.HorizontalGroup", "io.anuke.arc.scene.ui.layout.Scl", "io.anuke.arc.scene.ui.layout.Stack", "io.anuke.arc.scene.ui.layout.Table", "io.anuke.arc.scene.ui.layout.Table$DrawRect", "io.anuke.arc.scene.ui.layout.VerticalGroup", "io.anuke.arc.scene.ui.layout.WidgetGroup", "io.anuke.arc.scene.utils.ArraySelection", "io.anuke.arc.scene.utils.Cullable", "io.anuke.arc.scene.utils.Disableable", "io.anuke.arc.scene.utils.DragAndDrop", "io.anuke.arc.scene.utils.DragAndDrop$Payload", "io.anuke.arc.scene.utils.DragAndDrop$Source", "io.anuke.arc.scene.utils.DragAndDrop$Target", "io.anuke.arc.scene.utils.Elements", "io.anuke.arc.scene.utils.Layout", "io.anuke.arc.scene.utils.Selection", "io.anuke.arc.util.Time", "io.anuke.mindustry.Vars", "io.anuke.mindustry.ai.BlockIndexer", "io.anuke.mindustry.ai.Pathfinder", "io.anuke.mindustry.ai.Pathfinder$PathData", "io.anuke.mindustry.ai.Pathfinder$PathTarget", "io.anuke.mindustry.ai.Pathfinder$PathTileStruct", "io.anuke.mindustry.ai.WaveSpawner", "io.anuke.mindustry.content.Blocks", "io.anuke.mindustry.content.Bullets", "io.anuke.mindustry.content.Fx", "io.anuke.mindustry.content.Items", "io.anuke.mindustry.content.Liquids", "io.anuke.mindustry.content.Loadouts", "io.anuke.mindustry.content.Mechs", "io.anuke.mindustry.content.StatusEffects", "io.anuke.mindustry.content.TechTree", "io.anuke.mindustry.content.TechTree$TechNode", "io.anuke.mindustry.content.TypeIDs", "io.anuke.mindustry.content.UnitTypes", "io.anuke.mindustry.content.Zones", "io.anuke.mindustry.core.ContentLoader", "io.anuke.mindustry.core.Control", "io.anuke.mindustry.core.FileTree", "io.anuke.mindustry.core.GameState", "io.anuke.mindustry.core.GameState$State", "io.anuke.mindustry.core.Logic", "io.anuke.mindustry.core.Platform", "io.anuke.mindustry.core.Renderer", "io.anuke.mindustry.core.UI", "io.anuke.mindustry.core.Version", "io.anuke.mindustry.core.World", "io.anuke.mindustry.core.World$Raycaster", "io.anuke.mindustry.ctype.Content", "io.anuke.mindustry.ctype.ContentList", "io.anuke.mindustry.ctype.MappableContent", "io.anuke.mindustry.ctype.UnlockableContent", "io.anuke.mindustry.editor.DrawOperation", "io.anuke.mindustry.editor.DrawOperation$OpType", "io.anuke.mindustry.editor.DrawOperation$TileOpStruct", "io.anuke.mindustry.editor.EditorTile", "io.anuke.mindustry.editor.EditorTool", "io.anuke.mindustry.editor.MapEditor", "io.anuke.mindustry.editor.MapEditor$Context", "io.anuke.mindustry.editor.MapEditorDialog", "io.anuke.mindustry.editor.MapGenerateDialog", "io.anuke.mindustry.editor.MapInfoDialog", "io.anuke.mindustry.editor.MapLoadDialog", "io.anuke.mindustry.editor.MapRenderer", "io.anuke.mindustry.editor.MapResizeDialog", "io.anuke.mindustry.editor.MapSaveDialog", "io.anuke.mindustry.editor.MapView", "io.anuke.mindustry.editor.OperationStack", "io.anuke.mindustry.editor.WaveInfoDialog", "io.anuke.mindustry.entities.Damage", "io.anuke.mindustry.entities.Damage$PropCellStruct", "io.anuke.mindustry.entities.Effects", "io.anuke.mindustry.entities.Effects$Effect", "io.anuke.mindustry.entities.Effects$EffectContainer", "io.anuke.mindustry.entities.Effects$EffectProvider", "io.anuke.mindustry.entities.Effects$EffectRenderer", "io.anuke.mindustry.entities.Effects$ScreenshakeProvider", "io.anuke.mindustry.entities.Entities", "io.anuke.mindustry.entities.EntityCollisions", "io.anuke.mindustry.entities.EntityGroup", "io.anuke.mindustry.entities.Predict", "io.anuke.mindustry.entities.TargetPriority", "io.anuke.mindustry.entities.Units", "io.anuke.mindustry.entities.bullet.ArtilleryBulletType", "io.anuke.mindustry.entities.bullet.BasicBulletType", "io.anuke.mindustry.entities.bullet.BombBulletType", "io.anuke.mindustry.entities.bullet.BulletType", "io.anuke.mindustry.entities.bullet.FlakBulletType", "io.anuke.mindustry.entities.bullet.HealBulletType", "io.anuke.mindustry.entities.bullet.LiquidBulletType", "io.anuke.mindustry.entities.bullet.MassDriverBolt", "io.anuke.mindustry.entities.bullet.MissileBulletType", "io.anuke.mindustry.entities.effect.Decal", "io.anuke.mindustry.entities.effect.Fire", "io.anuke.mindustry.entities.effect.GroundEffectEntity", "io.anuke.mindustry.entities.effect.GroundEffectEntity$GroundEffect", "io.anuke.mindustry.entities.effect.ItemTransfer", "io.anuke.mindustry.entities.effect.Lightning", "io.anuke.mindustry.entities.effect.Puddle", "io.anuke.mindustry.entities.effect.RubbleDecal", "io.anuke.mindustry.entities.effect.ScorchDecal", "io.anuke.mindustry.entities.traits.AbsorbTrait", "io.anuke.mindustry.entities.traits.BelowLiquidTrait", "io.anuke.mindustry.entities.traits.BuilderMinerTrait", "io.anuke.mindustry.entities.traits.BuilderTrait", "io.anuke.mindustry.entities.traits.BuilderTrait$BuildDataStatic", "io.anuke.mindustry.entities.traits.BuilderTrait$BuildRequest", "io.anuke.mindustry.entities.traits.DamageTrait", "io.anuke.mindustry.entities.traits.DrawTrait", "io.anuke.mindustry.entities.traits.Entity", "io.anuke.mindustry.entities.traits.HealthTrait", "io.anuke.mindustry.entities.traits.KillerTrait", "io.anuke.mindustry.entities.traits.MinerTrait", "io.anuke.mindustry.entities.traits.MoveTrait", "io.anuke.mindustry.entities.traits.SaveTrait", "io.anuke.mindustry.entities.traits.Saveable", "io.anuke.mindustry.entities.traits.ScaleTrait", "io.anuke.mindustry.entities.traits.ShooterTrait", "io.anuke.mindustry.entities.traits.SolidTrait", "io.anuke.mindustry.entities.traits.SpawnerTrait", "io.anuke.mindustry.entities.traits.SyncTrait", "io.anuke.mindustry.entities.traits.TargetTrait", "io.anuke.mindustry.entities.traits.TeamTrait", "io.anuke.mindustry.entities.traits.TimeTrait", "io.anuke.mindustry.entities.traits.TypeTrait", "io.anuke.mindustry.entities.traits.VelocityTrait", "io.anuke.mindustry.entities.type.BaseEntity", "io.anuke.mindustry.entities.type.BaseUnit", "io.anuke.mindustry.entities.type.Bullet", "io.anuke.mindustry.entities.type.DestructibleEntity", "io.anuke.mindustry.entities.type.EffectEntity", "io.anuke.mindustry.entities.type.Player", "io.anuke.mindustry.entities.type.SolidEntity", "io.anuke.mindustry.entities.type.TileEntity", "io.anuke.mindustry.entities.type.TimedEntity", "io.anuke.mindustry.entities.type.Unit", "io.anuke.mindustry.entities.type.base.BaseDrone", "io.anuke.mindustry.entities.type.base.BuilderDrone", "io.anuke.mindustry.entities.type.base.Crawler", "io.anuke.mindustry.entities.type.base.Dagger", "io.anuke.mindustry.entities.type.base.Draug", "io.anuke.mindustry.entities.type.base.Eruptor", "io.anuke.mindustry.entities.type.base.FlyingUnit", "io.anuke.mindustry.entities.type.base.Fortress", "io.anuke.mindustry.entities.type.base.Ghoul", "io.anuke.mindustry.entities.type.base.GroundUnit", "io.anuke.mindustry.entities.type.base.MinerDrone", "io.anuke.mindustry.entities.type.base.Phantom", "io.anuke.mindustry.entities.type.base.RepairDrone", "io.anuke.mindustry.entities.type.base.Revenant", "io.anuke.mindustry.entities.type.base.Spirit", "io.anuke.mindustry.entities.type.base.Titan", "io.anuke.mindustry.entities.type.base.Wraith", "io.anuke.mindustry.entities.units.StateMachine", "io.anuke.mindustry.entities.units.Statuses", "io.anuke.mindustry.entities.units.Statuses$StatusEntry", "io.anuke.mindustry.entities.units.UnitCommand", "io.anuke.mindustry.entities.units.UnitDrops", "io.anuke.mindustry.entities.units.UnitState", "io.anuke.mindustry.game.DefaultWaves", "io.anuke.mindustry.game.Difficulty", "io.anuke.mindustry.game.EventType", "io.anuke.mindustry.game.EventType$BlockBuildBeginEvent", "io.anuke.mindustry.game.EventType$BlockBuildEndEvent", "io.anuke.mindustry.game.EventType$BlockDestroyEvent", "io.anuke.mindustry.game.EventType$BlockInfoEvent", "io.anuke.mindustry.game.EventType$BuildSelectEvent", "io.anuke.mindustry.game.EventType$ClientLoadEvent", "io.anuke.mindustry.game.EventType$CommandIssueEvent", "io.anuke.mindustry.game.EventType$ContentReloadEvent", "io.anuke.mindustry.game.EventType$CoreItemDeliverEvent", "io.anuke.mindustry.game.EventType$DepositEvent", "io.anuke.mindustry.game.EventType$DisposeEvent", "io.anuke.mindustry.game.EventType$GameOverEvent", "io.anuke.mindustry.game.EventType$LaunchEvent", "io.anuke.mindustry.game.EventType$LaunchItemEvent", "io.anuke.mindustry.game.EventType$LineConfirmEvent", "io.anuke.mindustry.game.EventType$LoseEvent", "io.anuke.mindustry.game.EventType$MapMakeEvent", "io.anuke.mindustry.game.EventType$MapPublishEvent", "io.anuke.mindustry.game.EventType$MechChangeEvent", "io.anuke.mindustry.game.EventType$PlayEvent", "io.anuke.mindustry.game.EventType$PlayerBanEvent", "io.anuke.mindustry.game.EventType$PlayerChatEvent", "io.anuke.mindustry.game.EventType$PlayerConnect", "io.anuke.mindustry.game.EventType$PlayerIpBanEvent", "io.anuke.mindustry.game.EventType$PlayerIpUnbanEvent", "io.anuke.mindustry.game.EventType$PlayerJoin", "io.anuke.mindustry.game.EventType$PlayerLeave", "io.anuke.mindustry.game.EventType$PlayerUnbanEvent", "io.anuke.mindustry.game.EventType$ResearchEvent", "io.anuke.mindustry.game.EventType$ResetEvent", "io.anuke.mindustry.game.EventType$ResizeEvent", "io.anuke.mindustry.game.EventType$StateChangeEvent", "io.anuke.mindustry.game.EventType$TapConfigEvent", "io.anuke.mindustry.game.EventType$TapEvent", "io.anuke.mindustry.game.EventType$TileChangeEvent", "io.anuke.mindustry.game.EventType$Trigger", "io.anuke.mindustry.game.EventType$TurretAmmoDeliverEvent", "io.anuke.mindustry.game.EventType$UnitCreateEvent", "io.anuke.mindustry.game.EventType$UnitDestroyEvent", "io.anuke.mindustry.game.EventType$UnlockEvent", "io.anuke.mindustry.game.EventType$WaveEvent", "io.anuke.mindustry.game.EventType$WinEvent", "io.anuke.mindustry.game.EventType$WithdrawEvent", "io.anuke.mindustry.game.EventType$WorldLoadEvent", "io.anuke.mindustry.game.EventType$ZoneConfigureCompleteEvent", "io.anuke.mindustry.game.EventType$ZoneRequireCompleteEvent", "io.anuke.mindustry.game.Gamemode", "io.anuke.mindustry.game.GlobalData", "io.anuke.mindustry.game.LoopControl", "io.anuke.mindustry.game.MusicControl", "io.anuke.mindustry.game.Objective", "io.anuke.mindustry.game.Objectives", "io.anuke.mindustry.game.Objectives$Launched", "io.anuke.mindustry.game.Objectives$Unlock", "io.anuke.mindustry.game.Objectives$Wave", "io.anuke.mindustry.game.Objectives$ZoneObjective", "io.anuke.mindustry.game.Objectives$ZoneWave", "io.anuke.mindustry.game.Rules", "io.anuke.mindustry.game.Saves", "io.anuke.mindustry.game.Saves$SaveSlot", "io.anuke.mindustry.game.Schematic", "io.anuke.mindustry.game.Schematic$Stile", "io.anuke.mindustry.game.Schematics", "io.anuke.mindustry.game.SoundLoop", "io.anuke.mindustry.game.SpawnGroup", "io.anuke.mindustry.game.Stats", "io.anuke.mindustry.game.Stats$Rank", "io.anuke.mindustry.game.Stats$RankResult", "io.anuke.mindustry.game.Team", "io.anuke.mindustry.game.Teams", "io.anuke.mindustry.game.Teams$BrokenBlock", "io.anuke.mindustry.game.Teams$TeamData", "io.anuke.mindustry.game.Tutorial", "io.anuke.mindustry.game.Tutorial$TutorialStage", "io.anuke.mindustry.gen.BufferItem", "io.anuke.mindustry.gen.Call", "io.anuke.mindustry.gen.Call", "io.anuke.mindustry.gen.Icon", "io.anuke.mindustry.gen.Icon", "io.anuke.mindustry.gen.MethodHash", "io.anuke.mindustry.gen.Musics", "io.anuke.mindustry.gen.Musics", "io.anuke.mindustry.gen.PathTile", "io.anuke.mindustry.gen.PropCell", "io.anuke.mindustry.gen.RemoteReadClient", "io.anuke.mindustry.gen.RemoteReadServer", "io.anuke.mindustry.gen.Serialization", "io.anuke.mindustry.gen.Sounds", "io.anuke.mindustry.gen.Sounds", "io.anuke.mindustry.gen.Tex", "io.anuke.mindustry.gen.Tex", "io.anuke.mindustry.gen.TileOp", "io.anuke.mindustry.graphics.BlockRenderer", "io.anuke.mindustry.graphics.Bloom", "io.anuke.mindustry.graphics.CacheLayer", "io.anuke.mindustry.graphics.Drawf", "io.anuke.mindustry.graphics.FloorRenderer", "io.anuke.mindustry.graphics.IndexedRenderer", "io.anuke.mindustry.graphics.Layer", "io.anuke.mindustry.graphics.LightRenderer", "io.anuke.mindustry.graphics.MenuRenderer", "io.anuke.mindustry.graphics.MinimapRenderer", "io.anuke.mindustry.graphics.MultiPacker", "io.anuke.mindustry.graphics.MultiPacker$PageType", "io.anuke.mindustry.graphics.OverlayRenderer", "io.anuke.mindustry.graphics.Pal", "io.anuke.mindustry.graphics.Pixelator", "io.anuke.mindustry.graphics.Shaders", "io.anuke.mindustry.input.Binding", "io.anuke.mindustry.input.DesktopInput", "io.anuke.mindustry.input.InputHandler", "io.anuke.mindustry.input.InputHandler$PlaceLine", "io.anuke.mindustry.input.MobileInput", "io.anuke.mindustry.input.PlaceMode", "io.anuke.mindustry.input.Placement", "io.anuke.mindustry.input.Placement$DistanceHeuristic", "io.anuke.mindustry.input.Placement$NormalizeDrawResult", "io.anuke.mindustry.input.Placement$NormalizeResult", "io.anuke.mindustry.input.Placement$TileHueristic", "io.anuke.mindustry.maps.Map", "io.anuke.mindustry.maps.Maps", "io.anuke.mindustry.maps.Maps$MapProvider", "io.anuke.mindustry.maps.Maps$ShuffleMode", "io.anuke.mindustry.maps.Maps$ShuffleMode", "io.anuke.mindustry.maps.filters.BlendFilter", "io.anuke.mindustry.maps.filters.ClearFilter", "io.anuke.mindustry.maps.filters.DistortFilter", "io.anuke.mindustry.maps.filters.FilterOption", "io.anuke.mindustry.maps.filters.FilterOption$BlockOption", "io.anuke.mindustry.maps.filters.FilterOption$SliderOption", "io.anuke.mindustry.maps.filters.GenerateFilter", "io.anuke.mindustry.maps.filters.GenerateFilter$GenerateInput", "io.anuke.mindustry.maps.filters.GenerateFilter$GenerateInput$TileProvider", "io.anuke.mindustry.maps.filters.MedianFilter", "io.anuke.mindustry.maps.filters.MirrorFilter", "io.anuke.mindustry.maps.filters.NoiseFilter", "io.anuke.mindustry.maps.filters.OreFilter", "io.anuke.mindustry.maps.filters.OreMedianFilter", "io.anuke.mindustry.maps.filters.RiverNoiseFilter", "io.anuke.mindustry.maps.filters.ScatterFilter", "io.anuke.mindustry.maps.filters.TerrainFilter", "io.anuke.mindustry.maps.generators.BasicGenerator", "io.anuke.mindustry.maps.generators.BasicGenerator$DistanceHeuristic", "io.anuke.mindustry.maps.generators.BasicGenerator$TileHueristic", "io.anuke.mindustry.maps.generators.Generator", "io.anuke.mindustry.maps.generators.MapGenerator", "io.anuke.mindustry.maps.generators.MapGenerator$Decoration", "io.anuke.mindustry.maps.generators.RandomGenerator", "io.anuke.mindustry.maps.zonegen.DesertWastesGenerator", "io.anuke.mindustry.maps.zonegen.OvergrowthGenerator", "io.anuke.mindustry.type.Category", "io.anuke.mindustry.type.ContentType", "io.anuke.mindustry.type.Item", "io.anuke.mindustry.type.ItemStack", "io.anuke.mindustry.type.ItemType", "io.anuke.mindustry.type.Liquid", "io.anuke.mindustry.type.LiquidStack", "io.anuke.mindustry.type.Mech", "io.anuke.mindustry.type.Publishable", "io.anuke.mindustry.type.StatusEffect", "io.anuke.mindustry.type.StatusEffect$TransitionHandler", "io.anuke.mindustry.type.TypeID", "io.anuke.mindustry.type.UnitType", "io.anuke.mindustry.type.Weapon", "io.anuke.mindustry.type.WeatherEvent", "io.anuke.mindustry.type.Zone", "io.anuke.mindustry.ui.Bar", "io.anuke.mindustry.ui.BorderImage", "io.anuke.mindustry.ui.Cicon", "io.anuke.mindustry.ui.ContentDisplay", "io.anuke.mindustry.ui.Fonts", "io.anuke.mindustry.ui.GridImage", "io.anuke.mindustry.ui.IconSize", "io.anuke.mindustry.ui.IntFormat", "io.anuke.mindustry.ui.ItemDisplay", "io.anuke.mindustry.ui.ItemImage", "io.anuke.mindustry.ui.ItemsDisplay", "io.anuke.mindustry.ui.Links", "io.anuke.mindustry.ui.Links$LinkEntry", "io.anuke.mindustry.ui.LiquidDisplay", "io.anuke.mindustry.ui.Minimap", "io.anuke.mindustry.ui.MobileButton", "io.anuke.mindustry.ui.MultiReqImage", "io.anuke.mindustry.ui.ReqImage", "io.anuke.mindustry.ui.Styles", "io.anuke.mindustry.ui.dialogs.AboutDialog", "io.anuke.mindustry.ui.dialogs.AdminsDialog", "io.anuke.mindustry.ui.dialogs.BansDialog", "io.anuke.mindustry.ui.dialogs.ColorPicker", "io.anuke.mindustry.ui.dialogs.ContentInfoDialog", "io.anuke.mindustry.ui.dialogs.ControlsDialog", "io.anuke.mindustry.ui.dialogs.CustomGameDialog", "io.anuke.mindustry.ui.dialogs.CustomRulesDialog", "io.anuke.mindustry.ui.dialogs.DatabaseDialog", "io.anuke.mindustry.ui.dialogs.DeployDialog", "io.anuke.mindustry.ui.dialogs.DeployDialog$View", "io.anuke.mindustry.ui.dialogs.DeployDialog$ZoneNode", "io.anuke.mindustry.ui.dialogs.DiscordDialog", "io.anuke.mindustry.ui.dialogs.FileChooser", "io.anuke.mindustry.ui.dialogs.FileChooser$FileHistory", "io.anuke.mindustry.ui.dialogs.FloatingDialog", "io.anuke.mindustry.ui.dialogs.GameOverDialog", "io.anuke.mindustry.ui.dialogs.HostDialog", "io.anuke.mindustry.ui.dialogs.JoinDialog", "io.anuke.mindustry.ui.dialogs.JoinDialog$Server", "io.anuke.mindustry.ui.dialogs.LanguageDialog", "io.anuke.mindustry.ui.dialogs.LoadDialog", "io.anuke.mindustry.ui.dialogs.LoadoutDialog", "io.anuke.mindustry.ui.dialogs.MapPlayDialog", "io.anuke.mindustry.ui.dialogs.MapsDialog", "io.anuke.mindustry.ui.dialogs.MinimapDialog", "io.anuke.mindustry.ui.dialogs.ModsDialog", "io.anuke.mindustry.ui.dialogs.PaletteDialog", "io.anuke.mindustry.ui.dialogs.PausedDialog", "io.anuke.mindustry.ui.dialogs.SaveDialog", "io.anuke.mindustry.ui.dialogs.SchematicsDialog", "io.anuke.mindustry.ui.dialogs.SchematicsDialog$SchematicImage", "io.anuke.mindustry.ui.dialogs.SchematicsDialog$SchematicInfoDialog", "io.anuke.mindustry.ui.dialogs.SettingsMenuDialog", "io.anuke.mindustry.ui.dialogs.TechTreeDialog", "io.anuke.mindustry.ui.dialogs.TechTreeDialog$LayoutNode", "io.anuke.mindustry.ui.dialogs.TechTreeDialog$TechTreeNode", "io.anuke.mindustry.ui.dialogs.TechTreeDialog$View", "io.anuke.mindustry.ui.dialogs.TraceDialog", "io.anuke.mindustry.ui.dialogs.ZoneInfoDialog", "io.anuke.mindustry.ui.fragments.BlockConfigFragment", "io.anuke.mindustry.ui.fragments.BlockInventoryFragment", "io.anuke.mindustry.ui.fragments.ChatFragment", "io.anuke.mindustry.ui.fragments.FadeInFragment", "io.anuke.mindustry.ui.fragments.Fragment", "io.anuke.mindustry.ui.fragments.HudFragment", "io.anuke.mindustry.ui.fragments.LoadingFragment", "io.anuke.mindustry.ui.fragments.MenuFragment", "io.anuke.mindustry.ui.fragments.OverlayFragment", "io.anuke.mindustry.ui.fragments.PlacementFragment", "io.anuke.mindustry.ui.fragments.PlayerListFragment", "io.anuke.mindustry.ui.fragments.ScriptConsoleFragment", "io.anuke.mindustry.ui.layout.BranchTreeLayout", "io.anuke.mindustry.ui.layout.BranchTreeLayout$TreeAlignment", "io.anuke.mindustry.ui.layout.BranchTreeLayout$TreeLocation", "io.anuke.mindustry.ui.layout.RadialTreeLayout", "io.anuke.mindustry.ui.layout.TreeLayout", "io.anuke.mindustry.ui.layout.TreeLayout$TreeNode", "io.anuke.mindustry.world.Block", "io.anuke.mindustry.world.BlockStorage", "io.anuke.mindustry.world.Build", "io.anuke.mindustry.world.CachedTile", "io.anuke.mindustry.world.DirectionalItemBuffer", "io.anuke.mindustry.world.DirectionalItemBuffer$BufferItemStruct", "io.anuke.mindustry.world.Edges", "io.anuke.mindustry.world.ItemBuffer", "io.anuke.mindustry.world.LegacyColorMapper", "io.anuke.mindustry.world.LegacyColorMapper$LegacyBlock", "io.anuke.mindustry.world.Pos", "io.anuke.mindustry.world.StaticTree", "io.anuke.mindustry.world.Tile", "io.anuke.mindustry.world.WorldContext", "io.anuke.mindustry.world.blocks.Attributes", "io.anuke.mindustry.world.blocks.Autotiler", "io.anuke.mindustry.world.blocks.Autotiler$AutotilerHolder", "io.anuke.mindustry.world.blocks.BlockPart", "io.anuke.mindustry.world.blocks.BuildBlock", "io.anuke.mindustry.world.blocks.BuildBlock$BuildEntity", "io.anuke.mindustry.world.blocks.DoubleOverlayFloor", "io.anuke.mindustry.world.blocks.Floor", "io.anuke.mindustry.world.blocks.ItemSelection", "io.anuke.mindustry.world.blocks.LiquidBlock", "io.anuke.mindustry.world.blocks.OreBlock", "io.anuke.mindustry.world.blocks.OverlayFloor", "io.anuke.mindustry.world.blocks.PowerBlock", "io.anuke.mindustry.world.blocks.RespawnBlock", "io.anuke.mindustry.world.blocks.Rock", "io.anuke.mindustry.world.blocks.StaticWall", "io.anuke.mindustry.world.blocks.TreeBlock", "io.anuke.mindustry.world.blocks.defense.DeflectorWall", "io.anuke.mindustry.world.blocks.defense.DeflectorWall$DeflectorEntity", "io.anuke.mindustry.world.blocks.defense.Door", "io.anuke.mindustry.world.blocks.defense.Door$DoorEntity", "io.anuke.mindustry.world.blocks.defense.ForceProjector", "io.anuke.mindustry.world.blocks.defense.ForceProjector$ForceEntity", "io.anuke.mindustry.world.blocks.defense.ForceProjector$ShieldEntity", "io.anuke.mindustry.world.blocks.defense.MendProjector", "io.anuke.mindustry.world.blocks.defense.MendProjector$MendEntity", "io.anuke.mindustry.world.blocks.defense.OverdriveProjector", "io.anuke.mindustry.world.blocks.defense.OverdriveProjector$OverdriveEntity", "io.anuke.mindustry.world.blocks.defense.ShockMine", "io.anuke.mindustry.world.blocks.defense.SurgeWall", "io.anuke.mindustry.world.blocks.defense.Wall", "io.anuke.mindustry.world.blocks.defense.turrets.ArtilleryTurret", "io.anuke.mindustry.world.blocks.defense.turrets.BurstTurret", "io.anuke.mindustry.world.blocks.defense.turrets.ChargeTurret", "io.anuke.mindustry.world.blocks.defense.turrets.ChargeTurret$LaserTurretEntity", "io.anuke.mindustry.world.blocks.defense.turrets.CooledTurret", "io.anuke.mindustry.world.blocks.defense.turrets.DoubleTurret", "io.anuke.mindustry.world.blocks.defense.turrets.ItemTurret", "io.anuke.mindustry.world.blocks.defense.turrets.ItemTurret$ItemEntry", "io.anuke.mindustry.world.blocks.defense.turrets.ItemTurret$ItemTurretEntity", "io.anuke.mindustry.world.blocks.defense.turrets.LaserTurret", "io.anuke.mindustry.world.blocks.defense.turrets.LaserTurret$LaserTurretEntity", "io.anuke.mindustry.world.blocks.defense.turrets.LiquidTurret", "io.anuke.mindustry.world.blocks.defense.turrets.PowerTurret", "io.anuke.mindustry.world.blocks.defense.turrets.Turret", "io.anuke.mindustry.world.blocks.defense.turrets.Turret$AmmoEntry", "io.anuke.mindustry.world.blocks.defense.turrets.Turret$TurretEntity", "io.anuke.mindustry.world.blocks.distribution.ArmoredConveyor", "io.anuke.mindustry.world.blocks.distribution.BufferedItemBridge", "io.anuke.mindustry.world.blocks.distribution.BufferedItemBridge$BufferedItemBridgeEntity", "io.anuke.mindustry.world.blocks.distribution.Conveyor", "io.anuke.mindustry.world.blocks.distribution.Conveyor$ConveyorEntity", "io.anuke.mindustry.world.blocks.distribution.Conveyor$ItemPos", "io.anuke.mindustry.world.blocks.distribution.ExtendingItemBridge", "io.anuke.mindustry.world.blocks.distribution.ItemBridge", "io.anuke.mindustry.world.blocks.distribution.ItemBridge$ItemBridgeEntity", "io.anuke.mindustry.world.blocks.distribution.Junction", "io.anuke.mindustry.world.blocks.distribution.Junction$JunctionEntity", "io.anuke.mindustry.world.blocks.distribution.MassDriver", "io.anuke.mindustry.world.blocks.distribution.MassDriver$DriverBulletData", "io.anuke.mindustry.world.blocks.distribution.MassDriver$DriverState", "io.anuke.mindustry.world.blocks.distribution.MassDriver$MassDriverEntity", "io.anuke.mindustry.world.blocks.distribution.OverflowGate", "io.anuke.mindustry.world.blocks.distribution.OverflowGate$OverflowGateEntity", "io.anuke.mindustry.world.blocks.distribution.Router", "io.anuke.mindustry.world.blocks.distribution.Router$RouterEntity", "io.anuke.mindustry.world.blocks.distribution.Sorter", "io.anuke.mindustry.world.blocks.distribution.Sorter$SorterEntity", "io.anuke.mindustry.world.blocks.liquid.ArmoredConduit", "io.anuke.mindustry.world.blocks.liquid.Conduit", "io.anuke.mindustry.world.blocks.liquid.Conduit$ConduitEntity", "io.anuke.mindustry.world.blocks.liquid.LiquidBridge", "io.anuke.mindustry.world.blocks.liquid.LiquidExtendingBridge", "io.anuke.mindustry.world.blocks.liquid.LiquidJunction", "io.anuke.mindustry.world.blocks.liquid.LiquidOverflowGate", "io.anuke.mindustry.world.blocks.liquid.LiquidRouter", "io.anuke.mindustry.world.blocks.liquid.LiquidTank", "io.anuke.mindustry.world.blocks.logic.LogicBlock", "io.anuke.mindustry.world.blocks.logic.MessageBlock", "io.anuke.mindustry.world.blocks.logic.MessageBlock$MessageBlockEntity", "io.anuke.mindustry.world.blocks.power.Battery", "io.anuke.mindustry.world.blocks.power.BurnerGenerator", "io.anuke.mindustry.world.blocks.power.ConditionalConsumePower", "io.anuke.mindustry.world.blocks.power.DecayGenerator", "io.anuke.mindustry.world.blocks.power.ImpactReactor", "io.anuke.mindustry.world.blocks.power.ImpactReactor$FusionReactorEntity", "io.anuke.mindustry.world.blocks.power.ItemLiquidGenerator", "io.anuke.mindustry.world.blocks.power.ItemLiquidGenerator$ItemLiquidGeneratorEntity", "io.anuke.mindustry.world.blocks.power.LightBlock", "io.anuke.mindustry.world.blocks.power.LightBlock$LightEntity", "io.anuke.mindustry.world.blocks.power.NuclearReactor", "io.anuke.mindustry.world.blocks.power.NuclearReactor$NuclearReactorEntity", "io.anuke.mindustry.world.blocks.power.PowerDiode", "io.anuke.mindustry.world.blocks.power.PowerDistributor", "io.anuke.mindustry.world.blocks.power.PowerGenerator", "io.anuke.mindustry.world.blocks.power.PowerGenerator$GeneratorEntity", "io.anuke.mindustry.world.blocks.power.PowerGraph", "io.anuke.mindustry.world.blocks.power.PowerNode", "io.anuke.mindustry.world.blocks.power.SingleTypeGenerator", "io.anuke.mindustry.world.blocks.power.SolarGenerator", "io.anuke.mindustry.world.blocks.power.ThermalGenerator", "io.anuke.mindustry.world.blocks.production.Cultivator", "io.anuke.mindustry.world.blocks.production.Cultivator$CultivatorEntity", "io.anuke.mindustry.world.blocks.production.Drill", "io.anuke.mindustry.world.blocks.production.Drill$DrillEntity", "io.anuke.mindustry.world.blocks.production.Fracker", "io.anuke.mindustry.world.blocks.production.Fracker$FrackerEntity", "io.anuke.mindustry.world.blocks.production.GenericCrafter", "io.anuke.mindustry.world.blocks.production.GenericCrafter$GenericCrafterEntity", "io.anuke.mindustry.world.blocks.production.GenericSmelter", "io.anuke.mindustry.world.blocks.production.Incinerator", "io.anuke.mindustry.world.blocks.production.Incinerator$IncineratorEntity", "io.anuke.mindustry.world.blocks.production.LiquidConverter", "io.anuke.mindustry.world.blocks.production.Pump", "io.anuke.mindustry.world.blocks.production.Separator", "io.anuke.mindustry.world.blocks.production.SolidPump", "io.anuke.mindustry.world.blocks.production.SolidPump$SolidPumpEntity", "io.anuke.mindustry.world.blocks.sandbox.ItemSource", "io.anuke.mindustry.world.blocks.sandbox.ItemSource$ItemSourceEntity", "io.anuke.mindustry.world.blocks.sandbox.ItemVoid", "io.anuke.mindustry.world.blocks.sandbox.LiquidSource", "io.anuke.mindustry.world.blocks.sandbox.LiquidSource$LiquidSourceEntity", "io.anuke.mindustry.world.blocks.sandbox.PowerSource", "io.anuke.mindustry.world.blocks.sandbox.PowerVoid", "io.anuke.mindustry.world.blocks.storage.CoreBlock", "io.anuke.mindustry.world.blocks.storage.CoreBlock$CoreEntity", "io.anuke.mindustry.world.blocks.storage.LaunchPad", "io.anuke.mindustry.world.blocks.storage.StorageBlock", "io.anuke.mindustry.world.blocks.storage.StorageBlock$StorageBlockEntity", "io.anuke.mindustry.world.blocks.storage.Unloader", "io.anuke.mindustry.world.blocks.storage.Unloader$UnloaderEntity", "io.anuke.mindustry.world.blocks.storage.Vault", "io.anuke.mindustry.world.blocks.units.CommandCenter", "io.anuke.mindustry.world.blocks.units.CommandCenter$CommandCenterEntity", "io.anuke.mindustry.world.blocks.units.MechPad", "io.anuke.mindustry.world.blocks.units.MechPad$MechFactoryEntity", "io.anuke.mindustry.world.blocks.units.RallyPoint", "io.anuke.mindustry.world.blocks.units.RepairPoint", "io.anuke.mindustry.world.blocks.units.RepairPoint$RepairPointEntity", "io.anuke.mindustry.world.blocks.units.UnitFactory", "io.anuke.mindustry.world.blocks.units.UnitFactory$UnitFactoryEntity", "io.anuke.mindustry.world.consumers.Consume", "io.anuke.mindustry.world.consumers.ConsumeItemFilter", "io.anuke.mindustry.world.consumers.ConsumeItems", "io.anuke.mindustry.world.consumers.ConsumeLiquid", "io.anuke.mindustry.world.consumers.ConsumeLiquidBase", "io.anuke.mindustry.world.consumers.ConsumeLiquidFilter", "io.anuke.mindustry.world.consumers.ConsumePower", "io.anuke.mindustry.world.consumers.ConsumeType", "io.anuke.mindustry.world.consumers.Consumers", "io.anuke.mindustry.world.meta.Attribute", "io.anuke.mindustry.world.meta.BlockBars", "io.anuke.mindustry.world.meta.BlockFlag", "io.anuke.mindustry.world.meta.BlockGroup", "io.anuke.mindustry.world.meta.BlockStat", "io.anuke.mindustry.world.meta.BlockStats", "io.anuke.mindustry.world.meta.BuildVisibility", "io.anuke.mindustry.world.meta.PowerType", "io.anuke.mindustry.world.meta.Producers", "io.anuke.mindustry.world.meta.StatCategory", "io.anuke.mindustry.world.meta.StatUnit", "io.anuke.mindustry.world.meta.StatValue", "io.anuke.mindustry.world.meta.values.AmmoListValue", "io.anuke.mindustry.world.meta.values.BooleanValue", "io.anuke.mindustry.world.meta.values.BoosterListValue", "io.anuke.mindustry.world.meta.values.ItemFilterValue", "io.anuke.mindustry.world.meta.values.ItemListValue", "io.anuke.mindustry.world.meta.values.LiquidFilterValue", "io.anuke.mindustry.world.meta.values.LiquidValue", "io.anuke.mindustry.world.meta.values.NumberValue", "io.anuke.mindustry.world.meta.values.StringValue", "io.anuke.mindustry.world.modules.BlockModule", "io.anuke.mindustry.world.modules.ConsumeModule", "io.anuke.mindustry.world.modules.ItemModule", "io.anuke.mindustry.world.modules.ItemModule$ItemCalculator", "io.anuke.mindustry.world.modules.ItemModule$ItemConsumer", "io.anuke.mindustry.world.modules.LiquidModule", "io.anuke.mindustry.world.modules.LiquidModule$LiquidCalculator", "io.anuke.mindustry.world.modules.LiquidModule$LiquidConsumer", "io.anuke.mindustry.world.modules.PowerModule", "io.anuke.mindustry.world.producers.Produce", "io.anuke.mindustry.world.producers.ProduceItem", "java.io.PrintStream", "java.lang.Object", "java.lang.Runnable", "java.lang.String", "java.lang.System"); + public static final ObjectSet allowedClassNames = ObjectSet.with("io.anuke.arc.Core", "io.anuke.arc.collection.Array", "io.anuke.arc.collection.Array$ArrayIterable", "io.anuke.arc.collection.ArrayMap", "io.anuke.arc.collection.ArrayMap$Entries", "io.anuke.arc.collection.ArrayMap$Keys", "io.anuke.arc.collection.ArrayMap$Values", "io.anuke.arc.collection.AtomicQueue", "io.anuke.arc.collection.BinaryHeap", "io.anuke.arc.collection.BinaryHeap$Node", "io.anuke.arc.collection.Bits", "io.anuke.arc.collection.BooleanArray", "io.anuke.arc.collection.ByteArray", "io.anuke.arc.collection.CharArray", "io.anuke.arc.collection.ComparableTimSort", "io.anuke.arc.collection.DelayedRemovalArray", "io.anuke.arc.collection.EnumSet", "io.anuke.arc.collection.EnumSet$EnumSetIterator", "io.anuke.arc.collection.FloatArray", "io.anuke.arc.collection.GridBits", "io.anuke.arc.collection.GridMap", "io.anuke.arc.collection.IdentityMap", "io.anuke.arc.collection.IdentityMap$Entries", "io.anuke.arc.collection.IdentityMap$Entry", "io.anuke.arc.collection.IdentityMap$Keys", "io.anuke.arc.collection.IdentityMap$Values", "io.anuke.arc.collection.IntArray", "io.anuke.arc.collection.IntFloatMap", "io.anuke.arc.collection.IntFloatMap$Entries", "io.anuke.arc.collection.IntFloatMap$Entry", "io.anuke.arc.collection.IntFloatMap$Keys", "io.anuke.arc.collection.IntFloatMap$Values", "io.anuke.arc.collection.IntIntMap", "io.anuke.arc.collection.IntIntMap$Entries", "io.anuke.arc.collection.IntIntMap$Entry", "io.anuke.arc.collection.IntIntMap$Keys", "io.anuke.arc.collection.IntIntMap$Values", "io.anuke.arc.collection.IntMap", "io.anuke.arc.collection.IntMap$Entries", "io.anuke.arc.collection.IntMap$Entry", "io.anuke.arc.collection.IntMap$Keys", "io.anuke.arc.collection.IntMap$Values", "io.anuke.arc.collection.IntQueue", "io.anuke.arc.collection.IntSet", "io.anuke.arc.collection.IntSet$IntSetIterator", "io.anuke.arc.collection.LongArray", "io.anuke.arc.collection.LongMap", "io.anuke.arc.collection.LongMap$Entries", "io.anuke.arc.collection.LongMap$Entry", "io.anuke.arc.collection.LongMap$Keys", "io.anuke.arc.collection.LongMap$Values", "io.anuke.arc.collection.LongQueue", "io.anuke.arc.collection.ObjectFloatMap", "io.anuke.arc.collection.ObjectFloatMap$Entries", "io.anuke.arc.collection.ObjectFloatMap$Entry", "io.anuke.arc.collection.ObjectFloatMap$Keys", "io.anuke.arc.collection.ObjectFloatMap$Values", "io.anuke.arc.collection.ObjectIntMap", "io.anuke.arc.collection.ObjectIntMap$Entries", "io.anuke.arc.collection.ObjectIntMap$Entry", "io.anuke.arc.collection.ObjectIntMap$Keys", "io.anuke.arc.collection.ObjectIntMap$Values", "io.anuke.arc.collection.ObjectMap", "io.anuke.arc.collection.ObjectMap$Entries", "io.anuke.arc.collection.ObjectMap$Entry", "io.anuke.arc.collection.ObjectMap$Keys", "io.anuke.arc.collection.ObjectMap$Values", "io.anuke.arc.collection.ObjectSet", "io.anuke.arc.collection.ObjectSet$ObjectSetIterator", "io.anuke.arc.collection.OrderedMap", "io.anuke.arc.collection.OrderedMap$OrderedMapEntries", "io.anuke.arc.collection.OrderedMap$OrderedMapKeys", "io.anuke.arc.collection.OrderedMap$OrderedMapValues", "io.anuke.arc.collection.OrderedSet", "io.anuke.arc.collection.OrderedSet$OrderedSetIterator", "io.anuke.arc.collection.PooledLinkedList", "io.anuke.arc.collection.PooledLinkedList$Item", "io.anuke.arc.collection.Queue", "io.anuke.arc.collection.Queue$QueueIterable", "io.anuke.arc.collection.ShortArray", "io.anuke.arc.collection.SnapshotArray", "io.anuke.arc.collection.Sort", "io.anuke.arc.collection.SortedIntList", "io.anuke.arc.collection.SortedIntList$Iterator", "io.anuke.arc.collection.SortedIntList$Node", "io.anuke.arc.collection.StringMap", "io.anuke.arc.collection.TimSort", "io.anuke.arc.func.Boolc", "io.anuke.arc.func.Boolf", "io.anuke.arc.func.Boolf2", "io.anuke.arc.func.Boolp", "io.anuke.arc.func.Cons", "io.anuke.arc.func.Cons2", "io.anuke.arc.func.Floatc", "io.anuke.arc.func.Floatc2", "io.anuke.arc.func.Floatc4", "io.anuke.arc.func.Floatf", "io.anuke.arc.func.Floatp", "io.anuke.arc.func.Func", "io.anuke.arc.func.Func2", "io.anuke.arc.func.Func3", "io.anuke.arc.func.Intc", "io.anuke.arc.func.Intc2", "io.anuke.arc.func.Intc4", "io.anuke.arc.func.Intf", "io.anuke.arc.func.Intp", "io.anuke.arc.func.Prov", "io.anuke.arc.graphics.Color", "io.anuke.arc.graphics.g2d.Draw", "io.anuke.arc.graphics.g2d.Fill", "io.anuke.arc.graphics.g2d.Lines", "io.anuke.arc.graphics.g2d.TextureAtlas", "io.anuke.arc.graphics.g2d.TextureAtlas$AtlasRegion", "io.anuke.arc.graphics.g2d.TextureRegion", "io.anuke.arc.math.Angles", "io.anuke.arc.math.Mathf", "io.anuke.arc.scene.Action", "io.anuke.arc.scene.Element", "io.anuke.arc.scene.Group", "io.anuke.arc.scene.Scene", "io.anuke.arc.scene.Scene$TouchFocus", "io.anuke.arc.scene.actions.Actions", "io.anuke.arc.scene.actions.AddAction", "io.anuke.arc.scene.actions.AddListenerAction", "io.anuke.arc.scene.actions.AfterAction", "io.anuke.arc.scene.actions.AlphaAction", "io.anuke.arc.scene.actions.ColorAction", "io.anuke.arc.scene.actions.DelayAction", "io.anuke.arc.scene.actions.DelegateAction", "io.anuke.arc.scene.actions.FloatAction", "io.anuke.arc.scene.actions.IntAction", "io.anuke.arc.scene.actions.LayoutAction", "io.anuke.arc.scene.actions.MoveByAction", "io.anuke.arc.scene.actions.MoveToAction", "io.anuke.arc.scene.actions.OriginAction", "io.anuke.arc.scene.actions.ParallelAction", "io.anuke.arc.scene.actions.RelativeTemporalAction", "io.anuke.arc.scene.actions.RemoveAction", "io.anuke.arc.scene.actions.RemoveActorAction", "io.anuke.arc.scene.actions.RemoveListenerAction", "io.anuke.arc.scene.actions.RepeatAction", "io.anuke.arc.scene.actions.RotateByAction", "io.anuke.arc.scene.actions.RotateToAction", "io.anuke.arc.scene.actions.RunnableAction", "io.anuke.arc.scene.actions.ScaleByAction", "io.anuke.arc.scene.actions.ScaleToAction", "io.anuke.arc.scene.actions.SequenceAction", "io.anuke.arc.scene.actions.SizeByAction", "io.anuke.arc.scene.actions.SizeToAction", "io.anuke.arc.scene.actions.TemporalAction", "io.anuke.arc.scene.actions.TimeScaleAction", "io.anuke.arc.scene.actions.TouchableAction", "io.anuke.arc.scene.actions.TranslateByAction", "io.anuke.arc.scene.actions.VisibleAction", "io.anuke.arc.scene.event.ChangeListener", "io.anuke.arc.scene.event.ChangeListener$ChangeEvent", "io.anuke.arc.scene.event.ClickListener", "io.anuke.arc.scene.event.DragListener", "io.anuke.arc.scene.event.DragScrollListener", "io.anuke.arc.scene.event.ElementGestureListener", "io.anuke.arc.scene.event.EventListener", "io.anuke.arc.scene.event.FocusListener", "io.anuke.arc.scene.event.FocusListener$FocusEvent", "io.anuke.arc.scene.event.FocusListener$FocusEvent$Type", "io.anuke.arc.scene.event.HandCursorListener", "io.anuke.arc.scene.event.IbeamCursorListener", "io.anuke.arc.scene.event.InputEvent", "io.anuke.arc.scene.event.InputEvent$Type", "io.anuke.arc.scene.event.InputListener", "io.anuke.arc.scene.event.SceneEvent", "io.anuke.arc.scene.event.Touchable", "io.anuke.arc.scene.event.VisibilityEvent", "io.anuke.arc.scene.event.VisibilityListener", "io.anuke.arc.scene.style.BaseDrawable", "io.anuke.arc.scene.style.Drawable", "io.anuke.arc.scene.style.NinePatchDrawable", "io.anuke.arc.scene.style.ScaledNinePatchDrawable", "io.anuke.arc.scene.style.Style", "io.anuke.arc.scene.style.TextureRegionDrawable", "io.anuke.arc.scene.style.TiledDrawable", "io.anuke.arc.scene.style.TransformDrawable", "io.anuke.arc.scene.ui.Button", "io.anuke.arc.scene.ui.Button$ButtonStyle", "io.anuke.arc.scene.ui.ButtonGroup", "io.anuke.arc.scene.ui.CheckBox", "io.anuke.arc.scene.ui.CheckBox$CheckBoxStyle", "io.anuke.arc.scene.ui.ColorImage", "io.anuke.arc.scene.ui.Dialog", "io.anuke.arc.scene.ui.Dialog$DialogStyle", "io.anuke.arc.scene.ui.Image", "io.anuke.arc.scene.ui.ImageButton", "io.anuke.arc.scene.ui.ImageButton$ImageButtonStyle", "io.anuke.arc.scene.ui.KeybindDialog", "io.anuke.arc.scene.ui.KeybindDialog$KeybindDialogStyle", "io.anuke.arc.scene.ui.Label", "io.anuke.arc.scene.ui.Label$LabelStyle", "io.anuke.arc.scene.ui.ProgressBar", "io.anuke.arc.scene.ui.ProgressBar$ProgressBarStyle", "io.anuke.arc.scene.ui.ScrollPane", "io.anuke.arc.scene.ui.ScrollPane$ScrollPaneStyle", "io.anuke.arc.scene.ui.SettingsDialog", "io.anuke.arc.scene.ui.SettingsDialog$SettingsTable", "io.anuke.arc.scene.ui.SettingsDialog$SettingsTable$CheckSetting", "io.anuke.arc.scene.ui.SettingsDialog$SettingsTable$Setting", "io.anuke.arc.scene.ui.SettingsDialog$SettingsTable$SliderSetting", "io.anuke.arc.scene.ui.SettingsDialog$StringProcessor", "io.anuke.arc.scene.ui.Slider", "io.anuke.arc.scene.ui.Slider$SliderStyle", "io.anuke.arc.scene.ui.TextArea", "io.anuke.arc.scene.ui.TextArea$TextAreaListener", "io.anuke.arc.scene.ui.TextButton", "io.anuke.arc.scene.ui.TextButton$TextButtonStyle", "io.anuke.arc.scene.ui.TextField", "io.anuke.arc.scene.ui.TextField$DefaultOnscreenKeyboard", "io.anuke.arc.scene.ui.TextField$OnscreenKeyboard", "io.anuke.arc.scene.ui.TextField$TextFieldClickListener", "io.anuke.arc.scene.ui.TextField$TextFieldFilter", "io.anuke.arc.scene.ui.TextField$TextFieldListener", "io.anuke.arc.scene.ui.TextField$TextFieldStyle", "io.anuke.arc.scene.ui.TextField$TextFieldValidator", "io.anuke.arc.scene.ui.Tooltip", "io.anuke.arc.scene.ui.Tooltip$Tooltips", "io.anuke.arc.scene.ui.Touchpad", "io.anuke.arc.scene.ui.Touchpad$TouchpadStyle", "io.anuke.arc.scene.ui.TreeElement", "io.anuke.arc.scene.ui.TreeElement$Node", "io.anuke.arc.scene.ui.TreeElement$TreeStyle", "io.anuke.arc.scene.ui.layout.Cell", "io.anuke.arc.scene.ui.layout.Collapser", "io.anuke.arc.scene.ui.layout.HorizontalGroup", "io.anuke.arc.scene.ui.layout.Scl", "io.anuke.arc.scene.ui.layout.Stack", "io.anuke.arc.scene.ui.layout.Table", "io.anuke.arc.scene.ui.layout.Table$DrawRect", "io.anuke.arc.scene.ui.layout.VerticalGroup", "io.anuke.arc.scene.ui.layout.WidgetGroup", "io.anuke.arc.scene.utils.ArraySelection", "io.anuke.arc.scene.utils.Cullable", "io.anuke.arc.scene.utils.Disableable", "io.anuke.arc.scene.utils.DragAndDrop", "io.anuke.arc.scene.utils.DragAndDrop$Payload", "io.anuke.arc.scene.utils.DragAndDrop$Source", "io.anuke.arc.scene.utils.DragAndDrop$Target", "io.anuke.arc.scene.utils.Elements", "io.anuke.arc.scene.utils.Layout", "io.anuke.arc.scene.utils.Selection", "io.anuke.arc.util.Time", "io.anuke.mindustry.Vars", "io.anuke.mindustry.ai.BlockIndexer", "io.anuke.mindustry.ai.Pathfinder", "io.anuke.mindustry.ai.Pathfinder$PathData", "io.anuke.mindustry.ai.Pathfinder$PathTarget", "io.anuke.mindustry.ai.Pathfinder$PathTileStruct", "io.anuke.mindustry.ai.WaveSpawner", "io.anuke.mindustry.content.Blocks", "io.anuke.mindustry.content.Bullets", "io.anuke.mindustry.content.Fx", "io.anuke.mindustry.content.Items", "io.anuke.mindustry.content.Liquids", "io.anuke.mindustry.content.Loadouts", "io.anuke.mindustry.content.Mechs", "io.anuke.mindustry.content.StatusEffects", "io.anuke.mindustry.content.TechTree", "io.anuke.mindustry.content.TechTree$TechNode", "io.anuke.mindustry.content.TypeIDs", "io.anuke.mindustry.content.UnitTypes", "io.anuke.mindustry.content.Zones", "io.anuke.mindustry.core.ContentLoader", "io.anuke.mindustry.core.Control", "io.anuke.mindustry.core.FileTree", "io.anuke.mindustry.core.GameState", "io.anuke.mindustry.core.GameState$State", "io.anuke.mindustry.core.Logic", "io.anuke.mindustry.core.Platform", "io.anuke.mindustry.core.Renderer", "io.anuke.mindustry.core.UI", "io.anuke.mindustry.core.Version", "io.anuke.mindustry.core.World", "io.anuke.mindustry.core.World$Raycaster", "io.anuke.mindustry.ctype.Content", "io.anuke.mindustry.ctype.ContentList", "io.anuke.mindustry.ctype.MappableContent", "io.anuke.mindustry.ctype.UnlockableContent", "io.anuke.mindustry.editor.DrawOperation", "io.anuke.mindustry.editor.DrawOperation$OpType", "io.anuke.mindustry.editor.DrawOperation$TileOpStruct", "io.anuke.mindustry.editor.EditorTile", "io.anuke.mindustry.editor.EditorTool", "io.anuke.mindustry.editor.MapEditor", "io.anuke.mindustry.editor.MapEditor$Context", "io.anuke.mindustry.editor.MapEditorDialog", "io.anuke.mindustry.editor.MapGenerateDialog", "io.anuke.mindustry.editor.MapInfoDialog", "io.anuke.mindustry.editor.MapLoadDialog", "io.anuke.mindustry.editor.MapRenderer", "io.anuke.mindustry.editor.MapResizeDialog", "io.anuke.mindustry.editor.MapSaveDialog", "io.anuke.mindustry.editor.MapView", "io.anuke.mindustry.editor.OperationStack", "io.anuke.mindustry.editor.WaveInfoDialog", "io.anuke.mindustry.entities.Damage", "io.anuke.mindustry.entities.Damage$PropCellStruct", "io.anuke.mindustry.entities.Effects", "io.anuke.mindustry.entities.Effects$Effect", "io.anuke.mindustry.entities.Effects$EffectContainer", "io.anuke.mindustry.entities.Effects$EffectProvider", "io.anuke.mindustry.entities.Effects$EffectRenderer", "io.anuke.mindustry.entities.Effects$ScreenshakeProvider", "io.anuke.mindustry.entities.Entities", "io.anuke.mindustry.entities.EntityCollisions", "io.anuke.mindustry.entities.EntityGroup", "io.anuke.mindustry.entities.Predict", "io.anuke.mindustry.entities.TargetPriority", "io.anuke.mindustry.entities.Units", "io.anuke.mindustry.entities.bullet.ArtilleryBulletType", "io.anuke.mindustry.entities.bullet.BasicBulletType", "io.anuke.mindustry.entities.bullet.BombBulletType", "io.anuke.mindustry.entities.bullet.BulletType", "io.anuke.mindustry.entities.bullet.FlakBulletType", "io.anuke.mindustry.entities.bullet.HealBulletType", "io.anuke.mindustry.entities.bullet.LiquidBulletType", "io.anuke.mindustry.entities.bullet.MassDriverBolt", "io.anuke.mindustry.entities.bullet.MissileBulletType", "io.anuke.mindustry.entities.effect.Decal", "io.anuke.mindustry.entities.effect.Fire", "io.anuke.mindustry.entities.effect.GroundEffectEntity", "io.anuke.mindustry.entities.effect.GroundEffectEntity$GroundEffect", "io.anuke.mindustry.entities.effect.ItemTransfer", "io.anuke.mindustry.entities.effect.Lightning", "io.anuke.mindustry.entities.effect.Puddle", "io.anuke.mindustry.entities.effect.RubbleDecal", "io.anuke.mindustry.entities.effect.ScorchDecal", "io.anuke.mindustry.entities.traits.AbsorbTrait", "io.anuke.mindustry.entities.traits.BelowLiquidTrait", "io.anuke.mindustry.entities.traits.BuilderMinerTrait", "io.anuke.mindustry.entities.traits.BuilderTrait", "io.anuke.mindustry.entities.traits.BuilderTrait$BuildDataStatic", "io.anuke.mindustry.entities.traits.BuilderTrait$BuildRequest", "io.anuke.mindustry.entities.traits.DamageTrait", "io.anuke.mindustry.entities.traits.DrawTrait", "io.anuke.mindustry.entities.traits.Entity", "io.anuke.mindustry.entities.traits.HealthTrait", "io.anuke.mindustry.entities.traits.KillerTrait", "io.anuke.mindustry.entities.traits.MinerTrait", "io.anuke.mindustry.entities.traits.MoveTrait", "io.anuke.mindustry.entities.traits.SaveTrait", "io.anuke.mindustry.entities.traits.Saveable", "io.anuke.mindustry.entities.traits.ScaleTrait", "io.anuke.mindustry.entities.traits.ShooterTrait", "io.anuke.mindustry.entities.traits.SolidTrait", "io.anuke.mindustry.entities.traits.SpawnerTrait", "io.anuke.mindustry.entities.traits.SyncTrait", "io.anuke.mindustry.entities.traits.TargetTrait", "io.anuke.mindustry.entities.traits.TeamTrait", "io.anuke.mindustry.entities.traits.TimeTrait", "io.anuke.mindustry.entities.traits.TypeTrait", "io.anuke.mindustry.entities.traits.VelocityTrait", "io.anuke.mindustry.entities.type.BaseEntity", "io.anuke.mindustry.entities.type.BaseUnit", "io.anuke.mindustry.entities.type.Bullet", "io.anuke.mindustry.entities.type.DestructibleEntity", "io.anuke.mindustry.entities.type.EffectEntity", "io.anuke.mindustry.entities.type.Player", "io.anuke.mindustry.entities.type.SolidEntity", "io.anuke.mindustry.entities.type.TileEntity", "io.anuke.mindustry.entities.type.TimedEntity", "io.anuke.mindustry.entities.type.Unit", "io.anuke.mindustry.entities.type.base.BaseDrone", "io.anuke.mindustry.entities.type.base.BuilderDrone", "io.anuke.mindustry.entities.type.base.Crawler", "io.anuke.mindustry.entities.type.base.Dagger", "io.anuke.mindustry.entities.type.base.Draug", "io.anuke.mindustry.entities.type.base.Eruptor", "io.anuke.mindustry.entities.type.base.FlyingUnit", "io.anuke.mindustry.entities.type.base.Fortress", "io.anuke.mindustry.entities.type.base.Ghoul", "io.anuke.mindustry.entities.type.base.GroundUnit", "io.anuke.mindustry.entities.type.base.MinerDrone", "io.anuke.mindustry.entities.type.base.Phantom", "io.anuke.mindustry.entities.type.base.RepairDrone", "io.anuke.mindustry.entities.type.base.Revenant", "io.anuke.mindustry.entities.type.base.Spirit", "io.anuke.mindustry.entities.type.base.Titan", "io.anuke.mindustry.entities.type.base.Wraith", "io.anuke.mindustry.entities.units.StateMachine", "io.anuke.mindustry.entities.units.Statuses", "io.anuke.mindustry.entities.units.Statuses$StatusEntry", "io.anuke.mindustry.entities.units.UnitCommand", "io.anuke.mindustry.entities.units.UnitDrops", "io.anuke.mindustry.entities.units.UnitState", "io.anuke.mindustry.game.DefaultWaves", "io.anuke.mindustry.game.Difficulty", "io.anuke.mindustry.game.EventType", "io.anuke.mindustry.game.EventType$BlockBuildBeginEvent", "io.anuke.mindustry.game.EventType$BlockBuildEndEvent", "io.anuke.mindustry.game.EventType$BlockDestroyEvent", "io.anuke.mindustry.game.EventType$BlockInfoEvent", "io.anuke.mindustry.game.EventType$BuildSelectEvent", "io.anuke.mindustry.game.EventType$ClientLoadEvent", "io.anuke.mindustry.game.EventType$CommandIssueEvent", "io.anuke.mindustry.game.EventType$ContentReloadEvent", "io.anuke.mindustry.game.EventType$CoreItemDeliverEvent", "io.anuke.mindustry.game.EventType$DepositEvent", "io.anuke.mindustry.game.EventType$DisposeEvent", "io.anuke.mindustry.game.EventType$GameOverEvent", "io.anuke.mindustry.game.EventType$LaunchEvent", "io.anuke.mindustry.game.EventType$LaunchItemEvent", "io.anuke.mindustry.game.EventType$LineConfirmEvent", "io.anuke.mindustry.game.EventType$LoseEvent", "io.anuke.mindustry.game.EventType$MapMakeEvent", "io.anuke.mindustry.game.EventType$MapPublishEvent", "io.anuke.mindustry.game.EventType$MechChangeEvent", "io.anuke.mindustry.game.EventType$PlayEvent", "io.anuke.mindustry.game.EventType$PlayerBanEvent", "io.anuke.mindustry.game.EventType$PlayerChatEvent", "io.anuke.mindustry.game.EventType$PlayerConnect", "io.anuke.mindustry.game.EventType$PlayerIpBanEvent", "io.anuke.mindustry.game.EventType$PlayerIpUnbanEvent", "io.anuke.mindustry.game.EventType$PlayerJoin", "io.anuke.mindustry.game.EventType$PlayerLeave", "io.anuke.mindustry.game.EventType$PlayerUnbanEvent", "io.anuke.mindustry.game.EventType$ResearchEvent", "io.anuke.mindustry.game.EventType$ResetEvent", "io.anuke.mindustry.game.EventType$ResizeEvent", "io.anuke.mindustry.game.EventType$StateChangeEvent", "io.anuke.mindustry.game.EventType$TapConfigEvent", "io.anuke.mindustry.game.EventType$TapEvent", "io.anuke.mindustry.game.EventType$TileChangeEvent", "io.anuke.mindustry.game.EventType$Trigger", "io.anuke.mindustry.game.EventType$TurretAmmoDeliverEvent", "io.anuke.mindustry.game.EventType$UnitCreateEvent", "io.anuke.mindustry.game.EventType$UnitDestroyEvent", "io.anuke.mindustry.game.EventType$UnlockEvent", "io.anuke.mindustry.game.EventType$WaveEvent", "io.anuke.mindustry.game.EventType$WinEvent", "io.anuke.mindustry.game.EventType$WithdrawEvent", "io.anuke.mindustry.game.EventType$WorldLoadEvent", "io.anuke.mindustry.game.EventType$ZoneConfigureCompleteEvent", "io.anuke.mindustry.game.EventType$ZoneRequireCompleteEvent", "io.anuke.mindustry.game.Gamemode", "io.anuke.mindustry.game.GlobalData", "io.anuke.mindustry.game.LoopControl", "io.anuke.mindustry.game.MusicControl", "io.anuke.mindustry.game.Objective", "io.anuke.mindustry.game.Objectives", "io.anuke.mindustry.game.Objectives$Launched", "io.anuke.mindustry.game.Objectives$Unlock", "io.anuke.mindustry.game.Objectives$Wave", "io.anuke.mindustry.game.Objectives$ZoneObjective", "io.anuke.mindustry.game.Objectives$ZoneWave", "io.anuke.mindustry.game.Rules", "io.anuke.mindustry.game.Saves", "io.anuke.mindustry.game.Saves$SaveSlot", "io.anuke.mindustry.game.Schematic", "io.anuke.mindustry.game.Schematic$Stile", "io.anuke.mindustry.game.Schematics", "io.anuke.mindustry.game.SoundLoop", "io.anuke.mindustry.game.SpawnGroup", "io.anuke.mindustry.game.Stats", "io.anuke.mindustry.game.Stats$Rank", "io.anuke.mindustry.game.Stats$RankResult", "io.anuke.mindustry.game.Team", "io.anuke.mindustry.game.Teams", "io.anuke.mindustry.game.Teams$BrokenBlock", "io.anuke.mindustry.game.Teams$TeamData", "io.anuke.mindustry.game.Tutorial", "io.anuke.mindustry.game.Tutorial$TutorialStage", "io.anuke.mindustry.gen.BufferItem", "io.anuke.mindustry.gen.Call", "io.anuke.mindustry.gen.Call", "io.anuke.mindustry.gen.Icon", "io.anuke.mindustry.gen.Icon", "io.anuke.mindustry.gen.MethodHash", "io.anuke.mindustry.gen.Musics", "io.anuke.mindustry.gen.Musics", "io.anuke.mindustry.gen.PathTile", "io.anuke.mindustry.gen.PropCell", "io.anuke.mindustry.gen.RemoteReadClient", "io.anuke.mindustry.gen.RemoteReadServer", "io.anuke.mindustry.gen.Serialization", "io.anuke.mindustry.gen.Sounds", "io.anuke.mindustry.gen.Sounds", "io.anuke.mindustry.gen.Tex", "io.anuke.mindustry.gen.Tex", "io.anuke.mindustry.gen.TileOp", "io.anuke.mindustry.graphics.BlockRenderer", "io.anuke.mindustry.graphics.Bloom", "io.anuke.mindustry.graphics.CacheLayer", "io.anuke.mindustry.graphics.Drawf", "io.anuke.mindustry.graphics.FloorRenderer", "io.anuke.mindustry.graphics.IndexedRenderer", "io.anuke.mindustry.graphics.Layer", "io.anuke.mindustry.graphics.LightRenderer", "io.anuke.mindustry.graphics.MenuRenderer", "io.anuke.mindustry.graphics.MinimapRenderer", "io.anuke.mindustry.graphics.MultiPacker", "io.anuke.mindustry.graphics.MultiPacker$PageType", "io.anuke.mindustry.graphics.OverlayRenderer", "io.anuke.mindustry.graphics.Pal", "io.anuke.mindustry.graphics.Pixelator", "io.anuke.mindustry.graphics.Shaders", "io.anuke.mindustry.input.Binding", "io.anuke.mindustry.input.DesktopInput", "io.anuke.mindustry.input.InputHandler", "io.anuke.mindustry.input.InputHandler$PlaceLine", "io.anuke.mindustry.input.MobileInput", "io.anuke.mindustry.input.PlaceMode", "io.anuke.mindustry.input.Placement", "io.anuke.mindustry.input.Placement$DistanceHeuristic", "io.anuke.mindustry.input.Placement$NormalizeDrawResult", "io.anuke.mindustry.input.Placement$NormalizeResult", "io.anuke.mindustry.input.Placement$TileHueristic", "io.anuke.mindustry.maps.Map", "io.anuke.mindustry.maps.Maps", "io.anuke.mindustry.maps.Maps$MapProvider", "io.anuke.mindustry.maps.Maps$ShuffleMode", "io.anuke.mindustry.maps.Maps$ShuffleMode", "io.anuke.mindustry.maps.filters.BlendFilter", "io.anuke.mindustry.maps.filters.ClearFilter", "io.anuke.mindustry.maps.filters.DistortFilter", "io.anuke.mindustry.maps.filters.FilterOption", "io.anuke.mindustry.maps.filters.FilterOption$BlockOption", "io.anuke.mindustry.maps.filters.FilterOption$SliderOption", "io.anuke.mindustry.maps.filters.GenerateFilter", "io.anuke.mindustry.maps.filters.GenerateFilter$GenerateInput", "io.anuke.mindustry.maps.filters.GenerateFilter$GenerateInput$TileProvider", "io.anuke.mindustry.maps.filters.MedianFilter", "io.anuke.mindustry.maps.filters.MirrorFilter", "io.anuke.mindustry.maps.filters.NoiseFilter", "io.anuke.mindustry.maps.filters.OreFilter", "io.anuke.mindustry.maps.filters.OreMedianFilter", "io.anuke.mindustry.maps.filters.RiverNoiseFilter", "io.anuke.mindustry.maps.filters.ScatterFilter", "io.anuke.mindustry.maps.filters.TerrainFilter", "io.anuke.mindustry.maps.generators.BasicGenerator", "io.anuke.mindustry.maps.generators.BasicGenerator$DistanceHeuristic", "io.anuke.mindustry.maps.generators.BasicGenerator$TileHueristic", "io.anuke.mindustry.maps.generators.Generator", "io.anuke.mindustry.maps.generators.MapGenerator", "io.anuke.mindustry.maps.generators.MapGenerator$Decoration", "io.anuke.mindustry.maps.generators.RandomGenerator", "io.anuke.mindustry.maps.zonegen.DesertWastesGenerator", "io.anuke.mindustry.maps.zonegen.OvergrowthGenerator", "io.anuke.mindustry.type.Category", "", "io.anuke.mindustry.type.Item", "io.anuke.mindustry.type.ItemStack", "io.anuke.mindustry.type.ItemType", "io.anuke.mindustry.type.Liquid", "io.anuke.mindustry.type.LiquidStack", "io.anuke.mindustry.type.Mech", "io.anuke.mindustry.type.Publishable", "io.anuke.mindustry.type.StatusEffect", "io.anuke.mindustry.type.StatusEffect$TransitionHandler", "io.anuke.mindustry.type.TypeID", "io.anuke.mindustry.type.UnitType", "io.anuke.mindustry.type.Weapon", "io.anuke.mindustry.type.WeatherEvent", "io.anuke.mindustry.type.Zone", "io.anuke.mindustry.ui.Bar", "io.anuke.mindustry.ui.BorderImage", "io.anuke.mindustry.ui.Cicon", "io.anuke.mindustry.ui.ContentDisplay", "io.anuke.mindustry.ui.Fonts", "io.anuke.mindustry.ui.GridImage", "io.anuke.mindustry.ui.IconSize", "io.anuke.mindustry.ui.IntFormat", "io.anuke.mindustry.ui.ItemDisplay", "io.anuke.mindustry.ui.ItemImage", "io.anuke.mindustry.ui.ItemsDisplay", "io.anuke.mindustry.ui.Links", "io.anuke.mindustry.ui.Links$LinkEntry", "io.anuke.mindustry.ui.LiquidDisplay", "io.anuke.mindustry.ui.Minimap", "io.anuke.mindustry.ui.MobileButton", "io.anuke.mindustry.ui.MultiReqImage", "io.anuke.mindustry.ui.ReqImage", "io.anuke.mindustry.ui.Styles", "io.anuke.mindustry.ui.dialogs.AboutDialog", "io.anuke.mindustry.ui.dialogs.AdminsDialog", "io.anuke.mindustry.ui.dialogs.BansDialog", "io.anuke.mindustry.ui.dialogs.ColorPicker", "io.anuke.mindustry.ui.dialogs.ContentInfoDialog", "io.anuke.mindustry.ui.dialogs.ControlsDialog", "io.anuke.mindustry.ui.dialogs.CustomGameDialog", "io.anuke.mindustry.ui.dialogs.CustomRulesDialog", "io.anuke.mindustry.ui.dialogs.DatabaseDialog", "io.anuke.mindustry.ui.dialogs.DeployDialog", "io.anuke.mindustry.ui.dialogs.DeployDialog$View", "io.anuke.mindustry.ui.dialogs.DeployDialog$ZoneNode", "io.anuke.mindustry.ui.dialogs.DiscordDialog", "io.anuke.mindustry.ui.dialogs.FileChooser", "io.anuke.mindustry.ui.dialogs.FileChooser$FileHistory", "io.anuke.mindustry.ui.dialogs.FloatingDialog", "io.anuke.mindustry.ui.dialogs.GameOverDialog", "io.anuke.mindustry.ui.dialogs.HostDialog", "io.anuke.mindustry.ui.dialogs.JoinDialog", "io.anuke.mindustry.ui.dialogs.JoinDialog$Server", "io.anuke.mindustry.ui.dialogs.LanguageDialog", "io.anuke.mindustry.ui.dialogs.LoadDialog", "io.anuke.mindustry.ui.dialogs.LoadoutDialog", "io.anuke.mindustry.ui.dialogs.MapPlayDialog", "io.anuke.mindustry.ui.dialogs.MapsDialog", "io.anuke.mindustry.ui.dialogs.MinimapDialog", "io.anuke.mindustry.ui.dialogs.ModsDialog", "io.anuke.mindustry.ui.dialogs.PaletteDialog", "io.anuke.mindustry.ui.dialogs.PausedDialog", "io.anuke.mindustry.ui.dialogs.SaveDialog", "io.anuke.mindustry.ui.dialogs.SchematicsDialog", "io.anuke.mindustry.ui.dialogs.SchematicsDialog$SchematicImage", "io.anuke.mindustry.ui.dialogs.SchematicsDialog$SchematicInfoDialog", "io.anuke.mindustry.ui.dialogs.SettingsMenuDialog", "io.anuke.mindustry.ui.dialogs.TechTreeDialog", "io.anuke.mindustry.ui.dialogs.TechTreeDialog$LayoutNode", "io.anuke.mindustry.ui.dialogs.TechTreeDialog$TechTreeNode", "io.anuke.mindustry.ui.dialogs.TechTreeDialog$View", "io.anuke.mindustry.ui.dialogs.TraceDialog", "io.anuke.mindustry.ui.dialogs.ZoneInfoDialog", "io.anuke.mindustry.ui.fragments.BlockConfigFragment", "io.anuke.mindustry.ui.fragments.BlockInventoryFragment", "io.anuke.mindustry.ui.fragments.ChatFragment", "io.anuke.mindustry.ui.fragments.FadeInFragment", "io.anuke.mindustry.ui.fragments.Fragment", "io.anuke.mindustry.ui.fragments.HudFragment", "io.anuke.mindustry.ui.fragments.LoadingFragment", "io.anuke.mindustry.ui.fragments.MenuFragment", "io.anuke.mindustry.ui.fragments.OverlayFragment", "io.anuke.mindustry.ui.fragments.PlacementFragment", "io.anuke.mindustry.ui.fragments.PlayerListFragment", "io.anuke.mindustry.ui.fragments.ScriptConsoleFragment", "io.anuke.mindustry.ui.layout.BranchTreeLayout", "io.anuke.mindustry.ui.layout.BranchTreeLayout$TreeAlignment", "io.anuke.mindustry.ui.layout.BranchTreeLayout$TreeLocation", "io.anuke.mindustry.ui.layout.RadialTreeLayout", "io.anuke.mindustry.ui.layout.TreeLayout", "io.anuke.mindustry.ui.layout.TreeLayout$TreeNode", "io.anuke.mindustry.world.Block", "io.anuke.mindustry.world.BlockStorage", "io.anuke.mindustry.world.Build", "io.anuke.mindustry.world.CachedTile", "io.anuke.mindustry.world.DirectionalItemBuffer", "io.anuke.mindustry.world.DirectionalItemBuffer$BufferItemStruct", "io.anuke.mindustry.world.Edges", "io.anuke.mindustry.world.ItemBuffer", "io.anuke.mindustry.world.LegacyColorMapper", "io.anuke.mindustry.world.LegacyColorMapper$LegacyBlock", "io.anuke.mindustry.world.Pos", "io.anuke.mindustry.world.StaticTree", "io.anuke.mindustry.world.Tile", "io.anuke.mindustry.world.WorldContext", "io.anuke.mindustry.world.blocks.Attributes", "io.anuke.mindustry.world.blocks.Autotiler", "io.anuke.mindustry.world.blocks.Autotiler$AutotilerHolder", "io.anuke.mindustry.world.blocks.BlockPart", "io.anuke.mindustry.world.blocks.BuildBlock", "io.anuke.mindustry.world.blocks.BuildBlock$BuildEntity", "io.anuke.mindustry.world.blocks.DoubleOverlayFloor", "io.anuke.mindustry.world.blocks.Floor", "io.anuke.mindustry.world.blocks.ItemSelection", "io.anuke.mindustry.world.blocks.LiquidBlock", "io.anuke.mindustry.world.blocks.OreBlock", "io.anuke.mindustry.world.blocks.OverlayFloor", "io.anuke.mindustry.world.blocks.PowerBlock", "io.anuke.mindustry.world.blocks.RespawnBlock", "io.anuke.mindustry.world.blocks.Rock", "io.anuke.mindustry.world.blocks.StaticWall", "io.anuke.mindustry.world.blocks.TreeBlock", "io.anuke.mindustry.world.blocks.defense.DeflectorWall", "io.anuke.mindustry.world.blocks.defense.DeflectorWall$DeflectorEntity", "io.anuke.mindustry.world.blocks.defense.Door", "io.anuke.mindustry.world.blocks.defense.Door$DoorEntity", "io.anuke.mindustry.world.blocks.defense.ForceProjector", "io.anuke.mindustry.world.blocks.defense.ForceProjector$ForceEntity", "io.anuke.mindustry.world.blocks.defense.ForceProjector$ShieldEntity", "io.anuke.mindustry.world.blocks.defense.MendProjector", "io.anuke.mindustry.world.blocks.defense.MendProjector$MendEntity", "io.anuke.mindustry.world.blocks.defense.OverdriveProjector", "io.anuke.mindustry.world.blocks.defense.OverdriveProjector$OverdriveEntity", "io.anuke.mindustry.world.blocks.defense.ShockMine", "io.anuke.mindustry.world.blocks.defense.SurgeWall", "io.anuke.mindustry.world.blocks.defense.Wall", "io.anuke.mindustry.world.blocks.defense.turrets.ArtilleryTurret", "io.anuke.mindustry.world.blocks.defense.turrets.BurstTurret", "io.anuke.mindustry.world.blocks.defense.turrets.ChargeTurret", "io.anuke.mindustry.world.blocks.defense.turrets.ChargeTurret$LaserTurretEntity", "io.anuke.mindustry.world.blocks.defense.turrets.CooledTurret", "io.anuke.mindustry.world.blocks.defense.turrets.DoubleTurret", "io.anuke.mindustry.world.blocks.defense.turrets.ItemTurret", "io.anuke.mindustry.world.blocks.defense.turrets.ItemTurret$ItemEntry", "io.anuke.mindustry.world.blocks.defense.turrets.ItemTurret$ItemTurretEntity", "io.anuke.mindustry.world.blocks.defense.turrets.LaserTurret", "io.anuke.mindustry.world.blocks.defense.turrets.LaserTurret$LaserTurretEntity", "io.anuke.mindustry.world.blocks.defense.turrets.LiquidTurret", "io.anuke.mindustry.world.blocks.defense.turrets.PowerTurret", "io.anuke.mindustry.world.blocks.defense.turrets.Turret", "io.anuke.mindustry.world.blocks.defense.turrets.Turret$AmmoEntry", "io.anuke.mindustry.world.blocks.defense.turrets.Turret$TurretEntity", "io.anuke.mindustry.world.blocks.distribution.ArmoredConveyor", "io.anuke.mindustry.world.blocks.distribution.BufferedItemBridge", "io.anuke.mindustry.world.blocks.distribution.BufferedItemBridge$BufferedItemBridgeEntity", "io.anuke.mindustry.world.blocks.distribution.Conveyor", "io.anuke.mindustry.world.blocks.distribution.Conveyor$ConveyorEntity", "io.anuke.mindustry.world.blocks.distribution.Conveyor$ItemPos", "io.anuke.mindustry.world.blocks.distribution.ExtendingItemBridge", "io.anuke.mindustry.world.blocks.distribution.ItemBridge", "io.anuke.mindustry.world.blocks.distribution.ItemBridge$ItemBridgeEntity", "io.anuke.mindustry.world.blocks.distribution.Junction", "io.anuke.mindustry.world.blocks.distribution.Junction$JunctionEntity", "io.anuke.mindustry.world.blocks.distribution.MassDriver", "io.anuke.mindustry.world.blocks.distribution.MassDriver$DriverBulletData", "io.anuke.mindustry.world.blocks.distribution.MassDriver$DriverState", "io.anuke.mindustry.world.blocks.distribution.MassDriver$MassDriverEntity", "io.anuke.mindustry.world.blocks.distribution.OverflowGate", "io.anuke.mindustry.world.blocks.distribution.OverflowGate$OverflowGateEntity", "io.anuke.mindustry.world.blocks.distribution.Router", "io.anuke.mindustry.world.blocks.distribution.Router$RouterEntity", "io.anuke.mindustry.world.blocks.distribution.Sorter", "io.anuke.mindustry.world.blocks.distribution.Sorter$SorterEntity", "io.anuke.mindustry.world.blocks.liquid.ArmoredConduit", "io.anuke.mindustry.world.blocks.liquid.Conduit", "io.anuke.mindustry.world.blocks.liquid.Conduit$ConduitEntity", "io.anuke.mindustry.world.blocks.liquid.LiquidBridge", "io.anuke.mindustry.world.blocks.liquid.LiquidExtendingBridge", "io.anuke.mindustry.world.blocks.liquid.LiquidJunction", "io.anuke.mindustry.world.blocks.liquid.LiquidOverflowGate", "io.anuke.mindustry.world.blocks.liquid.LiquidRouter", "io.anuke.mindustry.world.blocks.liquid.LiquidTank", "io.anuke.mindustry.world.blocks.logic.LogicBlock", "io.anuke.mindustry.world.blocks.logic.MessageBlock", "io.anuke.mindustry.world.blocks.logic.MessageBlock$MessageBlockEntity", "io.anuke.mindustry.world.blocks.power.Battery", "io.anuke.mindustry.world.blocks.power.BurnerGenerator", "io.anuke.mindustry.world.blocks.power.ConditionalConsumePower", "io.anuke.mindustry.world.blocks.power.DecayGenerator", "io.anuke.mindustry.world.blocks.power.ImpactReactor", "io.anuke.mindustry.world.blocks.power.ImpactReactor$FusionReactorEntity", "io.anuke.mindustry.world.blocks.power.ItemLiquidGenerator", "io.anuke.mindustry.world.blocks.power.ItemLiquidGenerator$ItemLiquidGeneratorEntity", "io.anuke.mindustry.world.blocks.power.LightBlock", "io.anuke.mindustry.world.blocks.power.LightBlock$LightEntity", "io.anuke.mindustry.world.blocks.power.NuclearReactor", "io.anuke.mindustry.world.blocks.power.NuclearReactor$NuclearReactorEntity", "io.anuke.mindustry.world.blocks.power.PowerDiode", "io.anuke.mindustry.world.blocks.power.PowerDistributor", "io.anuke.mindustry.world.blocks.power.PowerGenerator", "io.anuke.mindustry.world.blocks.power.PowerGenerator$GeneratorEntity", "io.anuke.mindustry.world.blocks.power.PowerGraph", "io.anuke.mindustry.world.blocks.power.PowerNode", "io.anuke.mindustry.world.blocks.power.SingleTypeGenerator", "io.anuke.mindustry.world.blocks.power.SolarGenerator", "io.anuke.mindustry.world.blocks.power.ThermalGenerator", "io.anuke.mindustry.world.blocks.production.Cultivator", "io.anuke.mindustry.world.blocks.production.Cultivator$CultivatorEntity", "io.anuke.mindustry.world.blocks.production.Drill", "io.anuke.mindustry.world.blocks.production.Drill$DrillEntity", "io.anuke.mindustry.world.blocks.production.Fracker", "io.anuke.mindustry.world.blocks.production.Fracker$FrackerEntity", "io.anuke.mindustry.world.blocks.production.GenericCrafter", "io.anuke.mindustry.world.blocks.production.GenericCrafter$GenericCrafterEntity", "io.anuke.mindustry.world.blocks.production.GenericSmelter", "io.anuke.mindustry.world.blocks.production.Incinerator", "io.anuke.mindustry.world.blocks.production.Incinerator$IncineratorEntity", "io.anuke.mindustry.world.blocks.production.LiquidConverter", "io.anuke.mindustry.world.blocks.production.Pump", "io.anuke.mindustry.world.blocks.production.Separator", "io.anuke.mindustry.world.blocks.production.SolidPump", "io.anuke.mindustry.world.blocks.production.SolidPump$SolidPumpEntity", "io.anuke.mindustry.world.blocks.sandbox.ItemSource", "io.anuke.mindustry.world.blocks.sandbox.ItemSource$ItemSourceEntity", "io.anuke.mindustry.world.blocks.sandbox.ItemVoid", "io.anuke.mindustry.world.blocks.sandbox.LiquidSource", "io.anuke.mindustry.world.blocks.sandbox.LiquidSource$LiquidSourceEntity", "io.anuke.mindustry.world.blocks.sandbox.PowerSource", "io.anuke.mindustry.world.blocks.sandbox.PowerVoid", "io.anuke.mindustry.world.blocks.storage.CoreBlock", "io.anuke.mindustry.world.blocks.storage.CoreBlock$CoreEntity", "io.anuke.mindustry.world.blocks.storage.LaunchPad", "io.anuke.mindustry.world.blocks.storage.StorageBlock", "io.anuke.mindustry.world.blocks.storage.StorageBlock$StorageBlockEntity", "io.anuke.mindustry.world.blocks.storage.Unloader", "io.anuke.mindustry.world.blocks.storage.Unloader$UnloaderEntity", "io.anuke.mindustry.world.blocks.storage.Vault", "io.anuke.mindustry.world.blocks.units.CommandCenter", "io.anuke.mindustry.world.blocks.units.CommandCenter$CommandCenterEntity", "io.anuke.mindustry.world.blocks.units.MechPad", "io.anuke.mindustry.world.blocks.units.MechPad$MechFactoryEntity", "io.anuke.mindustry.world.blocks.units.RallyPoint", "io.anuke.mindustry.world.blocks.units.RepairPoint", "io.anuke.mindustry.world.blocks.units.RepairPoint$RepairPointEntity", "io.anuke.mindustry.world.blocks.units.UnitFactory", "io.anuke.mindustry.world.blocks.units.UnitFactory$UnitFactoryEntity", "io.anuke.mindustry.world.consumers.Consume", "io.anuke.mindustry.world.consumers.ConsumeItemFilter", "io.anuke.mindustry.world.consumers.ConsumeItems", "io.anuke.mindustry.world.consumers.ConsumeLiquid", "io.anuke.mindustry.world.consumers.ConsumeLiquidBase", "io.anuke.mindustry.world.consumers.ConsumeLiquidFilter", "io.anuke.mindustry.world.consumers.ConsumePower", "io.anuke.mindustry.world.consumers.ConsumeType", "io.anuke.mindustry.world.consumers.Consumers", "io.anuke.mindustry.world.meta.Attribute", "io.anuke.mindustry.world.meta.BlockBars", "io.anuke.mindustry.world.meta.BlockFlag", "io.anuke.mindustry.world.meta.BlockGroup", "io.anuke.mindustry.world.meta.BlockStat", "io.anuke.mindustry.world.meta.BlockStats", "io.anuke.mindustry.world.meta.BuildVisibility", "io.anuke.mindustry.world.meta.PowerType", "io.anuke.mindustry.world.meta.Producers", "io.anuke.mindustry.world.meta.StatCategory", "io.anuke.mindustry.world.meta.StatUnit", "io.anuke.mindustry.world.meta.StatValue", "io.anuke.mindustry.world.meta.values.AmmoListValue", "io.anuke.mindustry.world.meta.values.BooleanValue", "io.anuke.mindustry.world.meta.values.BoosterListValue", "io.anuke.mindustry.world.meta.values.ItemFilterValue", "io.anuke.mindustry.world.meta.values.ItemListValue", "io.anuke.mindustry.world.meta.values.LiquidFilterValue", "io.anuke.mindustry.world.meta.values.LiquidValue", "io.anuke.mindustry.world.meta.values.NumberValue", "io.anuke.mindustry.world.meta.values.StringValue", "io.anuke.mindustry.world.modules.BlockModule", "io.anuke.mindustry.world.modules.ConsumeModule", "io.anuke.mindustry.world.modules.ItemModule", "io.anuke.mindustry.world.modules.ItemModule$ItemCalculator", "io.anuke.mindustry.world.modules.ItemModule$ItemConsumer", "io.anuke.mindustry.world.modules.LiquidModule", "io.anuke.mindustry.world.modules.LiquidModule$LiquidCalculator", "io.anuke.mindustry.world.modules.LiquidModule$LiquidConsumer", "io.anuke.mindustry.world.modules.PowerModule", "io.anuke.mindustry.world.producers.Produce", "io.anuke.mindustry.world.producers.ProduceItem", "java.io.PrintStream", "java.lang.Object", "java.lang.Runnable", "java.lang.String", "java.lang.System"); } \ No newline at end of file diff --git a/core/src/io/anuke/mindustry/mod/ContentParser.java b/core/src/io/anuke/mindustry/mod/ContentParser.java index 09a030e1e6..1b1aa64c1d 100644 --- a/core/src/io/anuke/mindustry/mod/ContentParser.java +++ b/core/src/io/anuke/mindustry/mod/ContentParser.java @@ -138,26 +138,20 @@ public class ContentParser{ } //try to parse "item/amount" syntax - try{ - if(type == ItemStack.class && jsonData.isString() && jsonData.asString().contains("/")){ - String[] split = jsonData.asString().split("/"); + if(type == ItemStack.class && jsonData.isString() && jsonData.asString().contains("/")){ + String[] split = jsonData.asString().split("/"); - return (T)fromJson(ItemStack.class, "{item: " + split[0] + ", amount: " + split[1] + "}"); - } - }catch(Throwable ignored){ + return (T)fromJson(ItemStack.class, "{item: " + split[0] + ", amount: " + split[1] + "}"); } //try to parse "liquid/amount" syntax - try{ - if(jsonData.isString() && jsonData.asString().contains("/")){ - String[] split = jsonData.asString().split("/"); - if(type == LiquidStack.class){ - return (T)fromJson(LiquidStack.class, "{liquid: " + split[0] + ", amount: " + split[1] + "}"); - }else if(type == ConsumeLiquid.class){ - return (T)fromJson(ConsumeLiquid.class, "{liquid: " + split[0] + ", amount: " + split[1] + "}"); - } + if(jsonData.isString() && jsonData.asString().contains("/")){ + String[] split = jsonData.asString().split("/"); + if(type == LiquidStack.class){ + return (T)fromJson(LiquidStack.class, "{liquid: " + split[0] + ", amount: " + split[1] + "}"); + }else if(type == ConsumeLiquid.class){ + return (T)fromJson(ConsumeLiquid.class, "{liquid: " + split[0] + ", amount: " + split[1] + "}"); } - }catch(Throwable ignored){ } if(Content.class.isAssignableFrom(type)){ @@ -168,7 +162,7 @@ public class ContentParser{ T two = (T)Vars.content.getByName(ctype, jsonData.asString()); if(two != null) return two; - throw new IllegalArgumentException("\"" + jsonData.name + "\": No " + ctype + " found with name '" + jsonData.asString() + "'."); + throw new IllegalArgumentException("\"" + jsonData.name + "\": No " + ctype + " found with name '" + jsonData.asString() + "'.\nMake sure '" + jsonData.asString() + "' is spelled correctly, and that it really exists!\nThis may also occur because its file failed to parse."); } } @@ -442,7 +436,10 @@ public class ContentParser{ public void markError(Content content, LoadedMod mod, FileHandle file, Throwable error){ content.minfo.mod = mod; content.minfo.sourceFile = file; - content.minfo.error = Strings.parseException(error, true); + content.minfo.error = makeError(error, file); + if(mod != null){ + mod.erroredContent.add(content); + } } public void markError(Content content, Throwable error){ @@ -451,6 +448,24 @@ public class ContentParser{ } } + private String makeError(Throwable t, FileHandle file){ + StringBuilder builder = new StringBuilder(); + builder.append("[lightgray]").append("File: ").append(file.name()).append("[]\n\n"); + + if(t.getMessage() != null && t instanceof JsonParseException){ + builder.append("[accent][[JsonParse][] ").append(":\n").append(t.getMessage()); + }else{ + Array causes = Strings.getCauses(t); + for(Throwable e : causes){ + builder.append("[accent][[").append(e.getClass().getSimpleName().replace("Exception", "")) + .append("][] ") + .append(e.getMessage() != null ? + e.getMessage().replace("io.anuke.mindustry.", "").replace("io.anuke.arc.", "") : "").append("\n"); + } + } + return builder.toString(); + } + private T locate(ContentType type, String name){ T first = Vars.content.getByName(type, name); //try vanilla replacement return first != null ? first : Vars.content.getByName(type, currentMod.name + "-" + name); diff --git a/core/src/io/anuke/mindustry/mod/Mods.java b/core/src/io/anuke/mindustry/mod/Mods.java index 7f2ef573f6..e7067f850d 100644 --- a/core/src/io/anuke/mindustry/mod/Mods.java +++ b/core/src/io/anuke/mindustry/mod/Mods.java @@ -9,19 +9,22 @@ import io.anuke.arc.graphics.*; import io.anuke.arc.graphics.Texture.*; import io.anuke.arc.graphics.g2d.*; import io.anuke.arc.graphics.g2d.TextureAtlas.*; -import io.anuke.arc.util.ArcAnnotate.*; +import io.anuke.arc.scene.ui.*; import io.anuke.arc.util.*; +import io.anuke.arc.util.ArcAnnotate.*; import io.anuke.arc.util.io.*; import io.anuke.arc.util.serialization.*; import io.anuke.arc.util.serialization.Jval.*; import io.anuke.mindustry.core.*; import io.anuke.mindustry.ctype.*; +import io.anuke.mindustry.ctype.ContentType; import io.anuke.mindustry.game.EventType.*; import io.anuke.mindustry.gen.*; import io.anuke.mindustry.graphics.*; import io.anuke.mindustry.graphics.MultiPacker.*; import io.anuke.mindustry.plugin.*; import io.anuke.mindustry.type.*; +import io.anuke.mindustry.ui.*; import java.io.*; import java.net.*; @@ -42,6 +45,11 @@ public class Mods implements Loadable{ private ObjectMap, ModMeta> metas = new ObjectMap<>(); private boolean requiresReload; + public Mods(){ + Events.on(ClientLoadEvent.class, e -> Core.app.post(this::checkWarnings)); + Events.on(ContentReloadEvent.class, e -> Core.app.post(this::checkWarnings)); + } + /** Returns a file named 'config.json' in a special folder for the specified plugin. * Call this in init(). */ public FileHandle getConfig(Mod mod){ @@ -260,7 +268,7 @@ public class Mods implements Loadable{ mod.state = !mod.isSupported() ? ModState.unsupported : mod.hasUnmetDependencies() ? ModState.missingDependencies : - !mod.enabled() /*TODO check disabled state!*/ ? ModState.disabled : + !mod.shouldBeEnabled() ? ModState.disabled : ModState.enabled; } } @@ -333,13 +341,68 @@ public class Mods implements Loadable{ try{ PropertiesUtils.load(bundle.getProperties(), file.reader()); }catch(Exception e){ - throw new RuntimeException("Error loading bundle: " + file + "/" + locale, e); + Log.err("Error loading bundle: " + file + "/" + locale, e); } } bundle = bundle.getParent(); } } + /** Check all warnings related to content and show relevant dialogs. Client only. */ + private void checkWarnings(){ + //show 'scripts have errored' info + if(scripts != null && scripts.hasErrored()){ + Core.settings.getBoolOnce("scripts-errored2", () -> ui.showErrorMessage("$mod.scripts.unsupported")); + } + + //show list of errored content + if(mods.contains(LoadedMod::hasContentErrors)){ + ui.loadfrag.hide(); + new Dialog(""){{ + + setFillParent(true); + cont.margin(15); + cont.add("$error.title"); + cont.row(); + cont.addImage().width(300f).pad(2).colspan(2).height(4f).color(Color.scarlet); + cont.row(); + cont.add("$mod.errors").wrap().growX().center().get().setAlignment(Align.center); + cont.row(); + cont.pane(p -> { + mods.each(m -> m.enabled() && m.hasContentErrors(), m -> { + p.add(m.name).color(Pal.accent).left(); + p.row(); + p.addImage().fillX().pad(4).color(Pal.accent); + p.row(); + p.table(d -> { + d.left().marginLeft(15f); + for(Content c : m.erroredContent){ + d.add(c.minfo.sourceFile.nameWithoutExtension()).left().padRight(10); + d.addImageTextButton("$details", Icon.arrowDownSmall, Styles.transt, () -> { + new Dialog(""){{ + setFillParent(true); + cont.pane(e -> e.add(c.minfo.error)).grow(); + cont.row(); + cont.addImageTextButton("$ok", Icon.backSmall, this::hide).size(240f, 60f); + }}.show(); + }).size(190f, 50f).left().marginLeft(6); + d.row(); + } + }).left(); + p.row(); + }); + }); + + cont.row(); + cont.addButton("$ok", this::hide).size(300, 50); + }}.show(); + } + } + + public boolean hasContentErrors(){ + return mods.contains(LoadedMod::hasContentErrors); + } + /** Reloads all mod content. How does this even work? I refuse to believe that it functions correctly.*/ public void reloadContent(){ //epic memory leak @@ -369,10 +432,6 @@ public class Mods implements Loadable{ requiresReload = false; Events.fire(new ContentReloadEvent()); - - if(scripts != null && scripts.hasErrored()){ - Core.app.post(() -> Core.settings.getBoolOnce("scripts-errored", () -> ui.showErrorMessage("$mod.scripts.unsupported"))); - } } /** This must be run on the main thread! */ @@ -396,7 +455,6 @@ public class Mods implements Loadable{ Core.app.post(() -> { Log.err("Error loading script {0} for mod {1}.", file.name(), mod.meta.name); e.printStackTrace(); - //if(!headless) ui.showException(e); }); break; } @@ -461,8 +519,10 @@ public class Mods implements Loadable{ }catch(Throwable e){ if(current != content.getLastAdded() && content.getLastAdded() != null){ parser.markError(content.getLastAdded(), l.mod, l.file, e); + }else{ + ErrorContent error = new ErrorContent(); + parser.markError(error, l.mod, l.file, e); } - //throw new RuntimeException("Failed to parse content file '" + l.file + "' for mod '" + l.mod.meta.name + "'.", e); } } @@ -599,6 +659,8 @@ public class Mods implements Loadable{ public Array missingDependencies = new Array<>(); /** Script files to run. */ public Array scripts = new Array<>(); + /** Content with intialization code. */ + public ObjectSet erroredContent = new ObjectSet<>(); /** Current state of this mod. */ public ModState state = ModState.disabled; @@ -611,13 +673,21 @@ public class Mods implements Loadable{ } public boolean enabled(){ - return state == ModState.enabled; + return state == ModState.enabled || state == ModState.contentErrors; + } + + public boolean shouldBeEnabled(){ + return Core.settings.getBool("mod-" + name + "-enabled", true); } public boolean hasUnmetDependencies(){ return !missingDependencies.isEmpty(); } + public boolean hasContentErrors(){ + return !erroredContent.isEmpty(); + } + /** @return whether this mod is supported by the game verison */ public boolean isSupported(){ if(Version.build <= 0 || meta.minGameVersion == null) return true; @@ -711,9 +781,9 @@ public class Mods implements Loadable{ public enum ModState{ enabled, - disabled, + contentErrors, missingDependencies, unsupported, - contentErrors + disabled, } } diff --git a/core/src/io/anuke/mindustry/type/ErrorContent.java b/core/src/io/anuke/mindustry/type/ErrorContent.java new file mode 100644 index 0000000000..91c52207f8 --- /dev/null +++ b/core/src/io/anuke/mindustry/type/ErrorContent.java @@ -0,0 +1,12 @@ +package io.anuke.mindustry.type; + +import io.anuke.mindustry.ctype.*; +import io.anuke.mindustry.ctype.ContentType; + +/** Represents a blank type of content that has an error. Replaces anything that failed to parse. */ +public class ErrorContent extends Content{ + @Override + public ContentType getContentType(){ + return ContentType.error; + } +} diff --git a/core/src/io/anuke/mindustry/type/Item.java b/core/src/io/anuke/mindustry/type/Item.java index 597eb468b5..01cff82cd2 100644 --- a/core/src/io/anuke/mindustry/type/Item.java +++ b/core/src/io/anuke/mindustry/type/Item.java @@ -4,6 +4,7 @@ import io.anuke.arc.collection.*; import io.anuke.arc.graphics.*; import io.anuke.arc.scene.ui.layout.*; import io.anuke.mindustry.ctype.*; +import io.anuke.mindustry.ctype.ContentType; import io.anuke.mindustry.ui.*; import io.anuke.mindustry.world.blocks.*; diff --git a/core/src/io/anuke/mindustry/type/Liquid.java b/core/src/io/anuke/mindustry/type/Liquid.java index 8ed87e7941..0b896a389c 100644 --- a/core/src/io/anuke/mindustry/type/Liquid.java +++ b/core/src/io/anuke/mindustry/type/Liquid.java @@ -5,6 +5,7 @@ import io.anuke.arc.scene.ui.layout.*; import io.anuke.arc.util.ArcAnnotate.*; import io.anuke.mindustry.content.*; import io.anuke.mindustry.ctype.*; +import io.anuke.mindustry.ctype.ContentType; import io.anuke.mindustry.ui.*; public class Liquid extends UnlockableContent{ diff --git a/core/src/io/anuke/mindustry/type/Mech.java b/core/src/io/anuke/mindustry/type/Mech.java index 7a5de5ae2d..6172827ee8 100644 --- a/core/src/io/anuke/mindustry/type/Mech.java +++ b/core/src/io/anuke/mindustry/type/Mech.java @@ -5,6 +5,7 @@ import io.anuke.arc.graphics.Color; import io.anuke.arc.graphics.g2d.TextureRegion; import io.anuke.arc.scene.ui.layout.Table; import io.anuke.arc.util.ArcAnnotate.*; +import io.anuke.mindustry.ctype.ContentType; import io.anuke.mindustry.entities.type.Player; import io.anuke.mindustry.ctype.UnlockableContent; import io.anuke.mindustry.graphics.Pal; diff --git a/core/src/io/anuke/mindustry/type/StatusEffect.java b/core/src/io/anuke/mindustry/type/StatusEffect.java index 482f0f03f1..34d7a9cb77 100644 --- a/core/src/io/anuke/mindustry/type/StatusEffect.java +++ b/core/src/io/anuke/mindustry/type/StatusEffect.java @@ -6,6 +6,7 @@ import io.anuke.arc.math.*; import io.anuke.arc.util.*; import io.anuke.mindustry.content.*; import io.anuke.mindustry.ctype.*; +import io.anuke.mindustry.ctype.ContentType; import io.anuke.mindustry.entities.*; import io.anuke.mindustry.entities.Effects.*; import io.anuke.mindustry.entities.type.*; diff --git a/core/src/io/anuke/mindustry/type/TypeID.java b/core/src/io/anuke/mindustry/type/TypeID.java index bd190a7a63..5ab6c1f3f5 100644 --- a/core/src/io/anuke/mindustry/type/TypeID.java +++ b/core/src/io/anuke/mindustry/type/TypeID.java @@ -2,6 +2,7 @@ package io.anuke.mindustry.type; import io.anuke.arc.func.*; import io.anuke.mindustry.ctype.*; +import io.anuke.mindustry.ctype.ContentType; import io.anuke.mindustry.entities.traits.*; public class TypeID extends MappableContent{ diff --git a/core/src/io/anuke/mindustry/type/UnitType.java b/core/src/io/anuke/mindustry/type/UnitType.java index 1a7335b032..85a6882e86 100644 --- a/core/src/io/anuke/mindustry/type/UnitType.java +++ b/core/src/io/anuke/mindustry/type/UnitType.java @@ -8,6 +8,7 @@ import io.anuke.arc.graphics.g2d.*; import io.anuke.arc.scene.ui.layout.*; import io.anuke.arc.util.ArcAnnotate.*; import io.anuke.mindustry.content.*; +import io.anuke.mindustry.ctype.ContentType; import io.anuke.mindustry.ctype.UnlockableContent; import io.anuke.mindustry.entities.type.*; import io.anuke.mindustry.game.*; diff --git a/core/src/io/anuke/mindustry/type/WeatherEvent.java b/core/src/io/anuke/mindustry/type/WeatherEvent.java index 29b6ca0855..4f7eba597c 100644 --- a/core/src/io/anuke/mindustry/type/WeatherEvent.java +++ b/core/src/io/anuke/mindustry/type/WeatherEvent.java @@ -1,6 +1,7 @@ package io.anuke.mindustry.type; import io.anuke.mindustry.ctype.Content; +import io.anuke.mindustry.ctype.ContentType; //currently unimplemented, see trello for implementation plans public class WeatherEvent extends Content{ diff --git a/core/src/io/anuke/mindustry/type/Zone.java b/core/src/io/anuke/mindustry/type/Zone.java index 12686bb3da..cb047f91b0 100644 --- a/core/src/io/anuke/mindustry/type/Zone.java +++ b/core/src/io/anuke/mindustry/type/Zone.java @@ -7,6 +7,7 @@ import io.anuke.arc.graphics.g2d.*; import io.anuke.arc.scene.ui.layout.*; import io.anuke.arc.util.ArcAnnotate.*; import io.anuke.mindustry.content.*; +import io.anuke.mindustry.ctype.ContentType; import io.anuke.mindustry.ctype.UnlockableContent; import io.anuke.mindustry.game.EventType.*; import io.anuke.mindustry.game.*; diff --git a/core/src/io/anuke/mindustry/ui/Styles.java b/core/src/io/anuke/mindustry/ui/Styles.java index af519a4b14..1f7be8f08c 100644 --- a/core/src/io/anuke/mindustry/ui/Styles.java +++ b/core/src/io/anuke/mindustry/ui/Styles.java @@ -25,7 +25,7 @@ import static io.anuke.mindustry.gen.Tex.*; public class Styles{ public static Drawable black, black9, black8, black6, black3, none, flatDown, flatOver; public static ButtonStyle defaultb, waveb; - public static TextButtonStyle defaultt, squaret, nodet, cleart, discordt, infot, clearPartialt, clearTogglet, clearToggleMenut, togglet; + public static TextButtonStyle defaultt, squaret, nodet, cleart, discordt, infot, clearPartialt, clearTogglet, clearToggleMenut, togglet, transt; public static ImageButtonStyle defaulti, nodei, righti, emptyi, emptytogglei, selecti, cleari, clearFulli, clearPartiali, clearPartial2i, clearTogglei, clearTransi, clearToggleTransi, clearTogglePartiali; public static ScrollPaneStyle defaultPane, horizontalPane, smallPane; public static KeybindDialogStyle defaultKeybindDialog; @@ -110,6 +110,14 @@ public class Styles{ fontColor = Color.white; disabledFontColor = Color.gray; }}; + transt = new TextButtonStyle(){{ + down = flatDown; + up = none; + over = flatOver; + font = Fonts.def; + fontColor = Color.white; + disabledFontColor = Color.gray; + }}; clearTogglet = new TextButtonStyle(){{ font = Fonts.def; fontColor = Color.white; diff --git a/core/src/io/anuke/mindustry/ui/dialogs/DatabaseDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/DatabaseDialog.java index 65adb85efa..406665f431 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/DatabaseDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/DatabaseDialog.java @@ -10,9 +10,9 @@ import io.anuke.arc.util.*; import io.anuke.mindustry.*; import io.anuke.mindustry.core.GameState.*; import io.anuke.mindustry.ctype.*; +import io.anuke.mindustry.ctype.ContentType; import io.anuke.mindustry.gen.*; import io.anuke.mindustry.graphics.*; -import io.anuke.mindustry.type.*; import io.anuke.mindustry.ui.*; public class DatabaseDialog extends FloatingDialog{ diff --git a/core/src/io/anuke/mindustry/ui/dialogs/ModsDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/ModsDialog.java index a2e1f8b168..f18c7733cf 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/ModsDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/ModsDialog.java @@ -165,6 +165,9 @@ public class ModsDialog extends FloatingDialog{ }else if(mod.hasUnmetDependencies()){ t.labelWrap(Core.bundle.format("mod.missingdependencies", mod.missingDependencies.toString(", "))).growX(); t.row(); + }else if(mod.hasContentErrors()){ + t.labelWrap("$mod.erroredcontent").growX(); + t.row(); } }).width(mobile ? 430f : 500f); table.row(); diff --git a/core/src/io/anuke/mindustry/ui/fragments/HudFragment.java b/core/src/io/anuke/mindustry/ui/fragments/HudFragment.java index b2c60deca9..8b05c07d5a 100644 --- a/core/src/io/anuke/mindustry/ui/fragments/HudFragment.java +++ b/core/src/io/anuke/mindustry/ui/fragments/HudFragment.java @@ -17,6 +17,7 @@ import io.anuke.arc.scene.ui.ImageButton.*; import io.anuke.arc.scene.ui.layout.*; import io.anuke.arc.util.*; import io.anuke.mindustry.core.GameState.*; +import io.anuke.mindustry.ctype.ContentType; import io.anuke.mindustry.ctype.UnlockableContent; import io.anuke.mindustry.entities.*; import io.anuke.mindustry.entities.type.*; diff --git a/core/src/io/anuke/mindustry/ui/fragments/MenuFragment.java b/core/src/io/anuke/mindustry/ui/fragments/MenuFragment.java index b18be4b27e..abf313183b 100644 --- a/core/src/io/anuke/mindustry/ui/fragments/MenuFragment.java +++ b/core/src/io/anuke/mindustry/ui/fragments/MenuFragment.java @@ -88,11 +88,11 @@ public class MenuFragment extends Fragment{ container.defaults().size(size).pad(5).padTop(4f); MobileButton - play = new MobileButton(Icon.play2, "$campaign", ui.deploy::show), - custom = new MobileButton(Icon.playCustom, "$customgame", ui.custom::show), - maps = new MobileButton(Icon.load, "$loadgame", ui.load::show), - join = new MobileButton(Icon.add, "$joingame", ui.join::show), - editor = new MobileButton(Icon.editor, "$editor", ui.maps::show), + play = new MobileButton(Icon.play2, "$campaign", () -> checkPlay(ui.deploy::show)), + custom = new MobileButton(Icon.playCustom, "$customgame", () -> checkPlay(ui.custom::show)), + maps = new MobileButton(Icon.load, "$loadgame", () -> checkPlay(ui.load::show)), + join = new MobileButton(Icon.add, "$joingame", () -> checkPlay(ui.join::show)), + editor = new MobileButton(Icon.editor, "$editor", () -> checkPlay(ui.maps::show)), tools = new MobileButton(Icon.tools, "$settings", ui.settings::show), mods = new MobileButton(Icon.wiki, "$mods", ui.mods::show), donate = new MobileButton(Icon.link, "$website", () -> Core.net.openURI("https://anuke.itch.io/mindustry")), @@ -153,13 +153,13 @@ public class MenuFragment extends Fragment{ buttons(t, new Buttoni("$play", Icon.play2Small, - new Buttoni("$campaign", Icon.play2Small, ui.deploy::show), - new Buttoni("$joingame", Icon.addSmall, ui.join::show), - new Buttoni("$customgame", Icon.editorSmall, ui.custom::show), - new Buttoni("$loadgame", Icon.loadSmall, ui.load::show), - new Buttoni("$tutorial", Icon.infoSmall, control::playTutorial) + new Buttoni("$campaign", Icon.play2Small, () -> checkPlay(ui.deploy::show)), + new Buttoni("$joingame", Icon.addSmall, () -> checkPlay(ui.join::show)), + new Buttoni("$customgame", Icon.editorSmall, () -> checkPlay(ui.custom::show)), + new Buttoni("$loadgame", Icon.loadSmall, () -> checkPlay(ui.load::show)), + new Buttoni("$tutorial", Icon.infoSmall, () -> checkPlay(control::playTutorial)) ), - new Buttoni("$editor", Icon.editorSmall, ui.maps::show), steam ? new Buttoni("$workshop", Icon.saveSmall, platform::openWorkshop) : null, + new Buttoni("$editor", Icon.editorSmall, () -> checkPlay(ui.maps::show)), steam ? new Buttoni("$workshop", Icon.saveSmall, platform::openWorkshop) : null, new Buttoni(Core.bundle.get("mods") + "\n" + Core.bundle.get("mods.alpha"), Icon.wikiSmall, ui.mods::show), //not enough space for this button //new Buttoni("$schematics", Icon.pasteSmall, ui.schematics::show), @@ -180,6 +180,14 @@ public class MenuFragment extends Fragment{ }).width(width).growY(); } + private void checkPlay(Runnable run){ + if(!mods.hasContentErrors()){ + run.run(); + }else{ + ui.showInfo("$mod.noerrorplay"); + } + } + private void fadeInMenu(){ submenu.clearActions(); submenu.actions(Actions.alpha(1f, 0.15f, Interpolation.fade)); diff --git a/core/src/io/anuke/mindustry/world/Block.java b/core/src/io/anuke/mindustry/world/Block.java index e1f7e4763d..a6f7769d03 100644 --- a/core/src/io/anuke/mindustry/world/Block.java +++ b/core/src/io/anuke/mindustry/world/Block.java @@ -18,6 +18,7 @@ import io.anuke.arc.util.*; import io.anuke.arc.util.ArcAnnotate.*; import io.anuke.arc.util.pooling.*; import io.anuke.mindustry.ctype.*; +import io.anuke.mindustry.ctype.ContentType; import io.anuke.mindustry.entities.*; import io.anuke.mindustry.entities.effect.*; import io.anuke.mindustry.entities.traits.BuilderTrait.*; diff --git a/core/src/io/anuke/mindustry/world/blocks/units/MechPad.java b/core/src/io/anuke/mindustry/world/blocks/units/MechPad.java index 594ec7b154..54bc28fb03 100644 --- a/core/src/io/anuke/mindustry/world/blocks/units/MechPad.java +++ b/core/src/io/anuke/mindustry/world/blocks/units/MechPad.java @@ -47,7 +47,7 @@ public class MechPad extends Block{ @Remote(targets = Loc.both, called = Loc.server) public static void onMechFactoryTap(Player player, Tile tile){ - if(player == null || !(tile.block() instanceof MechPad) || !checkValidTap(tile, player)) return; + if(player == null || tile == null || !(tile.block() instanceof MechPad) || !checkValidTap(tile, player)) return; MechFactoryEntity entity = tile.ent(); diff --git a/gradle.properties b/gradle.properties index 212385a749..84b12d9235 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,3 @@ org.gradle.daemon=true org.gradle.jvmargs=-Xms256m -Xmx1024m -archash=190918590e8401b1686ecb9167e3c2a9e77eafaa +archash=b4f2a66518d2582ea4275193dfee128b186df9b3 diff --git a/tests/src/test/java/ApplicationTests.java b/tests/src/test/java/ApplicationTests.java index 12409c364f..2e706644c2 100644 --- a/tests/src/test/java/ApplicationTests.java +++ b/tests/src/test/java/ApplicationTests.java @@ -16,7 +16,7 @@ import io.anuke.mindustry.game.Team; import io.anuke.mindustry.io.SaveIO; import io.anuke.mindustry.maps.Map; import io.anuke.mindustry.net.*; -import io.anuke.mindustry.type.ContentType; +import io.anuke.mindustry.ctype.ContentType; import io.anuke.mindustry.type.Item; import io.anuke.mindustry.world.*; import io.anuke.mindustry.world.blocks.BlockPart;