From d53943c454ab704bfabf6e3263b98710e6835d15 Mon Sep 17 00:00:00 2001 From: Hexagon Date: Sun, 30 Jul 2023 14:07:40 -0300 Subject: [PATCH] persistence: transaction support --- .../work/fking/pangya/game/Bootstrap.kt | 15 ++--- .../handler/EquipmentUpdatePacketHandler.kt | 10 +-- .../persistence/AchievementsRepository.kt | 19 +++--- .../game/persistence/CaddieRepository.kt | 19 +++--- .../game/persistence/CharacterRepository.kt | 18 +++--- .../game/persistence/EquipmentRepository.kt | 19 +++--- .../game/persistence/InventoryRepository.kt | 19 +++--- .../game/persistence/PersistenceContext.kt | 26 +++++++- .../game/persistence/PlayerRepository.kt | 22 +++++-- .../game/persistence/StatisticsRepository.kt | 19 +++--- .../fking/pangya/game/task/HandoverTask.kt | 26 ++++---- .../pangya/game/task/NewPlayerSetupTask.kt | 63 +++++++++++-------- .../pangya/game/task/UnlockCaddieTask.kt | 4 +- .../pangya/game/task/UnlockCharacterTask.kt | 5 +- .../game/task/UpdatePlayerCaddieTask.kt | 7 +-- .../task/UpdatePlayerCharacterPartsTask.kt | 6 +- .../game/task/UpdatePlayerCharacterTask.kt | 6 +- .../game/task/UpdatePlayerCometClubSetTask.kt | 6 +- .../task/UpdatePlayerEquippedItemsTask.kt | 6 +- 19 files changed, 179 insertions(+), 136 deletions(-) diff --git a/game-server/src/main/kotlin/work/fking/pangya/game/Bootstrap.kt b/game-server/src/main/kotlin/work/fking/pangya/game/Bootstrap.kt index cdd6361..e06f634 100644 --- a/game-server/src/main/kotlin/work/fking/pangya/game/Bootstrap.kt +++ b/game-server/src/main/kotlin/work/fking/pangya/game/Bootstrap.kt @@ -57,13 +57,14 @@ object Bootstrap { private fun setupPersistenceContext(jooq: DSLContext): PersistenceContext { return PersistenceContext( - playerRepository = JooqPlayerRepository(jooq), - characterRepository = JooqCharacterRepository(jooq), - caddieRepository = JooqCaddieRepository(jooq), - inventoryRepository = JooqInventoryRepository(jooq), - equipmentRepository = JooqEquipmentRepository(jooq), - statisticsRepository = JooqStatisticsRepository(jooq), - achievementsRepository = JooqAchievementsRepository(jooq) + jooq = jooq, + playerRepository = JooqPlayerRepository(), + characterRepository = JooqCharacterRepository(), + caddieRepository = JooqCaddieRepository(), + inventoryRepository = JooqInventoryRepository(), + equipmentRepository = JooqEquipmentRepository(), + statisticsRepository = JooqStatisticsRepository(), + achievementsRepository = JooqAchievementsRepository() ) } diff --git a/game-server/src/main/kotlin/work/fking/pangya/game/packet/handler/EquipmentUpdatePacketHandler.kt b/game-server/src/main/kotlin/work/fking/pangya/game/packet/handler/EquipmentUpdatePacketHandler.kt index 43946b0..3c941b9 100644 --- a/game-server/src/main/kotlin/work/fking/pangya/game/packet/handler/EquipmentUpdatePacketHandler.kt +++ b/game-server/src/main/kotlin/work/fking/pangya/game/packet/handler/EquipmentUpdatePacketHandler.kt @@ -44,7 +44,7 @@ class EquipmentUpdatePacketHandler : ClientPacketHandler { val character = buffer.readCharacter() server.runTask( UpdatePlayerCharacterPartsTask( - server = server, + persistenceCtx = server.persistenceCtx, player = player, character = character ) @@ -60,7 +60,7 @@ class EquipmentUpdatePacketHandler : ClientPacketHandler { } server.runTask( UpdatePlayerCaddieTask( - server = server, + persistenceCtx = server.persistenceCtx, player = player, caddie = caddie ) @@ -74,7 +74,7 @@ class EquipmentUpdatePacketHandler : ClientPacketHandler { val clubSet = player.inventory.findByUid(clubSetUid) ?: throw IllegalStateException("Player ${player.nickname} tried to equip a clubSet it does not own ($clubSetUid)") server.runTask( UpdatePlayerCometClubSetTask( - server = server, + persistenceCtx = server.persistenceCtx, player = player, comet = comet, clubSet = clubSet @@ -90,7 +90,7 @@ class EquipmentUpdatePacketHandler : ClientPacketHandler { val character = player.characterRoster.findByUid(characterUid) ?: throw IllegalStateException("Player ${player.nickname} tried to equip a character it does not own") server.runTask( UpdatePlayerCharacterTask( - server = server, + persistenceCtx = server.persistenceCtx, player = player, character = character ) @@ -101,7 +101,7 @@ class EquipmentUpdatePacketHandler : ClientPacketHandler { val itemIffIds = IntArray(EQUIPPED_ITEMS_SIZE) { buffer.readIntLE() } server.runTask( UpdatePlayerEquippedItemsTask( - server = server, + persistenceCtx = server.persistenceCtx, player = player, itemIffIds = itemIffIds ) diff --git a/game-server/src/main/kotlin/work/fking/pangya/game/persistence/AchievementsRepository.kt b/game-server/src/main/kotlin/work/fking/pangya/game/persistence/AchievementsRepository.kt index 87513c0..91ea377 100644 --- a/game-server/src/main/kotlin/work/fking/pangya/game/persistence/AchievementsRepository.kt +++ b/game-server/src/main/kotlin/work/fking/pangya/game/persistence/AchievementsRepository.kt @@ -1,6 +1,5 @@ package work.fking.pangya.game.persistence -import org.jooq.DSLContext import org.jooq.impl.DSL.value import work.fking.pangya.game.persistence.jooq.tables.references.ACHIEVEMENT import work.fking.pangya.game.persistence.jooq.tables.references.ACHIEVEMENT_MILESTONE @@ -14,18 +13,18 @@ import java.util.stream.Collectors.groupingBy import java.util.stream.Collectors.mapping interface AchievementsRepository { - fun load(playerUid: Int): PlayerAchievements - fun createAchievements(playerUid: Int) + fun load(txCtx: TransactionalContext, playerUid: Int): PlayerAchievements + fun createAchievements(txCtx: TransactionalContext, playerUid: Int) } class InMemoryAchievementsRepository : AchievementsRepository { - override fun load(playerUid: Int): PlayerAchievements = PlayerAchievements(emptyList()) - override fun createAchievements(playerUid: Int) {} + override fun load(txCtx: TransactionalContext, playerUid: Int): PlayerAchievements = PlayerAchievements(emptyList()) + override fun createAchievements(txCtx: TransactionalContext, playerUid: Int) {} } -class JooqAchievementsRepository(private val jooq: DSLContext) : AchievementsRepository { - override fun load(playerUid: Int): PlayerAchievements { - val achievements = jooq.select( +class JooqAchievementsRepository : AchievementsRepository { + override fun load(txCtx: TransactionalContext, playerUid: Int): PlayerAchievements { + val achievements = txCtx.jooq().select( PLAYER_ACHIEVEMENT.UID, PLAYER_ACHIEVEMENT.IFF_ID, PLAYER_ACHIEVEMENT_MILESTONE.UID, @@ -60,8 +59,8 @@ class JooqAchievementsRepository(private val jooq: DSLContext) : AchievementsRep }) } - override fun createAchievements(playerUid: Int) { - jooq.transaction { tx -> + override fun createAchievements(txCtx: TransactionalContext, playerUid: Int) { + txCtx.jooq().transaction { tx -> tx.dsl().insertInto( PLAYER_ACHIEVEMENT, PLAYER_ACHIEVEMENT.ACCOUNT_UID, diff --git a/game-server/src/main/kotlin/work/fking/pangya/game/persistence/CaddieRepository.kt b/game-server/src/main/kotlin/work/fking/pangya/game/persistence/CaddieRepository.kt index 532979f..3c3781e 100644 --- a/game-server/src/main/kotlin/work/fking/pangya/game/persistence/CaddieRepository.kt +++ b/game-server/src/main/kotlin/work/fking/pangya/game/persistence/CaddieRepository.kt @@ -1,6 +1,5 @@ package work.fking.pangya.game.persistence -import org.jooq.DSLContext import org.jooq.RecordMapper import work.fking.pangya.game.persistence.jooq.keys.PLAYER_CADDIE_PKEY import work.fking.pangya.game.persistence.jooq.tables.records.PlayerCaddieRecord @@ -10,23 +9,23 @@ import work.fking.pangya.game.player.CaddieRoster import java.util.concurrent.atomic.AtomicInteger interface CaddieRepository { - fun loadRoster(playerUid: Int): CaddieRoster - fun save(playerUid: Int, caddie: Caddie): Caddie + fun loadRoster(txCtx: TransactionalContext, playerUid: Int): CaddieRoster + fun save(txCtx: TransactionalContext, playerUid: Int, caddie: Caddie): Caddie } class InMemoryCaddieRepository : CaddieRepository { private val uidSequence = AtomicInteger(1) private val playerCaddies = mutableMapOf>() - override fun loadRoster(playerUid: Int): CaddieRoster = CaddieRoster(playerCaddies[playerUid] ?: mutableListOf()) + override fun loadRoster(txCtx: TransactionalContext, playerUid: Int): CaddieRoster = CaddieRoster(playerCaddies[playerUid] ?: mutableListOf()) - override fun save(playerUid: Int, caddie: Caddie): Caddie { + override fun save(txCtx: TransactionalContext, playerUid: Int, caddie: Caddie): Caddie { val characters = playerCaddies[playerUid] ?: mutableListOf() return characters.find { it.uid == caddie.uid } ?: caddie.copy(uid = uidSequence.getAndIncrement()) } } -class JooqCaddieRepository(private val jooq: DSLContext) : CaddieRepository { +class JooqCaddieRepository : CaddieRepository { private val caddieMapper = RecordMapper { Caddie( uid = it.uid!!, @@ -36,15 +35,15 @@ class JooqCaddieRepository(private val jooq: DSLContext) : CaddieRepository { ) } - override fun loadRoster(playerUid: Int): CaddieRoster { - val caddies = jooq.selectFrom(PLAYER_CADDIE) + override fun loadRoster(txCtx: TransactionalContext, playerUid: Int): CaddieRoster { + val caddies = txCtx.jooq().selectFrom(PLAYER_CADDIE) .where(PLAYER_CADDIE.ACCOUNT_UID.eq(playerUid)) .fetch(caddieMapper) return CaddieRoster(caddies) } - override fun save(playerUid: Int, caddie: Caddie): Caddie { - val insert = jooq.insertInto(PLAYER_CADDIE) + override fun save(txCtx: TransactionalContext, playerUid: Int, caddie: Caddie): Caddie { + val insert = txCtx.jooq().insertInto(PLAYER_CADDIE) if (caddie.uid != -1) insert.set(PLAYER_CADDIE.UID, caddie.uid) diff --git a/game-server/src/main/kotlin/work/fking/pangya/game/persistence/CharacterRepository.kt b/game-server/src/main/kotlin/work/fking/pangya/game/persistence/CharacterRepository.kt index 8c4874a..e38c1b7 100644 --- a/game-server/src/main/kotlin/work/fking/pangya/game/persistence/CharacterRepository.kt +++ b/game-server/src/main/kotlin/work/fking/pangya/game/persistence/CharacterRepository.kt @@ -11,23 +11,23 @@ import java.util.concurrent.atomic.AtomicInteger interface CharacterRepository { - fun loadRoster(playerUid: Int): CharacterRoster - fun save(playerUid: Int, character: Character): Character + fun loadRoster(txCtx: TransactionalContext, playerUid: Int): CharacterRoster + fun save(txCtx: TransactionalContext, playerUid: Int, character: Character): Character } class InMemoryCharacterRepository : CharacterRepository { private val uidSequence = AtomicInteger(1) private val playerCharacters = mutableMapOf>() - override fun loadRoster(playerUid: Int): CharacterRoster = CharacterRoster(playerCharacters[playerUid] ?: mutableListOf()) + override fun loadRoster(txCtx: TransactionalContext, playerUid: Int): CharacterRoster = CharacterRoster(playerCharacters[playerUid] ?: mutableListOf()) - override fun save(playerUid: Int, character: Character): Character { + override fun save(txCtx: TransactionalContext, playerUid: Int, character: Character): Character { val characters = playerCharacters[playerUid] ?: mutableListOf() return characters.find { it.uid == character.uid } ?: character.copy(uid = uidSequence.getAndIncrement()) } } -class JooqCharacterRepository(private val jooq: DSLContext) : CharacterRepository { +class JooqCharacterRepository : CharacterRepository { private val characterMapper = RecordMapper { Character( uid = it.uid!!, @@ -43,15 +43,15 @@ class JooqCharacterRepository(private val jooq: DSLContext) : CharacterRepositor ) } - override fun loadRoster(playerUid: Int): CharacterRoster { - val characters = jooq.selectFrom(PLAYER_CHARACTER) + override fun loadRoster(txCtx: TransactionalContext, playerUid: Int): CharacterRoster { + val characters = txCtx.jooq().selectFrom(PLAYER_CHARACTER) .where(PLAYER_CHARACTER.ACCOUNT_UID.eq(playerUid)) .fetch(characterMapper) return CharacterRoster(characters) } - override fun save(playerUid: Int, character: Character): Character { - val insert = jooq.insertInto(PLAYER_CHARACTER) + override fun save(txCtx: TransactionalContext, playerUid: Int, character: Character): Character { + val insert = txCtx.jooq().insertInto(PLAYER_CHARACTER) if (character.uid != -1) insert.set(PLAYER_CHARACTER.UID, character.uid) diff --git a/game-server/src/main/kotlin/work/fking/pangya/game/persistence/EquipmentRepository.kt b/game-server/src/main/kotlin/work/fking/pangya/game/persistence/EquipmentRepository.kt index 17a2fc6..077951b 100644 --- a/game-server/src/main/kotlin/work/fking/pangya/game/persistence/EquipmentRepository.kt +++ b/game-server/src/main/kotlin/work/fking/pangya/game/persistence/EquipmentRepository.kt @@ -1,6 +1,5 @@ package work.fking.pangya.game.persistence -import org.jooq.DSLContext import org.jooq.RecordMapper import work.fking.pangya.game.persistence.jooq.keys.PLAYER_EQUIPMENT_PKEY import work.fking.pangya.game.persistence.jooq.tables.records.PlayerEquipmentRecord @@ -8,24 +7,24 @@ import work.fking.pangya.game.persistence.jooq.tables.references.PLAYER_EQUIPMEN import work.fking.pangya.game.player.Equipment interface EquipmentRepository { - fun load(playerUid: Int): Equipment - fun save(playerUid: Int, equipment: Equipment) + fun load(txCtx: TransactionalContext, playerUid: Int): Equipment + fun save(txCtx: TransactionalContext, playerUid: Int, equipment: Equipment) } class InMemoryEquipmentRepository : EquipmentRepository { private val equipments = mutableMapOf() - override fun load(playerUid: Int): Equipment = Equipment( + override fun load(txCtx: TransactionalContext, playerUid: Int): Equipment = Equipment( clubSetUid = 200, characterUid = 100, cometIffId = 0x14000000 ) - override fun save(playerUid: Int, equipment: Equipment) { + override fun save(txCtx: TransactionalContext, playerUid: Int, equipment: Equipment) { } } -class JooqEquipmentRepository(private val jooq: DSLContext) : EquipmentRepository { +class JooqEquipmentRepository : EquipmentRepository { private val equipmentMapper = RecordMapper { Equipment( itemIffIds = it.itemIffIds, @@ -36,14 +35,14 @@ class JooqEquipmentRepository(private val jooq: DSLContext) : EquipmentRepositor ) } - override fun load(playerUid: Int): Equipment { - return jooq.selectFrom(PLAYER_EQUIPMENT) + override fun load(txCtx: TransactionalContext, playerUid: Int): Equipment { + return txCtx.jooq().selectFrom(PLAYER_EQUIPMENT) .where(PLAYER_EQUIPMENT.ACCOUNT_UID.eq(playerUid)) .fetchOne(equipmentMapper) ?: throw IllegalStateException("could not load equipment for playerId=$playerUid") } - override fun save(playerUid: Int, equipment: Equipment) { - jooq.insertInto(PLAYER_EQUIPMENT) + override fun save(txCtx: TransactionalContext, playerUid: Int, equipment: Equipment) { + txCtx.jooq().insertInto(PLAYER_EQUIPMENT) .set(PLAYER_EQUIPMENT.ACCOUNT_UID, playerUid) .set(PLAYER_EQUIPMENT.ITEM_IFF_IDS, equipment.itemIffIds) .set(PLAYER_EQUIPMENT.CHARACTER_UID, equipment.characterUid) diff --git a/game-server/src/main/kotlin/work/fking/pangya/game/persistence/InventoryRepository.kt b/game-server/src/main/kotlin/work/fking/pangya/game/persistence/InventoryRepository.kt index b2474a5..e1021fa 100644 --- a/game-server/src/main/kotlin/work/fking/pangya/game/persistence/InventoryRepository.kt +++ b/game-server/src/main/kotlin/work/fking/pangya/game/persistence/InventoryRepository.kt @@ -1,6 +1,5 @@ package work.fking.pangya.game.persistence -import org.jooq.DSLContext import org.jooq.RecordMapper import work.fking.pangya.game.persistence.jooq.keys.PLAYER_INVENTORY_ITEM_PKEY import work.fking.pangya.game.persistence.jooq.tables.records.PlayerInventoryItemRecord @@ -10,8 +9,8 @@ import work.fking.pangya.game.player.Item import java.util.concurrent.atomic.AtomicInteger interface InventoryRepository { - fun load(playerUid: Int): Inventory - fun saveItem(playerUid: Int, item: Item): Item + fun load(txCtx: TransactionalContext, playerUid: Int): Inventory + fun saveItem(txCtx: TransactionalContext, playerUid: Int, item: Item): Item } class InMemoryInventoryRepository : InventoryRepository { @@ -25,18 +24,18 @@ class InMemoryInventoryRepository : InventoryRepository { ) } - override fun load(playerUid: Int): Inventory { + override fun load(txCtx: TransactionalContext, playerUid: Int): Inventory { return Inventory(findInventory(playerUid)) } - override fun saveItem(playerUid: Int, item: Item): Item { + override fun saveItem(txCtx: TransactionalContext, playerUid: Int, item: Item): Item { val persistedItem = item.copy(uid = uidSequence.getAndIncrement()) findInventory(playerUid).add(persistedItem) return persistedItem } } -class JooqInventoryRepository(private val jooq: DSLContext) : InventoryRepository { +class JooqInventoryRepository : InventoryRepository { private val itemMapper = RecordMapper { Item( uid = it.uid!!, @@ -46,15 +45,15 @@ class JooqInventoryRepository(private val jooq: DSLContext) : InventoryRepositor ) } - override fun load(playerUid: Int): Inventory { - val items = jooq.selectFrom(PLAYER_INVENTORY_ITEM) + override fun load(txCtx: TransactionalContext, playerUid: Int): Inventory { + val items = txCtx.jooq().selectFrom(PLAYER_INVENTORY_ITEM) .where(PLAYER_INVENTORY_ITEM.ACCOUNT_UID.eq(playerUid)) .fetch(itemMapper) return Inventory(items) } - override fun saveItem(playerUid: Int, item: Item): Item { - val insert = jooq.insertInto(PLAYER_INVENTORY_ITEM) + override fun saveItem(txCtx: TransactionalContext, playerUid: Int, item: Item): Item { + val insert = txCtx.jooq().insertInto(PLAYER_INVENTORY_ITEM) if (item.uid != -1) insert.set(PLAYER_INVENTORY_ITEM.UID, item.uid) diff --git a/game-server/src/main/kotlin/work/fking/pangya/game/persistence/PersistenceContext.kt b/game-server/src/main/kotlin/work/fking/pangya/game/persistence/PersistenceContext.kt index 6776161..4f1c196 100644 --- a/game-server/src/main/kotlin/work/fking/pangya/game/persistence/PersistenceContext.kt +++ b/game-server/src/main/kotlin/work/fking/pangya/game/persistence/PersistenceContext.kt @@ -1,6 +1,9 @@ package work.fking.pangya.game.persistence +import org.jooq.DSLContext + data class PersistenceContext( + val jooq: DSLContext?, val playerRepository: PlayerRepository = InMemoryPlayerRepository(), val characterRepository: CharacterRepository = InMemoryCharacterRepository(), val caddieRepository: CaddieRepository = InMemoryCaddieRepository(), @@ -8,4 +11,25 @@ data class PersistenceContext( val equipmentRepository: EquipmentRepository = InMemoryEquipmentRepository(), val statisticsRepository: StatisticsRepository = InMemoryStatisticsRepository(), val achievementsRepository: AchievementsRepository = InMemoryAchievementsRepository() -) \ No newline at end of file +) { + + /** + * Returns a transactional context without an active transaction. + */ + fun noTxContext() = TransactionalContext(jooq) + + /** + * Returns a transactional context with an active transaction. + */ + fun transactional(transactional: (txContext: TransactionalContext) -> Unit) { + if (jooq != null) { + jooq.transaction { tx -> transactional(TransactionalContext(tx.dsl())) } + } else { + transactional(TransactionalContext()) + } + } +} + +data class TransactionalContext(private val jooq: DSLContext? = null) { + fun jooq(): DSLContext = jooq ?: throw IllegalStateException("no jooq context available") +} \ No newline at end of file diff --git a/game-server/src/main/kotlin/work/fking/pangya/game/persistence/PlayerRepository.kt b/game-server/src/main/kotlin/work/fking/pangya/game/persistence/PlayerRepository.kt index e883b13..24f625f 100644 --- a/game-server/src/main/kotlin/work/fking/pangya/game/persistence/PlayerRepository.kt +++ b/game-server/src/main/kotlin/work/fking/pangya/game/persistence/PlayerRepository.kt @@ -1,23 +1,25 @@ package work.fking.pangya.game.persistence -import org.jooq.DSLContext import work.fking.pangya.game.persistence.jooq.tables.references.ACCOUNT import work.fking.pangya.game.player.PlayerWallet interface PlayerRepository { - fun loadWallet(playerUid: Int): PlayerWallet + fun loadWallet(txCtx: TransactionalContext, playerUid: Int): PlayerWallet + fun updateNickname(txCtx: TransactionalContext, playerUid: Int, nickname: String) } class InMemoryPlayerRepository : PlayerRepository { private val wallets = mutableMapOf() - override fun loadWallet(playerUid: Int): PlayerWallet = wallets[playerUid] ?: PlayerWallet() + override fun loadWallet(txCtx: TransactionalContext, playerUid: Int): PlayerWallet = wallets[playerUid] ?: PlayerWallet() + override fun updateNickname(txCtx: TransactionalContext, playerUid: Int, nickname: String) { + } } -class JooqPlayerRepository(private val jooq: DSLContext) : PlayerRepository { +class JooqPlayerRepository : PlayerRepository { - override fun loadWallet(playerUid: Int): PlayerWallet { - val wallet = jooq.select(ACCOUNT.PANG_BALANCE, ACCOUNT.COOKIE_BALANCE) + override fun loadWallet(txCtx: TransactionalContext, playerUid: Int): PlayerWallet { + val wallet = txCtx.jooq().select(ACCOUNT.PANG_BALANCE, ACCOUNT.COOKIE_BALANCE) .from(ACCOUNT) .where(ACCOUNT.UID.eq(playerUid)) .fetchOne { @@ -28,4 +30,12 @@ class JooqPlayerRepository(private val jooq: DSLContext) : PlayerRepository { } return wallet ?: throw IllegalStateException("could not load player wallet for playerUid=$playerUid") } + + override fun updateNickname(txCtx: TransactionalContext, playerUid: Int, nickname: String) { + txCtx.jooq().update(ACCOUNT) + .set(ACCOUNT.NICKNAME, nickname) + .where(ACCOUNT.UID.eq(playerUid)) + .and(ACCOUNT.NICKNAME.isNull) + .execute() + } } \ No newline at end of file diff --git a/game-server/src/main/kotlin/work/fking/pangya/game/persistence/StatisticsRepository.kt b/game-server/src/main/kotlin/work/fking/pangya/game/persistence/StatisticsRepository.kt index 96aaf31..fd1df49 100644 --- a/game-server/src/main/kotlin/work/fking/pangya/game/persistence/StatisticsRepository.kt +++ b/game-server/src/main/kotlin/work/fking/pangya/game/persistence/StatisticsRepository.kt @@ -1,6 +1,5 @@ package work.fking.pangya.game.persistence -import org.jooq.DSLContext import org.jooq.RecordMapper import work.fking.pangya.game.persistence.jooq.keys.PLAYER_STATISTICS_PKEY import work.fking.pangya.game.persistence.jooq.tables.records.PlayerStatisticsRecord @@ -8,17 +7,17 @@ import work.fking.pangya.game.persistence.jooq.tables.references.PLAYER_STATISTI import work.fking.pangya.game.player.PlayerStatistics interface StatisticsRepository { - fun load(playerUid: Int): PlayerStatistics - fun save(playerUid: Int, statistics: PlayerStatistics) + fun load(txCtx: TransactionalContext, playerUid: Int): PlayerStatistics + fun save(txCtx: TransactionalContext, playerUid: Int, statistics: PlayerStatistics) } class InMemoryStatisticsRepository : StatisticsRepository { - override fun load(playerUid: Int): PlayerStatistics = PlayerStatistics() - override fun save(playerUid: Int, statistics: PlayerStatistics) { + override fun load(txCtx: TransactionalContext, playerUid: Int): PlayerStatistics = PlayerStatistics() + override fun save(txCtx: TransactionalContext, playerUid: Int, statistics: PlayerStatistics) { } } -class JooqStatisticsRepository(private val jooq: DSLContext) : StatisticsRepository { +class JooqStatisticsRepository : StatisticsRepository { private val statisticsMapper = RecordMapper { PlayerStatistics( totalShots = it.totalShots, @@ -55,14 +54,14 @@ class JooqStatisticsRepository(private val jooq: DSLContext) : StatisticsReposit ) } - override fun load(playerUid: Int): PlayerStatistics { - return jooq.selectFrom(PLAYER_STATISTICS) + override fun load(txCtx: TransactionalContext, playerUid: Int): PlayerStatistics { + return txCtx.jooq().selectFrom(PLAYER_STATISTICS) .where(PLAYER_STATISTICS.ACCOUNT_UID.eq(playerUid)) .fetchOne(statisticsMapper) ?: throw throw IllegalStateException("could not load statistics for playerId=$playerUid") } - override fun save(playerUid: Int, statistics: PlayerStatistics) { - jooq.insertInto(PLAYER_STATISTICS) + override fun save(txCtx: TransactionalContext, playerUid: Int, statistics: PlayerStatistics) { + txCtx.jooq().insertInto(PLAYER_STATISTICS) .set(PLAYER_STATISTICS.ACCOUNT_UID, playerUid) .set(PLAYER_STATISTICS.TOTAL_SHOTS, statistics.totalShots) .set(PLAYER_STATISTICS.TOTAL_PUTTS, statistics.totalPutts) diff --git a/game-server/src/main/kotlin/work/fking/pangya/game/task/HandoverTask.kt b/game-server/src/main/kotlin/work/fking/pangya/game/task/HandoverTask.kt index 1d8c388..5ac88f6 100644 --- a/game-server/src/main/kotlin/work/fking/pangya/game/task/HandoverTask.kt +++ b/game-server/src/main/kotlin/work/fking/pangya/game/task/HandoverTask.kt @@ -44,20 +44,22 @@ class HandoverTask( } channel.write(HandoverReplies.ok()) - val playerId = sessionInfo.uid + val playerUid = sessionInfo.uid + + // The player picked a new character on the login server, this is a brand-new account sessionInfo.characterIffId?.let { val future = gameServer.submitTask( NewPlayerSetupTask( playerUid = sessionInfo.uid, characterIffId = sessionInfo.characterIffId, characterHairColor = sessionInfo.characterHairColor ?: 0, - persistenceContext = gameServer.persistenceCtx + persistenceCtx = gameServer.persistenceCtx ) ) try { future.get(10, TimeUnit.SECONDS) } catch (e: Exception) { - LOGGER.warn("Failed to process playerId $playerId handover", e) + LOGGER.warn("Failed to process playerId $playerUid handover", e) channel.disconnect() return } @@ -65,15 +67,17 @@ class HandoverTask( val persistenceCtx = gameServer.persistenceCtx - val playerWalletFuture = gameServer.submitTask { persistenceCtx.playerRepository.loadWallet(playerId) } - val characterRosterFuture = gameServer.submitTask { persistenceCtx.characterRepository.loadRoster(playerId) } - val caddieRosterFuture = gameServer.submitTask { persistenceCtx.caddieRepository.loadRoster(playerId) } - val inventoryFuture = gameServer.submitTask { persistenceCtx.inventoryRepository.load(playerId) } - val equipmentFuture = gameServer.submitTask { persistenceCtx.equipmentRepository.load(playerId) } - val statisticsFuture = gameServer.submitTask { persistenceCtx.statisticsRepository.load(playerId) } - val achievementsFuture = gameServer.submitTask { persistenceCtx.achievementsRepository.load(playerId) } + val updateNicknameFuture = gameServer.submitTask { persistenceCtx.playerRepository.updateNickname(persistenceCtx.noTxContext(), playerUid, sessionInfo.nickname) } + val playerWalletFuture = gameServer.submitTask { persistenceCtx.playerRepository.loadWallet(persistenceCtx.noTxContext(), playerUid) } + val characterRosterFuture = gameServer.submitTask { persistenceCtx.characterRepository.loadRoster(persistenceCtx.noTxContext(), playerUid) } + val caddieRosterFuture = gameServer.submitTask { persistenceCtx.caddieRepository.loadRoster(persistenceCtx.noTxContext(), playerUid) } + val inventoryFuture = gameServer.submitTask { persistenceCtx.inventoryRepository.load(persistenceCtx.noTxContext(), playerUid) } + val equipmentFuture = gameServer.submitTask { persistenceCtx.equipmentRepository.load(persistenceCtx.noTxContext(), playerUid) } + val statisticsFuture = gameServer.submitTask { persistenceCtx.statisticsRepository.load(persistenceCtx.noTxContext(), playerUid) } + val achievementsFuture = gameServer.submitTask { persistenceCtx.achievementsRepository.load(persistenceCtx.noTxContext(), playerUid) } val futures = listOf( + updateNicknameFuture, playerWalletFuture, characterRosterFuture, caddieRosterFuture, @@ -88,7 +92,7 @@ class HandoverTask( try { future.get(10, TimeUnit.SECONDS) } catch (e: Exception) { - LOGGER.warn("Failed to process playerId $playerId handover", e) + LOGGER.warn("Failed to process playerId $playerUid handover", e) channel.disconnect() futures.forEach { it.cancel(true) } return diff --git a/game-server/src/main/kotlin/work/fking/pangya/game/task/NewPlayerSetupTask.kt b/game-server/src/main/kotlin/work/fking/pangya/game/task/NewPlayerSetupTask.kt index f077f8d..7a20063 100644 --- a/game-server/src/main/kotlin/work/fking/pangya/game/task/NewPlayerSetupTask.kt +++ b/game-server/src/main/kotlin/work/fking/pangya/game/task/NewPlayerSetupTask.kt @@ -18,37 +18,46 @@ class NewPlayerSetupTask( private val playerUid: Int, private val characterIffId: Int, private val characterHairColor: Int, - private val persistenceContext: PersistenceContext + private val persistenceCtx: PersistenceContext ) : Callable { override fun call() { - // TODO: We have to run everything within a transaction, somehow - LOGGER.debug("Creating base entities for playerUid=$playerUid") - persistenceContext.statisticsRepository.save(playerUid, PlayerStatistics()) - - val character = persistenceContext.characterRepository.save( - playerUid, Character( - iffId = characterIffId, - hairColor = characterHairColor, - partIffIds = characterBaseParts(characterIffId) + persistenceCtx.transactional { tx -> + LOGGER.debug("Creating base entities for playerUid=$playerUid") + persistenceCtx.statisticsRepository.save(tx, playerUid, PlayerStatistics()) + + val character = persistenceCtx.characterRepository.save( + txCtx = tx, + playerUid = playerUid, + character = Character( + iffId = characterIffId, + hairColor = characterHairColor, + partIffIds = characterBaseParts(characterIffId) + ) ) - ) - - val clubSet = persistenceContext.inventoryRepository.saveItem( - playerUid, Item(iffId = airKnightClubSetIffId) - ) - persistenceContext.inventoryRepository.saveItem( - playerUid, Item(iffId = baseCometIffId) - ) - - persistenceContext.equipmentRepository.save( - playerUid, Equipment( - characterUid = character.uid, - clubSetUid = clubSet.uid, - cometIffId = baseCometIffId + + val clubSet = persistenceCtx.inventoryRepository.saveItem( + txCtx = tx, + playerUid = playerUid, + item = Item(iffId = airKnightClubSetIffId) + ) + persistenceCtx.inventoryRepository.saveItem( + txCtx = tx, + playerUid = playerUid, + item = Item(iffId = baseCometIffId) + ) + + persistenceCtx.equipmentRepository.save( + txCtx = tx, + playerUid = playerUid, + equipment = Equipment( + characterUid = character.uid, + clubSetUid = clubSet.uid, + cometIffId = baseCometIffId + ) ) - ) - persistenceContext.achievementsRepository.createAchievements(playerUid) + persistenceCtx.achievementsRepository.createAchievements(tx, playerUid) + } } -} \ No newline at end of file +} diff --git a/game-server/src/main/kotlin/work/fking/pangya/game/task/UnlockCaddieTask.kt b/game-server/src/main/kotlin/work/fking/pangya/game/task/UnlockCaddieTask.kt index 1a6fe9e..325b69a 100644 --- a/game-server/src/main/kotlin/work/fking/pangya/game/task/UnlockCaddieTask.kt +++ b/game-server/src/main/kotlin/work/fking/pangya/game/task/UnlockCaddieTask.kt @@ -7,7 +7,7 @@ import work.fking.pangya.game.player.Caddie import work.fking.pangya.game.player.Player class UnlockCaddieTask( - private val persistenceContext: PersistenceContext, + private val persistenceCtx: PersistenceContext, private val player: Player, private val iffId: Int ) : Runnable { @@ -15,7 +15,7 @@ class UnlockCaddieTask( override fun run() { require(iffTypeFromId(iffId) == IFF_TYPE_CADDIE) { "iffId is not a caddie" } val caddie = Caddie(iffId = iffId) - val persistedCaddie = persistenceContext.caddieRepository.save(player.uid, caddie) + val persistedCaddie = persistenceCtx.caddieRepository.save(persistenceCtx.noTxContext(), player.uid, caddie) player.caddieRoster.entries.add(persistedCaddie) } } \ No newline at end of file diff --git a/game-server/src/main/kotlin/work/fking/pangya/game/task/UnlockCharacterTask.kt b/game-server/src/main/kotlin/work/fking/pangya/game/task/UnlockCharacterTask.kt index abf1beb..d4e3808 100644 --- a/game-server/src/main/kotlin/work/fking/pangya/game/task/UnlockCharacterTask.kt +++ b/game-server/src/main/kotlin/work/fking/pangya/game/task/UnlockCharacterTask.kt @@ -8,7 +8,7 @@ import work.fking.pangya.game.player.Player import work.fking.pangya.game.player.characterBaseParts class UnlockCharacterTask( - private val persistenceContext: PersistenceContext, + private val persistenceCtx: PersistenceContext, private val player: Player, private val iffId: Int ) : Runnable { @@ -16,7 +16,8 @@ class UnlockCharacterTask( override fun run() { require(iffTypeFromId(iffId) == IFF_TYPE_CHARACTER) { "iffId is not a character" } val partIffIds = characterBaseParts(iffId) - val character = persistenceContext.characterRepository.save( + val character = persistenceCtx.characterRepository.save( + txCtx = persistenceCtx.noTxContext(), playerUid = player.uid, character = Character( iffId = iffId, diff --git a/game-server/src/main/kotlin/work/fking/pangya/game/task/UpdatePlayerCaddieTask.kt b/game-server/src/main/kotlin/work/fking/pangya/game/task/UpdatePlayerCaddieTask.kt index ebd8cbb..50cc0a5 100644 --- a/game-server/src/main/kotlin/work/fking/pangya/game/task/UpdatePlayerCaddieTask.kt +++ b/game-server/src/main/kotlin/work/fking/pangya/game/task/UpdatePlayerCaddieTask.kt @@ -1,12 +1,11 @@ package work.fking.pangya.game.task import org.slf4j.LoggerFactory -import work.fking.pangya.game.GameServer import work.fking.pangya.game.packet.outbound.EquipmentUpdateReplies import work.fking.pangya.game.packet.outbound.EquipmentUpdateReplies.EquipmentUpdateResult.FAILED_BECAUSE_OF_DB_ERROR import work.fking.pangya.game.packet.outbound.EquipmentUpdateReplies.EquipmentUpdateResult.SUCCESS import work.fking.pangya.game.packet.outbound.EquipmentUpdateReplies.EquipmentUpdateType.CADDIE -import work.fking.pangya.game.packet.outbound.EquipmentUpdateReplies.EquipmentUpdateType.CHARACTER_PARTS +import work.fking.pangya.game.persistence.PersistenceContext import work.fking.pangya.game.player.Caddie import work.fking.pangya.game.player.Player import java.sql.SQLException @@ -14,7 +13,7 @@ import java.sql.SQLException private val LOGGER = LoggerFactory.getLogger(UpdatePlayerCaddieTask::class.java) class UpdatePlayerCaddieTask( - private val server: GameServer, + private val persistenceCtx: PersistenceContext, private val player: Player, private val caddie: Caddie ) : Runnable { @@ -22,7 +21,7 @@ class UpdatePlayerCaddieTask( override fun run() { try { player.equipment.equipCaddie(caddie) - server.persistenceCtx.equipmentRepository.save(player.uid, player.equipment) + persistenceCtx.equipmentRepository.save(persistenceCtx.noTxContext(), player.uid, player.equipment) player.writeAndFlush(EquipmentUpdateReplies.ack(result = SUCCESS, type = CADDIE) { it.writeIntLE(caddie.uid) }) diff --git a/game-server/src/main/kotlin/work/fking/pangya/game/task/UpdatePlayerCharacterPartsTask.kt b/game-server/src/main/kotlin/work/fking/pangya/game/task/UpdatePlayerCharacterPartsTask.kt index 35f3ca9..a20e317 100644 --- a/game-server/src/main/kotlin/work/fking/pangya/game/task/UpdatePlayerCharacterPartsTask.kt +++ b/game-server/src/main/kotlin/work/fking/pangya/game/task/UpdatePlayerCharacterPartsTask.kt @@ -1,11 +1,11 @@ package work.fking.pangya.game.task import org.slf4j.LoggerFactory -import work.fking.pangya.game.GameServer import work.fking.pangya.game.packet.outbound.EquipmentUpdateReplies import work.fking.pangya.game.packet.outbound.EquipmentUpdateReplies.EquipmentUpdateResult.FAILED_BECAUSE_OF_DB_ERROR import work.fking.pangya.game.packet.outbound.EquipmentUpdateReplies.EquipmentUpdateResult.SUCCESS import work.fking.pangya.game.packet.outbound.EquipmentUpdateReplies.EquipmentUpdateType.CHARACTER_PARTS +import work.fking.pangya.game.persistence.PersistenceContext import work.fking.pangya.game.player.Character import work.fking.pangya.game.player.Player import work.fking.pangya.game.player.write @@ -14,14 +14,14 @@ import java.sql.SQLException private val LOGGER = LoggerFactory.getLogger(UpdatePlayerCharacterPartsTask::class.java) class UpdatePlayerCharacterPartsTask( - private val server: GameServer, + private val persistenceCtx: PersistenceContext, private val player: Player, private val character: Character ) : Runnable { override fun run() { try { - server.persistenceCtx.characterRepository.save(player.uid, character) + persistenceCtx.characterRepository.save(persistenceCtx.noTxContext(), player.uid, character) player.equippedCharacter().updateParts(character) player.writeAndFlush(EquipmentUpdateReplies.ack(result = SUCCESS, type = CHARACTER_PARTS) { it.write(character) diff --git a/game-server/src/main/kotlin/work/fking/pangya/game/task/UpdatePlayerCharacterTask.kt b/game-server/src/main/kotlin/work/fking/pangya/game/task/UpdatePlayerCharacterTask.kt index 38eacd2..9a3ccfb 100644 --- a/game-server/src/main/kotlin/work/fking/pangya/game/task/UpdatePlayerCharacterTask.kt +++ b/game-server/src/main/kotlin/work/fking/pangya/game/task/UpdatePlayerCharacterTask.kt @@ -1,11 +1,11 @@ package work.fking.pangya.game.task import org.slf4j.LoggerFactory -import work.fking.pangya.game.GameServer import work.fking.pangya.game.packet.outbound.EquipmentUpdateReplies import work.fking.pangya.game.packet.outbound.EquipmentUpdateReplies.EquipmentUpdateResult.FAILED_BECAUSE_OF_DB_ERROR import work.fking.pangya.game.packet.outbound.EquipmentUpdateReplies.EquipmentUpdateResult.SUCCESS import work.fking.pangya.game.packet.outbound.EquipmentUpdateReplies.EquipmentUpdateType.CHARACTER +import work.fking.pangya.game.persistence.PersistenceContext import work.fking.pangya.game.player.Character import work.fking.pangya.game.player.Player import java.sql.SQLException @@ -13,7 +13,7 @@ import java.sql.SQLException private val LOGGER = LoggerFactory.getLogger(UpdatePlayerCharacterTask::class.java) class UpdatePlayerCharacterTask( - private val server: GameServer, + private val persistenceCtx: PersistenceContext, private val player: Player, private val character: Character ) : Runnable { @@ -21,7 +21,7 @@ class UpdatePlayerCharacterTask( override fun run() { try { player.equipment.equipCharacter(character) - server.persistenceCtx.equipmentRepository.save(player.uid, player.equipment) + persistenceCtx.equipmentRepository.save(persistenceCtx.noTxContext(), player.uid, player.equipment) player.writeAndFlush(EquipmentUpdateReplies.ack(result = SUCCESS, type = CHARACTER) { it.writeIntLE(character.uid) }) diff --git a/game-server/src/main/kotlin/work/fking/pangya/game/task/UpdatePlayerCometClubSetTask.kt b/game-server/src/main/kotlin/work/fking/pangya/game/task/UpdatePlayerCometClubSetTask.kt index 4d0fbfe..411ff38 100644 --- a/game-server/src/main/kotlin/work/fking/pangya/game/task/UpdatePlayerCometClubSetTask.kt +++ b/game-server/src/main/kotlin/work/fking/pangya/game/task/UpdatePlayerCometClubSetTask.kt @@ -1,11 +1,11 @@ package work.fking.pangya.game.task import org.slf4j.LoggerFactory -import work.fking.pangya.game.GameServer import work.fking.pangya.game.packet.outbound.EquipmentUpdateReplies import work.fking.pangya.game.packet.outbound.EquipmentUpdateReplies.EquipmentUpdateResult.FAILED_BECAUSE_OF_DB_ERROR import work.fking.pangya.game.packet.outbound.EquipmentUpdateReplies.EquipmentUpdateResult.SUCCESS import work.fking.pangya.game.packet.outbound.EquipmentUpdateReplies.EquipmentUpdateType.COMET_CLUBSET +import work.fking.pangya.game.persistence.PersistenceContext import work.fking.pangya.game.player.Item import work.fking.pangya.game.player.Player import java.sql.SQLException @@ -13,7 +13,7 @@ import java.sql.SQLException private val LOGGER = LoggerFactory.getLogger(UpdatePlayerCometClubSetTask::class.java) class UpdatePlayerCometClubSetTask( - private val server: GameServer, + private val persistenceCtx: PersistenceContext, private val player: Player, private val comet: Item, private val clubSet: Item @@ -23,7 +23,7 @@ class UpdatePlayerCometClubSetTask( try { player.equipment.equipComet(comet) player.equipment.equipClubSet(clubSet) - server.persistenceCtx.equipmentRepository.save(player.uid, player.equipment) + persistenceCtx.equipmentRepository.save(persistenceCtx.noTxContext(), player.uid, player.equipment) player.writeAndFlush(EquipmentUpdateReplies.ack(result = SUCCESS, type = COMET_CLUBSET) { it.writeIntLE(comet.iffId) it.writeIntLE(clubSet.uid) diff --git a/game-server/src/main/kotlin/work/fking/pangya/game/task/UpdatePlayerEquippedItemsTask.kt b/game-server/src/main/kotlin/work/fking/pangya/game/task/UpdatePlayerEquippedItemsTask.kt index df3f39e..9168fa0 100644 --- a/game-server/src/main/kotlin/work/fking/pangya/game/task/UpdatePlayerEquippedItemsTask.kt +++ b/game-server/src/main/kotlin/work/fking/pangya/game/task/UpdatePlayerEquippedItemsTask.kt @@ -1,18 +1,18 @@ package work.fking.pangya.game.task import org.slf4j.LoggerFactory -import work.fking.pangya.game.GameServer import work.fking.pangya.game.packet.outbound.EquipmentUpdateReplies import work.fking.pangya.game.packet.outbound.EquipmentUpdateReplies.EquipmentUpdateResult.FAILED_BECAUSE_OF_DB_ERROR import work.fking.pangya.game.packet.outbound.EquipmentUpdateReplies.EquipmentUpdateResult.SUCCESS import work.fking.pangya.game.packet.outbound.EquipmentUpdateReplies.EquipmentUpdateType.EQUIPPED_ITEMS +import work.fking.pangya.game.persistence.PersistenceContext import work.fking.pangya.game.player.Player import java.sql.SQLException private val LOGGER = LoggerFactory.getLogger(UpdatePlayerEquippedItemsTask::class.java) class UpdatePlayerEquippedItemsTask( - private val server: GameServer, + private val persistenceCtx: PersistenceContext, private val player: Player, private val itemIffIds: IntArray ) : Runnable { @@ -20,7 +20,7 @@ class UpdatePlayerEquippedItemsTask( override fun run() { try { player.equipment.updateEquippedItems(itemIffIds) - server.persistenceCtx.equipmentRepository.save(player.uid, player.equipment) + persistenceCtx.equipmentRepository.save(persistenceCtx.noTxContext(), player.uid, player.equipment) player.writeAndFlush(EquipmentUpdateReplies.ack(result = SUCCESS, type = EQUIPPED_ITEMS) { buffer -> itemIffIds.forEach { buffer.writeIntLE(it) } })