Tweaks to improve in-game editing

This commit is contained in:
Anuken 2019-05-11 00:37:29 -04:00
parent 11ede2756e
commit 7a2234cd25
8 changed files with 153 additions and 118 deletions

View file

@ -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{

View file

@ -40,10 +40,98 @@ public interface BuilderTrait extends Entity, TeamTrait{
float placeDistance = 220f;
float mineDistance = 70f;
//due to iOS wierdness
class BuildDataStatic{
static Array<BuildRequest> 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<BuildRequest> removal = new Array<>();
static Vector2[] tmptr = new Vector2[]{new Vector2(), new Vector2(), new Vector2(), new Vector2()};
}
/** Do not call directly. */

View file

@ -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);

View file

@ -39,6 +39,7 @@ public enum Gamemode{
infiniteResources = true;
editor = true;
waves = true;
enemyCoreBuildRadius = 0f;
waveTimer = false;
respawnTime = 0f;
}}),;

View file

@ -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 -> {

View file

@ -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);
});

View file

@ -86,6 +86,7 @@ public class Build{
}
}
Tile tile = world.tile(x, y);
if(tile == null) return false;

View file

@ -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;
}
}
}
}