one painful merge later
This commit is contained in:
@@ -4,6 +4,7 @@ import com.badlogic.gdx.Application.ApplicationType;
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.files.FileHandle;
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
import io.anuke.mindustry.core.*;
|
||||
import io.anuke.mindustry.entities.Player;
|
||||
import io.anuke.mindustry.entities.TileEntity;
|
||||
@@ -14,13 +15,14 @@ import io.anuke.mindustry.entities.effect.Shield;
|
||||
import io.anuke.mindustry.entities.units.BaseUnit;
|
||||
import io.anuke.mindustry.game.Team;
|
||||
import io.anuke.mindustry.io.Version;
|
||||
import io.anuke.mindustry.core.Platform;
|
||||
import io.anuke.mindustry.net.EditLog;
|
||||
import io.anuke.ucore.entities.EffectEntity;
|
||||
import io.anuke.ucore.entities.Entities;
|
||||
import io.anuke.ucore.entities.Entity;
|
||||
import io.anuke.ucore.entities.EntityGroup;
|
||||
import io.anuke.ucore.scene.ui.layout.Unit;
|
||||
import io.anuke.ucore.util.OS;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
public class Vars{
|
||||
@@ -86,6 +88,8 @@ public class Vars{
|
||||
//amount of drops that are left when breaking a block
|
||||
public static final float breakDropAmount = 0.5f;
|
||||
|
||||
public static Array<EditLog> currentEditLogs = new Array<>();
|
||||
|
||||
//only if smoothCamera
|
||||
public static boolean snapCamera = true;
|
||||
|
||||
|
||||
@@ -3,6 +3,8 @@ package io.anuke.mindustry.core;
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
import com.badlogic.gdx.utils.IntMap;
|
||||
import com.badlogic.gdx.utils.IntSet;
|
||||
import com.badlogic.gdx.utils.TimeUtils;
|
||||
import io.anuke.mindustry.Vars;
|
||||
import io.anuke.mindustry.core.GameState.State;
|
||||
import io.anuke.mindustry.entities.Player;
|
||||
import io.anuke.mindustry.entities.SyncEntity;
|
||||
@@ -151,6 +153,10 @@ public class NetClient extends Module {
|
||||
state.wave = packet.wave;
|
||||
});
|
||||
|
||||
Net.handleClient(BlockLogRequestPacket.class, packet -> {
|
||||
currentEditLogs = packet.editlogs;
|
||||
});
|
||||
|
||||
Net.handleClient(PlacePacket.class, (packet) -> {
|
||||
Player placer = playerGroup.getByID(packet.playerid);
|
||||
|
||||
|
||||
@@ -30,7 +30,6 @@ import io.anuke.ucore.util.Timer;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class NetServer extends Module{
|
||||
@@ -217,6 +216,7 @@ public class NetServer extends Module{
|
||||
|
||||
TraceInfo trace = admins.getTraceByID(getUUID(id));
|
||||
|
||||
admins.logEdit(packet.x, packet.y, connections.get(id), block, packet.rotation, EditLog.EditAction.PLACE);
|
||||
trace.lastBlockPlaced = block;
|
||||
trace.totalBlocksPlaced ++;
|
||||
admins.getInfo(getUUID(id)).totalBlockPlaced ++;
|
||||
@@ -244,6 +244,7 @@ public class NetServer extends Module{
|
||||
if(block != null) {
|
||||
TraceInfo trace = admins.getTraceByID(getUUID(id));
|
||||
|
||||
admins.logEdit(packet.x, packet.y, connections.get(id), block, tile.getRotation(), EditLog.EditAction.BREAK);
|
||||
trace.lastBlockBroken = block;
|
||||
trace.totalBlocksBroken++;
|
||||
admins.getInfo(getUUID(id)).totalBlocksBroken ++;
|
||||
@@ -353,6 +354,24 @@ public class NetServer extends Module{
|
||||
Log.info("&lc{0} has requested trace info of {1}.", player.name, other.name);
|
||||
}
|
||||
});
|
||||
|
||||
Net.handleServer(BlockLogRequestPacket.class, (id, packet) -> {
|
||||
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(){
|
||||
|
||||
@@ -54,6 +54,7 @@ public class UI extends SceneModule{
|
||||
public BansDialog bans;
|
||||
public AdminsDialog admins;
|
||||
public TraceDialog traces;
|
||||
public RollbackDialog rollback;
|
||||
public ChangelogDialog changelog;
|
||||
public LocalPlayerDialog localplayers;
|
||||
|
||||
@@ -169,6 +170,7 @@ public class UI extends SceneModule{
|
||||
bans = new BansDialog();
|
||||
admins = new AdminsDialog();
|
||||
traces = new TraceDialog();
|
||||
rollback = new RollbackDialog();
|
||||
maps = new MapsDialog();
|
||||
localplayers = new LocalPlayerDialog();
|
||||
|
||||
|
||||
@@ -40,7 +40,8 @@ public class DefaultKeybinds {
|
||||
"chat_history_prev", Input.UP,
|
||||
"chat_history_next", Input.DOWN,
|
||||
"chat_scroll", new Axis(Input.SCROLL),
|
||||
"console", Input.GRAVE
|
||||
"console", Input.GRAVE,
|
||||
"block_logs", Input.I,
|
||||
);
|
||||
|
||||
KeyBinds.defaultSection(section, DeviceType.controller,
|
||||
|
||||
@@ -151,7 +151,7 @@ public class DesktopInput extends InputHandler{
|
||||
|
||||
renderer.minimap().zoomBy(-(int)Inputs.getAxisTapped(section,"zoom_minimap"));
|
||||
rotation = Mathf.mod(rotation + (int)Inputs.getAxisTapped(section,"rotate"), 4);
|
||||
|
||||
|
||||
Tile cursor = tileAt(control.gdxInput().getX(), control.gdxInput().getY());
|
||||
|
||||
if(cursor != null){
|
||||
@@ -165,6 +165,16 @@ public class DesktopInput extends InputHandler{
|
||||
&& cursor.block() == Blocks.air){
|
||||
cursorType = drill;
|
||||
}
|
||||
|
||||
if(recipe == null && !ui.hasMouse() && Inputs.keyDown("block_info")
|
||||
&& cursor.block().fullDescription != null){
|
||||
cursorType = hand;
|
||||
if(Inputs.keyTap("select")){
|
||||
ui.hudfrag.blockfrag.showBlockInfo(cursor.block());
|
||||
Cursors.restoreCursor();
|
||||
cursorType = normal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!ui.hasMouse()) {
|
||||
|
||||
@@ -1,9 +1,19 @@
|
||||
package io.anuke.mindustry.net;
|
||||
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
import com.badlogic.gdx.utils.IntMap;
|
||||
import com.badlogic.gdx.utils.Json;
|
||||
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;
|
||||
import io.anuke.mindustry.world.blocks.types.StaticBlock;
|
||||
import io.anuke.ucore.core.Settings;
|
||||
import static io.anuke.mindustry.Vars.world;
|
||||
|
||||
public class Administration {
|
||||
public static final int defaultMaxBrokenBlocks = 15;
|
||||
@@ -13,6 +23,9 @@ public class Administration {
|
||||
private ObjectMap<String, PlayerInfo> playerInfo = new ObjectMap<>();
|
||||
/**Maps UUIDs to trace infos. This is wiped when a player logs off.*/
|
||||
private ObjectMap<String, TraceInfo> traceInfo = new ObjectMap<>();
|
||||
/**Maps packed coordinates to logs for that coordinate */
|
||||
private IntMap<Array<EditLog>> editLogs = new IntMap<>();
|
||||
|
||||
private Array<String> bannedIPs = new Array<>();
|
||||
|
||||
public Administration(){
|
||||
@@ -44,6 +57,68 @@ public class Administration {
|
||||
Settings.save();
|
||||
}
|
||||
|
||||
public IntMap<Array<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.name, block, rotation, action));
|
||||
}
|
||||
else {
|
||||
Array<EditLog> logs = new Array<>();
|
||||
logs.add(new EditLog(player.name, block, rotation, action));
|
||||
editLogs.put(x + y * world.width(), logs);
|
||||
}
|
||||
}
|
||||
|
||||
public void rollbackWorld(int rollbackTimes) {
|
||||
for(IntMap.Entry<Array<EditLog>> editLog : editLogs.entries()) {
|
||||
int coords = editLog.key;
|
||||
Array<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.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;
|
||||
|
||||
|
||||
26
core/src/io/anuke/mindustry/net/EditLog.java
Normal file
26
core/src/io/anuke/mindustry/net/EditLog.java
Normal file
@@ -0,0 +1,26 @@
|
||||
package io.anuke.mindustry.net;
|
||||
|
||||
import io.anuke.mindustry.entities.Player;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
|
||||
public class EditLog {
|
||||
public String playername;
|
||||
public Block block;
|
||||
public int rotation;
|
||||
public EditAction action;
|
||||
|
||||
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", playername, block.name(), rotation, action.toString());
|
||||
}
|
||||
|
||||
public enum EditAction {
|
||||
PLACE, BREAK;
|
||||
}
|
||||
}
|
||||
@@ -120,4 +120,20 @@ public class NetEvents {
|
||||
ui.traces.show(target, netServer.admins.getTraceByID(target.uuid));
|
||||
}
|
||||
}
|
||||
|
||||
public static void handleBlockLogRequest(int x, int y) {
|
||||
BlockLogRequestPacket packet = new BlockLogRequestPacket();
|
||||
packet.x = x;
|
||||
packet.y = y;
|
||||
packet.editlogs = Vars.currentEditLogs;
|
||||
|
||||
Net.send(packet, SendMode.udp);
|
||||
}
|
||||
|
||||
public static void handleRollbackRequest(int rollbackTimes) {
|
||||
RollbackRequestPacket packet = new RollbackRequestPacket();
|
||||
packet.rollbackTimes = rollbackTimes;
|
||||
|
||||
Net.send(packet, SendMode.udp);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package io.anuke.mindustry.net;
|
||||
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
import com.badlogic.gdx.utils.Base64Coder;
|
||||
import com.badlogic.gdx.utils.TimeUtils;
|
||||
import com.badlogic.gdx.utils.reflect.ClassReflection;
|
||||
@@ -159,6 +160,60 @@ public class Packets {
|
||||
}
|
||||
}
|
||||
|
||||
public static class BlockLogRequestPacket implements Packet {
|
||||
public int x;
|
||||
public int y;
|
||||
public Array<EditLog> editlogs;
|
||||
|
||||
@Override
|
||||
public void write(ByteBuffer buffer) {
|
||||
buffer.putShort((short)x);
|
||||
buffer.putShort((short)y);
|
||||
buffer.putInt(editlogs.size);
|
||||
for(EditLog value : editlogs) {
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(ByteBuffer buffer) {
|
||||
x = buffer.getShort();
|
||||
y = buffer.getShort();
|
||||
editlogs = new Array<>();
|
||||
int arraySize = buffer.getInt();
|
||||
for(int a = 0; a < arraySize; a ++) {
|
||||
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(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 Player player;
|
||||
|
||||
|
||||
@@ -38,6 +38,8 @@ public class Registrator {
|
||||
AdministerRequestPacket.class,
|
||||
TracePacket.class,
|
||||
InvokePacket.class,
|
||||
BlockLogRequestPacket.class,
|
||||
RollbackRequestPacket.class
|
||||
};
|
||||
private static ObjectIntMap<Class<?>> ids = new ObjectIntMap<>();
|
||||
|
||||
|
||||
40
core/src/io/anuke/mindustry/ui/dialogs/RollbackDialog.java
Normal file
40
core/src/io/anuke/mindustry/ui/dialogs/RollbackDialog.java
Normal file
@@ -0,0 +1,40 @@
|
||||
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->{}).size(200f, 48f).get();
|
||||
field.setTextFieldFilter((f, c) -> field.getText().length() < 4);
|
||||
|
||||
content().row();
|
||||
buttons().defaults().size(200f, 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()));
|
||||
}
|
||||
}
|
||||
@@ -59,6 +59,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();
|
||||
|
||||
Reference in New Issue
Block a user