Admin player team switch + more trace info
This commit is contained in:
@@ -263,7 +263,17 @@ trace.mobile = Mobile Client: [accent]{0}
|
|||||||
trace.modclient = Custom Client: [accent]{0}
|
trace.modclient = Custom Client: [accent]{0}
|
||||||
trace.times.joined = Times Joined: [accent]{0}
|
trace.times.joined = Times Joined: [accent]{0}
|
||||||
trace.times.kicked = Times Kicked: [accent]{0}
|
trace.times.kicked = Times Kicked: [accent]{0}
|
||||||
|
trace.ips = IPs:
|
||||||
|
trace.names = Names:
|
||||||
invalidid = Invalid client ID! Submit a bug report.
|
invalidid = Invalid client ID! Submit a bug report.
|
||||||
|
|
||||||
|
player.ban = Ban
|
||||||
|
player.kick = Kick
|
||||||
|
player.trace = Trace
|
||||||
|
player.admin = Toggle Admin
|
||||||
|
player.team = Change Team
|
||||||
|
player.changeteam = Team
|
||||||
|
|
||||||
server.bans = Bans
|
server.bans = Bans
|
||||||
server.bans.none = No banned players found!
|
server.bans.none = No banned players found!
|
||||||
server.admins = Admins
|
server.admins = Admins
|
||||||
|
|||||||
@@ -50,8 +50,7 @@ public class ControlPathfinder{
|
|||||||
|
|
||||||
costLegs = (team, tile) ->
|
costLegs = (team, tile) ->
|
||||||
PathTile.legSolid(tile) ? impassable : 1 +
|
PathTile.legSolid(tile) ? impassable : 1 +
|
||||||
(PathTile.deep(tile) ? 6000 : 0) +
|
(PathTile.deep(tile) ? 6000 : 0),
|
||||||
(PathTile.nearSolid(tile) || PathTile.solid(tile) ? 3 : 0),
|
|
||||||
|
|
||||||
costNaval = (team, tile) ->
|
costNaval = (team, tile) ->
|
||||||
//impassable same-team neutral block, or non-liquid
|
//impassable same-team neutral block, or non-liquid
|
||||||
|
|||||||
@@ -784,7 +784,7 @@ public class NetServer implements ApplicationListener{
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Remote(targets = Loc.client, called = Loc.server)
|
@Remote(targets = Loc.client, called = Loc.server)
|
||||||
public static void adminRequest(Player player, Player other, AdminAction action){
|
public static void adminRequest(Player player, Player other, AdminAction action, Object params){
|
||||||
if(!player.admin && !player.isLocal()){
|
if(!player.admin && !player.isLocal()){
|
||||||
warn("ACCESS DENIED: Player @ / @ attempted to perform admin action '@' on '@' without proper security access.",
|
warn("ACCESS DENIED: Player @ / @ attempted to perform admin action '@' on '@' without proper security access.",
|
||||||
player.plainName(), player.con == null ? "null" : player.con.address, action.name(), other == null ? null : other.plainName());
|
player.plainName(), player.con == null ? "null" : player.con.address, action.name(), other == null ? null : other.plainName());
|
||||||
@@ -798,28 +798,38 @@ public class NetServer implements ApplicationListener{
|
|||||||
|
|
||||||
Events.fire(new EventType.AdminRequestEvent(player, other, action));
|
Events.fire(new EventType.AdminRequestEvent(player, other, action));
|
||||||
|
|
||||||
if(action == AdminAction.wave){
|
switch(action){
|
||||||
//no verification is done, so admins can hypothetically spam waves
|
case wave -> {
|
||||||
//not a real issue, because server owners may want to do just that
|
//no verification is done, so admins can hypothetically spam waves
|
||||||
logic.skipWave();
|
//not a real issue, because server owners may want to do just that
|
||||||
info("&lc@ &fi&lk[&lb@&fi&lk]&fb has skipped the wave.", player.plainName(), player.uuid());
|
logic.skipWave();
|
||||||
}else if(action == AdminAction.ban){
|
info("&lc@ &fi&lk[&lb@&fi&lk]&fb has skipped the wave.", player.plainName(), player.uuid());
|
||||||
netServer.admins.banPlayerID(other.con.uuid);
|
}
|
||||||
netServer.admins.banPlayerIP(other.con.address);
|
case ban -> {
|
||||||
other.kick(KickReason.banned);
|
netServer.admins.banPlayerID(other.con.uuid);
|
||||||
info("&lc@ &fi&lk[&lb@&fi&lk]&fb has banned @ &fi&lk[&lb@&fi&lk]&fb.", player.plainName(), player.uuid(), other.plainName(), other.uuid());
|
netServer.admins.banPlayerIP(other.con.address);
|
||||||
}else if(action == AdminAction.kick){
|
other.kick(KickReason.banned);
|
||||||
other.kick(KickReason.kick);
|
info("&lc@ &fi&lk[&lb@&fi&lk]&fb has banned @ &fi&lk[&lb@&fi&lk]&fb.", player.plainName(), player.uuid(), other.plainName(), other.uuid());
|
||||||
info("&lc@ &fi&lk[&lb@&fi&lk]&fb has kicked @ &fi&lk[&lb@&fi&lk]&fb.", player.plainName(), player.uuid(), other.plainName(), other.uuid());
|
}
|
||||||
}else if(action == AdminAction.trace){
|
case kick -> {
|
||||||
PlayerInfo stats = netServer.admins.getInfo(other.uuid());
|
other.kick(KickReason.kick);
|
||||||
TraceInfo info = new TraceInfo(other.con.address, other.uuid(), other.con.modclient, other.con.mobile, stats.timesJoined, stats.timesKicked);
|
info("&lc@ &fi&lk[&lb@&fi&lk]&fb has kicked @ &fi&lk[&lb@&fi&lk]&fb.", player.plainName(), player.uuid(), other.plainName(), other.uuid());
|
||||||
if(player.con != null){
|
}
|
||||||
Call.traceInfo(player.con, other, info);
|
case trace -> {
|
||||||
}else{
|
PlayerInfo stats = netServer.admins.getInfo(other.uuid());
|
||||||
NetClient.traceInfo(other, info);
|
TraceInfo info = new TraceInfo(other.con.address, other.uuid(), other.con.modclient, other.con.mobile, stats.timesJoined, stats.timesKicked, stats.ips.toArray(String.class), stats.names.toArray(String.class));
|
||||||
|
if(player.con != null){
|
||||||
|
Call.traceInfo(player.con, other, info);
|
||||||
|
}else{
|
||||||
|
NetClient.traceInfo(other, info);
|
||||||
|
}
|
||||||
|
info("&lc@ &fi&lk[&lb@&fi&lk]&fb has requested trace info of @ &fi&lk[&lb@&fi&lk]&fb.", player.plainName(), player.uuid(), other.plainName(), other.uuid());
|
||||||
|
}
|
||||||
|
case switchTeam -> {
|
||||||
|
if(params instanceof Team team){
|
||||||
|
other.team(team);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
info("&lc@ &fi&lk[&lb@&fi&lk]&fb has requested trace info of @ &fi&lk[&lb@&fi&lk]&fb.", player.plainName(), player.uuid(), other.plainName(), other.uuid());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -835,13 +835,40 @@ public class TypeIO{
|
|||||||
write.b(trace.mobile ? (byte)1 : 0);
|
write.b(trace.mobile ? (byte)1 : 0);
|
||||||
write.i(trace.timesJoined);
|
write.i(trace.timesJoined);
|
||||||
write.i(trace.timesKicked);
|
write.i(trace.timesKicked);
|
||||||
|
//there is a cap to prevent TCP packet size overrun
|
||||||
|
writeStrings(write, trace.ips, 12);
|
||||||
|
writeStrings(write, trace.names, 12);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TraceInfo readTraceInfo(Reads read){
|
public static TraceInfo readTraceInfo(Reads read){
|
||||||
return new TraceInfo(readString(read), readString(read), read.b() == 1, read.b() == 1, read.i(), read.i());
|
return new TraceInfo(readString(read), readString(read), read.b() == 1, read.b() == 1, read.i(), read.i(), readStrings(read), readStrings(read));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void writeStrings(Writes write, String[][] strings){
|
public static void writeStrings(Writes write, String[] strings, int maxLen){
|
||||||
|
write.b(Math.min(strings.length, maxLen));
|
||||||
|
for(int i = 0; i < Math.min(strings.length, maxLen); i++){
|
||||||
|
writeString(write, strings[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void writeStrings(Writes write, String[] strings){
|
||||||
|
write.b(strings.length);
|
||||||
|
for(String s : strings){
|
||||||
|
writeString(write, s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String[] readStrings(Reads read){
|
||||||
|
int length = read.ub();
|
||||||
|
var result = new String[length];
|
||||||
|
for(int j = 0; j < length; j++){
|
||||||
|
result[j] = readString(read);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static void writeStringArray(Writes write, String[][] strings){
|
||||||
write.b(strings.length);
|
write.b(strings.length);
|
||||||
for(String[] string : strings){
|
for(String[] string : strings){
|
||||||
write.b(string.length);
|
write.b(string.length);
|
||||||
@@ -851,7 +878,7 @@ public class TypeIO{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String[][] readStrings(Reads read){
|
public static String[][] readStringArray(Reads read){
|
||||||
int rows = read.ub();
|
int rows = read.ub();
|
||||||
|
|
||||||
String[][] strings = new String[rows][];
|
String[][] strings = new String[rows][];
|
||||||
|
|||||||
@@ -624,14 +624,17 @@ public class Administration{
|
|||||||
public String ip, uuid;
|
public String ip, uuid;
|
||||||
public boolean modded, mobile;
|
public boolean modded, mobile;
|
||||||
public int timesJoined, timesKicked;
|
public int timesJoined, timesKicked;
|
||||||
|
public String[] ips, names;
|
||||||
|
|
||||||
public TraceInfo(String ip, String uuid, boolean modded, boolean mobile, int timesJoined, int timesKicked){
|
public TraceInfo(String ip, String uuid, boolean modded, boolean mobile, int timesJoined, int timesKicked, String[] ips, String[] names){
|
||||||
this.ip = ip;
|
this.ip = ip;
|
||||||
this.uuid = uuid;
|
this.uuid = uuid;
|
||||||
this.modded = modded;
|
this.modded = modded;
|
||||||
this.mobile = mobile;
|
this.mobile = mobile;
|
||||||
this.timesJoined = timesJoined;
|
this.timesJoined = timesJoined;
|
||||||
this.timesKicked = timesKicked;
|
this.timesKicked = timesKicked;
|
||||||
|
this.names = names;
|
||||||
|
this.ips = ips;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ public class Packets{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public enum AdminAction{
|
public enum AdminAction{
|
||||||
kick, ban, trace, wave
|
kick, ban, trace, wave, switchTeam
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Generic client connection event. */
|
/** Generic client connection event. */
|
||||||
|
|||||||
@@ -20,8 +20,7 @@ public class BaseDialog extends Dialog{
|
|||||||
setFillParent(true);
|
setFillParent(true);
|
||||||
this.title.setAlignment(Align.center);
|
this.title.setAlignment(Align.center);
|
||||||
titleTable.row();
|
titleTable.row();
|
||||||
titleTable.image(Tex.whiteui, Pal.accent)
|
titleTable.image(Tex.whiteui, Pal.accent).growX().height(3f).pad(4f);
|
||||||
.growX().height(3f).pad(4f);
|
|
||||||
|
|
||||||
hidden(() -> {
|
hidden(() -> {
|
||||||
if(shouldPause && state.isGame() && !net.active() && !wasPaused){
|
if(shouldPause && state.isGame() && !net.active() && !wasPaused){
|
||||||
|
|||||||
@@ -39,14 +39,22 @@ public class TraceDialog extends BaseDialog{
|
|||||||
c.add(Core.bundle.format("trace.id", info.uuid)).row();
|
c.add(Core.bundle.format("trace.id", info.uuid)).row();
|
||||||
}).row();
|
}).row();
|
||||||
|
|
||||||
table.add(Core.bundle.format("trace.modclient", info.modded));
|
table.add(Core.bundle.format("trace.modclient", info.modded)).row();
|
||||||
table.row();
|
table.add(Core.bundle.format("trace.mobile", info.mobile)).row();
|
||||||
table.add(Core.bundle.format("trace.mobile", info.mobile));
|
table.add(Core.bundle.format("trace.times.joined", info.timesJoined)).row();
|
||||||
table.row();
|
table.add(Core.bundle.format("trace.times.kicked", info.timesKicked)).row();
|
||||||
table.add(Core.bundle.format("trace.times.joined", info.timesJoined));
|
|
||||||
table.row();
|
for(int i = 0; i < 2; i++){
|
||||||
table.add(Core.bundle.format("trace.times.kicked", info.timesKicked));
|
table.add(i == 0 ? "@trace.ips" : "@trace.names").row();
|
||||||
table.row();
|
String[] list = i == 0 ? info.ips : info.names;
|
||||||
|
|
||||||
|
table.pane(t -> {
|
||||||
|
t.left();
|
||||||
|
for(String val : list){
|
||||||
|
t.add("[lightgray]" + val).left().row();
|
||||||
|
}
|
||||||
|
}).padLeft(20f).fill().left().row();
|
||||||
|
}
|
||||||
|
|
||||||
table.add().pad(5);
|
table.add().pad(5);
|
||||||
table.row();
|
table.row();
|
||||||
|
|||||||
@@ -228,7 +228,7 @@ public class HudFragment{
|
|||||||
//table with button to skip wave
|
//table with button to skip wave
|
||||||
s.button(Icon.play, rightStyle, 30f, () -> {
|
s.button(Icon.play, rightStyle, 30f, () -> {
|
||||||
if(net.client() && player.admin){
|
if(net.client() && player.admin){
|
||||||
Call.adminRequest(player, AdminAction.wave);
|
Call.adminRequest(player, AdminAction.wave, null);
|
||||||
}else{
|
}else{
|
||||||
logic.skipWave();
|
logic.skipWave();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,12 +10,14 @@ import arc.scene.ui.ImageButton.*;
|
|||||||
import arc.scene.ui.layout.*;
|
import arc.scene.ui.layout.*;
|
||||||
import arc.struct.*;
|
import arc.struct.*;
|
||||||
import arc.util.*;
|
import arc.util.*;
|
||||||
|
import mindustry.game.*;
|
||||||
import mindustry.gen.*;
|
import mindustry.gen.*;
|
||||||
import mindustry.graphics.*;
|
import mindustry.graphics.*;
|
||||||
import mindustry.input.*;
|
import mindustry.input.*;
|
||||||
import mindustry.net.*;
|
import mindustry.net.*;
|
||||||
import mindustry.net.Packets.*;
|
import mindustry.net.Packets.*;
|
||||||
import mindustry.ui.*;
|
import mindustry.ui.*;
|
||||||
|
import mindustry.ui.dialogs.*;
|
||||||
|
|
||||||
import static mindustry.Vars.*;
|
import static mindustry.Vars.*;
|
||||||
|
|
||||||
@@ -156,45 +158,99 @@ public class PlayerListFragment{
|
|||||||
imageOverColor = Color.lightGray;
|
imageOverColor = Color.lightGray;
|
||||||
}};
|
}};
|
||||||
|
|
||||||
if((net.server() || player.admin) && !user.isLocal() && (!user.admin || net.server())){
|
//TODO for testing only
|
||||||
|
if((net.server() || player.admin || true) && (!user.admin || net.server() || user == player)){
|
||||||
button.add().growY();
|
button.add().growY();
|
||||||
|
|
||||||
float bs = (h) / 2f;
|
button.button(Icon.menu, ustyle, () -> {
|
||||||
|
var dialog = new BaseDialog(user.coloredName());
|
||||||
|
|
||||||
button.table(t -> {
|
dialog.title.setColor(Color.white);
|
||||||
t.defaults().size(bs);
|
dialog.titleTable.remove();
|
||||||
|
|
||||||
t.button(Icon.hammerSmall, ustyle,
|
dialog.closeOnBack();
|
||||||
() -> ui.showConfirm("@confirm", Core.bundle.format("confirmban", user.name()), () -> Call.adminRequest(user, AdminAction.ban)));
|
|
||||||
t.button(Icon.cancelSmall, ustyle,
|
|
||||||
() -> ui.showConfirm("@confirm", Core.bundle.format("confirmkick", user.name()), () -> Call.adminRequest(user, AdminAction.kick)));
|
|
||||||
|
|
||||||
t.row();
|
var bstyle = Styles.defaultt;
|
||||||
|
|
||||||
t.button(Icon.adminSmall, style, () -> {
|
dialog.cont.add(user.coloredName()).row();
|
||||||
if(net.client()) return;
|
dialog.cont.image(Tex.whiteui, Pal.accent).fillX().height(3f).pad(4f).row();
|
||||||
|
|
||||||
String id = user.uuid();
|
dialog.cont.pane(t -> {
|
||||||
|
t.defaults().size(220f, 55f).pad(3f);
|
||||||
|
|
||||||
if(user.admin){
|
if(user != player){
|
||||||
ui.showConfirm("@confirm", Core.bundle.format("confirmunadmin", user.name()), () -> {
|
t.button("@player.ban", Icon.hammer, bstyle, () -> {
|
||||||
netServer.admins.unAdminPlayer(id);
|
ui.showConfirm("@confirm", Core.bundle.format("confirmban", user.name()), () -> Call.adminRequest(user, AdminAction.ban, null));
|
||||||
user.admin = false;
|
dialog.hide();
|
||||||
});
|
}).row();
|
||||||
}else{
|
|
||||||
ui.showConfirm("@confirm", Core.bundle.format("confirmadmin", user.name()), () -> {
|
t.button("@player.kick", Icon.cancel, bstyle, () -> {
|
||||||
netServer.admins.adminPlayer(id, user.usid());
|
ui.showConfirm("@confirm", Core.bundle.format("confirmkick", user.name()), () -> Call.adminRequest(user, AdminAction.kick, null));
|
||||||
user.admin = true;
|
dialog.hide();
|
||||||
});
|
}).row();
|
||||||
}
|
}
|
||||||
}).update(b -> b.setChecked(user.admin))
|
|
||||||
.disabled(b -> net.client())
|
|
||||||
.touchable(() -> net.client() ? Touchable.disabled : Touchable.enabled)
|
|
||||||
.checked(user.admin);
|
|
||||||
|
|
||||||
t.button(Icon.zoomSmall, ustyle, () -> Call.adminRequest(user, AdminAction.trace));
|
if(!user.isLocal()){
|
||||||
|
t.button("@player.trace", Icon.zoom, bstyle, () -> {
|
||||||
|
Call.adminRequest(user, AdminAction.trace, null);
|
||||||
|
dialog.hide();
|
||||||
|
}).row();
|
||||||
|
}
|
||||||
|
|
||||||
}).padRight(12).size(bs + 10f, bs);
|
t.button("@player.team", Icon.redo, bstyle, () -> {
|
||||||
|
var teamSelect = new BaseDialog(Core.bundle.get("player.team") + ": " + user.name);
|
||||||
|
teamSelect.setFillParent(false);
|
||||||
|
|
||||||
|
var group = new ButtonGroup<>();
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
for(Team team : Team.baseTeams){
|
||||||
|
var b = new ImageButton(Tex.whiteui, Styles.clearNoneTogglei);
|
||||||
|
b.margin(4f);
|
||||||
|
b.getImageCell().grow();
|
||||||
|
b.getStyle().imageUpColor = team.color;
|
||||||
|
b.clicked(() -> {
|
||||||
|
Call.adminRequest(user, AdminAction.switchTeam, team);
|
||||||
|
teamSelect.hide();
|
||||||
|
});
|
||||||
|
teamSelect.cont.add(b).size(50f).checked(a -> user.team() == team).group(group);
|
||||||
|
|
||||||
|
if(i++ % 3 == 2) teamSelect.cont.row();
|
||||||
|
}
|
||||||
|
|
||||||
|
teamSelect.addCloseButton();
|
||||||
|
teamSelect.show();
|
||||||
|
|
||||||
|
dialog.hide();
|
||||||
|
}).row();
|
||||||
|
|
||||||
|
if(!net.client() && !user.isLocal()){
|
||||||
|
t.button("@player.admin", Icon.admin, Styles.togglet, () -> {
|
||||||
|
dialog.hide();
|
||||||
|
String id = user.uuid();
|
||||||
|
|
||||||
|
if(user.admin){
|
||||||
|
ui.showConfirm("@confirm", Core.bundle.format("confirmunadmin", user.name()), () -> {
|
||||||
|
netServer.admins.unAdminPlayer(id);
|
||||||
|
user.admin = false;
|
||||||
|
});
|
||||||
|
}else{
|
||||||
|
ui.showConfirm("@confirm", Core.bundle.format("confirmadmin", user.name()), () -> {
|
||||||
|
netServer.admins.adminPlayer(id, user.usid());
|
||||||
|
user.admin = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}).checked(b -> user.admin).row();
|
||||||
|
}
|
||||||
|
}).row();
|
||||||
|
|
||||||
|
dialog.cont.button("@back", Icon.left, dialog::hide).padTop(-1f).size(220f, 55f);
|
||||||
|
|
||||||
|
dialog.show();
|
||||||
|
|
||||||
|
|
||||||
|
}).size(h);
|
||||||
}else if(!user.isLocal() && !user.admin && net.client() && Groups.player.size() >= 3 && player.team() == user.team()){ //votekick
|
}else if(!user.isLocal() && !user.admin && net.client() && Groups.player.size() >= 3 && player.team() == user.team()){ //votekick
|
||||||
button.add().growY();
|
button.add().growY();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user