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