diff --git a/.gitignore b/.gitignore
index 7f032f6..c8a7b2d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -95,3 +95,10 @@ modules.xml
.idea/sonarlint
# End of https://www.toptal.com/developers/gitignore/api/intellij+all
+target/*
+cache.txt
+clone.log
+data.txt
+Sonitor.jar
+.vscode/launch.json
+.vscode/tasks.json
diff --git a/src/main/java/xyz/msws/admintools/Monitor.java b/src/main/java/xyz/msws/admintools/Monitor.java
index e9fb685..a8f7a09 100644
--- a/src/main/java/xyz/msws/admintools/Monitor.java
+++ b/src/main/java/xyz/msws/admintools/Monitor.java
@@ -5,6 +5,7 @@
import xyz.msws.admintools.parsers.JBParser;
import xyz.msws.admintools.parsers.Parser;
import xyz.msws.admintools.parsers.PlaytimeParser;
+import xyz.msws.admintools.parsers.TTTParser;
import java.io.File;
import java.io.FileWriter;
@@ -33,6 +34,8 @@ public Monitor() {
parsers.add(new PlaytimeParser(this));
if (config.doJailbreak())
parsers.add(new JBParser(this));
+ if (config.doTTT())
+ parsers.add(new TTTParser(this));
timer.schedule(this, 0, config.getRate());
}
@@ -82,13 +85,16 @@ private boolean setupFiles() {
}
// Drive Specific
- directories.add(master.getAbsolutePath().charAt(0) + ":\\Program Files (x86)\\Steam\\steamapps\\common\\Counter-Strike Global Offensive\\csgo");
- directories.add(master.getAbsolutePath().charAt(0) + ":\\Program Files\\Steam\\steamapps\\common\\Counter-Strike Global Offensive\\csgo");
+ directories.add(master.getAbsolutePath().charAt(0)
+ + ":\\Program Files (x86)\\Steam\\steamapps\\common\\Counter-Strike Global Offensive\\csgo");
+ directories.add(master.getAbsolutePath().charAt(0)
+ + ":\\Program Files\\Steam\\steamapps\\common\\Counter-Strike Global Offensive\\csgo");
// Default Computer
directories.add("C:\\Program Files (x86)\\Steam\\steamapps\\common\\Counter-Strike Global Offensive\\csgo");
directories.add("C:\\Program Files\\Steam\\steamapps\\common\\Counter-Strike Global Offensive\\csgo");
- directories.add("C:\\Program Files\\Steam\\steamapps\\common\\Counter-Strike Global Offensive\\csgo\\output.log");
+ directories
+ .add("C:\\Program Files\\Steam\\steamapps\\common\\Counter-Strike Global Offensive\\csgo\\output.log");
// Mac
directories.add("~/Library/Application Support/Steam/steamapps/common/Counter-Strike Global Offensive/csgo");
@@ -97,8 +103,10 @@ private boolean setupFiles() {
directories.add("~/.steam/steam/SteamApps/common/Counter-Strike Global Offensive/csgo");
for (int i = 'A'; i <= 'Z'; i++) {
- directories.add((char) i + ":\\Program Files (x86)\\Steam\\steamapps\\common\\Counter-Strike Global Offensive\\csgo");
- directories.add((char) i + ":\\Program Files\\Steam\\steamapps\\common\\Counter-Strike Global Offensive\\csgo");
+ directories.add((char) i
+ + ":\\Program Files (x86)\\Steam\\steamapps\\common\\Counter-Strike Global Offensive\\csgo");
+ directories.add(
+ (char) i + ":\\Program Files\\Steam\\steamapps\\common\\Counter-Strike Global Offensive\\csgo");
}
File parent = null;
@@ -112,7 +120,8 @@ private boolean setupFiles() {
}
}
if (!parent.exists()) {
- System.out.println("Could not locate CS:GO directory. Please specify the proper directory in the settings.txt");
+ System.out.println(
+ "Could not locate CS:GO directory. Please specify the proper directory in the settings.txt");
return false;
}
@@ -154,7 +163,8 @@ private boolean setupFiles() {
System.out.println("Supplied path is a folder, searching for " + logFile);
output = new File(output, logFile);
if (!output.exists())
- output = new File("C:\\Program Files (x86)\\Steam\\steamapps\\common\\Counter-Strike Global Offensive\\csgo\\output.log");
+ output = new File(
+ "C:\\Program Files (x86)\\Steam\\steamapps\\common\\Counter-Strike Global Offensive\\csgo\\output.log");
}
if (!output.exists()) {
output = new File(parent, logFile);
diff --git a/src/main/java/xyz/msws/admintools/data/Action.java b/src/main/java/xyz/msws/admintools/data/Action.java
new file mode 100644
index 0000000..09af156
--- /dev/null
+++ b/src/main/java/xyz/msws/admintools/data/Action.java
@@ -0,0 +1,88 @@
+package xyz.msws.admintools.data;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import xyz.msws.admintools.data.DataStructs.ActionType;
+import xyz.msws.admintools.data.DataStructs.Role;
+import xyz.msws.admintools.data.jb.JailRole;
+
+/**
+ * Represents a line in Jailbreak Logs
+ *
+ * Compares by time
+ */
+public abstract class Action implements Comparable {
+ protected ActionType type;
+ protected String player, target;
+ protected Role playerRole, targetRole;
+ protected String[] other;
+ protected String line;
+
+ protected int playerRoleStart = Integer.MAX_VALUE, playerRoleEnd, targetRoleStart = -1, targetRoleEnd = -1;
+ protected int playerStart, playerEnd;
+ protected int targetStart, targetEnd;
+
+ protected long time;
+
+ public Action(String line) {
+ this.line = line;
+ }
+
+ public String getPlayer() {
+ return player;
+ }
+
+ public String getTarget() {
+ return target;
+ }
+
+ public Role getPlayerRole() {
+ return playerRole;
+ }
+
+ public Role getTargetRole() {
+ return targetRole;
+ }
+
+ public ActionType getType() {
+ return type;
+ }
+
+ public String[] getOther() {
+ return other;
+ }
+
+ public String getLine() {
+ return line;
+ }
+
+ public String simplify() {
+ String[] opts;
+ if (target == null || target.isEmpty()) {
+ opts = other;
+ } else {
+ List s = new ArrayList<>();
+ s.add(target);
+ s.addAll(List.of(other));
+ opts = s.toArray(new String[0]);
+ }
+ if (playerRole == JailRole.WORLD)
+ return player + " " + type.getSummary(opts);
+
+ return player + " (" + getPlayerRole().getIcon() + ") " + type.getSummary(opts);
+ }
+
+ public long getTime() {
+ return time;
+ }
+
+ public String getTimeString() {
+ return String.format("%02d:%02d", (int) Math.floor((float) time / 60), time % 60);
+ }
+
+ @Override
+ public int compareTo(Action o) {
+ return (int) (this.getTime() - o.getTime());
+ }
+}
diff --git a/src/main/java/xyz/msws/admintools/data/Config.java b/src/main/java/xyz/msws/admintools/data/Config.java
index 5fc69eb..a0c46bf 100644
--- a/src/main/java/xyz/msws/admintools/data/Config.java
+++ b/src/main/java/xyz/msws/admintools/data/Config.java
@@ -1,8 +1,13 @@
package xyz.msws.admintools.data;
-import xyz.msws.admintools.utils.Convert;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
-import java.util.EnumSet;
+import xyz.msws.admintools.data.DataStructs.ActionType;
+import xyz.msws.admintools.data.DataStructs.GenericActionType;
+import xyz.msws.admintools.data.jb.JailActionType;
+import xyz.msws.admintools.utils.Convert;
/**
* Represents the configurable values that the user can specify
@@ -14,10 +19,12 @@ public abstract class Config {
protected String header = "";
protected String outputPath = null, apiKey = null, clonePath = null;
protected String webId = "";
- protected EnumSet actions = EnumSet.of(JailActionType.KILL, JailActionType.WARDEN, JailActionType.WARDEN_DEATH, JailActionType.FIRE, JailActionType.PASS, JailActionType.RESKIN);
+ protected Set actions = new HashSet<>(Arrays.asList(GenericActionType.KILL, JailActionType.WARDEN,
+ JailActionType.WARDEN_DEATH, JailActionType.FIRE, JailActionType.PASS, JailActionType.RESKIN));
protected int gunTimeout = 10, buttonTimeout = 5, nadeTimeout = 10, wardenTimeout = 5, freeTime = 10;
- protected boolean showEarlyVents = true, showEarlyKills = true, showGameButtons = true, showNades = true, showGunPlants = true;
- protected boolean doJailbreak = true, doPlaytime = true;
+ protected boolean showEarlyVents = true, showEarlyKills = true, showGameButtons = true, showNades = true,
+ showGunPlants = true;
+ protected boolean doJailbreak = true, doPlaytime = true, doTTT = true;
protected boolean cacheGametimes = true, requestGametimes = true;
protected int appId = 730;
protected Convert.TimeUnit limitPlaytime = Convert.TimeUnit.YEARS;
@@ -38,6 +45,10 @@ public boolean doJailbreak() {
return doJailbreak;
}
+ public boolean doTTT() {
+ return doJailbreak;
+ }
+
public boolean doPlaytime() {
return doPlaytime;
}
@@ -54,7 +65,7 @@ public int getAppId() {
return appId;
}
- public EnumSet getActions() {
+ public Set getActions() {
return actions;
}
diff --git a/src/main/java/xyz/msws/admintools/data/DataStructs.java b/src/main/java/xyz/msws/admintools/data/DataStructs.java
new file mode 100644
index 0000000..9e674c8
--- /dev/null
+++ b/src/main/java/xyz/msws/admintools/data/DataStructs.java
@@ -0,0 +1,35 @@
+package xyz.msws.admintools.data;
+
+public class DataStructs {
+ public static interface ActionType {
+ String getSummary(String... opts);
+ }
+
+ public static enum GenericActionType implements ActionType {
+ DAMAGE("damaged %s (%s) for %s"), KILL("killed %s (%s)"), NADE("threw a(n) %s"), GHOST_RESPAWN("respawned as ghost");
+
+ String sum;
+
+ GenericActionType(String summary) {
+ this.sum = summary;
+ }
+
+ @Override
+ public String getSummary(String... opts) {
+ return String.format(sum, (Object[]) opts);
+ }
+
+ }
+
+ public static interface Role {
+ String getIcon();
+
+ boolean isCT();
+
+ boolean isT();
+
+ default boolean isAlive() {
+ return isCT() || isT();
+ }
+ }
+}
diff --git a/src/main/java/xyz/msws/admintools/data/FileConfig.java b/src/main/java/xyz/msws/admintools/data/FileConfig.java
index 104bac9..edc00a9 100644
--- a/src/main/java/xyz/msws/admintools/data/FileConfig.java
+++ b/src/main/java/xyz/msws/admintools/data/FileConfig.java
@@ -1,5 +1,9 @@
package xyz.msws.admintools.data;
+import xyz.msws.admintools.data.DataStructs.ActionType;
+import xyz.msws.admintools.data.DataStructs.GenericActionType;
+import xyz.msws.admintools.data.jb.JailActionType;
+import xyz.msws.admintools.data.ttt.TTTActionType;
import xyz.msws.admintools.utils.Convert;
import xyz.msws.admintools.utils.Utils;
@@ -52,8 +56,26 @@ public FileConfig(File file) {
} else if (line.startsWith("showTypes=")) {
String[] acts = getValue(line, "showTypes=").split(",");
actions.clear();
- for (String s : acts)
- actions.add(JailActionType.valueOf(s.toUpperCase()));
+ for (String s : acts) {
+ ActionType type = null;
+ try {
+ type = GenericActionType.valueOf(s.toUpperCase());
+ } catch (IllegalArgumentException e1) {
+ try {
+ type = JailActionType.valueOf(s.toUpperCase());
+ } catch (IllegalArgumentException e2) {
+ try {
+ type = TTTActionType.valueOf(s.toUpperCase());
+ } catch (IllegalArgumentException e3) {
+ }
+ }
+ }
+ if (type == null) {
+ System.out.println("Invalid action type: " + s);
+ continue;
+ }
+ actions.add(type);
+ }
} else if (line.startsWith("gundropTimeout=")) {
gunTimeout = getValue(line, "gundropTimeout=", Integer.class);
} else if (line.startsWith("nadeTimeout=")) {
@@ -76,6 +98,8 @@ public FileConfig(File file) {
freeTime = getValue(line, "freeTime=", Integer.class);
} else if (line.startsWith("doJailbreak=")) {
doJailbreak = getValue(line, "doJailbreak=", Boolean.class);
+ } else if (line.startsWith("doTTT=")) {
+ doTTT = getValue(line, "doTTT=", Boolean.class);
} else if (line.startsWith("cacheGametimes=")) {
cacheGametimes = getValue(line, "cacheGametimes=", Boolean.class);
} else if (line.startsWith("requestGametimes=")) {
diff --git a/src/main/java/xyz/msws/admintools/data/JailActionType.java b/src/main/java/xyz/msws/admintools/data/JailActionType.java
deleted file mode 100644
index e874a4c..0000000
--- a/src/main/java/xyz/msws/admintools/data/JailActionType.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package xyz.msws.admintools.data;
-
-/**
- * Represents an action that a player can make on Jailbreak
- */
-public enum JailActionType {
- DAMAGE("damaged %s for %s"), KILL("killed %s (%s)"), BUTTON("pressed %s (%s)"), WARDEN("took warden"), VENTS("broke vents"),
- DROP_WEAPON("dropped a(n) %s"), NADE("threw a(n) %s"), WARDEN_DEATH("died as warden"), PASS("passed warden"), FIRE("was fired"),
- RESKIN("reskinned %2$s's %1$s"), GHOST_RESPAWN("respawned as ghost");
-
- private final String sum;
-
- JailActionType(String summary) {
- this.sum = summary;
- }
-
- public String getSummary(String... objects) {
- return String.format(sum, (Object[]) objects);
- }
-}
diff --git a/src/main/java/xyz/msws/admintools/data/JailAction.java b/src/main/java/xyz/msws/admintools/data/jb/JailAction.java
similarity index 64%
rename from src/main/java/xyz/msws/admintools/data/JailAction.java
rename to src/main/java/xyz/msws/admintools/data/jb/JailAction.java
index 61f01f2..f64a780 100644
--- a/src/main/java/xyz/msws/admintools/data/JailAction.java
+++ b/src/main/java/xyz/msws/admintools/data/jb/JailAction.java
@@ -1,28 +1,23 @@
-package xyz.msws.admintools.data;
+package xyz.msws.admintools.data.jb;
import java.util.ArrayList;
import java.util.List;
+import xyz.msws.admintools.data.Action;
+import xyz.msws.admintools.data.Button;
+import xyz.msws.admintools.data.ButtonDatabase;
+import xyz.msws.admintools.data.DataStructs.ActionType;
+import xyz.msws.admintools.data.DataStructs.GenericActionType;
+import xyz.msws.admintools.data.DataStructs.Role;
+
/**
* Represents a line in Jailbreak Logs
*
* Compares by time
*/
-public class JailAction implements Comparable {
- private JailActionType type;
- private String player, target;
- private JailRole playerRole, targetRole;
- private String[] other;
- private String line;
-
- private int playerRoleStart = Integer.MAX_VALUE, playerRoleEnd, targetRoleStart = -1, targetRoleEnd = -1;
- private int playerStart, playerEnd;
- private int targetStart, targetEnd;
-
- private long time;
-
+public class JailAction extends Action {
public JailAction(String line) {
- this.line = line;
+ super(line);
this.type = findActionType();
calculateIndices();
@@ -42,15 +37,15 @@ public String getTarget() {
return target;
}
- public JailRole getPlayerRole() {
+ public Role getPlayerRole() {
return playerRole;
}
- public JailRole getTargetRole() {
+ public Role getTargetRole() {
return targetRole;
}
- public JailActionType getType() {
+ public ActionType getType() {
return type;
}
@@ -58,21 +53,22 @@ public String[] getOther() {
return other;
}
- private JailActionType findActionType() {
+ private ActionType findActionType() {
if (line.endsWith("is now warden")) {
return JailActionType.WARDEN;
} else if (line.endsWith("broke a vent or wall")) {
return JailActionType.VENTS;
} else if (line.contains(") pressed button '")) {
return JailActionType.BUTTON;
- } else if (line.contains("threw a") && (line.endsWith("smoke") || line.endsWith("grenade") || line.endsWith("flash") || line.endsWith("decoy") || line.endsWith("molotov"))) {
- return JailActionType.NADE;
+ } else if (line.contains("threw a") && (line.endsWith("smoke") || line.endsWith("grenade")
+ || line.endsWith("flash") || line.endsWith("decoy") || line.endsWith("molotov"))) {
+ return GenericActionType.NADE;
} else if (line.contains("hurt") && line.contains("with") && line.contains("damage (")) {
- return JailActionType.DAMAGE;
+ return GenericActionType.DAMAGE;
} else if (line.contains("has died and is no longer warden")) {
return JailActionType.WARDEN_DEATH;
} else if (line.contains("killed ")) {
- return JailActionType.KILL;
+ return GenericActionType.KILL;
} else if (line.contains("dropped the weapon")) {
return JailActionType.DROP_WEAPON;
} else if (line.endsWith("has been fired by an admin")) {
@@ -82,7 +78,7 @@ private JailActionType findActionType() {
} else if (line.contains("reskinned weapon_")) {
return JailActionType.RESKIN;
} else if (line.contains("was respawned for touching")) {
- return JailActionType.GHOST_RESPAWN;
+ return GenericActionType.GHOST_RESPAWN;
} else if (line.endsWith("has disconnected, passing warden")) {
return JailActionType.PASS;
} else if (line.contains("broke '")) {
@@ -100,7 +96,8 @@ private void calculateIndices() {
} else if (role == JailRole.WORLD) {
index = line.toUpperCase().indexOf((role.toString()));
} else {
- index = line.indexOf("(" + role.toString().charAt(0) + role.toString().substring(1).toLowerCase() + ")") + 1;
+ index = line.indexOf("(" + role.toString().charAt(0) + role.toString().substring(1).toLowerCase() + ")")
+ + 1;
}
if (index <= 0 || index > playerRoleStart)
@@ -124,12 +121,13 @@ private void calculateIndices() {
playerStart = 8;
playerEnd = playerRoleStart - (world ? -5 : 2);
- if (type != JailActionType.DAMAGE && type != JailActionType.KILL)
+ if (type != GenericActionType.DAMAGE && type != GenericActionType.KILL)
return;
for (JailRole role : JailRole.values()) {
-// int index = line.toUpperCase().lastIndexOf("(" + role.toString() + ")") + 1;
- int index = role == JailRole.WARDEN ? line.toUpperCase().lastIndexOf(role.toString()) : (line.toUpperCase().lastIndexOf("(" + role + ")") + 1);
+ // int index = line.toUpperCase().lastIndexOf("(" + role.toString() + ")") + 1;
+ int index = role == JailRole.WARDEN ? line.toUpperCase().lastIndexOf(role.toString())
+ : (line.toUpperCase().lastIndexOf("(" + role + ")") + 1);
if (index <= 0 || index == playerRoleStart)
continue;
@@ -139,7 +137,8 @@ private void calculateIndices() {
break;
}
- String damageLine = line.substring(playerRoleEnd + (world ? 1 : 2), line.indexOf(" ", playerRoleEnd + (world ? 1 : 2)));
+ String damageLine = line.substring(playerRoleEnd + (world ? 1 : 2),
+ line.indexOf(" ", playerRoleEnd + (world ? 1 : 2)));
targetStart = playerRoleEnd + (world ? 2 : 3) + damageLine.length();
targetEnd = targetRoleStart - 2;
@@ -156,27 +155,44 @@ private String findTarget() {
}
private String[] findOther() {
- switch (type) {
- case KILL:
- return new String[]{targetRole.getIcon()};
- case DAMAGE:
- return new String[]{line.substring(line.lastIndexOf("with ") + "with ".length(), line.lastIndexOf("damage") - 1), line.substring(line.lastIndexOf("(") + 1, line.length() - 1)};
+ if (type instanceof GenericActionType gType) {
+ switch (gType) {
+ case KILL:
+ return new String[] { targetRole.getIcon() };
+ case DAMAGE:
+ return new String[] {
+ targetRole.getIcon(),
+ line.substring(line.lastIndexOf("with ") + "with ".length(),
+ line.lastIndexOf("damage") - 1),
+ line.substring(line.lastIndexOf("(") + 1, line.length() - 1) };
+ case NADE:
+ return new String[] { line.substring(line.lastIndexOf(" ") + 1) };
+ default:
+ return new String[] {};
+ }
+ }
+ if (!(type instanceof JailActionType jbType))
+ return new String[] { "Invalid Type" };
+ switch (jbType) {
case BUTTON:
- String name = line.substring(line.substring(0, line.length() - 1).lastIndexOf(line.contains("pressed button 'Unknown'") ? "(" : "'", line.length() - 2) + 1, line.length() - 1);
+ String name = line.substring(
+ line.substring(0, line.length() - 1).lastIndexOf(
+ line.contains("pressed button 'Unknown'") ? "(" : "'", line.length() - 2) + 1,
+ line.length() - 1);
Button b = ButtonDatabase.getInstance().getButton(name);
- return new String[]{b.getName(), b.getAlias()};
+ return new String[] { b.getName(), b.getAlias() };
case DROP_WEAPON:
- return new String[]{line.substring(line.lastIndexOf(" ") + 1, line.length() - 1)};
- case NADE:
- return new String[]{line.substring(line.lastIndexOf(" ") + 1)};
+ return new String[] { line.substring(line.lastIndexOf(" ") + 1, line.length() - 1) };
case RESKIN:
- String weapon = line.substring(line.indexOf("reskinned weapon_") + "reskinned weapon_".length(), line.indexOf(" ", line.lastIndexOf("weapon_")));
+ String weapon = line.substring(line.indexOf("reskinned weapon_") + "reskinned weapon_".length(),
+ line.indexOf(" ", line.lastIndexOf("weapon_")));
if (line.endsWith("(not previously owned)")) {
- return new String[]{weapon, "their own"};
+ return new String[] { weapon, "their own" };
}
- return new String[]{weapon, line.substring(line.indexOf("previous owner: ") + "previous owner: ".length(), line.length() - 1)};
+ return new String[] { weapon, line
+ .substring(line.indexOf("previous owner: ") + "previous owner: ".length(), line.length() - 1) };
default:
- return new String[]{};
+ return new String[] {};
}
}
@@ -213,9 +229,4 @@ public long getTime() {
public String getTimeString() {
return String.format("%02d:%02d", (int) Math.floor((float) time / 60), time % 60);
}
-
- @Override
- public int compareTo(JailAction o) {
- return (int) (this.getTime() - o.getTime());
- }
}
diff --git a/src/main/java/xyz/msws/admintools/data/jb/JailActionType.java b/src/main/java/xyz/msws/admintools/data/jb/JailActionType.java
new file mode 100644
index 0000000..2ad3568
--- /dev/null
+++ b/src/main/java/xyz/msws/admintools/data/jb/JailActionType.java
@@ -0,0 +1,24 @@
+package xyz.msws.admintools.data.jb;
+
+import xyz.msws.admintools.data.DataStructs.ActionType;
+
+/**
+ * Represents an action that a player can make on Jailbreak
+ */
+public enum JailActionType implements ActionType {
+ BUTTON("pressed %s (%s)"), WARDEN("took warden"),
+ VENTS("broke vents"),
+ DROP_WEAPON("dropped a(n) %s"), WARDEN_DEATH("died as warden"), PASS("passed warden"),
+ FIRE("was fired"),
+ RESKIN("reskinned %2$s's %1$s");
+
+ private final String sum;
+
+ JailActionType(String summary) {
+ this.sum = summary;
+ }
+
+ public String getSummary(String... objects) {
+ return String.format(sum, (Object[]) objects);
+ }
+}
diff --git a/src/main/java/xyz/msws/admintools/data/JailRole.java b/src/main/java/xyz/msws/admintools/data/jb/JailRole.java
similarity index 72%
rename from src/main/java/xyz/msws/admintools/data/JailRole.java
rename to src/main/java/xyz/msws/admintools/data/jb/JailRole.java
index 5b6a5c7..c6716b5 100644
--- a/src/main/java/xyz/msws/admintools/data/JailRole.java
+++ b/src/main/java/xyz/msws/admintools/data/jb/JailRole.java
@@ -1,10 +1,13 @@
-package xyz.msws.admintools.data;
+package xyz.msws.admintools.data.jb;
+
+import xyz.msws.admintools.data.DataStructs.Role;
/**
* Enum to identify a player's role on Jailbreak
*/
-public enum JailRole {
- WARDEN("W"), GUARD("G"), PRISONER("P"), REBEL("R"), SPECTATOR("S"), WORLD("World"), GHOST("Ghost"), UNKNOWN("Unknown");
+public enum JailRole implements Role {
+ WARDEN("W"), GUARD("G"), PRISONER("P"), REBEL("R"), SPECTATOR("S"), WORLD("World"), GHOST("Ghost"),
+ UNKNOWN("Unknown");
private final String icon;
diff --git a/src/main/java/xyz/msws/admintools/data/ttt/TTTAction.java b/src/main/java/xyz/msws/admintools/data/ttt/TTTAction.java
new file mode 100644
index 0000000..810eadb
--- /dev/null
+++ b/src/main/java/xyz/msws/admintools/data/ttt/TTTAction.java
@@ -0,0 +1,162 @@
+package xyz.msws.admintools.data.ttt;
+
+import xyz.msws.admintools.data.Action;
+import xyz.msws.admintools.data.DataStructs.ActionType;
+import xyz.msws.admintools.data.DataStructs.GenericActionType;
+
+public class TTTAction extends Action {
+ public TTTAction(String line) {
+ super(line);
+
+ this.type = findActionType();
+ calculateIndices();
+
+ this.player = findPlayer();
+ this.target = findTarget();
+ this.other = findOther();
+ }
+
+ private ActionType findActionType() {
+ if (line.contains("threw a") && (line.endsWith("smoke") || line.endsWith("grenade")
+ || line.endsWith("flash") || line.endsWith("decoy") || line.endsWith("molotov"))) {
+ return GenericActionType.NADE;
+ } else if (line.contains("killed ")) {
+ return this.isBadAction() ? TTTActionType.BAD_KILL : GenericActionType.KILL;
+ } else if (line.contains("damaged") && line.contains("for") && line.contains("with")) {
+ return this.isBadAction() ? TTTActionType.BAD_DAMAGE : GenericActionType.DAMAGE;
+ } else if (line.contains("identified body of")) {
+ return TTTActionType.IDENTIFY;
+ } else if (line.contains("purchased an item from the shop:")) {
+ return TTTActionType.SHOP;
+ } else if (line.contains("used traitor secret:")) {
+ return TTTActionType.T_SECRET;
+ } else if (line.contains("scanned a body, Killer was")) {
+ return TTTActionType.DNA;
+ } else if (line.contains("was tased by")) {
+ return TTTActionType.TAZE;
+ }
+
+ throw new IllegalArgumentException("Invalid line: " + line);
+ }
+
+ private void calculateIndices() {
+ for (TTTRole role : TTTRole.values()) {
+ int index = line.toUpperCase().indexOf("(" + role.toString() + ")");
+ if (index != -1) {
+ index++;
+ } else if (role == TTTRole.WORLD) {
+ index = line.toUpperCase().indexOf((role.toString()));
+ } else {
+ index = line.indexOf("(" + role.toString().charAt(0) + role.toString().substring(1).toLowerCase() + ")")
+ + 1;
+ }
+
+ if (index <= 0 || index > playerRoleStart)
+ continue;
+ if (role == TTTRole.WORLD) {
+ playerRoleStart = index;
+ playerRoleEnd = playerRoleStart + "The World".length();
+ playerRole = TTTRole.WORLD;
+ } else {
+ playerRoleStart = index;
+ playerRoleEnd = playerRoleStart + role.toString().length();
+ playerRole = TTTRole.valueOf(line.substring(playerRoleStart, playerRoleEnd).toUpperCase());
+ }
+ }
+
+ if (playerRole == null) {
+ System.out.println("Unknown line: " + line);
+ return;
+ }
+ boolean world = playerRole == TTTRole.WORLD;
+
+ playerStart = 12;
+ playerEnd = playerRoleStart - (world ? -5 : 2);
+
+ if (type != GenericActionType.DAMAGE && type != GenericActionType.KILL && type != TTTActionType.BAD_DAMAGE
+ && type != TTTActionType.BAD_KILL)
+ return;
+
+ for (TTTRole role : TTTRole.values()) {
+ int index = line.toUpperCase().lastIndexOf("(" + role + ")") + 1;
+
+ if (index <= 0 || index == playerRoleStart)
+ continue;
+ targetRoleStart = index;
+ targetRoleEnd = targetRoleStart + role.toString().length();
+ targetRole = TTTRole.valueOf(line.substring(targetRoleStart, targetRoleEnd).toUpperCase());
+ break;
+ }
+
+ String damageLine = line.substring(playerRoleEnd + (world ? 1 : 2),
+ line.indexOf(" ", playerRoleEnd + (world ? 1 : 2)));
+
+ targetStart = playerRoleEnd + (world ? 2 : 3) + damageLine.length();
+ targetEnd = targetRoleStart - 2;
+ }
+
+ private String findPlayer() {
+ return line.substring(playerStart, playerEnd);
+ }
+
+ private String findTarget() {
+ if (targetStart == -1 || targetEnd == -1)
+ return null;
+ return line.substring(targetStart, targetEnd);
+ }
+
+ private String[] findOther() {
+ if (type instanceof GenericActionType gType) {
+ switch (gType) {
+ case KILL:
+ return new String[] { targetRole.getIcon() };
+ case DAMAGE:
+ return new String[] {
+ targetRole.getIcon(),
+ line.substring(line.lastIndexOf(") for ") + ") for ".length(),
+ line.lastIndexOf(" damage ") - 1),
+ line.substring(line.lastIndexOf(" ") + 1, line.length() - 1) };
+ case NADE:
+ return new String[] { line.substring(line.lastIndexOf(" ") + 1) };
+ default:
+ return new String[] {};
+ }
+ }
+ if (!(type instanceof TTTActionType tttType))
+ return new String[] { "Invalid Type" };
+ switch (tttType) {
+ case BAD_KILL:
+ return new String[] { targetRole.getIcon() };
+ case BAD_DAMAGE:
+ return new String[] {
+ targetRole.getIcon(),
+ line.substring(line.lastIndexOf(") for ") + ") for ".length(),
+ line.lastIndexOf(" damage ") - 1),
+ line.substring(line.lastIndexOf(" ") + 1, line.length() - 1) };
+ case IDENTIFY:
+ return new String[] {
+ line.substring(line.lastIndexOf("identified body of ") + "identified body of ".length(),
+ line.lastIndexOf("(") - 1) };
+ case DNA:
+ return new String[] { line.substring(
+ line.indexOf("scanned a body, Killer was ") + "scanned a body, Killer was ".length(),
+ line.lastIndexOf("(") - 1) };
+ case SHOP:
+ return new String[] {
+ line.substring(line.lastIndexOf("shop: ") + "shop: ".length(), line.length() - 1) };
+ case T_SECRET:
+ return new String[] {
+ line.substring(line.lastIndexOf("traitor secret: ") + "traitor secret: ".length(),
+ line.length() - 1) };
+ case TAZE:
+ return new String[] { line.substring(line.lastIndexOf("was tased by ") + "was tased by ".length(),
+ line.length() - 1) };
+ default:
+ return new String[] {};
+ }
+ }
+
+ public boolean isBadAction() {
+ return line.endsWith("BAD ACTION");
+ }
+}
diff --git a/src/main/java/xyz/msws/admintools/data/ttt/TTTActionType.java b/src/main/java/xyz/msws/admintools/data/ttt/TTTActionType.java
new file mode 100644
index 0000000..ac4cfb9
--- /dev/null
+++ b/src/main/java/xyz/msws/admintools/data/ttt/TTTActionType.java
@@ -0,0 +1,21 @@
+package xyz.msws.admintools.data.ttt;
+
+import xyz.msws.admintools.data.DataStructs.ActionType;
+
+public enum TTTActionType implements ActionType {
+ IDENTIFY("found %s's body"), DNA("DNA'd %s's body"),
+ SHOP("bought %s"), T_SECRET("activated %s"), TAZE("tazed %s"), BAD_KILL("killed %s (%s)"),
+ BAD_DAMAGE("damaged %s (%s)");
+
+ private final String sum;
+
+ TTTActionType(String summary) {
+ this.sum = summary;
+ }
+
+ @Override
+ public String getSummary(String... opts) {
+ return String.format(sum, (Object[]) opts);
+ }
+
+}
diff --git a/src/main/java/xyz/msws/admintools/data/ttt/TTTRole.java b/src/main/java/xyz/msws/admintools/data/ttt/TTTRole.java
new file mode 100644
index 0000000..8c3d4cf
--- /dev/null
+++ b/src/main/java/xyz/msws/admintools/data/ttt/TTTRole.java
@@ -0,0 +1,30 @@
+package xyz.msws.admintools.data.ttt;
+
+import xyz.msws.admintools.data.DataStructs.Role;
+
+public enum TTTRole implements Role {
+ INNOCENT("I"), TRAITOR("T"), DETECTIVE("D"), SPECTATOR("S"), WORLD("World"), GHOST("Ghost"),
+ UNKNOWN("Unknown");
+
+ private final String icon;
+
+ TTTRole(String icon) {
+ this.icon = icon;
+ }
+
+ public String getIcon() {
+ return icon;
+ }
+
+ public boolean isCT() {
+ return this == DETECTIVE;
+ }
+
+ public boolean isT() {
+ return this == TRAITOR || this == INNOCENT;
+ }
+
+ public boolean isAlive() {
+ return isCT() || isT();
+ }
+}
diff --git a/src/main/java/xyz/msws/admintools/parsers/JBParser.java b/src/main/java/xyz/msws/admintools/parsers/JBParser.java
index ee510f8..cd6be5d 100644
--- a/src/main/java/xyz/msws/admintools/parsers/JBParser.java
+++ b/src/main/java/xyz/msws/admintools/parsers/JBParser.java
@@ -2,6 +2,10 @@
import xyz.msws.admintools.Monitor;
import xyz.msws.admintools.data.*;
+import xyz.msws.admintools.data.DataStructs.GenericActionType;
+import xyz.msws.admintools.data.jb.JailAction;
+import xyz.msws.admintools.data.jb.JailActionType;
+import xyz.msws.admintools.data.jb.JailRole;
import xyz.msws.admintools.utils.MSG;
import java.io.File;
@@ -17,7 +21,10 @@ public class JBParser extends Parser {
private final ButtonDatabase buttondb;
private final List jbActions = new ArrayList<>();
- private final Pattern pattern = Pattern.compile("^\\[\\d\\d:\\d\\d]\s"); // Matches the timecode prefix of jailbreak logs
+ private final Pattern pattern = Pattern.compile("^\\[\\d\\d:\\d\\d]\s"); // Matches the timecode prefix of jailbreak
+ // logs
+
+ private boolean parse = false;
public JBParser(Monitor monitor) {
super(monitor);
@@ -26,7 +33,8 @@ public JBParser(Monitor monitor) {
this.buttondb = new ButtonDatabase(buttons);
}
- private final EnumSet wardenRelated = EnumSet.of(JailActionType.WARDEN, JailActionType.WARDEN_DEATH, JailActionType.PASS, JailActionType.FIRE);
+ private final EnumSet wardenRelated = EnumSet.of(JailActionType.WARDEN, JailActionType.WARDEN_DEATH,
+ JailActionType.PASS, JailActionType.FIRE);
Set lines = new HashSet<>();
@@ -35,6 +43,7 @@ public void parse(String line) {
if (line.equals("----------------[ JAILBREAK LOGS ]----------------")) {
jbActions.clear();
lines.clear();
+ parse = true;
return;
}
if (line.equals("--------------[ JAILBREAK LOGS END ]--------------")) {
@@ -60,8 +69,11 @@ public void parse(String line) {
checkSpectator();
jbActions.clear();
lines.clear();
+ parse = false;
return;
}
+ if (!parse)
+ return;
if (!line.startsWith("["))
return;
@@ -86,17 +98,24 @@ public void parse(String line) {
* Compares warden death / fire / freeday times with CT kills
*/
private void checkFreekills() {
- List allWarden = jbActions.stream().filter(act -> wardenRelated.contains(act.getType())).sorted().collect(Collectors.toList());
+ List allWarden = jbActions.stream().filter(act -> wardenRelated.contains(act.getType())).sorted()
+ .collect(Collectors.toList());
TreeMap cease = new TreeMap<>();
for (JailAction act : allWarden) {
- switch (act.getType()) {
+ if (!(act.getType() instanceof JailActionType jbType))
+ continue;
+ switch (jbType) {
case WARDEN -> cease.put(act.getTime() + config.getWardenTimeout(), false);
case WARDEN_DEATH -> cease.put(act.getTime(), true);
case FIRE, PASS -> {
- if (cease.entrySet().stream().anyMatch(e -> !e.getValue() && e.getKey() + config.getFreeTime() < act.getTime()))
+ if (cease.entrySet().stream()
+ .anyMatch(e -> !e.getValue() && e.getKey() + config.getFreeTime() < act.getTime()))
break;
cease.put(act.getTime(), true);
}
+ default -> {
+ continue;
+ }
}
}
Set cts = new HashSet<>();
@@ -111,11 +130,14 @@ private void checkFreekills() {
if (act.getTargetRole() != null && act.getTargetRole().isCT())
cts.add(act.getTarget());
}
- List deaths = jbActions.stream().filter(act -> act.getType() == JailActionType.KILL).collect(Collectors.toList());
+ List deaths = jbActions.stream().filter(act -> act.getType() == GenericActionType.KILL)
+ .collect(Collectors.toList());
if (!deaths.isEmpty()) {
boolean ctWin = deaths.get(deaths.size() - 1).getPlayerRole().isCT();
- List ctDeaths = deaths.stream().filter(act -> act.getTargetRole().isCT()).sorted().collect(Collectors.toList());
- List tDeaths = deaths.stream().filter(act -> act.getTargetRole().isT()).sorted().collect(Collectors.toList());
+ List ctDeaths = deaths.stream().filter(act -> act.getTargetRole().isCT()).sorted()
+ .collect(Collectors.toList());
+ List tDeaths = deaths.stream().filter(act -> act.getTargetRole().isT()).sorted()
+ .collect(Collectors.toList());
JailAction lastGuard, lastRequest = null;
if (tDeaths.size() > 2 && ts.size() - tDeaths.size() <= 2) {
lastRequest = tDeaths.get(tDeaths.size() - 2);
@@ -123,27 +145,31 @@ private void checkFreekills() {
}
if (ctDeaths.size() > 2 && cts.size() - ctDeaths.size() <= 1) {
// There was one CT at the end of the round
- // If CT won, get most recent death (the last CT didn't die), otherwise get second most recent death
+ // If CT won, get most recent death (the last CT didn't die), otherwise get
+ // second most recent death
lastGuard = ctDeaths.get(ctDeaths.size() - (ctWin ? 1 : 2));
if (lastRequest == null || lastRequest.getTime() > lastGuard.getTime()) {
cease.put(lastGuard.getTime(), false);
- System.out.println(lastGuard.getTarget() + " died, activating last guard at " + lastGuard.getTimeString());
+ System.out.println(
+ lastGuard.getTarget() + " died, activating last guard at " + lastGuard.getTimeString());
}
}
// Last request always after last guard
if (lastRequest != null)
- System.out.println(lastRequest.getTarget() + " died, activating last request at " + lastRequest.getTimeString());
+ System.out.println(
+ lastRequest.getTarget() + " died, activating last request at " + lastRequest.getTimeString());
}
-
- List badCombat = jbActions.stream().filter(act -> act.getType() == JailActionType.DAMAGE || act.getType() == JailActionType.KILL)
+ List badCombat = jbActions.stream()
+ .filter(act -> act.getType() == GenericActionType.DAMAGE || act.getType() == GenericActionType.KILL)
.filter(act -> act.getPlayerRole().isCT()).filter(act -> act.getTargetRole() == JailRole.PRISONER)
.filter(act -> ceaseFire(cease, act.getTime())).collect(Collectors.toList());
if (!badCombat.isEmpty())
print("\nGuard Freekills");
for (JailAction act : badCombat)
- print(act.simplify() + " without warden or " + config.getWardenTimeout() + " " + MSG.plural("second", config.getWardenTimeout()) + " given.");
+ print(act.simplify() + " without warden or " + config.getWardenTimeout() + " "
+ + MSG.plural("second", config.getWardenTimeout()) + " given.");
}
/**
@@ -166,11 +192,14 @@ private void checkGuardVents() {
}
/**
- * Checks if a player pushed a button and another player was damaged by the world soon after
+ * Checks if a player pushed a button and another player was damaged by the
+ * world soon after
*/
private void checkWorldButtons() {
- List presses = jbActions.stream().filter(act -> act.getType() == JailActionType.BUTTON).collect(Collectors.toList());
- List damages = jbActions.stream().filter(act -> act.getPlayerRole() == JailRole.WORLD).collect(Collectors.toList());
+ List presses = jbActions.stream().filter(act -> act.getType() == JailActionType.BUTTON)
+ .collect(Collectors.toList());
+ List damages = jbActions.stream().filter(act -> act.getPlayerRole() == JailRole.WORLD)
+ .collect(Collectors.toList());
List lines = new ArrayList<>();
for (JailAction press : presses) {
@@ -178,7 +207,9 @@ private void checkWorldButtons() {
if (button.isSafe())
return;
StringBuilder result = new StringBuilder();
- List damaged = damages.stream().filter(d -> d.getTime() >= press.getTime() && d.getTime() < press.getTime() + config.getButtonTimeout()).collect(Collectors.toList());
+ List damaged = damages.stream().filter(
+ d -> d.getTime() >= press.getTime() && d.getTime() < press.getTime() + config.getButtonTimeout())
+ .collect(Collectors.toList());
if (damaged.isEmpty())
continue;
result.append(press.simplify());
@@ -212,12 +243,15 @@ private void checkWorldButtons() {
}
/**
- * Checks if a player threw a nade and another player was damaged by the world soon after
+ * Checks if a player threw a nade and another player was damaged by the world
+ * soon after
*/
private void checkNades() {
- List nades = jbActions.stream().filter(act -> act.getType() == JailActionType.NADE).collect(Collectors.toList());
+ List nades = jbActions.stream().filter(act -> act.getType() == GenericActionType.NADE)
+ .collect(Collectors.toList());
- for (JailAction act : jbActions.stream().filter(act -> act.getPlayerRole() == JailRole.WORLD).collect(Collectors.toList())) {
+ for (JailAction act : jbActions.stream().filter(act -> act.getPlayerRole() == JailRole.WORLD)
+ .collect(Collectors.toList())) {
List press = nades.stream()
.filter(p -> p.getTime() <= act.getTime() && p.getTime() > act.getTime() - config.getNadeTimeout())
.filter(p -> !act.getTarget().equals(p.getPlayer()))
@@ -225,7 +259,8 @@ private void checkNades() {
.collect(Collectors.toList());
for (JailAction p : press) {
print("\nNade Disruptions");
- print(p.simplify() + " which could've disrupted " + act.getTarget() + " (" + act.getTargetRole().getIcon() + ")");
+ print(p.simplify() + " which could've disrupted " + act.getTarget() + " ("
+ + act.getTargetRole().getIcon() + ")");
}
}
}
@@ -234,23 +269,32 @@ private void checkNades() {
* Checks if a CT drops a gun and a T uses the same type of gun soon after
*/
private void checkGuns() {
-
- List guns = jbActions.stream().filter(act -> act.getType() == JailActionType.DROP_WEAPON && act.getPlayerRole().isCT()).collect(Collectors.toList());
+ List guns = jbActions.stream()
+ .filter(act -> act.getType() == JailActionType.DROP_WEAPON && act.getPlayerRole().isCT())
+ .collect(Collectors.toList());
Iterator it = guns.iterator();
while (it.hasNext()) {
JailAction drop = it.next();
- JailAction death = jbActions.stream().filter(a -> a.getType() == JailActionType.KILL && a.getTarget().equals(drop.getPlayer())).findFirst().orElse(null);
+ JailAction death = jbActions.stream()
+ .filter(a -> a.getType() == GenericActionType.KILL && a.getTarget().equals(drop.getPlayer()))
+ .findFirst().orElse(null);
if (death == null)
continue;
if (death.getTime() == drop.getTime() || death.getTime() + 1 == drop.getTime())
it.remove();
}
- for (JailAction act : jbActions.stream().filter(act -> act.getType() == JailActionType.DAMAGE && act.getPlayerRole().isT()).collect(Collectors.toList())) {
- List ds = guns.stream().filter(p -> p.getTime() <= act.getTime() && p.getTime() > act.getTime() - config.getGunTimeout() && p.getOther()[0].equals(act.getOther()[1])).collect(Collectors.toList());
+ for (JailAction act : jbActions.stream()
+ .filter(act -> act.getType() == GenericActionType.DAMAGE && act.getPlayerRole().isT())
+ .collect(Collectors.toList())) {
+ List ds = guns.stream()
+ .filter(p -> p.getTime() <= act.getTime() && p.getTime() > act.getTime() - config.getGunTimeout()
+ && p.getOther()[0].equals(act.getOther()[1]))
+ .collect(Collectors.toList());
for (JailAction p : ds) {
print("\nGun Plants");
- print(p.simplify() + " and " + act.getPlayer() + " (" + act.getPlayerRole().getIcon() + ") used one shortly after");
+ print(p.simplify() + " and " + act.getPlayer() + " (" + act.getPlayerRole().getIcon()
+ + ") used one shortly after");
}
}
}
@@ -259,7 +303,8 @@ private void checkGuns() {
* Checks if a spectator deals damage to anyone
*/
private void checkSpectator() {
- List damage = jbActions.stream().filter(act -> act.getType() == JailActionType.DAMAGE || act.getType() == JailActionType.KILL)
+ List damage = jbActions.stream()
+ .filter(act -> act.getType() == GenericActionType.DAMAGE || act.getType() == GenericActionType.KILL)
.filter(act -> act.getPlayerRole() == JailRole.SPECTATOR).collect(Collectors.toList());
for (JailAction act : damage) {
print("\nSpectator Exploiters");
diff --git a/src/main/java/xyz/msws/admintools/parsers/TTTParser.java b/src/main/java/xyz/msws/admintools/parsers/TTTParser.java
new file mode 100644
index 0000000..4e0a5c0
--- /dev/null
+++ b/src/main/java/xyz/msws/admintools/parsers/TTTParser.java
@@ -0,0 +1,125 @@
+package xyz.msws.admintools.parsers;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.regex.Pattern;
+
+import xyz.msws.admintools.Monitor;
+import xyz.msws.admintools.data.DataStructs.GenericActionType;
+import xyz.msws.admintools.data.ttt.TTTAction;
+import xyz.msws.admintools.data.ttt.TTTActionType;
+import xyz.msws.admintools.data.ttt.TTTRole;
+
+public class TTTParser extends Parser {
+
+ private final List tttActions = new ArrayList<>();
+ private final Pattern pattern = Pattern.compile("^\\[\\d\\d:\\d\\d]\s"); // Matches the timecode prefix of TTT
+ // logs
+ private boolean parse = false;
+
+ Set lines = new HashSet<>();
+
+ public TTTParser(Monitor monitor) {
+ super(monitor);
+ }
+
+ @Override
+ public void parse(String line) {
+ if (line.equals("---------------TTT LOGS---------------") && !parse) {
+ tttActions.clear();
+ lines.clear();
+ parse = true;
+ return;
+ }
+ if (line.equals("--------------------------------------") && parse) {
+ Arrays.stream(config.getHeader().split("\\\\n")).forEach(System.out::println);
+
+ System.out.println("TTT Logs");
+ for (TTTAction act : tttActions) {
+ if (!config.getActions().contains(act.getType()))
+ continue;
+ try {
+ System.out.println(act.simplify());
+ } catch (Exception e) {
+ System.out.println("Error occured while parsing " + act.getLine() + ":\n" + e.getMessage());
+ }
+ }
+
+ checkHidden();
+ checkRDM();
+
+ tttActions.clear();
+ lines.clear();
+ parse = false;
+ return;
+ }
+ if (!parse)
+ return;
+ if (!line.startsWith("[") || line.charAt(8) != '-' || line.charAt(9) != '>')
+ return;
+ if (line.endsWith("has been started!"))
+ return;
+ if (!pattern.matcher(line).lookingAt())
+ return;
+
+ try {
+ TTTAction tttAction = new TTTAction(line);
+ tttActions.add(tttAction);
+ } catch (Exception e) {
+ e.printStackTrace();
+ System.out.println("Unknown TTT line: " + line);
+ }
+ }
+
+ private void checkHidden() {
+ Set revealed = new HashSet<>();
+ Set toPrint = new HashSet<>();
+ for (TTTAction act : tttActions) {
+ if (act.getPlayerRole() == TTTRole.TRAITOR
+ && (act.getType() == GenericActionType.DAMAGE || act.getType() == TTTActionType.T_SECRET
+ || act.getType() == TTTActionType.TAZE)) {
+ revealed.add(act.getType() == TTTActionType.TAZE ? act.getOther()[0] : act.getPlayer());
+ continue;
+ }
+
+ if (act.getTargetRole() != TTTRole.TRAITOR
+ || (act.getType() != GenericActionType.DAMAGE && act.getType() != GenericActionType.KILL))
+ continue;
+
+ if (revealed.contains(act.getTarget()))
+ continue;
+
+ toPrint.add(act.simplify());
+ }
+ if (toPrint.isEmpty())
+ return;
+ print("\nEarly Traitor Kills (Ts did not commit any acts)");
+ toPrint.forEach(s -> print(s));
+ }
+
+ private void checkRDM() {
+ Set toPrint = new HashSet<>();
+ for (TTTAction act : tttActions) {
+ if (act.getPlayerRole() != act.getTargetRole() && !act.isBadAction())
+ continue;
+ if (act.getType() == TTTActionType.BAD_DAMAGE)
+ continue;
+ toPrint.add(act.simplify());
+ }
+ if (toPrint.isEmpty())
+ return;
+ print("\nBad Actions");
+ toPrint.forEach(s -> print(s));
+ }
+
+ private void print(String line) {
+ if (lines.contains(line))
+ return;
+ System.out.println(line);
+ lines.add(line);
+ }
+
+}
diff --git a/src/main/resources/settings.txt b/src/main/resources/settings.txt
index 95ee924..824aaa1 100644
--- a/src/main/resources/settings.txt
+++ b/src/main/resources/settings.txt
@@ -23,6 +23,9 @@ doPlaytime=true
If true, the application will check Jailbreak Logs
doJailbreak=true
+If true, the application will check TTT Logs
+doTTT=true
+
If you wish to limit the largest unit used to display playtime, you can specify it here
eg. if set to HOURS then "48 hours" would be displayed instead of "2 days"
playtimeUnit=YEARS
@@ -63,7 +66,7 @@ warnNameChages=true
Jailbreak Specific Settings
Log specific summarized actions
-Values: DAMAGE, KILL, BUTTON, WARDEN, VENTS, DROP_WEAPON, NADE, WARDEN_DEATH, PASS, FIRE, RESKIN, GHOST_RESPAWN
+Values: DAMAGE, KILL, BUTTON, WARDEN, VENTS, DROP_WEAPON, NADE, WARDEN_DEATH, PASS, FIRE, RESKIN, GHOST_RESPAWN, BAD_DAMAGE, BAD_KILL, BODYID, DNA, SHOP, TSECRET, TAZE
Damage: Whenever a player damages another player
Kill: Whenever a player kills another player
Button: Whenever a player pushes a button
@@ -76,8 +79,13 @@ Pass: Whenever the warden passes
Fire: Whenever the warden is fired
Reskin: Whenever a player reskins a weapon
Ghost_Respawn: Whenever a ghost respawns
-
-showTypes=KILL,WARDEN,WARDEN_DEATH,FIRE,PASS,RESKIN
+Bad_Damage: Whenever a player deals bad damage (inno on inno, traitor on traitor, etc.)
+Bad_Kill: Whenever a player deals bad damage (inno on inno, traitor on traitor, etc.)
+Bodyid: Whenever a player identifies a body
+DNA: Whenever a detective DNA scans a body
+TSecret: Whenever a traitor activates a T secret
+Taze: Whenever a player tazes another player
+showTypes=KILL,WARDEN,WARDEN_DEATH,FIRE,PASS,RESKIN,BAD_KILL
Cooldown for when a CT drops a gun and a T uses the same type of gun (seconds)
gundropTimeout=10