Added player tracing tools, fixed some bugs

This commit is contained in:
Anuken
2018-02-26 17:20:05 -05:00
parent c90395ee2b
commit 32791b4baa
20 changed files with 464 additions and 250 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 228 B

View File

@@ -38,6 +38,15 @@ text.server.refreshing=Refreshing server
text.hosts.none=[lightgray]No LAN games found! text.hosts.none=[lightgray]No LAN games found!
text.host.invalid=[scarlet]Can't connect to host. text.host.invalid=[scarlet]Can't connect to host.
text.server.friendlyfire=Friendly Fire text.server.friendlyfire=Friendly Fire
text.trace=Trace Player
text.trace.playername=Player name: [accent]{0}
text.trace.ip=IP: [accent]{0}
text.trace.modclient=Modded Client: [accent]{0}
text.trace.totalblocksbroken=Total blocks broken: [accent]{0}
text.trace.structureblocksbroken=Structure blocks broken: [accent]{0}
text.trace.lastblockbroken=Last block broken: [accent]{0}
text.trace.totalblocksplaced=Total blocks placed: [accent]{0}
text.trace.lastblockplaced=Last block placed: [accent]{0}
text.server.bans=Bans text.server.bans=Bans
text.server.bans.none=No banned players found! text.server.bans.none=No banned players found!
text.server.admins=Admins text.server.admins=Admins

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 82 KiB

After

Width:  |  Height:  |  Size: 81 KiB

View File

@@ -1,7 +1,7 @@
#Autogenerated file. Do not modify. #Autogenerated file. Do not modify.
#Mon Feb 26 10:05:40 EST 2018 #Mon Feb 26 17:17:34 EST 2018
version=release version=release
androidBuildCode=290 androidBuildCode=291
name=Mindustry name=Mindustry
code=3.3 code=3.3
build=custom build build=custom build

View File

@@ -162,9 +162,6 @@ public class NetClient extends Module {
state.wavetime = packet.countdown; state.wavetime = packet.countdown;
state.wave = packet.wave; state.wave = packet.wave;
//removed: messing with time isn't necessary anymore
//Timers.resetTime(packet.time + (float) (TimeUtils.timeSinceMillis(packet.timestamp) / 1000.0 * 60.0));
ui.hudfrag.updateItems(); ui.hudfrag.updateItems();
}); });
@@ -343,6 +340,11 @@ public class NetClient extends Module {
player.isAdmin = packet.admin; player.isAdmin = packet.admin;
ui.listfrag.rebuild(); ui.listfrag.rebuild();
}); });
Net.handleClient(TracePacket.class, packet -> {
Player player = playerGroup.getByID(packet.info.playerid);
ui.traces.show(player, packet.info);
});
} }
@Override @Override

View File

