From 7a2234cd2501e2c4b35a5752bbbb390635e27aac Mon Sep 17 00:00:00 2001 From: Anuken Date: Sat, 11 May 2019 00:37:29 -0400 Subject: [PATCH] Tweaks to improve in-game editing --- .../io/anuke/annotations/Annotations.java | 2 +- .../entities/traits/BuilderTrait.java | 191 +++++++++--------- .../anuke/mindustry/entities/type/Unit.java | 6 +- .../src/io/anuke/mindustry/game/Gamemode.java | 1 + .../mindustry/ui/fragments/HudFragment.java | 46 ++++- .../ui/fragments/PlacementFragment.java | 2 +- core/src/io/anuke/mindustry/world/Build.java | 1 + .../mindustry/world/blocks/BuildBlock.java | 22 +- 8 files changed, 153 insertions(+), 118 deletions(-) diff --git a/annotations/src/main/java/io/anuke/annotations/Annotations.java b/annotations/src/main/java/io/anuke/annotations/Annotations.java index 06bde34e2e..1d5b62ed46 100644 --- a/annotations/src/main/java/io/anuke/annotations/Annotations.java +++ b/annotations/src/main/java/io/anuke/annotations/Annotations.java @@ -18,7 +18,7 @@ public class Annotations{ } /** Indicates that a method return or field can be null.*/ - @Target({ElementType.METHOD, ElementType.FIELD}) + @Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.LOCAL_VARIABLE}) @Retention(RetentionPolicy.SOURCE) public @interface Nullable{ diff --git a/core/src/io/anuke/mindustry/entities/traits/BuilderTrait.java b/core/src/io/anuke/mindustry/entities/traits/BuilderTrait.java index c8cf5c9164..1b1d0ca30e 100644 --- a/core/src/io/anuke/mindustry/entities/traits/BuilderTrait.java +++ b/core/src/io/anuke/mindustry/entities/traits/BuilderTrait.java @@ -40,10 +40,98 @@ public interface BuilderTrait extends Entity, TeamTrait{ float placeDistance = 220f; float mineDistance = 70f; - //due to iOS wierdness - class BuildDataStatic{ - static Array removal = new Array<>(); - static Vector2[] tmptr = new Vector2[]{new Vector2(), new Vector2(), new Vector2(), new Vector2()}; + /** + * Update building mechanism for this unit. + * This includes mining. + */ + default void updateBuilding(){ + float finalPlaceDst = state.rules.infiniteResources ? Float.MAX_VALUE : placeDistance; + Unit unit = (Unit)this; + //remove already completed build requests + removal.clear(); + for(BuildRequest req : getPlaceQueue()){ + removal.add(req); + } + + getPlaceQueue().clear(); + + for(BuildRequest request : removal){ + if(!((request.breaking && world.tile(request.x, request.y).block() == Blocks.air) || + (!request.breaking && (world.tile(request.x, request.y).rotation() == request.rotation || !request.block.rotate) + && world.tile(request.x, request.y).block() == request.block))){ + getPlaceQueue().addLast(request); + } + } + + BuildRequest current = getCurrentRequest(); + + //update mining here + if(current == null){ + if(getMineTile() != null){ + updateMining(); + } + return; + }else{ + setMineTile(null); + } + + Tile tile = world.tile(current.x, current.y); + + if(dst(tile) > finalPlaceDst){ + if(getPlaceQueue().size > 1){ + getPlaceQueue().removeFirst(); + getPlaceQueue().addLast(current); + } + return; + } + + if(!(tile.block() instanceof BuildBlock)){ + if(canCreateBlocks() && !current.breaking && Build.validPlace(getTeam(), current.x, current.y, current.block, current.rotation)){ + Call.beginPlace(getTeam(), current.x, current.y, current.block, current.rotation); + }else if(canCreateBlocks() && current.breaking && Build.validBreak(getTeam(), current.x, current.y)){ + Call.beginBreak(getTeam(), current.x, current.y); + }else{ + getPlaceQueue().removeFirst(); + return; + } + } + + TileEntity core = unit.getClosestCore(); + + //if there is no core to build with or no build entity, stop building! + if((core == null && !state.rules.infiniteResources) || !(tile.entity instanceof BuildEntity)){ + return; + } + + //otherwise, update it. + BuildEntity entity = tile.entity(); + + if(entity == null){ + return; + } + + if(unit.dst(tile) <= finalPlaceDst){ + unit.rotation = Mathf.slerpDelta(unit.rotation, unit.angleTo(entity), 0.4f); + } + + //progress is synced, thus not updated clientside + if(!Net.client()){ + //deconstructing is 2x as fast + if(current.breaking){ + entity.deconstruct(unit, core, 2f / entity.buildCost * Time.delta() * getBuildPower(tile) * state.rules.buildSpeedMultiplier); + }else{ + entity.construct(unit, core, 1f / entity.buildCost * Time.delta() * getBuildPower(tile) * state.rules.buildSpeedMultiplier); + } + + current.progress = entity.progress(); + }else{ + entity.progress = current.progress; + } + + if(!current.initialized){ + Core.app.post(() -> Events.fire(new BuildSelectEvent(tile, unit.getTeam(), this, current.breaking))); + current.initialized = true; + } } /** Returns the queue for storing build requests. */ @@ -148,97 +236,10 @@ public interface BuilderTrait extends Entity, TeamTrait{ return getPlaceQueue().size == 0 ? null : getPlaceQueue().first(); } - /** - * Update building mechanism for this unit. - * This includes mining. - */ - default void updateBuilding(){ - Unit unit = (Unit)this; - //remove already completed build requests - removal.clear(); - for(BuildRequest req : getPlaceQueue()){ - removal.add(req); - } - - getPlaceQueue().clear(); - - for(BuildRequest request : removal){ - if(!((request.breaking && world.tile(request.x, request.y).block() == Blocks.air) || - (!request.breaking && (world.tile(request.x, request.y).rotation() == request.rotation || !request.block.rotate) - && world.tile(request.x, request.y).block() == request.block))){ - getPlaceQueue().addLast(request); - } - } - - BuildRequest current = getCurrentRequest(); - - //update mining here - if(current == null){ - if(getMineTile() != null){ - updateMining(); - } - return; - }else{ - setMineTile(null); - } - - Tile tile = world.tile(current.x, current.y); - - if(dst(tile) > placeDistance){ - if(getPlaceQueue().size > 1){ - getPlaceQueue().removeFirst(); - getPlaceQueue().addLast(current); - } - return; - } - - if(!(tile.block() instanceof BuildBlock)){ - if(canCreateBlocks() && !current.breaking && Build.validPlace(getTeam(), current.x, current.y, current.block, current.rotation)){ - Call.beginPlace(getTeam(), current.x, current.y, current.block, current.rotation); - }else if(canCreateBlocks() && current.breaking && Build.validBreak(getTeam(), current.x, current.y)){ - Call.beginBreak(getTeam(), current.x, current.y); - }else{ - getPlaceQueue().removeFirst(); - return; - } - } - - TileEntity core = unit.getClosestCore(); - - //if there is no core to build with or no build entity, stop building! - if(core == null || !(tile.entity instanceof BuildEntity)){ - return; - } - - //otherwise, update it. - BuildEntity entity = tile.entity(); - - if(entity == null){ - return; - } - - if(unit.dst(tile) <= placeDistance){ - unit.rotation = Mathf.slerpDelta(unit.rotation, unit.angleTo(entity), 0.4f); - } - - //progress is synced, thus not updated clientside - if(!Net.client()){ - //deconstructing is 2x as fast - if(current.breaking){ - entity.deconstruct(unit, core, 2f / entity.buildCost * Time.delta() * getBuildPower(tile) * state.rules.buildSpeedMultiplier); - }else{ - entity.construct(unit, core, 1f / entity.buildCost * Time.delta() * getBuildPower(tile) * state.rules.buildSpeedMultiplier); - } - - current.progress = entity.progress(); - }else{ - entity.progress = current.progress; - } - - if(!current.initialized){ - Core.app.post(() -> Events.fire(new BuildSelectEvent(tile, unit.getTeam(), this, current.breaking))); - current.initialized = true; - } + //due to iOS wierdness, this is apparently required + class BuildDataStatic{ + static Array removal = new Array<>(); + static Vector2[] tmptr = new Vector2[]{new Vector2(), new Vector2(), new Vector2(), new Vector2()}; } /** Do not call directly. */ diff --git a/core/src/io/anuke/mindustry/entities/type/Unit.java b/core/src/io/anuke/mindustry/entities/type/Unit.java index 039c9d8c81..6579af6c97 100644 --- a/core/src/io/anuke/mindustry/entities/type/Unit.java +++ b/core/src/io/anuke/mindustry/entities/type/Unit.java @@ -1,5 +1,6 @@ package io.anuke.mindustry.entities.type; +import io.anuke.annotations.Annotations.Nullable; import io.anuke.arc.Core; import io.anuke.arc.Events; import io.anuke.arc.graphics.Color; @@ -8,7 +9,8 @@ import io.anuke.arc.graphics.g2d.TextureRegion; import io.anuke.arc.math.Mathf; import io.anuke.arc.math.geom.Geometry; import io.anuke.arc.math.geom.Vector2; -import io.anuke.arc.util.*; +import io.anuke.arc.util.Time; +import io.anuke.arc.util.Tmp; import io.anuke.mindustry.content.Blocks; import io.anuke.mindustry.content.Fx; import io.anuke.mindustry.entities.*; @@ -221,7 +223,7 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ velocity.add(moveVector.x / mass() * Time.delta(), moveVector.y / mass() * Time.delta()); } - public TileEntity getClosestCore(){ + public @Nullable TileEntity getClosestCore(){ TeamData data = state.teams.get(team); Tile tile = Geometry.findClosest(x, y, data.cores); diff --git a/core/src/io/anuke/mindustry/game/Gamemode.java b/core/src/io/anuke/mindustry/game/Gamemode.java index ce8c2276e8..f962693965 100644 --- a/core/src/io/anuke/mindustry/game/Gamemode.java +++ b/core/src/io/anuke/mindustry/game/Gamemode.java @@ -39,6 +39,7 @@ public enum Gamemode{ infiniteResources = true; editor = true; waves = true; + enemyCoreBuildRadius = 0f; waveTimer = false; respawnTime = 0f; }}),; diff --git a/core/src/io/anuke/mindustry/ui/fragments/HudFragment.java b/core/src/io/anuke/mindustry/ui/fragments/HudFragment.java index fa294a642a..4d19c9ae5d 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.utils.Elements; import io.anuke.arc.util.*; import io.anuke.mindustry.core.GameState.State; import io.anuke.mindustry.game.EventType.StateChangeEvent; +import io.anuke.mindustry.game.Team; import io.anuke.mindustry.game.UnlockableContent; import io.anuke.mindustry.gen.Call; import io.anuke.mindustry.graphics.Pal; @@ -26,8 +27,6 @@ import io.anuke.mindustry.net.Packets.AdminAction; import io.anuke.mindustry.ui.*; import io.anuke.mindustry.ui.dialogs.FloatingDialog; -import java.lang.StringBuilder; - import static io.anuke.mindustry.Vars.*; public class HudFragment extends Fragment{ @@ -131,8 +130,13 @@ public class HudFragment extends Fragment{ } }); - cont.table(stuff -> { - stuff.left(); + Table wavesMain, editorMain; + + cont.stack(wavesMain = new Table(), editorMain = new Table()); + + { + wavesMain.visible(() -> shown && !state.isEditor()); + wavesMain.left(); Stack stack = new Stack(); TextButton waves = new TextButton("", "wave"); Table btable = new Table().margin(0); @@ -142,12 +146,36 @@ public class HudFragment extends Fragment{ addWaveTable(waves); addPlayButton(btable); - stuff.add(stack).width(dsize * 4 + 3f); - stuff.row(); - stuff.table("button", t -> t.margin(10f).add(new Bar("boss.health", Pal.health, () -> state.boss() == null ? 0f : state.boss().healthf()).blink(Color.WHITE)) + wavesMain.add(stack).width(dsize * 4 + 3f); + wavesMain.row(); + wavesMain.table("button", t -> t.margin(10f).add(new Bar("boss.health", Pal.health, () -> state.boss() == null ? 0f : state.boss().healthf()).blink(Color.WHITE)) .grow()).fillX().visible(() -> state.rules.waves && state.boss() != null).height(60f).get(); - stuff.row(); - }).visible(() -> shown); + wavesMain.row(); + } + + { + editorMain.table("button-edge-4", t -> { + //t.margin(0f); + t.add("$editor.teams").growX().left(); + t.row(); + t.table(teams -> { + teams.left(); + int i = 0; + for(Team team : Team.all){ + ImageButton button = teams.addImageButton("white", "clear-toggle-partial", 40f, () -> player.setTeam(team)) + .size(50f).margin(6f).get(); + button.getImageCell().grow(); + button.getStyle().imageUpColor = team.color; + button.update(() -> button.setChecked(player.getTeam() == team)); + + if(++i % 3 == 0){ + teams.row(); + } + } + }).left(); + }).width(dsize * 4 + 3f); + editorMain.visible(() -> shown && state.isEditor()); + } //fps display cont.table(info -> { diff --git a/core/src/io/anuke/mindustry/ui/fragments/PlacementFragment.java b/core/src/io/anuke/mindustry/ui/fragments/PlacementFragment.java index 0514f6fc35..2dd59e2e75 100644 --- a/core/src/io/anuke/mindustry/ui/fragments/PlacementFragment.java +++ b/core/src/io/anuke/mindustry/ui/fragments/PlacementFragment.java @@ -150,7 +150,7 @@ public class PlacementFragment extends Fragment{ button.update(() -> { //color unplacable things gray TileEntity core = player.getClosestCore(); - Color color = core != null && (core.items.has(block.buildRequirements, state.rules.buildCostMultiplier) || state.rules.infiniteResources) ? Color.WHITE : Color.GRAY; + Color color = state.rules.infiniteResources || (core != null && (core.items.has(block.buildRequirements, state.rules.buildCostMultiplier) || state.rules.infiniteResources)) ? Color.WHITE : Color.GRAY; button.forEach(elem -> elem.setColor(color)); button.setChecked(input.block == block); }); diff --git a/core/src/io/anuke/mindustry/world/Build.java b/core/src/io/anuke/mindustry/world/Build.java index bb08372000..a97a310922 100644 --- a/core/src/io/anuke/mindustry/world/Build.java +++ b/core/src/io/anuke/mindustry/world/Build.java @@ -86,6 +86,7 @@ public class Build{ } } + Tile tile = world.tile(x, y); if(tile == null) return false; diff --git a/core/src/io/anuke/mindustry/world/blocks/BuildBlock.java b/core/src/io/anuke/mindustry/world/blocks/BuildBlock.java index 5be964ca80..e1205b465e 100644 --- a/core/src/io/anuke/mindustry/world/blocks/BuildBlock.java +++ b/core/src/io/anuke/mindustry/world/blocks/BuildBlock.java @@ -1,7 +1,6 @@ package io.anuke.mindustry.world.blocks; -import io.anuke.annotations.Annotations.Loc; -import io.anuke.annotations.Annotations.Remote; +import io.anuke.annotations.Annotations.*; import io.anuke.arc.Core; import io.anuke.arc.Events; import io.anuke.arc.Graphics.Cursor; @@ -185,13 +184,13 @@ public class BuildBlock extends Block{ private float[] accumulator; private float[] totalAccumulator; - public void construct(Unit builder, TileEntity core, float amount){ + public void construct(Unit builder, @Nullable TileEntity core, float amount){ if(cblock == null){ kill(); return; } - float maxProgress = checkRequired(core.items, amount, false); + float maxProgress = core == null ? amount : checkRequired(core.items, amount, false); for(int i = 0; i < cblock.buildRequirements.length; i++){ int reqamount = Math.round(state.rules.buildCostMultiplier * cblock.buildRequirements[i].amount); @@ -199,7 +198,7 @@ public class BuildBlock extends Block{ totalAccumulator[i] = Math.min(totalAccumulator[i] + reqamount * maxProgress, reqamount); } - maxProgress = checkRequired(core.items, maxProgress, true); + maxProgress = core == null ? maxProgress : checkRequired(core.items, maxProgress, true); progress = Mathf.clamp(progress + maxProgress); @@ -212,7 +211,7 @@ public class BuildBlock extends Block{ } } - public void deconstruct(Unit builder, TileEntity core, float amount){ + public void deconstruct(Unit builder, @Nullable TileEntity core, float amount){ float deconstructMultiplier = 0.5f; if(cblock != null){ @@ -229,10 +228,13 @@ public class BuildBlock extends Block{ int accumulated = (int)(accumulator[i]); //get amount if(amount > 0 && accumulated > 0){ //if it's positive, add it to the core - int accepting = core.tile.block().acceptStack(requirements[i].item, accumulated, core.tile, builder); - core.tile.block().handleStack(requirements[i].item, accepting, core.tile, builder); - - accumulator[i] -= accepting; + if(core != null){ + int accepting = core.tile.block().acceptStack(requirements[i].item, accumulated, core.tile, builder); + core.tile.block().handleStack(requirements[i].item, accepting, core.tile, builder); + accumulator[i] -= accepting; + }else{ + accumulator[i] -= accumulated; + } } } }