Browse Source

Merge branch '7-feature-ranking-command' into 'dev'

Resolve "[FEATURE] "ranking" command"

Closes #7

See merge request hamburghammer/playtime!14
dev
Augusto Dwenger 2 years ago
parent
commit
dfcd3cd35a
  1. 5
      README.md
  2. 2
      src/main/kotlin/Main.kt
  3. 38
      src/main/kotlin/SimplePlayerTime.kt
  4. 28
      src/main/kotlin/commands/TopTime.kt
  5. 5
      src/main/resources/plugin.yml
  6. 105
      src/test/kotlin/commands/TopTimeTest.kt
  7. 18
      src/test/kotlin/db/SimplePlayerTimeTest.kt

5
README.md

@ -19,9 +19,14 @@ It's a plugin for a [Spigot](https://www.spigotmc.org) Minecraft server to log t
`playtime` shows the total play time on the server (Format DD:HH:MM)
`playtimeof <player>` shows the total play time of the player (Format DD:HH:MM)
`toptime` shows the top 5 player with the highest total playtime
## Development
The plugin gets build with gradle. It is important to run the shadowJar task to include all dependencies.
It's entirely written in Kotlin and for testing it uses [Mockk](https://mockk.io/) and [Junit5](https://junit.org/junit5/).
This plugin uses the [linter from Pinterest for Kotlin](https://www.kotlinresources.com/library/ktlint/)

2
src/main/kotlin/Main.kt

@ -1,6 +1,7 @@
import commands.PlayTime
import commands.PlayTimeOfCommand
import commands.TestCommand
import commands.TopTime
import commands.UpTime
import listener.JoinListener
import listener.QuitListener
@ -31,6 +32,7 @@ class Main : JavaPlugin() {
this.getCommand("playtime")?.setExecutor(PlayTime())
this.getCommand("uptime")?.setExecutor(UpTime())
this.getCommand("playtimeof")?.setExecutor(PlayTimeOfCommand())
this.getCommand("toptime")?.setExecutor(TopTime())
server.pluginManager.registerEvents(JoinListener(), this)
server.pluginManager.registerEvents(QuitListener(), this)

38
src/main/kotlin/SimplePlayerTime.kt

@ -13,7 +13,7 @@ import models.Player
class SimplePlayerTime(private val db: PlayerTimeDB) : PlayerTime {
/**
* Adds the player to the playerMap.
* Adds the player to the [db].
* It creates an new player if it's no persisted and adds/refreshes the join time
*
* @param uuid the actual uuid of a player
@ -34,20 +34,18 @@ class SimplePlayerTime(private val db: PlayerTimeDB) : PlayerTime {
}
/**
* Updates the playtime and saves it
* Updates the playtime and saves it from the player with the [uuid]
*
* @param uuid UUID
*/
override fun updatePlayTime(uuid: UUID) {
val player = db.findById(uuid)
val playTime = timePlayed(uuid)
player.playTime = playTime
player.playTime = calculatePlaytime(player)
db.save(player)
}
/**
* Returns the playtime including the old time
* if the stats got save it should use the save time instead of the join time
* Returns the playtime of the player with the the [uuid]
*
* @param uuid player uuid
*
@ -55,13 +53,7 @@ class SimplePlayerTime(private val db: PlayerTimeDB) : PlayerTime {
*/
override fun timePlayed(uuid: UUID): Duration {
val player = db.findById(uuid)
val playTime: Duration =
if ((player.lastSave != null) && Duration.between(player.lastSave, player.joinTime).isNegative) {
Duration.between(player.lastSave, LocalDateTime.now())
} else {
Duration.between(player.joinTime, LocalDateTime.now())
}
return Duration.from(player.playTime).plus(playTime)
return calculatePlaytime(player)
}
/**
@ -70,6 +62,24 @@ class SimplePlayerTime(private val db: PlayerTimeDB) : PlayerTime {
* @return List<Player> in a descending order by playtime
*/
override fun getTopPlayers(): List<Player> {
return db.findAll().sortedByDescending { player -> player.playTime }
val playerList: List<Player> = db.findAll().onEach { player -> player.playTime = calculatePlaytime(player) }
return playerList.sortedByDescending { player -> player.playTime }
}
/**
* Calculates the time based on the join and on the last save time of the player
* if the playtime got saved it should use the saved time instead of the join time
*
* @param player Player
* @return Duration the playtime of the [player]
*/
private fun calculatePlaytime(player: Player): Duration {
val playTime: Duration =
if ((player.lastSave != null) && Duration.between(player.lastSave, player.joinTime).isNegative) {
Duration.between(player.lastSave, LocalDateTime.now())
} else {
Duration.between(player.joinTime, LocalDateTime.now())
}
return Duration.from(player.playTime).plus(playTime)
}
}

28
src/main/kotlin/commands/TopTime.kt

@ -0,0 +1,28 @@
package commands
import PlayerTime
import PlayerTimeService
import java.util.stream.Collectors
import org.bukkit.command.Command
import org.bukkit.command.CommandExecutor
import org.bukkit.command.CommandSender
/**
* Command to get the top players with the most playtime
*
* @property playerTime PlayerTime
* @property playerListSize Long default = 5
* @constructor
*/
class TopTime(private val playerTime: PlayerTime = PlayerTimeService, private val playerListSize: Long = 5) : CommandExecutor {
override fun onCommand(sender: CommandSender, command: Command, label: String, args: Array<out String>): Boolean {
val playerTopList = playerTime.getTopPlayers().stream().limit(playerListSize).collect(Collectors.toList()).toList()
val sb = StringBuilder().appendln("Top list")
playerTopList.forEach { sb.appendln("${it.playerName}: ${playerTime.timeToString(it.playTime)}") }
sender.sendMessage(sb.toString())
return true
}
}

5
src/main/resources/plugin.yml

@ -16,4 +16,7 @@ commands:
description: "Shows the up time of the server"
playtimeof:
usage: /<command> <player>
description: "Shows the playtime of the player"
description: "Shows the playtime of the player"
toptime:
usage: /<command>
description: "Shows top players with the highest playtime"

105
src/test/kotlin/commands/TopTimeTest.kt

@ -0,0 +1,105 @@
package commands
import SimplePlayerTime
import io.mockk.Runs
import io.mockk.every
import io.mockk.just
import io.mockk.mockk
import io.mockk.unmockkAll
import java.time.Duration
import java.util.UUID
import kotlin.test.BeforeTest
import kotlin.test.Test
import kotlin.test.assertEquals
import models.Player
import org.bukkit.command.CommandSender
import org.junit.jupiter.api.Assertions.assertNotEquals
import org.junit.jupiter.api.Assertions.assertTrue
class TopTimeTest {
@BeforeTest
fun setUp() {
unmockkAll()
}
@Test
fun `send string`() {
val captureList = mutableListOf<String>()
val uuid1 = UUID.randomUUID()
val uuid2 = UUID.randomUUID()
val uuid3 = UUID.randomUUID()
val player1 = Player(uuid1, "player1", playTime = Duration.ZERO)
val player2 = Player(uuid2, "player2", playTime = Duration.ofMinutes(10))
val player3 = Player(uuid3, "player3", playTime = Duration.ofHours(2))
val mockPlayTime = mockk<SimplePlayerTime>()
every { mockPlayTime.getTopPlayers() } returns listOf(player3, player2, player1)
every { mockPlayTime.timeToString(any()) } returns "00:00:00"
val topTime = TopTime(mockPlayTime)
val mockCommandSender = mockk<CommandSender>()
every { mockCommandSender.sendMessage(capture(captureList)) } just Runs
assertTrue(topTime.onCommand(mockCommandSender, mockk(), "", arrayOf()))
assertTrue(captureList.isNotEmpty())
assertNotEquals("", captureList.first())
}
@Test
fun `correct formatted string output`() {
val captureList = mutableListOf<String>()
val uuid1 = UUID.randomUUID()
val uuid2 = UUID.randomUUID()
val uuid3 = UUID.randomUUID()
val player1 = Player(uuid1, "player1", playTime = Duration.ZERO)
val player2 = Player(uuid2, "player2", playTime = Duration.ofMinutes(10))
val player3 = Player(uuid3, "player3", playTime = Duration.ofHours(2))
val mockPlayTime = mockk<SimplePlayerTime>()
every { mockPlayTime.getTopPlayers() } returns listOf(player3, player2, player1)
every { mockPlayTime.timeToString(any()) } returns "00:00:00"
val mockCommandSender = mockk<CommandSender>()
every { mockCommandSender.sendMessage(capture(captureList)) } just Runs
val topTime = TopTime(mockPlayTime)
assertTrue(topTime.onCommand(mockCommandSender, mockk(), "", arrayOf()))
assertEquals(
"""Top list
player3: 00:00:00
player2: 00:00:00
player1: 00:00:00
""", captureList.first().toString()
)
}
@Test
fun `show only top 6 player`() {
val playerListSize = 6
val defaultNewLines = 2
val captureList = mutableListOf<String>()
val playerList = mutableListOf<Player>()
for (i in 1..7) {
playerList.add(Player(UUID.randomUUID(), "$i", playTime = Duration.ZERO))
}
val mockPlayTime = mockk<SimplePlayerTime>()
every { mockPlayTime.getTopPlayers() } returns playerList.toList()
every { mockPlayTime.timeToString(any()) } returns "00:00:00"
val mockCommandSender = mockk<CommandSender>()
every { mockCommandSender.sendMessage(capture(captureList)) } just Runs
val topTime = TopTime(mockPlayTime, playerListSize.toLong())
assertTrue(topTime.onCommand(mockCommandSender, mockk(), "", arrayOf()))
assertEquals(playerListSize + defaultNewLines, captureList.first().split("\n").count())
}
}

18
src/test/kotlin/db/SimplePlayerTimeTest.kt

@ -113,6 +113,24 @@ class SimplePlayerTimeTest {
}
}
@Test
fun `update the play time and save`() {
val capturedPlayers = mutableListOf<Player>()
val uuid = UUID.randomUUID()
val player = Player(uuid, "", playTime = Duration.ZERO)
val mockDBPlayerTimeDB = mockk<PlayerTimeDB>()
every { mockDBPlayerTimeDB.findById(uuid) } returns player
every { mockDBPlayerTimeDB.save(capture(capturedPlayers)) } just Runs
val simplePlayerTime = SimplePlayerTime(mockDBPlayerTimeDB)
simplePlayerTime.updatePlayTime(uuid)
assertEquals(1, capturedPlayers.size)
assertNotEquals(Duration.ZERO, capturedPlayers.first().playTime)
}
@Nested
inner class TimePlayedTest {

Loading…
Cancel
Save