@@ -64,19 +64,19 @@ public class NetServer extends Module{
if(Net.getConnection(id) == null || if(Net.getConnection(id) == null ||
admins.isBanned(Net.getConnection(id).address)) return; admins.isBanned(Net.getConnection(id).address)) return;
admins.setKnownName(Net.getConnection(id).address, packet.name); String ip = Net.getConnection(id).address;
if(packet.version != Version.build && Version.build != -1){ admins.setKnownName(ip, packet.name);
if(packet.version == -1){
admins.banPlayer(Net.getConnection(id).address);
Net.kickConnection(id, KickReason.banned);
}else {
Net.kickConnection(id, packet.version > Version.build ? KickReason.serverOutdated : KickReason.clientOutdated);
}
if(packet.version != Version.build && Version.build != -1 && packet.version != -1){
Net.kickConnection(id, packet.version > Version.build ? KickReason.serverOutdated : KickReason.clientOutdated);
return; return;
} }
if(packet.version == -1){
admins.getTrace(ip).modclient = true;
}
Log.info("Sending data to player '{0}' / {1}", packet.name, id); Log.info("Sending data to player '{0}' / {1}", packet.name, id);
Player player = new Player(); Player player = new Player();
@@ -90,6 +90,8 @@ public class NetServer extends Module{
player.color.set(packet.color); player.color.set(packet.color);
connections.put(id, player); connections.put(id, player);
admins.getTrace(ip).playerid = player.id;
if(world.getMap().custom){ if(world.getMap().custom){
ByteArrayOutputStream stream = new ByteArrayOutputStream(); ByteArrayOutputStream stream = new ByteArrayOutputStream();
NetworkIO.writeMap(world.getMap(), stream); NetworkIO.writeMap(world.getMap(), stream);
@@ -164,15 +166,20 @@ public class NetServer extends Module{
Net.handleServer(PlacePacket.class, (id, packet) -> { Net.handleServer(PlacePacket.class, (id, packet) -> {
packet.playerid = connections.get(id).id; packet.playerid = connections.get(id).id;
if(!Placement.validPlace(packet.x, packet.y, Block.getByID(packet.block))) return; Block block = Block.getByID(packet.block);
Recipe recipe = Recipes.getByResult(Block.getByID(packet.block)); if(!Placement.validPlace(packet.x, packet.y, block)) return;
Recipe recipe = Recipes.getByResult(block);
if(recipe == null) return; if(recipe == null) return;
state.inventory.removeItems(recipe.requirements); state.inventory.removeItems(recipe.requirements);
Placement.placeBlock(packet.x, packet.y, Block.getByID(packet.block), packet.rotation, true, false); Placement.placeBlock(packet.x, packet.y, block, packet.rotation, true, false);
admins.getTrace(Net.getConnection(id).address).lastBlockPlaced = block;
admins.getTrace(Net.getConnection(id).address).totalBlocksPlaced ++;
Net.send(packet, SendMode.tcp); Net.send(packet, SendMode.tcp);
}); });
@@ -182,7 +189,14 @@ public class NetServer extends Module{
if(!Placement.validBreak(packet.x, packet.y)) return; if(!Placement.validBreak(packet.x, packet.y)) return;
Placement.breakBlock(packet.x, packet.y, true, false); Block block = Placement.breakBlock(packet.x, packet.y, true, false);
if(block != null) {
admins.getTrace(Net.getConnection(id).address).lastBlockBroken = block;
admins.getTrace(Net.getConnection(id).address).totalBlocksBroken++;
if (block.update || block.destructible)
admins.getTrace(Net.getConnection(id).address).structureBlocksBroken++;
}
Net.send(packet, SendMode.tcp); Net.send(packet, SendMode.tcp);
}); });
@@ -252,18 +266,25 @@ public class NetServer extends Module{
Player other = playerGroup.getByID(packet.id); Player other = playerGroup.getByID(packet.id);
if(other == null){ if(other == null || other.isAdmin){
Log.err("{0} attempted to perform admin action on nonexistant player.", player.name); Log.err("{0} attempted to perform admin action on nonexistant or admin player.", player.name);
return; return;
} }
String ip = Net.getConnection(other.clientid).address;
if(packet.action == AdminAction.ban){ if(packet.action == AdminAction.ban){
admins.banPlayer(Net.getConnection(other.clientid).address); admins.banPlayer(ip);
Net.kickConnection(other.clientid, KickReason.banned); Net.kickConnection(other.clientid, KickReason.banned);
Log.info("&lc{0} has banned {1}.", player.name, other.name); Log.info("&lc{0} has banned {1}.", player.name, other.name);
}else if(packet.action == AdminAction.kick){ }else if(packet.action == AdminAction.kick){
Net.kickConnection(other.clientid, KickReason.kick); Net.kickConnection(other.clientid, KickReason.kick);
Log.info("&lc{0} has kicked {1}.", player.name, other.name); Log.info("&lc{0} has kicked {1}.", player.name, other.name);
}else if(packet.action == AdminAction.trace){
TracePacket trace = new TracePacket();
trace.info = admins.getTrace(ip);
Net.sendTo(other.clientid, trace, SendMode.tcp);
Log.info("&lc{0} has requested trace info of {1}.", player.name, other.name);
} }
}); });
} }
@@ -287,6 +308,7 @@ public class NetServer extends Module{
public void reset(){ public void reset(){
weapons.clear(); weapons.clear();
admins.clearTraces();
} }
void sync(){ void sync(){

View File

@@ -47,6 +47,7 @@ public class UI extends SceneModule{
public LanguageDialog language; public LanguageDialog language;
public BansDialog bans; public BansDialog bans;
public AdminsDialog admins; public AdminsDialog admins;
public TraceDialog traces;
public final MenuFragment menufrag = new MenuFragment(); public final MenuFragment menufrag = new MenuFragment();
public final ToolFragment toolfrag = new ToolFragment(); public final ToolFragment toolfrag = new ToolFragment();
@@ -154,6 +155,7 @@ public class UI extends SceneModule{
host = new HostDialog(); host = new HostDialog();
bans = new BansDialog(); bans = new BansDialog();
admins = new AdminsDialog(); admins = new AdminsDialog();
traces = new TraceDialog();
build.begin(scene); build.begin(scene);

View File

@@ -85,7 +85,8 @@ public class EnemyType {
if(isCalculating(enemy)){ if(isCalculating(enemy)){
Draw.color(Color.SKY); Draw.color(Color.SKY);
Lines.polySeg(20, 0, 5, enemy.x, enemy.y, 11f, Timers.time() * 2f + enemy.id*52153f); Lines.polySeg(20, 0, 4, enemy.x, enemy.y, 11f, Timers.time() * 2f + enemy.id*52f);
Lines.polySeg(20, 0, 4, enemy.x, enemy.y, 11f, Timers.time() * 2f + enemy.id*52f + 180f);
Draw.color(); Draw.color();
} }

View File

@@ -56,4 +56,9 @@ public class TargetType extends EnemyType {
new Enemy(EnemyTypes.target).set(enemy.x, enemy.y).add(); new Enemy(EnemyTypes.target).set(enemy.x, enemy.y).add();
}); });
} }
@Override
public boolean isCalculating(Enemy enemy){
return false;
}
} }

