/
Player.kt
201 lines (179 loc) · 7.04 KB
/
Player.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
package network.warzone.api.database.models
import kotlinx.serialization.Serializable
import network.warzone.api.database.Database
import network.warzone.api.socket.leaderboard.ScoreType
import network.warzone.api.socket.player.XP_PER_LEVEL
import org.litote.kmongo.*
import kotlin.math.floor
@Serializable
data class Player(
val _id: String,
var name: String,
var nameLower: String,
var lastSessionId: String? = null,
var firstJoinedAt: Double,
var lastJoinedAt: Double,
var ips: List<String>,
var notes: List<StaffNote>,
var rankIds: List<String>,
var tagIds: List<String>,
var activeTagId: String? = null,
val stats: PlayerStats,
val gamemodeStats: HashMap<LevelGamemode, GamemodeStats>
) {
suspend fun getActiveSession(): Session? {
return Database.sessions.findOne(Session::endedAt eq null, Session::player / SimplePlayer::id eq _id)
}
suspend fun findSession(id: String): Session? {
return Database.sessions.findOne(Session::_id eq id, Session::player / SimplePlayer::id eq _id)
}
suspend fun getPunishments(): List<Punishment> {
return Database.punishments.find(Punishment::target / SimplePlayer::id eq this._id).toList()
.sortedBy { it.issuedAt }
}
suspend fun getActivePunishments(): List<Punishment> {
return getPunishments().filter { it.isActive }.sortedBy { it.issuedAt }
}
// note: only first degree alts atm
suspend fun getAlts(): List<Player> {
return Database.players.find(Player::ips `in` this.ips, Player::_id ne this._id).toList()
}
fun sanitise(): Player {
val sanitised = this.copy()
sanitised.ips = emptyList()
sanitised.notes = emptyList()
sanitised.lastSessionId = null
return sanitised
}
companion object {
suspend fun ensureNameUniqueness(name: String, keepId: String) {
val tempName = ">WZPlayer${(0..1000).random()}"
Database.players.updateMany(
and(Player::nameLower eq name.lowercase(), not(Player::_id eq keepId)),
SetTo(Player::name, tempName),
SetTo(Player::nameLower, tempName)
)
}
}
val simple: SimplePlayer
get() {
return SimplePlayer(name = this.name, id = this._id)
}
/**
* If name is Notch & ID is 069a79f4-44e9-4726-a5be-fca90e38aaf5
* Encoded string is 069a79f4-44e9-4726-a5be-fca90e38aaf5/Notch
*/
val idName: String
get() = "${_id}/${name}"
}
@Serializable
data class SimplePlayer(val name: String, val id: String)
typealias GamemodeStats = PlayerStats
@Serializable
data class PlayerStats(
var xp: Int = 0,
var serverPlaytime: Long = 0,
var gamePlaytime: Long = 0,
var kills: Int = 0,
var deaths: Int = 0,
var voidKills: Int = 0,
var voidDeaths: Int = 0,
var firstBloods: Int = 0,
var firstBloodsSuffered: Int = 0,
val objectives: PlayerObjectiveStatistics = PlayerObjectiveStatistics(),
var bowShotsTaken: Int = 0,
var bowShotsHit: Int = 0,
val blocksPlaced: HashMap<String, Int> = hashMapOf(),
val blocksBroken: HashMap<String, Int> = hashMapOf(),
var damageTaken: Double = 0.0,
var damageGiven: Double = 0.0,
var damageGivenBow: Double = 0.0,
val messages: PlayerMessages = PlayerMessages(),
var wins: Int = 0,
var losses: Int = 0,
var ties: Int = 0,
var matches: Int = 0,
var matchesPresentStart: Int = 0,
var matchesPresentFull: Int = 0,
var matchesPresentEnd: Int = 0,
val records: PlayerRecords = PlayerRecords(),
val weaponKills: MutableMap<String, Int> = mutableMapOf(),
val weaponDeaths: MutableMap<String, Int> = mutableMapOf(),
val killstreaks: MutableMap<Int, Int> = mutableMapOf(),
val killstreaksEnded: MutableMap<Int, Int> = mutableMapOf(),
) {
val level: Int
get() = floor(((xp + XP_PER_LEVEL) / XP_PER_LEVEL).toDouble()).toInt()
fun getScore(type: ScoreType): Int {
return when (type) {
ScoreType.KILLS -> kills
ScoreType.DEATHS -> deaths
ScoreType.FIRST_BLOODS -> firstBloods
ScoreType.WINS -> wins
ScoreType.LOSSES -> losses
ScoreType.TIES -> ties
ScoreType.XP -> xp
ScoreType.MESSAGES_SENT -> messages.total
ScoreType.MATCHES_PLAYED -> matches
ScoreType.SERVER_PLAYTIME -> serverPlaytime.toInt() // 2038
ScoreType.GAME_PLAYTIME -> gamePlaytime.toInt()
ScoreType.CORE_LEAKS -> objectives.coreLeaks
ScoreType.CORE_BLOCK_DESTROYS -> objectives.coreBlockDestroys
ScoreType.DESTROYABLE_DESTROYS -> objectives.destroyableDestroys
ScoreType.DESTROYABLE_BLOCK_DESTROYS -> objectives.destroyableBlockDestroys
ScoreType.FLAG_CAPTURES -> objectives.flagCaptures
ScoreType.FLAG_DROPS -> objectives.flagDrops
ScoreType.FLAG_PICKUPS -> objectives.flagPickups
ScoreType.FLAG_DEFENDS -> objectives.flagDefends
ScoreType.FLAG_HOLD_TIME -> objectives.totalFlagHoldTime.toInt()
ScoreType.WOOL_CAPTURES -> objectives.woolCaptures
ScoreType.WOOL_DROPS -> objectives.woolDrops
ScoreType.WOOL_PICKUPS -> objectives.woolPickups
ScoreType.WOOL_DEFENDS -> objectives.woolDefends
ScoreType.CONTROL_POINT_CAPTURES -> objectives.controlPointCaptures
ScoreType.HIGHEST_KILLSTREAK -> killstreaks[killstreaks.keys.maxOrNull() ?: 100] ?: 0
}
}
}
@Serializable
data class PlayerRecords(
var longestSession: SessionRecord? = null,
var longestProjectileKill: ProjectileRecord? = null,
var fastestWoolCapture: LongRecord? = null,
var fastestFlagCapture: LongRecord? = null,
var fastestFirstBlood: FirstBloodRecord? = null,
var killsInMatch: IntRecord? = null,
var deathsInMatch: IntRecord? = null,
)
@Serializable
data class SessionRecord(val sessionId: String, val length: Long)
@Serializable
data class ProjectileRecord(val matchId: String, val player: SimplePlayer, val distance: Int)
@Serializable
data class FirstBloodRecord(val matchId: String, val attacker: SimplePlayer, val victim: SimplePlayer, val time: Long)
@Serializable
data class IntRecord(val matchId: String, val player: SimplePlayer, val value: Int)
@Serializable
data class LongRecord(val matchId: String, val player: SimplePlayer, val value: Long)
@Serializable
data class PlayerObjectiveStatistics(
var coreLeaks: Int = 0,
var coreBlockDestroys: Int = 0,
var destroyableDestroys: Int = 0,
var destroyableBlockDestroys: Int = 0,
var flagCaptures: Int = 0,
var flagPickups: Int = 0,
var flagDrops: Int = 0,
var flagDefends: Int = 0,
var totalFlagHoldTime: Long = 0,
var woolCaptures: Int = 0,
var woolDrops: Int = 0,
var woolDefends: Int = 0,
var woolPickups: Int = 0,
var controlPointCaptures: Int = 0
)
@Serializable
data class PlayerMessages(var staff: Int = 0, var global: Int = 0, var team: Int = 0) {
val total: Int
get() = staff + global + team
}