Partial 7.0 merge - API preview

This commit is contained in:
Anuken
2021-06-02 11:08:08 -04:00
parent ea75a357ca
commit 28b235ef07
531 changed files with 12356 additions and 6286 deletions

View File

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

View File

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

View File

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

View File

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