Restructuring project for new bots
This commit is contained in:
parent
5ccb4b730f
commit
e40fc42482
287
Commands.fs
287
Commands.fs
@ -1,287 +0,0 @@
|
||||
module Joebot.Commands
|
||||
|
||||
open System
|
||||
open System.Threading.Tasks
|
||||
open DSharpPlus
|
||||
open DSharpPlus.Entities
|
||||
open DSharpPlus.EventArgs
|
||||
open DSharpPlus.SlashCommands
|
||||
open Joebot.Types
|
||||
open Joebot.Functions
|
||||
|
||||
let mutable players : Player list = []
|
||||
|
||||
[<Literal>]
|
||||
let battleChannel = 930363007781978142uL
|
||||
|
||||
let addHackerRole (ctx : InteractionContext) =
|
||||
async {
|
||||
for role in ctx.Guild.Roles do
|
||||
if role.Value.Name = "Hacker" then
|
||||
do! ctx.Member.GrantRoleAsync(role.Value)
|
||||
|> Async.AwaitTask
|
||||
|
||||
let player = players |> List.tryFind (fun p -> int64 p.DiscordId = int64 ctx.Member.Id)
|
||||
players <-
|
||||
match player with
|
||||
| Some _ -> players
|
||||
| None -> (newPlayer ctx.Member.Username ctx.Member.Id)::players
|
||||
|
||||
if Option.isSome player then
|
||||
do! ctx.CreateResponseAsync("Already registered as an elite haxxor", true)
|
||||
|> Async.AwaitTask
|
||||
else
|
||||
do! ctx.CreateResponseAsync("You are now an elite haxxor", true)
|
||||
|> Async.AwaitTask
|
||||
|
||||
} |> Async.StartAsTask
|
||||
:> Task
|
||||
|
||||
let removeHackerRole (ctx : InteractionContext) =
|
||||
async {
|
||||
for role in ctx.Member.Roles do
|
||||
if role.Name = "Hacker" then
|
||||
do! ctx.Member.RevokeRoleAsync(role)
|
||||
|> Async.AwaitTask
|
||||
players <- players |> List.filter (fun p -> p.DiscordId <> ctx.User.Id)
|
||||
do! ctx.CreateResponseAsync("You are now lame", true)
|
||||
|> Async.AwaitTask
|
||||
} |> Async.StartAsTask
|
||||
:> Task
|
||||
|
||||
let attack (ctx : InteractionContext) (target : DiscordUser) =
|
||||
// TODO: We need to check if the player has any active embed hacks going, if not they can cheat
|
||||
let attacker = players |> List.tryFind (fun p -> p.DiscordId = ctx.Member.Id)
|
||||
let defender = players |> List.tryFind (fun p -> p.DiscordId = target.Id)
|
||||
match attacker , defender with
|
||||
| Some attacker , Some defender ->
|
||||
let updatedAttacks = removeExpiredActions (TimeSpan.FromMinutes(5)) (fun (atk : Attack) -> atk.Timestamp) attacker.Attacks
|
||||
players <-
|
||||
players
|
||||
|> List.map (fun p -> if p.DiscordId = attacker.DiscordId then { p with Attacks = updatedAttacks } else p)
|
||||
if updatedAttacks.Length < 2 then
|
||||
async {
|
||||
let builder = DiscordInteractionResponseBuilder()
|
||||
builder.AddEmbed (constructEmbed "Pick the hack you wish to use.") |> ignore
|
||||
|
||||
let defenderInfo = $"{defender.DiscordId}-{target.Username}"
|
||||
constructButtons "Attack" defenderInfo attacker.Weapons
|
||||
|> Seq.cast<DiscordComponent>
|
||||
|> builder.AddComponents
|
||||
|> ignore
|
||||
|
||||
builder.AsEphemeral true |> ignore
|
||||
|
||||
do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder)
|
||||
|> Async.AwaitTask
|
||||
|
||||
} |> Async.StartAsTask
|
||||
:> Task
|
||||
else
|
||||
async {
|
||||
let builder = DiscordInteractionResponseBuilder()
|
||||
let timestamp = updatedAttacks |> List.rev |> List.head |> fun a -> a.Timestamp // This should be the next expiring timestamp
|
||||
let timeRemaining = TimeSpan.FromMinutes(15) - (DateTime.UtcNow - timestamp)
|
||||
builder.Content <- $"No more hacks available, please wait {timeRemaining.Minutes} minutes and {timeRemaining.Seconds} seconds to attempt another hack"
|
||||
|
||||
builder.AsEphemeral true |> ignore
|
||||
|
||||
do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder)
|
||||
|> Async.AwaitTask
|
||||
|
||||
} |> Async.StartAsTask
|
||||
:> Task
|
||||
| None , _ -> notYetAHackerMsg ctx
|
||||
| _ , None -> createSimpleResponseAsync "Your target is not connected to the network, they must join first by using the /redpill command" ctx
|
||||
|
||||
let defend (ctx : InteractionContext) =
|
||||
players
|
||||
|> List.tryFind (fun p -> p.DiscordId = ctx.Member.Id)
|
||||
|> function
|
||||
| Some player ->
|
||||
async {
|
||||
let updatedDefenses = removeExpiredActions (TimeSpan.FromMinutes(60)) (fun (pro : Defense) -> pro.Timestamp) player.Defenses
|
||||
players <-
|
||||
players
|
||||
|> List.map (fun p -> if p.DiscordId = player.DiscordId then { p with Defenses = updatedDefenses } else p)
|
||||
if updatedDefenses.Length < 2 then
|
||||
let builder = DiscordInteractionResponseBuilder()
|
||||
builder.AddEmbed (constructEmbed "Pick a defense to mount for a duration of time") |> ignore
|
||||
|
||||
constructButtons "Defend" (string player.DiscordId) player.Shields
|
||||
|> Seq.cast<DiscordComponent>
|
||||
|> builder.AddComponents
|
||||
|> ignore
|
||||
|
||||
builder.AsEphemeral true |> ignore
|
||||
|
||||
do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder)
|
||||
|> Async.AwaitTask
|
||||
else
|
||||
let builder = DiscordInteractionResponseBuilder()
|
||||
let timestamp = updatedDefenses |> List.rev |> List.head |> fun a -> a.Timestamp // This should be the next expiring timestamp
|
||||
let timeRemaining = TimeSpan.FromMinutes(15) - (DateTime.UtcNow - timestamp)
|
||||
builder.Content <- $"Cannot add new defense, please wait {timeRemaining.Minutes} minutes and {timeRemaining.Seconds} seconds to add another defense"
|
||||
|
||||
builder.AsEphemeral true |> ignore
|
||||
|
||||
do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder)
|
||||
|> Async.AwaitTask
|
||||
|
||||
} |> Async.StartAsTask
|
||||
:> Task
|
||||
| None -> notYetAHackerMsg ctx
|
||||
|
||||
let status (ctx : InteractionContext) =
|
||||
async {
|
||||
return!
|
||||
match players |> List.tryFind (fun p -> p.DiscordId = ctx.Member.Id) with
|
||||
| Some player ->
|
||||
async {
|
||||
let builder = DiscordInteractionResponseBuilder()
|
||||
builder.IsEphemeral <- true
|
||||
builder.Content <- Functions.statusFormat player
|
||||
do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder)
|
||||
|> Async.AwaitTask
|
||||
}
|
||||
| None -> notYetAHackerMsg ctx |> Async.AwaitTask
|
||||
} |> Async.StartAsTask
|
||||
:> Task
|
||||
|
||||
let leaderboard (ctx : InteractionContext) =
|
||||
async {
|
||||
let builder = DiscordInteractionResponseBuilder()
|
||||
builder.IsEphemeral <- true
|
||||
let content =
|
||||
players
|
||||
|> List.sortByDescending (fun p -> p.Bank)
|
||||
|> List.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 = attack::p.Attacks
|
||||
Bank = MathF.Max(p.Bank + amount, 0f)
|
||||
}
|
||||
async {
|
||||
let split = event.Id.Split("-")
|
||||
let resultHack = Weapon.TryParse(split.[1])
|
||||
let ( resultId , targetId ) = UInt64.TryParse split.[2]
|
||||
return!
|
||||
match resultHack , resultId with
|
||||
| Some weapon , true ->
|
||||
let hackType = weapon
|
||||
players
|
||||
|> List.find (fun p -> p.DiscordId = targetId)
|
||||
|> fun p -> p.Defenses
|
||||
|> List.map (fun dfn -> dfn.DefenseType)
|
||||
|> List.map (calculateDamage hackType)
|
||||
|> List.contains Weak
|
||||
|> function
|
||||
| false ->
|
||||
async {
|
||||
let prize = 0.1726f
|
||||
let attack = { HackType = hackType ; Timestamp = DateTime.UtcNow ; Target = { Id = targetId ; Name = split.[3] } }
|
||||
players <-
|
||||
players
|
||||
|> List.map (fun p -> if p.DiscordId = event.User.Id then updatePlayer prize attack p else p)
|
||||
|
||||
let builder = DiscordInteractionResponseBuilder()
|
||||
builder.IsEphemeral <- true
|
||||
builder.Content <- $"Successfully hacked {split.[3]} using {hackType}! You just won {prize} genz!"
|
||||
do! event.Interaction.CreateResponseAsync(InteractionResponseType.UpdateMessage, builder)
|
||||
|> Async.AwaitTask
|
||||
|
||||
let builder = DiscordMessageBuilder()
|
||||
builder.WithContent($"{event.User.Username} successfully hacked <@{targetId}>!") |> ignore
|
||||
let channel = (event.Guild.GetChannel(battleChannel))
|
||||
do! channel.SendMessageAsync(builder)
|
||||
|> Async.AwaitTask
|
||||
|> Async.Ignore
|
||||
}
|
||||
| true ->
|
||||
async {
|
||||
let builder = DiscordInteractionResponseBuilder()
|
||||
let loss = -0.0623f
|
||||
builder.IsEphemeral <- true
|
||||
builder.Content <- $"Hack failed! {split.[3]} was able to mount a successful defense! You lost {loss} genz!"
|
||||
do! event.Interaction.CreateResponseAsync(InteractionResponseType.UpdateMessage, builder)
|
||||
|> Async.AwaitTask
|
||||
|
||||
let attack = { HackType = hackType ; Timestamp = DateTime.UtcNow ; Target = { Id = targetId ; Name = split.[3] } }
|
||||
players <-
|
||||
players
|
||||
|> List.map (fun p -> if p.DiscordId = event.User.Id then updatePlayer loss attack p else p)
|
||||
|
||||
let builder = DiscordMessageBuilder()
|
||||
builder.WithContent($"{event.User.Username} failed to hack <@{targetId}>!") |> ignore
|
||||
let channel = (event.Guild.GetChannel(battleChannel))
|
||||
do! channel.SendMessageAsync(builder)
|
||||
|> Async.AwaitTask
|
||||
|> Async.Ignore
|
||||
}
|
||||
| _ ->
|
||||
async {
|
||||
let builder = DiscordInteractionResponseBuilder()
|
||||
builder.IsEphemeral <- true
|
||||
builder.Content <- "Error parsing Button Id"
|
||||
do! event.Interaction.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder)
|
||||
|> Async.AwaitTask
|
||||
}
|
||||
}
|
||||
|
||||
let handleDefense (event : ComponentInteractionCreateEventArgs) =
|
||||
async {
|
||||
let split = event.Id.Split("-")
|
||||
return!
|
||||
match Shield.TryParse(split.[1]) with
|
||||
| Some shield ->
|
||||
async {
|
||||
let builder = DiscordInteractionResponseBuilder()
|
||||
builder.IsEphemeral <- true
|
||||
builder.Content <- $"Mounted a {shield} defense for 1 hour"
|
||||
do! event.Interaction.CreateResponseAsync(InteractionResponseType.UpdateMessage, builder)
|
||||
|> Async.AwaitTask
|
||||
|
||||
let defense = { DefenseType = shield ; Timestamp = DateTime.UtcNow }
|
||||
players <-
|
||||
players
|
||||
|> List.map (fun p -> { p with Defenses = defense::p.Defenses })
|
||||
|
||||
let builder = DiscordMessageBuilder()
|
||||
builder.WithContent($"{event.User.Username} has protected their system!") |> ignore
|
||||
let channel = (event.Guild.GetChannel(battleChannel))
|
||||
do! channel.SendMessageAsync(builder)
|
||||
|> Async.AwaitTask
|
||||
|> Async.Ignore
|
||||
}
|
||||
| _ ->
|
||||
async {
|
||||
let builder = DiscordInteractionResponseBuilder()
|
||||
builder.IsEphemeral <- true
|
||||
builder.Content <- "Error parsing Button Id"
|
||||
do! event.Interaction.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder)
|
||||
|> Async.AwaitTask
|
||||
}
|
||||
}
|
||||
|
||||
let handleButtonEvent (client : DiscordClient) (event : ComponentInteractionCreateEventArgs) =
|
||||
async {
|
||||
return! match event.Id with
|
||||
| id when id.StartsWith("Attack") -> handleAttack event
|
||||
| id when id.StartsWith("Defend") -> handleDefense event
|
||||
| _ ->
|
||||
async {
|
||||
let builder = DiscordInteractionResponseBuilder()
|
||||
builder.IsEphemeral <- true
|
||||
builder.Content <- $"Incorrect Action identifier {event.Id}"
|
||||
do! event.Interaction.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder)
|
||||
|> Async.AwaitTask
|
||||
}
|
||||
} |> Async.StartAsTask
|
||||
:> Task
|
34
Degenz.sln
Normal file
34
Degenz.sln
Normal file
@ -0,0 +1,34 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.30114.105
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "HackerBattle", "HackerBattle\HackerBattle.fsproj", "{2A437756-3D5D-467D-9497-DF9789DB99CC}"
|
||||
EndProject
|
||||
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Shared", "Shared\Shared.fsproj", "{5F34C24E-BA4E-4E57-9141-812775687360}"
|
||||
EndProject
|
||||
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Store", "Store\Store.fsproj", "{CD88B0A6-DE42-4087-9B33-48FF84201633}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{2A437756-3D5D-467D-9497-DF9789DB99CC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{2A437756-3D5D-467D-9497-DF9789DB99CC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{2A437756-3D5D-467D-9497-DF9789DB99CC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{2A437756-3D5D-467D-9497-DF9789DB99CC}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{5F34C24E-BA4E-4E57-9141-812775687360}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{5F34C24E-BA4E-4E57-9141-812775687360}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{5F34C24E-BA4E-4E57-9141-812775687360}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{5F34C24E-BA4E-4E57-9141-812775687360}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{CD88B0A6-DE42-4087-9B33-48FF84201633}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{CD88B0A6-DE42-4087-9B33-48FF84201633}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{CD88B0A6-DE42-4087-9B33-48FF84201633}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{CD88B0A6-DE42-4087-9B33-48FF84201633}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
EndGlobal
|
25
HackerBattle/.dockerignore
Normal file
25
HackerBattle/.dockerignore
Normal file
@ -0,0 +1,25 @@
|
||||
**/.dockerignore
|
||||
**/.env
|
||||
**/.git
|
||||
**/.gitignore
|
||||
**/.project
|
||||
**/.settings
|
||||
**/.toolstarget
|
||||
**/.vs
|
||||
**/.vscode
|
||||
**/.idea
|
||||
**/*.*proj.user
|
||||
**/*.dbmdl
|
||||
**/*.jfm
|
||||
**/azds.yaml
|
||||
**/bin
|
||||
**/charts
|
||||
**/docker-compose*
|
||||
**/Dockerfile*
|
||||
**/node_modules
|
||||
**/npm-debug.log
|
||||
**/obj
|
||||
**/secrets.dev.yaml
|
||||
**/values.dev.yaml
|
||||
LICENSE
|
||||
README.md
|
290
HackerBattle/Commands.fs
Normal file
290
HackerBattle/Commands.fs
Normal file
@ -0,0 +1,290 @@
|
||||
module DegenzGame.Commands
|
||||
|
||||
open System
|
||||
open System.Threading.Tasks
|
||||
open DSharpPlus
|
||||
open DSharpPlus.Entities
|
||||
open DSharpPlus.EventArgs
|
||||
open DSharpPlus.SlashCommands
|
||||
open DegenzGame.Types
|
||||
open DegenzGame.Functions
|
||||
open MongoDB.Driver
|
||||
|
||||
[<Literal>]
|
||||
// Degenz Server
|
||||
//let battleChannel = 930363007781978142uL
|
||||
// My server
|
||||
let battleChannel = 927449884204867664uL
|
||||
|
||||
let mongo = MongoClient("mongodb://localhost:27017")
|
||||
let db = mongo.GetDatabase("degenz-game")
|
||||
let players = db.GetCollection<Player>("players")
|
||||
|
||||
let tryFindPlayer (id : uint64) : Async<Player option> =
|
||||
async {
|
||||
let filter = Builders<Player>.Filter.Eq((fun p -> p.DiscordId), id)
|
||||
let! player = players.FindAsync<Player>(filter) |> Async.AwaitTask
|
||||
return match player.ToEnumerable() |> Seq.toList with
|
||||
| [] -> None
|
||||
| p::_ -> Some p
|
||||
}
|
||||
|
||||
let addHackerRole (ctx : InteractionContext) =
|
||||
async {
|
||||
let! player = tryFindPlayer ctx.Member.Id
|
||||
let! newPlayer =
|
||||
match player with
|
||||
| Some _ -> async.Return false
|
||||
| None ->
|
||||
async {
|
||||
let p = (newPlayer ctx.Member.Username ctx.Member.Id)
|
||||
do! players.InsertOneAsync p |> Async.AwaitTask
|
||||
|
||||
for role in ctx.Guild.Roles do
|
||||
if role.Value.Name = "Hacker" then
|
||||
do! ctx.Member.GrantRoleAsync(role.Value)
|
||||
|> Async.AwaitTask
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
if newPlayer then
|
||||
do! ctx.CreateResponseAsync("You are now an elite haxxor", true)
|
||||
|> Async.AwaitTask
|
||||
else
|
||||
do! ctx.CreateResponseAsync("Already registered as an elite haxxor", true)
|
||||
|> Async.AwaitTask
|
||||
|
||||
} |> Async.StartAsTask
|
||||
:> Task
|
||||
|
||||
let removeHackerRole (ctx : InteractionContext) =
|
||||
async {
|
||||
for role in ctx.Member.Roles do
|
||||
if role.Name = "Hacker" then
|
||||
do! ctx.Member.RevokeRoleAsync(role)
|
||||
|> Async.AwaitTask
|
||||
// TODO: Check the result of this delete operation
|
||||
let! _ = players.DeleteOneAsync (fun p -> p.DiscordId = ctx.Member.Id) |> Async.AwaitTask
|
||||
do! ctx.CreateResponseAsync("You are now lame", true)
|
||||
|> Async.AwaitTask
|
||||
} |> Async.StartAsTask
|
||||
:> Task
|
||||
|
||||
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
|
||||
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
|
||||
if updatedAttacks.Length < 2 then
|
||||
let builder = DiscordInteractionResponseBuilder()
|
||||
builder.AddEmbed (constructEmbed "Pick the hack you wish to use.") |> ignore
|
||||
|
||||
let defenderInfo = $"{defender.DiscordId}-{target.Username}"
|
||||
constructButtons "Attack" defenderInfo attacker.Weapons
|
||||
|> Seq.cast<DiscordComponent>
|
||||
|> builder.AddComponents
|
||||
|> ignore
|
||||
|
||||
builder.AsEphemeral true |> ignore
|
||||
|
||||
do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder)
|
||||
|> Async.AwaitTask
|
||||
|
||||
else
|
||||
let builder = DiscordInteractionResponseBuilder()
|
||||
let timestamp = updatedAttacks |> Array.rev |> Array.head |> fun a -> a.Timestamp // This should be the next expiring timestamp
|
||||
let timeRemaining = TimeSpan.FromMinutes(15) - (DateTime.UtcNow - timestamp)
|
||||
builder.Content <- $"No more hacks available, please wait {timeRemaining.Minutes} minutes and {timeRemaining.Seconds} seconds to attempt another hack"
|
||||
|
||||
builder.AsEphemeral true |> ignore
|
||||
|
||||
do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder)
|
||||
|> Async.AwaitTask
|
||||
|
||||
| None , _ -> do! notYetAHackerMsg ctx
|
||||
| _ , None -> do! createSimpleResponseAsync "Your target is not connected to the network, they must join first by using the /redpill command" ctx
|
||||
} |> Async.StartAsTask
|
||||
:> Task
|
||||
|
||||
let defend (ctx : InteractionContext) =
|
||||
async {
|
||||
let! player = 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
|
||||
if updatedDefenses.Length < 2 then
|
||||
let builder = DiscordInteractionResponseBuilder()
|
||||
builder.AddEmbed (constructEmbed "Pick a defense to mount for a duration of time") |> ignore
|
||||
|
||||
constructButtons "Defend" (string player.DiscordId) player.Shields
|
||||
|> Seq.cast<DiscordComponent>
|
||||
|> builder.AddComponents
|
||||
|> ignore
|
||||
|
||||
builder.AsEphemeral true |> ignore
|
||||
|
||||
do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder)
|
||||
|> Async.AwaitTask
|
||||
else
|
||||
let builder = DiscordInteractionResponseBuilder()
|
||||
let timestamp = updatedDefenses |> Array.rev |> Array.head |> fun a -> a.Timestamp // This should be the next expiring timestamp
|
||||
let timeRemaining = TimeSpan.FromMinutes(15) - (DateTime.UtcNow - timestamp)
|
||||
builder.Content <- $"Cannot add new defense, please wait {timeRemaining.Minutes} minutes and {timeRemaining.Seconds} seconds to add another defense"
|
||||
|
||||
builder.AsEphemeral true |> ignore
|
||||
|
||||
do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder)
|
||||
|> Async.AwaitTask
|
||||
| None -> do! notYetAHackerMsg ctx
|
||||
} |> 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) }
|
||||
async {
|
||||
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
|
||||
match resultPlayer , resultTarget , resultHack , resultId with
|
||||
| Some player , Some target , true , true ->
|
||||
let wasSuccessfulHack =
|
||||
target.Defenses
|
||||
|> Seq.toArray
|
||||
|> Array.map (fun dfn -> int dfn.DefenseType)
|
||||
|> Array.map (calculateDamage weapon)
|
||||
|> Array.contains Weak
|
||||
match wasSuccessfulHack with
|
||||
| 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
|
||||
|
||||
let builder = DiscordInteractionResponseBuilder()
|
||||
builder.IsEphemeral <- true
|
||||
builder.Content <- $"Successfully hacked {split.[3]} using {weapon}! You just won {prize} genz!"
|
||||
do! event.Interaction.CreateResponseAsync(InteractionResponseType.UpdateMessage, builder)
|
||||
|> Async.AwaitTask
|
||||
|
||||
let builder = DiscordMessageBuilder()
|
||||
builder.WithContent($"{event.User.Username} successfully hacked <@{targetId}>!") |> ignore
|
||||
let channel = (event.Guild.GetChannel(battleChannel))
|
||||
do! channel.SendMessageAsync(builder)
|
||||
|> Async.AwaitTask
|
||||
|> Async.Ignore
|
||||
| true ->
|
||||
let builder = DiscordInteractionResponseBuilder()
|
||||
let loss = -0.0623f
|
||||
builder.IsEphemeral <- true
|
||||
builder.Content <- $"Hack failed! {split.[3]} was able to mount a successful defense! You lost {loss} genz!"
|
||||
do! event.Interaction.CreateResponseAsync(InteractionResponseType.UpdateMessage, builder)
|
||||
|> 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
|
||||
|
||||
let builder = DiscordMessageBuilder()
|
||||
builder.WithContent($"{event.User.Username} failed to hack <@{targetId}>!") |> ignore
|
||||
let channel = (event.Guild.GetChannel(battleChannel))
|
||||
do! channel.SendMessageAsync(builder)
|
||||
|> Async.AwaitTask
|
||||
|> Async.Ignore
|
||||
| _ ->
|
||||
let builder = DiscordInteractionResponseBuilder()
|
||||
builder.IsEphemeral <- true
|
||||
builder.Content <- "Error occurred processing attack"
|
||||
do! event.Interaction.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder)
|
||||
|> Async.AwaitTask
|
||||
}
|
||||
|
||||
let handleDefense (event : ComponentInteractionCreateEventArgs) =
|
||||
async {
|
||||
let split = event.Id.Split("-")
|
||||
let ( shieldResult , shield ) = Shield.TryParse(split.[1])
|
||||
let! playerResult = tryFindPlayer event.User.Id
|
||||
match playerResult , shieldResult with
|
||||
| Some player , true ->
|
||||
let builder = DiscordInteractionResponseBuilder()
|
||||
builder.IsEphemeral <- true
|
||||
builder.Content <- $"Mounted a {shield} defense for 1 hour"
|
||||
do! event.Interaction.CreateResponseAsync(InteractionResponseType.UpdateMessage, builder)
|
||||
|> 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
|
||||
|
||||
let builder = DiscordMessageBuilder()
|
||||
builder.WithContent($"{event.User.Username} has protected their system!") |> ignore
|
||||
let channel = event.Guild.Channels.Values |> Seq.find (fun c -> c.Name = "battle-1")
|
||||
do! channel.SendMessageAsync(builder)
|
||||
|> Async.AwaitTask
|
||||
|> Async.Ignore
|
||||
| _ ->
|
||||
let builder = DiscordInteractionResponseBuilder()
|
||||
builder.IsEphemeral <- true
|
||||
builder.Content <- "Error parsing Button Id"
|
||||
do! event.Interaction.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder)
|
||||
|> Async.AwaitTask
|
||||
}
|
||||
|
||||
let handleButtonEvent (client : DiscordClient) (event : ComponentInteractionCreateEventArgs) =
|
||||
async {
|
||||
return! match event.Id with
|
||||
| id when id.StartsWith("Attack") -> handleAttack event
|
||||
| id when id.StartsWith("Defend") -> handleDefense event
|
||||
| _ ->
|
||||
async {
|
||||
let builder = DiscordInteractionResponseBuilder()
|
||||
builder.IsEphemeral <- true
|
||||
builder.Content <- $"Incorrect Action identifier {event.Id}"
|
||||
do! event.Interaction.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder)
|
||||
|> Async.AwaitTask
|
||||
}
|
||||
} |> Async.StartAsTask
|
||||
:> Task
|
18
HackerBattle/Dockerfile
Normal file
18
HackerBattle/Dockerfile
Normal file
@ -0,0 +1,18 @@
|
||||
FROM mcr.microsoft.com/dotnet/runtime:6.0 AS base
|
||||
WORKDIR /app
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
|
||||
WORKDIR /src
|
||||
COPY ["HackerBattle/HackerBattle.fsproj", "HackerBattle/"]
|
||||
RUN dotnet restore "HackerBattle/HackerBattle.fsproj"
|
||||
COPY . .
|
||||
WORKDIR "/src/HackerBattle"
|
||||
RUN dotnet build "HackerBattle.fsproj" -c Release -o /app/build
|
||||
|
||||
FROM build AS publish
|
||||
RUN dotnet publish "HackerBattle.fsproj" -c Release -o /app/publish
|
||||
|
||||
FROM base AS final
|
||||
WORKDIR /app
|
||||
COPY --from=publish /app/publish .
|
||||
ENTRYPOINT ["dotnet", "HackerBattle.dll"]
|
@ -1,52 +1,52 @@
|
||||
module Joebot.Functions
|
||||
module DegenzGame.Functions
|
||||
|
||||
open System
|
||||
open System.Threading.Tasks
|
||||
open DSharpPlus
|
||||
open DSharpPlus.Entities
|
||||
open DSharpPlus.SlashCommands
|
||||
open Joebot.Types
|
||||
open DegenzGame.Types
|
||||
open MongoDB.Bson
|
||||
|
||||
let hackDescription = ""
|
||||
|
||||
|
||||
let statusFormat player =
|
||||
$"Hack Inventory: {player.Weapons}
|
||||
Shield Inventory: {player.Shields}
|
||||
Active Hacks: {player.Attacks}
|
||||
Active Defenses: {player.Defenses}
|
||||
Active Hacks: {player.Attacks |> Array.toList}
|
||||
Active Defenses: {player.Defenses |> Array.toList}
|
||||
Bank: {player.Bank}"
|
||||
|
||||
|
||||
let newPlayer nickname (membr : uint64) =
|
||||
let h1 = [| Virus ; Ransom |]
|
||||
let h2 = [| DDos ; Worm |]
|
||||
let h3 = [| Crack ; Injection |]
|
||||
let d1 = [| Firewall ; PortScan |]
|
||||
let d2 = [| Encryption ; Cypher |]
|
||||
let d3 = [| Hardening ; Sanitation |]
|
||||
|
||||
let h1 = [| Weapon.Virus ; Weapon.Ransom |]
|
||||
let h2 = [| Weapon.DDos ; Weapon.Worm |]
|
||||
let h3 = [| Weapon.Crack ; Weapon.Injection |]
|
||||
let d1 = [| Shield.Firewall ; Shield.PortScan |]
|
||||
let d2 = [| Shield.Encryption ; Shield.Cypher |]
|
||||
let d3 = [| Shield.Hardening ; Shield.Sanitation |]
|
||||
|
||||
let rand = System.Random(System.Guid.NewGuid().GetHashCode())
|
||||
let getRandom (actions : 'a array) = actions.[rand.Next(0,2)]
|
||||
|
||||
let weapons = [ getRandom h1 ; getRandom h2 ; getRandom h3 ]
|
||||
let shields = [ getRandom d1 ; getRandom d2 ; getRandom d3 ]
|
||||
|
||||
{ DiscordId = membr
|
||||
|
||||
let weapons = [| getRandom h1 ; getRandom h2 ; getRandom h3 |]
|
||||
let shields = [| getRandom d1 ; getRandom d2 ; getRandom d3 |]
|
||||
|
||||
{ Id = BsonObjectId(ObjectId.GenerateNewId())
|
||||
DiscordId = membr
|
||||
Name = nickname
|
||||
Weapons = weapons
|
||||
Shields = shields
|
||||
Attacks = []
|
||||
Defenses = []
|
||||
Attacks = [||]
|
||||
Defenses = [||]
|
||||
Bank = 0f }
|
||||
|
||||
let constructButtons (actionType : string) (playerInfo : string) (weapons : 'a list) =
|
||||
let constructButtons (actionType : string) (playerInfo : string) (weapons : 'a array) =
|
||||
weapons
|
||||
|> Seq.map (fun hack ->
|
||||
DiscordButtonComponent(
|
||||
ButtonStyle.Primary,
|
||||
$"{actionType}-{hack}-{playerInfo}",
|
||||
$"{hack}"))
|
||||
|
||||
|
||||
let createSimpleResponseAsync msg (ctx : InteractionContext) =
|
||||
async {
|
||||
let builder = DiscordInteractionResponseBuilder()
|
||||
@ -54,14 +54,13 @@ let createSimpleResponseAsync msg (ctx : InteractionContext) =
|
||||
builder.AsEphemeral true |> ignore
|
||||
do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder)
|
||||
|> Async.AwaitTask
|
||||
} |> Async.StartAsTask
|
||||
:> Task
|
||||
}
|
||||
|
||||
let notYetAHackerMsg = createSimpleResponseAsync "You are not currently a hacker, first use the /redpill command to become one"
|
||||
|
||||
let removeExpiredActions timespan (timestamp : 'a -> DateTime) actions =
|
||||
actions
|
||||
|> List.filter (fun act ->
|
||||
|> Array.filter (fun act ->
|
||||
if DateTime.UtcNow - (timestamp act) < timespan
|
||||
then true
|
||||
else false)
|
||||
@ -71,16 +70,16 @@ let constructEmbed message =
|
||||
builder.Color <- Optional(DiscordColor.PhthaloGreen)
|
||||
builder.Description <- message
|
||||
let author = DiscordEmbedBuilder.EmbedAuthor()
|
||||
author.Name <- "Joebot Pro"
|
||||
author.Name <- "Degenz Hacker Game"
|
||||
author.Url <- "https://twitter.com/degenzgame"
|
||||
author.IconUrl <- "https://pbs.twimg.com/profile_images/1473192843359309825/cqjm0VQ4_400x400.jpg"
|
||||
builder.Author <- author
|
||||
builder.Build()
|
||||
|
||||
let calculateDamage (hack : IClass) (protection : IClass) =
|
||||
let hackClass = hack.GetClass()
|
||||
let protectionClass = protection.GetClass()
|
||||
|
||||
let calculateDamage (hack : int) (shield : int) =
|
||||
let hackClass = getClass hack
|
||||
let protectionClass = getClass shield
|
||||
match hackClass , protectionClass with
|
||||
| h , p when h = p -> Weak
|
||||
| _ -> Strong
|
||||
|
||||
|
@ -3,21 +3,23 @@
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<RootNamespace>discord_bot</RootNamespace>
|
||||
<RootNamespace>hacker-game</RootNamespace>
|
||||
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="challenge.jpg">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include=".dockerignore" />
|
||||
<Content Include="Dockerfile" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ReferencePathWithRefAssemblies Update="\home\joe\.nuget\packages\dsharpplus.slashcommands\4.2.0-nightly-01054\lib\netstandard2.0\DSharpPlus.SlashCommands.dll" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Types.fs" />
|
||||
<Compile Include="Functions.fs" />
|
||||
<Compile Include="Commands.fs" />
|
||||
<Compile Include="Program.fs" />
|
||||
</ItemGroup>
|
||||
<Import Project=".paket\Paket.Restore.targets" />
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Shared\Shared.fsproj" />
|
||||
</ItemGroup>
|
||||
<Import Project="..\.paket\Paket.Restore.targets" />
|
||||
</Project>
|
@ -1,4 +1,4 @@
|
||||
module Joebot.Program
|
||||
module DegenzGame.Program
|
||||
|
||||
open System
|
||||
open System.Threading.Tasks
|
||||
@ -7,30 +7,31 @@ open DSharpPlus.Entities
|
||||
open DSharpPlus.EventArgs
|
||||
open DSharpPlus.SlashCommands
|
||||
open Emzi0767.Utilities
|
||||
open Joebot.Types
|
||||
open Joebot.Commands
|
||||
open DegenzGame.Types
|
||||
open DegenzGame.Commands
|
||||
open MongoDB.Driver
|
||||
|
||||
type EmptyGlobalCommandToAvoidFamousDuplicateSlashCommandsBug() = inherit ApplicationCommandModule ()
|
||||
|
||||
type JoeBot() =
|
||||
type HackerGame() =
|
||||
inherit ApplicationCommandModule ()
|
||||
|
||||
|
||||
[<SlashCommand("redpill", "Take the redpill and become a hacker")>]
|
||||
member _.AddHackerRole (ctx : InteractionContext) = Commands.addHackerRole ctx
|
||||
|
||||
|
||||
[<SlashCommand("bluepill", "Take the bluepill and become lame")>]
|
||||
member _.RemoveHackerRole (ctx : InteractionContext) = Commands.removeHackerRole ctx
|
||||
|
||||
|
||||
[<SlashCommand("hack", "Send a hack attack to another player")>]
|
||||
member this.AttackCommand (ctx : InteractionContext, [<Option("target", "The player you want to hack")>] target : DiscordUser) =
|
||||
Commands.attack ctx target
|
||||
|
||||
|
||||
[<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
|
||||
|
||||
@ -46,7 +47,10 @@ client.add_ComponentInteractionCreated(AsyncEventHandler(handleButtonEvent))
|
||||
|
||||
let slash = client.UseSlashCommands()
|
||||
|
||||
slash.RegisterCommands<JoeBot>(922414052708327494uL);
|
||||
// My server
|
||||
slash.RegisterCommands<HackerGame>(922419263275425832uL);
|
||||
// Degenz
|
||||
//slash.RegisterCommands<HackerGame>(922414052708327494uL);
|
||||
|
||||
client.ConnectAsync ()
|
||||
|> Async.AwaitTask
|
@ -3,4 +3,5 @@ DSharpPlus
|
||||
// DSharpPlus.CommandsNext
|
||||
// DSharpPlus.Interactivity
|
||||
DSharpPlus.SlashCommands
|
||||
LiteDB.FSharp
|
||||
|
||||
MongoDB.Driver
|
11
Shared/Shared.fsproj
Normal file
11
Shared/Shared.fsproj
Normal file
@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Types.fs" />
|
||||
</ItemGroup>
|
||||
<Import Project="..\.paket\Paket.Restore.targets" />
|
||||
</Project>
|
67
Shared/Types.fs
Normal file
67
Shared/Types.fs
Normal file
@ -0,0 +1,67 @@
|
||||
module DegenzGame.Types
|
||||
|
||||
open System
|
||||
open MongoDB.Bson
|
||||
|
||||
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 = {
|
||||
Id : BsonObjectId
|
||||
DiscordId : uint64
|
||||
Name : string
|
||||
Weapons : Weapon array
|
||||
Shields : Shield array
|
||||
Attacks : Attack array
|
||||
Defenses : Defense array
|
||||
Bank : single
|
||||
}
|
||||
|
||||
|
2
Shared/paket.references
Normal file
2
Shared/paket.references
Normal file
@ -0,0 +1,2 @@
|
||||
FSharp.Core
|
||||
MongoDB.Driver
|
25
Store/.dockerignore
Normal file
25
Store/.dockerignore
Normal file
@ -0,0 +1,25 @@
|
||||
**/.dockerignore
|
||||
**/.env
|
||||
**/.git
|
||||
**/.gitignore
|
||||
**/.project
|
||||
**/.settings
|
||||
**/.toolstarget
|
||||
**/.vs
|
||||
**/.vscode
|
||||
**/.idea
|
||||
**/*.*proj.user
|
||||
**/*.dbmdl
|
||||
**/*.jfm
|
||||
**/azds.yaml
|
||||
**/bin
|
||||
**/charts
|
||||
**/docker-compose*
|
||||
**/Dockerfile*
|
||||
**/node_modules
|
||||
**/npm-debug.log
|
||||
**/obj
|
||||
**/secrets.dev.yaml
|
||||
**/values.dev.yaml
|
||||
LICENSE
|
||||
README.md
|
18
Store/Dockerfile
Normal file
18
Store/Dockerfile
Normal file
@ -0,0 +1,18 @@
|
||||
FROM mcr.microsoft.com/dotnet/runtime:6.0 AS base
|
||||
WORKDIR /app
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
|
||||
WORKDIR /src
|
||||
COPY ["Store/Store.fsproj", "Store/"]
|
||||
RUN dotnet restore "Store/Store.fsproj"
|
||||
COPY . .
|
||||
WORKDIR "/src/Store"
|
||||
RUN dotnet build "Store.fsproj" -c Release -o /app/build
|
||||
|
||||
FROM build AS publish
|
||||
RUN dotnet publish "Store.fsproj" -c Release -o /app/publish
|
||||
|
||||
FROM base AS final
|
||||
WORKDIR /app
|
||||
COPY --from=publish /app/publish .
|
||||
ENTRYPOINT ["dotnet", "Store.dll"]
|
4
Store/Program.fs
Normal file
4
Store/Program.fs
Normal file
@ -0,0 +1,4 @@
|
||||
|
||||
|
||||
// For more information see https://aka.ms/fsharp-console-apps
|
||||
printfn "Hello from F#"
|
19
Store/Store.fsproj
Normal file
19
Store/Store.fsproj
Normal file
@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Program.fs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include=".dockerignore" />
|
||||
<Content Include="Dockerfile" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Shared\Shared.fsproj" />
|
||||
</ItemGroup>
|
||||
<Import Project="..\.paket\Paket.Restore.targets" />
|
||||
</Project>
|
7
Store/paket.references
Normal file
7
Store/paket.references
Normal file
@ -0,0 +1,7 @@
|
||||
FSharp.Core
|
||||
DSharpPlus
|
||||
// DSharpPlus.CommandsNext
|
||||
// DSharpPlus.Interactivity
|
||||
DSharpPlus.SlashCommands
|
||||
|
||||
MongoDB.Driver
|
88
Types.fs
88
Types.fs
@ -1,88 +0,0 @@
|
||||
module Joebot.Types
|
||||
|
||||
open System
|
||||
|
||||
type ActionClass =
|
||||
| Network
|
||||
| Exploit
|
||||
| Penetration
|
||||
|
||||
type IClass = abstract GetClass : unit -> ActionClass
|
||||
|
||||
type Weapon =
|
||||
| Virus
|
||||
| Ransom
|
||||
| Worm
|
||||
| DDos
|
||||
| Crack
|
||||
| Injection
|
||||
interface IClass with
|
||||
member this.GetClass () =
|
||||
match this with
|
||||
| Virus | Ransom -> Exploit
|
||||
| DDos | Worm -> Network
|
||||
| Crack | Injection -> Penetration
|
||||
static member TryParse weapon =
|
||||
match weapon with
|
||||
| "Virus" -> Some Virus
|
||||
| "Ransom" -> Some Ransom
|
||||
| "Worm" -> Some Worm
|
||||
| "DDos" -> Some DDos
|
||||
| "Crack" -> Some Crack
|
||||
| "Injection" -> Some Injection
|
||||
| _ -> None
|
||||
|
||||
type Shield =
|
||||
| Firewall
|
||||
| PortScan
|
||||
| Encryption
|
||||
| Cypher
|
||||
| Hardening
|
||||
| Sanitation
|
||||
interface IClass with
|
||||
member this.GetClass () =
|
||||
match this with
|
||||
| Firewall | PortScan -> Network
|
||||
| Encryption | Cypher -> Exploit
|
||||
| Hardening | Sanitation -> Penetration
|
||||
static member TryParse shield =
|
||||
match shield with
|
||||
| "Firewall" -> Some Firewall
|
||||
| "PortScan" -> Some PortScan
|
||||
| "Encryption" -> Some Encryption
|
||||
| "Cypher" -> Some Cypher
|
||||
| "Hardening" -> Some Hardening
|
||||
| "Sanitation" -> Some Sanitation
|
||||
| _ -> None
|
||||
|
||||
type HackResult =
|
||||
| Strong
|
||||
| Weak
|
||||
|
||||
type DiscordPlayer = {
|
||||
Id : uint64
|
||||
Name : string
|
||||
}
|
||||
|
||||
type Attack = {
|
||||
HackType : Weapon
|
||||
Target : DiscordPlayer
|
||||
Timestamp : DateTime
|
||||
}
|
||||
|
||||
type Defense = {
|
||||
DefenseType : Shield
|
||||
Timestamp : DateTime
|
||||
}
|
||||
|
||||
type Player = {
|
||||
DiscordId : uint64
|
||||
Name : string
|
||||
Weapons : Weapon list
|
||||
Shields : Shield list
|
||||
Attacks : Attack list
|
||||
Defenses : Defense list
|
||||
Bank : single
|
||||
}
|
||||
|
||||
|
BIN
challenge.jpg
BIN
challenge.jpg
Binary file not shown.
Before Width: | Height: | Size: 24 KiB |
@ -10,4 +10,4 @@ source https://nuget.emzi0767.com/api/v3/index.json
|
||||
nuget DSharpPlus >= 4.2.0-nightly-01054
|
||||
nuget DSharpPlus.SlashCommands >= 4.2.0-nightly-01054
|
||||
|
||||
nuget LiteDB.FSharp 2.16.0
|
||||
nuget MongoDB.Driver
|
||||
|
74
paket.lock
74
paket.lock
@ -1,35 +1,16 @@
|
||||
STORAGE: NONE
|
||||
RESTRICTION: || (== net6.0) (== netstandard2.0) (== netstandard2.1)
|
||||
NUGET
|
||||
remote: https://nuget.emzi0767.com/api/v3/index.json
|
||||
DSharpPlus (4.2.0-nightly-01054)
|
||||
Emzi0767.Common (>= 2.6.2)
|
||||
Microsoft.Extensions.Logging.Abstractions (>= 5.0)
|
||||
Newtonsoft.Json (>= 13.0.1)
|
||||
System.Memory (>= 4.5.4)
|
||||
System.Net.Http (>= 4.3.4)
|
||||
System.Net.WebSockets (>= 4.3)
|
||||
System.Net.WebSockets.Client (>= 4.3.2)
|
||||
System.Runtime.InteropServices.RuntimeInformation (>= 4.3)
|
||||
System.Threading.Channels (>= 5.0)
|
||||
DSharpPlus.SlashCommands (4.2.0-nightly-01054)
|
||||
DSharpPlus (>= 4.2.0-nightly-01054)
|
||||
Microsoft.Extensions.DependencyInjection (>= 5.0.1)
|
||||
remote: https://api.nuget.org/v3/index.json
|
||||
DnsClient (1.5)
|
||||
Microsoft.Win32.Registry (>= 5.0)
|
||||
System.Buffers (>= 4.5.1) - restriction: || (&& (== net6.0) (>= net471)) (&& (== net6.0) (< netstandard2.0)) (&& (== net6.0) (< netstandard2.1)) (== netstandard2.0) (&& (== netstandard2.1) (>= net471)) (&& (== netstandard2.1) (< netstandard2.0))
|
||||
Emzi0767.Common (2.6.2)
|
||||
System.Collections.Immutable (>= 5.0)
|
||||
System.Memory (>= 4.5.4)
|
||||
System.Runtime.CompilerServices.Unsafe (>= 5.0)
|
||||
System.ValueTuple (>= 4.5)
|
||||
FSharp.Core (6.0.1)
|
||||
LiteDB (4.1.4)
|
||||
System.Reflection (>= 4.3)
|
||||
System.Reflection.TypeExtensions (>= 4.3)
|
||||
LiteDB.FSharp (2.16)
|
||||
FSharp.Core (>= 4.7.2)
|
||||
LiteDB (>= 4.1.4 < 5.0)
|
||||
Newtonsoft.Json (>= 13.0.1)
|
||||
TypeShape (>= 9.0)
|
||||
Microsoft.Bcl.AsyncInterfaces (6.0) - restriction: || (&& (== net6.0) (>= net461)) (&& (== net6.0) (< netstandard2.1)) (== netstandard2.0) (&& (== netstandard2.1) (>= net461))
|
||||
System.Threading.Tasks.Extensions (>= 4.5.4) - restriction: || (&& (== net6.0) (>= net461)) (&& (== net6.0) (< netstandard2.1)) (== netstandard2.0) (&& (== netstandard2.1) (>= net461))
|
||||
Microsoft.Extensions.DependencyInjection (6.0)
|
||||
@ -49,6 +30,24 @@ NUGET
|
||||
Microsoft.NETCore.Platforms (>= 1.1)
|
||||
Microsoft.NETCore.Targets (>= 1.1)
|
||||
System.Runtime (>= 4.3)
|
||||
Microsoft.Win32.Registry (5.0)
|
||||
System.Buffers (>= 4.5.1) - restriction: || (&& (== net6.0) (>= monoandroid) (< netstandard1.3)) (&& (== net6.0) (>= monotouch)) (&& (== net6.0) (< netcoreapp2.0)) (&& (== net6.0) (>= xamarinios)) (&& (== net6.0) (>= xamarinmac)) (&& (== net6.0) (>= xamarintvos)) (&& (== net6.0) (>= xamarinwatchos)) (== netstandard2.0) (== netstandard2.1)
|
||||
System.Memory (>= 4.5.4) - restriction: || (&& (== net6.0) (< netcoreapp2.0)) (&& (== net6.0) (< netcoreapp2.1)) (&& (== net6.0) (>= uap10.1)) (== netstandard2.0) (== netstandard2.1)
|
||||
System.Security.AccessControl (>= 5.0)
|
||||
System.Security.Principal.Windows (>= 5.0)
|
||||
MongoDB.Bson (2.14.1)
|
||||
System.Runtime.CompilerServices.Unsafe (>= 5.0)
|
||||
MongoDB.Driver (2.14.1)
|
||||
MongoDB.Bson (>= 2.14.1)
|
||||
MongoDB.Driver.Core (>= 2.14.1)
|
||||
MongoDB.Libmongocrypt (>= 1.3)
|
||||
MongoDB.Driver.Core (2.14.1)
|
||||
DnsClient (>= 1.4)
|
||||
MongoDB.Bson (>= 2.14.1)
|
||||
MongoDB.Libmongocrypt (>= 1.3)
|
||||
SharpCompress (>= 0.30.1)
|
||||
System.Buffers (>= 4.5.1)
|
||||
MongoDB.Libmongocrypt (1.3)
|
||||
Newtonsoft.Json (13.0.1)
|
||||
runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3)
|
||||
runtime.debian.9-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3)
|
||||
@ -93,7 +92,10 @@ NUGET
|
||||
runtime.ubuntu.16.04-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3)
|
||||
runtime.ubuntu.16.10-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3)
|
||||
runtime.ubuntu.18.04-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3)
|
||||
System.Buffers (4.5.1) - restriction: || (&& (== net6.0) (>= net461)) (== netstandard2.0) (== netstandard2.1)
|
||||
SharpCompress (0.30.1)
|
||||
System.Memory (>= 4.5.4) - restriction: || (&& (== net6.0) (>= net461)) (&& (== net6.0) (< netstandard2.1)) (== netstandard2.0) (&& (== netstandard2.1) (>= net461))
|
||||
System.Text.Encoding.CodePages (>= 5.0) - restriction: || (&& (== net6.0) (>= net461)) (&& (== net6.0) (< netcoreapp3.1)) (&& (== net6.0) (< netstandard2.1)) (== netstandard2.0) (== netstandard2.1)
|
||||
System.Buffers (4.5.1)
|
||||
System.Collections (4.3)
|
||||
Microsoft.NETCore.Platforms (>= 1.1)
|
||||
Microsoft.NETCore.Targets (>= 1.1)
|
||||
@ -294,9 +296,6 @@ NUGET
|
||||
System.IO (>= 4.3)
|
||||
System.Reflection.Primitives (>= 4.3)
|
||||
System.Runtime (>= 4.3)
|
||||
System.Reflection.Emit.ILGeneration (4.7) - restriction: || (&& (== net6.0) (< netcoreapp2.0) (< netstandard2.1)) (&& (== net6.0) (< netstandard2.0)) (&& (== net6.0) (< portable-net45+wp8)) (&& (== net6.0) (>= uap10.1)) (== netstandard2.0) (&& (== netstandard2.1) (< netstandard2.0)) (&& (== netstandard2.1) (< portable-net45+wp8)) (&& (== netstandard2.1) (>= uap10.1))
|
||||
System.Reflection.Emit.LightWeight (4.7) - restriction: || (&& (== net6.0) (< netcoreapp3.1)) (== netstandard2.0) (== netstandard2.1)
|
||||
System.Reflection.Emit.ILGeneration (>= 4.7) - restriction: || (&& (== net6.0) (< netcoreapp2.0) (< netstandard2.1)) (&& (== net6.0) (< netstandard2.0)) (&& (== net6.0) (< portable-net45+wp8)) (&& (== net6.0) (>= uap10.1)) (== netstandard2.0) (&& (== netstandard2.1) (< netstandard2.0)) (&& (== netstandard2.1) (< portable-net45+wp8)) (&& (== netstandard2.1) (>= uap10.1))
|
||||
System.Reflection.Extensions (4.3)
|
||||
Microsoft.NETCore.Platforms (>= 1.1)
|
||||
Microsoft.NETCore.Targets (>= 1.1)
|
||||
@ -306,7 +305,6 @@ NUGET
|
||||
Microsoft.NETCore.Platforms (>= 1.1)
|
||||
Microsoft.NETCore.Targets (>= 1.1)
|
||||
System.Runtime (>= 4.3)
|
||||
System.Reflection.TypeExtensions (4.7)
|
||||
System.Resources.ResourceManager (4.3)
|
||||
Microsoft.NETCore.Platforms (>= 1.1)
|
||||
Microsoft.NETCore.Targets (>= 1.1)
|
||||
@ -345,6 +343,8 @@ NUGET
|
||||
System.Resources.ResourceManager (>= 4.3)
|
||||
System.Runtime (>= 4.3)
|
||||
System.Runtime.Extensions (>= 4.3)
|
||||
System.Security.AccessControl (6.0)
|
||||
System.Security.Principal.Windows (>= 5.0) - restriction: || (&& (== net6.0) (>= net461)) (== netstandard2.0) (== netstandard2.1)
|
||||
System.Security.Claims (4.3)
|
||||
System.Collections (>= 4.3)
|
||||
System.Globalization (>= 4.3)
|
||||
@ -440,6 +440,9 @@ NUGET
|
||||
Microsoft.NETCore.Platforms (>= 1.1)
|
||||
Microsoft.NETCore.Targets (>= 1.1)
|
||||
System.Runtime (>= 4.3)
|
||||
System.Text.Encoding.CodePages (6.0) - restriction: || (&& (== net6.0) (>= net461)) (&& (== net6.0) (< netcoreapp3.1)) (&& (== net6.0) (< netstandard2.1)) (== netstandard2.0) (== netstandard2.1)
|
||||
System.Memory (>= 4.5.4) - restriction: || (&& (== net6.0) (>= net461)) (&& (== net6.0) (< netcoreapp3.1)) (== netstandard2.0) (== netstandard2.1)
|
||||
System.Runtime.CompilerServices.Unsafe (>= 6.0)
|
||||
System.Text.Encoding.Extensions (4.3)
|
||||
Microsoft.NETCore.Platforms (>= 1.1)
|
||||
Microsoft.NETCore.Targets (>= 1.1)
|
||||
@ -464,6 +467,17 @@ NUGET
|
||||
Microsoft.NETCore.Targets (>= 1.1)
|
||||
System.Runtime (>= 4.3)
|
||||
System.ValueTuple (4.5)
|
||||
TypeShape (10.0)
|
||||
FSharp.Core (>= 4.5.4)
|
||||
System.Reflection.Emit.LightWeight (>= 4.7) - restriction: || (&& (== net6.0) (< netcoreapp3.1)) (== netstandard2.0) (== netstandard2.1)
|
||||
remote: https://nuget.emzi0767.com/api/v3/index.json
|
||||
DSharpPlus (4.2.0-nightly-01059)
|
||||
Emzi0767.Common (>= 2.6.2)
|
||||
Microsoft.Extensions.Logging.Abstractions (>= 5.0)
|
||||
Newtonsoft.Json (>= 13.0.1)
|
||||
System.Memory (>= 4.5.4)
|
||||
System.Net.Http (>= 4.3.4)
|
||||
System.Net.WebSockets (>= 4.3)
|
||||
System.Net.WebSockets.Client (>= 4.3.2)
|
||||
System.Runtime.InteropServices.RuntimeInformation (>= 4.3)
|
||||
System.Threading.Channels (>= 5.0)
|
||||
DSharpPlus.SlashCommands (4.2.0-nightly-01059)
|
||||
DSharpPlus (>= 4.2.0-nightly-01059)
|
||||
Microsoft.Extensions.DependencyInjection (>= 5.0.1)
|
||||
|
Loading…
x
Reference in New Issue
Block a user