From d86991d72d940cf075cbd687ae884ac6d6ff97c0 Mon Sep 17 00:00:00 2001 From: Half_nothing Date: Sun, 22 Sep 2024 21:00:45 +0800 Subject: [PATCH] refactor: Refactor database manager to json manager * Because a SQLite package resulted in too large jar package, I decided to abandon SQLite and use JSON to store player data * Add interface DataService for possible future expansions --- build.gradle.kts | 6 +- detekt.yml | 2 - libs.versions.toml | 12 +- .../net/superricky/tpaplusplus/GlobalConst.kt | 1 + .../net/superricky/tpaplusplus/TpaPlusPlus.kt | 17 +- .../command/commands/BlockCommand.kt | 3 +- .../command/commands/ToggleCommand.kt | 3 +- .../command/commands/UnblockCommand.kt | 3 +- .../tpaplusplus/database/DataService.kt | 17 ++ .../database/DatabaseCacheService.kt | 9 - .../tpaplusplus/database/DatabaseConst.kt | 9 - .../tpaplusplus/database/DatabaseManager.kt | 164 ------------------ .../tpaplusplus/database/DeathPos.kt | 9 + .../tpaplusplus/database/PlayerData.kt | 13 ++ .../tpaplusplus/database/PlayerDataManager.kt | 125 +++++++++++++ .../superricky/tpaplusplus/database/Tables.kt | 68 -------- .../tpaplusplus/event/PlayerEvent.kt | 7 +- .../tpaplusplus/utility/Extensions.kt | 5 +- src/main/resources/tpaplusplus.toml | 2 + 19 files changed, 184 insertions(+), 291 deletions(-) create mode 100644 src/main/kotlin/net/superricky/tpaplusplus/database/DataService.kt delete mode 100644 src/main/kotlin/net/superricky/tpaplusplus/database/DatabaseCacheService.kt delete mode 100644 src/main/kotlin/net/superricky/tpaplusplus/database/DatabaseConst.kt delete mode 100644 src/main/kotlin/net/superricky/tpaplusplus/database/DatabaseManager.kt create mode 100644 src/main/kotlin/net/superricky/tpaplusplus/database/DeathPos.kt create mode 100644 src/main/kotlin/net/superricky/tpaplusplus/database/PlayerData.kt create mode 100644 src/main/kotlin/net/superricky/tpaplusplus/database/PlayerDataManager.kt delete mode 100644 src/main/kotlin/net/superricky/tpaplusplus/database/Tables.kt diff --git a/build.gradle.kts b/build.gradle.kts index 92d600d..98978f1 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -41,14 +41,12 @@ dependencies { modImplementation(libs.translations) // For debug - modImplementation(libs.bundles.database) - modImplementation(libs.bundles.jdbc) modImplementation(libs.bundles.konf) + modImplementation(libs.gson) // For release - shadow(libs.bundles.database) - shadow(libs.bundles.jdbc) shadow(libs.bundles.konf) + shadow(libs.gson) } base { diff --git a/detekt.yml b/detekt.yml index ed8e495..c4488b6 100644 --- a/detekt.yml +++ b/detekt.yml @@ -250,8 +250,6 @@ style: DataClassContainsFunctions: active: true allowOperators: true - DataClassShouldBeImmutable: - active: true DestructuringDeclarationWithTooManyEntries: active: false ForbiddenComment: diff --git a/libs.versions.toml b/libs.versions.toml index f6d7123..ffbac8d 100644 --- a/libs.versions.toml +++ b/libs.versions.toml @@ -9,9 +9,7 @@ yarn-mappings = "1.21.1+build.3" translations = "2.3.1+1.21-pre2" detekt = "1.23.7" konf = "1.1.2" - -exposed = "0.54.0" -sqlite-jdbc = "3.46.1.0" +gson = "2.11.0" [libraries] minecraft = { module = "net.minecraft:minecraft", version.ref = "minecraft" } @@ -25,17 +23,11 @@ konf-core = { module = "com.uchuhimo:konf-core", version.ref = "konf"} konf-toml = { module = "com.uchuhimo:konf-toml", version.ref = "konf"} translations = { module = "xyz.nucleoid:server-translations-api", version.ref = "translations" } -exposed-core = { module = "org.jetbrains.exposed:exposed-core", version.ref = "exposed" } -exposed-dao = { module = "org.jetbrains.exposed:exposed-dao", version.ref = "exposed" } -exposed-jdbc = { module = "org.jetbrains.exposed:exposed-jdbc", version.ref = "exposed" } -exposed-java-time = { module = "org.jetbrains.exposed:exposed-java-time", version.ref = "exposed" } -sqlite-jdbc = { module = "org.xerial:sqlite-jdbc", version.ref = "sqlite-jdbc" } +gson = {module = "com.google.code.gson:gson", version.ref="gson"} [bundles] fabric = ["fabric-api", "fabric-kotlin", "fabric-loader"] konf = ["konf-core", "konf-toml"] -database = ["exposed-core", "exposed-dao", "exposed-java-time", "exposed-jdbc"] -jdbc = ["sqlite-jdbc"] [plugins] kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } diff --git a/src/main/kotlin/net/superricky/tpaplusplus/GlobalConst.kt b/src/main/kotlin/net/superricky/tpaplusplus/GlobalConst.kt index 5632d9b..34d96b4 100644 --- a/src/main/kotlin/net/superricky/tpaplusplus/GlobalConst.kt +++ b/src/main/kotlin/net/superricky/tpaplusplus/GlobalConst.kt @@ -8,6 +8,7 @@ object GlobalConst { const val CONFIG_FOLDER_PATH = MOD_ID const val CONFIG_FILE_NAME = "$MOD_ID.toml" const val CONFIG_FILE_PATH = "$CONFIG_FOLDER_PATH/$CONFIG_FILE_NAME" + const val PLAYER_DATA_FILE_NAME = "$MOD_ID.json" const val GITHUB_URL = "https://github.com/SuperRicky14/TpaPlusPlus" const val MODRINTH_URL = "https://modrinth.com/mod/tpa++" diff --git a/src/main/kotlin/net/superricky/tpaplusplus/TpaPlusPlus.kt b/src/main/kotlin/net/superricky/tpaplusplus/TpaPlusPlus.kt index 32efac2..212ed82 100644 --- a/src/main/kotlin/net/superricky/tpaplusplus/TpaPlusPlus.kt +++ b/src/main/kotlin/net/superricky/tpaplusplus/TpaPlusPlus.kt @@ -7,7 +7,6 @@ import dev.architectury.event.events.common.TickEvent import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.cancel -import kotlinx.coroutines.launch import net.fabricmc.api.ModInitializer import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents import net.fabricmc.loader.api.FabricLoader @@ -22,7 +21,8 @@ import net.superricky.tpaplusplus.async.AsyncCommandHelper import net.superricky.tpaplusplus.command.CommandRegister import net.superricky.tpaplusplus.config.AdvancedSpec import net.superricky.tpaplusplus.config.Config -import net.superricky.tpaplusplus.database.DatabaseManager +import net.superricky.tpaplusplus.database.DataService +import net.superricky.tpaplusplus.database.PlayerDataManager import java.nio.file.Files import kotlin.coroutines.CoroutineContext import net.superricky.tpaplusplus.event.PlayerEvent as PlayerEventListener @@ -31,6 +31,7 @@ object TpaPlusPlus : ModInitializer, CoroutineScope { lateinit var server: MinecraftServer override val coroutineContext: CoroutineContext = Dispatchers.IO val version: Version = FabricLoader.getInstance().getModContainer(MOD_ID).get().metadata.version + var dataService: DataService = PlayerDataManager override fun onInitialize() { logger.info("Initializing TPA++ ${version.friendlyString}") @@ -76,15 +77,8 @@ object TpaPlusPlus : ModInitializer, CoroutineScope { logger.info("Main logic initializing...") this.server = server - logger.info("Database initializing...") - DatabaseManager.setup() - DatabaseManager.ensureTables() - - logger.info("Make database cache...") - launch { - DatabaseManager.setupCache() - logger.info("The database cache is successfully constructed") - } + logger.info("Data service initializing...") + dataService.initDataService() logger.info("Add player event listener...") PlayerEvent.PLAYER_JOIN.register(PlayerEventListener::joinEvent) @@ -108,5 +102,6 @@ object TpaPlusPlus : ModInitializer, CoroutineScope { logger.info("Shutting down TPA++") AsyncCommandHelper.stopTickLoop() coroutineContext.cancel() + dataService.savePlayerData() } } diff --git a/src/main/kotlin/net/superricky/tpaplusplus/command/commands/BlockCommand.kt b/src/main/kotlin/net/superricky/tpaplusplus/command/commands/BlockCommand.kt index ff96cf8..ed1ab64 100644 --- a/src/main/kotlin/net/superricky/tpaplusplus/command/commands/BlockCommand.kt +++ b/src/main/kotlin/net/superricky/tpaplusplus/command/commands/BlockCommand.kt @@ -17,7 +17,6 @@ import net.superricky.tpaplusplus.config.command.CommandCooldownSpec import net.superricky.tpaplusplus.config.command.CommandDelaySpec import net.superricky.tpaplusplus.config.command.CommandDistanceSpec import net.superricky.tpaplusplus.config.command.CommandNameSpec -import net.superricky.tpaplusplus.database.DatabaseManager import net.superricky.tpaplusplus.utility.Context import net.superricky.tpaplusplus.utility.LiteralNode import net.superricky.tpaplusplus.utility.TextColorPallet @@ -54,7 +53,7 @@ object BlockCommand : AsyncCommand(), BuildableCommand { sender!! target!! TpaPlusPlus.launch { - if (DatabaseManager.insertBlockedPlayer(sender.uuid, target.uuid)) { + if (TpaPlusPlus.dataService.addBlockPlayer(sender.uuid, target.uuid)) { source.sendFeedback( { Text.translatable( diff --git a/src/main/kotlin/net/superricky/tpaplusplus/command/commands/ToggleCommand.kt b/src/main/kotlin/net/superricky/tpaplusplus/command/commands/ToggleCommand.kt index f28837e..9348030 100644 --- a/src/main/kotlin/net/superricky/tpaplusplus/command/commands/ToggleCommand.kt +++ b/src/main/kotlin/net/superricky/tpaplusplus/command/commands/ToggleCommand.kt @@ -13,7 +13,6 @@ import net.superricky.tpaplusplus.config.command.CommandCooldownSpec import net.superricky.tpaplusplus.config.command.CommandDelaySpec import net.superricky.tpaplusplus.config.command.CommandDistanceSpec import net.superricky.tpaplusplus.config.command.CommandNameSpec -import net.superricky.tpaplusplus.database.DatabaseManager import net.superricky.tpaplusplus.utility.Context import net.superricky.tpaplusplus.utility.LiteralNode import net.superricky.tpaplusplus.utility.toggleOff @@ -53,7 +52,7 @@ object ToggleCommand : AsyncCommand(), BuildableCommand { val sender = source.player sender ?: return CommandResult.SENDER_NOT_EXIST.status TpaPlusPlus.launch { - val blocked = DatabaseManager.playerSwitchBlock(sender.uuid) + val blocked = TpaPlusPlus.dataService.playerSwitchBlock(sender.uuid) if (blocked) { source.sendFeedback({ Text.translatable("command.toggle.success.on") }, false) } else { diff --git a/src/main/kotlin/net/superricky/tpaplusplus/command/commands/UnblockCommand.kt b/src/main/kotlin/net/superricky/tpaplusplus/command/commands/UnblockCommand.kt index 48ccf3e..3b1555c 100644 --- a/src/main/kotlin/net/superricky/tpaplusplus/command/commands/UnblockCommand.kt +++ b/src/main/kotlin/net/superricky/tpaplusplus/command/commands/UnblockCommand.kt @@ -17,7 +17,6 @@ import net.superricky.tpaplusplus.config.command.CommandCooldownSpec import net.superricky.tpaplusplus.config.command.CommandDelaySpec import net.superricky.tpaplusplus.config.command.CommandDistanceSpec import net.superricky.tpaplusplus.config.command.CommandNameSpec -import net.superricky.tpaplusplus.database.DatabaseManager import net.superricky.tpaplusplus.utility.Context import net.superricky.tpaplusplus.utility.LiteralNode import net.superricky.tpaplusplus.utility.TextColorPallet @@ -54,7 +53,7 @@ object UnblockCommand : AsyncCommand(), BuildableCommand { sender!! target!! TpaPlusPlus.launch { - if (DatabaseManager.deleteBlockedPlayer(sender.uuid, target.uuid)) { + if (TpaPlusPlus.dataService.removeBlockPlayer(sender.uuid, target.uuid)) { source.sendFeedback( { Text.translatable( diff --git a/src/main/kotlin/net/superricky/tpaplusplus/database/DataService.kt b/src/main/kotlin/net/superricky/tpaplusplus/database/DataService.kt new file mode 100644 index 0000000..b58e68d --- /dev/null +++ b/src/main/kotlin/net/superricky/tpaplusplus/database/DataService.kt @@ -0,0 +1,17 @@ +package net.superricky.tpaplusplus.database + +import net.minecraft.server.network.ServerPlayerEntity +import net.superricky.tpaplusplus.utility.LevelBoundVec3 +import java.util.* + +interface DataService { + fun initDataService() + fun getPlayerData(player: ServerPlayerEntity): PlayerData + fun addBlockPlayer(uuid: UUID, blockPlayer: UUID): Boolean + fun removeBlockPlayer(uuid: UUID, blockPlayer: UUID): Boolean + fun playerSwitchBlock(uuid: UUID): Boolean + fun playerSwitchBlock(uuid: UUID, toggle: Boolean): Boolean + fun insertPlayer(uuid: UUID) + fun insertDeath(uuid: UUID, pos: LevelBoundVec3) + fun savePlayerData() +} diff --git a/src/main/kotlin/net/superricky/tpaplusplus/database/DatabaseCacheService.kt b/src/main/kotlin/net/superricky/tpaplusplus/database/DatabaseCacheService.kt deleted file mode 100644 index af25a0f..0000000 --- a/src/main/kotlin/net/superricky/tpaplusplus/database/DatabaseCacheService.kt +++ /dev/null @@ -1,9 +0,0 @@ -package net.superricky.tpaplusplus.database - -import com.google.common.cache.Cache -import com.google.common.cache.CacheBuilder -import java.util.UUID - -object DatabaseCacheService { - val playerKeys: Cache = CacheBuilder.newBuilder().build() -} diff --git a/src/main/kotlin/net/superricky/tpaplusplus/database/DatabaseConst.kt b/src/main/kotlin/net/superricky/tpaplusplus/database/DatabaseConst.kt deleted file mode 100644 index 344d98b..0000000 --- a/src/main/kotlin/net/superricky/tpaplusplus/database/DatabaseConst.kt +++ /dev/null @@ -1,9 +0,0 @@ -package net.superricky.tpaplusplus.database - -object DatabaseConst { - const val MAX_PLAYER_NAME_LENGTH = 16 - const val MAX_WORLD_LENGTH = 64 - const val MAX_QUERY_RETRIES = 10 - const val MIN_RETRY_DELAY = 1000L - const val MAX_RETRY_DELAY = 300_000L -} diff --git a/src/main/kotlin/net/superricky/tpaplusplus/database/DatabaseManager.kt b/src/main/kotlin/net/superricky/tpaplusplus/database/DatabaseManager.kt deleted file mode 100644 index 80b5307..0000000 --- a/src/main/kotlin/net/superricky/tpaplusplus/database/DatabaseManager.kt +++ /dev/null @@ -1,164 +0,0 @@ -package net.superricky.tpaplusplus.database - -import kotlinx.coroutines.delay -import net.superricky.tpaplusplus.GlobalConst.logger -import net.superricky.tpaplusplus.TpaPlusPlus -import net.superricky.tpaplusplus.config.Config -import net.superricky.tpaplusplus.database.DatabaseConst.MAX_QUERY_RETRIES -import net.superricky.tpaplusplus.database.DatabaseConst.MAX_RETRY_DELAY -import net.superricky.tpaplusplus.database.DatabaseConst.MIN_RETRY_DELAY -import net.superricky.tpaplusplus.utility.LevelBoundVec3 -import org.jetbrains.exposed.sql.* -import org.jetbrains.exposed.sql.statements.StatementContext -import org.jetbrains.exposed.sql.statements.expandArgs -import org.jetbrains.exposed.sql.transactions.experimental.newSuspendedTransaction -import org.jetbrains.exposed.sql.transactions.transaction -import org.sqlite.SQLiteConfig -import org.sqlite.SQLiteDataSource -import java.util.* -import javax.sql.DataSource -import kotlin.io.path.pathString - -object DatabaseManager { - private lateinit var database: Database - - private val sqlLogger = object : SqlLogger { - override fun log(context: StatementContext, transaction: Transaction) { - logger.info("SQL: ${context.expandArgs(transaction)}") - } - } - val databaseType: String - get() = database.dialect.name - - private val cache = DatabaseCacheService - - fun setup() { - database = Database.connect(getDefaultDatasource()) - } - - private fun getDefaultDatasource(): DataSource { - val dbFilepath = Config.getDatabasePath().resolve("tpaplusplus.sqlite").pathString - return SQLiteDataSource( - SQLiteConfig().apply { - setJournalMode(SQLiteConfig.JournalMode.WAL) - } - ).apply { - url = "jdbc:sqlite:$dbFilepath" - } - } - - fun ensureTables() = transaction { - addLogger(sqlLogger) - SchemaUtils.createMissingTablesAndColumns( - Tables.Players, - Tables.BlockedPlayers, - Tables.LastDeaths, - withLogs = true - ) - logger.info("Tables created") - } - - private suspend fun execute(body: suspend Transaction.() -> T): T { - while (TpaPlusPlus.server.overworld?.savingDisabled != false) { - delay(timeMillis = 1000) - } - - return newSuspendedTransaction(db = database) { - maxAttempts = MAX_QUERY_RETRIES - minRetryDelay = MIN_RETRY_DELAY - maxRetryDelay = MAX_RETRY_DELAY - - addLogger(sqlLogger) - body(this) - } - } - - suspend fun setupCache() { - execute { - Tables.Player.all().forEach { - cache.playerKeys.put(it.playerId, it.id.value) - } - } - } - - suspend fun getPlayer(uuid: UUID): Tables.Player? = - execute { - return@execute Tables.Player.find { Tables.Players.playerId eq uuid }.firstOrNull() - } - - suspend fun insertPlayerDeath(uuid: UUID, pos: LevelBoundVec3) = - execute { - val player = getPlayer(uuid) - player?.let { - Tables.LastDeath.find { Tables.LastDeaths.playerId eq uuid }.forEach { it.delete() } - Tables.LastDeath.new { - this.playerId = player - this.deathWorld = pos.serverLevel.value.toString() - this.x = pos.x - this.y = pos.y - this.z = pos.z - this.backed = false - } - } - } - - suspend fun insertPlayer(uuid: UUID, name: String) = - execute { - val player = getPlayer(uuid) - if (player == null) { - Tables.Player.new { - this.playerId = uuid - this.playerName = name - } - } - } - - suspend fun playerSwitchBlock(uuid: UUID) = - execute { - val player = getPlayer(uuid) - if (player == null) { - throw NullPointerException("Player $uuid not found") - } - val blocked = player.blockAll - player.blockAll = !blocked - return@execute !blocked - } - - suspend fun playerSwitchBlock(uuid: UUID, blocked: Boolean) = - execute { - val player = getPlayer(uuid) - player?.let { - if (player.blockAll == blocked) return@let - player.blockAll = blocked - } - } - - suspend fun insertBlockedPlayer(senderUUID: UUID, targetUUID: UUID) = - execute { - val sender = Tables.Player.find { Tables.Players.playerId eq senderUUID }.firstOrNull() - val target = Tables.Player.find { Tables.Players.playerId eq targetUUID }.firstOrNull() - if (sender == null || target == null) { - return@execute false - } - Tables.BlockedPlayer.new { - playerId = sender - playerName = sender - blockedPlayerId = target - blockedPlayerName = target - } - return@execute true - } - - suspend fun deleteBlockedPlayer(senderUUID: UUID, targetUUID: UUID) = - execute { - val blocked = Tables.BlockedPlayer.find { - Tables.BlockedPlayers.playerId eq senderUUID and (Tables.BlockedPlayers.blockedPlayerId eq targetUUID) - } - .firstOrNull() - if (blocked == null) { - return@execute false - } - blocked.delete() - return@execute true - } -} diff --git a/src/main/kotlin/net/superricky/tpaplusplus/database/DeathPos.kt b/src/main/kotlin/net/superricky/tpaplusplus/database/DeathPos.kt new file mode 100644 index 0000000..b992093 --- /dev/null +++ b/src/main/kotlin/net/superricky/tpaplusplus/database/DeathPos.kt @@ -0,0 +1,9 @@ +package net.superricky.tpaplusplus.database + +data class DeathPos( + var x: Double = 0.0, + var y: Double = 0.0, + var z: Double = 0.0, + var world: String = "", + var backed: Boolean = true +) diff --git a/src/main/kotlin/net/superricky/tpaplusplus/database/PlayerData.kt b/src/main/kotlin/net/superricky/tpaplusplus/database/PlayerData.kt new file mode 100644 index 0000000..1d810d0 --- /dev/null +++ b/src/main/kotlin/net/superricky/tpaplusplus/database/PlayerData.kt @@ -0,0 +1,13 @@ +package net.superricky.tpaplusplus.database + +import com.google.gson.annotations.SerializedName +import java.util.* + +class PlayerData( + @SerializedName("block_players") + val blockPlayers: MutableSet = Collections.synchronizedSet(HashSet()), + @SerializedName("last_death_pos") + val lastDeathPos: DeathPos = DeathPos(), + @SerializedName("toggle") + var toggle: Boolean = false +) diff --git a/src/main/kotlin/net/superricky/tpaplusplus/database/PlayerDataManager.kt b/src/main/kotlin/net/superricky/tpaplusplus/database/PlayerDataManager.kt new file mode 100644 index 0000000..fb0e1d0 --- /dev/null +++ b/src/main/kotlin/net/superricky/tpaplusplus/database/PlayerDataManager.kt @@ -0,0 +1,125 @@ +package net.superricky.tpaplusplus.database + +import com.google.gson.GsonBuilder +import com.google.gson.reflect.TypeToken +import kotlinx.coroutines.delay +import kotlinx.coroutines.isActive +import kotlinx.coroutines.launch +import net.minecraft.server.network.ServerPlayerEntity +import net.superricky.tpaplusplus.GlobalConst.ONE_SECOND +import net.superricky.tpaplusplus.GlobalConst.PLAYER_DATA_FILE_NAME +import net.superricky.tpaplusplus.GlobalConst.logger +import net.superricky.tpaplusplus.TpaPlusPlus +import net.superricky.tpaplusplus.config.AdvancedSpec +import net.superricky.tpaplusplus.config.Config +import net.superricky.tpaplusplus.utility.LevelBoundVec3 +import java.io.File +import java.io.FileReader +import java.io.FileWriter +import java.io.IOException +import java.nio.file.Files +import java.util.* + +object PlayerDataManager : DataService { + private var playerDataMap: MutableMap = Collections.synchronizedMap(HashMap()) + private val gson = GsonBuilder().setPrettyPrinting().create() + private val dataSavePath: File = Config.getDatabasePath().resolve(PLAYER_DATA_FILE_NAME).toFile() + + init { + if (!dataSavePath.exists()) { + logger.info("Data file not exist, creating") + Files.createFile(dataSavePath.toPath()) + FileWriter(dataSavePath).use { + it.write("{}") + } + } + } + + override fun initDataService() { + loadPlayerData() + TpaPlusPlus.launch { + while (isActive) { + savePlayerData() + delay(Config.getConfig()[AdvancedSpec.autoSaveInterval] * ONE_SECOND) + } + } + } + + override fun getPlayerData(player: ServerPlayerEntity): PlayerData { + require(playerDataMap.containsKey(player.uuid)) { "PlayerData does not exist." } + return playerDataMap[player.uuid]!! + } + + override fun addBlockPlayer(uuid: UUID, blockPlayer: UUID): Boolean { + if (playerDataMap.containsKey(uuid) && playerDataMap[uuid] != null) { + playerDataMap[uuid]!!.blockPlayers.add(blockPlayer) + return true + } + return false + } + + override fun removeBlockPlayer(uuid: UUID, blockPlayer: UUID): Boolean { + if (playerDataMap.containsKey(uuid) && playerDataMap[uuid] != null) { + playerDataMap[uuid]!!.blockPlayers.remove(blockPlayer) + return true + } + return false + } + + override fun playerSwitchBlock(uuid: UUID): Boolean { + if (playerDataMap.containsKey(uuid) && playerDataMap[uuid] != null) { + playerDataMap[uuid]!!.toggle = !playerDataMap[uuid]!!.toggle + return playerDataMap[uuid]!!.toggle + } + return false + } + + override fun playerSwitchBlock(uuid: UUID, toggle: Boolean): Boolean { + if (playerDataMap.containsKey(uuid) && playerDataMap[uuid] != null) { + playerDataMap[uuid]!!.toggle = toggle + return true + } + return false + } + + override fun insertPlayer(uuid: UUID) { + if (!playerDataMap.containsKey(uuid) || playerDataMap[uuid] == null) { + playerDataMap[uuid] = PlayerData() + } + } + + override fun insertDeath(uuid: UUID, pos: LevelBoundVec3) { + val playerData = playerDataMap[uuid]!! + playerData.lastDeathPos.x = pos.x + playerData.lastDeathPos.y = pos.y + playerData.lastDeathPos.z = pos.z + playerData.lastDeathPos.world = pos.serverLevel.value.toString() + playerData.lastDeathPos.backed = false + } + + override fun savePlayerData() { + try { + FileWriter(dataSavePath).use { + gson.toJson(playerDataMap, it) + } + } catch (e: IOException) { + logger.error("An IOException occurred when trying to save playerData.") + logger.error(e.message) + } + } + + private fun loadPlayerData() { + try { + FileReader(dataSavePath).use { + playerDataMap = gson.fromJson>( + it, + object : TypeToken>() {}.type + ).toMutableMap() + logger.info("Successfully loaded player data!") + } + } catch (e: IOException) { + logger.error("An IOException occurred when trying to load playerData.") + logger.error(e.message) + } + } +} diff --git a/src/main/kotlin/net/superricky/tpaplusplus/database/Tables.kt b/src/main/kotlin/net/superricky/tpaplusplus/database/Tables.kt deleted file mode 100644 index 8256c9b..0000000 --- a/src/main/kotlin/net/superricky/tpaplusplus/database/Tables.kt +++ /dev/null @@ -1,68 +0,0 @@ -package net.superricky.tpaplusplus.database - -import net.superricky.tpaplusplus.GlobalConst -import org.jetbrains.exposed.dao.IntEntity -import org.jetbrains.exposed.dao.IntEntityClass -import org.jetbrains.exposed.dao.id.EntityID -import org.jetbrains.exposed.dao.id.IntIdTable - -@Suppress("StringLiteralDuplication") -object Tables { - object Players : IntIdTable("${GlobalConst.MOD_ID.lowercase()}_players") { - val playerId = uuid("player_id").uniqueIndex("player_id") - val playerName = char("player_name", DatabaseConst.MAX_PLAYER_NAME_LENGTH) - val blockAll = bool("block_all").default(false) - } - - class Player(id: EntityID) : IntEntity(id) { - var playerId by Players.playerId - var playerName by Players.playerName - var blockAll by Players.blockAll - - companion object : IntEntityClass(Players) - } - - object BlockedPlayers : IntIdTable("${GlobalConst.MOD_ID.lowercase()}_blocked_players") { - val playerId = reference("player_id", Players.playerId) - val playerName = reference("player_name", Players.playerName) - val blockedPlayerId = reference("blocked_player_id", Players.playerId) - val blockedPlayerName = reference("blocked_player_name", Players.playerName) - - init { - index("uuid_index_blocked_players", false, playerId, blockedPlayerId) - } - } - - class BlockedPlayer(id: EntityID) : IntEntity(id) { - var playerId by Player referencedOn BlockedPlayers.playerId - var playerName by Player referencedOn BlockedPlayers.playerName - var blockedPlayerId by Player referencedOn BlockedPlayers.blockedPlayerId - var blockedPlayerName by Player referencedOn BlockedPlayers.blockedPlayerName - - companion object : IntEntityClass(BlockedPlayers) - } - - object LastDeaths : IntIdTable("${GlobalConst.MOD_ID.lowercase()}_last_deaths") { - val playerId = reference("player_id", Players.playerId) - val deathWorld = char("death_world", DatabaseConst.MAX_WORLD_LENGTH) - val x = double("x") - val y = double("y") - val z = double("z") - val backed = bool("backed").default(false) - - init { - index("uuid_index_last_deaths", false, playerId) - } - } - - class LastDeath(id: EntityID) : IntEntity(id) { - var playerId by Player referencedOn LastDeaths.playerId - var deathWorld by LastDeaths.deathWorld - var x by LastDeaths.x - var y by LastDeaths.y - var z by LastDeaths.z - var backed by LastDeaths.backed - - companion object : IntEntityClass(LastDeaths) - } -} diff --git a/src/main/kotlin/net/superricky/tpaplusplus/event/PlayerEvent.kt b/src/main/kotlin/net/superricky/tpaplusplus/event/PlayerEvent.kt index a5e9bb9..a46295f 100644 --- a/src/main/kotlin/net/superricky/tpaplusplus/event/PlayerEvent.kt +++ b/src/main/kotlin/net/superricky/tpaplusplus/event/PlayerEvent.kt @@ -6,15 +6,12 @@ import net.minecraft.entity.LivingEntity import net.minecraft.entity.damage.DamageSource import net.minecraft.server.network.ServerPlayerEntity import net.superricky.tpaplusplus.TpaPlusPlus -import net.superricky.tpaplusplus.database.DatabaseManager import net.superricky.tpaplusplus.utility.LevelBoundVec3 import net.superricky.tpaplusplus.utility.getDimension object PlayerEvent { fun joinEvent(player: ServerPlayerEntity) { - TpaPlusPlus.launch { - player.name.literalString?.let { DatabaseManager.insertPlayer(player.uuid, it) } - } + TpaPlusPlus.dataService.insertPlayer(player.uuid) } fun deathEvent(deathEntity: LivingEntity, ignored: DamageSource): EventResult { @@ -23,7 +20,7 @@ object PlayerEvent { } val deathPos = LevelBoundVec3(deathEntity.getDimension(), deathEntity.pos) TpaPlusPlus.launch { - DatabaseManager.insertPlayerDeath(deathEntity.uuid, deathPos) + TpaPlusPlus.dataService.insertDeath(deathEntity.uuid, deathPos) } return EventResult.pass() } diff --git a/src/main/kotlin/net/superricky/tpaplusplus/utility/Extensions.kt b/src/main/kotlin/net/superricky/tpaplusplus/utility/Extensions.kt index f8cb05f..3072946 100644 --- a/src/main/kotlin/net/superricky/tpaplusplus/utility/Extensions.kt +++ b/src/main/kotlin/net/superricky/tpaplusplus/utility/Extensions.kt @@ -10,7 +10,6 @@ import net.minecraft.text.Text import net.minecraft.util.Identifier import net.superricky.tpaplusplus.TpaPlusPlus import net.superricky.tpaplusplus.config.Config -import net.superricky.tpaplusplus.database.DatabaseManager fun String.literal(): MutableText = Text.literal(this) fun String.translate(): MutableText = Text.translatable(this) @@ -18,11 +17,11 @@ fun String.getWorld(): ServerDimension = RegistryKey.of(RegistryKeys.WORLD, Identifier.of(this)) fun PlayerEntity.toggleOn() = TpaPlusPlus.launch { - DatabaseManager.playerSwitchBlock(uuid, true) + TpaPlusPlus.dataService.playerSwitchBlock(uuid, true) } fun PlayerEntity.toggleOff() = TpaPlusPlus.launch { - DatabaseManager.playerSwitchBlock(uuid, false) + TpaPlusPlus.dataService.playerSwitchBlock(uuid, false) } fun PlayerEntity.getColoredName(color: Style): MutableText? = this.name.literalString?.literal()?.setStyle(color) diff --git a/src/main/resources/tpaplusplus.toml b/src/main/resources/tpaplusplus.toml index 7cf743e..562d24e 100644 --- a/src/main/resources/tpaplusplus.toml +++ b/src/main/resources/tpaplusplus.toml @@ -1,5 +1,6 @@ # This is tpaplusplus config file [common] +# Modifying these options can take effect without a restart of the game. # Whether to send a message to the person being blocked / unblocked, when the sender blocks them. # Default: true showBlockedMessage = true @@ -20,6 +21,7 @@ waitTimeBeforeTp = 5.0 [common.color] # Colors in hex format +# Modifying these options may require a restart of the game. primary = "#009688" primaryVariant = "#52c7b8" secondary = "#1e88e5"