View File

@@ -10,6 +10,7 @@ public class Administration {
private Array<String> bannedIPS = new Array<>(); private Array<String> bannedIPS = new Array<>();
private Array<String> admins = new Array<>(); private Array<String> admins = new Array<>();
private ObjectMap<String, String> known = new ObjectMap<>(); private ObjectMap<String, String> known = new ObjectMap<>();
private ObjectMap<String, TraceInfo> traces = new ObjectMap<>();
public Administration(){ public Administration(){
Settings.defaultList( Settings.defaultList(
@@ -21,6 +22,16 @@ public class Administration {
load(); load();
} }
public TraceInfo getTrace(String ip){
if(!traces.containsKey(ip)) traces.put(ip, new TraceInfo(ip));
return traces.get(ip);
}
public void clearTraces(){
traces.clear();
}
/**Sets last known name for an IP.*/ /**Sets last known name for an IP.*/
public void setKnownName(String ip, String name){ public void setKnownName(String ip, String name){
known.put(ip, name); known.put(ip, name);

View File

@@ -13,7 +13,7 @@ import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.Tile; import io.anuke.mindustry.world.Tile;
import io.anuke.ucore.entities.Entity; import io.anuke.ucore.entities.Entity;
import static io.anuke.mindustry.Vars.netCommon; import static io.anuke.mindustry.Vars.*;
public class NetEvents { public class NetEvents {
@@ -165,4 +165,12 @@ public class NetEvents {
packet.action = action; packet.action = action;
Net.send(packet, SendMode.tcp); Net.send(packet, SendMode.tcp);
} }
public static void handleTraceRequest(Player target){
if(Net.client()) {
handleAdministerRequest(target, AdminAction.trace);
}else{
ui.traces.show(target, netServer.admins.getTrace(Net.getConnection(target.clientid).address));
}
}
} }

View File

@@ -8,6 +8,7 @@ import io.anuke.mindustry.io.Version;
import io.anuke.mindustry.net.Packet.ImportantPacket; import io.anuke.mindustry.net.Packet.ImportantPacket;
import io.anuke.mindustry.net.Packet.UnimportantPacket; import io.anuke.mindustry.net.Packet.UnimportantPacket;
import io.anuke.mindustry.resource.Item; import io.anuke.mindustry.resource.Item;
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;
@@ -612,6 +613,43 @@ public class Packets {
} }
public enum AdminAction{ public enum AdminAction{
kick, ban kick, ban, trace
}
public static class TracePacket implements Packet{
public TraceInfo info;
@Override
public void write(ByteBuffer buffer) {
buffer.putInt(info.playerid);
buffer.putShort((short)info.ip.getBytes().length);
buffer.put(info.ip.getBytes());
buffer.put(info.modclient ? (byte)1 : 0);
buffer.putInt(info.totalBlocksBroken);
buffer.putInt(info.structureBlocksBroken);
buffer.putInt(info.lastBlockBroken.id);
buffer.putInt(info.totalBlocksPlaced);
buffer.putInt(info.lastBlockPlaced.id);
}
@Override
public void read(ByteBuffer buffer) {
int id = buffer.getInt();
short iplen = buffer.getShort();
byte[] ipb = new byte[iplen];
buffer.get(ipb);
info = new TraceInfo(new String(ipb));
info.playerid = id;
info.modclient = buffer.get() == 1;
info.totalBlocksBroken = buffer.getInt();
info.structureBlocksBroken = buffer.getInt();
info.lastBlockBroken = Block.getByID(buffer.getInt());
info.totalBlocksPlaced = buffer.getInt();
info.lastBlockPlaced = Block.getByID(buffer.getInt());
}
} }
} }

View File

@@ -44,6 +44,7 @@ public class Registrator {
NetErrorPacket.class, NetErrorPacket.class,
PlayerAdminPacket.class, PlayerAdminPacket.class,
AdministerRequestPacket.class, AdministerRequestPacket.class,
TracePacket.class,
}; };
private static ObjectIntMap<Class<?>> ids = new ObjectIntMap<>(); private static ObjectIntMap<Class<?>> ids = new ObjectIntMap<>();

View File

@@ -0,0 +1,21 @@
package io.anuke.mindustry.net;
import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.blocks.Blocks;
public class TraceInfo {
public int playerid;
public String ip;
public boolean modclient;
public int totalBlocksBroken;
public int structureBlocksBroken;
public Block lastBlockBroken = Blocks.air;
public int totalBlocksPlaced;
public Block lastBlockPlaced = Blocks.air;
public TraceInfo(String ip){
this.ip = ip;
}
}

View File

@@ -0,0 +1,53 @@
package io.anuke.mindustry.ui.dialogs;
import io.anuke.mindustry.entities.Player;
import io.anuke.mindustry.net.TraceInfo;
import io.anuke.ucore.scene.ui.layout.Table;
import io.anuke.ucore.util.Bundles;
public class TraceDialog extends FloatingDialog {
public TraceDialog(){
super("$text.trace");
addCloseButton();
}
public void show(Player player, TraceInfo info){
content().clear();
Table table = new Table("button");
table.margin(14);
table.defaults().pad(1);
table.defaults().left();
table.add(Bundles.format("text.trace.playername", player.name));
table.row();
table.add(Bundles.format("text.trace.ip", info.ip));
table.row();
table.add(Bundles.format("text.trace.modclient", info.modclient));
table.row();
table.add().pad(5);
table.row();
table.add(Bundles.format("text.trace.totalblocksbroken", info.totalBlocksBroken));
table.row();
table.add(Bundles.format("text.trace.structureblocksbroken", info.structureBlocksBroken));
table.row();
table.add(Bundles.format("text.trace.lastblockbroken", info.lastBlockBroken));
table.row();
table.add().pad(5);
table.row();
table.add(Bundles.format("text.trace.totalblocksplaced", info.totalBlocksPlaced));
table.row();
table.add(Bundles.format("text.trace.lastblockplaced", info.lastBlockPlaced));
table.row();
content().add(table);
show();
}
}

View File

@@ -117,7 +117,7 @@ public class PlayerListFragment implements Fragment{
button.addImage("icon-admin").size(14*2).visible(() -> player.isAdmin && !(!player.isLocal && Net.server())).padRight(5); button.addImage("icon-admin").size(14*2).visible(() -> player.isAdmin && !(!player.isLocal && Net.server())).padRight(5);
if((Net.server() || Vars.player.isAdmin) && !player.isLocal && !player.isAdmin){ if((Net.server() || Vars.player.isAdmin) && !player.isLocal && (!player.isAdmin || Net.server())){
button.add().growY(); button.add().growY();
float bs = (h + 14)/2f; float bs = (h + 14)/2f;
@@ -163,8 +163,8 @@ public class PlayerListFragment implements Fragment{
}).update(b -> b.setChecked(connection != null && netServer.admins.isAdmin(connection.address))) }).update(b -> b.setChecked(connection != null && netServer.admins.isAdmin(connection.address)))
.disabled(Net.client()); .disabled(Net.client());
//TODO unused? //TODO trace info for player
t.addImageButton("icon-cancel", 14*2, () -> {}); t.addImageButton("icon-zoom-small", 14*2, () -> NetEvents.handleTraceRequest(player));
}).padRight(12).padTop(-5).padLeft(0).padBottom(-10).size(bs + 10f, bs); }).padRight(12).padTop(-5).padLeft(0).padBottom(-10).size(bs + 10f, bs);

