From 4dc55e5594125f1485c6c226fcef1067bd06377f Mon Sep 17 00:00:00 2001 From: David Held Date: Mon, 16 Sep 2019 16:00:06 -0700 Subject: [PATCH 01/15] Fixes bug which let phase conveyor operate with any non-zero power; now requires full power to work (#672) * Fixes bug which let phase conveyor operate with any non-zero power; now requires full power to work * Fixed normal bridge, deprecated method --- core/src/io/anuke/mindustry/plugin/Plugins.java | 2 +- .../world/blocks/distribution/ItemBridge.java | 11 ++--------- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/core/src/io/anuke/mindustry/plugin/Plugins.java b/core/src/io/anuke/mindustry/plugin/Plugins.java index dcd7d8501b..946ec00f4f 100644 --- a/core/src/io/anuke/mindustry/plugin/Plugins.java +++ b/core/src/io/anuke/mindustry/plugin/Plugins.java @@ -67,7 +67,7 @@ public class Plugins{ URLClassLoader classLoader = new URLClassLoader(new URL[]{jar.file().toURI().toURL()}, ClassLoader.getSystemClassLoader()); Class main = classLoader.loadClass(meta.main); metas.put(main, meta); - return new LoadedPlugin(jar, zip, (Plugin)main.newInstance(), meta); + return new LoadedPlugin(jar, zip, (Plugin)main.getDeclaredConstructor().newInstance(), meta); } /** Represents a plugin that has been loaded from a jar file.*/ diff --git a/core/src/io/anuke/mindustry/world/blocks/distribution/ItemBridge.java b/core/src/io/anuke/mindustry/world/blocks/distribution/ItemBridge.java index f0cac836d6..782d94fdda 100644 --- a/core/src/io/anuke/mindustry/world/blocks/distribution/ItemBridge.java +++ b/core/src/io/anuke/mindustry/world/blocks/distribution/ItemBridge.java @@ -24,7 +24,6 @@ public class ItemBridge extends Block{ protected int timerTransport = timers++; protected int range; protected float transportTime = 2f; - protected IntArray removals = new IntArray(); protected TextureRegion endRegion, bridgeRegion, arrowRegion; private static int lastPlaced = Pos.invalid; @@ -162,21 +161,15 @@ public class ItemBridge extends Block{ entity.time += entity.cycleSpeed * entity.delta(); entity.time2 += (entity.cycleSpeed - 1f) * entity.delta(); - removals.clear(); - IntSetIterator it = entity.incoming.iterator(); - while(it.hasNext){ int i = it.next(); Tile other = world.tile(i); if(!linkValid(tile, other, false)){ - removals.add(i); + it.remove(); } } - for(int j = 0; j < removals.size; j++) - entity.incoming.remove(removals.get(j)); - Tile other = world.tile(entity.link); if(!linkValid(tile, other)){ entity.link = Pos.invalid; @@ -184,7 +177,7 @@ public class ItemBridge extends Block{ entity.uptime = 0f; }else{ - if(entity.cons.valid()){ + if(entity.cons.valid() && (!hasPower || Mathf.isZero(1f - entity.power.satisfaction))){ entity.uptime = Mathf.lerpDelta(entity.uptime, 1f, 0.04f); }else{ entity.uptime = Mathf.lerpDelta(entity.uptime, 0f, 0.02f); From 669ce6dfbb38b96dd34df41d3086019b1d45a575 Mon Sep 17 00:00:00 2001 From: Anuken Date: Mon, 16 Sep 2019 23:25:09 -0400 Subject: [PATCH 02/15] launch pad fix --- .../mindustry/world/blocks/storage/LaunchPad.java | 5 +++-- .../io/anuke/mindustry/desktop/steam/SWorkshop.java | 12 ++++++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/core/src/io/anuke/mindustry/world/blocks/storage/LaunchPad.java b/core/src/io/anuke/mindustry/world/blocks/storage/LaunchPad.java index d432944ea4..0e8d0fc7db 100644 --- a/core/src/io/anuke/mindustry/world/blocks/storage/LaunchPad.java +++ b/core/src/io/anuke/mindustry/world/blocks/storage/LaunchPad.java @@ -77,8 +77,9 @@ public class LaunchPad extends StorageBlock{ for(Item item : Vars.content.items()){ Events.fire(Trigger.itemLaunch); Effects.effect(Fx.padlaunch, tile); - data.addItem(item, entity.items.get(item)); - entity.items.set(item, 0); + int used = Math.min(entity.items.get(item), itemCapacity); + data.addItem(item, used); + entity.items.remove(item, used); } } } diff --git a/desktop/src/io/anuke/mindustry/desktop/steam/SWorkshop.java b/desktop/src/io/anuke/mindustry/desktop/steam/SWorkshop.java index be4e1348d7..07273818d2 100644 --- a/desktop/src/io/anuke/mindustry/desktop/steam/SWorkshop.java +++ b/desktop/src/io/anuke/mindustry/desktop/steam/SWorkshop.java @@ -19,6 +19,18 @@ public class SWorkshop implements SteamUGCCallback{ private Map lastMap; + public SWorkshop(){ + int items = ugc.getNumSubscribedItems(); + SteamPublishedFileID[] ids = new SteamPublishedFileID[items]; + ugc.getSubscribedItems(ids); + for(int i = 0; i < items; i++){ + SteamPublishedFileID id = ids[i]; + ItemInstallInfo info = new ItemInstallInfo(); + ugc.getItemInstallInfo(id, info); + + } + } + public void publishMap(Map map){ FloatingDialog dialog = new FloatingDialog("$confirm"); dialog.setFillParent(false); From dbe7251c6b1a531e1115dc94f4d48cfa6721e81b Mon Sep 17 00:00:00 2001 From: Anuken Date: Tue, 17 Sep 2019 10:59:40 -0400 Subject: [PATCH 03/15] Update Statuses.java --- core/src/io/anuke/mindustry/entities/units/Statuses.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/src/io/anuke/mindustry/entities/units/Statuses.java b/core/src/io/anuke/mindustry/entities/units/Statuses.java index 62bcec4a2f..7a92a2c128 100644 --- a/core/src/io/anuke/mindustry/entities/units/Statuses.java +++ b/core/src/io/anuke/mindustry/entities/units/Statuses.java @@ -41,7 +41,7 @@ public class Statuses implements Saveable{ entry.effect.getTransition(unit, effect, entry.time, duration, globalResult); entry.time = globalResult.time; - if(globalResult.effect != entry.effect){ + if(globalResult.effect != entry.effect && globalResult.effect != null){ entry.effect = globalResult.effect; } @@ -127,6 +127,7 @@ public class Statuses implements Saveable{ public void writeSave(DataOutput stream) throws IOException{ stream.writeByte(statuses.size); for(StatusEntry entry : statuses){ + stream.writeByte(entry.effect.id); stream.writeFloat(entry.time); } From c357b97b3b052f27d5840039de65875982b22f2e Mon Sep 17 00:00:00 2001 From: Anuken Date: Tue, 17 Sep 2019 11:00:57 -0400 Subject: [PATCH 04/15] Update Control.java --- core/src/io/anuke/mindustry/core/Control.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/core/src/io/anuke/mindustry/core/Control.java b/core/src/io/anuke/mindustry/core/Control.java index 4a3d94a3b1..c954235c13 100644 --- a/core/src/io/anuke/mindustry/core/Control.java +++ b/core/src/io/anuke/mindustry/core/Control.java @@ -371,11 +371,13 @@ public class Control implements ApplicationListener, Loadable{ @Override public void update(){ + //TODO find out why this happens on Android + if(assets == null) return; + saves.update(); + //update and load any requested assets - if(assets != null){ - assets.update(); - } + assets.update(); input.updateController(); From 02736524bdfe40c486679a7b95640fd4f6d4edb2 Mon Sep 17 00:00:00 2001 From: Anuken Date: Tue, 17 Sep 2019 12:27:18 -0400 Subject: [PATCH 05/15] Update Tutorial.java --- core/src/io/anuke/mindustry/game/Tutorial.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/core/src/io/anuke/mindustry/game/Tutorial.java b/core/src/io/anuke/mindustry/game/Tutorial.java index d2534c151b..8eb8e9e054 100644 --- a/core/src/io/anuke/mindustry/game/Tutorial.java +++ b/core/src/io/anuke/mindustry/game/Tutorial.java @@ -187,7 +187,7 @@ public class Tutorial{ } },; - protected final String line = Core.bundle.has("tutorial." + name() + ".mobile") && mobile ? "tutorial." + name() + ".mobile" : "tutorial." + name(); + protected String line = ""; protected final Function text; protected Array sentences; protected final BooleanProvider done; @@ -203,7 +203,10 @@ public class Tutorial{ /** displayed tutorial stage text.*/ public String text(){ - if(sentences == null) this.sentences = Array.select(Core.bundle.get(line).split("\n"), s -> !s.isEmpty()); + if(sentences == null){ + this.line = Core.bundle.has("tutorial." + name() + ".mobile") && mobile ? "tutorial." + name() + ".mobile" : "tutorial." + name(); + this.sentences = Array.select(Core.bundle.get(line).split("\n"), s -> !s.isEmpty()); + } String line = sentences.get(control.tutorial.sentence); return line.contains("{") ? text.get(line) : line; } From ee412e199418dcf6e9d612d325e9ed9f3056d8e7 Mon Sep 17 00:00:00 2001 From: Anuken Date: Tue, 17 Sep 2019 17:39:20 -0400 Subject: [PATCH 06/15] passbackback --- .../io/anuke/mindustry/world/blocks/distribution/Router.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/src/io/anuke/mindustry/world/blocks/distribution/Router.java b/core/src/io/anuke/mindustry/world/blocks/distribution/Router.java index 382a5dd470..bd92126717 100644 --- a/core/src/io/anuke/mindustry/world/blocks/distribution/Router.java +++ b/core/src/io/anuke/mindustry/world/blocks/distribution/Router.java @@ -2,6 +2,7 @@ package io.anuke.mindustry.world.blocks.distribution; import io.anuke.arc.collection.Array; import io.anuke.arc.util.Time; +import io.anuke.mindustry.content.*; import io.anuke.mindustry.entities.type.TileEntity; import io.anuke.mindustry.type.Item; import io.anuke.mindustry.world.*; @@ -63,7 +64,7 @@ public class Router extends Block{ for(int i = 0; i < proximity.size; i++){ Tile other = proximity.get((i + counter) % proximity.size); if(set) tile.rotation((byte)((tile.rotation() + 1) % proximity.size)); - if(other == from) continue; + if(other == from && from.block() == Blocks.overflowGate) continue; if(other.block().acceptItem(item, other, Edges.getFacingEdge(tile, other))){ return other; } From 5e8da856e7587d9c086f4c0c54eb7f2b94d92364 Mon Sep 17 00:00:00 2001 From: Anuken Date: Tue, 17 Sep 2019 18:54:30 -0400 Subject: [PATCH 07/15] Conclusively fixed status effect null issue --- .../mindustry/content/StatusEffects.java | 1 + .../src/io/anuke/mindustry/core/Platform.java | 6 ++++++ .../anuke/mindustry/entities/EntityGroup.java | 11 ++++++++++ .../anuke/mindustry/entities/type/Unit.java | 20 ++++++++++++++----- .../mindustry/entities/units/Statuses.java | 9 ++------- .../io/anuke/mindustry/type/StatusEffect.java | 2 +- 6 files changed, 36 insertions(+), 13 deletions(-) diff --git a/core/src/io/anuke/mindustry/content/StatusEffects.java b/core/src/io/anuke/mindustry/content/StatusEffects.java index cb4035dd0e..fb94a881ce 100644 --- a/core/src/io/anuke/mindustry/content/StatusEffects.java +++ b/core/src/io/anuke/mindustry/content/StatusEffects.java @@ -46,6 +46,7 @@ public class StatusEffects implements ContentList{ if(unit.getTeam() == waveTeam){ Events.fire(Trigger.shock); } + result.set(this, time); })); opposite(() -> burning); }}; diff --git a/core/src/io/anuke/mindustry/core/Platform.java b/core/src/io/anuke/mindustry/core/Platform.java index 7ccb700499..29e5c0d5ea 100644 --- a/core/src/io/anuke/mindustry/core/Platform.java +++ b/core/src/io/anuke/mindustry/core/Platform.java @@ -2,6 +2,7 @@ package io.anuke.mindustry.core; import io.anuke.arc.*; import io.anuke.arc.Input.*; +import io.anuke.arc.collection.*; import io.anuke.arc.files.*; import io.anuke.arc.function.*; import io.anuke.arc.math.*; @@ -25,6 +26,11 @@ public interface Platform{ /** Steam: Share a map on the workshop.*/ default void publishMap(Map map){} + /** Steam: Return external workshop maps to be loaded.*/ + default Array getExternalMaps(){ + return Array.with(); + } + /** Steam: Open workshop for maps.*/ default void openWorkshop(){} diff --git a/core/src/io/anuke/mindustry/entities/EntityGroup.java b/core/src/io/anuke/mindustry/entities/EntityGroup.java index ff48a1ad2e..07057d0436 100644 --- a/core/src/io/anuke/mindustry/entities/EntityGroup.java +++ b/core/src/io/anuke/mindustry/entities/EntityGroup.java @@ -18,6 +18,8 @@ public class EntityGroup{ private final Array entityArray = new Array<>(false, 32); private final Array entitiesToRemove = new Array<>(false, 32); private final Array entitiesToAdd = new Array<>(false, 32); + private final Array intersectArray = new Array<>(); + private final Rectangle intersectRect = new Rectangle(); private IntMap map; private QuadTree tree; private Consumer removeListener; @@ -161,6 +163,15 @@ public class EntityGroup{ tree().getIntersect(out, x, y, width, height); } + @SuppressWarnings("unchecked") + public Array intersect(float x, float y, float width, float height){ + intersectArray.clear(); + //don't waste time for empty groups + if(isEmpty()) return intersectArray; + tree().getIntersect(intersectArray, intersectRect.set(x, y, width, height)); + return intersectArray; + } + public QuadTree tree(){ if(!useTree) throw new RuntimeException("This group does not support quadtrees! Enable quadtrees when creating it."); return tree; diff --git a/core/src/io/anuke/mindustry/entities/type/Unit.java b/core/src/io/anuke/mindustry/entities/type/Unit.java index 3dfd2e0364..bbf3197621 100644 --- a/core/src/io/anuke/mindustry/entities/type/Unit.java +++ b/core/src/io/anuke/mindustry/entities/type/Unit.java @@ -2,6 +2,7 @@ package io.anuke.mindustry.entities.type; import io.anuke.annotations.Annotations.*; 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.*; @@ -212,15 +213,24 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ float radScl = 1.5f; float fsize = getSize() / radScl; moveVector.setZero(); + float cx = x - fsize/2f, cy = y - fsize/2f; - Units.nearby(x - fsize/2f, y - fsize/2f, fsize, fsize, en -> { - if(en == this || en.isFlying() != isFlying()) return; + for(Team team : Team.all){ + avoid(unitGroups[team.ordinal()].intersect(cx, cy, fsize, fsize)); + } + + avoid(playerGroup.intersect(cx, cy, fsize, fsize)); + velocity.add(moveVector.x / mass() * Time.delta(), moveVector.y / mass() * Time.delta()); + } + + private void avoid(Array arr){ + float radScl = 1.5f; + + for(Unit en : arr){ float dst = dst(en); float scl = Mathf.clamp(1f - dst / (getSize()/(radScl*2f) + en.getSize()/(radScl*2f))); moveVector.add(Tmp.v1.set((x - en.x) * scl, (y - en.y) * scl).limit(0.4f)); - }); - - velocity.add(moveVector.x / mass() * Time.delta(), moveVector.y / mass() * Time.delta()); + } } public @Nullable TileEntity getClosestCore(){ diff --git a/core/src/io/anuke/mindustry/entities/units/Statuses.java b/core/src/io/anuke/mindustry/entities/units/Statuses.java index 7a92a2c128..b96937bfcb 100644 --- a/core/src/io/anuke/mindustry/entities/units/Statuses.java +++ b/core/src/io/anuke/mindustry/entities/units/Statuses.java @@ -32,16 +32,16 @@ public class Statuses implements Saveable{ if(statuses.size > 0){ //check for opposite effects for(StatusEntry entry : statuses){ - if(entry.effect == null) continue; //extend effect if(entry.effect == effect){ entry.time = Math.max(entry.time, duration); return; }else if(entry.effect.reactsWith(effect)){ //find opposite + globalResult.effect = entry.effect; entry.effect.getTransition(unit, effect, entry.time, duration, globalResult); entry.time = globalResult.time; - if(globalResult.effect != entry.effect && globalResult.effect != null){ + if(globalResult.effect != entry.effect){ entry.effect = globalResult.effect; } @@ -84,10 +84,6 @@ public class Statuses implements Saveable{ removals.clear(); for(StatusEntry entry : statuses){ - if(entry.effect == null){ - removals.add(entry); - continue; - } entry.time = Math.max(entry.time - Time.delta(), 0); applied.set(entry.effect.id); @@ -127,7 +123,6 @@ public class Statuses implements Saveable{ public void writeSave(DataOutput stream) throws IOException{ stream.writeByte(statuses.size); for(StatusEntry entry : statuses){ - stream.writeByte(entry.effect.id); stream.writeFloat(entry.time); } diff --git a/core/src/io/anuke/mindustry/type/StatusEffect.java b/core/src/io/anuke/mindustry/type/StatusEffect.java index 19b662d76c..ae74288758 100644 --- a/core/src/io/anuke/mindustry/type/StatusEffect.java +++ b/core/src/io/anuke/mindustry/type/StatusEffect.java @@ -5,7 +5,7 @@ import io.anuke.arc.collection.ObjectMap; import io.anuke.arc.function.Supplier; import io.anuke.arc.graphics.Color; import io.anuke.arc.math.Mathf; -import io.anuke.arc.util.Time; +import io.anuke.arc.util.*; import io.anuke.mindustry.content.Fx; import io.anuke.mindustry.entities.Effects; import io.anuke.mindustry.entities.Effects.Effect; From 0ceb58a1052d00be3de8ca965df9af85ebd4b8d5 Mon Sep 17 00:00:00 2001 From: Anuken Date: Tue, 17 Sep 2019 19:25:37 -0400 Subject: [PATCH 08/15] Bugfixes --- core/assets/bundles/bundle.properties | 1 + core/src/io/anuke/mindustry/core/UI.java | 5 ++-- .../io/anuke/mindustry/input/MobileInput.java | 28 +------------------ .../mindustry/ui/dialogs/MapsDialog.java | 8 +++++- 4 files changed, 12 insertions(+), 30 deletions(-) diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index d0ef17bcad..5a92f0002f 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -288,6 +288,7 @@ editor.resizemap = Resize Map editor.mapname = Map Name: editor.overwrite = [accent]Warning!\nThis overwrites an existing map. editor.overwrite.confirm = [scarlet]Warning![] A map with this name already exists. Are you sure you want to overwrite it? +editor.exists = A map with this name already exists. editor.selectmap = Select a map to load: toolmode.replace = Replace diff --git a/core/src/io/anuke/mindustry/core/UI.java b/core/src/io/anuke/mindustry/core/UI.java index 5e18483e11..1f5eb0f137 100644 --- a/core/src/io/anuke/mindustry/core/UI.java +++ b/core/src/io/anuke/mindustry/core/UI.java @@ -325,8 +325,9 @@ public class UI implements ApplicationListener, Loadable{ cont.row(); cont.addImage().width(300f).pad(2).height(4f).color(Color.scarlet); cont.row(); - cont.add(text).pad(2f).growX().wrap(); - buttons.addButton("$ok", this::hide).size(120, 50).pad(4); + cont.add(text).pad(2f).growX().wrap().get().setAlignment(Align.center); + cont.row(); + cont.addButton("$ok", this::hide).size(120, 50).pad(4); }}.show(); } diff --git a/core/src/io/anuke/mindustry/input/MobileInput.java b/core/src/io/anuke/mindustry/input/MobileInput.java index 14f86e360f..7564325e1c 100644 --- a/core/src/io/anuke/mindustry/input/MobileInput.java +++ b/core/src/io/anuke/mindustry/input/MobileInput.java @@ -67,33 +67,7 @@ public class MobileInput extends InputHandler implements GestureListener{ public MobileInput(){ Events.on(ClientLoadEvent.class, e -> { - GestureDetector dec = new GestureDetector(20, 0.5f, 0.4f, 0.15f, this){ - boolean clearMouse = false; - - @Override - public boolean touchDown(int x, int y, int pointer, KeyCode button){ - if(Core.scene.hasMouse(x, y)){ - clearMouse = true; - return false; - } - return super.touchDown(x, y, pointer, button); - } - - @Override - public boolean touchDragged(int x, int y, int pointer){ - if(!clearMouse){ - return super.touchDragged(x, y, pointer); - } - return false; - } - - @Override - public boolean touchUp(int x, int y, int pointer, KeyCode button){ - clearMouse = false; - return super.touchUp(x, y, pointer, button); - } - }; - Core.input.getInputProcessors().insert(0, dec); + Core.input.getInputProcessors().add(new GestureDetector(20, 0.5f, 0.4f, 0.15f, this)); }); } diff --git a/core/src/io/anuke/mindustry/ui/dialogs/MapsDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/MapsDialog.java index 956c76bbd5..e58af17752 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/MapsDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/MapsDialog.java @@ -53,12 +53,18 @@ public class MapsDialog extends FloatingDialog{ buttons.addImageTextButton("$editor.newmap", Icon.add, () -> { ui.showTextInput("$editor.newmap", "$name", "", text -> { - ui.loadAnd(() -> { + Runnable show = () -> ui.loadAnd(() -> { hide(); ui.editor.show(); ui.editor.editor.getTags().put("name", text); Events.fire(new MapMakeEvent()); }); + + if(maps.byName(text) != null){ + ui.showErrorMessage("$editor.exists"); + }else{ + show.run(); + } }); }).size(210f, 64f); From 69944a2b632fd2df4945cd1d23215167c9751c17 Mon Sep 17 00:00:00 2001 From: Anuken Date: Tue, 17 Sep 2019 19:29:38 -0400 Subject: [PATCH 09/15] Crash fixes --- .../anuke/mindustry/ui/fragments/BlockInventoryFragment.java | 3 +-- core/src/io/anuke/mindustry/ui/fragments/HudFragment.java | 3 --- gradle.properties | 2 +- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/core/src/io/anuke/mindustry/ui/fragments/BlockInventoryFragment.java b/core/src/io/anuke/mindustry/ui/fragments/BlockInventoryFragment.java index fc80e13ac8..0f1b31c3ad 100644 --- a/core/src/io/anuke/mindustry/ui/fragments/BlockInventoryFragment.java +++ b/core/src/io/anuke/mindustry/ui/fragments/BlockInventoryFragment.java @@ -32,7 +32,7 @@ import static io.anuke.mindustry.Vars.*; public class BlockInventoryFragment extends Fragment{ private final static float holdWithdraw = 20f; - private Table table; + private Table table = new Table(); private Tile tile; private float holdTime = 0f; private boolean holding; @@ -52,7 +52,6 @@ public class BlockInventoryFragment extends Fragment{ @Override public void build(Group parent){ - table = new Table(); table.setName("inventory"); table.setTransform(true); parent.setTransform(true); diff --git a/core/src/io/anuke/mindustry/ui/fragments/HudFragment.java b/core/src/io/anuke/mindustry/ui/fragments/HudFragment.java index 37c48d27a0..5196a97119 100644 --- a/core/src/io/anuke/mindustry/ui/fragments/HudFragment.java +++ b/core/src/io/anuke/mindustry/ui/fragments/HudFragment.java @@ -572,9 +572,6 @@ public class HudFragment extends Fragment{ } shown = !shown; - if(flip != null){ - flip.getParent().act(Core.graphics.getDeltaTime()); - } } private void addWaveTable(Button table){ diff --git a/gradle.properties b/gradle.properties index f686bb2212..119b9bb609 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,3 @@ org.gradle.daemon=true org.gradle.jvmargs=-Xms256m -Xmx1024m -archash=1fda7fc4ed52e00fdbd6b9a5fab9af6add78dc63 +archash=de8be7efb888294932a9d41140ac9a71b4ff7f18 From 2424afa1fbb239fbfb5d61753ffad9aa13add7ca Mon Sep 17 00:00:00 2001 From: Anuken Date: Tue, 17 Sep 2019 21:55:57 -0400 Subject: [PATCH 10/15] Workshop implementation progress --- core/assets/bundles/bundle.properties | 2 +- .../io/anuke/mindustry/ClientLauncher.java | 1 + .../anuke/mindustry/editor/MapLoadDialog.java | 2 +- core/src/io/anuke/mindustry/maps/Map.java | 6 +++ core/src/io/anuke/mindustry/maps/Maps.java | 52 ++++++++++--------- .../io/anuke/mindustry/net/CrashSender.java | 4 +- .../ui/dialogs/CustomGameDialog.java | 4 +- .../mindustry/ui/dialogs/MapPlayDialog.java | 2 +- .../mindustry/ui/dialogs/MapsDialog.java | 6 +-- .../mindustry/desktop/DesktopLauncher.java | 23 +++++++- .../mindustry/desktop/steam/SWorkshop.java | 17 ++++-- 11 files changed, 78 insertions(+), 41 deletions(-) diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index 5a92f0002f..5345273c4e 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -202,7 +202,7 @@ wave.enemy = [lightgray]{0} Enemy Remaining loadimage = Load Image saveimage = Save Image unknown = Unknown -custom = Custom +custom = Custom builtin = Built-In map.delete.confirm = Are you sure you want to delete this map? This action cannot be undone! map.random = [accent]Random Map diff --git a/core/src/io/anuke/mindustry/ClientLauncher.java b/core/src/io/anuke/mindustry/ClientLauncher.java index e63fc9ac01..fe15d49d88 100644 --- a/core/src/io/anuke/mindustry/ClientLauncher.java +++ b/core/src/io/anuke/mindustry/ClientLauncher.java @@ -40,6 +40,7 @@ public abstract class ClientLauncher extends ApplicationCore implements Platform batch = new SpriteBatch(); assets = new AssetManager(); assets.setLoader(Texture.class, "." + mapExtension, new MapPreviewLoader()); + assets.load("sprites/error.png", Texture.class); atlas = TextureAtlas.blankAtlas(); Vars.net = new Net(platform.getNet()); diff --git a/core/src/io/anuke/mindustry/editor/MapLoadDialog.java b/core/src/io/anuke/mindustry/editor/MapLoadDialog.java index 6cfaaeca7a..c0567a724c 100644 --- a/core/src/io/anuke/mindustry/editor/MapLoadDialog.java +++ b/core/src/io/anuke/mindustry/editor/MapLoadDialog.java @@ -54,7 +54,7 @@ public class MapLoadDialog extends FloatingDialog{ for(Map map : maps.all()){ TextButton button = new TextButton(map.name(), Styles.togglet); - button.add(new BorderImage(map.texture, 2f).setScaling(Scaling.fit)).size(16 * 4f); + button.add(new BorderImage(map.safeTexture(), 2f).setScaling(Scaling.fit)).size(16 * 4f); button.getCells().reverse(); button.clicked(() -> selected = map); button.getLabelCell().grow().left().padLeft(5f); diff --git a/core/src/io/anuke/mindustry/maps/Map.java b/core/src/io/anuke/mindustry/maps/Map.java index 92789727dc..df0a2d711f 100644 --- a/core/src/io/anuke/mindustry/maps/Map.java +++ b/core/src/io/anuke/mindustry/maps/Map.java @@ -20,6 +20,8 @@ public class Map implements Comparable{ public final FileHandle file; /** Format version. */ public final int version; + /** Whether this map is managed, e.g. downloaded from the Steam workshop.*/ + public boolean workshop; /** Map width/height, shorts. */ public int width, height; /** Preview texture. */ @@ -57,6 +59,10 @@ public class Map implements Comparable{ return Core.settings.getInt("hiscore" + file.nameWithoutExtension(), 0); } + public Texture safeTexture(){ + return texture == null ? Core.assets.get("sprites/error.png") : texture; + } + public FileHandle previewFile(){ return Vars.mapPreviewDirectory.child(file.nameWithoutExtension() + ".png"); } diff --git a/core/src/io/anuke/mindustry/maps/Maps.java b/core/src/io/anuke/mindustry/maps/Maps.java index 7336e63114..dd45cc9e6f 100644 --- a/core/src/io/anuke/mindustry/maps/Maps.java +++ b/core/src/io/anuke/mindustry/maps/Maps.java @@ -81,6 +81,7 @@ public class Maps{ /** Load all maps. Should be called at application start. */ public void load(){ + //defaults; must work try{ for(String name : defaultMapNames){ FileHandle file = Core.files.internal("maps/" + name + "." + mapExtension); @@ -90,7 +91,27 @@ public class Maps{ throw new RuntimeException(e); } - loadCustomMaps(); + //custom + for(FileHandle file : customMapDirectory.list()){ + try{ + if(file.extension().equalsIgnoreCase(mapExtension)){ + loadMap(file, true); + } + }catch(Exception e){ + Log.err("Failed to load custom map file '{0}'!", file); + Log.err(e); + } + } + + //workshop + for(FileHandle file : platform.getExternalMaps()){ + try{ + loadMap(file, false).workshop = true; + }catch(Exception e){ + Log.err("Failed to load workshop map file '{0}'!", file); + Log.err(e); + } + } } public void reload(){ @@ -174,14 +195,6 @@ public class Maps{ } } - /** Creates a legacy map by converting it to a non-legacy map and pasting it in a temp directory. - * Should be followed up by {@link #importMap(FileHandle)} .*/ - public Map makeLegacyMap(FileHandle file) throws IOException{ - FileHandle dst = tmpDirectory.child("conversion_map." + mapExtension); - LegacyMapIO.convertMap(file, dst); - return MapIO.createMap(dst, true); - } - /** Import a map, then save it. This updates all values and stored data necessary. */ public void importMap(FileHandle file) throws IOException{ FileHandle dest = findFile(); @@ -203,7 +216,6 @@ public class Maps{ if(error[0] != null){ throw new IOException(error[0]); } - } /** Attempts to run the following code; @@ -312,9 +324,11 @@ public class Maps{ public void loadPreviews(){ for(Map map : maps){ + Log.info("Generating preview for {0}", map.name()); //try to load preview if(map.previewFile().exists()){ - //this may fail, but calls createNewPreview + Log.info("> exists"); + //this may fail, but calls queueNewPreview Core.assets.load(new AssetDescriptor<>(map.previewFile().path() + "." + mapExtension, Texture.class, new MapPreviewParameter(map))).loaded = t -> map.texture = (Texture)t; try{ @@ -324,6 +338,7 @@ public class Maps{ queueNewPreview(map); } }else{ + Log.info("> doesn't exist, queuing"); queueNewPreview(map); } } @@ -332,7 +347,8 @@ public class Maps{ private void createAllPreviews(){ Core.app.post(() -> { for(Map map : previewList){ - createNewPreview(map, e -> Core.app.post(() -> map.texture = new Texture("sprites/error.png"))); + Log.info("> > GEN NEW preview for {0}", map.name()); + createNewPreview(map, e -> Core.app.post(() -> map.texture = Core.assets.get("sprites/error.png"))); } previewList.clear(); }); @@ -407,16 +423,4 @@ public class Maps{ return map; } - private void loadCustomMaps(){ - for(FileHandle file : customMapDirectory.list()){ - try{ - if(file.extension().equalsIgnoreCase(mapExtension)){ - loadMap(file, true); - } - }catch(Exception e){ - Log.err("Failed to load custom map file '{0}'!", file); - Log.err(e); - } - } - } } \ No newline at end of file diff --git a/core/src/io/anuke/mindustry/net/CrashSender.java b/core/src/io/anuke/mindustry/net/CrashSender.java index 6970e9521b..cc29071615 100644 --- a/core/src/io/anuke/mindustry/net/CrashSender.java +++ b/core/src/io/anuke/mindustry/net/CrashSender.java @@ -25,8 +25,8 @@ public class CrashSender{ try{ exception.printStackTrace(); - //don't create crash logs for me (anuke) or custom builds, as it's expected - if(System.getProperty("user.name").equals("anuke") || Version.build == -1) return; + //don't create crash logs for custom builds, as it's expected + if(Version.build == -1) return; //attempt to load version regardless if(Version.number == 0){ diff --git a/core/src/io/anuke/mindustry/ui/dialogs/CustomGameDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/CustomGameDialog.java index efbdfa65df..74eb693fec 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/CustomGameDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/CustomGameDialog.java @@ -48,7 +48,7 @@ public class CustomGameDialog extends FloatingDialog{ maps.row(); } - ImageButton image = new ImageButton(new TextureRegion(map.texture), Styles.cleari); + ImageButton image = new ImageButton(new TextureRegion(map.safeTexture()), Styles.cleari); image.margin(5); image.top(); @@ -72,7 +72,7 @@ public class CustomGameDialog extends FloatingDialog{ image.add(img).size(images); - BorderImage border = new BorderImage(map.texture, 3f); + BorderImage border = new BorderImage(map.safeTexture(), 3f); border.setScaling(Scaling.fit); image.replaceImage(border); diff --git a/core/src/io/anuke/mindustry/ui/dialogs/MapPlayDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/MapPlayDialog.java index c55b4f6fb8..b3da2b2f3f 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/MapPlayDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/MapPlayDialog.java @@ -69,7 +69,7 @@ public class MapPlayDialog extends FloatingDialog{ cont.row(); cont.addImageTextButton("$customize", Icon.toolsSmall, () -> dialog.show(rules, () -> rules = map.applyRules(selectedGamemode))).width(230); cont.row(); - cont.add(new BorderImage(map.texture, 3f)).size(mobile && !Core.graphics.isPortrait() ? 150f : 250f).get().setScaling(Scaling.fit); + cont.add(new BorderImage(map.safeTexture(), 3f)).size(mobile && !Core.graphics.isPortrait() ? 150f : 250f).get().setScaling(Scaling.fit); //only maps with survival are valid for high scores if(Gamemode.survival.valid(map)){ cont.row(); diff --git a/core/src/io/anuke/mindustry/ui/dialogs/MapsDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/MapsDialog.java index e58af17752..66de040bb2 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/MapsDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/MapsDialog.java @@ -143,9 +143,9 @@ public class MapsDialog extends FloatingDialog{ button.row(); button.addImage().growX().pad(4).color(Pal.gray); button.row(); - button.stack(new Image(map.texture).setScaling(Scaling.fit), new BorderImage(map.texture).setScaling(Scaling.fit)).size(mapsize - 20f); + button.stack(new Image(map.safeTexture()).setScaling(Scaling.fit), new BorderImage(map.safeTexture()).setScaling(Scaling.fit)).size(mapsize - 20f); button.row(); - button.add(map.custom ? "$custom" : "$builtin").color(Color.gray).padTop(3); + button.add(map.custom ? "$custom" : map.workshop ? "$workshop" : "$builtin").color(Color.gray).padTop(3); i++; } @@ -166,7 +166,7 @@ public class MapsDialog extends FloatingDialog{ float mapsize = Core.graphics.isPortrait() ? 160f : 300f; Table table = dialog.cont; - table.stack(new Image(map.texture).setScaling(Scaling.fit), new BorderImage(map.texture).setScaling(Scaling.fit)).size(mapsize); + table.stack(new Image(map.safeTexture()).setScaling(Scaling.fit), new BorderImage(map.safeTexture()).setScaling(Scaling.fit)).size(mapsize); table.table(Styles.black, desc -> { desc.top(); diff --git a/desktop/src/io/anuke/mindustry/desktop/DesktopLauncher.java b/desktop/src/io/anuke/mindustry/desktop/DesktopLauncher.java index 59b665b31b..d4cb2582c2 100644 --- a/desktop/src/io/anuke/mindustry/desktop/DesktopLauncher.java +++ b/desktop/src/io/anuke/mindustry/desktop/DesktopLauncher.java @@ -7,6 +7,7 @@ import io.anuke.arc.Files.*; import io.anuke.arc.backends.sdl.*; import io.anuke.arc.backends.sdl.jni.*; import io.anuke.arc.collection.*; +import io.anuke.arc.files.*; import io.anuke.arc.function.*; import io.anuke.arc.input.*; import io.anuke.arc.math.*; @@ -48,11 +49,12 @@ public class DesktopLauncher extends ClientLauncher{ setWindowIcon(FileType.Internal, "icons/icon_64.png"); }}); }catch(Throwable e){ - DesktopLauncher.handleCrash(e); + handleCrash(e); } } public DesktopLauncher(String[] args){ + Log.setUseColors(false); Version.init(); boolean useSteam = Version.modifier.equals("steam"); testMobile = Array.with(args).contains("-testMobile"); @@ -72,6 +74,16 @@ public class DesktopLauncher extends ClientLauncher{ if(useSteam){ if(showConsole){ + StringBuilder base = new StringBuilder(); + Log.setLogger(new LogHandler(){ + @Override + public void print(String text, Object... args){ + String out = Log.format(text, false, args); + + base.append(out).append("\n"); + } + }); + Events.on(ClientLoadEvent.class, event -> { Label[] label = {null}; boolean[] visible = {false}; @@ -86,6 +98,7 @@ public class DesktopLauncher extends ClientLauncher{ t.toFront(); }); t.table(Styles.black3, f -> label[0] = f.add("").get()).visible(() -> visible[0]); + label[0].getText().append(base); }); Log.setLogger(new LogHandler(){ @@ -177,12 +190,18 @@ public class DesktopLauncher extends ClientLauncher{ boolean fbgp = badGPU; CrashSender.send(e, file -> { + Throwable cause = Strings.getFinalCause(e); if(!fbgp){ - dialog.accept(() -> message("A crash has occured. It has been saved in:\n" + file.getAbsolutePath() + "\n" + (e.getMessage() == null ? "" : "\n" + e.getMessage()))); + dialog.accept(() -> 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()))); } }); } + @Override + public Array getExternalMaps(){ + return !steam ? super.getExternalMaps() : SVars.workshop.getMapFiles(); + } + @Override public NetProvider getNet(){ return steam ? SVars.net : new ArcNetImpl(); diff --git a/desktop/src/io/anuke/mindustry/desktop/steam/SWorkshop.java b/desktop/src/io/anuke/mindustry/desktop/steam/SWorkshop.java index 07273818d2..fd9f360084 100644 --- a/desktop/src/io/anuke/mindustry/desktop/steam/SWorkshop.java +++ b/desktop/src/io/anuke/mindustry/desktop/steam/SWorkshop.java @@ -4,6 +4,7 @@ import com.codedisaster.steamworks.*; import com.codedisaster.steamworks.SteamRemoteStorage.*; import com.codedisaster.steamworks.SteamUGC.*; import io.anuke.arc.*; +import io.anuke.arc.collection.*; import io.anuke.arc.files.*; import io.anuke.arc.util.*; import io.anuke.mindustry.game.EventType.*; @@ -18,17 +19,23 @@ public class SWorkshop implements SteamUGCCallback{ public final SteamUGC ugc = new SteamUGC(this); private Map lastMap; + private Array mapFiles; public SWorkshop(){ int items = ugc.getNumSubscribedItems(); SteamPublishedFileID[] ids = new SteamPublishedFileID[items]; + ItemInstallInfo info = new ItemInstallInfo(); ugc.getSubscribedItems(ids); - for(int i = 0; i < items; i++){ - SteamPublishedFileID id = ids[i]; - ItemInstallInfo info = new ItemInstallInfo(); - ugc.getItemInstallInfo(id, info); + mapFiles = Array.with(ids).map(f -> { + ugc.getItemInstallInfo(f, info); + return new FileHandle(info.getFolder()); + }).select(f -> f.list().length > 0).map(f -> f.list()[0]); - } + Log.info("Fetching {0} subscribed maps.", items); + } + + public Array getMapFiles(){ + return mapFiles; } public void publishMap(Map map){ From 5d0cfc3599b0658138e1833d780bf87a85f8f61c Mon Sep 17 00:00:00 2001 From: Anuken Date: Tue, 17 Sep 2019 22:39:58 -0400 Subject: [PATCH 11/15] Workshop tweaks --- core/assets/bundles/bundle.properties | 2 ++ core/src/io/anuke/mindustry/Vars.java | 2 +- .../src/io/anuke/mindustry/core/Platform.java | 3 +++ .../mindustry/editor/MapEditorDialog.java | 17 ++++++++++++++--- core/src/io/anuke/mindustry/maps/Map.java | 4 +++- .../mindustry/maps/MapPreviewLoader.java | 7 ++++--- core/src/io/anuke/mindustry/maps/Maps.java | 4 ---- .../mindustry/ui/dialogs/MapsDialog.java | 19 +++++++++++-------- .../mindustry/desktop/DesktopLauncher.java | 5 +++++ .../mindustry/desktop/steam/SWorkshop.java | 15 +++++++++++++++ gradle.properties | 2 +- 11 files changed, 59 insertions(+), 21 deletions(-) diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index 5345273c4e..03c38a2746 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -174,6 +174,7 @@ save.playtime = Playtime: {0} warning = Warning. confirm = Confirm delete = Delete +view.workshop = View In Workshop ok = OK open = Open customize = Customize Rules @@ -222,6 +223,7 @@ editor.oregen.info = Ore Generation: editor.mapinfo = Map Info editor.author = Author: editor.description = Description: +editor.nodescription = A map must have a description of at least 4 characters before being published. editor.waves = Waves: editor.rules = Rules: editor.generation = Generation: diff --git a/core/src/io/anuke/mindustry/Vars.java b/core/src/io/anuke/mindustry/Vars.java index 720b7d33bf..445a634714 100644 --- a/core/src/io/anuke/mindustry/Vars.java +++ b/core/src/io/anuke/mindustry/Vars.java @@ -139,7 +139,7 @@ public class Vars implements Loadable{ public static EntityCollisions collisions; public static DefaultWaves defaultWaves; public static LoopControl loops; - public static Platform platform; + public static Platform platform = new Platform(){}; public static Plugins plugins; public static World world; diff --git a/core/src/io/anuke/mindustry/core/Platform.java b/core/src/io/anuke/mindustry/core/Platform.java index 29e5c0d5ea..55c57e82a4 100644 --- a/core/src/io/anuke/mindustry/core/Platform.java +++ b/core/src/io/anuke/mindustry/core/Platform.java @@ -31,6 +31,9 @@ public interface Platform{ return Array.with(); } + /** Steam: View a map listing on the workshop.*/ + default void viewMapListing(Map map){} + /** Steam: Open workshop for maps.*/ default void openWorkshop(){} diff --git a/core/src/io/anuke/mindustry/editor/MapEditorDialog.java b/core/src/io/anuke/mindustry/editor/MapEditorDialog.java index 8f2dd20d92..773ce88749 100644 --- a/core/src/io/anuke/mindustry/editor/MapEditorDialog.java +++ b/core/src/io/anuke/mindustry/editor/MapEditorDialog.java @@ -154,9 +154,20 @@ public class MapEditorDialog extends Dialog implements Disposable{ if(steam){ menu.cont.addImageTextButton("$editor.publish.workshop", Icon.linkSmall, () -> { Map map = save(); - if(map != null){ - platform.publishMap(map); + + if(map == null) return; + + if(map.tags.get("description", "").length() < 4){ + ui.showErrorMessage("$editor.nodescription"); + return; } + + if(!Gamemode.survival.valid(map)){ + ui.showErrorMessage("$map.nospawn"); + return; + } + + platform.publishMap(map); }).padTop(-3).size(swidth * 2f + 10, 60f); menu.cont.row(); @@ -276,7 +287,7 @@ public class MapEditorDialog extends Dialog implements Disposable{ }); } - private Map save(){ + public Map save(){ String name = editor.getTags().get("name", "").trim(); editor.getTags().put("rules", JsonIO.write(state.rules)); editor.getTags().remove("width"); diff --git a/core/src/io/anuke/mindustry/maps/Map.java b/core/src/io/anuke/mindustry/maps/Map.java index df0a2d711f..94fa841f08 100644 --- a/core/src/io/anuke/mindustry/maps/Map.java +++ b/core/src/io/anuke/mindustry/maps/Map.java @@ -64,7 +64,7 @@ public class Map implements Comparable{ } public FileHandle previewFile(){ - return Vars.mapPreviewDirectory.child(file.nameWithoutExtension() + ".png"); + return Vars.mapPreviewDirectory.child((workshop ? file.parent().name() : file.nameWithoutExtension()) + ".png"); } public FileHandle cacheFile(){ @@ -133,6 +133,8 @@ public class Map implements Comparable{ @Override public int compareTo(Map map){ + int work = -Boolean.compare(workshop, map.workshop); + if(work != 0) return work; int type = -Boolean.compare(custom, map.custom); if(type != 0) return type; int modes = Boolean.compare(Gamemode.pvp.valid(this), Gamemode.pvp.valid(map)); diff --git a/core/src/io/anuke/mindustry/maps/MapPreviewLoader.java b/core/src/io/anuke/mindustry/maps/MapPreviewLoader.java index 262f3dc45f..da229addce 100644 --- a/core/src/io/anuke/mindustry/maps/MapPreviewLoader.java +++ b/core/src/io/anuke/mindustry/maps/MapPreviewLoader.java @@ -6,6 +6,7 @@ import io.anuke.arc.assets.loaders.resolvers.*; import io.anuke.arc.collection.*; import io.anuke.arc.files.*; import io.anuke.arc.graphics.*; +import io.anuke.arc.util.*; import io.anuke.mindustry.*; import io.anuke.mindustry.game.*; @@ -20,7 +21,7 @@ public class MapPreviewLoader extends TextureLoader{ try{ super.loadAsync(manager, fileName, file.sibling(file.nameWithoutExtension()), parameter); }catch(Exception e){ - e.printStackTrace(); + Log.err(e); MapPreviewParameter param = (MapPreviewParameter)parameter; Vars.maps.queueNewPreview(param.map); } @@ -31,11 +32,11 @@ public class MapPreviewLoader extends TextureLoader{ try{ return super.loadSync(manager, fileName, file, parameter); }catch(Throwable e){ - e.printStackTrace(); + Log.err(e); try{ return new Texture(file); }catch(Throwable e2){ - e2.printStackTrace(); + Log.err(e2); return new Texture("sprites/error.png"); } } diff --git a/core/src/io/anuke/mindustry/maps/Maps.java b/core/src/io/anuke/mindustry/maps/Maps.java index dd45cc9e6f..395ceafec6 100644 --- a/core/src/io/anuke/mindustry/maps/Maps.java +++ b/core/src/io/anuke/mindustry/maps/Maps.java @@ -324,10 +324,8 @@ public class Maps{ public void loadPreviews(){ for(Map map : maps){ - Log.info("Generating preview for {0}", map.name()); //try to load preview if(map.previewFile().exists()){ - Log.info("> exists"); //this may fail, but calls queueNewPreview Core.assets.load(new AssetDescriptor<>(map.previewFile().path() + "." + mapExtension, Texture.class, new MapPreviewParameter(map))).loaded = t -> map.texture = (Texture)t; @@ -338,7 +336,6 @@ public class Maps{ queueNewPreview(map); } }else{ - Log.info("> doesn't exist, queuing"); queueNewPreview(map); } } @@ -347,7 +344,6 @@ public class Maps{ private void createAllPreviews(){ Core.app.post(() -> { for(Map map : previewList){ - Log.info("> > GEN NEW preview for {0}", map.name()); createNewPreview(map, e -> Core.app.post(() -> map.texture = Core.assets.get("sprites/error.png"))); } previewList.clear(); diff --git a/core/src/io/anuke/mindustry/ui/dialogs/MapsDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/MapsDialog.java index 66de040bb2..c6b2dabe60 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/MapsDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/MapsDialog.java @@ -4,7 +4,6 @@ import io.anuke.arc.*; import io.anuke.arc.graphics.*; import io.anuke.arc.input.*; import io.anuke.arc.math.*; -import io.anuke.arc.scene.event.*; import io.anuke.arc.scene.ui.*; import io.anuke.arc.scene.ui.layout.*; import io.anuke.arc.util.*; @@ -205,13 +204,17 @@ public class MapsDialog extends FloatingDialog{ } }).fillX().height(54f).marginLeft(10); - table.addImageTextButton("$delete", Icon.trash16Small, () -> { - ui.showConfirm("$confirm", Core.bundle.format("map.delete", map.name()), () -> { - maps.removeMap(map); - dialog.hide(); - setup(); - }); - }).fillX().height(54f).marginLeft(10).disabled(!map.custom).touchable(map.custom ? Touchable.enabled : Touchable.disabled); + table.addImageTextButton(map.workshop ? "$view.workshop" : "$delete", map.workshop ? Icon.linkSmall : Icon.trash16Small, () -> { + if(map.workshop){ + platform.viewMapListing(map); + }else{ + ui.showConfirm("$confirm", Core.bundle.format("map.delete", map.name()), () -> { + maps.removeMap(map); + dialog.hide(); + setup(); + }); + } + }).fillX().height(54f).marginLeft(10).disabled(!map.workshop && !map.custom); dialog.show(); } diff --git a/desktop/src/io/anuke/mindustry/desktop/DesktopLauncher.java b/desktop/src/io/anuke/mindustry/desktop/DesktopLauncher.java index d4cb2582c2..d215e28d9c 100644 --- a/desktop/src/io/anuke/mindustry/desktop/DesktopLauncher.java +++ b/desktop/src/io/anuke/mindustry/desktop/DesktopLauncher.java @@ -202,6 +202,11 @@ public class DesktopLauncher extends ClientLauncher{ return !steam ? super.getExternalMaps() : SVars.workshop.getMapFiles(); } + @Override + public void viewMapListing(Map map){ + SVars.net.friends.activateGameOverlayToWebPage("steam://url/CommunityFilePage/" + map.file.parent().name()); + } + @Override public NetProvider getNet(){ return steam ? SVars.net : new ArcNetImpl(); diff --git a/desktop/src/io/anuke/mindustry/desktop/steam/SWorkshop.java b/desktop/src/io/anuke/mindustry/desktop/steam/SWorkshop.java index fd9f360084..f233218fd1 100644 --- a/desktop/src/io/anuke/mindustry/desktop/steam/SWorkshop.java +++ b/desktop/src/io/anuke/mindustry/desktop/steam/SWorkshop.java @@ -39,6 +39,15 @@ public class SWorkshop implements SteamUGCCallback{ } public void publishMap(Map map){ + if(map.tags.containsKey("steamid")){ + Log.info("Map already published, redirecting to ID."); + SVars.net.friends.activateGameOverlayToWebPage("steam://url/CommunityFilePage/" + map.tags.get("steamid")); + return; + } + + //update author name when publishing + map.tags.put("author", SVars.net.friends.getPersonaName()); + FloatingDialog dialog = new FloatingDialog("$confirm"); dialog.setFillParent(false); dialog.cont.add("$map.publish.confirm").width(600f).wrap(); @@ -141,6 +150,12 @@ public class SWorkshop implements SteamUGCCallback{ if(needsToAcceptWLA){ SVars.net.friends.activateGameOverlayToWebPage("https://steamcommunity.com/sharedfiles/workshoplegalagreement"); } + ui.editor.editor.getTags().put("steamid", SteamNativeHandle.getNativeHandle(publishedFileID) + ""); + try{ + ui.editor.save(); + }catch(Exception e){ + Log.err(e); + } Events.fire(new MapPublishEvent()); }else{ ui.showErrorMessage(Core.bundle.format("map.publish.error ", result.name())); diff --git a/gradle.properties b/gradle.properties index 119b9bb609..f47982435b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,3 @@ org.gradle.daemon=true org.gradle.jvmargs=-Xms256m -Xmx1024m -archash=de8be7efb888294932a9d41140ac9a71b4ff7f18 +archash=818e26ff093403031fcf31d3424dacb9c646d4b6 From c6a4bf69ee65064dae0e9f19f682a064616ff197 Mon Sep 17 00:00:00 2001 From: Anuken Date: Wed, 18 Sep 2019 08:49:48 -0400 Subject: [PATCH 12/15] Fixed turret cooling --- core/src/io/anuke/mindustry/Vars.java | 2 -- .../world/blocks/defense/turrets/CooledTurret.java | 2 +- .../mindustry/world/blocks/defense/turrets/Turret.java | 2 +- .../mindustry/world/blocks/production/GenericCrafter.java | 7 +++++++ 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/core/src/io/anuke/mindustry/Vars.java b/core/src/io/anuke/mindustry/Vars.java index 445a634714..24807883d1 100644 --- a/core/src/io/anuke/mindustry/Vars.java +++ b/core/src/io/anuke/mindustry/Vars.java @@ -122,8 +122,6 @@ public class Vars implements Loadable{ public static FileHandle saveDirectory; /** data subdirectory used for plugins */ public static FileHandle pluginDirectory; - /** old map file extension, for conversion */ - public static final String oldMapExtension = "mmap"; /** map file extension */ public static final String mapExtension = "msav"; /** save file extension */ diff --git a/core/src/io/anuke/mindustry/world/blocks/defense/turrets/CooledTurret.java b/core/src/io/anuke/mindustry/world/blocks/defense/turrets/CooledTurret.java index 7ed149ba2e..86f15dce93 100644 --- a/core/src/io/anuke/mindustry/world/blocks/defense/turrets/CooledTurret.java +++ b/core/src/io/anuke/mindustry/world/blocks/defense/turrets/CooledTurret.java @@ -55,7 +55,7 @@ public class CooledTurret extends Turret{ Liquid liquid = entity.liquids.current(); float used = Math.min(Math.min(entity.liquids.get(liquid), maxUsed * Time.delta()), Math.max(0, ((reload - entity.reload) / coolantMultiplier) / liquid.heatCapacity)) * baseReloadSpeed(tile); - entity.reload += (used * liquid.heatCapacity) / liquid.heatCapacity; + entity.reload += used * liquid.heatCapacity * coolantMultiplier; entity.liquids.remove(liquid, used); if(Mathf.chance(0.06 * used)){ diff --git a/core/src/io/anuke/mindustry/world/blocks/defense/turrets/Turret.java b/core/src/io/anuke/mindustry/world/blocks/defense/turrets/Turret.java index ba3e8dda79..948161dfd1 100644 --- a/core/src/io/anuke/mindustry/world/blocks/defense/turrets/Turret.java +++ b/core/src/io/anuke/mindustry/world/blocks/defense/turrets/Turret.java @@ -100,7 +100,7 @@ public abstract class Turret extends Block{ stats.add(BlockStat.shootRange, range / tilesize, StatUnit.blocks); stats.add(BlockStat.inaccuracy, (int)inaccuracy, StatUnit.degrees); - stats.add(BlockStat.reload, 60f / reload * shots, StatUnit.none); + stats.add(BlockStat.reload, 60f / reload, StatUnit.none); stats.add(BlockStat.shots, shots, StatUnit.none); stats.add(BlockStat.targetsAir, targetAir); stats.add(BlockStat.targetsGround, targetGround); diff --git a/core/src/io/anuke/mindustry/world/blocks/production/GenericCrafter.java b/core/src/io/anuke/mindustry/world/blocks/production/GenericCrafter.java index 428697d853..eb76325965 100644 --- a/core/src/io/anuke/mindustry/world/blocks/production/GenericCrafter.java +++ b/core/src/io/anuke/mindustry/world/blocks/production/GenericCrafter.java @@ -127,6 +127,13 @@ public class GenericCrafter extends Block{ } } + @Override + public boolean outputsItems(){ + return outputItem != null; + } + + + @Override public boolean canProduce(Tile tile){ if(outputItem != null && tile.entity.items.get(outputItem.item) >= itemCapacity){ From 1e667946b35c96b7c696becbae17887851101978 Mon Sep 17 00:00:00 2001 From: Anuken Date: Wed, 18 Sep 2019 12:46:11 -0400 Subject: [PATCH 13/15] Bugfixes --- .../io/anuke/mindustry/AndroidLauncher.java | 2 ++ .../world/blocks/distribution/MassDriver.java | 29 ++++++++++--------- .../world/blocks/storage/CoreBlock.java | 6 ++-- 3 files changed, 21 insertions(+), 16 deletions(-) diff --git a/android/src/io/anuke/mindustry/AndroidLauncher.java b/android/src/io/anuke/mindustry/AndroidLauncher.java index 97443f0d3b..138d00c224 100644 --- a/android/src/io/anuke/mindustry/AndroidLauncher.java +++ b/android/src/io/anuke/mindustry/AndroidLauncher.java @@ -76,6 +76,8 @@ public class AndroidLauncher extends AndroidApplication{ if(code == Activity.RESULT_OK && in != null && in.getData() != null){ Uri uri = in.getData(); + if(uri.getPath().contains("(invalid)")) return; + Core.app.post(() -> Core.app.post(() -> cons.accept(new FileHandle(uri.getPath()){ @Override public InputStream read(){ diff --git a/core/src/io/anuke/mindustry/world/blocks/distribution/MassDriver.java b/core/src/io/anuke/mindustry/world/blocks/distribution/MassDriver.java index 2bce0d1904..60822e9f08 100644 --- a/core/src/io/anuke/mindustry/world/blocks/distribution/MassDriver.java +++ b/core/src/io/anuke/mindustry/world/blocks/distribution/MassDriver.java @@ -12,7 +12,6 @@ import io.anuke.mindustry.content.*; import io.anuke.mindustry.entities.*; import io.anuke.mindustry.entities.Effects.*; import io.anuke.mindustry.entities.type.*; -import io.anuke.mindustry.entities.type.Bullet; import io.anuke.mindustry.gen.*; import io.anuke.mindustry.graphics.*; import io.anuke.mindustry.type.*; @@ -120,26 +119,28 @@ public class MassDriver extends Block{ if( tile.entity.items.total() >= minDistribute && //must shoot minimum amount of items - link.block().itemCapacity - link.entity.items.total() >= minDistribute && //must have minimum amount of space - entity.reload <= 0.0001f //must have reloaded + link.block().itemCapacity - link.entity.items.total() >= minDistribute //must have minimum amount of space ){ MassDriverEntity other = link.entity(); other.waitingShooters.add(tile); - //align to target location - entity.rotation = Mathf.slerpDelta(entity.rotation, targetRotation, rotateSpeed * entity.power.satisfaction); + if(entity.reload <= 0.0001f){ - //fire when it's the first in the queue and angles are ready. - if(other.currentShooter() == tile && + //align to target location + entity.rotation = Mathf.slerpDelta(entity.rotation, targetRotation, rotateSpeed * entity.power.satisfaction); + + //fire when it's the first in the queue and angles are ready. + if(other.currentShooter() == tile && other.state == DriverState.accepting && Angles.near(entity.rotation, targetRotation, 2f) && Angles.near(other.rotation, targetRotation + 180f, 2f)){ - //actually fire - fire(tile, link); - //remove waiting shooters, it's done firing - other.waitingShooters.remove(tile); - //set both states to idle - entity.state = DriverState.idle; - other.state = DriverState.idle; + //actually fire + fire(tile, link); + //remove waiting shooters, it's done firing + other.waitingShooters.remove(tile); + //set both states to idle + entity.state = DriverState.idle; + other.state = DriverState.idle; + } } } } diff --git a/core/src/io/anuke/mindustry/world/blocks/storage/CoreBlock.java b/core/src/io/anuke/mindustry/world/blocks/storage/CoreBlock.java index 5cafa70f57..ec7cd5f616 100644 --- a/core/src/io/anuke/mindustry/world/blocks/storage/CoreBlock.java +++ b/core/src/io/anuke/mindustry/world/blocks/storage/CoreBlock.java @@ -97,8 +97,10 @@ public class CoreBlock extends StorageBlock{ entity.storageCapacity += other.block().itemCapacity + other.entity.proximity().sum(e -> isContainer(e) ? e.block().itemCapacity : 0); } - for(Item item : content.items()){ - entity.items.set(item, Math.min(entity.items.get(item), entity.storageCapacity)); + if(!world.isGenerating()){ + for(Item item : content.items()){ + entity.items.set(item, Math.min(entity.items.get(item), entity.storageCapacity)); + } } for(Tile other : state.teams.get(tile.getTeam()).cores){ From 0d29d94800f3522b572fd1e3261cd03fc5c01d94 Mon Sep 17 00:00:00 2001 From: Anuken Date: Wed, 18 Sep 2019 15:18:59 -0400 Subject: [PATCH 14/15] Bugfixes --- core/src/io/anuke/mindustry/editor/MapEditorDialog.java | 2 +- core/src/io/anuke/mindustry/entities/type/Unit.java | 1 + core/src/io/anuke/mindustry/input/InputHandler.java | 2 +- core/src/io/anuke/mindustry/net/Net.java | 4 +++- 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/core/src/io/anuke/mindustry/editor/MapEditorDialog.java b/core/src/io/anuke/mindustry/editor/MapEditorDialog.java index 773ce88749..95b5869e24 100644 --- a/core/src/io/anuke/mindustry/editor/MapEditorDialog.java +++ b/core/src/io/anuke/mindustry/editor/MapEditorDialog.java @@ -168,7 +168,7 @@ public class MapEditorDialog extends Dialog implements Disposable{ } platform.publishMap(map); - }).padTop(-3).size(swidth * 2f + 10, 60f); + }).padTop(-3).size(swidth * 2f + 10, 60f).update(b -> b.setText(editor.getTags().containsKey("steamid") ? "$view.workshop" : "$editor.publish.workshop")); menu.cont.row(); } diff --git a/core/src/io/anuke/mindustry/entities/type/Unit.java b/core/src/io/anuke/mindustry/entities/type/Unit.java index bbf3197621..63289f53e1 100644 --- a/core/src/io/anuke/mindustry/entities/type/Unit.java +++ b/core/src/io/anuke/mindustry/entities/type/Unit.java @@ -227,6 +227,7 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ float radScl = 1.5f; for(Unit en : arr){ + if(en.isFlying() != isFlying()) continue; float dst = dst(en); float scl = Mathf.clamp(1f - dst / (getSize()/(radScl*2f) + en.getSize()/(radScl*2f))); moveVector.add(Tmp.v1.set((x - en.x) * scl, (y - en.y) * scl).limit(0.4f)); diff --git a/core/src/io/anuke/mindustry/input/InputHandler.java b/core/src/io/anuke/mindustry/input/InputHandler.java index e4e8dadfc7..3ea3302194 100644 --- a/core/src/io/anuke/mindustry/input/InputHandler.java +++ b/core/src/io/anuke/mindustry/input/InputHandler.java @@ -58,7 +58,7 @@ public abstract class InputHandler implements InputProcessor{ @Remote(targets = Loc.both, forward = true, called = Loc.server) public static void transferInventory(Player player, Tile tile){ - if(!player.timer.get(Player.timerTransfer, 40)) return; + if(player == null || player.timer == null || !player.timer.get(Player.timerTransfer, 40)) return; if(net.server() && (player.item().amount <= 0 || player.isTransferring|| !tile.interactable(player.getTeam()))){ throw new ValidateException(player, "Player cannot transfer an item."); } diff --git a/core/src/io/anuke/mindustry/net/Net.java b/core/src/io/anuke/mindustry/net/Net.java index 66482ab729..eddd19c1e6 100644 --- a/core/src/io/anuke/mindustry/net/Net.java +++ b/core/src/io/anuke/mindustry/net/Net.java @@ -46,7 +46,9 @@ public class Net{ t = t.getCause(); } - String error = t.getMessage() == null ? "" : t.getMessage().toLowerCase(); + String baseError = Strings.getFinalMesage(e); + + String error = baseError == null ? "" : baseError.toLowerCase(); String type = t.getClass().toString().toLowerCase(); boolean isError = false; From 5a0669d4377469e2e427b4be8f5d1fd37673843f Mon Sep 17 00:00:00 2001 From: Anuken Date: Wed, 18 Sep 2019 19:24:49 -0400 Subject: [PATCH 15/15] SAF is terrible --- .../io/anuke/mindustry/AndroidLauncher.java | 24 +++++++++++++++++-- .../mindustry/entities/effect/Lightning.java | 2 +- .../mindustry/entities/type/BaseUnit.java | 3 ++- 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/android/src/io/anuke/mindustry/AndroidLauncher.java b/android/src/io/anuke/mindustry/AndroidLauncher.java index 138d00c224..2cc928d322 100644 --- a/android/src/io/anuke/mindustry/AndroidLauncher.java +++ b/android/src/io/anuke/mindustry/AndroidLauncher.java @@ -1,5 +1,6 @@ package io.anuke.mindustry; +import android.*; import android.app.*; import android.content.*; import android.content.pm.*; @@ -21,6 +22,7 @@ import io.anuke.mindustry.ui.dialogs.*; import java.io.*; import java.lang.System; +import java.util.*; import static io.anuke.mindustry.Vars.*; @@ -68,10 +70,10 @@ public class AndroidLauncher extends AndroidApplication{ @Override public void showFileChooser(boolean open, String extension, Consumer cons){ - if(VERSION.SDK_INT >= 19){ + if(VERSION.SDK_INT >= VERSION_CODES.Q){ Intent intent = new Intent(open ? Intent.ACTION_OPEN_DOCUMENT : Intent.ACTION_CREATE_DOCUMENT); intent.addCategory(Intent.CATEGORY_OPENABLE); - intent.setType("*/*"); + intent.setType(extension.equals("zip") ? "application/zip" : "*/*"); addResultListener(i -> startActivityForResult(intent, i), (code, in) -> { if(code == Activity.RESULT_OK && in != null && in.getData() != null){ Uri uri = in.getData(); @@ -99,6 +101,24 @@ public class AndroidLauncher extends AndroidApplication{ }))); } }); + }else if(VERSION.SDK_INT >= VERSION_CODES.M && !(checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED && + checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED)){ + chooser = new FileChooser(open ? "$open" : "$save", file -> file.extension().equalsIgnoreCase(extension), open, file -> { + if(!open){ + cons.accept(file.parent().child(file.nameWithoutExtension() + "." + extension)); + }else{ + cons.accept(file); + } + }); + + ArrayList perms = new ArrayList<>(); + if(checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED){ + perms.add(Manifest.permission.WRITE_EXTERNAL_STORAGE); + } + if(checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED){ + perms.add(Manifest.permission.READ_EXTERNAL_STORAGE); + } + requestPermissions(perms.toArray(new String[0]), PERMISSION_REQUEST_CODE); }else{ super.showFileChooser(open, extension, cons); } diff --git a/core/src/io/anuke/mindustry/entities/effect/Lightning.java b/core/src/io/anuke/mindustry/entities/effect/Lightning.java index db8eeb5b1b..83dedb94be 100644 --- a/core/src/io/anuke/mindustry/entities/effect/Lightning.java +++ b/core/src/io/anuke/mindustry/entities/effect/Lightning.java @@ -47,7 +47,7 @@ public class Lightning extends TimedEntity implements DrawTrait, TimeTrait{ } /** Do not invoke! */ - @Remote(called = Loc.server) + @Remote(called = Loc.server, unreliable = true) public static void createLighting(int seed, Team team, Color color, float damage, float x, float y, float rotation, int length){ Lightning l = Pools.obtain(Lightning.class, Lightning::new); diff --git a/core/src/io/anuke/mindustry/entities/type/BaseUnit.java b/core/src/io/anuke/mindustry/entities/type/BaseUnit.java index 4a9d8695f3..9d3a92a170 100644 --- a/core/src/io/anuke/mindustry/entities/type/BaseUnit.java +++ b/core/src/io/anuke/mindustry/entities/type/BaseUnit.java @@ -16,6 +16,7 @@ import io.anuke.mindustry.game.*; import io.anuke.mindustry.gen.*; import io.anuke.mindustry.type.*; import io.anuke.mindustry.world.*; +import io.anuke.mindustry.world.blocks.*; import io.anuke.mindustry.world.blocks.defense.DeflectorWall.*; import io.anuke.mindustry.world.blocks.units.CommandCenter.*; import io.anuke.mindustry.world.blocks.units.UnitFactory.*; @@ -273,7 +274,7 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{ return; } - if(!isFlying() && (world.tileWorld(x, y) != null && world.tileWorld(x, y).solid())){ + if(!isFlying() && (world.tileWorld(x, y) != null && !(world.tileWorld(x, y).block() instanceof BuildBlock) && world.tileWorld(x, y).solid())){ kill(); }