diff --git a/DbService/DbService.fs b/DbService/DbService.fs new file mode 100644 index 0000000..bd06df1 --- /dev/null +++ b/DbService/DbService.fs @@ -0,0 +1,39 @@ +module DegenzGame.DbService + +open DegenzGame.Shared +open DegenzGame.Shared +open MongoDB.Bson +open MongoDB.Driver + +type PlayerEntry = { + Id : BsonObjectId + Player : Player +} + +let mongo = MongoClient("mongodb://localhost:27017") +let db = mongo.GetDatabase("degenz-game") +let players = db.GetCollection("players") + +let tryFindPlayer (id : uint64) : Async = + async { + let filter = Builders.Filter.Eq((fun p -> p.Player.DiscordId), id) + let! player = players.FindAsync(filter) |> Async.AwaitTask + return match player.ToEnumerable() |> Seq.toList with + | [] -> None + | entry::_ -> Some entry.Player + } + +let insertNewPlayer (player : Player) = + async { + do! { Id = BsonObjectId(ObjectId.GenerateNewId()) ; Player = player } + |> players.InsertOneAsync + |> Async.AwaitTask + } + +let removePlayer (memberId : uint64) = + async { + // TODO: Check the result of this delete operation + return! players.DeleteOneAsync (fun p -> p.Player.DiscordId = memberId) + |> Async.AwaitTask + |> Async.Ignore + } diff --git a/DbService/DbService.fsproj b/DbService/DbService.fsproj new file mode 100644 index 0000000..45a74ae --- /dev/null +++ b/DbService/DbService.fsproj @@ -0,0 +1,14 @@ + + + + net6.0 + true + + + + + + + + + \ No newline at end of file diff --git a/DbService/paket.references b/DbService/paket.references new file mode 100644 index 0000000..5753ebc --- /dev/null +++ b/DbService/paket.references @@ -0,0 +1,7 @@ +FSharp.Core +DSharpPlus +// DSharpPlus.CommandsNext +// DSharpPlus.Interactivity +DSharpPlus.SlashCommands + +MongoDB.Driver diff --git a/Degenz.sln b/DegenzGame.sln similarity index 65% rename from Degenz.sln rename to DegenzGame.sln index ec17336..d08053a 100644 --- a/Degenz.sln +++ b/DegenzGame.sln @@ -9,6 +9,10 @@ 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}" +EndProject +Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "DbService", "DbService\DbService.fsproj", "{B1D3E1CC-451C-42D4-B054-D64E75E1A3B9}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -30,5 +34,13 @@ Global {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 + {FF9E58A6-1A1D-4DEC-B52D-265F215BF315}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FF9E58A6-1A1D-4DEC-B52D-265F215BF315}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FF9E58A6-1A1D-4DEC-B52D-265F215BF315}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FF9E58A6-1A1D-4DEC-B52D-265F215BF315}.Release|Any CPU.Build.0 = Release|Any CPU + {B1D3E1CC-451C-42D4-B054-D64E75E1A3B9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B1D3E1CC-451C-42D4-B054-D64E75E1A3B9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B1D3E1CC-451C-42D4-B054-D64E75E1A3B9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B1D3E1CC-451C-42D4-B054-D64E75E1A3B9}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal diff --git a/HackerBattle/Commands.fs b/HackerBattle/Commands.fs index 57983d2..26f9cbb 100644 --- a/HackerBattle/Commands.fs +++ b/HackerBattle/Commands.fs @@ -6,7 +6,8 @@ open DSharpPlus open DSharpPlus.Entities open DSharpPlus.EventArgs open DSharpPlus.SlashCommands -open DegenzGame.Types +open DegenzGame.Shared +open DegenzGame.DbService open DegenzGame.Functions open MongoDB.Driver @@ -16,60 +17,6 @@ open MongoDB.Driver // My server let battleChannel = 927449884204867664uL -let mongo = MongoClient("mongodb://localhost:27017") -let db = mongo.GetDatabase("degenz-game") -let players = db.GetCollection("players") - -let tryFindPlayer (id : uint64) : Async = - async { - let filter = Builders.Filter.Eq((fun p -> p.DiscordId), id) - let! player = players.FindAsync(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 { diff --git a/HackerBattle/Functions.fs b/HackerBattle/Functions.fs index 6ac32be..d153564 100644 --- a/HackerBattle/Functions.fs +++ b/HackerBattle/Functions.fs @@ -3,9 +3,7 @@ module DegenzGame.Functions open System open DSharpPlus open DSharpPlus.Entities -open DSharpPlus.SlashCommands -open DegenzGame.Types -open MongoDB.Bson +open DegenzGame.Shared let hackDescription = "" @@ -16,29 +14,6 @@ Active Hacks: {player.Attacks |> Array.toList} Active Defenses: {player.Defenses |> Array.toList} Bank: {player.Bank}" -let newPlayer nickname (membr : uint64) = - 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 |] - - { Id = BsonObjectId(ObjectId.GenerateNewId()) - DiscordId = membr - Name = nickname - Weapons = weapons - Shields = shields - Attacks = [||] - Defenses = [||] - Bank = 0f } - let constructButtons (actionType : string) (playerInfo : string) (weapons : 'a array) = weapons |> Seq.map (fun hack -> @@ -47,17 +22,6 @@ let constructButtons (actionType : string) (playerInfo : string) (weapons : 'a a $"{actionType}-{hack}-{playerInfo}", $"{hack}")) -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 removeExpiredActions timespan (timestamp : 'a -> DateTime) actions = actions |> Array.filter (fun act -> diff --git a/HackerBattle/HackerBattle.fsproj b/HackerBattle/HackerBattle.fsproj index d52adce..c567858 100644 --- a/HackerBattle/HackerBattle.fsproj +++ b/HackerBattle/HackerBattle.fsproj @@ -17,8 +17,10 @@ + + diff --git a/HackerBattle/Program.fs b/HackerBattle/Program.fs index 0a6d931..50809a7 100644 --- a/HackerBattle/Program.fs +++ b/HackerBattle/Program.fs @@ -1,27 +1,16 @@ -module DegenzGame.Program - -open System -open System.Threading.Tasks +open System.Threading.Tasks open DSharpPlus open DSharpPlus.Entities -open DSharpPlus.EventArgs open DSharpPlus.SlashCommands open Emzi0767.Utilities -open DegenzGame.Types +open DegenzGame open DegenzGame.Commands -open MongoDB.Driver type EmptyGlobalCommandToAvoidFamousDuplicateSlashCommandsBug() = inherit ApplicationCommandModule () type HackerGame() = inherit ApplicationCommandModule () - [] - member _.AddHackerRole (ctx : InteractionContext) = Commands.addHackerRole ctx - - [] - member _.RemoveHackerRole (ctx : InteractionContext) = Commands.removeHackerRole ctx - [] member this.AttackCommand (ctx : InteractionContext, [] target : DiscordUser) = Commands.attack ctx target diff --git a/HackerBattle/paket.references b/HackerBattle/paket.references index 5753ebc..a5fcca2 100644 --- a/HackerBattle/paket.references +++ b/HackerBattle/paket.references @@ -4,4 +4,4 @@ DSharpPlus // DSharpPlus.Interactivity DSharpPlus.SlashCommands -MongoDB.Driver +// MongoDB.Driver diff --git a/PlayerRegistration/.dockerignore b/PlayerRegistration/.dockerignore new file mode 100644 index 0000000..38bece4 --- /dev/null +++ b/PlayerRegistration/.dockerignore @@ -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 \ No newline at end of file diff --git a/PlayerRegistration/Dockerfile b/PlayerRegistration/Dockerfile new file mode 100644 index 0000000..801fe2e --- /dev/null +++ b/PlayerRegistration/Dockerfile @@ -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 ["PlayerRegistration/PlayerRegistration.fsproj", "PlayerRegistration/"] +RUN dotnet restore "PlayerRegistration/PlayerRegistration.fsproj" +COPY . . +WORKDIR "/src/PlayerRegistration" +RUN dotnet build "PlayerRegistration.fsproj" -c Release -o /app/build + +FROM build AS publish +RUN dotnet publish "PlayerRegistration.fsproj" -c Release -o /app/publish + +FROM base AS final +WORKDIR /app +COPY --from=publish /app/publish . +ENTRYPOINT ["dotnet", "PlayerRegistration.dll"] diff --git a/PlayerRegistration/PlayerRegistration.fsproj b/PlayerRegistration/PlayerRegistration.fsproj new file mode 100644 index 0000000..565f091 --- /dev/null +++ b/PlayerRegistration/PlayerRegistration.fsproj @@ -0,0 +1,21 @@ + + + + Exe + net6.0 + Linux + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/PlayerRegistration/Program.fs b/PlayerRegistration/Program.fs new file mode 100644 index 0000000..b9e66d2 --- /dev/null +++ b/PlayerRegistration/Program.fs @@ -0,0 +1,115 @@ + +open System.Threading.Tasks +open DegenzGame.DbService +open DSharpPlus +open DSharpPlus.SlashCommands +open DegenzGame.Shared + +module Commands = + let newPlayer nickname (membr : uint64) = + 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 + Name = nickname + Weapons = weapons + Shields = shields + Attacks = [||] + Defenses = [||] + Bank = 0f } + + let addHackerRole (ctx : InteractionContext) = + async { + let! player = tryFindPlayer ctx.Member.Id + let! newPlayer = + match player with + | Some _ -> async.Return false + | None -> + async { + do! newPlayer ctx.Member.Username ctx.Member.Id + |> insertNewPlayer + + 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 + + do! removePlayer ctx.Member.Id + + do! ctx.CreateResponseAsync("You are now lame", true) + |> Async.AwaitTask + } |> Async.StartAsTask + :> Task + + +type EmptyGlobalCommandToAvoidFamousDuplicateSlashCommandsBug() = inherit ApplicationCommandModule () + +type PlayerRegistration() = + inherit ApplicationCommandModule () + + [] + member _.AddHackerRole (ctx : InteractionContext) = Commands.addHackerRole ctx + + [] + member _.RemoveHackerRole (ctx : InteractionContext) = Commands.removeHackerRole ctx + + +let config = DiscordConfiguration() +config.Token <- "OTIyNDIyMDIyMTI1MDEwOTU1.YcBOcw.JxfW1CSIwEO7j6RbRFCnPZ-HoTk" +config.TokenType <- TokenType.Bot +config.Intents <- DiscordIntents.All +//config.MinimumLogLevel <- Microsoft.Extensions.Logging.LogLevel.Trace + +let client = new DiscordClient(config) + +//client.add_ComponentInteractionCreated(AsyncEventHandler(handleButtonEvent)) + +let slash = client.UseSlashCommands() + +// My server +slash.RegisterCommands(922419263275425832uL); +// Degenz +//slash.RegisterCommands(922414052708327494uL); + +client.ConnectAsync () +|> Async.AwaitTask +|> Async.RunSynchronously + +Task.Delay(-1) +|> Async.AwaitTask +|> Async.RunSynchronously + +client.DisconnectAsync () +|> Async.AwaitTask +|> Async.RunSynchronously + diff --git a/PlayerRegistration/paket.references b/PlayerRegistration/paket.references new file mode 100644 index 0000000..a5fcca2 --- /dev/null +++ b/PlayerRegistration/paket.references @@ -0,0 +1,7 @@ +FSharp.Core +DSharpPlus +// DSharpPlus.CommandsNext +// DSharpPlus.Interactivity +DSharpPlus.SlashCommands + +// MongoDB.Driver diff --git a/Shared/Shared.fsproj b/Shared/Shared.fsproj index 47c6c0a..a86cb3a 100644 --- a/Shared/Shared.fsproj +++ b/Shared/Shared.fsproj @@ -6,6 +6,7 @@ + \ No newline at end of file diff --git a/Shared/Types.fs b/Shared/Types.fs index 9b9650b..94ba8d9 100644 --- a/Shared/Types.fs +++ b/Shared/Types.fs @@ -1,7 +1,9 @@ -module DegenzGame.Types +module DegenzGame.Shared open System -open MongoDB.Bson +open DSharpPlus +open DSharpPlus.Entities +open DSharpPlus.SlashCommands type ActionClass = | Network @@ -54,7 +56,6 @@ type Defense = { [] type Player = { - Id : BsonObjectId DiscordId : uint64 Name : string Weapons : Weapon array @@ -64,4 +65,13 @@ type Player = { 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" \ No newline at end of file diff --git a/Shared/paket.references b/Shared/paket.references index 7e4dfad..71731ab 100644 --- a/Shared/paket.references +++ b/Shared/paket.references @@ -1,2 +1,3 @@ FSharp.Core -MongoDB.Driver +DSharpPlus +DSharpPlus.SlashCommands diff --git a/Store/Store.fsproj b/Store/Store.fsproj index e69619e..565f091 100644 --- a/Store/Store.fsproj +++ b/Store/Store.fsproj @@ -11,8 +11,10 @@ + + diff --git a/Store/paket.references b/Store/paket.references index 5753ebc..a5fcca2 100644 --- a/Store/paket.references +++ b/Store/paket.references @@ -4,4 +4,4 @@ DSharpPlus // DSharpPlus.Interactivity DSharpPlus.SlashCommands -MongoDB.Driver +// MongoDB.Driver