Functional desktop schematic placement

This commit is contained in:
Anuken
2019-10-18 00:41:30 -04:00
parent 61d15782d0
commit 30bcfb6d5e
13 changed files with 116 additions and 51 deletions

View File

@@ -104,7 +104,7 @@ public interface BuilderTrait extends Entity, TeamTrait{
if(current.breaking){ if(current.breaking){
entity.deconstruct(unit, core, 1f / entity.buildCost * Time.delta() * getBuildPower(tile) * state.rules.buildSpeedMultiplier); entity.deconstruct(unit, core, 1f / entity.buildCost * Time.delta() * getBuildPower(tile) * state.rules.buildSpeedMultiplier);
}else{ }else{
if(entity.construct(unit, core, 1f / entity.buildCost * Time.delta() * getBuildPower(tile) * state.rules.buildSpeedMultiplier)){ if(entity.construct(unit, core, 1f / entity.buildCost * Time.delta() * getBuildPower(tile) * state.rules.buildSpeedMultiplier, current.hasConfig)){
if(current.hasConfig){ if(current.hasConfig){
Call.onTileConfig(null, tile, current.config); Call.onTileConfig(null, tile, current.config);
} }
@@ -267,18 +267,26 @@ public interface BuilderTrait extends Entity, TeamTrait{
/** Class for storing build requests. Can be either a place or remove request. */ /** Class for storing build requests. Can be either a place or remove request. */
class BuildRequest{ class BuildRequest{
/** Position and rotation of this request. */
public int x, y, rotation; public int x, y, rotation;
/** Block being placed. If null, this is a breaking request.*/
public @Nullable Block block; public @Nullable Block block;
/** Whether this is a break request.*/
public boolean breaking; public boolean breaking;
/** Whether this request comes with a config int. If yes, any blocks placed with this request will not call playerPlaced.*/
public boolean hasConfig; public boolean hasConfig;
/** Config int. Not used unless hasConfig is true.*/
public int config; public int config;
/** Original position, only used in schematics.*/
public int originalX, originalY;
/** Last progress.*/
public float progress; public float progress;
/** Whether construction has started for this request.*/
public boolean initialized; public boolean initialized;
//animation variables /** Visual scale. Used only for rendering.*/
public float animScale = 0f; public float animScale = 0f;
public float animInvalid;
/** This creates a build request. */ /** This creates a build request. */
public BuildRequest(int x, int y, int rotation, Block block){ public BuildRequest(int x, int y, int rotation, Block block){
@@ -302,6 +310,29 @@ public interface BuilderTrait extends Entity, TeamTrait{
} }
public BuildRequest copy(){
BuildRequest copy = new BuildRequest();
copy.x = x;
copy.y = y;
copy.rotation = rotation;
copy.block = block;
copy.breaking = breaking;
copy.hasConfig = hasConfig;
copy.config = config;
copy.originalX = originalX;
copy.originalY = originalY;
copy.progress = progress;
copy.initialized = initialized;
copy.animScale = animScale;
return copy;
}
public BuildRequest original(int x, int y){
originalX = x;
originalY = y;
return this;
}
public Rectangle bounds(Rectangle rect){ public Rectangle bounds(Rectangle rect){
if(breaking){ if(breaking){
return rect.set(-100f, -100f, 0f, 0f); return rect.set(-100f, -100f, 0f, 0f);

View File

@@ -1,5 +1,6 @@
package io.anuke.mindustry.entities.type; package io.anuke.mindustry.entities.type;
import io.anuke.mindustry.*;
import io.anuke.mindustry.entities.EntityGroup; import io.anuke.mindustry.entities.EntityGroup;
import io.anuke.mindustry.entities.traits.Entity; import io.anuke.mindustry.entities.traits.Entity;
@@ -14,6 +15,14 @@ public abstract class BaseEntity implements Entity{
id = lastid++; id = lastid++;
} }
public int tileX(){
return Vars.world.toTile(x);
}
public int tileY(){
return Vars.world.toTile(y);
}
@Override @Override
public int getID(){ public int getID(){
return id; return id;

View File

@@ -236,11 +236,6 @@ public class TileEntity extends BaseEntity implements TargetTrait, HealthTrait{
return 0; return 0;
} }
/** @return whether the config is a position that should be translated.*/
public boolean posConfig(){
return false;
}
@Override @Override
public void removed(){ public void removed(){
if(sound != null){ if(sound != null){

View File

@@ -145,7 +145,7 @@ public class Schematics implements Loadable{
/** Creates an array of build requests from a schematic's data, centered on the provided x+y coordinates. */ /** Creates an array of build requests from a schematic's data, centered on the provided x+y coordinates. */
public Array<BuildRequest> toRequests(Schematic schem, int x, int y){ public Array<BuildRequest> toRequests(Schematic schem, int x, int y){
return schem.tiles.map(t -> new BuildRequest(t.x + x - schem.width/2, t.y + y - schem.height/2, t.rotation, t.block).configure(t.config)); return schem.tiles.map(t -> new BuildRequest(t.x + x - schem.width/2, t.y + y - schem.height/2, t.rotation, t.block).original(t.x, t.y).configure(t.config));
} }
/** Adds a schematic to the list, also copying it into the files.*/ /** Adds a schematic to the list, also copying it into the files.*/
@@ -209,7 +209,7 @@ public class Schematics implements Loadable{
if(tile != null && tile.entity != null){ if(tile != null && tile.entity != null){
int config = tile.entity.config(); int config = tile.entity.config();
if(tile.entity.posConfig()){ if(tile.block().posConfig){
config = Pos.get(Pos.x(config) + offsetX, Pos.y(config) + offsetY); config = Pos.get(Pos.x(config) + offsetX, Pos.y(config) + offsetY);
} }
@@ -240,7 +240,11 @@ public class Schematics implements Loadable{
//region IO methods //region IO methods
public static Schematic read(FileHandle file) throws IOException{ public static Schematic read(FileHandle file) throws IOException{
return read(new DataInputStream(file.read(1024))); Schematic s = read(new DataInputStream(file.read(1024)));
if(!s.tags.containsKey("name")){
s.tags.put("name", file.nameWithoutExtension());
}
return s;
} }
public static Schematic read(InputStream input) throws IOException{ public static Schematic read(InputStream input) throws IOException{
@@ -271,8 +275,6 @@ public class Schematics implements Loadable{
blocks.put(i, block == null ? Blocks.air : block); blocks.put(i, block == null ? Blocks.air : block);
} }
Log.info(blocks);
int total = stream.readInt(); int total = stream.readInt();
Array<Stile> tiles = new Array<>(total); Array<Stile> tiles = new Array<>(total);
for(int i = 0; i < total; i++){ for(int i = 0; i < total; i++){

View File

@@ -3,7 +3,6 @@ package io.anuke.mindustry.input;
import io.anuke.arc.*; import io.anuke.arc.*;
import io.anuke.arc.Graphics.*; import io.anuke.arc.Graphics.*;
import io.anuke.arc.Graphics.Cursor.*; import io.anuke.arc.Graphics.Cursor.*;
import io.anuke.arc.graphics.*;
import io.anuke.arc.graphics.g2d.*; import io.anuke.arc.graphics.g2d.*;
import io.anuke.arc.input.*; import io.anuke.arc.input.*;
import io.anuke.arc.math.*; import io.anuke.arc.math.*;
@@ -14,7 +13,6 @@ import io.anuke.mindustry.core.GameState.*;
import io.anuke.mindustry.entities.traits.BuilderTrait.*; import io.anuke.mindustry.entities.traits.BuilderTrait.*;
import io.anuke.mindustry.game.EventType.*; import io.anuke.mindustry.game.EventType.*;
import io.anuke.mindustry.game.*; import io.anuke.mindustry.game.*;
import io.anuke.mindustry.game.Schematics.*;
import io.anuke.mindustry.gen.*; import io.anuke.mindustry.gen.*;
import io.anuke.mindustry.graphics.*; import io.anuke.mindustry.graphics.*;
import io.anuke.mindustry.ui.*; import io.anuke.mindustry.ui.*;
@@ -30,7 +28,7 @@ public class DesktopInput extends InputHandler{
/** Position where the player started dragging a line. */ /** Position where the player started dragging a line. */
private int selectX, selectY, schemX, schemY; private int selectX, selectY, schemX, schemY;
/** Last known line positions.*/ /** Last known line positions.*/
private int lastLineX, lastLineY; private int lastLineX, lastLineY, schematicX, schematicY;
/** Whether selecting mode is active. */ /** Whether selecting mode is active. */
private PlaceMode mode; private PlaceMode mode;
/** Animation scale for line. */ /** Animation scale for line. */
@@ -40,8 +38,6 @@ public class DesktopInput extends InputHandler{
/** Whether player is currently deleting removal requests. */ /** Whether player is currently deleting removal requests. */
private boolean deleting = false; private boolean deleting = false;
private Schematic __REMOVE__;
@Override @Override
public void buildUI(Group group){ public void buildUI(Group group){
group.fill(t -> { group.fill(t -> {
@@ -89,6 +85,12 @@ public class DesktopInput extends InputHandler{
} }
} }
//draw schematic requests
for(BuildRequest request : selectRequests){
request.animScale = 1f;
drawRequest(request);
}
if(sreq != null){ if(sreq != null){
boolean valid = validPlace(sreq.x, sreq.y, sreq.block, sreq.rotation, sreq); boolean valid = validPlace(sreq.x, sreq.y, sreq.block, sreq.rotation, sreq);
if(sreq.block.rotate){ if(sreq.block.rotate){
@@ -108,13 +110,6 @@ public class DesktopInput extends InputHandler{
} }
Draw.reset(); Draw.reset();
if(__REMOVE__ != null){
Texture tex = schematics.getPreview(__REMOVE__, PreviewRes.low);
Draw.blend(Blending.disabled);
Draw.rect(Draw.wrap(tex), Core.camera.position.x, Core.camera.position.y, tex.getWidth() / 4f, tex.getHeight() / 4f);
Draw.blend();
}
} }
@Override @Override
@@ -154,6 +149,10 @@ public class DesktopInput extends InputHandler{
mode = none; mode = none;
} }
if(mode != none){
selectRequests.clear();
}
if(player.isShooting && !canShoot()){ if(player.isShooting && !canShoot()){
player.isShooting = false; player.isShooting = false;
} }
@@ -182,7 +181,7 @@ public class DesktopInput extends InputHandler{
cursorType = cursor.block().getCursor(cursor); cursorType = cursor.block().getCursor(cursor);
if(isPlacing()){ if(isPlacing() || !selectRequests.isEmpty()){
cursorType = SystemCursor.hand; cursorType = SystemCursor.hand;
} }
@@ -210,6 +209,16 @@ public class DesktopInput extends InputHandler{
cursorType = SystemCursor.arrow; cursorType = SystemCursor.arrow;
} }
@Override
public void useSchematic(Schematic schem){
block = null;
schematicX = tileX(getMouseX());
schematicY = tileY(getMouseY());
selectRequests.addAll(schematics.toRequests(schem, schematicX, schematicY));
mode = none;
}
@Override @Override
public boolean isBreaking(){ public boolean isBreaking(){
return mode == breaking; return mode == breaking;
@@ -221,6 +230,18 @@ public class DesktopInput extends InputHandler{
int cursorY = tileY(Core.input.mouseY()); int cursorY = tileY(Core.input.mouseY());
int rawCursorX = world.toTile(Core.input.mouseWorld().x), rawCursorY = world.toTile(Core.input.mouseWorld().y); int rawCursorX = world.toTile(Core.input.mouseWorld().x), rawCursorY = world.toTile(Core.input.mouseWorld().y);
if(!selectRequests.isEmpty()){
int shiftX = rawCursorX - schematicX, shiftY = rawCursorY - schematicY;
selectRequests.each(s -> {
s.x += shiftX;
s.y += shiftY;
});
schematicX += shiftX;
schematicY += shiftY;
}
if(Core.input.keyTap(Binding.deselect)){ if(Core.input.keyTap(Binding.deselect)){
player.setMineTile(null); player.setMineTile(null);
} }
@@ -236,12 +257,12 @@ public class DesktopInput extends InputHandler{
if(Core.input.keyRelease(Binding.schematic)){ if(Core.input.keyRelease(Binding.schematic)){
Schematic schem = schematics.create(schemX, schemY, rawCursorX, rawCursorY); Schematic schem = schematics.create(schemX, schemY, rawCursorX, rawCursorY);
__REMOVE__ = schem;
schematics.add(schem); schematics.add(schem);
useSchematic(schem);
} }
//TODO remove //TODO remove
if(Core.input.keyTap(KeyCode.T)){ if(Core.input.keyTap(KeyCode.V)){
ui.schematics.show(); ui.schematics.show();
} }
@@ -270,7 +291,10 @@ public class DesktopInput extends InputHandler{
if(Core.input.keyTap(Binding.select) && !Core.scene.hasMouse()){ if(Core.input.keyTap(Binding.select) && !Core.scene.hasMouse()){
BuildRequest req = getRequest(cursorX, cursorY); BuildRequest req = getRequest(cursorX, cursorY);
if(isPlacing()){ if(!selectRequests.isEmpty()){
flushRequests(selectRequests);
//selectRequests.clear();
}else if(isPlacing()){
selectX = cursorX; selectX = cursorX;
selectY = cursorY; selectY = cursorY;
lastLineX = cursorX; lastLineX = cursorX;
@@ -366,6 +390,7 @@ public class DesktopInput extends InputHandler{
mode = none; mode = none;
block = null; block = null;
sreq = null; sreq = null;
selectRequests.clear();
} }
} }
} }

View File

@@ -19,6 +19,7 @@ import io.anuke.mindustry.entities.*;
import io.anuke.mindustry.entities.effect.*; import io.anuke.mindustry.entities.effect.*;
import io.anuke.mindustry.entities.traits.BuilderTrait.*; import io.anuke.mindustry.entities.traits.BuilderTrait.*;
import io.anuke.mindustry.entities.type.*; import io.anuke.mindustry.entities.type.*;
import io.anuke.mindustry.game.*;
import io.anuke.mindustry.game.EventType.*; import io.anuke.mindustry.game.EventType.*;
import io.anuke.mindustry.game.Teams.*; import io.anuke.mindustry.game.Teams.*;
import io.anuke.mindustry.gen.*; import io.anuke.mindustry.gen.*;
@@ -219,6 +220,10 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
drawSelected(x, y, block, Pal.remove); drawSelected(x, y, block, Pal.remove);
} }
public void useSchematic(Schematic schem){
selectRequests.addAll(schematics.toRequests(schem, world.toTile(player.x), world.toTile(player.y)));
}
/** Returns the selection request that overlaps this position, or null. */ /** Returns the selection request that overlaps this position, or null. */
protected BuildRequest getRequest(int x, int y){ protected BuildRequest getRequest(int x, int y){
return getRequest(x, y, 1, null); return getRequest(x, y, 1, null);
@@ -310,7 +315,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
protected void flushSelectRequests(Array<BuildRequest> requests){ protected void flushSelectRequests(Array<BuildRequest> requests){
for(BuildRequest req : requests){ for(BuildRequest req : requests){
if(req.block != null && validPlace(req.x, req.y, req.block, req.rotation)){ if(req.block != null && validPlace(req.x, req.y, req.block, req.rotation)){
selectRequests.add(req); selectRequests.add(req.copy());
} }
} }
} }
@@ -318,7 +323,11 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
protected void flushRequests(Array<BuildRequest> requests){ protected void flushRequests(Array<BuildRequest> requests){
for(BuildRequest req : requests){ for(BuildRequest req : requests){
if(req.block != null && validPlace(req.x, req.y, req.block, req.rotation)){ if(req.block != null && validPlace(req.x, req.y, req.block, req.rotation)){
player.addBuildRequest(req); BuildRequest copy = req.copy();
if(copy.hasConfig && copy.block.posConfig){
copy.config = Pos.get(Pos.x(copy.config) + copy.x - copy.originalX, Pos.y(copy.config) + copy.y - copy.originalY);
}
player.addBuildRequest(copy);
} }
} }
} }

View File

@@ -243,7 +243,6 @@ public class MobileInput extends InputHandler implements GestureListener{
if(tile == null) continue; if(tile == null) continue;
request.animScale = Mathf.lerpDelta(request.animScale, 0f, 0.2f); request.animScale = Mathf.lerpDelta(request.animScale, 0f, 0.2f);
request.animInvalid = Mathf.lerpDelta(request.animInvalid, 0f, 0.2f);
if(request.breaking){ if(request.breaking){
drawSelected(request.x, request.y, tile.block(), Pal.remove); drawSelected(request.x, request.y, tile.block(), Pal.remove);
@@ -263,10 +262,8 @@ public class MobileInput extends InputHandler implements GestureListener{
if((!request.breaking && validPlace(tile.x, tile.y, request.block, request.rotation)) if((!request.breaking && validPlace(tile.x, tile.y, request.block, request.rotation))
|| (request.breaking && validBreak(tile.x, tile.y))){ || (request.breaking && validBreak(tile.x, tile.y))){
request.animScale = Mathf.lerpDelta(request.animScale, 1f, 0.2f); request.animScale = Mathf.lerpDelta(request.animScale, 1f, 0.2f);
request.animInvalid = Mathf.lerpDelta(request.animInvalid, 0f, 0.2f);
}else{ }else{
request.animScale = Mathf.lerpDelta(request.animScale, 0.6f, 0.1f); request.animScale = Mathf.lerpDelta(request.animScale, 0.6f, 0.1f);
request.animInvalid = Mathf.lerpDelta(request.animInvalid, 0.9f, 0.2f);
} }
Tmp.c1.set(Draw.getMixColor()); Tmp.c1.set(Draw.getMixColor());

View File

@@ -8,7 +8,7 @@ import io.anuke.mindustry.game.Schematics.*;
import io.anuke.mindustry.graphics.*; import io.anuke.mindustry.graphics.*;
import io.anuke.mindustry.ui.*; import io.anuke.mindustry.ui.*;
import static io.anuke.mindustry.Vars.schematics; import static io.anuke.mindustry.Vars.*;
public class SchematicsDialog extends FloatingDialog{ public class SchematicsDialog extends FloatingDialog{
@@ -40,7 +40,8 @@ public class SchematicsDialog extends FloatingDialog{
} }
}.setScaling(Scaling.fit).setName("border")); }.setScaling(Scaling.fit).setName("border"));
}, () -> { }, () -> {
control.input.useSchematic(s);
hide();
}).size(200f, 230f).pad(2).style(Styles.clearPartiali).get(); }).size(200f, 230f).pad(2).style(Styles.clearPartiali).get();
BorderImage image = sel.find("border"); BorderImage image = sel.find("border");

View File

@@ -87,6 +87,8 @@ public class Block extends BlockStorage{
public boolean configurable; public boolean configurable;
/** Whether this block consumes touchDown events when tapped. */ /** Whether this block consumes touchDown events when tapped. */
public boolean consumesTap; public boolean consumesTap;
/** Whether the config is positional and needs to be shifted. */
public boolean posConfig;
/** /**
* The color of this block when displayed on the minimap or map preview. * The color of this block when displayed on the minimap or map preview.
* Do not set manually! This is overriden when loading for most blocks. * Do not set manually! This is overriden when loading for most blocks.

View File

@@ -56,7 +56,7 @@ public class BuildBlock extends Block{
} }
@Remote(called = Loc.server) @Remote(called = Loc.server)
public static void onConstructFinish(Tile tile, Block block, int builderID, byte rotation, Team team){ public static void onConstructFinish(Tile tile, Block block, int builderID, byte rotation, Team team, boolean skipConfig){
if(tile == null) return; if(tile == null) return;
float healthf = tile.entity == null ? 1f : tile.entity.healthf(); float healthf = tile.entity == null ? 1f : tile.entity.healthf();
world.setBlock(tile, block, team, rotation); world.setBlock(tile, block, team, rotation);
@@ -70,8 +70,10 @@ public class BuildBlock extends Block{
if(!headless && builderID == player.id){ if(!headless && builderID == player.id){
//this is run delayed, since if this is called on the server, all clients need to recieve the onBuildFinish() //this is run delayed, since if this is called on the server, all clients need to recieve the onBuildFinish()
//event first before they can recieve the placed() event modification results //event first before they can recieve the placed() event modification results
if(!skipConfig){
Core.app.post(() -> tile.block().playerPlaced(tile)); Core.app.post(() -> tile.block().playerPlaced(tile));
} }
}
Core.app.post(() -> Events.fire(new BlockBuildEndEvent(tile, playerGroup.getByID(builderID), team, false))); Core.app.post(() -> Events.fire(new BlockBuildEndEvent(tile, playerGroup.getByID(builderID), team, false)));
Sounds.place.at(tile, Mathf.random(0.7f, 1.4f)); Sounds.place.at(tile, Mathf.random(0.7f, 1.4f));
} }
@@ -185,7 +187,7 @@ public class BuildBlock extends Block{
private float[] accumulator; private float[] accumulator;
private float[] totalAccumulator; private float[] totalAccumulator;
public boolean construct(Unit builder, @Nullable TileEntity core, float amount){ public boolean construct(Unit builder, @Nullable TileEntity core, float amount, boolean configured){
if(cblock == null){ if(cblock == null){
kill(); kill();
return false; return false;
@@ -208,7 +210,7 @@ public class BuildBlock extends Block{
} }
if(progress >= 1f || state.rules.infiniteResources){ if(progress >= 1f || state.rules.infiniteResources){
Call.onConstructFinish(tile, cblock, builderID, tile.rotation(), builder.getTeam()); Call.onConstructFinish(tile, cblock, builderID, tile.rotation(), builder.getTeam(), configured);
return true; return true;
} }
return false; return false;

View File

@@ -37,6 +37,7 @@ public class ItemBridge extends Block{
layer = Layer.power; layer = Layer.power;
expanded = true; expanded = true;
itemCapacity = 10; itemCapacity = 10;
posConfig = true;
configurable = true; configurable = true;
hasItems = true; hasItems = true;
unloadable = false; unloadable = false;
@@ -385,11 +386,6 @@ public class ItemBridge extends Block{
return link; return link;
} }
@Override
public boolean posConfig(){
return true;
}
@Override @Override
public void write(DataOutput stream) throws IOException{ public void write(DataOutput stream) throws IOException{
super.write(stream); super.write(stream);

View File

@@ -36,6 +36,7 @@ public class MassDriver extends Block{
super(name); super(name);
update = true; update = true;
solid = true; solid = true;
posConfig = true;
configurable = true; configurable = true;
hasItems = true; hasItems = true;
layer = Layer.turret; layer = Layer.turret;
@@ -319,11 +320,6 @@ public class MassDriver extends Block{
return link; return link;
} }
@Override
public boolean posConfig(){
return true;
}
@Override @Override
public void write(DataOutput stream) throws IOException{ public void write(DataOutput stream) throws IOException{
super.write(stream); super.write(stream);

View File

@@ -1,3 +1,3 @@
org.gradle.daemon=true org.gradle.daemon=true
org.gradle.jvmargs=-Xms256m -Xmx1024m org.gradle.jvmargs=-Xms256m -Xmx1024m
archash=7f4239e462c07fb3d76a18262cff91dd877df5cc archash=795ded7ccae9aeb15ee480e3b9f6d6af57148ea0