Added configurable block access validation
This commit is contained in:
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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){
|
||||
|
||||
@@ -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)));
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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.*;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user