View File

@@ -21,10 +21,11 @@ import static io.anuke.mindustry.Vars.*;
public class Placement { public class Placement {
private static final Rectangle rect = new Rectangle(); private static final Rectangle rect = new Rectangle();
public static void breakBlock(int x, int y, boolean effect, boolean sound){ /**Returns block type that was broken, or null if unsuccesful.*/
public static Block breakBlock(int x, int y, boolean effect, boolean sound){
Tile tile = world.tile(x, y); Tile tile = world.tile(x, y);
if(tile == null) return; if(tile == null) return null;
Block block = tile.isLinked() ? tile.getLinked().block() : tile.block(); Block block = tile.isLinked() ? tile.getLinked().block() : tile.block();
Recipe result = Recipes.getByResult(block); Recipe result = Recipes.getByResult(block);
@@ -53,6 +54,8 @@ public class Placement {
if(effect) Effects.effect(Fx.breakBlock, toremove.worldx(), toremove.worldy()); if(effect) Effects.effect(Fx.breakBlock, toremove.worldx(), toremove.worldy());
} }
} }
return block;
} }
public static void placeBlock(int x, int y, Block result, int rotation, boolean effects, boolean sound){ public static void placeBlock(int x, int y, Block result, int rotation, boolean effects, boolean sound){

View File

@@ -1 +0,0 @@
{}

View File

@@ -13,6 +13,7 @@ import io.anuke.mindustry.net.Net;
import io.anuke.mindustry.net.NetEvents; import io.anuke.mindustry.net.NetEvents;
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.net.TraceInfo;
import io.anuke.mindustry.ui.fragments.DebugFragment; import io.anuke.mindustry.ui.fragments.DebugFragment;
import io.anuke.mindustry.world.Map; import io.anuke.mindustry.world.Map;
import io.anuke.mindustry.world.Tile; import io.anuke.mindustry.world.Tile;
@@ -335,8 +336,6 @@ public class ServerControl extends Module {
} }
}); });
//assadsad
handler.register("admin", "<username>", "Make a user admin", arg -> { handler.register("admin", "<username>", "Make a user admin", arg -> {
if(!state.is(State.playing)) { if(!state.is(State.playing)) {
err("Open the server first."); err("Open the server first.");
@@ -458,7 +457,7 @@ public class ServerControl extends Module {
info(DebugFragment.debugInfo()); info(DebugFragment.debugInfo());
}); });
handler.register("trace", "<x> <y>", "Prints debug info about a block", arg -> { handler.register("traceblock", "<x> <y>", "Prints debug info about a block", arg -> {
try{ try{
int x = Integer.parseInt(arg[0]); int x = Integer.parseInt(arg[0]);
int y = Integer.parseInt(arg[1]); int y = Integer.parseInt(arg[1]);
@@ -484,6 +483,39 @@ public class ServerControl extends Module {
Log.err("Invalid coordinates passed."); Log.err("Invalid coordinates passed.");
} }
}); });
handler.register("trace", "<username>", "Trace a player's actions", arg -> {
if(!state.is(State.playing)) {
err("Open the server first.");
return;
}
Player target = null;
for(Player player : playerGroup.all()){
if(player.name.equalsIgnoreCase(arg[0])){
target = player;
break;
}
}
if(target != null){
TraceInfo info = netServer.admins.getTrace(Net.getConnection(target.clientid).address);
Log.info("&lcTrace info for player '{0}':", target.name);
Log.info(" &lyEntity ID: {0}", info. playerid);
Log.info(" &lyIP: {0}", info.ip);
Log.info(" &lymodded client: {0}", info.modclient);
Log.info("");
Log.info(" &lytotal blocks broken: {0}", info.totalBlocksBroken);
Log.info(" &lystructure blocks broken: {0}", info.structureBlocksBroken);
Log.info(" &lylast block broken: {0}", info.lastBlockBroken);
Log.info("");
Log.info(" &lytotal blocks placed: {0}", info.totalBlocksPlaced);
Log.info(" &lylast block placed: {0}", info.lastBlockPlaced);
}else{
info("Nobody with that name could be found.");
}
});
} }
private void readCommands(){ private void readCommands(){