Added additional abstraction for better squad overview.
This commit is contained in:
parent
78b102dfbf
commit
72625833cd
1
.idea/misc.xml
generated
1
.idea/misc.xml
generated
@ -1,4 +1,3 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="17" project-jdk-type="JavaSDK">
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="17" project-jdk-type="JavaSDK">
|
||||||
|
|||||||
@ -5,17 +5,44 @@ object Css {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
.teamA{
|
.team{
|
||||||
width: 50%;
|
width: 50%;
|
||||||
|
margin: 6px;
|
||||||
|
padding: 6px;
|
||||||
}
|
}
|
||||||
.teamB{
|
.colorBluFor{
|
||||||
width: 50%;
|
background-color: #bbffff;
|
||||||
|
}
|
||||||
|
.colorRedFor{
|
||||||
|
background-color: #ffbbbb;
|
||||||
|
}
|
||||||
|
.squad{
|
||||||
|
background-color: #00000020;
|
||||||
|
margin: 6px;
|
||||||
}
|
}
|
||||||
.squadTable{
|
.squadTable{
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
.squadHeader{
|
||||||
|
background-color: #00000050
|
||||||
|
}
|
||||||
|
.leader{
|
||||||
|
background-color: #CD7F32
|
||||||
|
}
|
||||||
|
.playerClass{
|
||||||
|
width: 15%;
|
||||||
|
}
|
||||||
|
.playerName{
|
||||||
|
width: 35%;
|
||||||
|
}
|
||||||
|
.playerId{
|
||||||
|
width: 35%;
|
||||||
|
}
|
||||||
|
.playerButtons{
|
||||||
|
width: 15%;
|
||||||
|
}
|
||||||
tr:nth-child(even) {
|
tr:nth-child(even) {
|
||||||
background-color: rgba(0, 0, 0, 0.5);
|
background-color: rgba(0, 0, 0, 0.1);
|
||||||
}
|
}
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
}
|
}
|
||||||
@ -74,8 +74,47 @@ fun main() {
|
|||||||
}
|
}
|
||||||
get("/overview") {
|
get("/overview") {
|
||||||
val players = abstraction.getCurrentPlayers()
|
val players = abstraction.getCurrentPlayers()
|
||||||
|
val squadInfo = abstraction.getSquadList()
|
||||||
|
|
||||||
call.respondHtmlTemplate(OverviewTemplate(players)) {}
|
call.respondHtmlTemplate(OverviewTemplate(players, squadInfo)) {}
|
||||||
|
}
|
||||||
|
get("/overviewDemo") {
|
||||||
|
//val players = abstraction.getCurrentPlayers()
|
||||||
|
//val squadInfo = abstraction.getSquadList()
|
||||||
|
val players = ListPlayersOutput(
|
||||||
|
arrayListOf(
|
||||||
|
Player(1, 86868686868686868L, "newSlMan", 1, 1, true, "SL"),
|
||||||
|
Player(2, 31337313373133711L, "IStayed(TM)", 2, 1, true, "SL"),
|
||||||
|
Player(1, 1L, "Man1", 1, 1, false, "RM"),
|
||||||
|
Player(1, 2L, "Man2", 1, 1, false, "LAT"),
|
||||||
|
Player(1, 3L, "Man3", 1, 1, false, "HAT"),
|
||||||
|
Player(1, 4L, "Man4", 1, 1, false, "MED"),
|
||||||
|
Player(1, 5L, "Man5", 1, 1, false, "GR"),
|
||||||
|
Player(1, 6L, "OtherSL1", 2, 2, true, "SL"),
|
||||||
|
Player(1, 7L, "OtherMan2", 2, 2, false, "MED"),
|
||||||
|
Player(1, 8L, "OtherMan3", 2, 0, false, "RM"),
|
||||||
|
Player(1, 9L, "OtherMan4", 2, 0, false, "RM"),
|
||||||
|
Player(1, 10L, "OtherMan5", 2, 0, false, "RM"),
|
||||||
|
), arrayListOf()
|
||||||
|
)
|
||||||
|
|
||||||
|
val squadInfo = Pair(
|
||||||
|
RconAbstraction.SquadListFaction(
|
||||||
|
"1st Battalion, 1st Marines", hashMapOf(
|
||||||
|
1 to RconAbstraction.SquadListSquad("HERPS", 5, true, "leaver9000", 69696969696969696L)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
RconAbstraction.SquadListFaction(
|
||||||
|
"Insurgent Rebel Federation", hashMapOf(
|
||||||
|
1 to RconAbstraction.SquadListSquad("DERPS", 1, true, "IStayed(TM)", 31337313373133711L),
|
||||||
|
2 to RconAbstraction.SquadListSquad("NOOBS WELCOME", 2, false, "OtherSL1", 6L)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
call.respondHtmlTemplate(OverviewTemplate(players, squadInfo)) {
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
get("/css") {
|
get("/css") {
|
||||||
call.respondText(contentType = ContentType.Text.CSS, text = Css.cssString)
|
call.respondText(contentType = ContentType.Text.CSS, text = Css.cssString)
|
||||||
|
|||||||
@ -1,7 +1,10 @@
|
|||||||
import io.ktor.server.html.*
|
import io.ktor.server.html.*
|
||||||
import kotlinx.html.*
|
import kotlinx.html.*
|
||||||
|
|
||||||
class OverviewTemplate(private val players: ListPlayersOutput) : Template<HTML> {
|
class OverviewTemplate(
|
||||||
|
private val players: ListPlayersOutput,
|
||||||
|
private val squadInfo: Pair<RconAbstraction.SquadListFaction, RconAbstraction.SquadListFaction>
|
||||||
|
) : Template<HTML> {
|
||||||
private fun TR.makePlayer(player: Player) {
|
private fun TR.makePlayer(player: Player) {
|
||||||
td { +player.role }
|
td { +player.role }
|
||||||
td { +player.name }
|
td { +player.name }
|
||||||
@ -11,7 +14,7 @@ class OverviewTemplate(private val players: ListPlayersOutput) : Template<HTML>
|
|||||||
+"✉"
|
+"✉"
|
||||||
}
|
}
|
||||||
button {//Kick
|
button {//Kick
|
||||||
+"\uD83E\uDDB6"
|
+"⏏"
|
||||||
}
|
}
|
||||||
button {//Ban
|
button {//Ban
|
||||||
+"⛔"
|
+"⛔"
|
||||||
@ -19,17 +22,38 @@ class OverviewTemplate(private val players: ListPlayersOutput) : Template<HTML>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun FlowContent.makeSquad(squad: Map.Entry<Int, List<Player>>) {
|
private fun FlowContent.makeSquad(
|
||||||
|
squad: Map.Entry<Int, List<Player>>,
|
||||||
|
squadListSquad: RconAbstraction.SquadListSquad
|
||||||
|
) {
|
||||||
val leader = squad.value.find { it.leader }
|
val leader = squad.value.find { it.leader }
|
||||||
+if (squad.key != 0) {
|
div("squad") {
|
||||||
"Squad ${squad.key}"
|
div("squadHeader") {
|
||||||
|
if (squad.key != 0) {
|
||||||
|
+squadListSquad.name
|
||||||
} else {
|
} else {
|
||||||
"Unassigned"
|
+"Unassigned"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (squadListSquad.locked) {
|
||||||
|
+" \uD83D\uDD12"
|
||||||
|
}
|
||||||
|
|
||||||
|
if (squadListSquad.creatorSteamId != (leader?.steamId ?: 0) && squadListSquad.creatorSteamId != 0L) {
|
||||||
|
+" (originally created by ${squadListSquad.creatorName} ${squadListSquad.creatorSteamId})"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
table("squadTable") {
|
table("squadTable") {
|
||||||
|
colGroup {
|
||||||
|
col("playerClass")
|
||||||
|
col("playerName")
|
||||||
|
col("playerId")
|
||||||
|
col("playerButtons")
|
||||||
|
}
|
||||||
leader?.let {
|
leader?.let {
|
||||||
thead {
|
thead {
|
||||||
tr {
|
tr("leader") {
|
||||||
makePlayer(leader)
|
makePlayer(leader)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -43,14 +67,23 @@ class OverviewTemplate(private val players: ListPlayersOutput) : Template<HTML>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun FlowContent.makeSide(team: Map<Int, List<Player>>) {
|
private fun FlowContent.makeSide(team: Map<Int, List<Player>>, squadListFaction: RconAbstraction.SquadListFaction) {
|
||||||
|
div("teamHeader") {
|
||||||
|
+squadListFaction.name
|
||||||
|
}
|
||||||
if (team.keys.isEmpty()) {
|
if (team.keys.isEmpty()) {
|
||||||
+"empty"
|
+"empty"
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
team.forEach {
|
team.forEach {
|
||||||
makeSquad(it)
|
if (it.key != 0) {
|
||||||
|
makeSquad(it, squadListFaction.squads[it.key]!!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
team.filter { it.key == 0 }.forEach {
|
||||||
|
makeSquad(it, RconAbstraction.SquadListSquad("Unassigned", it.value.size, false, "default", 0L))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,11 +97,11 @@ class OverviewTemplate(private val players: ListPlayersOutput) : Template<HTML>
|
|||||||
|
|
||||||
body {
|
body {
|
||||||
div("teamView") {
|
div("teamView") {
|
||||||
div("teamA") {
|
div("team colorRedFor") {
|
||||||
makeSide(teamA)
|
makeSide(teamA, squadInfo.first)
|
||||||
}
|
}
|
||||||
div("teamB") {
|
div("team colorBluFor") {
|
||||||
makeSide(teamB)
|
makeSide(teamB, squadInfo.second)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,11 +1,4 @@
|
|||||||
/*
|
|
||||||
Format for "ListPlayers"
|
|
||||||
----- Active Players -----
|
|
||||||
ID: 0 | SteamID: 76561198037144702 | Name: [PACK] yenon | Team ID: 1 | Squad ID: N/A | Is Leader: False | Role: USA_Rifleman_01
|
|
||||||
----- Recently Disconnected Players [Max of 15] -----
|
|
||||||
ID: 1 | SteamID: 76561199074475884 | Since Disconnect: 03m.56s | Name: RoeveNn
|
|
||||||
ID: 2 | SteamID: 76561199262966526 | Since Disconnect: 03m.51s | Name: Aliko
|
|
||||||
*/
|
|
||||||
|
|
||||||
data class ListPlayersOutput(val players: ArrayList<Player>, val disconnected: ArrayList<DisconnectedPlayer>)
|
data class ListPlayersOutput(val players: ArrayList<Player>, val disconnected: ArrayList<DisconnectedPlayer>)
|
||||||
data class Player(
|
data class Player(
|
||||||
@ -30,12 +23,19 @@ val inactivePlayerInListRegex = Regex(
|
|||||||
)
|
)
|
||||||
|
|
||||||
class RconAbstraction(private val connection: RconConnection) {
|
class RconAbstraction(private val connection: RconConnection) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
Format for "ListPlayers"
|
||||||
|
----- Active Players -----
|
||||||
|
ID: 0 | SteamID: 76561198037144702 | Name: [PACK] yenon | Team ID: 1 | Squad ID: N/A | Is Leader: False | Role: USA_Rifleman_01
|
||||||
|
----- Recently Disconnected Players [Max of 15] -----
|
||||||
|
ID: 1 | SteamID: 76561199074475884 | Since Disconnect: 03m.56s | Name: RoeveNn
|
||||||
|
ID: 2 | SteamID: 76561199262966526 | Since Disconnect: 03m.51s | Name: Aliko
|
||||||
|
*/
|
||||||
suspend fun getCurrentPlayers(): ListPlayersOutput {
|
suspend fun getCurrentPlayers(): ListPlayersOutput {
|
||||||
val active = arrayListOf<Player>()
|
val active = arrayListOf<Player>()
|
||||||
val disconnected = arrayListOf<DisconnectedPlayer>()
|
val disconnected = arrayListOf<DisconnectedPlayer>()
|
||||||
connection.sendCommand("ListPlayers").getOrNull()?.let {
|
connection.sendCommand("ListPlayers").getOrNull()?.let {
|
||||||
|
|
||||||
println(it)
|
|
||||||
activePlayerInListRegex.findAll(it).forEach { match ->
|
activePlayerInListRegex.findAll(it).forEach { match ->
|
||||||
val playerId = match.groupValues[1].toInt()
|
val playerId = match.groupValues[1].toInt()
|
||||||
val steamId = match.groupValues[2].toLong()
|
val steamId = match.groupValues[2].toLong()
|
||||||
@ -57,6 +57,60 @@ class RconAbstraction(private val connection: RconConnection) {
|
|||||||
return ListPlayersOutput(active, disconnected)
|
return ListPlayersOutput(active, disconnected)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
----- Active Squads -----
|
||||||
|
Team ID: 1 (3rd Division)
|
||||||
|
ID: 1 | Name: HERPDERP2 THE RECONING | Size: 1 | Locked: True | Creator Name: yenon | Creator Steam ID: 76561198037144702
|
||||||
|
Team ID: 2 (Insurgent Rebel Federation)
|
||||||
|
*/
|
||||||
|
|
||||||
|
data class SquadListSquad(
|
||||||
|
val name: String,
|
||||||
|
val size: Int,
|
||||||
|
val locked: Boolean,
|
||||||
|
val creatorName: String,
|
||||||
|
val creatorSteamId: Long
|
||||||
|
)
|
||||||
|
|
||||||
|
data class SquadListFaction(val name: String, val squads: HashMap<Int, SquadListSquad>)
|
||||||
|
|
||||||
|
suspend fun getSquadList(): Pair<SquadListFaction, SquadListFaction> {
|
||||||
|
val lines = connection.sendCommand("ListSquads").getOrNull()!!.split("\n")
|
||||||
|
|
||||||
|
val teamRegex = Regex("""^Team ID: ([12]) \(([^)]+)\)$""")
|
||||||
|
val squadRegex =
|
||||||
|
Regex("""^ID: (\d+) \| Name: (.*) \| Size: (\d+) \| Locked: (True|False) \| Creator Name: (.*) \| Creator Steam ID: (\d{17})${'$'}""")
|
||||||
|
|
||||||
|
lateinit var faction1: SquadListFaction
|
||||||
|
lateinit var faction2: SquadListFaction
|
||||||
|
|
||||||
|
lateinit var currentFaction: SquadListFaction
|
||||||
|
|
||||||
|
lines.forEach { line ->
|
||||||
|
teamRegex.find(line)?.let {
|
||||||
|
if (it.groupValues[1].toInt() == 1) {
|
||||||
|
faction1 = SquadListFaction(it.groupValues[2], hashMapOf())
|
||||||
|
currentFaction = faction1
|
||||||
|
} else {
|
||||||
|
faction2 = SquadListFaction(it.groupValues[2], hashMapOf())
|
||||||
|
currentFaction = faction2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
squadRegex.find(line)?.let {
|
||||||
|
val squadId = it.groupValues[1].toInt()
|
||||||
|
val name = it.groupValues[2]
|
||||||
|
val size = it.groupValues[3].toInt()
|
||||||
|
val locked = it.groupValues[4].lowercase().toBooleanStrict()
|
||||||
|
val creatorName = it.groupValues[5]
|
||||||
|
val creatorSteamId = it.groupValues[6].toLong()
|
||||||
|
|
||||||
|
currentFaction.squads[squadId] = SquadListSquad(name, size, locked, creatorName, creatorSteamId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Pair(faction1, faction2)
|
||||||
|
}
|
||||||
|
|
||||||
suspend fun kickPlayer(steamId: Long, reason: String) {
|
suspend fun kickPlayer(steamId: Long, reason: String) {
|
||||||
connection.sendCommand("AdminKickById $steamId \"$reason\"")
|
connection.sendCommand("AdminKickById $steamId \"$reason\"")
|
||||||
}
|
}
|
||||||
@ -66,6 +120,6 @@ class RconAbstraction(private val connection: RconConnection) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
suspend fun messagePlayer(steamId: Long, message: String) {
|
suspend fun messagePlayer(steamId: Long, message: String) {
|
||||||
connection.sendCommand("AdminKickById $steamId \"$message\"")
|
connection.sendCommand("AdminMessageById $steamId \"$message\"")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user