From 25654c9b8c2bbeaeb416da710096ca4743453bcd Mon Sep 17 00:00:00 2001 From: Joseph Ferano Date: Wed, 23 Feb 2022 21:44:36 +0700 Subject: [PATCH] Read PlayerEvents from DB and check if achievement exists --- Bot/Game.fs | 5 +- Bot/Trainer.fs | 10 ++-- DbService/DbService.fs | 101 +++++++++++++++++++++++++++++------------ Shared/Shared.fs | 4 +- 4 files changed, 81 insertions(+), 39 deletions(-) diff --git a/Bot/Game.fs b/Bot/Game.fs index 18ea069..697a267 100644 --- a/Bot/Game.fs +++ b/Bot/Game.fs @@ -100,7 +100,8 @@ module Arsenal = let actionFormat (actions : PlayerEvent array) = match actions with | [||] -> "None" - | _ -> actions + | acts -> + acts |> Array.map (fun act -> match act.Type with | Hacking h -> @@ -112,7 +113,7 @@ module Arsenal = let cooldown = Messaging.getTimeText true (System.TimeSpan.FromMinutes(int act.Cooldown)) act.Timestamp $"{item.Name} Shield active for {cooldown}" | _ -> "") - |> Array.filter (System.String.IsNullOrWhiteSpace) + |> Array.filter (System.String.IsNullOrWhiteSpace >> not) |> String.concat "\n" let statusFormat p = diff --git a/Bot/Trainer.fs b/Bot/Trainer.fs index 68fcc08..c93dd0e 100644 --- a/Bot/Trainer.fs +++ b/Bot/Trainer.fs @@ -144,9 +144,7 @@ let handleHack (ctx : IDiscordContext) = let sb = StringBuilder("Here, ") - // TODO DB: -// let isFirstTrainer = player.Achievements |> Seq.contains trainerAchievement |> not - let isFirstTrainer = true + let! isFirstTrainer = DbService.checkHasAchievement GuildEnvironment.pgDb player.DiscordId trainerAchievement if isFirstTrainer then do! DbService.addAchievement GuildEnvironment.pgDb player.DiscordId trainerAchievement |> Async.Ignore @@ -180,9 +178,9 @@ let handleArsenal (ctx : IDiscordContext) = |> Async.Ignore let embed = Embeds.getArsenalEmbed updatedPlayer do! ctx.FollowUp(embed) |> Async.AwaitTask - // TODO DB: -// if not (player.Achievements |> Array.contains trainerAchievement) then - if true then + + let! isFirstTrainer = DbService.checkHasAchievement GuildEnvironment.pgDb player.DiscordId trainerAchievement + if isFirstTrainer then do! Async.Sleep 3000 let rewards = [ $"{defaultHack.Name} Hack" ; $"{defaultShield.Name} Shield" ] let embed = Embeds.getAchievementEmbed rewards "You completed the Training Dojo and collected loot." trainerAchievement diff --git a/DbService/DbService.fs b/DbService/DbService.fs index 9bf37ff..f717921 100644 --- a/DbService/DbService.fs +++ b/DbService/DbService.fs @@ -28,33 +28,57 @@ let mapBack user : PlayerData = Bank = user.Bank } +let getPlayerEvents connStr (player : PlayerData) = + connStr + |> Sql.connect + |> Sql.parameters [ "did", Sql.string (string player.DiscordId) ] + |> Sql.query """ + WITH usr AS (SELECT id FROM "user" WHERE discord_id = @did) + SELECT event_type, success, is_instigator, item_id, cooldown, adversary_id, adversary_name, created_at + FROM player_event ,usr WHERE user_id = usr.id; + """ + |> Sql.executeAsync (fun read -> + match read.string "event_type" with + | "Hacking" -> + Hacking { + IsInstigator = read.bool "is_instigator" + Success = read.bool "success" + Adversary = { Id = read.string "adversary_id" |> uint64 ; Name = read.string "adversary_name" } + HackId = read.int "item_id" + } + | "Shielding" -> Shielding (read.int "item_id") + | "Stealing" -> Stealing ( read.bool "is_instigator" , { Id = read.string "adversary_id" |> uint64 ; Name = read.string "adversary_name" } ) + | _ -> Imprison + |> fun t -> + let date = read.dateTimeOrNone "created_at" |> Option.defaultValue DateTime.UtcNow + { Type = t ; Cooldown = read.int "cooldown" * 1 ; Timestamp = date } + ) + |> Async.AwaitTask + let tryFindPlayer connStr (discordId : uint64) = async { - try - let! user = - connStr - |> Sql.connect - |> Sql.query """ - SELECT discord_id, display_name, gbt, strength, inventory - FROM "user" WHERE discord_id = @did") - """ - |> Sql.parameters [ "did", Sql.string (string discordId) ] - |> Sql.executeAsync (fun read -> - { - DiscordId = read.string "discord_id" |> uint64 - Name = read.string "display_name" - Bank = read.int "gbt" * 1 - Strength = read.int "strength" - Inventory = read.intArray "inventory" - }) - |> Async.AwaitTask - - match List.tryHead user with - | None -> return None - | Some u -> return Some (mapBack u) - with e -> - printfn $"{e.Message}" - return None + let! user = + connStr + |> Sql.connect + |> Sql.parameters [ "did", Sql.string (string discordId) ] + |> Sql.query """ + SELECT discord_id, display_name, gbt, strength, inventory FROM "user" WHERE discord_id = @did + """ + |> Sql.executeAsync (fun read -> + { + DiscordId = read.string "discord_id" |> uint64 + Name = read.string "display_name" + Bank = read.int "gbt" * 1 + Strength = read.int "strength" + Inventory = read.intArray "inventory" + }) + |> Async.AwaitTask + match List.tryHead user with + | None -> return None + | Some u -> + let player = mapBack u + let! events = getPlayerEvents connStr player + return Some { player with Events = events |> List.toArray } } let updatePlayer connStr (player : PlayerData) = @@ -68,7 +92,7 @@ let updatePlayer connStr (player : PlayerData) = ] |> Sql.query """ UPDATE "user" SET gbt = @gbt, strength = @str, inventory = @inv - WHERE discord_id = @did") + WHERE discord_id = @did """ |> Sql.executeNonQueryAsync |> Async.AwaitTask @@ -76,15 +100,34 @@ let updatePlayer connStr (player : PlayerData) = let addAchievement connStr (did : uint64) (achievement : string) = connStr |> Sql.connect + |> Sql.parameters + [ ( "did" , Sql.string (string did) ) + ( "symbol", Sql.string achievement ) ] |> Sql.query """ WITH ach AS (INSERT INTO achievement (symbol) VALUES (@symbol) RETURNING id), usr AS (SELECT id FROM "user" WHERE discord_id = @did) - INSERT INTO user_achievements_achievement (user_id, achievement_id) SELECT usr.id, ach.id FROM usr, ach") + INSERT INTO user_achievements_achievement (user_id, achievement_id) SELECT usr.id, ach.id FROM usr, ach """ - |> Sql.parameters [ ( "did" , Sql.string (string did) ) ; ( "achievement", Sql.string achievement ) ] |> Sql.executeNonQueryAsync |> Async.AwaitTask +let checkHasAchievement connStr (did : uint64) (achievement : string) = async { + let! result = + connStr + |> Sql.connect + |> Sql.parameters + [ ( "did" , Sql.string (string did) ) + ( "symbol", Sql.string achievement ) ] + |> Sql.query """ + WITH ach AS (SELECT id FROM achievement WHERE symbol = @symbol), + usr AS (SELECT id FROM "user" WHERE discord_id = @did) + SELECT achievement_id FROM user_achievements_achievement, ach, usr WHERE user_id = usr.id and achievement_id = ach.id; + """ + |> Sql.executeAsync (fun read -> read.int "achievement_id") + |> Async.AwaitTask + return List.isEmpty result |> not +} + let addPlayerEvent connStr (did : uint64) (playerEvent : PlayerEvent) = let sqlParams , query = match playerEvent.Type with @@ -135,7 +178,7 @@ let addPlayerEvent connStr (did : uint64) (playerEvent : PlayerEvent) = """ WITH usr AS (SELECT id FROM "user" WHERE discord_id = @did) INSERT INTO player_event (event_type, cooldown, user_id) - SELECT 'Stealing', @cooldown, usr.id FROM usr + SELECT 'Imprison', @cooldown, usr.id FROM usr """ connStr |> Sql.connect diff --git a/Shared/Shared.fs b/Shared/Shared.fs index 366a086..82fe138 100644 --- a/Shared/Shared.fs +++ b/Shared/Shared.fs @@ -122,10 +122,10 @@ module Types = Inventory : Item array Events : PlayerEvent array Traits : PlayerTraits -// Achievements : string array -// XP : int Bank : int } +// Achievements : string array +// XP : int with member this.basicPlayer = { Id = this.DiscordId ; Name = this.Name } static member empty = { DiscordId = 0uL