mirror of
https://github.com/Anuken/Mindustry.git
synced 2025-03-13 19:39:04 +07:00
Functional desktop schematic placement
This commit is contained in:
parent
61d15782d0
commit
30bcfb6d5e
@ -104,7 +104,7 @@ public interface BuilderTrait extends Entity, TeamTrait{
|
||||
if(current.breaking){
|
||||
entity.deconstruct(unit, core, 1f / entity.buildCost * Time.delta() * getBuildPower(tile) * state.rules.buildSpeedMultiplier);
|
||||
}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){
|
||||
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 BuildRequest{
|
||||
/** Position and rotation of this request. */
|
||||
public int x, y, rotation;
|
||||
/** Block being placed. If null, this is a breaking request.*/
|
||||
public @Nullable Block block;
|
||||
/** Whether this is a break request.*/
|
||||
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;
|
||||
/** Config int. Not used unless hasConfig is true.*/
|
||||
public int config;
|
||||
/** Original position, only used in schematics.*/
|
||||
public int originalX, originalY;
|
||||
|
||||
/** Last progress.*/
|
||||
public float progress;
|
||||
/** Whether construction has started for this request.*/
|
||||
public boolean initialized;
|
||||
|
||||
//animation variables
|
||||
/** Visual scale. Used only for rendering.*/
|
||||
public float animScale = 0f;
|
||||
public float animInvalid;
|
||||
|
||||
/** This creates a build request. */
|
||||
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){
|
||||
if(breaking){
|
||||
return rect.set(-100f, -100f, 0f, 0f);
|
||||
|
@ -1,5 +1,6 @@
|
||||
package io.anuke.mindustry.entities.type;
|
||||
|
||||
import io.anuke.mindustry.*;
|
||||
import io.anuke.mindustry.entities.EntityGroup;
|
||||
import io.anuke.mindustry.entities.traits.Entity;
|
||||
|
||||
@ -14,6 +15,14 @@ public abstract class BaseEntity implements Entity{
|
||||
id = lastid++;
|
||||
}
|
||||
|
||||
public int tileX(){
|
||||
return Vars.world.toTile(x);
|
||||
}
|
||||
|
||||
public int tileY(){
|
||||
return Vars.world.toTile(y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getID(){
|
||||
return id;
|
||||
|
@ -236,11 +236,6 @@ public class TileEntity extends BaseEntity implements TargetTrait, HealthTrait{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** @return whether the config is a position that should be translated.*/
|
||||
public boolean posConfig(){
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removed(){
|
||||
if(sound != null){
|
||||
|
@ -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. */
|
||||
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.*/
|
||||
@ -209,7 +209,7 @@ public class Schematics implements Loadable{
|
||||
|
||||
if(tile != null && tile.entity != null){
|
||||
int config = tile.entity.config();
|
||||
if(tile.entity.posConfig()){
|
||||
if(tile.block().posConfig){
|
||||
config = Pos.get(Pos.x(config) + offsetX, Pos.y(config) + offsetY);
|
||||
}
|
||||
|
||||
@ -240,7 +240,11 @@ public class Schematics implements Loadable{
|
||||
//region IO methods
|
||||
|
||||
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{
|
||||
@ -271,8 +275,6 @@ public class Schematics implements Loadable{
|
||||
blocks.put(i, block == null ? Blocks.air : block);
|
||||
}
|
||||
|
||||
Log.info(blocks);
|
||||
|
||||
int total = stream.readInt();
|
||||
Array<Stile> tiles = new Array<>(total);
|
||||
for(int i = 0; i < total; i++){
|
||||
|
@ -3,7 +3,6 @@ package io.anuke.mindustry.input;
|
||||
import io.anuke.arc.*;
|
||||
import io.anuke.arc.Graphics.*;
|
||||
import io.anuke.arc.Graphics.Cursor.*;
|
||||
import io.anuke.arc.graphics.*;
|
||||
import io.anuke.arc.graphics.g2d.*;
|
||||
import io.anuke.arc.input.*;
|
||||
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.game.EventType.*;
|
||||
import io.anuke.mindustry.game.*;
|
||||
import io.anuke.mindustry.game.Schematics.*;
|
||||
import io.anuke.mindustry.gen.*;
|
||||
import io.anuke.mindustry.graphics.*;
|
||||
import io.anuke.mindustry.ui.*;
|
||||
@ -30,7 +28,7 @@ public class DesktopInput extends InputHandler{
|
||||
/** Position where the player started dragging a line. */
|
||||
private int selectX, selectY, schemX, schemY;
|
||||
/** Last known line positions.*/
|
||||
private int lastLineX, lastLineY;
|
||||
private int lastLineX, lastLineY, schematicX, schematicY;
|
||||
/** Whether selecting mode is active. */
|
||||
private PlaceMode mode;
|
||||
/** Animation scale for line. */
|
||||
@ -40,8 +38,6 @@ public class DesktopInput extends InputHandler{
|
||||
/** Whether player is currently deleting removal requests. */
|
||||
private boolean deleting = false;
|
||||
|
||||
private Schematic __REMOVE__;
|
||||
|
||||
@Override
|
||||
public void buildUI(Group group){
|
||||
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){
|
||||
boolean valid = validPlace(sreq.x, sreq.y, sreq.block, sreq.rotation, sreq);
|
||||
if(sreq.block.rotate){
|
||||
@ -108,13 +110,6 @@ public class DesktopInput extends InputHandler{
|
||||
}
|
||||
|
||||
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
|
||||
@ -154,6 +149,10 @@ public class DesktopInput extends InputHandler{
|
||||
mode = none;
|
||||
}
|
||||
|
||||
if(mode != none){
|
||||
selectRequests.clear();
|
||||
}
|
||||
|
||||
if(player.isShooting && !canShoot()){
|
||||
player.isShooting = false;
|
||||
}
|
||||
@ -182,7 +181,7 @@ public class DesktopInput extends InputHandler{
|
||||
|
||||
cursorType = cursor.block().getCursor(cursor);
|
||||
|
||||
if(isPlacing()){
|
||||
if(isPlacing() || !selectRequests.isEmpty()){
|
||||
cursorType = SystemCursor.hand;
|
||||
}
|
||||
|
||||
@ -210,6 +209,16 @@ public class DesktopInput extends InputHandler{
|
||||
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
|
||||
public boolean isBreaking(){
|
||||
return mode == breaking;
|
||||
@ -221,6 +230,18 @@ public class DesktopInput extends InputHandler{
|
||||
int cursorY = tileY(Core.input.mouseY());
|
||||
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)){
|
||||
player.setMineTile(null);
|
||||
}
|
||||
@ -236,12 +257,12 @@ public class DesktopInput extends InputHandler{
|
||||
|
||||
if(Core.input.keyRelease(Binding.schematic)){
|
||||
Schematic schem = schematics.create(schemX, schemY, rawCursorX, rawCursorY);
|
||||
__REMOVE__ = schem;
|
||||
schematics.add(schem);
|
||||
useSchematic(schem);
|
||||
}
|
||||
|
||||
//TODO remove
|
||||
if(Core.input.keyTap(KeyCode.T)){
|
||||
if(Core.input.keyTap(KeyCode.V)){
|
||||
ui.schematics.show();
|
||||
}
|
||||
|
||||
@ -270,7 +291,10 @@ public class DesktopInput extends InputHandler{
|
||||
if(Core.input.keyTap(Binding.select) && !Core.scene.hasMouse()){
|
||||
BuildRequest req = getRequest(cursorX, cursorY);
|
||||
|
||||
if(isPlacing()){
|
||||
if(!selectRequests.isEmpty()){
|
||||
flushRequests(selectRequests);
|
||||
//selectRequests.clear();
|
||||
}else if(isPlacing()){
|
||||
selectX = cursorX;
|
||||
selectY = cursorY;
|
||||
lastLineX = cursorX;
|
||||
@ -366,6 +390,7 @@ public class DesktopInput extends InputHandler{
|
||||
mode = none;
|
||||
block = null;
|
||||
sreq = null;
|
||||
selectRequests.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ import io.anuke.mindustry.entities.*;
|
||||
import io.anuke.mindustry.entities.effect.*;
|
||||
import io.anuke.mindustry.entities.traits.BuilderTrait.*;
|
||||
import io.anuke.mindustry.entities.type.*;
|
||||
import io.anuke.mindustry.game.*;
|
||||
import io.anuke.mindustry.game.EventType.*;
|
||||
import io.anuke.mindustry.game.Teams.*;
|
||||
import io.anuke.mindustry.gen.*;
|
||||
@ -219,6 +220,10 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
|
||||
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. */
|
||||
protected BuildRequest getRequest(int x, int y){
|
||||
return getRequest(x, y, 1, null);
|
||||
@ -310,7 +315,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
|
||||
protected void flushSelectRequests(Array<BuildRequest> requests){
|
||||
for(BuildRequest req : requests){
|
||||
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){
|
||||
for(BuildRequest req : requests){
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -243,7 +243,6 @@ public class MobileInput extends InputHandler implements GestureListener{
|
||||
if(tile == null) continue;
|
||||
|
||||
request.animScale = Mathf.lerpDelta(request.animScale, 0f, 0.2f);
|
||||
request.animInvalid = Mathf.lerpDelta(request.animInvalid, 0f, 0.2f);
|
||||
|
||||
if(request.breaking){
|
||||
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))
|
||||
|| (request.breaking && validBreak(tile.x, tile.y))){
|
||||
request.animScale = Mathf.lerpDelta(request.animScale, 1f, 0.2f);
|
||||
request.animInvalid = Mathf.lerpDelta(request.animInvalid, 0f, 0.2f);
|
||||
}else{
|
||||
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());
|
||||
|
@ -8,7 +8,7 @@ import io.anuke.mindustry.game.Schematics.*;
|
||||
import io.anuke.mindustry.graphics.*;
|
||||
import io.anuke.mindustry.ui.*;
|
||||
|
||||
import static io.anuke.mindustry.Vars.schematics;
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class SchematicsDialog extends FloatingDialog{
|
||||
|
||||
@ -40,7 +40,8 @@ public class SchematicsDialog extends FloatingDialog{
|
||||
}
|
||||
}.setScaling(Scaling.fit).setName("border"));
|
||||
}, () -> {
|
||||
|
||||
control.input.useSchematic(s);
|
||||
hide();
|
||||
}).size(200f, 230f).pad(2).style(Styles.clearPartiali).get();
|
||||
|
||||
BorderImage image = sel.find("border");
|
||||
|
@ -87,6 +87,8 @@ public class Block extends BlockStorage{
|
||||
public boolean configurable;
|
||||
/** Whether this block consumes touchDown events when tapped. */
|
||||
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.
|
||||
* Do not set manually! This is overriden when loading for most blocks.
|
||||
|
@ -56,7 +56,7 @@ public class BuildBlock extends Block{
|
||||
}
|
||||
|
||||
@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;
|
||||
float healthf = tile.entity == null ? 1f : tile.entity.healthf();
|
||||
world.setBlock(tile, block, team, rotation);
|
||||
@ -70,8 +70,10 @@ public class BuildBlock extends Block{
|
||||
if(!headless && builderID == player.id){
|
||||
//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
|
||||
if(!skipConfig){
|
||||
Core.app.post(() -> tile.block().playerPlaced(tile));
|
||||
}
|
||||
}
|
||||
Core.app.post(() -> Events.fire(new BlockBuildEndEvent(tile, playerGroup.getByID(builderID), team, false)));
|
||||
Sounds.place.at(tile, Mathf.random(0.7f, 1.4f));
|
||||
}
|
||||
@ -185,7 +187,7 @@ public class BuildBlock extends Block{
|
||||
private float[] accumulator;
|
||||
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){
|
||||
kill();
|
||||
return false;
|
||||
@ -208,7 +210,7 @@ public class BuildBlock extends Block{
|
||||
}
|
||||
|
||||
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 false;
|
||||
|
@ -37,6 +37,7 @@ public class ItemBridge extends Block{
|
||||
layer = Layer.power;
|
||||
expanded = true;
|
||||
itemCapacity = 10;
|
||||
posConfig = true;
|
||||
configurable = true;
|
||||
hasItems = true;
|
||||
unloadable = false;
|
||||
@ -385,11 +386,6 @@ public class ItemBridge extends Block{
|
||||
return link;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean posConfig(){
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(DataOutput stream) throws IOException{
|
||||
super.write(stream);
|
||||
|
@ -36,6 +36,7 @@ public class MassDriver extends Block{
|
||||
super(name);
|
||||
update = true;
|
||||
solid = true;
|
||||
posConfig = true;
|
||||
configurable = true;
|
||||
hasItems = true;
|
||||
layer = Layer.turret;
|
||||
@ -319,11 +320,6 @@ public class MassDriver extends Block{
|
||||
return link;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean posConfig(){
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(DataOutput stream) throws IOException{
|
||||
super.write(stream);
|
||||
|
@ -1,3 +1,3 @@
|
||||
org.gradle.daemon=true
|
||||
org.gradle.jvmargs=-Xms256m -Xmx1024m
|
||||
archash=7f4239e462c07fb3d76a18262cff91dd877df5cc
|
||||
archash=795ded7ccae9aeb15ee480e3b9f6d6af57148ea0
|
||||
|
Loading…
Reference in New Issue
Block a user