Partial 7.0 merge - API preview
This commit is contained in:
@@ -162,7 +162,7 @@ public class DesktopInput extends InputHandler{
|
||||
}
|
||||
lineRequests.each(this::drawOverRequest);
|
||||
}else if(isPlacing()){
|
||||
if(block.rotate){
|
||||
if(block.rotate && block.drawArrow){
|
||||
drawArrow(block, cursorX, cursorY, rotation);
|
||||
}
|
||||
Draw.color();
|
||||
@@ -225,17 +225,20 @@ public class DesktopInput extends InputHandler{
|
||||
if(!scene.hasMouse()){
|
||||
if(Core.input.keyDown(Binding.control) && Core.input.keyTap(Binding.select)){
|
||||
Unit on = selectedUnit();
|
||||
var build = selectedControlBuild();
|
||||
if(on != null){
|
||||
Call.unitControl(player, on);
|
||||
shouldShoot = false;
|
||||
}else if(build != null){
|
||||
Call.buildingControlSelect(player, build);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!player.dead() && !state.isPaused() && !(Core.scene.getKeyboardFocus() instanceof TextField)){
|
||||
if(!player.dead() && !state.isPaused() && !scene.hasField()){
|
||||
updateMovement(player.unit());
|
||||
|
||||
if(Core.input.keyDown(Binding.respawn) && !player.unit().spawnedByCore() && !scene.hasField()){
|
||||
if(Core.input.keyDown(Binding.respawn)){
|
||||
Call.unitClear(player);
|
||||
controlledType = null;
|
||||
}
|
||||
@@ -641,15 +644,17 @@ public class DesktopInput extends InputHandler{
|
||||
unit.moveAt(movement);
|
||||
}else{
|
||||
unit.moveAt(Tmp.v2.trns(unit.rotation, movement.len()));
|
||||
|
||||
//problem: actual unit rotation is controlled by velocity, but velocity is 1) unpredictable and 2) can be set to 0
|
||||
if(!movement.isZero()){
|
||||
unit.vel.rotateTo(movement.angle(), unit.type.rotateSpeed * Math.max(Time.delta, 1));
|
||||
unit.rotation = Angles.moveToward(unit.rotation, movement.angle(), unit.type.rotateSpeed * Math.max(Time.delta, 1));
|
||||
}
|
||||
}
|
||||
|
||||
unit.aim(unit.type.faceTarget ? Core.input.mouseWorld() : Tmp.v1.trns(unit.rotation, Core.input.mouseWorld().dst(unit)).add(unit.x, unit.y));
|
||||
unit.controlWeapons(true, player.shooting && !boosted);
|
||||
|
||||
player.boosting = Core.input.keyDown(Binding.boost) && !movement.isZero();
|
||||
player.boosting = Core.input.keyDown(Binding.boost);
|
||||
player.mouseX = unit.aimX();
|
||||
player.mouseY = unit.aimY();
|
||||
|
||||
|
||||
@@ -34,7 +34,6 @@ import mindustry.world.blocks.ConstructBlock.*;
|
||||
import mindustry.world.blocks.*;
|
||||
import mindustry.world.blocks.distribution.*;
|
||||
import mindustry.world.blocks.payloads.*;
|
||||
import mindustry.world.blocks.storage.CoreBlock.*;
|
||||
import mindustry.world.meta.*;
|
||||
|
||||
import java.util.*;
|
||||
@@ -44,6 +43,7 @@ import static mindustry.Vars.*;
|
||||
public abstract class InputHandler implements InputProcessor, GestureListener{
|
||||
/** Used for dropping items. */
|
||||
final static float playerSelectRange = mobile ? 17f : 11f;
|
||||
final static IntSeq removed = new IntSeq();
|
||||
/** Maximum line length. */
|
||||
final static int maxLength = 100;
|
||||
final static Rect r1 = new Rect(), r2 = new Rect();
|
||||
@@ -128,6 +128,27 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
|
||||
}
|
||||
}
|
||||
|
||||
@Remote(called = Loc.both, targets = Loc.both, forward = true, unreliable = true)
|
||||
public static void deletePlans(Player player, int[] positions){
|
||||
if(netServer.admins.allowAction(player, ActionType.removePlanned, a -> a.plans = positions)){
|
||||
|
||||
var it = state.teams.get(player.team()).blocks.iterator();
|
||||
//O(n^2) search here; no way around it
|
||||
outer:
|
||||
while(it.hasNext()){
|
||||
BlockPlan req = it.next();
|
||||
|
||||
for(int pos : positions){
|
||||
if(req.x == Point2.x(pos) && req.y == Point2.y(pos)){
|
||||
it.remove();
|
||||
continue outer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public static void createItemTransfer(Item item, int amount, float x, float y, Position to, Runnable done){
|
||||
Fx.itemTransfer.at(x, y, amount, item.color, to);
|
||||
if(done != null){
|
||||
@@ -331,6 +352,20 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
|
||||
Events.fire(new TapEvent(player, tile));
|
||||
}
|
||||
|
||||
@Remote(targets = Loc.both, called = Loc.both, forward = true)
|
||||
public static void buildingControlSelect(Player player, Building build){
|
||||
if(player == null || build == null || player.dead()) return;
|
||||
|
||||
//make sure player is allowed to control the building
|
||||
if(net.server() && !netServer.admins.allowAction(player, ActionType.buildSelect, action -> action.tile = build.tile)){
|
||||
throw new ValidateException(player, "Player cannot control a building.");
|
||||
}
|
||||
|
||||
if(player.team() == build.team && build.canControlSelect(player)){
|
||||
build.onControlSelect(player);
|
||||
}
|
||||
}
|
||||
|
||||
@Remote(targets = Loc.both, called = Loc.both, forward = true)
|
||||
public static void unitControl(Player player, @Nullable Unit unit){
|
||||
if(player == null) return;
|
||||
@@ -341,16 +376,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
|
||||
}
|
||||
|
||||
//clear player unit when they possess a core
|
||||
if(unit instanceof BlockUnitc block && block.tile() instanceof CoreBuild build){
|
||||
Fx.spawn.at(player);
|
||||
if(net.client()){
|
||||
control.input.controlledType = null;
|
||||
}
|
||||
|
||||
player.clearUnit();
|
||||
player.deathTimer = Player.deathDelay + 1f;
|
||||
build.requestSpawn(player);
|
||||
}else if(unit == null){ //just clear the unit (is this used?)
|
||||
if(unit == null){ //just clear the unit (is this used?)
|
||||
player.clearUnit();
|
||||
//make sure it's AI controlled, so players can't overwrite each other
|
||||
}else if(unit.isAI() && unit.team == player.team() && !unit.dead){
|
||||
@@ -369,8 +395,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
|
||||
|
||||
@Remote(targets = Loc.both, called = Loc.both, forward = true)
|
||||
public static void unitClear(Player player){
|
||||
//no free core teleports?
|
||||
if(player == null || !player.dead() && player.unit().spawnedByCore) return;
|
||||
if(player == null) return;
|
||||
|
||||
Fx.spawn.at(player);
|
||||
player.clearUnit();
|
||||
@@ -379,19 +404,19 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
|
||||
|
||||
@Remote(targets = Loc.both, called = Loc.server, forward = true)
|
||||
public static void unitCommand(Player player){
|
||||
if(player == null || player.dead() || !(player.unit() instanceof Commanderc commander)) return;
|
||||
if(player == null || player.dead() || (player.unit() == null)) return;
|
||||
|
||||
//make sure player is allowed to make the command
|
||||
if(net.server() && !netServer.admins.allowAction(player, ActionType.command, action -> {})){
|
||||
throw new ValidateException(player, "Player cannot command a unit.");
|
||||
}
|
||||
|
||||
if(commander.isCommanding()){
|
||||
commander.clearCommand();
|
||||
}else if(player.unit().type.commandLimit > 0 && player.unit().type.commandRadius > 0){
|
||||
if(player.unit().isCommanding()){
|
||||
player.unit().clearCommand();
|
||||
}else if(player.unit().type.commandLimit > 0){
|
||||
|
||||
//TODO try out some other formations
|
||||
commander.commandNearby(new CircleFormation());
|
||||
player.unit().commandNearby(new CircleFormation());
|
||||
Fx.commandSend.at(player, player.unit().type.commandRadius);
|
||||
}
|
||||
|
||||
@@ -530,7 +555,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
|
||||
|
||||
public boolean requestMatches(BuildPlan request){
|
||||
Tile tile = world.tile(request.x, request.y);
|
||||
return tile != null && tile.build instanceof ConstructBuild cons && cons.cblock == request.block;
|
||||
return tile != null && tile.build instanceof ConstructBuild cons && cons.current == request.block;
|
||||
}
|
||||
|
||||
public void drawBreaking(int x, int y){
|
||||
@@ -571,6 +596,8 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
|
||||
int ox = schemOriginX(), oy = schemOriginY();
|
||||
|
||||
requests.each(req -> {
|
||||
if(req.breaking) return;
|
||||
|
||||
req.pointConfig(p -> {
|
||||
int cx = p.x, cy = p.y;
|
||||
int lx = cx;
|
||||
@@ -605,6 +632,8 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
|
||||
int origin = (x ? schemOriginX() : schemOriginY()) * tilesize;
|
||||
|
||||
requests.each(req -> {
|
||||
if(req.breaking) return;
|
||||
|
||||
float value = -((x ? req.x : req.y) * tilesize - origin + req.block.offset) + origin;
|
||||
|
||||
if(x){
|
||||
@@ -840,15 +869,23 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
|
||||
}
|
||||
}
|
||||
|
||||
removed.clear();
|
||||
|
||||
//remove blocks to rebuild
|
||||
Iterator<BlockPlan> broken = state.teams.get(player.team()).blocks.iterator();
|
||||
while(broken.hasNext()){
|
||||
BlockPlan req = broken.next();
|
||||
Block block = content.block(req.block);
|
||||
if(block.bounds(req.x, req.y, Tmp.r2).overlaps(Tmp.r1)){
|
||||
removed.add(Point2.pack(req.x, req.y));
|
||||
broken.remove();
|
||||
}
|
||||
}
|
||||
|
||||
//TODO array may be too large?
|
||||
if(removed.size > 0 && net.active()){
|
||||
Call.deletePlans(player, removed.toArray());
|
||||
}
|
||||
}
|
||||
|
||||
protected void updateLine(int x1, int y1, int x2, int y2){
|
||||
@@ -1041,6 +1078,14 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
|
||||
return null;
|
||||
}
|
||||
|
||||
public @Nullable Building selectedControlBuild(){
|
||||
Building build = world.buildWorld(Core.input.mouseWorld().x, Core.input.mouseWorld().y);
|
||||
if(build != null && !player.dead() && build.canControlSelect(player) && build.team == player.team()){
|
||||
return build;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void remove(){
|
||||
Core.input.removeProcessor(this);
|
||||
frag.remove();
|
||||
@@ -1218,13 +1263,15 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
|
||||
line.x = point.x;
|
||||
line.y = point.y;
|
||||
if(!overrideLineRotation || diagonal){
|
||||
int result = baseRotation;
|
||||
if(next != null){
|
||||
line.rotation = Tile.relativeTo(point.x, point.y, next.x, next.y);
|
||||
result = Tile.relativeTo(point.x, point.y, next.x, next.y);
|
||||
}else if(block.conveyorPlacement && i > 0){
|
||||
Point2 prev = points.get(i - 1);
|
||||
line.rotation = Tile.relativeTo(prev.x, prev.y, point.x, point.y);
|
||||
}else{
|
||||
line.rotation = baseRotation;
|
||||
result = Tile.relativeTo(prev.x, prev.y, point.x, point.y);
|
||||
}
|
||||
if(result != -1){
|
||||
line.rotation = result;
|
||||
}
|
||||
}else{
|
||||
line.rotation = rotation;
|
||||
|
||||
@@ -59,20 +59,22 @@ public class MobileInput extends InputHandler implements GestureListener{
|
||||
/** Current place mode. */
|
||||
public PlaceMode mode = none;
|
||||
/** Whether no recipe was available when switching to break mode. */
|
||||
public Block lastBlock;
|
||||
public @Nullable Block lastBlock;
|
||||
/** Last placed request. Used for drawing block overlay. */
|
||||
public BuildPlan lastPlaced;
|
||||
public @Nullable BuildPlan lastPlaced;
|
||||
/** Down tracking for panning. */
|
||||
public boolean down = false;
|
||||
/** Whether manual shooting (point with finger) is enabled. */
|
||||
public boolean manualShooting = false;
|
||||
|
||||
/** Current thing being shot at. */
|
||||
public Teamc target;
|
||||
public @Nullable Teamc target;
|
||||
/** Payload target being moved to. Can be a position (for dropping), or a unit/block. */
|
||||
public Position payloadTarget;
|
||||
public @Nullable Position payloadTarget;
|
||||
/** Unit last tapped, or null if last tap was not on a unit. */
|
||||
public Unit unitTapped;
|
||||
public @Nullable Unit unitTapped;
|
||||
/** Control building last tapped. */
|
||||
public @Nullable Building buildingTapped;
|
||||
|
||||
//region utility methods
|
||||
|
||||
@@ -362,7 +364,7 @@ public class MobileInput extends InputHandler implements GestureListener{
|
||||
}
|
||||
|
||||
//draw last placed request
|
||||
if(!request.breaking && request == lastPlaced && request.block != null){
|
||||
if(!request.breaking && request == lastPlaced && request.block != null && request.block.drawArrow){
|
||||
Draw.mixcol();
|
||||
request.block.drawPlace(tile.x, tile.y, rotation, validPlace(tile.x, tile.y, request.block, rotation));
|
||||
}
|
||||
@@ -530,7 +532,7 @@ public class MobileInput extends InputHandler implements GestureListener{
|
||||
}else{
|
||||
Building build = world.buildWorld(pos.x, pos.y);
|
||||
|
||||
if(build != null && build.team == player.team() && pay.canPickup(build)){
|
||||
if(build != null && build.team == player.team() && (pay.canPickup(build) || build.getPayload() != null && pay.canPickupPayload(build.getPayload()))){
|
||||
payloadTarget = build;
|
||||
}else if(pay.hasPayload()){
|
||||
//drop off at position
|
||||
@@ -612,6 +614,8 @@ public class MobileInput extends InputHandler implements GestureListener{
|
||||
//control a unit/block detected on first tap of double-tap
|
||||
if(unitTapped != null){
|
||||
Call.unitControl(player, unitTapped);
|
||||
}else if(buildingTapped != null){
|
||||
Call.buildingControlSelect(player, buildingTapped);
|
||||
}else if(!tryBeginMine(cursor)){
|
||||
tileTapped(linked.build);
|
||||
}
|
||||
@@ -620,6 +624,7 @@ public class MobileInput extends InputHandler implements GestureListener{
|
||||
}
|
||||
|
||||
unitTapped = selectedUnit();
|
||||
buildingTapped = selectedControlBuild();
|
||||
//prevent mining if placing/breaking blocks
|
||||
if(!tryStopMine() && !canTapPlayer(worldx, worldy) && !tileTapped(linked.build) && mode == none && !Core.settings.getBool("doubletapmine")){
|
||||
tryBeginMine(cursor);
|
||||
@@ -885,7 +890,7 @@ public class MobileInput extends InputHandler implements GestureListener{
|
||||
if(payloadTarget instanceof Vec2 && pay.hasPayload()){
|
||||
//vec -> dropping something
|
||||
tryDropPayload();
|
||||
}else if(payloadTarget instanceof Building build && pay.canPickup(build)){
|
||||
}else if(payloadTarget instanceof Building build && build.team == unit.team){
|
||||
//building -> picking building up
|
||||
Call.requestBuildPayload(player, build);
|
||||
}else if(payloadTarget instanceof Unit other && pay.canPickup(other)){
|
||||
|
||||
@@ -169,6 +169,62 @@ public class Placement{
|
||||
plans.set(result);
|
||||
}
|
||||
|
||||
public static void calculateDuctBridges(Seq<BuildPlan> plans, DuctBridge bridge){
|
||||
//check for orthogonal placement + unlocked state
|
||||
if(!(plans.first().x == plans.peek().x || plans.first().y == plans.peek().y) || !bridge.unlockedNow()){
|
||||
return;
|
||||
}
|
||||
|
||||
Boolf<BuildPlan> placeable = plan -> (plan.placeable(player.team())) ||
|
||||
(plan.tile() != null && plan.tile().block() == plan.block); //don't count the same block as inaccessible
|
||||
|
||||
var result = plans1.clear();
|
||||
var team = player.team();
|
||||
var rot = plans.first().rotation;
|
||||
|
||||
outer:
|
||||
for(int i = 0; i < plans.size;){
|
||||
var cur = plans.get(i);
|
||||
result.add(cur);
|
||||
|
||||
//gap found
|
||||
if(i < plans.size - 1 && placeable.get(cur) && !placeable.get(plans.get(i + 1))){
|
||||
|
||||
//find the closest valid position within range
|
||||
for(int j = i + 1; j < plans.size; j++){
|
||||
var other = plans.get(j);
|
||||
|
||||
//out of range now, set to current position and keep scanning forward for next occurrence
|
||||
if(!bridge.positionsValid(cur.x, cur.y, other.x, other.y)){
|
||||
//add 'missed' conveyors
|
||||
for(int k = i + 1; k < j; k++){
|
||||
result.add(plans.get(k));
|
||||
}
|
||||
i = j;
|
||||
continue outer;
|
||||
}else if(other.placeable(team)){
|
||||
//found a link, assign bridges
|
||||
cur.block = bridge;
|
||||
other.block = bridge;
|
||||
|
||||
i = j;
|
||||
continue outer;
|
||||
}
|
||||
}
|
||||
|
||||
//if it got here, that means nothing was found. this likely means there's a bunch of stuff at the end; add it and bail out
|
||||
for(int j = i + 1; j < plans.size; j++){
|
||||
result.add(plans.get(j));
|
||||
}
|
||||
break;
|
||||
}else{
|
||||
i ++;
|
||||
}
|
||||
}
|
||||
|
||||
plans.set(result);
|
||||
}
|
||||
|
||||
private static float tileHeuristic(Tile tile, Tile other){
|
||||
Block block = control.input.block;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user