module Degenz.DbService open System open System.Collections.Generic open MongoDB.Bson open MongoDB.Bson.Serialization open MongoDB.Driver open Degenz.Types [] type AttackAction = { ActionId : int Result : bool Target : DiscordPlayer Timestamp : DateTime } [] type DefenseAction = { ActionId : int Timestamp : DateTime } [] type PlayerEntry = { DiscordId : uint64 Name : string XP : int Bank : int } let private actionToAttack (action : Action) (hack : AttackResult) = { ActionId = action.ActionId Result = hack.Result Target = hack.Target Timestamp = action.Timestamp } let private actionToDefense (action : Action) = { ActionId = action.ActionId Timestamp = action.Timestamp } let private attackToAction (attack : AttackAction) = { ActionId = attack.ActionId Type = Attack { Target = attack.Target ; Result = attack.Result } Timestamp = attack.Timestamp } let private defenseToAction (action : DefenseAction) = { ActionId = action.ActionId Type = Defense Timestamp = action.Timestamp } let private playerMap (player : PlayerData) = { DiscordId = player.DiscordId Name = player.Name XP = player.XP Bank = int player.Bank } let tryWithDefault (bson : BsonDocument) field (defaultValue : 'a) (map : BsonValue -> 'a) = let result , bval = bson.TryGetValue(field) if result then map bval else defaultValue let private mapBack (bson : BsonDocument) : PlayerData = { DiscordId = tryWithDefault bson "Player.DiscordId" 0uL (fun v -> v.AsInt64 |> uint64) Name = tryWithDefault bson "Player.Name" "Empty" (fun v -> v.AsString) Arsenal = tryWithDefault bson "Inventory" [||] (fun v -> v.AsBsonArray |> Seq.map (fun (bv : BsonValue) -> bv.AsInt32) |> Seq.map (fun w -> Armory.battleItems |> Array.find (fun w' -> w = w'.Id)) |> Seq.toArray) Actions = tryWithDefault bson "Events" [||] (fun _ -> [||]) Traits = tryWithDefault bson "Traits" PlayerTraits.empty (fun _ -> PlayerTraits.empty) Achievements = tryWithDefault bson "Achievements" [||] (fun _ -> [||]) XP = tryWithDefault bson "XP" 0 (fun _ -> 0) Bank = tryWithDefault bson "Player.Bank" 0 (fun v -> v.AsInt32 * 1) } let mongo = MongoClient(Environment.GetEnvironmentVariable("CONN_STRING")) let db = mongo.GetDatabase("degenz") let players = db.GetCollection("players") let tryFindPlayer (id : uint64) = async { let filter = Builders.Filter.Eq("Player.DiscordId", id) let! player = players.FindAsync(filter) |> Async.AwaitTask match player.FirstOrDefault() with | null -> return None | p -> return p .GetValue("Player") .ToBsonDocument() |> mapBack |> Some } let updatePlayer (player : PlayerData) = async { let filter = Builders.Filter.Eq("Player.DiscordId", player.DiscordId) let update = Builders.Update .Set("Player", playerMap player) .AddToSet("Traits", player.Traits) .AddToSet("Events", player.Actions) .AddToSet("Achievements", player.Achievements) .AddToSet("Inventory", player.Arsenal) return! players.UpdateOneAsync(filter, update) |> Async.AwaitTask |> Async.Ignore } let getAchievements (id : uint64) = async { let filter = Builders.Filter.Eq("Player.DiscordId", id) try let! player = players.FindAsync(filter) |> Async.AwaitTask match player.FirstOrDefault() with | null -> return None | p -> return p .GetValue("achievements") .AsBsonArray |> Seq.map (fun (bv : BsonValue) -> bv.AsString) |> Some with ex -> return None } let addAchievement (id : uint64) (achievement : string) = async { let filter = Builders.Filter.Eq("Player.DiscordId", id) let update = Builders.Update.Push("Achievements", achievement) return! players.UpdateOneAsync(filter, update) |> Async.AwaitTask |> Async.Ignore } let insertNewPlayer (player : PlayerData) = async { let dict = [ KeyValuePair("Player" , (playerMap player).ToBsonDocument() :> Object) KeyValuePair("Events" , [||] :> Object) KeyValuePair("Inventory" , [||] :> Object) KeyValuePair("Traits" , PlayerTraits.empty.ToBsonDocument() :> Object) KeyValuePair("XP" , 0 :> Object) ] do! BsonDocument(dict) |> players.InsertOneAsync |> Async.AwaitTask } //let deletePlayer (player : PlayerData) = // async { // let dict = [ KeyValuePair("Player" , player.ToBsonDocument() :> Object) ] // do! BsonDocument(dict) // |> players.InsertOneAsync // |> Async.AwaitTask // } // //let getTopPlayers amount = // async { // return! players.FindAsync() // }