From 585761ae9c0c500477fe0efe0e94ac893f8a68c7 Mon Sep 17 00:00:00 2001 From: TONY_All Date: Sat, 5 Feb 2022 22:08:50 +0800 Subject: [PATCH] add new features: - logout time check - inspect command --- README.md | 31 +++++++++++++++--- build.gradle.kts | 1 + .../kotlin/cc/maxmc/invite/BiliInviteCode.kt | 1 + .../invite/command/InviteCodeCommands.kt | 22 ++++++++++++- .../cc/maxmc/invite/data/InviteCodeData.kt | 21 ++++++++++-- .../maxmc/invite/listener/InvitedListener.kt | 32 +++++++++++++++++++ 6 files changed, 100 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index dae364a..5f90020 100644 --- a/README.md +++ b/README.md @@ -10,18 +10,41 @@ BiliInviteCode - 邀请制入服检测 子命令: -- /inviteCode use <邀请码> 激活邀请码 √ +- /inviteCode use <邀请码> 激活邀请码 -- /inviteCode generate <数量> 生成指定数量的激活码 (后台) √ +- /inviteCode generate <数量> 生成指定数量的激活码 (后台) 激活码会被保存在`服务器根目录/plugins/BiliInviteCode/InviteCode/generated/xx.txt` -- /inviteCode edit <玩家ID> <新的QQ号> 修改激活码对应的值 (后台) √ +- /inviteCode edit <玩家ID> <新的QQ号> 修改激活码对应的值 (后台) - /inviteCode remove <激活码> 移除该激活码 - /inviteCode current 显示所有可用激活码 -- /inviteCode add <激活码> 手动创建激活码 (后台) √ +- /inviteCode add <激活码> 手动创建激活码 (后台) 激活码的长度不能长于24位 + +- /inviteCode inspect <玩家ID> 查询玩家绑定的QQ号 + +## 数据库结构 + +数据库分为两张表: `InviteCodes` 与 `TimeTable` + +### InviteCodes + +`InviteCodes` 负责存储玩家的邀请码数据, 格式如下: + +| id(int) | inviteCode(varchar) | name(id) | uid(UUID) | qq(varchar) | +| ------------ | ------------------- | ------------------------ | ---------- | ------------ | +| 数据库索引ID | 玩家的邀请码 | 玩家ID(随正版ID自动变更) | 玩家的UUID | 玩家绑定QQ号 | + +### TimeTable + +`TimeTable` 负责存储玩家的最后退出游戏的日期, 以便能在超过3个月未进入过服务器时移除权限, 格式如下: + +| id(UUID) | lastLogout(date) | +| ---------- | -------------------------------- | +| 玩家的UUID | 玩家最后推出游戏的日期(精确到日) | + diff --git a/build.gradle.kts b/build.gradle.kts index 77b57e9..62df41d 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -34,6 +34,7 @@ dependencies { implementation("org.jetbrains.exposed:exposed-core:$exposedVersion") implementation("org.jetbrains.exposed:exposed-dao:$exposedVersion") implementation("org.jetbrains.exposed:exposed-jdbc:$exposedVersion") + implementation("org.jetbrains.exposed:exposed-java-time:$exposedVersion") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.0") } diff --git a/src/main/kotlin/cc/maxmc/invite/BiliInviteCode.kt b/src/main/kotlin/cc/maxmc/invite/BiliInviteCode.kt index 1df5279..3267b9f 100644 --- a/src/main/kotlin/cc/maxmc/invite/BiliInviteCode.kt +++ b/src/main/kotlin/cc/maxmc/invite/BiliInviteCode.kt @@ -19,6 +19,7 @@ import java.util.concurrent.Executor RuntimeDependency("org.jetbrains.exposed:exposed-core:0.37.3"), RuntimeDependency("org.jetbrains.exposed:exposed-dao:0.37.3"), RuntimeDependency("org.jetbrains.exposed:exposed-jdbc:0.37.3"), + RuntimeDependency("org.jetbrains.exposed:exposed-java-time:0.37.3"), RuntimeDependency("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.0"), RuntimeDependency("com.h2database:h2:1.4.200") ) diff --git a/src/main/kotlin/cc/maxmc/invite/command/InviteCodeCommands.kt b/src/main/kotlin/cc/maxmc/invite/command/InviteCodeCommands.kt index 844f8fb..64272ae 100644 --- a/src/main/kotlin/cc/maxmc/invite/command/InviteCodeCommands.kt +++ b/src/main/kotlin/cc/maxmc/invite/command/InviteCodeCommands.kt @@ -11,8 +11,10 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import org.bukkit.Bukkit +import org.bukkit.command.CommandSender import org.bukkit.command.ConsoleCommandSender import org.bukkit.entity.Player +import org.jetbrains.exposed.sql.transactions.experimental.newSuspendedTransaction import org.jetbrains.exposed.sql.transactions.transaction import taboolib.common.platform.command.CommandBuilder import taboolib.common.platform.command.command @@ -139,7 +141,7 @@ object InviteCodeCommands { } } - private fun CommandBuilder.CommandComponent.cmdEdit() = literal("edit", permission = "invitecode.edit") { + private fun CommandBuilder.CommandComponent.cmdEdit() = literal("edit", permission = "inviteCode.edit".lowercase()) { dynamic { restrict { _, _, arg -> transaction { @@ -222,4 +224,22 @@ object InviteCodeCommands { } } } + + private fun CommandBuilder.CommandComponent.cmdInspect() = + literal("inspect", permission = "inviteCode.inspect".lowercase()) { + dynamic { + suggestion(uncheck = true) { _, _ -> + return@suggestion Bukkit.getOnlinePlayers().map { it.name } + } + execute { sender, _, arg -> + PluginScope.launch { + newSuspendedTransaction { + val code = InviteCode.find { InviteCodes.name eq arg }.firstOrNull() + ?: return@newSuspendedTransaction sender.sendMessage("§c| §7该玩家不存在") + sender.sendMessage("§a| §7该玩家绑定的QQ为: §a${code.qq}") + } + } + } + } + } } \ No newline at end of file diff --git a/src/main/kotlin/cc/maxmc/invite/data/InviteCodeData.kt b/src/main/kotlin/cc/maxmc/invite/data/InviteCodeData.kt index cfcad09..494fda5 100644 --- a/src/main/kotlin/cc/maxmc/invite/data/InviteCodeData.kt +++ b/src/main/kotlin/cc/maxmc/invite/data/InviteCodeData.kt @@ -3,12 +3,14 @@ package cc.maxmc.invite.data import cc.maxmc.invite.PluginScope import kotlinx.coroutines.launch import org.bukkit.Bukkit -import org.jetbrains.exposed.dao.IntEntity -import org.jetbrains.exposed.dao.IntEntityClass +import org.jetbrains.exposed.dao.* import org.jetbrains.exposed.dao.id.EntityID +import org.jetbrains.exposed.dao.id.IdTable import org.jetbrains.exposed.dao.id.IntIdTable +import org.jetbrains.exposed.sql.Column import org.jetbrains.exposed.sql.Database import org.jetbrains.exposed.sql.SchemaUtils +import org.jetbrains.exposed.sql.javatime.date import org.jetbrains.exposed.sql.transactions.transaction import taboolib.common.platform.function.getDataFolder import taboolib.common.platform.function.info @@ -47,11 +49,24 @@ class InviteCode(id: EntityID) : IntEntity(id) { companion object : IntEntityClass(InviteCodes) var inviteCode by InviteCodes.inviteCode - var name by InviteCodes.name var uid by InviteCodes.uid + var name by InviteCodes.name var qq by InviteCodes.qq } +object TimeTable : IdTable() { + override val id = uuid("uid").entityId() + val lastLogout = date("last_login") + override val primaryKey = PrimaryKey(id) +} + +class LastLogout(id: EntityID): UUIDEntity(id) { + companion object : UUIDEntityClass(TimeTable) + + val uid by TimeTable.id + var last by TimeTable.lastLogout +} + val userTrials = HashMap() data class UserTrial(val uid: UUID, private var attempts: Int = 0) { diff --git a/src/main/kotlin/cc/maxmc/invite/listener/InvitedListener.kt b/src/main/kotlin/cc/maxmc/invite/listener/InvitedListener.kt index e0817c2..ca9efff 100644 --- a/src/main/kotlin/cc/maxmc/invite/listener/InvitedListener.kt +++ b/src/main/kotlin/cc/maxmc/invite/listener/InvitedListener.kt @@ -4,6 +4,7 @@ import cc.maxmc.invite.PluginScope import cc.maxmc.invite.concurrent.chatInput import cc.maxmc.invite.data.InviteCode import cc.maxmc.invite.data.InviteCodes +import cc.maxmc.invite.data.LastLogout import kotlinx.coroutines.launch import org.bukkit.Location import org.bukkit.entity.Player @@ -11,6 +12,7 @@ import org.bukkit.event.player.* import org.jetbrains.exposed.sql.transactions.experimental.newSuspendedTransaction import taboolib.common.platform.event.SubscribeEvent import taboolib.common.platform.function.console +import java.time.LocalDate import java.util.* import java.util.concurrent.ConcurrentHashMap @@ -64,6 +66,13 @@ object InvitedListener { return input } + suspend fun checkTime(uid: UUID): Boolean { + return newSuspendedTransaction { + val lastLogout = LastLogout.findById(uid) ?: return@newSuspendedTransaction true + lastLogout.last.plusMonths(3).isBefore(LocalDate.now()) + } + } + cache[e.player.uniqueId] = e.player.location e.player.sendMessage("§e| §7正在检查您的邀请码...请稍等.") PluginScope.launch { @@ -71,6 +80,11 @@ object InvitedListener { val playerInviteCode = InviteCode.find { InviteCodes.uid eq e.player.uniqueId } .firstOrNull() ?: return@newSuspendedTransaction e.player.sendMessage("§c| §7您的账号未激活, 请输入 §c/ic use <激活码> §7来进行激活.") + if (!checkTime(e.player.uniqueId)) { + e.player.kickPlayer("§c| §7由于超过3个月未登录游戏, 您的邀请码已失效.") + playerInviteCode.delete() + return@newSuspendedTransaction + } if (playerInviteCode.qq == null) { playerInviteCode.qq = requireQQNumber(e.player) } @@ -84,4 +98,22 @@ object InvitedListener { } } } + + @SubscribeEvent + fun onQuit(e: PlayerQuitEvent) { + PluginScope.launch { + newSuspendedTransaction { + val lastLogout = LastLogout.findById(e.player.uniqueId) + if (lastLogout == null) { + LastLogout.new(e.player.uniqueId) { + last = LocalDate.now() + } + } else { + lastLogout.run { + last = LocalDate.now() + } + } + } + } + } } \ No newline at end of file