Added edit logging and whole world rollback
This commit is contained in:
@@ -209,6 +209,8 @@ placemode.touch.name=touch
|
|||||||
placemode.cursor.name=cursor
|
placemode.cursor.name=cursor
|
||||||
text.blocks.extrainfo=[accent]extra block info:
|
text.blocks.extrainfo=[accent]extra block info:
|
||||||
text.blocks.blockinfo=Block Info
|
text.blocks.blockinfo=Block Info
|
||||||
|
text.blocks.editlogs=Edit Logs
|
||||||
|
text.block.editlogsnotfound=[red]There are no edit logs for this location.
|
||||||
text.blocks.powercapacity=Power Capacity
|
text.blocks.powercapacity=Power Capacity
|
||||||
text.blocks.powershot=Power/shot
|
text.blocks.powershot=Power/shot
|
||||||
text.blocks.powersecond=Power/second
|
text.blocks.powersecond=Power/second
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import com.badlogic.gdx.Application.ApplicationType;
|
|||||||
import com.badlogic.gdx.Gdx;
|
import com.badlogic.gdx.Gdx;
|
||||||
import com.badlogic.gdx.files.FileHandle;
|
import com.badlogic.gdx.files.FileHandle;
|
||||||
import com.badlogic.gdx.graphics.Color;
|
import com.badlogic.gdx.graphics.Color;
|
||||||
|
import com.badlogic.gdx.utils.IntMap;
|
||||||
import io.anuke.mindustry.core.*;
|
import io.anuke.mindustry.core.*;
|
||||||
import io.anuke.mindustry.entities.Bullet;
|
import io.anuke.mindustry.entities.Bullet;
|
||||||
import io.anuke.mindustry.entities.Player;
|
import io.anuke.mindustry.entities.Player;
|
||||||
@@ -11,6 +12,7 @@ import io.anuke.mindustry.entities.TileEntity;
|
|||||||
import io.anuke.mindustry.entities.effect.Shield;
|
import io.anuke.mindustry.entities.effect.Shield;
|
||||||
import io.anuke.mindustry.entities.enemies.Enemy;
|
import io.anuke.mindustry.entities.enemies.Enemy;
|
||||||
import io.anuke.mindustry.io.Platform;
|
import io.anuke.mindustry.io.Platform;
|
||||||
|
import io.anuke.mindustry.net.EditLog;
|
||||||
import io.anuke.mindustry.net.ClientDebug;
|
import io.anuke.mindustry.net.ClientDebug;
|
||||||
import io.anuke.mindustry.net.ServerDebug;
|
import io.anuke.mindustry.net.ServerDebug;
|
||||||
import io.anuke.ucore.UCore;
|
import io.anuke.ucore.UCore;
|
||||||
@@ -18,7 +20,7 @@ import io.anuke.ucore.entities.EffectEntity;
|
|||||||
import io.anuke.ucore.entities.Entities;
|
import io.anuke.ucore.entities.Entities;
|
||||||
import io.anuke.ucore.entities.EntityGroup;
|
import io.anuke.ucore.entities.EntityGroup;
|
||||||
import io.anuke.ucore.scene.ui.layout.Unit;
|
import io.anuke.ucore.scene.ui.layout.Unit;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
public class Vars{
|
public class Vars{
|
||||||
@@ -80,6 +82,8 @@ public class Vars{
|
|||||||
//whether to show block debug
|
//whether to show block debug
|
||||||
public static boolean showBlockDebug = false;
|
public static boolean showBlockDebug = false;
|
||||||
|
|
||||||
|
public static IntMap<ArrayList<EditLog>> editLogs = new IntMap<>();
|
||||||
|
|
||||||
public static boolean headless = false;
|
public static boolean headless = false;
|
||||||
|
|
||||||
public static float controllerMin = 0.25f;
|
public static float controllerMin = 0.25f;
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import com.badlogic.gdx.graphics.Color;
|
|||||||
import com.badlogic.gdx.utils.IntMap;
|
import com.badlogic.gdx.utils.IntMap;
|
||||||
import com.badlogic.gdx.utils.IntSet;
|
import com.badlogic.gdx.utils.IntSet;
|
||||||
import com.badlogic.gdx.utils.TimeUtils;
|
import com.badlogic.gdx.utils.TimeUtils;
|
||||||
|
import io.anuke.mindustry.Vars;
|
||||||
import io.anuke.mindustry.core.GameState.State;
|
import io.anuke.mindustry.core.GameState.State;
|
||||||
import io.anuke.mindustry.entities.Bullet;
|
import io.anuke.mindustry.entities.Bullet;
|
||||||
import io.anuke.mindustry.entities.BulletType;
|
import io.anuke.mindustry.entities.BulletType;
|
||||||
@@ -168,6 +169,10 @@ public class NetClient extends Module {
|
|||||||
ui.hudfrag.updateItems();
|
ui.hudfrag.updateItems();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Net.handleClient(BlockLogSyncPacket.class, packet -> {
|
||||||
|
Vars.editLogs = packet.editlogs;
|
||||||
|
});
|
||||||
|
|
||||||
Net.handleClient(PlacePacket.class, (packet) -> {
|
Net.handleClient(PlacePacket.class, (packet) -> {
|
||||||
Placement.placeBlock(packet.x, packet.y, Block.getByID(packet.block), packet.rotation, true, Timers.get("placeblocksound", 10));
|
Placement.placeBlock(packet.x, packet.y, Block.getByID(packet.block), packet.rotation, true, Timers.get("placeblocksound", 10));
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ import io.anuke.ucore.util.Timer;
|
|||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
import static io.anuke.mindustry.Vars.*;
|
import static io.anuke.mindustry.Vars.*;
|
||||||
|
|
||||||
public class NetServer extends Module{
|
public class NetServer extends Module{
|
||||||
@@ -34,6 +33,7 @@ public class NetServer extends Module{
|
|||||||
|
|
||||||
private final static int timerEntitySync = 0;
|
private final static int timerEntitySync = 0;
|
||||||
private final static int timerStateSync = 1;
|
private final static int timerStateSync = 1;
|
||||||
|
private final static int timerBlockLogSync = 2;
|
||||||
|
|
||||||
public final Administration admins = new Administration();
|
public final Administration admins = new Administration();
|
||||||
|
|
||||||
@@ -212,6 +212,7 @@ public class NetServer extends Module{
|
|||||||
|
|
||||||
Placement.placeBlock(packet.x, packet.y, block, packet.rotation, true, false);
|
Placement.placeBlock(packet.x, packet.y, block, packet.rotation, true, false);
|
||||||
|
|
||||||
|
admins.logEdit(packet.x, packet.y, connections.get(id), block, packet.rotation, EditLog.EditAction.PLACE);
|
||||||
admins.getTrace(Net.getConnection(id).address).lastBlockPlaced = block;
|
admins.getTrace(Net.getConnection(id).address).lastBlockPlaced = block;
|
||||||
admins.getTrace(Net.getConnection(id).address).totalBlocksPlaced ++;
|
admins.getTrace(Net.getConnection(id).address).totalBlocksPlaced ++;
|
||||||
admins.getInfo(admins.getTrace(Net.getConnection(id).address).uuid).totalBlockPlaced ++;
|
admins.getInfo(admins.getTrace(Net.getConnection(id).address).uuid).totalBlockPlaced ++;
|
||||||
@@ -236,6 +237,7 @@ public class NetServer extends Module{
|
|||||||
Block block = Placement.breakBlock(packet.x, packet.y, true, false);
|
Block block = Placement.breakBlock(packet.x, packet.y, true, false);
|
||||||
|
|
||||||
if(block != null) {
|
if(block != null) {
|
||||||
|
admins.logEdit(packet.x, packet.y, connections.get(id), block, tile.getRotation(), EditLog.EditAction.BREAK);
|
||||||
admins.getTrace(Net.getConnection(id).address).lastBlockBroken = block;
|
admins.getTrace(Net.getConnection(id).address).lastBlockBroken = block;
|
||||||
admins.getTrace(Net.getConnection(id).address).totalBlocksBroken++;
|
admins.getTrace(Net.getConnection(id).address).totalBlocksBroken++;
|
||||||
admins.getInfo(admins.getTrace(Net.getConnection(id).address).uuid).totalBlocksBroken ++;
|
admins.getInfo(admins.getTrace(Net.getConnection(id).address).uuid).totalBlocksBroken ++;
|
||||||
@@ -478,5 +480,12 @@ public class NetServer extends Module{
|
|||||||
|
|
||||||
Net.send(packet, SendMode.udp);
|
Net.send(packet, SendMode.udp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(timer.get(timerBlockLogSync, serverSyncTime)) {
|
||||||
|
BlockLogSyncPacket packet = new BlockLogSyncPacket();
|
||||||
|
packet.editlogs = admins.getEditLogs();
|
||||||
|
|
||||||
|
Net.send(packet, SendMode.udp);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -490,6 +490,12 @@ public class Renderer extends RendererModule{
|
|||||||
Draw.color();
|
Draw.color();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(Inputs.keyDown("block_logs")){
|
||||||
|
Draw.color(Colors.get("accent"));
|
||||||
|
Lines.crect(target.drawx(), target.drawy(), target.block().width * tilesize, target.block().height * tilesize);
|
||||||
|
Draw.color();
|
||||||
|
}
|
||||||
|
|
||||||
if(target.entity != null) {
|
if(target.entity != null) {
|
||||||
int bot = 0, top = 0;
|
int bot = 0, top = 0;
|
||||||
for (BlockBar bar : target.block().bars) {
|
for (BlockBar bar : target.block().bars) {
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ public class DefaultKeybinds {
|
|||||||
"rotate", new Axis(Input.SCROLL),
|
"rotate", new Axis(Input.SCROLL),
|
||||||
"toggle_menus", Input.C,
|
"toggle_menus", Input.C,
|
||||||
"block_info", Input.CONTROL_LEFT,
|
"block_info", Input.CONTROL_LEFT,
|
||||||
|
"block_logs", Input.I,
|
||||||
"player_list", Input.TAB,
|
"player_list", Input.TAB,
|
||||||
"chat", Input.ENTER,
|
"chat", Input.ENTER,
|
||||||
"chat_history_prev", Input.UP,
|
"chat_history_prev", Input.UP,
|
||||||
|
|||||||
@@ -108,6 +108,16 @@ public class DesktopInput extends InputHandler{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(recipe == null && !ui.hasMouse() && Inputs.keyDown("block_logs")) {
|
||||||
|
showCursor = true;
|
||||||
|
if(Inputs.keyTap("select")){
|
||||||
|
Timers.runTask(20f, () -> {
|
||||||
|
ui.hudfrag.blockfrag.showBlockLogs(getBlockX(), getBlockY());
|
||||||
|
Cursors.restoreCursor();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(target != null && target.block().isConfigurable(target)){
|
if(target != null && target.block().isConfigurable(target)){
|
||||||
showCursor = true;
|
showCursor = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,19 @@
|
|||||||
package io.anuke.mindustry.net;
|
package io.anuke.mindustry.net;
|
||||||
|
|
||||||
import com.badlogic.gdx.utils.Array;
|
import com.badlogic.gdx.utils.Array;
|
||||||
|
import com.badlogic.gdx.utils.IntMap;
|
||||||
import com.badlogic.gdx.utils.Json;
|
import com.badlogic.gdx.utils.Json;
|
||||||
import com.badlogic.gdx.utils.ObjectMap;
|
import com.badlogic.gdx.utils.ObjectMap;
|
||||||
import com.badlogic.gdx.utils.TimeUtils;
|
import com.badlogic.gdx.utils.TimeUtils;
|
||||||
|
import io.anuke.mindustry.entities.Player;
|
||||||
|
import io.anuke.mindustry.world.Block;
|
||||||
|
import io.anuke.mindustry.world.blocks.types.BlockPart;
|
||||||
|
import io.anuke.mindustry.world.blocks.types.Floor;
|
||||||
|
import io.anuke.mindustry.world.blocks.types.Rock;
|
||||||
|
import io.anuke.mindustry.world.blocks.types.StaticBlock;
|
||||||
import io.anuke.ucore.core.Settings;
|
import io.anuke.ucore.core.Settings;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import static io.anuke.mindustry.Vars.world;
|
||||||
|
|
||||||
public class Administration {
|
public class Administration {
|
||||||
public static final int defaultMaxBrokenBlocks = 15;
|
public static final int defaultMaxBrokenBlocks = 15;
|
||||||
@@ -15,6 +24,9 @@ public class Administration {
|
|||||||
private ObjectMap<String, PlayerInfo> playerInfo = new ObjectMap<>();
|
private ObjectMap<String, PlayerInfo> playerInfo = new ObjectMap<>();
|
||||||
/**Maps UUIDs to trace infos. This is wiped when a player logs off.*/
|
/**Maps UUIDs to trace infos. This is wiped when a player logs off.*/
|
||||||
private ObjectMap<String, TraceInfo> traceInfo = new ObjectMap<>();
|
private ObjectMap<String, TraceInfo> traceInfo = new ObjectMap<>();
|
||||||
|
/**Maps packed coordinates to logs for that coordinate */
|
||||||
|
private IntMap<ArrayList<EditLog>> editLogs = new IntMap<>();
|
||||||
|
|
||||||
private Array<String> bannedIPs = new Array<>();
|
private Array<String> bannedIPs = new Array<>();
|
||||||
|
|
||||||
public Administration(){
|
public Administration(){
|
||||||
@@ -48,6 +60,22 @@ public class Administration {
|
|||||||
Settings.save();
|
Settings.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IntMap<ArrayList<EditLog>> getEditLogs() {
|
||||||
|
return editLogs;
|
||||||
|
}
|
||||||
|
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ArrayList<EditLog> logs = new ArrayList<>();
|
||||||
|
logs.add(new EditLog(player, block, rotation, action));
|
||||||
|
editLogs.put(x + y * world.width(), logs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public boolean validateBreak(String id, String ip){
|
public boolean validateBreak(String id, String ip){
|
||||||
if(!isAntiGrief() || isAdmin(id, ip)) return true;
|
if(!isAntiGrief() || isAdmin(id, ip)) return true;
|
||||||
|
|
||||||
|
|||||||
41
core/src/io/anuke/mindustry/net/EditLog.java
Normal file
41
core/src/io/anuke/mindustry/net/EditLog.java
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
package io.anuke.mindustry.net;
|
||||||
|
|
||||||
|
import io.anuke.mindustry.entities.Player;
|
||||||
|
import io.anuke.mindustry.world.Block;
|
||||||
|
import static io.anuke.mindustry.Vars.playerGroup;
|
||||||
|
|
||||||
|
public class EditLog {
|
||||||
|
|
||||||
|
public Player player;
|
||||||
|
public Block block;
|
||||||
|
public int rotation;
|
||||||
|
public EditAction action;
|
||||||
|
|
||||||
|
EditLog(Player player, Block block, int rotation, EditAction action){
|
||||||
|
this.player = player;
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static EditLog valueOf(String string) {
|
||||||
|
String[] parts = string.split(":");
|
||||||
|
return new EditLog(playerGroup.getByID(Integer.valueOf(parts[0])),
|
||||||
|
Block.getByID(Integer.valueOf(parts[1])),
|
||||||
|
Integer.valueOf(parts[2]),
|
||||||
|
EditAction.valueOf(parts[3]));
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return String.format("%s:%s:%s:%s", player.id, block.id, rotation, action.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum EditAction{
|
||||||
|
PLACE,
|
||||||
|
BREAK;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package io.anuke.mindustry.net;
|
package io.anuke.mindustry.net;
|
||||||
|
|
||||||
import com.badlogic.gdx.utils.Base64Coder;
|
import com.badlogic.gdx.utils.Base64Coder;
|
||||||
|
import com.badlogic.gdx.utils.IntMap;
|
||||||
import com.badlogic.gdx.utils.reflect.ClassReflection;
|
import com.badlogic.gdx.utils.reflect.ClassReflection;
|
||||||
import com.badlogic.gdx.utils.reflect.ReflectionException;
|
import com.badlogic.gdx.utils.reflect.ReflectionException;
|
||||||
import io.anuke.mindustry.entities.Player;
|
import io.anuke.mindustry.entities.Player;
|
||||||
@@ -12,8 +13,8 @@ import io.anuke.mindustry.resource.Item;
|
|||||||
import io.anuke.mindustry.world.Block;
|
import io.anuke.mindustry.world.Block;
|
||||||
import io.anuke.ucore.entities.Entities;
|
import io.anuke.ucore.entities.Entities;
|
||||||
import io.anuke.ucore.entities.EntityGroup;
|
import io.anuke.ucore.entities.EntityGroup;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
/**Class for storing all packets.*/
|
/**Class for storing all packets.*/
|
||||||
public class Packets {
|
public class Packets {
|
||||||
@@ -140,6 +141,54 @@ public class Packets {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class BlockLogSyncPacket implements Packet {
|
||||||
|
public IntMap<ArrayList<EditLog>> editlogs;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(ByteBuffer buffer) {
|
||||||
|
int size = editlogs.size;
|
||||||
|
buffer.putInt(size);
|
||||||
|
for(IntMap.Entry<ArrayList<EditLog>> editlog :editlogs.entries()) {
|
||||||
|
|
||||||
|
String key = String.valueOf(editlog.key);
|
||||||
|
buffer.put((byte) key.getBytes().length);
|
||||||
|
buffer.put(key.getBytes());
|
||||||
|
|
||||||
|
ArrayList<EditLog> values = editlog.value;
|
||||||
|
buffer.putInt(values.size());
|
||||||
|
for(EditLog value : values) {
|
||||||
|
|
||||||
|
String rawValue = value.toString();
|
||||||
|
buffer.put((byte) rawValue.getBytes().length);
|
||||||
|
buffer.put(rawValue.getBytes());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void read(ByteBuffer buffer) {
|
||||||
|
editlogs = new IntMap<>();
|
||||||
|
int logssize = buffer.getInt();
|
||||||
|
for(int i = 0; i < logssize; i ++){
|
||||||
|
|
||||||
|
byte length = buffer.get();
|
||||||
|
byte[] bytes = new byte[length];
|
||||||
|
buffer.get(bytes);
|
||||||
|
Integer key = Integer.valueOf(new String(bytes));
|
||||||
|
|
||||||
|
ArrayList<EditLog> list = new ArrayList<>();
|
||||||
|
int arraySize = buffer.getInt();
|
||||||
|
for(int a = 0; a < arraySize; a ++) {
|
||||||
|
|
||||||
|
byte[] arraybytes = new byte[buffer.get()];
|
||||||
|
buffer.get(arraybytes);
|
||||||
|
list.add(EditLog.valueOf(new String(arraybytes)));
|
||||||
|
}
|
||||||
|
editlogs.put(key, list);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static class PositionPacket implements Packet{
|
public static class PositionPacket implements Packet{
|
||||||
public byte[] data;
|
public byte[] data;
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ public class Registrator {
|
|||||||
PlacePacket.class,
|
PlacePacket.class,
|
||||||
BreakPacket.class,
|
BreakPacket.class,
|
||||||
StateSyncPacket.class,
|
StateSyncPacket.class,
|
||||||
|
BlockLogSyncPacket.class,
|
||||||
BlockSyncPacket.class,
|
BlockSyncPacket.class,
|
||||||
BulletPacket.class,
|
BulletPacket.class,
|
||||||
EnemyDeathPacket.class,
|
EnemyDeathPacket.class,
|
||||||
@@ -44,7 +45,7 @@ public class Registrator {
|
|||||||
NetErrorPacket.class,
|
NetErrorPacket.class,
|
||||||
PlayerAdminPacket.class,
|
PlayerAdminPacket.class,
|
||||||
AdministerRequestPacket.class,
|
AdministerRequestPacket.class,
|
||||||
TracePacket.class,
|
TracePacket.class
|
||||||
};
|
};
|
||||||
private static ObjectIntMap<Class<?>> ids = new ObjectIntMap<>();
|
private static ObjectIntMap<Class<?>> ids = new ObjectIntMap<>();
|
||||||
|
|
||||||
|
|||||||
@@ -5,8 +5,10 @@ import com.badlogic.gdx.graphics.Colors;
|
|||||||
import com.badlogic.gdx.graphics.g2d.TextureRegion;
|
import com.badlogic.gdx.graphics.g2d.TextureRegion;
|
||||||
import com.badlogic.gdx.math.Interpolation;
|
import com.badlogic.gdx.math.Interpolation;
|
||||||
import com.badlogic.gdx.utils.Array;
|
import com.badlogic.gdx.utils.Array;
|
||||||
|
import io.anuke.mindustry.Vars;
|
||||||
import io.anuke.mindustry.core.GameState.State;
|
import io.anuke.mindustry.core.GameState.State;
|
||||||
import io.anuke.mindustry.input.InputHandler;
|
import io.anuke.mindustry.input.InputHandler;
|
||||||
|
import io.anuke.mindustry.net.EditLog;
|
||||||
import io.anuke.mindustry.resource.*;
|
import io.anuke.mindustry.resource.*;
|
||||||
import io.anuke.mindustry.ui.dialogs.FloatingDialog;
|
import io.anuke.mindustry.ui.dialogs.FloatingDialog;
|
||||||
import io.anuke.mindustry.world.Block;
|
import io.anuke.mindustry.world.Block;
|
||||||
@@ -24,7 +26,7 @@ import io.anuke.ucore.scene.ui.layout.Table;
|
|||||||
import io.anuke.ucore.util.Bundles;
|
import io.anuke.ucore.util.Bundles;
|
||||||
import io.anuke.ucore.util.Mathf;
|
import io.anuke.ucore.util.Mathf;
|
||||||
import io.anuke.ucore.util.Strings;
|
import io.anuke.ucore.util.Strings;
|
||||||
|
import java.util.ArrayList;
|
||||||
import static io.anuke.mindustry.Vars.*;
|
import static io.anuke.mindustry.Vars.*;
|
||||||
|
|
||||||
public class BlocksFragment implements Fragment{
|
public class BlocksFragment implements Fragment{
|
||||||
@@ -345,6 +347,45 @@ public class BlocksFragment implements Fragment{
|
|||||||
d.show();
|
d.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void showBlockLogs(int x, int y){
|
||||||
|
boolean wasPaused = state.is(State.paused);
|
||||||
|
state.set(State.paused);
|
||||||
|
|
||||||
|
FloatingDialog d = new FloatingDialog("$text.blocks.editlogs");
|
||||||
|
Table table = new Table();
|
||||||
|
table.defaults().pad(1f);
|
||||||
|
ScrollPane pane = new ScrollPane(table, "clear");
|
||||||
|
pane.setFadeScrollBars(false);
|
||||||
|
Table top = new Table();
|
||||||
|
top.left();
|
||||||
|
top.add("[accent]Edit logs for: "+ x + ", " + y);
|
||||||
|
table.add(top).fill().left();
|
||||||
|
table.row();
|
||||||
|
|
||||||
|
d.content().add(pane).grow();
|
||||||
|
|
||||||
|
ArrayList<EditLog> logs = Vars.editLogs.get(x + y * world.width());
|
||||||
|
if(logs == null || logs.isEmpty()) {
|
||||||
|
table.add("$text.block.editlogsnotfound").left();
|
||||||
|
table.row();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for(int i = 0; i < logs.size(); i++) {
|
||||||
|
EditLog log = logs.get(i);
|
||||||
|
table.add("[gold]" + (i + 1) + ". [white]" + log.info()).left();
|
||||||
|
table.row();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
d.buttons().addButton("$text.ok", () -> {
|
||||||
|
if(!wasPaused)
|
||||||
|
state.set(State.playing);
|
||||||
|
d.hide();
|
||||||
|
}).size(110, 50).pad(10f);
|
||||||
|
|
||||||
|
d.show();
|
||||||
|
}
|
||||||
|
|
||||||
public void updateItems(){
|
public void updateItems(){
|
||||||
|
|
||||||
itemtable.clear();
|
itemtable.clear();
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package io.anuke.mindustry.server;
|
|||||||
import com.badlogic.gdx.ApplicationLogger;
|
import com.badlogic.gdx.ApplicationLogger;
|
||||||
import com.badlogic.gdx.Gdx;
|
import com.badlogic.gdx.Gdx;
|
||||||
import com.badlogic.gdx.utils.Array;
|
import com.badlogic.gdx.utils.Array;
|
||||||
|
import com.badlogic.gdx.utils.IntMap;
|
||||||
import io.anuke.mindustry.core.GameState.State;
|
import io.anuke.mindustry.core.GameState.State;
|
||||||
import io.anuke.mindustry.entities.Player;
|
import io.anuke.mindustry.entities.Player;
|
||||||
import io.anuke.mindustry.game.Difficulty;
|
import io.anuke.mindustry.game.Difficulty;
|
||||||
@@ -15,7 +16,9 @@ import io.anuke.mindustry.net.Administration.PlayerInfo;
|
|||||||
import io.anuke.mindustry.net.Packets.ChatPacket;
|
import io.anuke.mindustry.net.Packets.ChatPacket;
|
||||||
import io.anuke.mindustry.net.Packets.KickReason;
|
import io.anuke.mindustry.net.Packets.KickReason;
|
||||||
import io.anuke.mindustry.ui.fragments.DebugFragment;
|
import io.anuke.mindustry.ui.fragments.DebugFragment;
|
||||||
|
import io.anuke.mindustry.world.Block;
|
||||||
import io.anuke.mindustry.world.Map;
|
import io.anuke.mindustry.world.Map;
|
||||||
|
import io.anuke.mindustry.world.Placement;
|
||||||
import io.anuke.mindustry.world.Tile;
|
import io.anuke.mindustry.world.Tile;
|
||||||
import io.anuke.ucore.core.*;
|
import io.anuke.ucore.core.*;
|
||||||
import io.anuke.ucore.modules.Module;
|
import io.anuke.ucore.modules.Module;
|
||||||
@@ -27,6 +30,8 @@ import io.anuke.ucore.util.Log;
|
|||||||
import io.anuke.ucore.util.Strings;
|
import io.anuke.ucore.util.Strings;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.Scanner;
|
import java.util.Scanner;
|
||||||
|
|
||||||
import static io.anuke.mindustry.Vars.*;
|
import static io.anuke.mindustry.Vars.*;
|
||||||
@@ -723,6 +728,69 @@ public class ServerControl extends Module {
|
|||||||
info("Nobody with that name could be found.");
|
info("Nobody with that name could be found.");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
handler.register("rollback", "<amount>", "Rollback the block edits in the world", arg -> {
|
||||||
|
if(!state.is(State.playing)) {
|
||||||
|
err("Open the server first.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(arg[0] == null) {
|
||||||
|
err("Please specify the amount of block edit cycles to rollback");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rollbackTimes = Integer.valueOf(arg[0]);
|
||||||
|
IntMap<ArrayList<EditLog>> editLogs = netServer.admins.getEditLogs();
|
||||||
|
if(editLogs.size == 0){
|
||||||
|
err("Nothing to rollback!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(IntMap.Entry<ArrayList<EditLog>> editLog : editLogs.entries()) {
|
||||||
|
int coords = editLog.key;
|
||||||
|
ArrayList<EditLog> 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.remove(logs.size() - 1);
|
||||||
|
if(logs.isEmpty()) {
|
||||||
|
editLogs.remove(coords);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
info("Rollback done!");
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void readCommands(){
|
private void readCommands(){
|
||||||
|
|||||||
Reference in New Issue
Block a user