Finish refactoring DbService. Rename project to PlayerInteractions
This commit is contained in:
parent
7b2f6ba861
commit
162f6af03f
@ -1,6 +1,6 @@
|
||||
module DegenzGame.DbService
|
||||
|
||||
open DegenzGame.Shared
|
||||
open System
|
||||
open DegenzGame.Shared
|
||||
open MongoDB.Bson
|
||||
open MongoDB.Driver
|
||||
@ -16,7 +16,7 @@ let players = db.GetCollection<PlayerEntry>("players")
|
||||
|
||||
let tryFindPlayer (id : uint64) : Async<Player option> =
|
||||
async {
|
||||
let filter = Builders<PlayerEntry>.Filter.Eq((fun p -> p.Player.DiscordId), id)
|
||||
let filter = Builders<PlayerEntry>.Filter.Eq((fun e -> e.Player.DiscordId), id)
|
||||
let! player = players.FindAsync<PlayerEntry>(filter) |> Async.AwaitTask
|
||||
return match player.ToEnumerable() |> Seq.toList with
|
||||
| [] -> None
|
||||
@ -33,7 +33,27 @@ let insertNewPlayer (player : Player) =
|
||||
let removePlayer (memberId : uint64) =
|
||||
async {
|
||||
// TODO: Check the result of this delete operation
|
||||
return! players.DeleteOneAsync (fun p -> p.Player.DiscordId = memberId)
|
||||
return! players.DeleteOneAsync (fun e -> e.Player.DiscordId = memberId)
|
||||
|> Async.AwaitTask
|
||||
|> Async.Ignore
|
||||
}
|
||||
|
||||
let updateAttacks (playerId : uint64) (attacks : Attack array) =
|
||||
async {
|
||||
let filter = Builders<PlayerEntry>.Filter.Eq((fun e -> e.Player.DiscordId), playerId)
|
||||
let update = Builders<PlayerEntry>.Update.Set((fun e -> e.Player.Attacks), attacks)
|
||||
return! players.UpdateOneAsync(filter, update) |> Async.AwaitTask |> Async.Ignore
|
||||
}
|
||||
|
||||
let updatePlayer player =
|
||||
async {
|
||||
let filter = Builders<PlayerEntry>.Filter.Eq((fun e -> e.Player.DiscordId), player.DiscordId)
|
||||
let update = Builders<PlayerEntry>.Update.Set((fun e -> e.Player), player)
|
||||
return! players.UpdateOneAsync(filter, update) |> Async.AwaitTask |> Async.Ignore
|
||||
}
|
||||
|
||||
let getTopPlayers number =
|
||||
async {
|
||||
let! entries = players.Find(fun _ -> true).SortBy(fun e -> e.Player.Bank).Limit(Nullable<int>(number)).ToListAsync() |> Async.AwaitTask
|
||||
return entries |> Seq.map (fun e -> e.Player)
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Shared", "Shared\Shared.fsp
|
||||
EndProject
|
||||
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Store", "Store\Store.fsproj", "{CD88B0A6-DE42-4087-9B33-48FF84201633}"
|
||||
EndProject
|
||||
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "PlayerRegistration", "PlayerRegistration\PlayerRegistration.fsproj", "{FF9E58A6-1A1D-4DEC-B52D-265F215BF315}"
|
||||
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "PlayerInteractions", "PlayerInteractions\PlayerInteractions.fsproj", "{FF9E58A6-1A1D-4DEC-B52D-265F215BF315}"
|
||||
EndProject
|
||||
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "DbService", "DbService\DbService.fsproj", "{B1D3E1CC-451C-42D4-B054-D64E75E1A3B9}"
|
||||
EndProject
|
||||
|
@ -7,9 +7,6 @@ open DSharpPlus.Entities
|
||||
open DSharpPlus.EventArgs
|
||||
open DSharpPlus.SlashCommands
|
||||
open DegenzGame.Shared
|
||||
open DegenzGame.DbService
|
||||
open DegenzGame.Functions
|
||||
open MongoDB.Driver
|
||||
|
||||
[<Literal>]
|
||||
// Degenz Server
|
||||
@ -17,18 +14,17 @@ open MongoDB.Driver
|
||||
// My server
|
||||
let battleChannel = 927449884204867664uL
|
||||
|
||||
|
||||
let attack (ctx : InteractionContext) (target : DiscordUser) =
|
||||
async {
|
||||
// TODO: We need to check if the player has any active embed hacks going, if not they can cheat
|
||||
let! attacker = tryFindPlayer ctx.Member.Id
|
||||
let! defender = tryFindPlayer target.Id
|
||||
let! attacker = DbService.tryFindPlayer ctx.Member.Id
|
||||
let! defender = DbService.tryFindPlayer target.Id
|
||||
match attacker , defender with
|
||||
| Some attacker , Some defender ->
|
||||
let updatedAttacks = removeExpiredActions (TimeSpan.FromMinutes(5)) (fun (atk : Attack) -> atk.Timestamp) attacker.Attacks
|
||||
let filter = Builders<Player>.Filter.Eq((fun p -> p.DiscordId), attacker.DiscordId)
|
||||
let update = Builders<Player>.Update.Set((fun p -> p.Attacks), updatedAttacks)
|
||||
let! _ = players.UpdateOneAsync(filter, update) |> Async.AwaitTask
|
||||
let updatedAttacks =
|
||||
attacker.Attacks
|
||||
|> removeExpiredActions (TimeSpan.FromMinutes(5)) (fun (atk : Attack) -> atk.Timestamp)
|
||||
do! DbService.updateAttacks attacker.DiscordId updatedAttacks
|
||||
if updatedAttacks.Length < 2 then
|
||||
let builder = DiscordInteractionResponseBuilder()
|
||||
builder.AddEmbed (constructEmbed "Pick the hack you wish to use.") |> ignore
|
||||
@ -62,13 +58,11 @@ let attack (ctx : InteractionContext) (target : DiscordUser) =
|
||||
|
||||
let defend (ctx : InteractionContext) =
|
||||
async {
|
||||
let! player = tryFindPlayer ctx.Member.Id
|
||||
let! player = DbService.tryFindPlayer ctx.Member.Id
|
||||
match player with
|
||||
| Some player ->
|
||||
let updatedDefenses = removeExpiredActions (TimeSpan.FromMinutes(60)) (fun (pro : Defense) -> pro.Timestamp) player.Defenses
|
||||
let filter = Builders<Player>.Filter.Eq((fun p -> p.DiscordId), player.DiscordId)
|
||||
let update = Builders<Player>.Update.Set((fun p -> p.Defenses), updatedDefenses)
|
||||
let! _ = players.UpdateOneAsync(filter, update) |> Async.AwaitTask
|
||||
do! DbService.updatePlayer <| { player with Defenses = updatedDefenses }
|
||||
if updatedDefenses.Length < 2 then
|
||||
let builder = DiscordInteractionResponseBuilder()
|
||||
builder.AddEmbed (constructEmbed "Pick a defense to mount for a duration of time") |> ignore
|
||||
@ -96,36 +90,6 @@ let defend (ctx : InteractionContext) =
|
||||
} |> Async.StartAsTask
|
||||
:> Task
|
||||
|
||||
let status (ctx : InteractionContext) =
|
||||
async {
|
||||
let! player = tryFindPlayer ctx.Member.Id
|
||||
match player with
|
||||
| Some p ->
|
||||
let builder = DiscordInteractionResponseBuilder()
|
||||
builder.IsEphemeral <- true
|
||||
builder.Content <- Functions.statusFormat p
|
||||
do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder)
|
||||
|> Async.AwaitTask
|
||||
| None -> do! notYetAHackerMsg ctx
|
||||
} |> Async.StartAsTask
|
||||
:> Task
|
||||
|
||||
let leaderboard (ctx : InteractionContext) =
|
||||
async {
|
||||
let builder = DiscordInteractionResponseBuilder()
|
||||
builder.IsEphemeral <- true
|
||||
|
||||
let! leaders = players.Find(fun _ -> true).SortBy(fun p -> p.Bank).Limit(10).ToListAsync() |> Async.AwaitTask
|
||||
let content =
|
||||
leaders.ToArray()
|
||||
|> Array.mapi (fun i p -> $"{i + 1}. {p.Bank} {p.Name}")
|
||||
|> String.concat "\n"
|
||||
builder.Content <- if not <| String.IsNullOrEmpty content then content else "There are no active hackers"
|
||||
do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder)
|
||||
|> Async.AwaitTask
|
||||
} |> Async.StartAsTask
|
||||
:> Task
|
||||
|
||||
let handleAttack (event : ComponentInteractionCreateEventArgs) =
|
||||
let updatePlayer amount attack p =
|
||||
{ p with Attacks = Array.append [| attack |] p.Attacks ; Bank = MathF.Max(p.Bank + amount, 0f) }
|
||||
@ -133,8 +97,8 @@ let handleAttack (event : ComponentInteractionCreateEventArgs) =
|
||||
let split = event.Id.Split("-")
|
||||
let ( resultHack , weapon ) = Weapon.TryParse(split.[1])
|
||||
let ( resultId , targetId ) = UInt64.TryParse split.[2]
|
||||
let! resultPlayer = tryFindPlayer event.User.Id
|
||||
let! resultTarget = tryFindPlayer targetId
|
||||
let! resultPlayer = DbService.tryFindPlayer event.User.Id
|
||||
let! resultTarget = DbService.tryFindPlayer targetId
|
||||
match resultPlayer , resultTarget , resultHack , resultId with
|
||||
| Some player , Some target , true , true ->
|
||||
let wasSuccessfulHack =
|
||||
@ -147,8 +111,7 @@ let handleAttack (event : ComponentInteractionCreateEventArgs) =
|
||||
| false ->
|
||||
let prize = 0.1726f
|
||||
let attack = { HackType = enum<Weapon>(weapon) ; Timestamp = DateTime.UtcNow ; Target = { Id = targetId ; Name = split.[3] } }
|
||||
let filter = Builders<Player>.Filter.Eq((fun p -> p.DiscordId), player.DiscordId)
|
||||
let! _ = players.ReplaceOneAsync(filter, updatePlayer prize attack player) |> Async.AwaitTask
|
||||
do! DbService.updatePlayer <| updatePlayer prize attack player
|
||||
|
||||
let builder = DiscordInteractionResponseBuilder()
|
||||
builder.IsEphemeral <- true
|
||||
@ -171,8 +134,7 @@ let handleAttack (event : ComponentInteractionCreateEventArgs) =
|
||||
|> Async.AwaitTask
|
||||
|
||||
let attack = { HackType = enum<Weapon>(weapon) ; Timestamp = DateTime.UtcNow ; Target = { Id = targetId ; Name = split.[3] } }
|
||||
let filter = Builders<Player>.Filter.Eq((fun p -> p.DiscordId), player.DiscordId)
|
||||
let! _ = players.ReplaceOneAsync(filter, updatePlayer loss attack player) |> Async.AwaitTask
|
||||
do! DbService.updatePlayer <| updatePlayer loss attack player
|
||||
|
||||
let builder = DiscordMessageBuilder()
|
||||
builder.WithContent($"{event.User.Username} failed to hack <@{targetId}>!") |> ignore
|
||||
@ -192,7 +154,7 @@ let handleDefense (event : ComponentInteractionCreateEventArgs) =
|
||||
async {
|
||||
let split = event.Id.Split("-")
|
||||
let ( shieldResult , shield ) = Shield.TryParse(split.[1])
|
||||
let! playerResult = tryFindPlayer event.User.Id
|
||||
let! playerResult = DbService.tryFindPlayer event.User.Id
|
||||
match playerResult , shieldResult with
|
||||
| Some player , true ->
|
||||
let builder = DiscordInteractionResponseBuilder()
|
||||
@ -202,9 +164,7 @@ let handleDefense (event : ComponentInteractionCreateEventArgs) =
|
||||
|> Async.AwaitTask
|
||||
|
||||
let defense = { DefenseType = shield ; Timestamp = DateTime.UtcNow }
|
||||
let filter = Builders<Player>.Filter.Eq((fun p -> p.DiscordId), player.DiscordId)
|
||||
let update = Builders<Player>.Update.Set((fun p -> p.Defenses), Array.append [| defense |] player.Defenses )
|
||||
let! _ = players.UpdateOneAsync(filter, update) |> Async.AwaitTask
|
||||
do! DbService.updatePlayer <| { player with Defenses = Array.append [| defense |] player.Defenses }
|
||||
|
||||
let builder = DiscordMessageBuilder()
|
||||
builder.WithContent($"{event.User.Username} has protected their system!") |> ignore
|
||||
@ -220,7 +180,7 @@ let handleDefense (event : ComponentInteractionCreateEventArgs) =
|
||||
|> Async.AwaitTask
|
||||
}
|
||||
|
||||
let handleButtonEvent (client : DiscordClient) (event : ComponentInteractionCreateEventArgs) =
|
||||
let handleButtonEvent (_ : DiscordClient) (event : ComponentInteractionCreateEventArgs) =
|
||||
async {
|
||||
return! match event.Id with
|
||||
| id when id.StartsWith("Attack") -> handleAttack event
|
||||
|
@ -14,7 +14,6 @@
|
||||
<ReferencePathWithRefAssemblies Update="\home\joe\.nuget\packages\dsharpplus.slashcommands\4.2.0-nightly-01054\lib\netstandard2.0\DSharpPlus.SlashCommands.dll" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Functions.fs" />
|
||||
<Compile Include="Commands.fs" />
|
||||
<Compile Include="Program.fs" />
|
||||
<Content Include="paket.references" />
|
||||
|
@ -18,12 +18,6 @@ type HackerGame() =
|
||||
[<SlashCommand("defend", "Create a passive defense that will last a certain amount of time")>]
|
||||
member this.DefendCommand (ctx : InteractionContext) = Commands.defend ctx
|
||||
|
||||
[<SlashCommand("status", "Get your current status like bank account, and active hacks and defenses")>]
|
||||
member this.Status (ctx : InteractionContext) = Commands.status ctx
|
||||
|
||||
[<SlashCommand("leaderboard", "View the current list of players ranked by highest earnings")>]
|
||||
member this.Leaderboard (ctx : InteractionContext) = Commands.leaderboard ctx
|
||||
|
||||
let config = DiscordConfiguration()
|
||||
config.Token <- "OTIyNDIyMDIyMTI1MDEwOTU1.YcBOcw.JxfW1CSIwEO7j6RbRFCnPZ-HoTk"
|
||||
config.TokenType <- TokenType.Bot
|
||||
|
@ -4,6 +4,7 @@
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
||||
<RootNamespace>PlayerRegistration</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Program.fs" />
|
@ -1,8 +1,9 @@
|
||||
|
||||
open System
|
||||
open System.Threading.Tasks
|
||||
open DegenzGame.DbService
|
||||
open DSharpPlus.Entities
|
||||
open DSharpPlus
|
||||
open DSharpPlus.SlashCommands
|
||||
open DegenzGame
|
||||
open DegenzGame.Shared
|
||||
|
||||
module Commands =
|
||||
@ -30,14 +31,14 @@ module Commands =
|
||||
|
||||
let addHackerRole (ctx : InteractionContext) =
|
||||
async {
|
||||
let! player = tryFindPlayer ctx.Member.Id
|
||||
let! player = DbService.tryFindPlayer ctx.Member.Id
|
||||
let! newPlayer =
|
||||
match player with
|
||||
| Some _ -> async.Return false
|
||||
| None ->
|
||||
async {
|
||||
do! newPlayer ctx.Member.Username ctx.Member.Id
|
||||
|> insertNewPlayer
|
||||
|> DbService.insertNewPlayer
|
||||
|
||||
for role in ctx.Guild.Roles do
|
||||
if role.Value.Name = "Hacker" then
|
||||
@ -64,13 +65,44 @@ module Commands =
|
||||
do! ctx.Member.RevokeRoleAsync(role)
|
||||
|> Async.AwaitTask
|
||||
|
||||
do! removePlayer ctx.Member.Id
|
||||
do! DbService.removePlayer ctx.Member.Id
|
||||
|
||||
do! ctx.CreateResponseAsync("You are now lame", true)
|
||||
|> Async.AwaitTask
|
||||
} |> Async.StartAsTask
|
||||
:> Task
|
||||
|
||||
let leaderboard (ctx : InteractionContext) =
|
||||
async {
|
||||
let builder = DiscordInteractionResponseBuilder()
|
||||
builder.IsEphemeral <- true
|
||||
|
||||
let! leaders = DbService.getTopPlayers 10
|
||||
let content =
|
||||
leaders
|
||||
|> Seq.toArray
|
||||
|> Array.mapi (fun i p -> $"{i + 1}. {p.Bank} {p.Name}")
|
||||
|> String.concat "\n"
|
||||
builder.Content <- if not <| String.IsNullOrEmpty content then content else "There are no active hackers"
|
||||
do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder)
|
||||
|> Async.AwaitTask
|
||||
} |> Async.StartAsTask
|
||||
:> Task
|
||||
|
||||
let status (ctx : InteractionContext) =
|
||||
async {
|
||||
let! player = DbService.tryFindPlayer ctx.Member.Id
|
||||
match player with
|
||||
| Some p ->
|
||||
let builder = DiscordInteractionResponseBuilder()
|
||||
builder.IsEphemeral <- true
|
||||
builder.Content <- statusFormat p
|
||||
do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder)
|
||||
|> Async.AwaitTask
|
||||
| None -> do! notYetAHackerMsg ctx
|
||||
} |> Async.StartAsTask
|
||||
:> Task
|
||||
|
||||
|
||||
type EmptyGlobalCommandToAvoidFamousDuplicateSlashCommandsBug() = inherit ApplicationCommandModule ()
|
||||
|
||||
@ -83,6 +115,12 @@ type PlayerRegistration() =
|
||||
[<SlashCommand("bluepill", "Take the bluepill and become lame")>]
|
||||
member _.RemoveHackerRole (ctx : InteractionContext) = Commands.removeHackerRole ctx
|
||||
|
||||
[<SlashCommand("status", "Get your current status like bank account, and active hacks and defenses")>]
|
||||
member this.Status (ctx : InteractionContext) = Commands.status ctx
|
||||
|
||||
[<SlashCommand("leaderboard", "View the current list of players ranked by highest earnings")>]
|
||||
member this.Leaderboard (ctx : InteractionContext) = Commands.leaderboard ctx
|
||||
|
||||
|
||||
let config = DiscordConfiguration()
|
||||
config.Token <- "OTIyNDIyMDIyMTI1MDEwOTU1.YcBOcw.JxfW1CSIwEO7j6RbRFCnPZ-HoTk"
|
@ -1,9 +1,80 @@
|
||||
module DegenzGame.Functions
|
||||
module DegenzGame.Shared
|
||||
|
||||
open System
|
||||
open DSharpPlus
|
||||
open DSharpPlus.Entities
|
||||
open DegenzGame.Shared
|
||||
open DSharpPlus.SlashCommands
|
||||
|
||||
type ActionClass =
|
||||
| Network
|
||||
| Exploit
|
||||
| Penetration
|
||||
|
||||
type Weapon =
|
||||
| Virus = 0
|
||||
| Ransom = 1
|
||||
| Worm = 2
|
||||
| DDos = 3
|
||||
| Crack = 4
|
||||
| Injection = 5
|
||||
|
||||
type Shield =
|
||||
| Firewall = 0
|
||||
| PortScan = 1
|
||||
| Encryption = 2
|
||||
| Hardening = 4
|
||||
| Sanitation = 5
|
||||
| Cypher = 3
|
||||
|
||||
let getClass = function
|
||||
| 0 | 1 -> Network
|
||||
| 2 | 3 -> Exploit
|
||||
| 4 | _ -> Penetration
|
||||
|
||||
type HackResult =
|
||||
| Strong
|
||||
| Weak
|
||||
|
||||
[<CLIMutable>]
|
||||
type DiscordPlayer = {
|
||||
Id : uint64
|
||||
Name : string
|
||||
}
|
||||
|
||||
[<CLIMutable>]
|
||||
type Attack = {
|
||||
HackType : Weapon
|
||||
Target : DiscordPlayer
|
||||
Timestamp : DateTime
|
||||
}
|
||||
|
||||
[<CLIMutable>]
|
||||
type Defense = {
|
||||
DefenseType : Shield
|
||||
Timestamp : DateTime
|
||||
}
|
||||
|
||||
[<CLIMutable>]
|
||||
type Player = {
|
||||
DiscordId : uint64
|
||||
Name : string
|
||||
Weapons : Weapon array
|
||||
Shields : Shield array
|
||||
Attacks : Attack array
|
||||
Defenses : Defense array
|
||||
Bank : single
|
||||
}
|
||||
|
||||
let createSimpleResponseAsync msg (ctx : InteractionContext) =
|
||||
async {
|
||||
let builder = DiscordInteractionResponseBuilder()
|
||||
builder.Content <- msg
|
||||
builder.AsEphemeral true |> ignore
|
||||
do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder)
|
||||
|> Async.AwaitTask
|
||||
}
|
||||
|
||||
let notYetAHackerMsg = createSimpleResponseAsync "You are not currently a hacker, first use the /redpill command to become one"
|
||||
|
||||
let hackDescription = ""
|
||||
|
@ -5,7 +5,7 @@
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Types.fs" />
|
||||
<Compile Include="Shared.fs" />
|
||||
<Content Include="paket.references" />
|
||||
</ItemGroup>
|
||||
<Import Project="..\.paket\Paket.Restore.targets" />
|
||||
|
@ -1,77 +0,0 @@
|
||||
module DegenzGame.Shared
|
||||
|
||||
open System
|
||||
open DSharpPlus
|
||||
open DSharpPlus.Entities
|
||||
open DSharpPlus.SlashCommands
|
||||
|
||||
type ActionClass =
|
||||
| Network
|
||||
| Exploit
|
||||
| Penetration
|
||||
|
||||
type Weapon =
|
||||
| Virus = 0
|
||||
| Ransom = 1
|
||||
| Worm = 2
|
||||
| DDos = 3
|
||||
| Crack = 4
|
||||
| Injection = 5
|
||||
|
||||
type Shield =
|
||||
| Firewall = 0
|
||||
| PortScan = 1
|
||||
| Encryption = 2
|
||||
| Hardening = 4
|
||||
| Sanitation = 5
|
||||
| Cypher = 3
|
||||
|
||||
let getClass = function
|
||||
| 0 | 1 -> Network
|
||||
| 2 | 3 -> Exploit
|
||||
| 4 | _ -> Penetration
|
||||
|
||||
type HackResult =
|
||||
| Strong
|
||||
| Weak
|
||||
|
||||
[<CLIMutable>]
|
||||
type DiscordPlayer = {
|
||||
Id : uint64
|
||||
Name : string
|
||||
}
|
||||
|
||||
[<CLIMutable>]
|
||||
type Attack = {
|
||||
HackType : Weapon
|
||||
Target : DiscordPlayer
|
||||
Timestamp : DateTime
|
||||
}
|
||||
|
||||
[<CLIMutable>]
|
||||
type Defense = {
|
||||
DefenseType : Shield
|
||||
Timestamp : DateTime
|
||||
}
|
||||
|
||||
[<CLIMutable>]
|
||||
type Player = {
|
||||
DiscordId : uint64
|
||||
Name : string
|
||||
Weapons : Weapon array
|
||||
Shields : Shield array
|
||||
Attacks : Attack array
|
||||
Defenses : Defense array
|
||||
Bank : single
|
||||
}
|
||||
|
||||
let createSimpleResponseAsync msg (ctx : InteractionContext) =
|
||||
async {
|
||||
let builder = DiscordInteractionResponseBuilder()
|
||||
builder.Content <- msg
|
||||
builder.AsEphemeral true |> ignore
|
||||
do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder)
|
||||
|> Async.AwaitTask
|
||||
}
|
||||
|
||||
let notYetAHackerMsg = createSimpleResponseAsync "You are not currently a hacker, first use the /redpill command to become one"
|
Loading…
x
Reference in New Issue
Block a user