Merge branch 'master' of https://github.com/Anuken/Mindustry into 4.0
This commit is contained in:
@@ -96,7 +96,7 @@ public class Vars{
|
||||
|
||||
public static final int tilesize = 8;
|
||||
|
||||
public static final Locale[] locales = {new Locale("en"), new Locale("fr", "FR"), new Locale("ru"), new Locale("pl", "PL"),
|
||||
public static final Locale[] locales = {new Locale("en"), new Locale("fr", "FR"), new Locale("ru"), new Locale("uk", "UA"), new Locale("pl", "PL"),
|
||||
new Locale("de"), new Locale("es", "LA"), new Locale("pt", "BR"), new Locale("ko"), new Locale("in", "ID")};
|
||||
|
||||
public static final Color[] playerColors = {
|
||||
|
||||
@@ -8,10 +8,9 @@ import io.anuke.mindustry.entities.SyncEntity;
|
||||
import io.anuke.mindustry.game.EventType.GameOverEvent;
|
||||
import io.anuke.mindustry.io.Platform;
|
||||
import io.anuke.mindustry.io.Version;
|
||||
import io.anuke.mindustry.net.Administration;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
import io.anuke.mindustry.net.*;
|
||||
import io.anuke.mindustry.net.Administration.PlayerInfo;
|
||||
import io.anuke.mindustry.net.Net.SendMode;
|
||||
import io.anuke.mindustry.net.NetworkIO;
|
||||
import io.anuke.mindustry.net.Packets.*;
|
||||
import io.anuke.mindustry.resource.*;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
@@ -32,7 +31,7 @@ import java.nio.ByteBuffer;
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class NetServer extends Module{
|
||||
private final static float serverSyncTime = 4, itemSyncTime = 10;
|
||||
private final static float serverSyncTime = 4, itemSyncTime = 10, kickDuration = 30 * 1000;
|
||||
|
||||
private final static int timerEntitySync = 0;
|
||||
private final static int timerStateSync = 1;
|
||||
@@ -52,40 +51,48 @@ public class NetServer extends Module{
|
||||
|
||||
Net.handleServer(Connect.class, (id, connect) -> {
|
||||
if(admins.isIPBanned(connect.addressTCP)){
|
||||
Net.kickConnection(id, KickReason.banned);
|
||||
kick(id, KickReason.banned);
|
||||
}
|
||||
});
|
||||
|
||||
Net.handleServer(ConnectPacket.class, (id, packet) -> {
|
||||
String uuid = new String(Base64Coder.encode(packet.uuid));
|
||||
|
||||
if(Net.getConnection(id) == null ||
|
||||
admins.isIPBanned(Net.getConnection(id).address)) return;
|
||||
|
||||
TraceInfo trace = admins.getTrace(Net.getConnection(id).address);
|
||||
PlayerInfo info = admins.getInfo(uuid);
|
||||
|
||||
if(admins.isIDBanned(uuid)){
|
||||
Net.kickConnection(id, KickReason.banned);
|
||||
kick(id, KickReason.banned);
|
||||
return;
|
||||
}
|
||||
|
||||
if(TimeUtils.millis() - info.lastKicked < kickDuration){
|
||||
kick(id, KickReason.recentKick);
|
||||
return;
|
||||
}
|
||||
|
||||
String ip = Net.getConnection(id).address;
|
||||
|
||||
admins.setKnownName(ip, packet.name);
|
||||
admins.setKnownIP(uuid, ip);
|
||||
admins.getTrace(ip).uuid = uuid;
|
||||
admins.getTrace(ip).android = packet.android;
|
||||
admins.updatePlayerJoined(uuid, ip, packet.name);
|
||||
trace.uuid = uuid;
|
||||
trace.android = packet.android;
|
||||
|
||||
if(packet.version != Version.build && Version.build != -1 && packet.version != -1){
|
||||
Net.kickConnection(id, packet.version > Version.build ? KickReason.serverOutdated : KickReason.clientOutdated);
|
||||
kick(id, packet.version > Version.build ? KickReason.serverOutdated : KickReason.clientOutdated);
|
||||
return;
|
||||
}
|
||||
|
||||
if(packet.version == -1){
|
||||
admins.getTrace(ip).modclient = true;
|
||||
trace.modclient = true;
|
||||
}
|
||||
|
||||
Log.info("Sending data to player '{0}' / {1}", packet.name, id);
|
||||
|
||||
Player player = new Player();
|
||||
player.isAdmin = admins.isAdmin(Net.getConnection(id).address);
|
||||
player.isAdmin = admins.isAdmin(uuid, ip);
|
||||
player.clientid = id;
|
||||
player.name = packet.name;
|
||||
player.mech = packet.android ? Mech.standardShip : Mech.standard;
|
||||
@@ -95,7 +102,7 @@ public class NetServer extends Module{
|
||||
player.color.set(packet.color);
|
||||
connections.put(id, player);
|
||||
|
||||
admins.getTrace(ip).playerid = player.id;
|
||||
trace.playerid = player.id;
|
||||
|
||||
//TODO try DeflaterOutputStream
|
||||
ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
||||
@@ -137,6 +144,7 @@ public class NetServer extends Module{
|
||||
Net.send(dc, SendMode.tcp);
|
||||
|
||||
Platform.instance.updateRPC();
|
||||
admins.save();
|
||||
});
|
||||
|
||||
Net.handleServer(PositionPacket.class, (id, packet) -> {
|
||||
@@ -149,9 +157,23 @@ public class NetServer extends Module{
|
||||
BulletType type = BaseBulletType.getByID(packet.bulletid);
|
||||
|
||||
player.onRemoteShoot(type, packet.x, packet.y, packet.rotation, packet.data);
|
||||
TraceInfo info = admins.getTrace(Net.getConnection(id).address);
|
||||
Weapon weapon = Upgrade.getByID((byte)packet.data);
|
||||
|
||||
packet.entityid = player.id;
|
||||
packet.groupid = (byte)player.getGroup().getID();
|
||||
float wtrc = 40f;
|
||||
|
||||
if(!Timers.get(info.ip + "-weapontrace", wtrc)){
|
||||
info.fastShots ++;
|
||||
}else{
|
||||
|
||||
if(info.fastShots - 2 > (int)(wtrc / (weapon.getReload() / 2f))){
|
||||
kick(id, KickReason.kick);
|
||||
}
|
||||
|
||||
info.fastShots = 0;
|
||||
}
|
||||
|
||||
packet.entityid = connections.get(id).id;
|
||||
Net.sendExcept(id, packet, SendMode.udp);
|
||||
});
|
||||
|
||||
@@ -173,6 +195,7 @@ public class NetServer extends Module{
|
||||
|
||||
admins.getTrace(Net.getConnection(id).address).lastBlockPlaced = block;
|
||||
admins.getTrace(Net.getConnection(id).address).totalBlocksPlaced ++;
|
||||
admins.getInfo(admins.getTrace(Net.getConnection(id).address).uuid).totalBlockPlaced ++;
|
||||
|
||||
Net.send(packet, SendMode.tcp);
|
||||
});
|
||||
@@ -188,6 +211,7 @@ public class NetServer extends Module{
|
||||
if(block != null) {
|
||||
admins.getTrace(Net.getConnection(id).address).lastBlockBroken = block;
|
||||
admins.getTrace(Net.getConnection(id).address).totalBlocksBroken++;
|
||||
admins.getInfo(admins.getTrace(Net.getConnection(id).address).uuid).totalBlocksBroken ++;
|
||||
if (block.update || block.destructible)
|
||||
admins.getTrace(Net.getConnection(id).address).structureBlocksBroken++;
|
||||
}
|
||||
@@ -270,10 +294,10 @@ public class NetServer extends Module{
|
||||
|
||||
if(packet.action == AdminAction.ban){
|
||||
admins.banPlayerIP(ip);
|
||||
Net.kickConnection(other.clientid, KickReason.banned);
|
||||
kick(other.clientid, KickReason.banned);
|
||||
Log.info("&lc{0} has banned {1}.", player.name, other.name);
|
||||
}else if(packet.action == AdminAction.kick){
|
||||
Net.kickConnection(other.clientid, KickReason.kick);
|
||||
kick(other.clientid, KickReason.kick);
|
||||
Log.info("&lc{0} has kicked {1}.", player.name, other.name);
|
||||
}else if(packet.action == AdminAction.trace){
|
||||
TracePacket trace = new TracePacket();
|
||||
@@ -306,6 +330,31 @@ public class NetServer extends Module{
|
||||
admins.clearTraces();
|
||||
}
|
||||
|
||||
public void kick(int connection, KickReason reason){
|
||||
NetConnection con = Net.getConnection(connection);
|
||||
if(con == null){
|
||||
Log.err("Cannot kick unknown player!");
|
||||
return;
|
||||
}else{
|
||||
Log.info("Kicking connection #{0} / IP: {1}. Reason: {2}", connection, con.address, reason);
|
||||
}
|
||||
|
||||
PlayerInfo info = admins.getInfo(admins.getTrace(con.address).uuid);
|
||||
|
||||
if(reason == KickReason.kick || reason == KickReason.banned){
|
||||
info.timesKicked ++;
|
||||
info.lastKicked = TimeUtils.millis();
|
||||
}
|
||||
|
||||
KickPacket p = new KickPacket();
|
||||
p.reason = reason;
|
||||
|
||||
con.send(p, SendMode.tcp);
|
||||
Timers.runTask(2f, con::close);
|
||||
|
||||
admins.save();
|
||||
}
|
||||
|
||||
void sync(){
|
||||
|
||||
if(timer.get(timerEntitySync, serverSyncTime)){
|
||||
|
||||
@@ -156,12 +156,12 @@ public class UI extends SceneModule{
|
||||
language = new LanguageDialog();
|
||||
settings = new SettingsMenuDialog();
|
||||
paused = new PausedDialog();
|
||||
changelog = new ChangelogDialog();
|
||||
about = new AboutDialog();
|
||||
host = new HostDialog();
|
||||
bans = new BansDialog();
|
||||
admins = new AdminsDialog();
|
||||
traces = new TraceDialog();
|
||||
changelog = new ChangelogDialog();
|
||||
|
||||
build.begin(scene);
|
||||
|
||||
|
||||
@@ -26,6 +26,8 @@ public class DefaultKeybinds {
|
||||
"block_info", Input.CONTROL_LEFT,
|
||||
"player_list", Input.TAB,
|
||||
"chat", Input.ENTER,
|
||||
"chat_scroll_up", Input.UP,
|
||||
"chat_scroll_down", Input.DOWN,
|
||||
"console", Input.GRAVE,
|
||||
"weapon_1", Input.NUM_1,
|
||||
"weapon_2", Input.NUM_2,
|
||||
@@ -53,6 +55,8 @@ public class DefaultKeybinds {
|
||||
"rotate", new Axis(Input.CONTROLLER_A, Input.CONTROLLER_B),
|
||||
"player_list", Input.CONTROLLER_START,
|
||||
"chat", Input.ENTER,
|
||||
"chat_scroll_up", Input.UP,
|
||||
"chat_scroll_down", Input.DOWN,
|
||||
"console", Input.GRAVE,
|
||||
"weapon_1", Input.NUM_1,
|
||||
"weapon_2", Input.NUM_2,
|
||||
|
||||
@@ -107,6 +107,10 @@ public class DesktopInput extends InputHandler{
|
||||
Cursors.restoreCursor();
|
||||
}
|
||||
}
|
||||
|
||||
if(target != null && target.block().isConfigurable(target)){
|
||||
showCursor = true;
|
||||
}
|
||||
|
||||
if(target != null && Inputs.keyTap("select") && !ui.hasMouse()){
|
||||
if(target.block().isConfigurable(target)){
|
||||
|
||||
@@ -116,19 +116,23 @@ public abstract class InputHandler extends InputAdapter{
|
||||
}
|
||||
|
||||
public void placeBlock(int x, int y, Block result, int rotation, boolean effects, boolean sound){
|
||||
if(!Net.client()){
|
||||
if(!Net.client()){ //is server or singleplayer
|
||||
Placement.placeBlock(player.team, x, y, result, rotation, effects, sound);
|
||||
Tile tile = world.tile(x, y);
|
||||
if(tile != null) result.placed(tile);
|
||||
}
|
||||
|
||||
if(Net.active()){
|
||||
NetEvents.handlePlace(x, y, result, rotation);
|
||||
}
|
||||
|
||||
if(!Net.client()){
|
||||
Tile tile = world.tile(x, y);
|
||||
if(tile != null) result.placed(tile);
|
||||
}
|
||||
}
|
||||
|
||||
public void breakBlock(int x, int y, boolean sound){
|
||||
if(!Net.client()) Placement.breakBlock(player.team, x, y, true, sound);
|
||||
if(!Net.client())
|
||||
Placement.breakBlock(player.team, x, y, true, sound);
|
||||
|
||||
if(Net.active()){
|
||||
NetEvents.handleBreak(x, y);
|
||||
|
||||
@@ -7,177 +7,228 @@ import io.anuke.ucore.core.Settings;
|
||||
|
||||
public class Administration {
|
||||
private Json json = new Json();
|
||||
/**All player info. Maps UUIDs to info. This persists throughout restarts.*/
|
||||
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<>();
|
||||
private Array<String> bannedIPs = new Array<>();
|
||||
private Array<String> bannedIDs = new Array<>();
|
||||
private Array<String> admins = new Array<>();
|
||||
private ObjectMap<String, String> ipNames = new ObjectMap<>();
|
||||
private ObjectMap<String, String> idIPs = new ObjectMap<>();
|
||||
private ObjectMap<String, TraceInfo> traces = new ObjectMap<>();
|
||||
|
||||
public Administration(){
|
||||
Settings.defaultList(
|
||||
"bans", "{}",
|
||||
"bannedIDs", "{}",
|
||||
"admins", "{}",
|
||||
"knownIPs", "{}",
|
||||
"knownIDs", "{}"
|
||||
);
|
||||
Settings.defaults("playerInfo", "{}");
|
||||
Settings.defaults("bannedIPs", "{}");
|
||||
|
||||
load();
|
||||
}
|
||||
|
||||
public TraceInfo getTrace(String ip){
|
||||
if(!traces.containsKey(ip)) traces.put(ip, new TraceInfo(ip));
|
||||
/**Call when a player joins to update their information here.*/
|
||||
public void updatePlayerJoined(String id, String ip, String name){
|
||||
PlayerInfo info = getCreateInfo(id);
|
||||
info.lastName = name;
|
||||
info.lastIP = ip;
|
||||
info.timesJoined ++;
|
||||
if(!info.names.contains(name, false)) info.names.add(name);
|
||||
if(!info.ips.contains(ip, false)) info.ips.add(ip);
|
||||
}
|
||||
|
||||
return traces.get(ip);
|
||||
/**Returns trace info by IP.*/
|
||||
public TraceInfo getTrace(String ip){
|
||||
if(!traceInfo.containsKey(ip)) traceInfo.put(ip, new TraceInfo(ip));
|
||||
|
||||
return traceInfo.get(ip);
|
||||
}
|
||||
|
||||
public void clearTraces(){
|
||||
traces.clear();
|
||||
traceInfo.clear();
|
||||
}
|
||||
|
||||
/**Sets last known name for an IP.*/
|
||||
public void setKnownName(String ip, String name){
|
||||
ipNames.put(ip, name);
|
||||
saveKnown();
|
||||
}
|
||||
|
||||
/**Sets last known UUID for an IP.*/
|
||||
public void setKnownIP(String id, String ip){
|
||||
idIPs.put(id, ip);
|
||||
saveKnown();
|
||||
}
|
||||
|
||||
/**Returns the last known name for an IP. Returns 'unknown' if this IP has an unknown username.*/
|
||||
public String getLastName(String ip){
|
||||
return ipNames.get(ip, "unknown");
|
||||
}
|
||||
|
||||
/**Returns the last known IP for a UUID. Returns 'unknown' if this IP has an unknown IP.*/
|
||||
public String getLastIP(String id){
|
||||
return idIPs.get(id, "unknown");
|
||||
}
|
||||
|
||||
/**Return the last known device ID associated with an IP. Returns 'unknown' if this IP has an unknown device.*/
|
||||
public String getLastID(String ip){
|
||||
for(String id : idIPs.keys()){
|
||||
if(idIPs.get(id).equals(ip)){
|
||||
return id;
|
||||
}
|
||||
}
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
/**Returns list of banned IPs.*/
|
||||
public Array<String> getBanned(){
|
||||
return bannedIPs;
|
||||
}
|
||||
|
||||
/**Returns list of banned IDs.*/
|
||||
public Array<String> getBannedIDs(){
|
||||
return bannedIDs;
|
||||
}
|
||||
|
||||
/**Bans a player by IP; returns whether this player was already banned.*/
|
||||
/**Bans a player by IP; returns whether this player was already banned.
|
||||
* If there are players who at any point had this IP, they will be UUID banned as well.*/
|
||||
public boolean banPlayerIP(String ip){
|
||||
if(bannedIPs.contains(ip, false))
|
||||
return false;
|
||||
|
||||
for(PlayerInfo info : playerInfo.values()){
|
||||
if(info.ips.contains(ip, false)){
|
||||
info.banned = true;
|
||||
}
|
||||
}
|
||||
|
||||
bannedIPs.add(ip);
|
||||
saveBans();
|
||||
save();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**Bans a player by UUID.*/
|
||||
/**Bans a player by UUID; returns whether this player was already banned.*/
|
||||
public boolean banPlayerID(String id){
|
||||
if(bannedIDs.contains(id, false))
|
||||
if(playerInfo.containsKey(id) && playerInfo.get(id).banned)
|
||||
return false;
|
||||
bannedIDs.add(id);
|
||||
saveBans();
|
||||
|
||||
getCreateInfo(id).banned = true;
|
||||
|
||||
save();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**Unbans a player by IP; returns whether this player was banned in the first place..*/
|
||||
/**Unbans a player by IP; returns whether this player was banned in the first place.
|
||||
* This method also unbans any player that was banned and had this IP.*/
|
||||
public boolean unbanPlayerIP(String ip){
|
||||
if(!bannedIPs.contains(ip, false))
|
||||
return false;
|
||||
boolean found = bannedIPs.contains(ip, false);
|
||||
|
||||
for(PlayerInfo info : playerInfo.values()){
|
||||
if(info.ips.contains(ip, false)){
|
||||
info.banned = false;
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
bannedIPs.removeValue(ip, false);
|
||||
saveBans();
|
||||
|
||||
return true;
|
||||
if(found) save();
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
/**Unbans a player by IP; returns whether this player was banned in the first place..*/
|
||||
public boolean unbanPlayerID(String ip){
|
||||
if(!bannedIDs.contains(ip, false))
|
||||
/**Unbans a player by ID; returns whether this player was banned in the first place.
|
||||
* This also unbans all IPs the player used.*/
|
||||
public boolean unbanPlayerID(String id){
|
||||
PlayerInfo info = getCreateInfo(id);
|
||||
|
||||
if(!info.banned)
|
||||
return false;
|
||||
bannedIDs.removeValue(ip, false);
|
||||
saveBans();
|
||||
|
||||
info.banned = false;
|
||||
bannedIPs.removeAll(info.ips, false);
|
||||
save();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**Returns list of banned IPs.*/
|
||||
public Array<String> getAdmins(){
|
||||
return admins;
|
||||
/**Returns list of all players with admin status*/
|
||||
public Array<PlayerInfo> getAdmins(){
|
||||
Array<PlayerInfo> result = new Array<>();
|
||||
for(PlayerInfo info : playerInfo.values()){
|
||||
if(info.admin){
|
||||
result.add(info);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**Returns list of all players with admin status*/
|
||||
public Array<PlayerInfo> getBanned(){
|
||||
Array<PlayerInfo> result = new Array<>();
|
||||
for(PlayerInfo info : playerInfo.values()){
|
||||
if(info.banned){
|
||||
result.add(info);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**Returns all banned IPs. This does not include the IPs of ID-banned players.*/
|
||||
public Array<String> getBannedIPs(){
|
||||
return bannedIPs;
|
||||
}
|
||||
|
||||
/**Makes a player an admin. Returns whether this player was already an admin.*/
|
||||
public boolean adminPlayer(String ip){
|
||||
if(admins.contains(ip, false))
|
||||
public boolean adminPlayer(String id, String ip){
|
||||
PlayerInfo info = getCreateInfo(id);
|
||||
|
||||
if(info.admin)
|
||||
return false;
|
||||
admins.add(ip);
|
||||
saveAdmins();
|
||||
|
||||
info.validAdminIP = ip;
|
||||
info.admin = true;
|
||||
save();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**Makes a player no longer an admin. Returns whether this player was an admin in the first place.*/
|
||||
public boolean unAdminPlayer(String ip){
|
||||
if(!admins.contains(ip, false))
|
||||
public boolean unAdminPlayer(String id){
|
||||
PlayerInfo info = getCreateInfo(id);
|
||||
|
||||
if(!info.admin)
|
||||
return false;
|
||||
admins.removeValue(ip, false);
|
||||
saveAdmins();
|
||||
|
||||
info.admin = false;
|
||||
save();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isIPBanned(String ip){
|
||||
return bannedIPs.contains(ip, false);
|
||||
return bannedIPs.contains(ip, false) || (findByIP(ip) != null && findByIP(ip).banned);
|
||||
}
|
||||
|
||||
public boolean isIDBanned(String uuid){
|
||||
return bannedIDs.contains(uuid, false);
|
||||
return getCreateInfo(uuid).banned;
|
||||
}
|
||||
|
||||
public boolean isAdmin(String ip){
|
||||
return admins.contains(ip, false);
|
||||
public boolean isAdmin(String id, String ip){
|
||||
PlayerInfo info = getCreateInfo(id);
|
||||
return info.admin && ip.equals(info.validAdminIP);
|
||||
}
|
||||
|
||||
private void saveKnown(){
|
||||
Settings.putString("knownIPs", json.toJson(ipNames));
|
||||
Settings.putString("knownIDs", json.toJson(idIPs));
|
||||
Settings.save();
|
||||
public PlayerInfo getInfo(String id){
|
||||
return getCreateInfo(id);
|
||||
}
|
||||
|
||||
private void saveBans(){
|
||||
Settings.putString("bans", json.toJson(bannedIPs));
|
||||
Settings.putString("bannedIDs", json.toJson(bannedIDs));
|
||||
Settings.save();
|
||||
public PlayerInfo getInfoOptional(String id){
|
||||
return playerInfo.get(id);
|
||||
}
|
||||
|
||||
private void saveAdmins(){
|
||||
Settings.putString("admins", json.toJson(admins));
|
||||
public PlayerInfo findByIP(String ip){
|
||||
for(PlayerInfo info : playerInfo.values()){
|
||||
if(info.ips.contains(ip, false)){
|
||||
return info;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private PlayerInfo getCreateInfo(String id){
|
||||
if(playerInfo.containsKey(id)){
|
||||
return playerInfo.get(id);
|
||||
}else{
|
||||
PlayerInfo info = new PlayerInfo(id);
|
||||
playerInfo.put(id, info);
|
||||
save();
|
||||
return info;
|
||||
}
|
||||
}
|
||||
|
||||
public void save(){
|
||||
Settings.putString("playerInfo", json.toJson(playerInfo));
|
||||
Settings.putString("bannedIPs", json.toJson(bannedIPs));
|
||||
Settings.save();
|
||||
}
|
||||
|
||||
private void load(){
|
||||
bannedIPs = json.fromJson(Array.class, Settings.getString("bans"));
|
||||
bannedIDs = json.fromJson(Array.class, Settings.getString("bannedIDs"));
|
||||
admins = json.fromJson(Array.class, Settings.getString("admins"));
|
||||
ipNames = json.fromJson(ObjectMap.class, Settings.getString("knownIPs"));
|
||||
idIPs = json.fromJson(ObjectMap.class, Settings.getString("knownIDs"));
|
||||
playerInfo = json.fromJson(ObjectMap.class, Settings.getString("playerInfo"));
|
||||
bannedIPs = json.fromJson(Array.class, Settings.getString("bannedIPs"));
|
||||
}
|
||||
|
||||
public static class PlayerInfo{
|
||||
public String id;
|
||||
public String lastName = "<unknown>", lastIP = "<unknown>";
|
||||
public String validAdminIP;
|
||||
public Array<String> ips = new Array<>();
|
||||
public Array<String> names = new Array<>();
|
||||
public int timesKicked; //TODO not implemented!
|
||||
public int timesJoined;
|
||||
public int totalBlockPlaced;
|
||||
public int totalBlocksBroken;
|
||||
public boolean banned, admin;
|
||||
public long lastKicked; //last kicked timestamp
|
||||
|
||||
PlayerInfo(String id){
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
private PlayerInfo(){}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -12,7 +12,6 @@ import com.badlogic.gdx.utils.reflect.ClassReflection;
|
||||
import io.anuke.mindustry.io.Platform;
|
||||
import io.anuke.mindustry.net.Packet.ImportantPacket;
|
||||
import io.anuke.mindustry.net.Packet.UnimportantPacket;
|
||||
import io.anuke.mindustry.net.Packets.KickReason;
|
||||
import io.anuke.mindustry.net.Streamable.StreamBegin;
|
||||
import io.anuke.mindustry.net.Streamable.StreamBuilder;
|
||||
import io.anuke.mindustry.net.Streamable.StreamChunk;
|
||||
@@ -101,11 +100,6 @@ public class Net{
|
||||
clientProvider.discover(cons);
|
||||
}
|
||||
|
||||
/**Kick a specified connection from the server.*/
|
||||
public static void kickConnection(int id, KickReason reason){
|
||||
serverProvider.kick(id, reason);
|
||||
}
|
||||
|
||||
/**Returns a list of all connections IDs.*/
|
||||
public static Array<NetConnection> getConnections(){
|
||||
return (Array<NetConnection>)serverProvider.getConnections();
|
||||
@@ -307,10 +301,6 @@ public class Net{
|
||||
Array<? extends NetConnection> getConnections();
|
||||
/**Returns a connection by ID.*/
|
||||
NetConnection getByID(int id);
|
||||
/**Kick a certain connection.*/
|
||||
void kick(int connection, KickReason reason);
|
||||
/**Returns the ping for a certain connection.*/
|
||||
int getPingFor(NetConnection connection);
|
||||
/**Close all connections.*/
|
||||
void dispose();
|
||||
}
|
||||
|
||||
@@ -350,7 +350,7 @@ public class Packets {
|
||||
}
|
||||
|
||||
public enum KickReason{
|
||||
kick, invalidPassword, clientOutdated, serverOutdated, banned, gameover(true);
|
||||
kick, invalidPassword, clientOutdated, serverOutdated, banned, gameover(true), recentKick;
|
||||
public final boolean quiet;
|
||||
|
||||
KickReason(){ quiet = false; }
|
||||
|
||||
@@ -9,6 +9,8 @@ public class TraceInfo {
|
||||
public boolean modclient;
|
||||
public boolean android;
|
||||
|
||||
public int fastShots;
|
||||
|
||||
public int totalBlocksBroken;
|
||||
public int structureBlocksBroken;
|
||||
public Block lastBlockBroken = Blocks.air;
|
||||
|
||||
@@ -117,6 +117,10 @@ public class Weapon extends Upgrade{
|
||||
Effects.sound(shootsound, x, y);
|
||||
}
|
||||
|
||||
public float getReload(){
|
||||
return reload;
|
||||
}
|
||||
|
||||
public void shoot(Player p, float x, float y, float angle){
|
||||
shootInternal(p, x, y, angle);
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@ package io.anuke.mindustry.ui.dialogs;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
import io.anuke.mindustry.Vars;
|
||||
import io.anuke.mindustry.ui.Links;
|
||||
import io.anuke.mindustry.ui.Links.LinkEntry;
|
||||
import io.anuke.ucore.core.Core;
|
||||
@@ -10,6 +9,8 @@ import io.anuke.ucore.core.Timers;
|
||||
import io.anuke.ucore.scene.ui.ScrollPane;
|
||||
import io.anuke.ucore.scene.ui.layout.Table;
|
||||
|
||||
import static io.anuke.mindustry.Vars.ui;
|
||||
|
||||
public class AboutDialog extends FloatingDialog {
|
||||
|
||||
public AboutDialog(){
|
||||
@@ -45,7 +46,7 @@ public class AboutDialog extends FloatingDialog {
|
||||
|
||||
table.addImageButton("icon-link", 14*3, () -> {
|
||||
if(!Gdx.net.openURI(link.link)){
|
||||
Vars.ui.showError("$text.linkfail");
|
||||
ui.showError("$text.linkfail");
|
||||
Gdx.app.getClipboard().setContents(link.link);
|
||||
}
|
||||
}).size(h-5, h);
|
||||
@@ -58,6 +59,7 @@ public class AboutDialog extends FloatingDialog {
|
||||
content().add(pane).growX();
|
||||
|
||||
buttons().addButton("$text.credits", this::showCredits).size(200f, 64f);
|
||||
buttons().addButton("$text.changelog.title", ui.changelog::show).size(200f, 64f);
|
||||
}
|
||||
|
||||
private void showCredits(){
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package io.anuke.mindustry.ui.dialogs;
|
||||
|
||||
import io.anuke.mindustry.entities.Player;
|
||||
import io.anuke.mindustry.net.Administration.PlayerInfo;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
import io.anuke.mindustry.net.NetConnection;
|
||||
import io.anuke.mindustry.net.NetEvents;
|
||||
@@ -36,15 +37,15 @@ public class AdminsDialog extends FloatingDialog {
|
||||
table.add("$text.server.admins.none");
|
||||
}
|
||||
|
||||
for(String ip : netServer.admins.getAdmins()){
|
||||
for(PlayerInfo info : netServer.admins.getAdmins()){
|
||||
Table res = new Table("button");
|
||||
res.margin(14f);
|
||||
|
||||
res.labelWrap("[LIGHT_GRAY]" + netServer.admins.getLastName(ip)).width(w - h - 24f);
|
||||
res.labelWrap("[LIGHT_GRAY]" + info.lastName).width(w - h - 24f);
|
||||
res.add().growX();
|
||||
res.addImageButton("icon-cancel", 14*3, () -> {
|
||||
ui.showConfirm("$text.confirm", "$text.confirmunadmin", () -> {
|
||||
netServer.admins.unAdminPlayer(ip);
|
||||
netServer.admins.unAdminPlayer(info.id);
|
||||
for(Player player : playerGroup.all()){
|
||||
NetConnection c = Net.getConnection(player.clientid);
|
||||
if(c != null){
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package io.anuke.mindustry.ui.dialogs;
|
||||
|
||||
import io.anuke.mindustry.net.Administration.PlayerInfo;
|
||||
import io.anuke.ucore.scene.ui.ScrollPane;
|
||||
import io.anuke.ucore.scene.ui.layout.Table;
|
||||
|
||||
@@ -33,15 +34,15 @@ public class BansDialog extends FloatingDialog {
|
||||
table.add("$text.server.bans.none");
|
||||
}
|
||||
|
||||
for(String ip : netServer.admins.getBanned()){
|
||||
for(PlayerInfo info : netServer.admins.getBanned()){
|
||||
Table res = new Table("button");
|
||||
res.margin(14f);
|
||||
|
||||
res.labelWrap("IP: [LIGHT_GRAY]" + ip + "\n[]Name: [LIGHT_GRAY]" + netServer.admins.getLastName(ip)).width(w - h - 24f);
|
||||
res.labelWrap("IP: [LIGHT_GRAY]" + info.lastIP + "\n[]Name: [LIGHT_GRAY]" + info.lastName).width(w - h - 24f);
|
||||
res.add().growX();
|
||||
res.addImageButton("icon-cancel", 14*3, () -> {
|
||||
ui.showConfirm("$text.confirm", "$text.confirmunban", () -> {
|
||||
netServer.admins.unbanPlayerIP(ip);
|
||||
netServer.admins.unbanPlayerID(info.id);
|
||||
setup();
|
||||
});
|
||||
}).size(h).pad(-14f);
|
||||
|
||||
@@ -31,7 +31,7 @@ public class BackgroundFragment implements Fragment {
|
||||
float logoh = logo.getRegionHeight()*logoscl;
|
||||
|
||||
Draw.color();
|
||||
Core.batch.draw(logo, w/2 - logow/2, h - logoh + 15 - Unit.dp.scl(portrait ? 30f : 30), logow, logoh);
|
||||
Core.batch.draw(logo, w/2 - logow/2, h - logoh + 15 - Unit.dp.scl(portrait ? 30f : 0), logow, logoh);
|
||||
}).visible(() -> state.is(State.menu)).grow();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import io.anuke.ucore.scene.ui.TextField;
|
||||
import io.anuke.ucore.scene.ui.layout.Table;
|
||||
import io.anuke.ucore.scene.ui.layout.Unit;
|
||||
import io.anuke.ucore.util.Log;
|
||||
import java.util.Arrays;
|
||||
|
||||
import static io.anuke.mindustry.Vars.state;
|
||||
import static io.anuke.ucore.core.Core.scene;
|
||||
@@ -39,6 +40,8 @@ public class ChatFragment extends Table implements Fragment{
|
||||
private float textWidth = Unit.dp.scl(600);
|
||||
private Color shadowColor = new Color(0, 0, 0, 0.4f);
|
||||
private float textspacing = Unit.dp.scl(10);
|
||||
private Array<String> history = new Array<String>();
|
||||
private int historyPos = 0;
|
||||
|
||||
public ChatFragment(){
|
||||
super();
|
||||
@@ -57,8 +60,21 @@ public class ChatFragment extends Table implements Fragment{
|
||||
if(Net.active() && Inputs.keyTap("chat")){
|
||||
toggle();
|
||||
}
|
||||
|
||||
if (chatOpen) {
|
||||
if (Inputs.keyTap("chat_scroll_up") && historyPos < history.size - 1) {
|
||||
if (historyPos == 0) history.set(0, chatfield.getText());
|
||||
historyPos++;
|
||||
updateChat();
|
||||
}
|
||||
if (Inputs.keyTap("chat_scroll_down") && historyPos > 0) {
|
||||
historyPos--;
|
||||
updateChat();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
history.insert(0, "");
|
||||
setup();
|
||||
}
|
||||
|
||||
@@ -69,6 +85,8 @@ public class ChatFragment extends Table implements Fragment{
|
||||
|
||||
public void clearMessages(){
|
||||
messages.clear();
|
||||
history.clear();
|
||||
history.insert(0, "");
|
||||
}
|
||||
|
||||
private void setup(){
|
||||
@@ -144,7 +162,8 @@ public class ChatFragment extends Table implements Fragment{
|
||||
|
||||
private void sendMessage(){
|
||||
String message = chatfield.getText();
|
||||
chatfield.clearText();
|
||||
clearChatInput();
|
||||
history.insert(1, message);
|
||||
|
||||
if(message.replaceAll(" ", "").isEmpty()) return;
|
||||
|
||||
@@ -170,6 +189,17 @@ public class ChatFragment extends Table implements Fragment{
|
||||
public void hide(){
|
||||
scene.setKeyboardFocus(null);
|
||||
chatOpen = false;
|
||||
clearChatInput();
|
||||
}
|
||||
|
||||
public void updateChat() {
|
||||
chatfield.setText(history.get(historyPos));
|
||||
chatfield.setCursorPosition(chatfield.getText().length());
|
||||
}
|
||||
|
||||
public void clearChatInput() {
|
||||
historyPos = 0;
|
||||
history.set(0, "");
|
||||
chatfield.setText("");
|
||||
}
|
||||
|
||||
|
||||
@@ -128,7 +128,7 @@ public class PlayerListFragment implements Fragment{
|
||||
ui.showConfirm("$text.confirm", "$text.confirmban", () -> {
|
||||
if(Net.server()) {
|
||||
netServer.admins.banPlayerIP(connection.address);
|
||||
Net.kickConnection(player.clientid, KickReason.banned);
|
||||
netServer.kick(player.clientid, KickReason.banned);
|
||||
}else{
|
||||
NetEvents.handleAdministerRequest(player, AdminAction.ban);
|
||||
}
|
||||
@@ -137,7 +137,7 @@ public class PlayerListFragment implements Fragment{
|
||||
|
||||
t.addImageButton("icon-cancel", 14*2, () -> {
|
||||
if(Net.server()) {
|
||||
Net.kickConnection(player.clientid, KickReason.kick);
|
||||
netServer.kick(player.clientid, KickReason.kick);
|
||||
}else{
|
||||
NetEvents.handleAdministerRequest(player, AdminAction.kick);
|
||||
}
|
||||
@@ -148,14 +148,16 @@ public class PlayerListFragment implements Fragment{
|
||||
t.addImageButton("icon-admin", "toggle", 14*2, () -> {
|
||||
if(Net.client()) return;
|
||||
|
||||
if(netServer.admins.isAdmin(connection.address)){
|
||||
String id = netServer.admins.getTrace(connection.address).uuid;
|
||||
|
||||
if(netServer.admins.isAdmin(id, connection.address)){
|
||||
ui.showConfirm("$text.confirm", "$text.confirmunadmin", () -> {
|
||||
netServer.admins.unAdminPlayer(connection.address);
|
||||
netServer.admins.unAdminPlayer(id);
|
||||
NetEvents.handleAdminSet(player, false);
|
||||
});
|
||||
}else{
|
||||
ui.showConfirm("$text.confirm", "$text.confirmadmin", () -> {
|
||||
netServer.admins.adminPlayer(connection.address);
|
||||
netServer.admins.adminPlayer(id, connection.address);
|
||||
NetEvents.handleAdminSet(player, true);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ public class Teleporter extends PowerBlock{
|
||||
@Override
|
||||
public void placed(Tile tile){
|
||||
tile.<TeleporterEntity>entity().color = lastColor;
|
||||
Timers.run(1f, () -> setConfigure(tile, lastColor));
|
||||
setConfigure(tile, lastColor);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user