From febc1e53b61cfaeb9845020ada6de1c452bb094f Mon Sep 17 00:00:00 2001 From: Anuken Date: Thu, 30 Aug 2018 09:05:15 -0400 Subject: [PATCH] Added dedicated server crash reports --- .../io/anuke/mindustry/core/GameState.java | 1 - .../anuke/mindustry/net/Administration.java | 49 ------------- .../anuke/mindustry/desktop/CrashHandler.java | 1 + .../anuke/mindustry/server/CrashHandler.java | 70 +++++++++++++++++++ .../anuke/mindustry/server/ServerControl.java | 10 ++- .../mindustry/server/ServerLauncher.java | 16 +++-- 6 files changed, 90 insertions(+), 57 deletions(-) create mode 100644 server/src/io/anuke/mindustry/server/CrashHandler.java diff --git a/core/src/io/anuke/mindustry/core/GameState.java b/core/src/io/anuke/mindustry/core/GameState.java index 76a0ae95b1..a38a46e01f 100644 --- a/core/src/io/anuke/mindustry/core/GameState.java +++ b/core/src/io/anuke/mindustry/core/GameState.java @@ -14,7 +14,6 @@ public class GameState{ public boolean gameOver = false; public GameMode mode = GameMode.waves; public Difficulty difficulty = Difficulty.normal; - public boolean friendlyFire; public WaveSpawner spawner = new WaveSpawner(); public Teams teams = new Teams(); private State state = State.menu; diff --git a/core/src/io/anuke/mindustry/net/Administration.java b/core/src/io/anuke/mindustry/net/Administration.java index 87ca337415..51129ac9f7 100644 --- a/core/src/io/anuke/mindustry/net/Administration.java +++ b/core/src/io/anuke/mindustry/net/Administration.java @@ -63,55 +63,6 @@ public class Administration{ return editLogs; } - /* - public void rollbackWorld(int rollbackTimes) { - for(IntMap.Entry> editLog : editLogs.entries()) { - int coords = editLog.key; - Array 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; - - //TODO fix this mess, broken with 4.0 - - if(log.action == EditLog.EditAction.PLACE) { - // Build.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) { - //Build.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; diff --git a/desktop/src/io/anuke/mindustry/desktop/CrashHandler.java b/desktop/src/io/anuke/mindustry/desktop/CrashHandler.java index 735d727b01..b0bfcb5f19 100644 --- a/desktop/src/io/anuke/mindustry/desktop/CrashHandler.java +++ b/desktop/src/io/anuke/mindustry/desktop/CrashHandler.java @@ -40,6 +40,7 @@ public class CrashHandler{ ex(() -> value.addChild("build", new JsonValue(Version.build))); ex(() -> value.addChild("net", new JsonValue(fn))); ex(() -> value.addChild("server", new JsonValue(fs))); + ex(() -> value.addChild("gamemode", new JsonValue(Vars.state.mode.toString()))); ex(() -> value.addChild("os", new JsonValue(System.getProperty("os.name")))); ex(() -> value.addChild("multithreading", new JsonValue(Settings.getBool("multithread")))); ex(() -> value.addChild("trace", new JsonValue(parseException(e)))); diff --git a/server/src/io/anuke/mindustry/server/CrashHandler.java b/server/src/io/anuke/mindustry/server/CrashHandler.java new file mode 100644 index 0000000000..706e02343b --- /dev/null +++ b/server/src/io/anuke/mindustry/server/CrashHandler.java @@ -0,0 +1,70 @@ +package io.anuke.mindustry.server; + +import com.badlogic.gdx.utils.JsonValue; +import com.badlogic.gdx.utils.JsonValue.ValueType; +import com.badlogic.gdx.utils.JsonWriter.OutputType; +import io.anuke.mindustry.Vars; +import io.anuke.mindustry.game.Version; +import io.anuke.mindustry.net.Net; +import io.anuke.ucore.core.Settings; +import io.anuke.ucore.util.Log; + +import java.io.PrintWriter; +import java.io.StringWriter; + +public class CrashHandler{ + + public static void handle(Throwable e){ + e.printStackTrace(); + + //don't create crash logs for me (anuke), as it's expected + //also don't create logs for custom builds + if(System.getProperty("user.name").equals("anuke") || Version.build == -1) return; + + //if getting the crash report property failed, OR if it set to false... don't send it + try{ + if(!Settings.getBool("crashreport")) return; + }catch(Throwable ignored){ + return; + } + + //attempt to close connections, if applicable + try{ + Net.dispose(); + }catch(Throwable p){ + p.printStackTrace(); + } + + JsonValue value = new JsonValue(ValueType.object); + + //add all relevant info, ignoring exceptions + ex(() -> value.addChild("build", new JsonValue(Version.build))); + ex(() -> value.addChild("mode", new JsonValue(Vars.state.mode.toString()))); + ex(() -> value.addChild("difficulty", new JsonValue(Vars.state.difficulty.toString()))); + ex(() -> value.addChild("players", new JsonValue(Vars.playerGroup.size()))); + ex(() -> value.addChild("os", new JsonValue(System.getProperty("os.name")))); + ex(() -> value.addChild("trace", new JsonValue(parseException(e)))); + + Log.info("&lcSending crash report."); + //post to crash report URL + Net.http(Vars.crashReportURL, "POST", value.toJson(OutputType.json), r -> System.exit(1), t -> System.exit(1)); + + //sleep forever + try{ Thread.sleep(Long.MAX_VALUE); }catch(InterruptedException ignored){} + } + + private static String parseException(Throwable e){ + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + e.printStackTrace(pw); + return sw.toString(); + } + + private static void ex(Runnable r){ + try{ + r.run(); + }catch(Throwable t){ + t.printStackTrace(); + } + } +} diff --git a/server/src/io/anuke/mindustry/server/ServerControl.java b/server/src/io/anuke/mindustry/server/ServerControl.java index a579ca4710..a8d0a2ab7f 100644 --- a/server/src/io/anuke/mindustry/server/ServerControl.java +++ b/server/src/io/anuke/mindustry/server/ServerControl.java @@ -54,6 +54,7 @@ public class ServerControl extends Module{ "admins", "", "sector_x", 0, "sector_y", 1, + "crashreport", false, "port", port ); @@ -338,7 +339,14 @@ public class ServerControl extends Module{ } }); - handler.register("debug", "", "Disables or enables debug ode", arg -> { + handler.register("crashreport", "", "Disables or enables automatic crash reporting", arg -> { + boolean value = arg[0].equalsIgnoreCase("on"); + Settings.putBool("crashreport", value); + Settings.save(); + info("Crash reporting is now {0}.", value ? "on" : "off"); + }); + + handler.register("debug", "", "Disables or enables debug mode", arg -> { boolean value = arg[0].equalsIgnoreCase("on"); debug = value; info("Debug mode is now {0}.", value ? "on" : "off"); diff --git a/server/src/io/anuke/mindustry/server/ServerLauncher.java b/server/src/io/anuke/mindustry/server/ServerLauncher.java index dbc25ea35b..3ed3280250 100644 --- a/server/src/io/anuke/mindustry/server/ServerLauncher.java +++ b/server/src/io/anuke/mindustry/server/ServerLauncher.java @@ -52,20 +52,24 @@ public class ServerLauncher extends HeadlessApplication{ } public static void main(String[] args){ + try{ - Net.setClientProvider(new KryoClient()); - Net.setServerProvider(new KryoServer()); + Net.setClientProvider(new KryoClient()); + Net.setServerProvider(new KryoServer()); - HeadlessApplicationConfiguration config = new HeadlessApplicationConfiguration(); - config.preferencesDirectory = OS.getAppDataDirectoryString("Mindustry"); + HeadlessApplicationConfiguration config = new HeadlessApplicationConfiguration(); + config.preferencesDirectory = OS.getAppDataDirectoryString("Mindustry"); - new ServerLauncher(new MindustryServer(args), config); + new ServerLauncher(new MindustryServer(args), config); + }catch(Throwable t){ + CrashHandler.handle(t); + } //find and handle uncaught exceptions in libGDX thread for(Thread thread : Thread.getAllStackTraces().keySet()){ if(thread.getName().equals("HeadlessApplication")){ thread.setUncaughtExceptionHandler((t, throwable) -> { - throwable.printStackTrace(); + CrashHandler.handle(throwable); System.exit(-1); }); break;