From 68af32bc9f903dfb99aa895fdf02d6b11521ed8c Mon Sep 17 00:00:00 2001 From: Commodore64x Date: Sat, 19 May 2018 13:37:44 +1000 Subject: [PATCH] Added rollback into the admin menu, fixed a bug where players would crash upon trying to view their own logs on relog. --- core/assets/bundles/bundle.properties | 2 + .../io/anuke/mindustry/core/NetServer.java | 13 +++++ core/src/io/anuke/mindustry/core/UI.java | 2 + .../anuke/mindustry/net/Administration.java | 51 ++++++++++++++++++- core/src/io/anuke/mindustry/net/EditLog.java | 8 +-- .../src/io/anuke/mindustry/net/NetEvents.java | 7 +++ core/src/io/anuke/mindustry/net/Packets.java | 25 +++++++-- .../io/anuke/mindustry/net/Registrator.java | 1 + .../mindustry/ui/dialogs/RollbackDialog.java | 41 +++++++++++++++ .../ui/fragments/BlocksFragment.java | 9 ++-- .../ui/fragments/PlayerListFragment.java | 4 ++ .../anuke/mindustry/server/ServerControl.java | 44 +--------------- 12 files changed, 149 insertions(+), 58 deletions(-) create mode 100644 core/src/io/anuke/mindustry/ui/dialogs/RollbackDialog.java diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index 86e5af0127..8929473e30 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -70,6 +70,8 @@ text.server.bans=Bans text.server.bans.none=No banned players found! text.server.admins=Admins text.server.admins.none=No admins found! +text.server.rollback=Rollback +text.server.rollback.numberfield=Rollback Amount: text.server.add=Add Server text.server.delete=Are you sure you want to delete this server? text.server.hostname=Host: {0} diff --git a/core/src/io/anuke/mindustry/core/NetServer.java b/core/src/io/anuke/mindustry/core/NetServer.java index 08b46d282f..84ba7bc83c 100644 --- a/core/src/io/anuke/mindustry/core/NetServer.java +++ b/core/src/io/anuke/mindustry/core/NetServer.java @@ -355,6 +355,19 @@ public class NetServer extends Module{ packet.editlogs = admins.getEditLogs().get(packet.x + packet.y * world.width(), new Array<>()); Net.sendTo(id, packet, SendMode.udp); }); + + Net.handleServer(RollbackRequestPacket.class, (id, packet) -> { + Player player = connections.get(id); + + if(!player.isAdmin){ + Log.err("ACCESS DENIED: Player {0} / {1} attempted to perform a rollback without proper security access.", + player.name, Net.getConnection(player.clientid).address); + return; + } + + admins.rollbackWorld(packet.rollbackTimes); + Log.info("&lc{0} has rolled back the world {1} times.", player.name, packet.rollbackTimes); + }); } public void update(){ diff --git a/core/src/io/anuke/mindustry/core/UI.java b/core/src/io/anuke/mindustry/core/UI.java index fe28e973cd..d2c2fd83df 100644 --- a/core/src/io/anuke/mindustry/core/UI.java +++ b/core/src/io/anuke/mindustry/core/UI.java @@ -49,6 +49,7 @@ public class UI extends SceneModule{ public BansDialog bans; public AdminsDialog admins; public TraceDialog traces; + public RollbackDialog rollback; public ChangelogDialog changelog; public final MenuFragment menufrag = new MenuFragment(); @@ -160,6 +161,7 @@ public class UI extends SceneModule{ bans = new BansDialog(); admins = new AdminsDialog(); traces = new TraceDialog(); + rollback = new RollbackDialog(); build.begin(scene); diff --git a/core/src/io/anuke/mindustry/net/Administration.java b/core/src/io/anuke/mindustry/net/Administration.java index 762f454dc0..cd412e9c25 100644 --- a/core/src/io/anuke/mindustry/net/Administration.java +++ b/core/src/io/anuke/mindustry/net/Administration.java @@ -7,6 +7,7 @@ import com.badlogic.gdx.utils.ObjectMap; import com.badlogic.gdx.utils.TimeUtils; import io.anuke.mindustry.entities.Player; import io.anuke.mindustry.world.Block; +import io.anuke.mindustry.world.Placement; import io.anuke.mindustry.world.blocks.types.BlockPart; import io.anuke.mindustry.world.blocks.types.Floor; import io.anuke.mindustry.world.blocks.types.Rock; @@ -66,15 +67,61 @@ public class Administration { public void logEdit(int x, int y, Player player, Block block, int rotation, EditLog.EditAction action) { if(block instanceof BlockPart || block instanceof Rock || block instanceof Floor || block instanceof StaticBlock) return; if(editLogs.containsKey(x + y * world.width())) { - editLogs.get(x + y * world.width()).add(new EditLog(player, block, rotation, action)); + editLogs.get(x + y * world.width()).add(new EditLog(player.name, block, rotation, action)); } else { Array logs = new Array<>(); - logs.add(new EditLog(player, block, rotation, action)); + logs.add(new EditLog(player.name, block, rotation, action)); editLogs.put(x + y * world.width(), logs); } } + public void rollbackWorld(int rollbackTimes) { + for(IntMap.Entry> editLog : editLogs.entries()) { + int coords = editLog.key; + Array logs = editLog.value; + + for(int i = 0; i < rollbackTimes; i++) { + + EditLog log = logs.get(logs.size - 1); + + int x = coords % world.width(); + int y = coords / world.width(); + Block result = log.block; + int rotation = log.rotation; + + if(log.action == EditLog.EditAction.PLACE) { + Placement.breakBlock(x, y, false, false); + + Packets.BreakPacket packet = new Packets.BreakPacket(); + packet.x = (short) x; + packet.y = (short) y; + packet.playerid = 0; + + Net.send(packet, Net.SendMode.tcp); + } + else if(log.action == EditLog.EditAction.BREAK) { + Placement.placeBlock(x, y, result, rotation, false, false); + + Packets.PlacePacket packet = new Packets.PlacePacket(); + packet.x = (short) x; + packet.y = (short) y; + packet.rotation = (byte) rotation; + packet.playerid = 0; + packet.block = result.id; + + Net.send(packet, Net.SendMode.tcp); + } + + logs.removeIndex(logs.size - 1); + if(logs.size == 0) { + editLogs.remove(coords); + break; + } + } + } + } + public boolean validateBreak(String id, String ip){ if(!isAntiGrief() || isAdmin(id, ip)) return true; diff --git a/core/src/io/anuke/mindustry/net/EditLog.java b/core/src/io/anuke/mindustry/net/EditLog.java index 2c8b0f76bc..e9bbeec043 100644 --- a/core/src/io/anuke/mindustry/net/EditLog.java +++ b/core/src/io/anuke/mindustry/net/EditLog.java @@ -4,20 +4,20 @@ import io.anuke.mindustry.entities.Player; import io.anuke.mindustry.world.Block; public class EditLog { - public Player player; + public String playername; public Block block; public int rotation; public EditAction action; - EditLog(Player player, Block block, int rotation, EditAction action) { - this.player = player; + EditLog(String playername, Block block, int rotation, EditAction action) { + this.playername = playername; this.block = block; this.rotation = rotation; this.action = action; } public String info() { - return String.format("Player: %s, Block: %s, Rotation: %s, Edit Action: %s", player.name, block.name(), rotation, action.toString()); + return String.format("Player: %s, Block: %s, Rotation: %s, Edit Action: %s", playername, block.name(), rotation, action.toString()); } public enum EditAction { diff --git a/core/src/io/anuke/mindustry/net/NetEvents.java b/core/src/io/anuke/mindustry/net/NetEvents.java index bf4884c381..c9603e92fc 100644 --- a/core/src/io/anuke/mindustry/net/NetEvents.java +++ b/core/src/io/anuke/mindustry/net/NetEvents.java @@ -186,4 +186,11 @@ public class NetEvents { Net.send(packet, SendMode.udp); } + + public static void handleRollbackRequest(int rollbackTimes) { + RollbackRequestPacket packet = new RollbackRequestPacket(); + packet.rollbackTimes = rollbackTimes; + + Net.send(packet, SendMode.udp); + } } diff --git a/core/src/io/anuke/mindustry/net/Packets.java b/core/src/io/anuke/mindustry/net/Packets.java index efcdb31299..bd0b8b9d39 100644 --- a/core/src/io/anuke/mindustry/net/Packets.java +++ b/core/src/io/anuke/mindustry/net/Packets.java @@ -153,7 +153,8 @@ public class Packets { buffer.putShort((short)y); buffer.putInt(editlogs.size); for(EditLog value : editlogs) { - buffer.putInt(value.player.id); + buffer.put((byte)value.playername.getBytes().length); + buffer.put(value.playername.getBytes()); buffer.putInt(value.block.id); buffer.put((byte) value.rotation); buffer.put((byte) value.action.ordinal()); @@ -167,16 +168,34 @@ public class Packets { editlogs = new Array<>(); int arraySize = buffer.getInt(); for(int a = 0; a < arraySize; a ++) { - int playerid = buffer.getInt(); + byte length = buffer.get(); + byte[] bytes = new byte[length]; + buffer.get(bytes); + String name = new String(bytes); + int blockid = buffer.getInt(); int rotation = buffer.get(); int ordinal = buffer.get(); - editlogs.add(new EditLog(Vars.playerGroup.getByID(playerid), Block.getByID(blockid), rotation, EditLog.EditAction.values()[ordinal])); + editlogs.add(new EditLog(name, Block.getByID(blockid), rotation, EditLog.EditAction.values()[ordinal])); } } } + public static class RollbackRequestPacket implements Packet { + public int rollbackTimes; + + @Override + public void write(ByteBuffer buffer) { + buffer.putInt(rollbackTimes); + } + + @Override + public void read(ByteBuffer buffer) { + rollbackTimes = buffer.getInt(); + } + } + public static class PositionPacket implements Packet{ public byte[] data; diff --git a/core/src/io/anuke/mindustry/net/Registrator.java b/core/src/io/anuke/mindustry/net/Registrator.java index 65b83f0066..92d6eca4b8 100644 --- a/core/src/io/anuke/mindustry/net/Registrator.java +++ b/core/src/io/anuke/mindustry/net/Registrator.java @@ -18,6 +18,7 @@ public class Registrator { BreakPacket.class, StateSyncPacket.class, BlockLogRequestPacket.class, + RollbackRequestPacket.class, BlockSyncPacket.class, BulletPacket.class, EnemyDeathPacket.class, diff --git a/core/src/io/anuke/mindustry/ui/dialogs/RollbackDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/RollbackDialog.java new file mode 100644 index 0000000000..a581c183a7 --- /dev/null +++ b/core/src/io/anuke/mindustry/ui/dialogs/RollbackDialog.java @@ -0,0 +1,41 @@ +package io.anuke.mindustry.ui.dialogs; + +import io.anuke.mindustry.net.NetEvents; +import io.anuke.ucore.scene.ui.Label; +import io.anuke.ucore.scene.ui.TextField; +import io.anuke.ucore.scene.ui.layout.Table; +import io.anuke.ucore.util.Strings; +import static io.anuke.mindustry.Vars.*; + +public class RollbackDialog extends FloatingDialog { + + public RollbackDialog(){ + super("$text.server.rollback"); + + setup(); + shown(this::setup); + } + + private void setup(){ + content().clear(); + buttons().clear(); + + if(gwt) return; + + content().row(); + content().add("$text.server.rollback.numberfield"); + + TextField field = content().addField("", t->{}).get(); + field.setTextFieldFilter((f, c) -> field.getText().length() < 4); + content().add(field).size(220f, 48f); + + content().row(); + buttons().defaults().size(50f, 50f).left().pad(2f); + buttons().addButton("$text.cancel", this::hide); + + buttons().addButton("$text.ok", () -> { + NetEvents.handleRollbackRequest(Integer.valueOf(field.getText())); + hide(); + }).disabled(b -> field.getText().isEmpty() || !Strings.canParsePostiveInt(field.getText())); + } +} diff --git a/core/src/io/anuke/mindustry/ui/fragments/BlocksFragment.java b/core/src/io/anuke/mindustry/ui/fragments/BlocksFragment.java index e8bd7b388a..67cb96cd38 100644 --- a/core/src/io/anuke/mindustry/ui/fragments/BlocksFragment.java +++ b/core/src/io/anuke/mindustry/ui/fragments/BlocksFragment.java @@ -5,11 +5,9 @@ import com.badlogic.gdx.graphics.Colors; import com.badlogic.gdx.graphics.g2d.TextureRegion; import com.badlogic.gdx.math.Interpolation; import com.badlogic.gdx.utils.Array; -import io.anuke.mindustry.Vars; import io.anuke.mindustry.core.GameState.State; import io.anuke.mindustry.input.InputHandler; import io.anuke.mindustry.net.EditLog; -import io.anuke.mindustry.net.NetEvents; import io.anuke.mindustry.resource.*; import io.anuke.mindustry.ui.dialogs.FloatingDialog; import io.anuke.mindustry.world.Block; @@ -364,14 +362,13 @@ public class BlocksFragment implements Fragment{ d.content().add(pane).grow(); - Array logs = Vars.currentEditLogs; - if(logs == null || logs.size == 0) { + if(currentEditLogs == null || currentEditLogs.size == 0) { table.add("$text.block.editlogsnotfound").left(); table.row(); } else { - for(int i = 0; i < logs.size; i++) { - EditLog log = logs.get(i); + for(int i = 0; i < currentEditLogs.size; i++) { + EditLog log = currentEditLogs.get(i); table.add("[gold]" + (i + 1) + ". [white]" + log.info()).left(); table.row(); } diff --git a/core/src/io/anuke/mindustry/ui/fragments/PlayerListFragment.java b/core/src/io/anuke/mindustry/ui/fragments/PlayerListFragment.java index a636ba545a..8e0aaf9323 100644 --- a/core/src/io/anuke/mindustry/ui/fragments/PlayerListFragment.java +++ b/core/src/io/anuke/mindustry/ui/fragments/PlayerListFragment.java @@ -58,6 +58,10 @@ public class PlayerListFragment implements Fragment{ new button("$text.server.admins", () -> { ui.admins.show(); }).padTop(-12).padBottom(-12).padRight(-12).fillY().cell.disabled(b -> Net.client()); + + new button("$text.server.rollback", () -> { + ui.rollback.show(); + }).padTop(-12).padBottom(-12).padRight(-12).fillY().cell.disabled(b -> !player.isAdmin); }}.pad(10f).growX().end(); }}.end(); diff --git a/server/src/io/anuke/mindustry/server/ServerControl.java b/server/src/io/anuke/mindustry/server/ServerControl.java index 3dbcb922a1..143e22b7ef 100644 --- a/server/src/io/anuke/mindustry/server/ServerControl.java +++ b/server/src/io/anuke/mindustry/server/ServerControl.java @@ -743,49 +743,7 @@ public class ServerControl extends Module { return; } - for(IntMap.Entry> editLog : editLogs.entries()) { - int coords = editLog.key; - Array logs = editLog.value; - - for(int i = 0; i < rollbackTimes; i++) { - - EditLog log = logs.get(logs.size - 1); - - int x = coords % world.width(); - int y = coords / world.width(); - Block result = log.block; - int rotation = log.rotation; - - if(log.action == EditLog.EditAction.PLACE) { - Placement.breakBlock(x, y, false, false); - - Packets.BreakPacket packet = new Packets.BreakPacket(); - packet.x = (short) x; - packet.y = (short) y; - packet.playerid = 0; - - Net.send(packet, Net.SendMode.tcp); - } - else if(log.action == EditLog.EditAction.BREAK) { - Placement.placeBlock(x, y, result, rotation, false, false); - - Packets.PlacePacket packet = new Packets.PlacePacket(); - packet.x = (short) x; - packet.y = (short) y; - packet.rotation = (byte) rotation; - packet.playerid = 0; - packet.block = result.id; - - Net.send(packet, Net.SendMode.tcp); - } - - logs.removeIndex(logs.size - 1); - if(logs.size == 0) { - editLogs.remove(coords); - break; - } - } - } + netServer.admins.rollbackWorld(rollbackTimes); info("Rollback done!"); }); }