Added configurable block access validation

This commit is contained in:
Anuken
2020-01-14 10:32:52 -05:00
parent a526eaa112
commit 68be77fa1d
12 changed files with 93 additions and 43 deletions

View File

@@ -230,7 +230,11 @@ public class NetServer implements ApplicationListener{
net.handleServer(InvokePacket.class, (con, packet) -> {
if(con.player == null) return;
RemoteReadServer.readPacket(packet.writeBuffer, packet.type, con.player);
try{
RemoteReadServer.readPacket(packet.writeBuffer, packet.type, con.player);
}catch(ValidateException e){
Log.debug("Validation failed for '{0}': {1}", e.player, e.getMessage());
}
});
registerCommands();
@@ -504,6 +508,7 @@ public class NetServer implements ApplicationListener{
player.isShooting = shooting;
player.isBuilding = building;
player.buildQueue().clear();
for(BuildRequest req : requests){
if(req == null) continue;
Tile tile = world.tile(req.x, req.y);
@@ -513,10 +518,23 @@ public class NetServer implements ApplicationListener{
continue;
}else if(!req.breaking && tile.block() == req.block && (!req.block.rotate || tile.rotation() == req.rotation)){
continue;
}else if(connection.rejectedRequests.contains(r -> r.breaking == req.breaking && r.x == req.x && r.y == req.y)){ //check if request was recently rejected, and skip it if so
continue;
}else if(!netServer.admins.allowAction(player, req.breaking ? ActionType.breakBlock : ActionType.placeBlock, tile, action -> { //make sure request is allowed by the server
action.block = req.block;
action.rotation = req.rotation;
action.config = req.config;
})){
//force the player to remove this request if that's not the case
Call.removeQueueBlock(player.con, req.x, req.y, req.breaking);
connection.rejectedRequests.add(req);
continue;
}
player.buildQueue().addLast(req);
}
connection.rejectedRequests.clear();
vector.set(x - player.getInterpolator().target.x, y - player.getInterpolator().target.y);
vector.limit(maxMove);

View File

@@ -1,5 +1,6 @@
package mindustry.entities;
/** A higher ordinal means a higher priority. Higher priority blocks will always get targeted over those of lower priority, regardless of distance. */
public enum TargetPriority{
base,
turret

View File

@@ -67,9 +67,9 @@ public interface BuilderTrait extends Entity, TeamTrait{
if(!(tile.block() instanceof BuildBlock)){
if(!current.initialized && 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);
Build.beginPlace(getTeam(), current.x, current.y, current.block, current.rotation);
}else if(!current.initialized && canCreateBlocks() && current.breaking && Build.validBreak(getTeam(), current.x, current.y)){
Call.beginBreak(getTeam(), current.x, current.y);
Build.beginBreak(getTeam(), current.x, current.y);
}else{
buildQueue().removeFirst();
return;
@@ -118,6 +118,14 @@ public interface BuilderTrait extends Entity, TeamTrait{
return request.stuck && !core.items.has(request.block.requirements);
}
default void removeRequest(int x, int y, boolean breaking){
//remove matching request
int idx = player.buildQueue().indexOf(req -> req.breaking == breaking && req.x == x && req.y == y);
if(idx != -1){
player.buildQueue().removeIndex(idx);
}
}
/** Returns the queue for storing build requests. */
Queue<BuildRequest> buildQueue();

View File

@@ -85,9 +85,15 @@ public class GlobalData{
if(amount > 0){
unlockContent(item);
}
amount = Math.max(amount, 0);
modified = true;
items.getAndIncrement(item, 0, amount);
state.stats.itemsDelivered.getAndIncrement(item, 0, amount);
//clamp overflow
if(items.get(item, 0) < 0) items.put(item, Integer.MAX_VALUE);
if(state.stats.itemsDelivered.get(item, 0) < 0) state.stats.itemsDelivered.put(item, Integer.MAX_VALUE);
}
public boolean hasItems(Array<ItemStack> stacks){

View File

@@ -1,8 +1,6 @@
package mindustry.input;
import arc.*;
import mindustry.annotations.Annotations.*;
import arc.struct.*;
import arc.func.*;
import arc.graphics.*;
import arc.graphics.g2d.*;
@@ -13,8 +11,10 @@ import arc.math.geom.*;
import arc.scene.*;
import arc.scene.event.*;
import arc.scene.ui.layout.*;
import arc.struct.*;
import arc.util.ArcAnnotate.*;
import arc.util.*;
import mindustry.annotations.Annotations.*;
import mindustry.content.*;
import mindustry.entities.*;
import mindustry.entities.effect.*;
@@ -27,12 +27,13 @@ import mindustry.gen.*;
import mindustry.graphics.*;
import mindustry.input.Placement.*;
import mindustry.net.*;
import mindustry.net.Administration.*;
import mindustry.type.*;
import mindustry.ui.fragments.*;
import mindustry.world.*;
import mindustry.world.blocks.*;
import mindustry.world.blocks.BuildBlock.*;
import mindustry.world.blocks.power.PowerNode;
import mindustry.world.blocks.power.*;
import java.util.*;
@@ -66,6 +67,11 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
//methods to override
@Remote(variants = Variant.one)
public static void removeQueueBlock(int x, int y, boolean breaking){
player.removeRequest(x, y, breaking);
}
@Remote(targets = Loc.client, called = Loc.server)
public static void dropItem(Player player, float angle){
if(net.server() && player.item().amount <= 0){
@@ -78,8 +84,9 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
@Remote(targets = Loc.both, called = Loc.server, forward = true, unreliable = true)
public static void rotateBlock(Player player, Tile tile, boolean direction){
if(net.server() && !Units.canInteract(player, tile)){
throw new ValidateException(player, "Player cannot drop an item.");
if(net.server() && (!Units.canInteract(player, tile) ||
!netServer.admins.allowAction(player, ActionType.rotate, tile, action -> action.rotation = Mathf.mod(tile.rotation() + Mathf.sign(direction), 4)))){
throw new ValidateException(player, "Player cannot rotate a block.");
}
tile.rotation(Mathf.mod(tile.rotation() + Mathf.sign(direction), 4));
@@ -93,7 +100,11 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
@Remote(targets = Loc.both, forward = true, called = Loc.server)
public static void transferInventory(Player player, Tile tile){
if(player == null || player.timer == null) return;
if(net.server() && (player.item().amount <= 0 || player.isTransferring|| !Units.canInteract(player, tile))){
if(net.server() && (player.item().amount <= 0 || player.isTransferring|| !Units.canInteract(player, tile) ||
!netServer.admins.allowAction(player, ActionType.depositItem, tile, action -> {
action.itemAmount = player.item().amount;
action.item = player.item().item;
}))){
throw new ValidateException(player, "Player cannot transfer an item.");
}
@@ -143,14 +154,18 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
@Remote(targets = Loc.both, called = Loc.server, forward = true)
public static void onTileTapped(Player player, Tile tile){
if(tile == null || player == null) return;
if(!Units.canInteract(player, tile)) return;
if(net.server() && (!Units.canInteract(player, tile) ||
!netServer.admins.allowAction(player, ActionType.tapTile, tile, action -> {}))) throw new ValidateException(player, "Player cannot tap a tile.");
tile.block().tapped(tile, player);
Core.app.post(() -> Events.fire(new TapEvent(tile, player)));
}
@Remote(targets = Loc.both, called = Loc.both, forward = true)
public static void onTileConfig(Player player, Tile tile, int value){
if(tile == null || !Units.canInteract(player, tile)) return;
if(tile == null) return;
if(net.server() && (!Units.canInteract(player, tile) ||
!netServer.admins.allowAction(player, ActionType.configure, tile, action -> action.config = value))) throw new ValidateException(player, "Player cannot configure a tile.");
tile.block().configured(tile, player, value);
Core.app.post(() -> Events.fire(new TapConfigEvent(tile, player, value)));
}

View File

@@ -529,6 +529,10 @@ public class Administration{
public @NonNull ActionType type;
public @NonNull Tile tile;
/** valid for block placement events only */
public @Nullable Block block;
public int rotation;
/** valid for configure and rotation-type events only. */
public int config;
@@ -554,7 +558,7 @@ public class Administration{
}
public enum ActionType{
breakBlock, placeBlock, rotate, configure, withdrawItem, depositItem
breakBlock, placeBlock, rotate, configure, tapTile, withdrawItem, depositItem
}
}

View File

@@ -114,12 +114,7 @@ public class ArcNetProvider implements NetProvider{
try{
net.handleServerReceived(k, object);
}catch(RuntimeException e){
if(e.getCause() instanceof ValidateException){
ValidateException v = (ValidateException)e.getCause();
Log.err("Validation failed: {0} ({1})", v.player.name, v.getMessage());
}else{
e.printStackTrace();
}
e.printStackTrace();
}catch(Exception e){
e.printStackTrace();
}

View File

@@ -1,7 +1,9 @@
package mindustry.net;
import arc.util.*;
import arc.struct.*;
import arc.util.ArcAnnotate.*;
import arc.util.*;
import mindustry.entities.traits.BuilderTrait.*;
import mindustry.entities.type.*;
import mindustry.gen.*;
import mindustry.net.Administration.*;
@@ -21,6 +23,8 @@ public abstract class NetConnection{
public int lastRecievedClientSnapshot = -1;
/** Timestamp of last recieved snapshot. */
public long lastRecievedClientTime;
/** Build requests that have been recently rejected. This is cleared every snapshot. */
public Array<BuildRequest> rejectedRequests = new Array<>();
public boolean hasConnected, hasBegunConnecting, hasDisconnected;
public float viewWidth, viewHeight, viewX, viewY;

View File

@@ -1,8 +1,6 @@
package mindustry.ui.fragments;
import arc.*;
import mindustry.annotations.Annotations.*;
import arc.struct.*;
import arc.func.*;
import arc.graphics.g2d.*;
import arc.input.*;
@@ -13,14 +11,18 @@ import arc.scene.actions.*;
import arc.scene.event.*;
import arc.scene.ui.*;
import arc.scene.ui.layout.*;
import arc.struct.*;
import arc.util.*;
import mindustry.annotations.Annotations.*;
import mindustry.core.GameState.*;
import mindustry.entities.*;
import mindustry.entities.type.*;
import mindustry.game.EventType.*;
import mindustry.gen.*;
import mindustry.net.Administration.*;
import mindustry.net.*;
import mindustry.type.*;
import mindustry.ui.Cicon;
import mindustry.ui.*;
import mindustry.world.*;
import static mindustry.Vars.*;
@@ -37,8 +39,14 @@ public class BlockInventoryFragment extends Fragment{
@Remote(called = Loc.server, targets = Loc.both, forward = true)
public static void requestItem(Player player, Tile tile, Item item, int amount){
if(player == null || tile == null || !tile.interactable(player.getTeam())) return;
if(!Units.canInteract(player, tile)) return;
amount = Mathf.clamp(amount, 0, player.getItemCapacity());
int fa = amount;
if(net.server() && (!Units.canInteract(player, tile) ||
!netServer.admins.allowAction(player, ActionType.withdrawItem, tile, action -> {
action.item = item;
action.itemAmount = fa;
}))) throw new ValidateException(player, "Player cannot request items.");
int removed = tile.block().removeStack(tile, item, amount);

View File

@@ -1,17 +1,15 @@
package mindustry.world;
import mindustry.annotations.Annotations.Loc;
import mindustry.annotations.Annotations.Remote;
import arc.Core;
import arc.Events;
import arc.math.Mathf;
import arc.*;
import arc.math.*;
import arc.math.geom.*;
import mindustry.content.Blocks;
import mindustry.entities.Units;
import mindustry.game.EventType.BlockBuildBeginEvent;
import mindustry.game.Team;
import mindustry.world.blocks.BuildBlock;
import mindustry.world.blocks.BuildBlock.BuildEntity;
import mindustry.annotations.Annotations.*;
import mindustry.content.*;
import mindustry.entities.*;
import mindustry.game.EventType.*;
import mindustry.game.*;
import mindustry.world.blocks.*;
import mindustry.world.blocks.BuildBlock.*;
import static mindustry.Vars.*;