mirror of
https://gitlab.com/Kwoth/nadekobot.git
synced 2025-09-10 09:18:27 -04:00
Compare commits
83 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
7d5c4666b8 | ||
|
8d3f2f186a | ||
|
9572b9dc43 | ||
|
ca32086089 | ||
|
57f839dbcd | ||
|
71d6eeb9dd | ||
|
8c51cf8537 | ||
|
b683026cf3 | ||
|
bca2bc5af1 | ||
|
b385a83bdd | ||
|
3bf0286c81 | ||
|
98272f66e7 | ||
|
cf3788c6ea | ||
|
4b3fc53cb6 | ||
|
4e17dca856 | ||
|
82d89148f3 | ||
|
cc4c09b4d7 | ||
|
616f01f8b2 | ||
|
56f89a02bc | ||
|
48ce988d20 | ||
|
119b1cdec2 | ||
|
43fa5a22f5 | ||
|
3c715a29ca | ||
|
31e1cbb19f | ||
|
8e464e9f09 | ||
|
a190a3d933 | ||
|
bedba98130 | ||
|
d69f8435f6 | ||
|
8440b34338 | ||
|
a2715740c1 | ||
|
36b7fd2352 | ||
|
6563cb507a | ||
|
cc6128997e | ||
|
e942da4470 | ||
|
ab2bcdf00d | ||
|
d7c1dad4f0 | ||
|
8bd6b887b8 | ||
|
d326e19196 | ||
|
fa822853df | ||
|
22bff7838a | ||
|
25fce1bd75 | ||
|
a73482e838 | ||
|
bb395f18a2 | ||
|
e20212a6cb | ||
|
0f8291c589 | ||
|
a7b3a238f5 | ||
|
bb800f4e38 | ||
|
b10eded334 | ||
|
3e15e50667 | ||
|
516bc1e484 | ||
|
6a042c3faa | ||
|
967784c860 | ||
|
ccf92ca702 | ||
|
c20b851dc7 | ||
|
39fc21d41c | ||
|
c8c0b27d6a | ||
|
9a21ba3d53 | ||
|
0042c22ceb | ||
|
a0ba9be34e | ||
|
91da78a2ee | ||
|
8eca8e1dfb | ||
|
b12e97a0a7 | ||
|
99c60459f8 | ||
|
3db194c186 | ||
|
0b720a0439 | ||
|
d9011106ac | ||
|
17ca609fe9 | ||
|
0f1ba400db | ||
|
2b8daa2177 | ||
|
f3ed14de5b | ||
|
251d5a4df4 | ||
|
f761714f15 | ||
|
93b0e38264 | ||
|
5f7b030a66 | ||
|
0b122e8d3f | ||
|
34955f88f6 | ||
|
9a35716331 | ||
|
156069db0e | ||
|
ea8e444b10 | ||
|
ff779ad494 | ||
|
946b095d4b | ||
|
5bb8f3f7c8 | ||
|
f41b1fb93c |
@@ -1,6 +1,11 @@
|
||||
# Ignore all files
|
||||
*
|
||||
|
||||
# Don't ignore nugetconfig
|
||||
!./NuGet.Config
|
||||
# Don't ignore src projects
|
||||
!src/Nadeko.Econ/**
|
||||
!src/Nadeko.Common/**
|
||||
# Use Nadeko.Medusa project
|
||||
!src/Nadeko.Medusa/**
|
||||
# Use NadekoBot project
|
||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,5 +1,7 @@
|
||||
#Manually added files
|
||||
|
||||
src/NadekoBot/data/last_known_version.txt
|
||||
|
||||
# medusa stuff
|
||||
!src/NadekoBot/data/medusae/medusa.yml
|
||||
src/NadekoBot/data/medusae/**
|
||||
|
98
CHANGELOG.md
98
CHANGELOG.md
@@ -2,6 +2,104 @@
|
||||
|
||||
Experimental changelog. Mostly based on [keepachangelog](https://keepachangelog.com/en/1.0.0/) except date format. a-c-f-r-o
|
||||
|
||||
## Unreleased
|
||||
|
||||
## [4.3.3] - 06.08.2022
|
||||
|
||||
### Added
|
||||
|
||||
- Added `betroll` option to `.bettest` command
|
||||
- Added `.xpshopbuy` and `.xpshopuse` convenience commands
|
||||
- Added an optional preview url to teh xp shop item config model which will be shown instead of the real Url
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated position of Username and Club name on the .xp card
|
||||
- Improved text visibility on the .xp card
|
||||
|
||||
### Fixed
|
||||
|
||||
- Possibly fixed .trivia not stopping bug
|
||||
- Fixed very low payout rate on `.betroll`
|
||||
- Fixed an issue with youtube song resolver which caused invalid data to be cached
|
||||
- Added client id to the cache key as a potential fix for VoiceXp 'bug'. The solution may be to use different redis instances for each bot, or to switch from botCache: from 'redis' to 'memory' in creds.yml
|
||||
- Bot owner should now be able to buy items from the xpshop when patron requirement is set
|
||||
- Fixed youtube-dl caching invalid data. Please use yt-dlp instead
|
||||
|
||||
## [4.3.2] - 28.07.2022
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed Reaction Roles not working properly with animated emojis
|
||||
- Fixed `.slot` alignment
|
||||
- Fixed `mysql` and `postgresql` reactionrole migration
|
||||
- Fixed repeat loop with `postgresql` db provider
|
||||
- Fixed `.bank withdraw <expression>` will now correctly use bank amount for calculation
|
||||
- [dev] Fixed medusa Reply*LocalizedAsync not working with placeholders
|
||||
|
||||
## [4.3.1] - 27.07.2022
|
||||
|
||||
### Changed
|
||||
|
||||
- Check for updates will run once per hour as it was supposed to
|
||||
|
||||
## [4.3.0] - 27.07.2022
|
||||
|
||||
### Added
|
||||
|
||||
- Added `.bettest` command which lets you test many gambling commands
|
||||
- Better than .slottest
|
||||
- Counts win/loss streaks too
|
||||
- Doesn't count 1x returns as neither wins nor losses
|
||||
- multipliers < 1 are considered losses, > 1 considered wins
|
||||
- Added `.betdraw` command which lets you guess red/black and/or high/low for a random card
|
||||
- They payouts are very good, but seven always loses
|
||||
- Added `.lula` command. Plays the same as `.wof` but looks much nicer, and is easily customizable from gambling.yml without any changes to the sourcecode needed.
|
||||
- Added `.repeatskip` command which makes the next repeat trigger not post anything
|
||||
- Added `.linkonly` which will make the bot only allow link posts in the channel. Exclusive with `.imageonly`
|
||||
- Added release notifications. Bot owners will now receive new release notifications in dms if they have `checkForUpdates` set to `true` in data/bot.yml
|
||||
- You can also configure it via `.conf bot checkfor
|
||||
- updates <true/false>`
|
||||
- Added `.xpshop` which lets bot owners add xp backgrounds and xp frames for sale by configuring `data/xp.yml`
|
||||
- You can also toggle xpshop feature via `.conf xp shop.is_enabled`
|
||||
|
||||
### Changed
|
||||
|
||||
- `.t` Trivia code cleaned up, added ALL pokemon generations
|
||||
|
||||
- `.xpadd` will now work on roles too. It will add the specified xp to each user (visible to the bot) in the role
|
||||
- Improved / cleaned up / modernized how most gambling commands look
|
||||
- `.roll`
|
||||
- `.rolluo`
|
||||
- `.draw`
|
||||
- `.flip`
|
||||
- `.slot`
|
||||
- `.betroll`
|
||||
- `.betflip`
|
||||
- Try them out!
|
||||
- `.draw`, `.betdraw` and some other card commands (not all) will use the new, rewritten deck system
|
||||
- Error will be printed to the console if there's a problem in `.plant`
|
||||
- [dev] Split Nadeko.Common into a separate project
|
||||
- [dev] It will contain classes/utilities which can be shared across different nadeko related projects
|
||||
- [dev] Split Nadeko.Econ into a separate project
|
||||
- [dev] It should be home for the backend any gambling/currency/economy feature
|
||||
- [dev] It will contain most gambling games and any shared logic
|
||||
- [dev] Compliation should take less time and RAM
|
||||
- [dev] No longer using generator and partial methods for commands
|
||||
|
||||
### Fixed
|
||||
|
||||
- `.slot` will now show correct multipliers if they've been modified
|
||||
- Fix patron errors showing up even with permissions disabling the command
|
||||
- Fixed an issue with voice xp breaking xp gain.
|
||||
|
||||
### Removed
|
||||
|
||||
- Removed `.slottest`, replaced by `.bettest`
|
||||
- Removed `.wof`, replaced by `.lula`
|
||||
- [dev] Removed a lot of unused methods
|
||||
- [dev] Removed several unused response strings
|
||||
|
||||
## [4.2.15] - 12.07.2022
|
||||
|
||||
### Fixed
|
||||
|
@@ -2,10 +2,13 @@ FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
|
||||
WORKDIR /source
|
||||
|
||||
COPY src/Nadeko.Medusa/*.csproj src/Nadeko.Medusa/
|
||||
COPY src/Nadeko.Econ/*.csproj src/Nadeko.Econ/
|
||||
COPY src/Nadeko.Common/*.csproj src/Nadeko.Common/
|
||||
COPY src/NadekoBot/*.csproj src/NadekoBot/
|
||||
COPY src/NadekoBot.Coordinator/*.csproj src/NadekoBot.Coordinator/
|
||||
COPY src/NadekoBot.Generators/*.csproj src/NadekoBot.Generators/
|
||||
COPY src/ayu/Ayu.Discord.Voice/*.csproj src/ayu/Ayu.Discord.Voice/
|
||||
COPY NuGet.Config ./
|
||||
RUN dotnet restore src/NadekoBot/
|
||||
|
||||
COPY . .
|
||||
@@ -39,6 +42,7 @@ COPY docker-entrypoint.sh /usr/local/sbin
|
||||
|
||||
ENV shard_id=0
|
||||
ENV total_shards=1
|
||||
ENV NadekoBot__creds=/app/data/creds.yml
|
||||
|
||||
VOLUME [ "/app/data" ]
|
||||
ENTRYPOINT [ "/usr/local/sbin/docker-entrypoint.sh" ]
|
||||
|
@@ -12,6 +12,7 @@ ProjectSection(SolutionItems) = preProject
|
||||
README.md = README.md
|
||||
.gitlab-ci.yml = .gitlab-ci.yml
|
||||
Dockerfile = Dockerfile
|
||||
NuGet.Config = NuGet.Config
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NadekoBot", "src\NadekoBot\NadekoBot.csproj", "{45EC1473-C678-4857-A544-07DFE0D0B478}"
|
||||
@@ -30,6 +31,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NadekoBot.VotesApi", "src\N
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nadeko.Medusa", "src\Nadeko.Medusa\Nadeko.Medusa.csproj", "{E685977E-31A4-46F4-A5D7-4E3E39E82E43}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nadeko.Common", "src\Nadeko.Common\Nadeko.Common.csproj", "{A6022F5F-A764-4D3F-847B-36F0391FF659}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nadeko.Econ", "src\Nadeko.Econ\Nadeko.Econ.csproj", "{4F4FBF7C-74F0-4AE4-B451-9E60BDCA9C37}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -79,6 +84,18 @@ Global
|
||||
{E685977E-31A4-46F4-A5D7-4E3E39E82E43}.GlobalNadeko|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E685977E-31A4-46F4-A5D7-4E3E39E82E43}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E685977E-31A4-46F4-A5D7-4E3E39E82E43}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{A6022F5F-A764-4D3F-847B-36F0391FF659}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{A6022F5F-A764-4D3F-847B-36F0391FF659}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A6022F5F-A764-4D3F-847B-36F0391FF659}.GlobalNadeko|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{A6022F5F-A764-4D3F-847B-36F0391FF659}.GlobalNadeko|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A6022F5F-A764-4D3F-847B-36F0391FF659}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{A6022F5F-A764-4D3F-847B-36F0391FF659}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{4F4FBF7C-74F0-4AE4-B451-9E60BDCA9C37}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{4F4FBF7C-74F0-4AE4-B451-9E60BDCA9C37}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{4F4FBF7C-74F0-4AE4-B451-9E60BDCA9C37}.GlobalNadeko|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{4F4FBF7C-74F0-4AE4-B451-9E60BDCA9C37}.GlobalNadeko|Any CPU.Build.0 = Debug|Any CPU
|
||||
{4F4FBF7C-74F0-4AE4-B451-9E60BDCA9C37}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{4F4FBF7C-74F0-4AE4-B451-9E60BDCA9C37}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@@ -92,6 +109,8 @@ Global
|
||||
{3BC3BDF8-1A0B-45EB-AB2B-C0891D4D37B8} = {04929013-5BAB-42B0-B9B2-8F2BB8F16AF2}
|
||||
{3BC82CFE-BEE7-451F-986B-17EDD1570C4F} = {04929013-5BAB-42B0-B9B2-8F2BB8F16AF2}
|
||||
{E685977E-31A4-46F4-A5D7-4E3E39E82E43} = {04929013-5BAB-42B0-B9B2-8F2BB8F16AF2}
|
||||
{A6022F5F-A764-4D3F-847B-36F0391FF659} = {04929013-5BAB-42B0-B9B2-8F2BB8F16AF2}
|
||||
{4F4FBF7C-74F0-4AE4-B451-9E60BDCA9C37} = {04929013-5BAB-42B0-B9B2-8F2BB8F16AF2}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {5F3F555C-855F-4BE8-B526-D062D3E8ACA4}
|
||||
|
6
NuGet.Config
Normal file
6
NuGet.Config
Normal file
@@ -0,0 +1,6 @@
|
||||
<configuration>
|
||||
<packageSources>
|
||||
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
|
||||
<add key="nadeko.bot" value="https://www.myget.org/F/nadeko/api/v3/index.json" protocolVersion="3" />
|
||||
</packageSources>
|
||||
</configuration>
|
@@ -13,7 +13,15 @@ do
|
||||
fi
|
||||
done
|
||||
|
||||
# fix folder permissions
|
||||
# creds.yml migration
|
||||
if [ -f /app/creds.yml ]; then
|
||||
echo "Default location for creds.yml is now /app/data/creds.yml."
|
||||
echo "Please move your creds.yml and update your docker-compose.yml accordingly."
|
||||
|
||||
export Nadeko_creds=/app/creds.yml
|
||||
fi
|
||||
|
||||
# ensure nadeko can write on /app/data
|
||||
chown -R nadeko:nadeko "$data"
|
||||
|
||||
# drop to regular user and launch command
|
||||
|
@@ -69,7 +69,7 @@ Open Terminal (if you're on an installation with a window manager) and navigate
|
||||
|
||||
###### Prerequisites
|
||||
|
||||
1. Nadeko requires redis to function
|
||||
1. (Optional) Installing Redis
|
||||
- ubuntu installation command: `sudo apt-get install redis-server`
|
||||
2. Playing music requires `ffmpeg`, `libopus`, `libsodium` and `youtube-dl` (which in turn requires python3)
|
||||
- ubuntu installation command: `sudo apt-get install ffmpeg libopus0 opus-tools libopus-dev libsodium-dev -y`
|
||||
|
@@ -19,7 +19,7 @@
|
||||
|
||||
**Optional**
|
||||
|
||||
- [Notepad++] (makes it easier to edit your credentials)
|
||||
- [Visual Studio Code](https://code.visualstudio.com/Download) (Highly suggested if you plan on editing files)
|
||||
- [Visual C++ 2010 (x86)] and [Visual C++ 2017 (x64)] (both are required if you want Nadeko to play music - restart Windows after installation)
|
||||
|
||||
#### Setup
|
||||
|
11
privacy-policy.md
Normal file
11
privacy-policy.md
Normal file
@@ -0,0 +1,11 @@
|
||||
# Privacy Policy
|
||||
|
||||
## Profile Information
|
||||
Nadeko stores userids, avatars, usernames, discriminators and nicknames of users who were targeted by or have used commands which require Xp, Clubs or Waifu features (not limited to these, as other features may be added over time).
|
||||
|
||||
## Other
|
||||
Nadeko doesn't do analytics, doesn't store messages, doesn't track users, doesn't store their emails etc.
|
||||
Nadeko only stores user settings and states as the result of executed commands or as the effect of administration tools (for example warnings or protection commands).
|
||||
|
||||
## Sensitive Information
|
||||
Nadeko doesn't store sensitive information, and users are strongly discouraged from adding their passwords, keys, or other important information as quotes or expressions.
|
@@ -1,7 +1,6 @@
|
||||
#nullable disable
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace NadekoBot.Common;
|
||||
namespace Nadeko.Common;
|
||||
|
||||
public class AsyncLazy<T> : Lazy<Task<T>>
|
||||
{
|
@@ -1,14 +1,9 @@
|
||||
#nullable enable
|
||||
#pragma warning disable
|
||||
// License MIT
|
||||
// Source: https://github.com/i3arnon/ConcurrentHashSet
|
||||
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace System.Collections.Generic;
|
||||
|
||||
[DebuggerDisplay("{_backingStore.Count}")]
|
||||
public sealed class ConcurrentHashSet<T> : IReadOnlyCollection<T>, ICollection<T>
|
||||
public sealed class ConcurrentHashSet<T> : IReadOnlyCollection<T>, ICollection<T> where T : notnull
|
||||
{
|
||||
private readonly ConcurrentDictionary<T, bool> _backingStore;
|
||||
|
@@ -1,8 +1,11 @@
|
||||
#nullable disable
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using System.Collections;
|
||||
using System.Collections;
|
||||
|
||||
namespace NadekoBot.Common.Collections;
|
||||
namespace Nadeko.Common;
|
||||
|
||||
public interface IIndexed
|
||||
{
|
||||
int Index { get; set; }
|
||||
}
|
||||
|
||||
public class IndexedCollection<T> : IList<T>
|
||||
where T : class, IIndexed
|
@@ -1,6 +1,4 @@
|
||||
using System.Buffers;
|
||||
|
||||
namespace NadekoBot.Extensions;
|
||||
namespace Nadeko.Common;
|
||||
|
||||
// made for expressions because they almost never get added
|
||||
// and they get looped through constantly
|
||||
@@ -32,6 +30,14 @@ public static class ArrayExtensions
|
||||
public static TOut[] Map<TIn, TOut>(this TIn[] arr, Func<TIn, TOut> f)
|
||||
=> Array.ConvertAll(arr, x => f(x));
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new array by applying the specified function to every element in the input array
|
||||
/// </summary>
|
||||
/// <param name="col">Array to modify</param>
|
||||
/// <param name="f">Function to apply</param>
|
||||
/// <typeparam name="TIn">Orignal type of the elements in the array</typeparam>
|
||||
/// <typeparam name="TOut">Output type of the elements of the array</typeparam>
|
||||
/// <returns>New array with updated elements</returns>
|
||||
public static TOut[] Map<TIn, TOut>(this IReadOnlyCollection<TIn> col, Func<TIn, TOut> f)
|
||||
{
|
||||
var toReturn = new TOut[col.Count];
|
@@ -1,8 +1,6 @@
|
||||
using NadekoBot.Common.Collections;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace NadekoBot.Extensions;
|
||||
namespace Nadeko.Common;
|
||||
|
||||
public static class EnumerableExtensions
|
||||
{
|
35
src/Nadeko.Common/Extensions/HttpClientExtensions.cs
Normal file
35
src/Nadeko.Common/Extensions/HttpClientExtensions.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
using System.Net.Http.Headers;
|
||||
|
||||
namespace Nadeko.Common;
|
||||
|
||||
public static class HttpClientExtensions
|
||||
{
|
||||
public static HttpClient AddFakeHeaders(this HttpClient http)
|
||||
{
|
||||
AddFakeHeaders(http.DefaultRequestHeaders);
|
||||
return http;
|
||||
}
|
||||
|
||||
public static void AddFakeHeaders(this HttpHeaders dict)
|
||||
{
|
||||
dict.Clear();
|
||||
dict.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
|
||||
dict.Add("User-Agent",
|
||||
"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.202 Safari/535.1");
|
||||
}
|
||||
|
||||
public static bool IsImage(this HttpResponseMessage msg)
|
||||
=> IsImage(msg, out _);
|
||||
|
||||
public static bool IsImage(this HttpResponseMessage msg, out string? mimeType)
|
||||
{
|
||||
mimeType = msg.Content.Headers.ContentType?.MediaType;
|
||||
if (mimeType is "image/png" or "image/jpeg" or "image/gif")
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static long GetContentLength(this HttpResponseMessage msg)
|
||||
=> msg.Content.Headers.ContentLength ?? long.MaxValue;
|
||||
}
|
@@ -1,5 +1,4 @@
|
||||
namespace NadekoBot.Extensions;
|
||||
|
||||
namespace Nadeko.Common;
|
||||
|
||||
public delegate TOut PipeFunc<TIn, out TOut>(in TIn a);
|
||||
public delegate TOut PipeFunc<TIn1, TIn2, out TOut>(in TIn1 a, in TIn2 b);
|
1
src/Nadeko.Common/GlobalUsings.cs
Normal file
1
src/Nadeko.Common/GlobalUsings.cs
Normal file
@@ -0,0 +1 @@
|
||||
global using NonBlocking;
|
@@ -1,9 +1,9 @@
|
||||
#nullable disable
|
||||
using Serilog.Events;
|
||||
using Serilog.Sinks.SystemConsole.Themes;
|
||||
using System.Text;
|
||||
using Serilog;
|
||||
|
||||
namespace NadekoBot.Services;
|
||||
namespace Nadeko.Common;
|
||||
|
||||
public static class LogSetup
|
||||
{
|
@@ -1,5 +1,4 @@
|
||||
#nullable disable
|
||||
namespace NadekoBot.Services;
|
||||
namespace Nadeko.Common;
|
||||
|
||||
public static class StandardConversions
|
||||
{
|
@@ -1,7 +1,6 @@
|
||||
#nullable disable
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace NadekoBot.Common;
|
||||
namespace Nadeko.Common;
|
||||
|
||||
// needs proper invalid input check (character array input out of range)
|
||||
// needs negative number support
|
||||
@@ -90,7 +89,7 @@ public readonly struct kwum : IEquatable<kwum>
|
||||
return new(chars);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
public override bool Equals(object? obj)
|
||||
=> obj is kwum kw && kw == this;
|
||||
|
||||
public bool Equals(kwum other)
|
14
src/Nadeko.Common/Nadeko.Common.csproj
Normal file
14
src/Nadeko.Common/Nadeko.Common.csproj
Normal file
@@ -0,0 +1,14 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="NonBlocking" Version="2.1.0" />
|
||||
|
||||
<PackageReference Include="Serilog.Sinks.Console" Version="4.0.1" />
|
||||
</ItemGroup>
|
||||
</Project>
|
@@ -1,7 +1,7 @@
|
||||
#nullable disable
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace NadekoBot.Common;
|
||||
namespace Nadeko.Common;
|
||||
|
||||
public class NadekoRandom : Random
|
||||
{
|
@@ -1,6 +1,7 @@
|
||||
using System.Threading.Channels;
|
||||
using Serilog;
|
||||
|
||||
namespace NadekoBot.Common;
|
||||
namespace Nadeko.Common;
|
||||
|
||||
public sealed class QueueRunner
|
||||
{
|
19
src/Nadeko.Common/ShmartBankAmount.cs
Normal file
19
src/Nadeko.Common/ShmartBankAmount.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
namespace Nadeko.Common;
|
||||
|
||||
public readonly struct ShmartBankAmount
|
||||
{
|
||||
public long Amount { get; }
|
||||
public ShmartBankAmount(long amount)
|
||||
{
|
||||
Amount = amount;
|
||||
}
|
||||
|
||||
public static implicit operator ShmartBankAmount(long num)
|
||||
=> new(num);
|
||||
|
||||
public static implicit operator long(ShmartBankAmount num)
|
||||
=> num.Amount;
|
||||
|
||||
public static implicit operator ShmartBankAmount(int num)
|
||||
=> new(num);
|
||||
}
|
@@ -1,17 +1,12 @@
|
||||
#nullable disable
|
||||
using System;
|
||||
namespace Nadeko.Common;
|
||||
|
||||
namespace NadekoBot.Common;
|
||||
|
||||
public struct ShmartNumber : IEquatable<ShmartNumber>
|
||||
public readonly struct ShmartNumber : IEquatable<ShmartNumber>
|
||||
{
|
||||
public long Value { get; }
|
||||
public string Input { get; }
|
||||
|
||||
public ShmartNumber(long val, string input = null)
|
||||
public ShmartNumber(long val)
|
||||
{
|
||||
Value = val;
|
||||
Input = input;
|
||||
}
|
||||
|
||||
public static implicit operator ShmartNumber(long num)
|
||||
@@ -26,14 +21,14 @@ public struct ShmartNumber : IEquatable<ShmartNumber>
|
||||
public override string ToString()
|
||||
=> Value.ToString();
|
||||
|
||||
public override bool Equals(object obj)
|
||||
public override bool Equals(object? obj)
|
||||
=> obj is ShmartNumber sn && Equals(sn);
|
||||
|
||||
public bool Equals(ShmartNumber other)
|
||||
=> other.Value == Value;
|
||||
|
||||
public override int GetHashCode()
|
||||
=> Value.GetHashCode() ^ Input.GetHashCode(StringComparison.InvariantCulture);
|
||||
=> Value.GetHashCode();
|
||||
|
||||
public static bool operator ==(ShmartNumber left, ShmartNumber right)
|
||||
=> left.Equals(right);
|
@@ -1,5 +1,5 @@
|
||||
#nullable disable
|
||||
namespace NadekoBot.Modules.Gambling.Common;
|
||||
namespace Nadeko.Econ;
|
||||
|
||||
public class Deck
|
||||
{
|
||||
@@ -272,7 +272,7 @@ public class Deck
|
||||
|
||||
public string GetValueText()
|
||||
=> _cardNames[Number];
|
||||
|
||||
|
||||
public override string ToString()
|
||||
=> _cardNames[Number] + " Of " + Suit;
|
||||
|
5
src/Nadeko.Econ/Deck/NewCard.cs
Normal file
5
src/Nadeko.Econ/Deck/NewCard.cs
Normal file
@@ -0,0 +1,5 @@
|
||||
namespace Nadeko.Econ;
|
||||
|
||||
public abstract record class NewCard<TSuit, TValue>(TSuit Suit, TValue Value)
|
||||
where TSuit : struct, Enum
|
||||
where TValue : struct, Enum;
|
54
src/Nadeko.Econ/Deck/NewDeck.cs
Normal file
54
src/Nadeko.Econ/Deck/NewDeck.cs
Normal file
@@ -0,0 +1,54 @@
|
||||
namespace Nadeko.Econ;
|
||||
|
||||
public abstract class NewDeck<TCard, TSuit, TValue>
|
||||
where TCard: NewCard<TSuit, TValue>
|
||||
where TSuit : struct, Enum
|
||||
where TValue : struct, Enum
|
||||
{
|
||||
protected static readonly TSuit[] _suits = Enum.GetValues<TSuit>();
|
||||
protected static readonly TValue[] _values = Enum.GetValues<TValue>();
|
||||
|
||||
public virtual int CurrentCount
|
||||
=> _cards.Count;
|
||||
|
||||
public virtual int TotalCount { get; }
|
||||
|
||||
protected readonly LinkedList<TCard> _cards = new();
|
||||
public NewDeck()
|
||||
{
|
||||
TotalCount = _suits.Length * _values.Length;
|
||||
}
|
||||
|
||||
public virtual TCard? Draw()
|
||||
{
|
||||
var first = _cards.First;
|
||||
if (first is not null)
|
||||
{
|
||||
_cards.RemoveFirst();
|
||||
return first.Value;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public virtual TCard? Peek(int x = 0)
|
||||
{
|
||||
var card = _cards.First;
|
||||
for (var i = 0; i < x; i++)
|
||||
{
|
||||
card = card?.Next;
|
||||
}
|
||||
|
||||
return card?.Value;
|
||||
}
|
||||
|
||||
public virtual void Shuffle()
|
||||
{
|
||||
var cards = _cards.ToList();
|
||||
var newCards = cards.Shuffle();
|
||||
|
||||
_cards.Clear();
|
||||
foreach (var card in newCards)
|
||||
_cards.AddFirst(card);
|
||||
}
|
||||
}
|
@@ -0,0 +1,28 @@
|
||||
namespace Nadeko.Econ;
|
||||
|
||||
public class MultipleRegularDeck : NewDeck<RegularCard, RegularSuit, RegularValue>
|
||||
{
|
||||
private int Decks { get; }
|
||||
|
||||
public override int TotalCount { get; }
|
||||
|
||||
public MultipleRegularDeck(int decks = 1)
|
||||
{
|
||||
if (decks < 1)
|
||||
throw new ArgumentOutOfRangeException(nameof(decks), "Has to be more than 0");
|
||||
|
||||
Decks = decks;
|
||||
TotalCount = base.TotalCount * decks;
|
||||
|
||||
for (var i = 0; i < Decks; i++)
|
||||
{
|
||||
foreach (var suit in _suits)
|
||||
{
|
||||
foreach (var val in _values)
|
||||
{
|
||||
_cards.AddLast((RegularCard)Activator.CreateInstance(typeof(RegularCard), suit, val)!);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
4
src/Nadeko.Econ/Deck/Regular/RegularCard.cs
Normal file
4
src/Nadeko.Econ/Deck/Regular/RegularCard.cs
Normal file
@@ -0,0 +1,4 @@
|
||||
namespace Nadeko.Econ;
|
||||
|
||||
public sealed record class RegularCard(RegularSuit Suit, RegularValue Value)
|
||||
: NewCard<RegularSuit, RegularValue>(Suit, Value);
|
15
src/Nadeko.Econ/Deck/Regular/RegularDeck.cs
Normal file
15
src/Nadeko.Econ/Deck/Regular/RegularDeck.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
namespace Nadeko.Econ;
|
||||
|
||||
public sealed class RegularDeck : NewDeck<RegularCard, RegularSuit, RegularValue>
|
||||
{
|
||||
public RegularDeck()
|
||||
{
|
||||
foreach (var suit in _suits)
|
||||
{
|
||||
foreach (var val in _values)
|
||||
{
|
||||
_cards.AddLast((RegularCard)Activator.CreateInstance(typeof(RegularCard), suit, val)!);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
56
src/Nadeko.Econ/Deck/Regular/RegularDeckExtensions.cs
Normal file
56
src/Nadeko.Econ/Deck/Regular/RegularDeckExtensions.cs
Normal file
@@ -0,0 +1,56 @@
|
||||
namespace Nadeko.Econ;
|
||||
|
||||
public static class RegularDeckExtensions
|
||||
{
|
||||
public static string GetEmoji(this RegularSuit suit)
|
||||
=> suit switch
|
||||
{
|
||||
RegularSuit.Hearts => "♥️",
|
||||
RegularSuit.Spades => "♠️",
|
||||
RegularSuit.Diamonds => "♦️",
|
||||
_ => "♣️",
|
||||
};
|
||||
|
||||
public static string GetEmoji(this RegularValue value)
|
||||
=> value switch
|
||||
{
|
||||
RegularValue.Ace => "🇦",
|
||||
RegularValue.Two => "2️⃣",
|
||||
RegularValue.Three => "3️⃣",
|
||||
RegularValue.Four => "4️⃣",
|
||||
RegularValue.Five => "5️⃣",
|
||||
RegularValue.Six => "6️⃣",
|
||||
RegularValue.Seven => "7️⃣",
|
||||
RegularValue.Eight => "8️⃣",
|
||||
RegularValue.Nine => "9️⃣",
|
||||
RegularValue.Ten => "🔟",
|
||||
RegularValue.Jack => "🇯",
|
||||
RegularValue.Queen => "🇶",
|
||||
_ => "🇰",
|
||||
};
|
||||
|
||||
public static string GetEmoji(this RegularCard card)
|
||||
=> $"{card.Value.GetEmoji()} {card.Suit.GetEmoji()}";
|
||||
|
||||
public static string GetName(this RegularValue value)
|
||||
=> value.ToString();
|
||||
|
||||
public static string GetName(this RegularSuit suit)
|
||||
=> suit.ToString();
|
||||
|
||||
public static string GetName(this RegularCard card)
|
||||
=> $"{card.Value.ToString()} of {card.Suit.GetName()}";
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
9
src/Nadeko.Econ/Deck/Regular/RegularSuit.cs
Normal file
9
src/Nadeko.Econ/Deck/Regular/RegularSuit.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace Nadeko.Econ;
|
||||
|
||||
public enum RegularSuit
|
||||
{
|
||||
Hearts,
|
||||
Diamonds,
|
||||
Clubs,
|
||||
Spades
|
||||
}
|
18
src/Nadeko.Econ/Deck/Regular/RegularValue.cs
Normal file
18
src/Nadeko.Econ/Deck/Regular/RegularValue.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
namespace Nadeko.Econ;
|
||||
|
||||
public enum RegularValue
|
||||
{
|
||||
Ace = 1,
|
||||
Two = 2,
|
||||
Three = 3,
|
||||
Four = 4,
|
||||
Five = 5,
|
||||
Six = 6,
|
||||
Seven = 7,
|
||||
Eight = 8,
|
||||
Nine = 9,
|
||||
Ten = 10,
|
||||
Jack = 12,
|
||||
Queen = 13,
|
||||
King = 14,
|
||||
}
|
7
src/Nadeko.Econ/Gambling/Betdraw/BetdrawColorGuess.cs
Normal file
7
src/Nadeko.Econ/Gambling/Betdraw/BetdrawColorGuess.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace Nadeko.Econ.Gambling.Betdraw;
|
||||
|
||||
public enum BetdrawColorGuess
|
||||
{
|
||||
Red,
|
||||
Black
|
||||
}
|
86
src/Nadeko.Econ/Gambling/Betdraw/BetdrawGame.cs
Normal file
86
src/Nadeko.Econ/Gambling/Betdraw/BetdrawGame.cs
Normal file
@@ -0,0 +1,86 @@
|
||||
using Serilog;
|
||||
|
||||
namespace Nadeko.Econ.Gambling.Betdraw;
|
||||
|
||||
public sealed class BetdrawGame
|
||||
{
|
||||
private static readonly NadekoRandom _rng = new();
|
||||
private readonly RegularDeck _deck;
|
||||
|
||||
private const decimal SINGLE_GUESS_MULTI = 2.075M;
|
||||
private const decimal DOUBLE_GUESS_MULTI = 4.15M;
|
||||
|
||||
public BetdrawGame()
|
||||
{
|
||||
_deck = new RegularDeck();
|
||||
}
|
||||
|
||||
public BetdrawResult Draw(BetdrawValueGuess? val, BetdrawColorGuess? col, decimal amount)
|
||||
{
|
||||
if (val is null && col is null)
|
||||
throw new ArgumentNullException(nameof(val));
|
||||
|
||||
var card = _deck.Peek(_rng.Next(0, 52))!;
|
||||
|
||||
var realVal = (int)card.Value < 7
|
||||
? BetdrawValueGuess.Low
|
||||
: BetdrawValueGuess.High;
|
||||
|
||||
var realCol = card.Suit is RegularSuit.Diamonds or RegularSuit.Hearts
|
||||
? BetdrawColorGuess.Red
|
||||
: BetdrawColorGuess.Black;
|
||||
|
||||
// if card is 7, autoloss
|
||||
if (card.Value == RegularValue.Seven)
|
||||
{
|
||||
return new()
|
||||
{
|
||||
Won = 0M,
|
||||
Multiplier = 0M,
|
||||
ResultType = BetdrawResultType.Lose,
|
||||
Card = card,
|
||||
};
|
||||
}
|
||||
|
||||
byte win = 0;
|
||||
if (val is BetdrawValueGuess valGuess)
|
||||
{
|
||||
if (realVal != valGuess)
|
||||
return new()
|
||||
{
|
||||
Won = 0M,
|
||||
Multiplier = 0M,
|
||||
ResultType = BetdrawResultType.Lose,
|
||||
Card = card
|
||||
};
|
||||
|
||||
++win;
|
||||
}
|
||||
|
||||
if (col is BetdrawColorGuess colGuess)
|
||||
{
|
||||
if (realCol != colGuess)
|
||||
return new()
|
||||
{
|
||||
Won = 0M,
|
||||
Multiplier = 0M,
|
||||
ResultType = BetdrawResultType.Lose,
|
||||
Card = card
|
||||
};
|
||||
|
||||
++win;
|
||||
}
|
||||
|
||||
var multi = win == 1
|
||||
? SINGLE_GUESS_MULTI
|
||||
: DOUBLE_GUESS_MULTI;
|
||||
|
||||
return new()
|
||||
{
|
||||
Won = amount * multi,
|
||||
Multiplier = multi,
|
||||
ResultType = BetdrawResultType.Win,
|
||||
Card = card
|
||||
};
|
||||
}
|
||||
}
|
9
src/Nadeko.Econ/Gambling/Betdraw/BetdrawResult.cs
Normal file
9
src/Nadeko.Econ/Gambling/Betdraw/BetdrawResult.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace Nadeko.Econ.Gambling.Betdraw;
|
||||
|
||||
public readonly struct BetdrawResult
|
||||
{
|
||||
public decimal Won { get; init; }
|
||||
public decimal Multiplier { get; init; }
|
||||
public BetdrawResultType ResultType { get; init; }
|
||||
public RegularCard Card { get; init; }
|
||||
}
|
7
src/Nadeko.Econ/Gambling/Betdraw/BetdrawResultType.cs
Normal file
7
src/Nadeko.Econ/Gambling/Betdraw/BetdrawResultType.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace Nadeko.Econ.Gambling.Betdraw;
|
||||
|
||||
public enum BetdrawResultType
|
||||
{
|
||||
Win,
|
||||
Lose
|
||||
}
|
7
src/Nadeko.Econ/Gambling/Betdraw/BetdrawValueGuess.cs
Normal file
7
src/Nadeko.Econ/Gambling/Betdraw/BetdrawValueGuess.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace Nadeko.Econ.Gambling.Betdraw;
|
||||
|
||||
public enum BetdrawValueGuess
|
||||
{
|
||||
High,
|
||||
Low,
|
||||
}
|
33
src/Nadeko.Econ/Gambling/Betflip/BetflipGame.cs
Normal file
33
src/Nadeko.Econ/Gambling/Betflip/BetflipGame.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
namespace Nadeko.Econ.Gambling;
|
||||
|
||||
public sealed class BetflipGame
|
||||
{
|
||||
private readonly decimal _winMulti;
|
||||
private static readonly NadekoRandom _rng = new NadekoRandom();
|
||||
|
||||
public BetflipGame(decimal winMulti)
|
||||
{
|
||||
_winMulti = winMulti;
|
||||
}
|
||||
|
||||
public BetflipResult Flip(byte guess, decimal amount)
|
||||
{
|
||||
var side = (byte)_rng.Next(0, 2);
|
||||
if (side == guess)
|
||||
{
|
||||
return new BetflipResult()
|
||||
{
|
||||
Side = side,
|
||||
Won = amount * _winMulti,
|
||||
Multiplier = _winMulti
|
||||
};
|
||||
}
|
||||
|
||||
return new BetflipResult()
|
||||
{
|
||||
Side = side,
|
||||
Won = 0,
|
||||
Multiplier = 0,
|
||||
};
|
||||
}
|
||||
}
|
8
src/Nadeko.Econ/Gambling/Betflip/BetflipResult.cs
Normal file
8
src/Nadeko.Econ/Gambling/Betflip/BetflipResult.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace Nadeko.Econ.Gambling;
|
||||
|
||||
public readonly struct BetflipResult
|
||||
{
|
||||
public decimal Won { get; init; }
|
||||
public byte Side { get; init; }
|
||||
public decimal Multiplier { get; init; }
|
||||
}
|
42
src/Nadeko.Econ/Gambling/Betroll/BetrollGame.cs
Normal file
42
src/Nadeko.Econ/Gambling/Betroll/BetrollGame.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
namespace Nadeko.Econ.Gambling;
|
||||
|
||||
public sealed class BetrollGame
|
||||
{
|
||||
private readonly (int WhenAbove, decimal MultiplyBy)[] _thresholdPairs;
|
||||
private readonly NadekoRandom _rng;
|
||||
|
||||
public BetrollGame(IReadOnlyList<(int WhenAbove, decimal MultiplyBy)> pairs)
|
||||
{
|
||||
_thresholdPairs = pairs.OrderByDescending(x => x.WhenAbove).ToArray();
|
||||
_rng = new();
|
||||
}
|
||||
|
||||
public BetrollResult Roll(decimal amount = 0)
|
||||
{
|
||||
var roll = _rng.Next(1, 101);
|
||||
|
||||
for (var i = 0; i < _thresholdPairs.Length; i++)
|
||||
{
|
||||
ref var pair = ref _thresholdPairs[i];
|
||||
|
||||
if (pair.WhenAbove < roll)
|
||||
{
|
||||
return new()
|
||||
{
|
||||
Multiplier = pair.MultiplyBy,
|
||||
Roll = roll,
|
||||
Threshold = pair.WhenAbove,
|
||||
Won = amount * pair.MultiplyBy
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return new()
|
||||
{
|
||||
Multiplier = 0,
|
||||
Roll = roll,
|
||||
Threshold = -1,
|
||||
Won = 0,
|
||||
};
|
||||
}
|
||||
}
|
9
src/Nadeko.Econ/Gambling/Betroll/BetrollResult.cs
Normal file
9
src/Nadeko.Econ/Gambling/Betroll/BetrollResult.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace Nadeko.Econ.Gambling;
|
||||
|
||||
public readonly struct BetrollResult
|
||||
{
|
||||
public int Roll { get; init; }
|
||||
public decimal Multiplier { get; init; }
|
||||
public decimal Threshold { get; init; }
|
||||
public decimal Won { get; init; }
|
||||
}
|
75
src/Nadeko.Econ/Gambling/Rps/RpsGame.cs
Normal file
75
src/Nadeko.Econ/Gambling/Rps/RpsGame.cs
Normal file
@@ -0,0 +1,75 @@
|
||||
namespace Nadeko.Econ.Gambling.Rps;
|
||||
|
||||
public sealed class RpsGame
|
||||
{
|
||||
private static readonly NadekoRandom _rng = new NadekoRandom();
|
||||
|
||||
const decimal WIN_MULTI = 1.95m;
|
||||
const decimal DRAW_MULTI = 1m;
|
||||
const decimal LOSE_MULTI = 0m;
|
||||
|
||||
public RpsGame()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public RpsResult Play(RpsPick pick, decimal amount)
|
||||
{
|
||||
var compPick = (RpsPick)_rng.Next(0, 3);
|
||||
if (compPick == pick)
|
||||
{
|
||||
return new()
|
||||
{
|
||||
Won = amount * DRAW_MULTI,
|
||||
Multiplier = DRAW_MULTI,
|
||||
ComputerPick = compPick,
|
||||
Result = RpsResultType.Draw,
|
||||
};
|
||||
}
|
||||
|
||||
if ((compPick == RpsPick.Paper && pick == RpsPick.Rock)
|
||||
|| (compPick == RpsPick.Rock && pick == RpsPick.Scissors)
|
||||
|| (compPick == RpsPick.Scissors && pick == RpsPick.Paper))
|
||||
{
|
||||
return new()
|
||||
{
|
||||
Won = amount * LOSE_MULTI,
|
||||
Multiplier = LOSE_MULTI,
|
||||
Result = RpsResultType.Lose,
|
||||
ComputerPick = compPick,
|
||||
};
|
||||
}
|
||||
|
||||
return new()
|
||||
{
|
||||
Won = amount * WIN_MULTI,
|
||||
Multiplier = WIN_MULTI,
|
||||
Result = RpsResultType.Win,
|
||||
ComputerPick = compPick,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public enum RpsPick : byte
|
||||
{
|
||||
Rock = 0,
|
||||
Paper = 1,
|
||||
Scissors = 2,
|
||||
}
|
||||
|
||||
public enum RpsResultType : byte
|
||||
{
|
||||
Win,
|
||||
Draw,
|
||||
Lose
|
||||
}
|
||||
|
||||
|
||||
|
||||
public readonly struct RpsResult
|
||||
{
|
||||
public decimal Won { get; init; }
|
||||
public decimal Multiplier { get; init; }
|
||||
public RpsResultType Result { get; init; }
|
||||
public RpsPick ComputerPick { get; init; }
|
||||
}
|
113
src/Nadeko.Econ/Gambling/Slot/SlotGame.cs
Normal file
113
src/Nadeko.Econ/Gambling/Slot/SlotGame.cs
Normal file
@@ -0,0 +1,113 @@
|
||||
namespace Nadeko.Econ.Gambling;
|
||||
|
||||
public class SlotGame
|
||||
{
|
||||
private static readonly NadekoRandom _rng = new NadekoRandom();
|
||||
|
||||
public SlotResult Spin(decimal bet)
|
||||
{
|
||||
var rolls = new[]
|
||||
{
|
||||
(byte)_rng.Next(0, 6),
|
||||
(byte)_rng.Next(0, 6),
|
||||
(byte)_rng.Next(0, 6)
|
||||
};
|
||||
|
||||
ref var a = ref rolls[0];
|
||||
ref var b = ref rolls[1];
|
||||
ref var c = ref rolls[2];
|
||||
|
||||
var multi = 0;
|
||||
var winType = SlotWinType.None;
|
||||
if (a == b && b == c)
|
||||
{
|
||||
if (a == 5)
|
||||
{
|
||||
winType = SlotWinType.TrippleJoker;
|
||||
multi = 30;
|
||||
}
|
||||
else
|
||||
{
|
||||
winType = SlotWinType.TrippleNormal;
|
||||
multi = 10;
|
||||
}
|
||||
}
|
||||
else if (a == 5 && (b == 5 || c == 5)
|
||||
|| (b == 5 && c == 5))
|
||||
{
|
||||
winType = SlotWinType.DoubleJoker;
|
||||
multi = 4;
|
||||
}
|
||||
else if (a == 5 || b == 5 || c == 5)
|
||||
{
|
||||
winType = SlotWinType.SingleJoker;
|
||||
multi = 1;
|
||||
}
|
||||
|
||||
return new()
|
||||
{
|
||||
Won = bet * multi,
|
||||
WinType = winType,
|
||||
Multiplier = multi,
|
||||
Rolls = rolls,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public enum SlotWinType : byte
|
||||
{
|
||||
None,
|
||||
SingleJoker,
|
||||
DoubleJoker,
|
||||
TrippleNormal,
|
||||
TrippleJoker,
|
||||
}
|
||||
|
||||
/*
|
||||
var rolls = new[]
|
||||
{
|
||||
_rng.Next(default(byte), 6),
|
||||
_rng.Next(default(byte), 6),
|
||||
_rng.Next(default(byte), 6)
|
||||
};
|
||||
|
||||
var multi = 0;
|
||||
var winType = SlotWinType.None;
|
||||
|
||||
ref var a = ref rolls[0];
|
||||
ref var b = ref rolls[1];
|
||||
ref var c = ref rolls[2];
|
||||
if (a == b && b == c)
|
||||
{
|
||||
if (a == 5)
|
||||
{
|
||||
winType = SlotWinType.TrippleJoker;
|
||||
multi = 30;
|
||||
}
|
||||
else
|
||||
{
|
||||
winType = SlotWinType.TrippleNormal;
|
||||
multi = 10;
|
||||
}
|
||||
}
|
||||
else if (a == 5 && (b == 5 || c == 5)
|
||||
|| (b == 5 && c == 5))
|
||||
{
|
||||
winType = SlotWinType.DoubleJoker;
|
||||
multi = 4;
|
||||
}
|
||||
else if (rolls.Any(x => x == 5))
|
||||
{
|
||||
winType = SlotWinType.SingleJoker;
|
||||
multi = 1;
|
||||
}
|
||||
|
||||
return new()
|
||||
{
|
||||
Won = bet * multi,
|
||||
WinType = winType,
|
||||
Multiplier = multi,
|
||||
Rolls = rolls,
|
||||
};
|
||||
}
|
||||
*/
|
9
src/Nadeko.Econ/Gambling/Slot/SlotResult.cs
Normal file
9
src/Nadeko.Econ/Gambling/Slot/SlotResult.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace Nadeko.Econ.Gambling;
|
||||
|
||||
public readonly struct SlotResult
|
||||
{
|
||||
public decimal Multiplier { get; init; }
|
||||
public byte[] Rolls { get; init; }
|
||||
public decimal Won { get; init; }
|
||||
public SlotWinType WinType { get; init; }
|
||||
}
|
9
src/Nadeko.Econ/Gambling/Wof/LuLaResult.cs
Normal file
9
src/Nadeko.Econ/Gambling/Wof/LuLaResult.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace Nadeko.Econ.Gambling;
|
||||
|
||||
public readonly struct LuLaResult
|
||||
{
|
||||
public int Index { get; init; }
|
||||
public decimal Multiplier { get; init; }
|
||||
public decimal Won { get; init; }
|
||||
public IReadOnlyList<decimal> Multipliers { get; init; }
|
||||
}
|
34
src/Nadeko.Econ/Gambling/Wof/WofGame.cs
Normal file
34
src/Nadeko.Econ/Gambling/Wof/WofGame.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
namespace Nadeko.Econ.Gambling;
|
||||
|
||||
public sealed class LulaGame
|
||||
{
|
||||
private static readonly IReadOnlyList<decimal> DEFAULT_MULTIPLIERS = new[] { 1.7M, 1.5M, 0.2M, 0.1M, 0.3M, 0.5M, 1.2M, 2.4M };
|
||||
|
||||
private readonly IReadOnlyList<decimal> _multipliers;
|
||||
private static readonly NadekoRandom _rng = new();
|
||||
|
||||
public LulaGame(IReadOnlyList<decimal> multipliers)
|
||||
{
|
||||
_multipliers = multipliers;
|
||||
}
|
||||
|
||||
public LulaGame() : this(DEFAULT_MULTIPLIERS)
|
||||
{
|
||||
}
|
||||
|
||||
public LuLaResult Spin(long bet)
|
||||
{
|
||||
var result = _rng.Next(0, _multipliers.Count);
|
||||
|
||||
var multi = _multipliers[result];
|
||||
var amount = bet * multi;
|
||||
|
||||
return new()
|
||||
{
|
||||
Index = result,
|
||||
Multiplier = multi,
|
||||
Won = amount,
|
||||
Multipliers = _multipliers.ToArray(),
|
||||
};
|
||||
}
|
||||
}
|
1
src/Nadeko.Econ/GlobalUsings.cs
Normal file
1
src/Nadeko.Econ/GlobalUsings.cs
Normal file
@@ -0,0 +1 @@
|
||||
global using Nadeko.Common;
|
13
src/Nadeko.Econ/Nadeko.Econ.csproj
Normal file
13
src/Nadeko.Econ/Nadeko.Econ.csproj
Normal file
@@ -0,0 +1,13 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Nadeko.Common\Nadeko.Common.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
@@ -47,7 +47,7 @@ public static class MedusaExtensions
|
||||
=> ctx.Message.AddReactionAsync(new Emoji("🤔"));
|
||||
|
||||
public static Task<IUserMessage> ErrorLocalizedAsync(this AnyContext ctx, string key, params object[]? args)
|
||||
=> ctx.SendErrorAsync(ctx.GetText(key));
|
||||
=> ctx.SendErrorAsync(ctx.GetText(key, args));
|
||||
|
||||
public static Task<IUserMessage> PendingLocalizedAsync(this AnyContext ctx, string key, params object[]? args)
|
||||
=> ctx.SendPendingAsync(ctx.GetText(key, args));
|
||||
@@ -56,11 +56,11 @@ public static class MedusaExtensions
|
||||
=> ctx.SendConfirmAsync(ctx.GetText(key, args));
|
||||
|
||||
public static Task<IUserMessage> ReplyErrorLocalizedAsync(this AnyContext ctx, string key, params object[]? args)
|
||||
=> ctx.SendErrorAsync($"{Format.Bold(ctx.User.ToString())} {ctx.GetText(key)}");
|
||||
=> ctx.SendErrorAsync($"{Format.Bold(ctx.User.ToString())} {ctx.GetText(key, args)}");
|
||||
|
||||
public static Task<IUserMessage> ReplyPendingLocalizedAsync(this AnyContext ctx, string key, params object[]? args)
|
||||
=> ctx.SendPendingAsync($"{Format.Bold(ctx.User.ToString())} {ctx.GetText(key)}");
|
||||
=> ctx.SendPendingAsync($"{Format.Bold(ctx.User.ToString())} {ctx.GetText(key, args)}");
|
||||
|
||||
public static Task<IUserMessage> ReplyConfirmLocalizedAsync(this AnyContext ctx, string key, params object[]? args)
|
||||
=> ctx.SendConfirmAsync($"{Format.Bold(ctx.User.ToString())} {ctx.GetText(key)}");
|
||||
=> ctx.SendConfirmAsync($"{Format.Bold(ctx.User.ToString())} {ctx.GetText(key, args)}");
|
||||
}
|
@@ -12,7 +12,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Discord.Net.Core" Version="3.6.1" />
|
||||
<PackageReference Include="Discord.Net.Core" Version="3.103.0" />
|
||||
<PackageReference Include="Serilog" Version="2.11.0" />
|
||||
<PackageReference Include="YamlDotNet" Version="11.2.1" />
|
||||
</ItemGroup>
|
||||
|
@@ -9,7 +9,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Grpc.AspNetCore" Version="2.45.0" />
|
||||
<PackageReference Include="Grpc.AspNetCore" Version="2.47.0" />
|
||||
<PackageReference Include="Serilog" Version="2.11.0" />
|
||||
<PackageReference Include="Serilog.Sinks.Console" Version="4.0.1" />
|
||||
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
|
||||
|
@@ -1,336 +1,336 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.CodeDom.Compiler;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using Microsoft.CodeAnalysis.Text;
|
||||
|
||||
namespace NadekoBot.Generators.Command;
|
||||
|
||||
[Generator]
|
||||
public class CommandAttributesGenerator : IIncrementalGenerator
|
||||
{
|
||||
public const string ATTRIBUTE = @"// <AutoGenerated />
|
||||
|
||||
namespace NadekoBot.Common;
|
||||
|
||||
[System.AttributeUsage(System.AttributeTargets.Method)]
|
||||
public class CmdAttribute : System.Attribute
|
||||
{
|
||||
|
||||
}";
|
||||
|
||||
public class MethodModel
|
||||
{
|
||||
public string? Namespace { get; }
|
||||
public IReadOnlyCollection<string> Classes { get; }
|
||||
public string ReturnType { get; }
|
||||
public string MethodName { get; }
|
||||
public IEnumerable<string> Params { get; }
|
||||
|
||||
public MethodModel(string? ns, IReadOnlyCollection<string> classes, string returnType, string methodName, IEnumerable<string> @params)
|
||||
{
|
||||
Namespace = ns;
|
||||
Classes = classes;
|
||||
ReturnType = returnType;
|
||||
MethodName = methodName;
|
||||
Params = @params;
|
||||
}
|
||||
}
|
||||
|
||||
public class FileModel
|
||||
{
|
||||
public string? Namespace { get; }
|
||||
public IReadOnlyCollection<string> ClassHierarchy { get; }
|
||||
public IReadOnlyCollection<MethodModel> Methods { get; }
|
||||
|
||||
public FileModel(string? ns, IReadOnlyCollection<string> classHierarchy, IReadOnlyCollection<MethodModel> methods)
|
||||
{
|
||||
Namespace = ns;
|
||||
ClassHierarchy = classHierarchy;
|
||||
Methods = methods;
|
||||
}
|
||||
}
|
||||
|
||||
public void Initialize(IncrementalGeneratorInitializationContext context)
|
||||
{
|
||||
// #if DEBUG
|
||||
// if (!Debugger.IsAttached)
|
||||
// Debugger.Launch();
|
||||
// // SpinWait.SpinUntil(() => Debugger.IsAttached);
|
||||
// #endif
|
||||
context.RegisterPostInitializationOutput(static ctx => ctx.AddSource(
|
||||
"CmdAttribute.g.cs",
|
||||
SourceText.From(ATTRIBUTE, Encoding.UTF8)));
|
||||
|
||||
var methods = context.SyntaxProvider
|
||||
.CreateSyntaxProvider(
|
||||
static (node, _) => node is MethodDeclarationSyntax { AttributeLists.Count: > 0 },
|
||||
static (ctx, cancel) => Transform(ctx, cancel))
|
||||
.Where(static m => m is not null)
|
||||
.Where(static m => m?.ChildTokens().Any(static x => x.IsKind(SyntaxKind.PublicKeyword)) ?? false);
|
||||
|
||||
var compilationMethods = context.CompilationProvider.Combine(methods.Collect());
|
||||
|
||||
context.RegisterSourceOutput(compilationMethods,
|
||||
static (ctx, tuple) => RegisterAction(in ctx, tuple.Left, in tuple.Right));
|
||||
}
|
||||
|
||||
private static void RegisterAction(in SourceProductionContext ctx,
|
||||
Compilation comp,
|
||||
in ImmutableArray<MethodDeclarationSyntax?> methods)
|
||||
{
|
||||
if (methods is { IsDefaultOrEmpty: true })
|
||||
return;
|
||||
|
||||
var models = GetModels(comp, methods, ctx.CancellationToken);
|
||||
|
||||
foreach (var model in models)
|
||||
{
|
||||
var name = $"{model.Namespace}.{string.Join(".", model.ClassHierarchy)}.g.cs";
|
||||
try
|
||||
{
|
||||
var source = GetSourceText(model);
|
||||
ctx.AddSource(name, SourceText.From(source, Encoding.UTF8));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Error writing source file {name}\n" + ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetSourceText(FileModel model)
|
||||
{
|
||||
using var sw = new StringWriter();
|
||||
using var tw = new IndentedTextWriter(sw);
|
||||
|
||||
tw.WriteLine("// <AutoGenerated />");
|
||||
tw.WriteLine("#pragma warning disable CS1066");
|
||||
|
||||
if (model.Namespace is not null)
|
||||
{
|
||||
tw.WriteLine($"namespace {model.Namespace};");
|
||||
tw.WriteLine();
|
||||
}
|
||||
|
||||
foreach (var className in model.ClassHierarchy)
|
||||
{
|
||||
tw.WriteLine($"public partial class {className}");
|
||||
tw.WriteLine("{");
|
||||
tw.Indent ++;
|
||||
}
|
||||
|
||||
foreach (var method in model.Methods)
|
||||
{
|
||||
tw.WriteLine("[NadekoCommand]");
|
||||
tw.WriteLine("[NadekoDescription]");
|
||||
tw.WriteLine("[Aliases]");
|
||||
tw.WriteLine($"public partial {method.ReturnType} {method.MethodName}({string.Join(", ", method.Params)});");
|
||||
}
|
||||
|
||||
foreach (var _ in model.ClassHierarchy)
|
||||
{
|
||||
tw.Indent --;
|
||||
tw.WriteLine("}");
|
||||
}
|
||||
|
||||
tw.Flush();
|
||||
return sw.ToString();
|
||||
}
|
||||
|
||||
private static IReadOnlyCollection<FileModel> GetModels(Compilation compilation,
|
||||
in ImmutableArray<MethodDeclarationSyntax?> inputMethods,
|
||||
CancellationToken cancel)
|
||||
{
|
||||
var models = new List<FileModel>();
|
||||
|
||||
var methods = inputMethods
|
||||
.Where(static x => x is not null)
|
||||
.Distinct();
|
||||
|
||||
var methodModels = methods
|
||||
.Select(x => MethodDeclarationToMethodModel(compilation, x!))
|
||||
.Where(static x => x is not null)
|
||||
.Cast<MethodModel>();
|
||||
|
||||
var groups = methodModels
|
||||
.GroupBy(static x => $"{x.Namespace}.{string.Join(".", x.Classes)}");
|
||||
|
||||
foreach (var group in groups)
|
||||
{
|
||||
if (cancel.IsCancellationRequested)
|
||||
return new Collection<FileModel>();
|
||||
|
||||
if (group is null)
|
||||
continue;
|
||||
|
||||
var elems = group.ToList();
|
||||
if (elems.Count is 0)
|
||||
continue;
|
||||
|
||||
var model = new FileModel(
|
||||
methods: elems,
|
||||
ns: elems[0].Namespace,
|
||||
classHierarchy: elems![0].Classes
|
||||
);
|
||||
|
||||
models.Add(model);
|
||||
}
|
||||
|
||||
|
||||
return models;
|
||||
}
|
||||
|
||||
private static MethodModel? MethodDeclarationToMethodModel(Compilation comp, MethodDeclarationSyntax decl)
|
||||
{
|
||||
// SpinWait.SpinUntil(static () => Debugger.IsAttached);
|
||||
|
||||
SemanticModel semanticModel;
|
||||
try
|
||||
{
|
||||
semanticModel = comp.GetSemanticModel(decl.SyntaxTree);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// for some reason this method can throw "Not part of this compilation" argument exception
|
||||
return null;
|
||||
}
|
||||
|
||||
var methodModel = new MethodModel(
|
||||
@params: decl.ParameterList.Parameters
|
||||
.Where(p => p.Type is not null)
|
||||
.Select(p =>
|
||||
{
|
||||
var prefix = p.Modifiers.Any(static x => x.IsKind(SyntaxKind.ParamsKeyword))
|
||||
? "params "
|
||||
: string.Empty;
|
||||
|
||||
var type = semanticModel
|
||||
.GetTypeInfo(p.Type!)
|
||||
.Type
|
||||
?.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
|
||||
|
||||
|
||||
var name = p.Identifier.Text;
|
||||
|
||||
var suffix = string.Empty;
|
||||
if (p.Default is not null)
|
||||
{
|
||||
if (p.Default.Value is LiteralExpressionSyntax)
|
||||
{
|
||||
suffix = " = " + p.Default.Value;
|
||||
}
|
||||
else if (p.Default.Value is MemberAccessExpressionSyntax maes)
|
||||
{
|
||||
var maesSemModel = comp.GetSemanticModel(maes.SyntaxTree);
|
||||
var sym = maesSemModel.GetSymbolInfo(maes.Name);
|
||||
if (sym.Symbol is null)
|
||||
{
|
||||
suffix = " = " + p.Default.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
suffix = " = " + sym.Symbol.ToDisplayString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $"{prefix}{type} {name}{suffix}";
|
||||
})
|
||||
.ToList(),
|
||||
methodName: decl.Identifier.Text,
|
||||
returnType: decl.ReturnType.ToString(),
|
||||
ns: GetNamespace(decl),
|
||||
classes: GetClasses(decl)
|
||||
);
|
||||
|
||||
return methodModel;
|
||||
}
|
||||
|
||||
//https://github.com/andrewlock/NetEscapades.EnumGenerators/blob/main/src/NetEscapades.EnumGenerators/EnumGenerator.cs
|
||||
static string? GetNamespace(MethodDeclarationSyntax declarationSyntax)
|
||||
{
|
||||
// determine the namespace the class is declared in, if any
|
||||
string? nameSpace = null;
|
||||
var parentOfInterest = declarationSyntax.Parent;
|
||||
while (parentOfInterest is not null)
|
||||
{
|
||||
parentOfInterest = parentOfInterest.Parent;
|
||||
|
||||
if (parentOfInterest is BaseNamespaceDeclarationSyntax ns)
|
||||
{
|
||||
nameSpace = ns.Name.ToString();
|
||||
while (true)
|
||||
{
|
||||
if (ns.Parent is not NamespaceDeclarationSyntax parent)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
ns = parent;
|
||||
nameSpace = $"{ns.Name}.{nameSpace}";
|
||||
}
|
||||
|
||||
return nameSpace;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return nameSpace;
|
||||
}
|
||||
|
||||
static IReadOnlyCollection<string> GetClasses(MethodDeclarationSyntax declarationSyntax)
|
||||
{
|
||||
// determine the namespace the class is declared in, if any
|
||||
var classes = new LinkedList<string>();
|
||||
var parentOfInterest = declarationSyntax.Parent;
|
||||
while (parentOfInterest is not null)
|
||||
{
|
||||
if (parentOfInterest is ClassDeclarationSyntax cds)
|
||||
{
|
||||
classes.AddFirst(cds.Identifier.ToString());
|
||||
}
|
||||
|
||||
parentOfInterest = parentOfInterest.Parent;
|
||||
}
|
||||
|
||||
Debug.WriteLine($"Method {declarationSyntax.Identifier.Text} has {classes.Count} classes");
|
||||
|
||||
return classes;
|
||||
}
|
||||
|
||||
private static MethodDeclarationSyntax? Transform(GeneratorSyntaxContext ctx, CancellationToken cancel)
|
||||
{
|
||||
var methodDecl = ctx.Node as MethodDeclarationSyntax;
|
||||
if (methodDecl is null)
|
||||
return default;
|
||||
|
||||
foreach (var attListSyntax in methodDecl.AttributeLists)
|
||||
{
|
||||
foreach (var attSyntax in attListSyntax.Attributes)
|
||||
{
|
||||
if (cancel.IsCancellationRequested)
|
||||
return default;
|
||||
|
||||
var symbol = ctx.SemanticModel.GetSymbolInfo(attSyntax).Symbol;
|
||||
if (symbol is not IMethodSymbol attSymbol)
|
||||
continue;
|
||||
|
||||
if (attSymbol.ContainingType.ToDisplayString() == "NadekoBot.Common.CmdAttribute")
|
||||
return methodDecl;
|
||||
}
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
}
|
||||
// #nullable enable
|
||||
// using System;
|
||||
// using System.CodeDom.Compiler;
|
||||
// using System.Collections.Generic;
|
||||
// using System.Collections.Immutable;
|
||||
// using System.Collections.ObjectModel;
|
||||
// using System.Diagnostics;
|
||||
// using System.IO;
|
||||
// using System.Linq;
|
||||
// using System.Text;
|
||||
// using System.Threading;
|
||||
// using Microsoft.CodeAnalysis;
|
||||
// using Microsoft.CodeAnalysis.CSharp;
|
||||
// using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
// using Microsoft.CodeAnalysis.Text;
|
||||
//
|
||||
// namespace NadekoBot.Generators.Command;
|
||||
//
|
||||
// [Generator]
|
||||
// public class CommandAttributesGenerator : IIncrementalGenerator
|
||||
// {
|
||||
// public const string ATTRIBUTE = @"// <AutoGenerated />
|
||||
//
|
||||
// namespace NadekoBot.Common;
|
||||
//
|
||||
// [System.AttributeUsage(System.AttributeTargets.Method)]
|
||||
// public class CmdAttribute : System.Attribute
|
||||
// {
|
||||
//
|
||||
// }";
|
||||
//
|
||||
// public class MethodModel
|
||||
// {
|
||||
// public string? Namespace { get; }
|
||||
// public IReadOnlyCollection<string> Classes { get; }
|
||||
// public string ReturnType { get; }
|
||||
// public string MethodName { get; }
|
||||
// public IEnumerable<string> Params { get; }
|
||||
//
|
||||
// public MethodModel(string? ns, IReadOnlyCollection<string> classes, string returnType, string methodName, IEnumerable<string> @params)
|
||||
// {
|
||||
// Namespace = ns;
|
||||
// Classes = classes;
|
||||
// ReturnType = returnType;
|
||||
// MethodName = methodName;
|
||||
// Params = @params;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// public class FileModel
|
||||
// {
|
||||
// public string? Namespace { get; }
|
||||
// public IReadOnlyCollection<string> ClassHierarchy { get; }
|
||||
// public IReadOnlyCollection<MethodModel> Methods { get; }
|
||||
//
|
||||
// public FileModel(string? ns, IReadOnlyCollection<string> classHierarchy, IReadOnlyCollection<MethodModel> methods)
|
||||
// {
|
||||
// Namespace = ns;
|
||||
// ClassHierarchy = classHierarchy;
|
||||
// Methods = methods;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// public void Initialize(IncrementalGeneratorInitializationContext context)
|
||||
// {
|
||||
// // #if DEBUG
|
||||
// // if (!Debugger.IsAttached)
|
||||
// // Debugger.Launch();
|
||||
// // // SpinWait.SpinUntil(() => Debugger.IsAttached);
|
||||
// // #endif
|
||||
// context.RegisterPostInitializationOutput(static ctx => ctx.AddSource(
|
||||
// "CmdAttribute.g.cs",
|
||||
// SourceText.From(ATTRIBUTE, Encoding.UTF8)));
|
||||
//
|
||||
// var methods = context.SyntaxProvider
|
||||
// .CreateSyntaxProvider(
|
||||
// static (node, _) => node is MethodDeclarationSyntax { AttributeLists.Count: > 0 },
|
||||
// static (ctx, cancel) => Transform(ctx, cancel))
|
||||
// .Where(static m => m is not null)
|
||||
// .Where(static m => m?.ChildTokens().Any(static x => x.IsKind(SyntaxKind.PublicKeyword)) ?? false);
|
||||
//
|
||||
// var compilationMethods = context.CompilationProvider.Combine(methods.Collect());
|
||||
//
|
||||
// context.RegisterSourceOutput(compilationMethods,
|
||||
// static (ctx, tuple) => RegisterAction(in ctx, tuple.Left, in tuple.Right));
|
||||
// }
|
||||
//
|
||||
// private static void RegisterAction(in SourceProductionContext ctx,
|
||||
// Compilation comp,
|
||||
// in ImmutableArray<MethodDeclarationSyntax?> methods)
|
||||
// {
|
||||
// if (methods is { IsDefaultOrEmpty: true })
|
||||
// return;
|
||||
//
|
||||
// var models = GetModels(comp, methods, ctx.CancellationToken);
|
||||
//
|
||||
// foreach (var model in models)
|
||||
// {
|
||||
// var name = $"{model.Namespace}.{string.Join(".", model.ClassHierarchy)}.g.cs";
|
||||
// try
|
||||
// {
|
||||
// var source = GetSourceText(model);
|
||||
// ctx.AddSource(name, SourceText.From(source, Encoding.UTF8));
|
||||
// }
|
||||
// catch (Exception ex)
|
||||
// {
|
||||
// Console.WriteLine($"Error writing source file {name}\n" + ex);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private static string GetSourceText(FileModel model)
|
||||
// {
|
||||
// using var sw = new StringWriter();
|
||||
// using var tw = new IndentedTextWriter(sw);
|
||||
//
|
||||
// tw.WriteLine("// <AutoGenerated />");
|
||||
// tw.WriteLine("#pragma warning disable CS1066");
|
||||
//
|
||||
// if (model.Namespace is not null)
|
||||
// {
|
||||
// tw.WriteLine($"namespace {model.Namespace};");
|
||||
// tw.WriteLine();
|
||||
// }
|
||||
//
|
||||
// foreach (var className in model.ClassHierarchy)
|
||||
// {
|
||||
// tw.WriteLine($"public partial class {className}");
|
||||
// tw.WriteLine("{");
|
||||
// tw.Indent ++;
|
||||
// }
|
||||
//
|
||||
// foreach (var method in model.Methods)
|
||||
// {
|
||||
// tw.WriteLine("[NadekoCommand]");
|
||||
// tw.WriteLine("[NadekoDescription]");
|
||||
// tw.WriteLine("[Aliases]");
|
||||
// tw.WriteLine($"public partial {method.ReturnType} {method.MethodName}({string.Join(", ", method.Params)});");
|
||||
// }
|
||||
//
|
||||
// foreach (var _ in model.ClassHierarchy)
|
||||
// {
|
||||
// tw.Indent --;
|
||||
// tw.WriteLine("}");
|
||||
// }
|
||||
//
|
||||
// tw.Flush();
|
||||
// return sw.ToString();
|
||||
// }
|
||||
//
|
||||
// private static IReadOnlyCollection<FileModel> GetModels(Compilation compilation,
|
||||
// in ImmutableArray<MethodDeclarationSyntax?> inputMethods,
|
||||
// CancellationToken cancel)
|
||||
// {
|
||||
// var models = new List<FileModel>();
|
||||
//
|
||||
// var methods = inputMethods
|
||||
// .Where(static x => x is not null)
|
||||
// .Distinct();
|
||||
//
|
||||
// var methodModels = methods
|
||||
// .Select(x => MethodDeclarationToMethodModel(compilation, x!))
|
||||
// .Where(static x => x is not null)
|
||||
// .Cast<MethodModel>();
|
||||
//
|
||||
// var groups = methodModels
|
||||
// .GroupBy(static x => $"{x.Namespace}.{string.Join(".", x.Classes)}");
|
||||
//
|
||||
// foreach (var group in groups)
|
||||
// {
|
||||
// if (cancel.IsCancellationRequested)
|
||||
// return new Collection<FileModel>();
|
||||
//
|
||||
// if (group is null)
|
||||
// continue;
|
||||
//
|
||||
// var elems = group.ToList();
|
||||
// if (elems.Count is 0)
|
||||
// continue;
|
||||
//
|
||||
// var model = new FileModel(
|
||||
// methods: elems,
|
||||
// ns: elems[0].Namespace,
|
||||
// classHierarchy: elems![0].Classes
|
||||
// );
|
||||
//
|
||||
// models.Add(model);
|
||||
// }
|
||||
//
|
||||
//
|
||||
// return models;
|
||||
// }
|
||||
//
|
||||
// private static MethodModel? MethodDeclarationToMethodModel(Compilation comp, MethodDeclarationSyntax decl)
|
||||
// {
|
||||
// // SpinWait.SpinUntil(static () => Debugger.IsAttached);
|
||||
//
|
||||
// SemanticModel semanticModel;
|
||||
// try
|
||||
// {
|
||||
// semanticModel = comp.GetSemanticModel(decl.SyntaxTree);
|
||||
// }
|
||||
// catch
|
||||
// {
|
||||
// // for some reason this method can throw "Not part of this compilation" argument exception
|
||||
// return null;
|
||||
// }
|
||||
//
|
||||
// var methodModel = new MethodModel(
|
||||
// @params: decl.ParameterList.Parameters
|
||||
// .Where(p => p.Type is not null)
|
||||
// .Select(p =>
|
||||
// {
|
||||
// var prefix = p.Modifiers.Any(static x => x.IsKind(SyntaxKind.ParamsKeyword))
|
||||
// ? "params "
|
||||
// : string.Empty;
|
||||
//
|
||||
// var type = semanticModel
|
||||
// .GetTypeInfo(p.Type!)
|
||||
// .Type
|
||||
// ?.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
|
||||
//
|
||||
//
|
||||
// var name = p.Identifier.Text;
|
||||
//
|
||||
// var suffix = string.Empty;
|
||||
// if (p.Default is not null)
|
||||
// {
|
||||
// if (p.Default.Value is LiteralExpressionSyntax)
|
||||
// {
|
||||
// suffix = " = " + p.Default.Value;
|
||||
// }
|
||||
// else if (p.Default.Value is MemberAccessExpressionSyntax maes)
|
||||
// {
|
||||
// var maesSemModel = comp.GetSemanticModel(maes.SyntaxTree);
|
||||
// var sym = maesSemModel.GetSymbolInfo(maes.Name);
|
||||
// if (sym.Symbol is null)
|
||||
// {
|
||||
// suffix = " = " + p.Default.Value;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// suffix = " = " + sym.Symbol.ToDisplayString();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return $"{prefix}{type} {name}{suffix}";
|
||||
// })
|
||||
// .ToList(),
|
||||
// methodName: decl.Identifier.Text,
|
||||
// returnType: decl.ReturnType.ToString(),
|
||||
// ns: GetNamespace(decl),
|
||||
// classes: GetClasses(decl)
|
||||
// );
|
||||
//
|
||||
// return methodModel;
|
||||
// }
|
||||
//
|
||||
// //https://github.com/andrewlock/NetEscapades.EnumGenerators/blob/main/src/NetEscapades.EnumGenerators/EnumGenerator.cs
|
||||
// static string? GetNamespace(MethodDeclarationSyntax declarationSyntax)
|
||||
// {
|
||||
// // determine the namespace the class is declared in, if any
|
||||
// string? nameSpace = null;
|
||||
// var parentOfInterest = declarationSyntax.Parent;
|
||||
// while (parentOfInterest is not null)
|
||||
// {
|
||||
// parentOfInterest = parentOfInterest.Parent;
|
||||
//
|
||||
// if (parentOfInterest is BaseNamespaceDeclarationSyntax ns)
|
||||
// {
|
||||
// nameSpace = ns.Name.ToString();
|
||||
// while (true)
|
||||
// {
|
||||
// if (ns.Parent is not NamespaceDeclarationSyntax parent)
|
||||
// {
|
||||
// break;
|
||||
// }
|
||||
//
|
||||
// ns = parent;
|
||||
// nameSpace = $"{ns.Name}.{nameSpace}";
|
||||
// }
|
||||
//
|
||||
// return nameSpace;
|
||||
// }
|
||||
//
|
||||
// }
|
||||
//
|
||||
// return nameSpace;
|
||||
// }
|
||||
//
|
||||
// static IReadOnlyCollection<string> GetClasses(MethodDeclarationSyntax declarationSyntax)
|
||||
// {
|
||||
// // determine the namespace the class is declared in, if any
|
||||
// var classes = new LinkedList<string>();
|
||||
// var parentOfInterest = declarationSyntax.Parent;
|
||||
// while (parentOfInterest is not null)
|
||||
// {
|
||||
// if (parentOfInterest is ClassDeclarationSyntax cds)
|
||||
// {
|
||||
// classes.AddFirst(cds.Identifier.ToString());
|
||||
// }
|
||||
//
|
||||
// parentOfInterest = parentOfInterest.Parent;
|
||||
// }
|
||||
//
|
||||
// Debug.WriteLine($"Method {declarationSyntax.Identifier.Text} has {classes.Count} classes");
|
||||
//
|
||||
// return classes;
|
||||
// }
|
||||
//
|
||||
// private static MethodDeclarationSyntax? Transform(GeneratorSyntaxContext ctx, CancellationToken cancel)
|
||||
// {
|
||||
// var methodDecl = ctx.Node as MethodDeclarationSyntax;
|
||||
// if (methodDecl is null)
|
||||
// return default;
|
||||
//
|
||||
// foreach (var attListSyntax in methodDecl.AttributeLists)
|
||||
// {
|
||||
// foreach (var attSyntax in attListSyntax.Attributes)
|
||||
// {
|
||||
// if (cancel.IsCancellationRequested)
|
||||
// return default;
|
||||
//
|
||||
// var symbol = ctx.SemanticModel.GetSymbolInfo(attSyntax).Symbol;
|
||||
// if (symbol is not IMethodSymbol attSymbol)
|
||||
// continue;
|
||||
//
|
||||
// if (attSymbol.ContainingType.ToDisplayString() == "NadekoBot.Common.CmdAttribute")
|
||||
// return methodDecl;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return default;
|
||||
// }
|
||||
// }
|
@@ -47,7 +47,7 @@ namespace NadekoBot.Tests
|
||||
|| !(type.GetCustomAttribute<GroupAttribute>(true) is null)) // or a submodule
|
||||
.SelectMany(x => x.GetMethods()
|
||||
.Where(mi => mi.CustomAttributes
|
||||
.Any(ca => ca.AttributeType == typeof(NadekoCommandAttribute))))
|
||||
.Any(ca => ca.AttributeType == typeof(CmdAttribute))))
|
||||
.Select(x => x.Name.ToLowerInvariant())
|
||||
.ToArray();
|
||||
|
||||
|
@@ -1,5 +1,6 @@
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Nadeko.Common;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Services;
|
||||
using NUnit.Framework;
|
||||
|
@@ -1,4 +1,4 @@
|
||||
using NadekoBot.Common.Collections;
|
||||
using Nadeko.Common;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using NUnit.Framework;
|
||||
using System;
|
||||
|
@@ -1,4 +1,5 @@
|
||||
using NadekoBot.Common;
|
||||
using Nadeko.Common;
|
||||
using NadekoBot.Common;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace NadekoBot.Tests
|
||||
|
@@ -14,6 +14,8 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Nadeko.Common\Nadeko.Common.csproj" />
|
||||
<ProjectReference Include="..\Nadeko.Econ\Nadeko.Econ.csproj" />
|
||||
<ProjectReference Include="..\NadekoBot\NadekoBot.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
|
83
src/NadekoBot.Tests/NewDeckTests.cs
Normal file
83
src/NadekoBot.Tests/NewDeckTests.cs
Normal file
@@ -0,0 +1,83 @@
|
||||
using Nadeko.Econ;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace NadekoBot.Tests;
|
||||
|
||||
public class NewDeckTests
|
||||
{
|
||||
private RegularDeck _deck;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_deck = new RegularDeck();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestCount()
|
||||
{
|
||||
Assert.AreEqual(52, _deck.TotalCount);
|
||||
Assert.AreEqual(52, _deck.CurrentCount);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestDeckDraw()
|
||||
{
|
||||
var card = _deck.Draw();
|
||||
|
||||
Assert.IsNotNull(card);
|
||||
Assert.AreEqual(card.Suit, RegularSuit.Hearts);
|
||||
Assert.AreEqual(card.Value, RegularValue.Ace);
|
||||
Assert.AreEqual(_deck.CurrentCount, _deck.TotalCount - 1);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestDeckSpent()
|
||||
{
|
||||
for (var i = 0; i < _deck.TotalCount - 1; ++i)
|
||||
{
|
||||
_deck.Draw();
|
||||
}
|
||||
|
||||
var lastCard = _deck.Draw();
|
||||
|
||||
Assert.IsNotNull(lastCard);
|
||||
Assert.AreEqual(new RegularCard(RegularSuit.Spades, RegularValue.King), lastCard);
|
||||
|
||||
var noCard = _deck.Draw();
|
||||
|
||||
Assert.IsNull(noCard);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestCardGetName()
|
||||
{
|
||||
var ace = _deck.Draw()!;
|
||||
var two = _deck.Draw()!;
|
||||
|
||||
Assert.AreEqual("Ace of Hearts", ace.GetName());
|
||||
Assert.AreEqual("Two of Hearts", two.GetName());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestPeek()
|
||||
{
|
||||
var ace = _deck.Peek()!;
|
||||
|
||||
var tenOfSpades = _deck.Peek(48);
|
||||
Assert.AreEqual(new RegularCard(RegularSuit.Hearts, RegularValue.Ace), ace);
|
||||
Assert.AreEqual(new RegularCard(RegularSuit.Spades, RegularValue.Ten), tenOfSpades);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestMultipleDeck()
|
||||
{
|
||||
var quadDeck = new MultipleRegularDeck(4);
|
||||
var count = quadDeck.TotalCount;
|
||||
|
||||
Assert.AreEqual(52 * 4, count);
|
||||
|
||||
var card = quadDeck.Peek(54);
|
||||
Assert.AreEqual(new RegularCard(RegularSuit.Hearts, RegularValue.Three), card);
|
||||
}
|
||||
}
|
@@ -7,7 +7,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="MorseCode.ITask" Version="2.0.3" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.3.1" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.3.2" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
@@ -10,6 +10,7 @@ using System.Collections.Immutable;
|
||||
using System.Diagnostics;
|
||||
using System.Net;
|
||||
using System.Reflection;
|
||||
using Nadeko.Common;
|
||||
using RunMode = Discord.Commands.RunMode;
|
||||
|
||||
namespace NadekoBot;
|
||||
@@ -34,13 +35,13 @@ public sealed class Bot
|
||||
private readonly IBotCredsProvider _credsProvider;
|
||||
// private readonly InteractionService _interactionService;
|
||||
|
||||
public Bot(int shardId, int? totalShards)
|
||||
public Bot(int shardId, int? totalShards, string credPath = null)
|
||||
{
|
||||
if (shardId < 0)
|
||||
throw new ArgumentOutOfRangeException(nameof(shardId));
|
||||
|
||||
ShardId = shardId;
|
||||
_credsProvider = new BotCredsProvider(totalShards);
|
||||
_credsProvider = new BotCredsProvider(totalShards, credPath);
|
||||
_creds = _credsProvider.GetCreds();
|
||||
|
||||
_db = new(_credsProvider);
|
||||
|
@@ -3,11 +3,16 @@ using System.Runtime.CompilerServices;
|
||||
namespace NadekoBot.Common.Attributes;
|
||||
|
||||
[AttributeUsage(AttributeTargets.Method)]
|
||||
public sealed class NadekoCommandAttribute : CommandAttribute
|
||||
public sealed class CmdAttribute : CommandAttribute
|
||||
{
|
||||
public string MethodName { get; }
|
||||
|
||||
public NadekoCommandAttribute([CallerMemberName] string memberName = "")
|
||||
public CmdAttribute([CallerMemberName] string memberName = "")
|
||||
: base(CommandNameLoadHelper.GetCommandNameFor(memberName))
|
||||
=> MethodName = memberName.ToLowerInvariant();
|
||||
{
|
||||
MethodName = memberName.ToLowerInvariant();
|
||||
Aliases = CommandNameLoadHelper.GetAliasesFor(memberName);
|
||||
Remarks = memberName.ToLowerInvariant();
|
||||
Summary = memberName.ToLowerInvariant();
|
||||
}
|
||||
}
|
@@ -1,30 +0,0 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace NadekoBot.Common.Attributes;
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
internal sealed class NadekoModuleAttribute : GroupAttribute
|
||||
{
|
||||
public NadekoModuleAttribute(string moduleName)
|
||||
: base(moduleName)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Method)]
|
||||
internal sealed class NadekoDescriptionAttribute : SummaryAttribute
|
||||
{
|
||||
public NadekoDescriptionAttribute([CallerMemberName] string name = "")
|
||||
: base(name.ToLowerInvariant())
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Method)]
|
||||
internal sealed class NadekoUsageAttribute : RemarksAttribute
|
||||
{
|
||||
public NadekoUsageAttribute([CallerMemberName] string name = "")
|
||||
: base(name.ToLowerInvariant())
|
||||
{
|
||||
}
|
||||
}
|
@@ -12,7 +12,7 @@ namespace NadekoBot.Common.Configs;
|
||||
public sealed partial class BotConfig : ICloneable<BotConfig>
|
||||
{
|
||||
[Comment(@"DO NOT CHANGE")]
|
||||
public int Version { get; set; } = 3;
|
||||
public int Version { get; set; } = 4;
|
||||
|
||||
[Comment(@"Most commands, when executed, have a small colored line
|
||||
next to the response. The color depends whether the command
|
||||
@@ -29,12 +29,8 @@ and copy the hex code fo your selected color (marked as #)")]
|
||||
Allowed values: Simple, Normal, None")]
|
||||
public ConsoleOutputType ConsoleOutputType { get; set; }
|
||||
|
||||
// [Comment(@"For what kind of updates will the bot check.
|
||||
// Allowed values: Release, Commit, None")]
|
||||
// public UpdateCheckType CheckForUpdates { get; set; }
|
||||
|
||||
// [Comment(@"How often will the bot check for updates, in hours")]
|
||||
// public int CheckUpdateInterval { get; set; }
|
||||
[Comment(@"Whether the bot will check for new releases every hour")]
|
||||
public bool CheckForUpdates { get; set; } = true;
|
||||
|
||||
[Comment(@"Do you want any messages sent by users in Bot's DM to be forwarded to the owner(s)?")]
|
||||
public bool ForwardMessages { get; set; }
|
||||
|
20
src/NadekoBot/Common/Interaction/SimpleInteraction.cs
Normal file
20
src/NadekoBot/Common/Interaction/SimpleInteraction.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
namespace NadekoBot;
|
||||
|
||||
public class SimpleInteraction<T>
|
||||
{
|
||||
public ButtonBuilder Button { get; }
|
||||
private readonly Func<SocketMessageComponent, T, Task> _onClick;
|
||||
private readonly T? _state;
|
||||
|
||||
public SimpleInteraction(ButtonBuilder button, Func<SocketMessageComponent, T?, Task> onClick, T? state = default)
|
||||
{
|
||||
Button = button;
|
||||
_onClick = onClick;
|
||||
_state = state;
|
||||
}
|
||||
|
||||
public async Task TriggerAsync(SocketMessageComponent smc)
|
||||
{
|
||||
await _onClick(smc, _state!);
|
||||
}
|
||||
}
|
@@ -1,47 +0,0 @@
|
||||
#nullable disable
|
||||
namespace NadekoBot.Common;
|
||||
|
||||
public class OldImageUrls
|
||||
{
|
||||
public int Version { get; set; } = 2;
|
||||
|
||||
public CoinData Coins { get; set; }
|
||||
public Uri[] Currency { get; set; }
|
||||
public Uri[] Dice { get; set; }
|
||||
public RategirlData Rategirl { get; set; }
|
||||
public XpData Xp { get; set; }
|
||||
|
||||
//new
|
||||
public RipData Rip { get; set; }
|
||||
public SlotData Slots { get; set; }
|
||||
|
||||
public class RipData
|
||||
{
|
||||
public Uri Bg { get; set; }
|
||||
public Uri Overlay { get; set; }
|
||||
}
|
||||
|
||||
public class SlotData
|
||||
{
|
||||
public Uri[] Emojis { get; set; }
|
||||
public Uri[] Numbers { get; set; }
|
||||
public Uri Bg { get; set; }
|
||||
}
|
||||
|
||||
public class CoinData
|
||||
{
|
||||
public Uri[] Heads { get; set; }
|
||||
public Uri[] Tails { get; set; }
|
||||
}
|
||||
|
||||
public class RategirlData
|
||||
{
|
||||
public Uri Matrix { get; set; }
|
||||
public Uri Dot { get; set; }
|
||||
}
|
||||
|
||||
public class XpData
|
||||
{
|
||||
public Uri Bg { get; set; }
|
||||
}
|
||||
}
|
@@ -1,25 +0,0 @@
|
||||
#nullable disable
|
||||
namespace NadekoBot.Common;
|
||||
|
||||
public static class PlatformHelper
|
||||
{
|
||||
private const int PROCESSOR_COUNT_REFRESH_INTERVAL_MS = 30000;
|
||||
|
||||
private static volatile int processorCount;
|
||||
private static volatile int lastProcessorCountRefreshTicks;
|
||||
|
||||
public static int ProcessorCount
|
||||
{
|
||||
get
|
||||
{
|
||||
var now = Environment.TickCount;
|
||||
if (processorCount == 0 || now - lastProcessorCountRefreshTicks >= PROCESSOR_COUNT_REFRESH_INTERVAL_MS)
|
||||
{
|
||||
processorCount = Environment.ProcessorCount;
|
||||
lastProcessorCountRefreshTicks = now;
|
||||
}
|
||||
|
||||
return processorCount;
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,5 +1,6 @@
|
||||
#nullable disable
|
||||
using System.Text.RegularExpressions;
|
||||
using Nadeko.Common;
|
||||
|
||||
namespace NadekoBot.Common;
|
||||
|
||||
|
@@ -1,4 +1,6 @@
|
||||
#nullable disable
|
||||
using Nadeko.Common;
|
||||
|
||||
namespace NadekoBot.Common.TypeReaders;
|
||||
|
||||
public sealed class KwumTypeReader : NadekoTypeReader<kwum>
|
||||
|
@@ -0,0 +1,94 @@
|
||||
using System.Text.RegularExpressions;
|
||||
using NadekoBot.Db;
|
||||
using NadekoBot.Modules.Gambling.Services;
|
||||
using NCalc;
|
||||
using OneOf;
|
||||
|
||||
namespace NadekoBot.Common.TypeReaders;
|
||||
|
||||
public class BaseShmartInputAmountReader
|
||||
{
|
||||
private static readonly Regex _percentRegex = new(@"^((?<num>100|\d{1,2})%)$", RegexOptions.Compiled);
|
||||
protected readonly DbService _db;
|
||||
protected readonly GamblingConfigService _gambling;
|
||||
|
||||
public BaseShmartInputAmountReader(DbService db, GamblingConfigService gambling)
|
||||
{
|
||||
_db = db;
|
||||
_gambling = gambling;
|
||||
}
|
||||
|
||||
public async ValueTask<OneOf<long, OneOf.Types.Error<string>>> ReadAsync(ICommandContext context, string input)
|
||||
{
|
||||
var i = input.Trim().ToUpperInvariant();
|
||||
|
||||
i = i.Replace("K", "000");
|
||||
|
||||
//can't add m because it will conflict with max atm
|
||||
|
||||
if (await TryHandlePercentage(context, i) is long num)
|
||||
{
|
||||
return num;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var expr = new Expression(i, EvaluateOptions.IgnoreCase);
|
||||
expr.EvaluateParameter += (str, ev) => EvaluateParam(str, ev, context).GetAwaiter().GetResult();
|
||||
return (long)decimal.Parse(expr.Evaluate().ToString()!);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return new OneOf.Types.Error<string>($"Invalid input: {input}");
|
||||
}
|
||||
}
|
||||
|
||||
private async Task EvaluateParam(string name, ParameterArgs args, ICommandContext ctx)
|
||||
{
|
||||
switch (name.ToUpperInvariant())
|
||||
{
|
||||
case "PI":
|
||||
args.Result = Math.PI;
|
||||
break;
|
||||
case "E":
|
||||
args.Result = Math.E;
|
||||
break;
|
||||
case "ALL":
|
||||
case "ALLIN":
|
||||
args.Result = await Cur(ctx);
|
||||
break;
|
||||
case "HALF":
|
||||
args.Result = await Cur(ctx) / 2;
|
||||
break;
|
||||
case "MAX":
|
||||
args.Result = await Max(ctx);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual async Task<long> Cur(ICommandContext ctx)
|
||||
{
|
||||
await using var uow = _db.GetDbContext();
|
||||
return await uow.DiscordUser.GetUserCurrencyAsync(ctx.User.Id);
|
||||
}
|
||||
|
||||
protected virtual async Task<long> Max(ICommandContext ctx)
|
||||
{
|
||||
var settings = _gambling.Data;
|
||||
var max = settings.MaxBet;
|
||||
return max == 0 ? await Cur(ctx) : max;
|
||||
}
|
||||
|
||||
private async Task<long?> TryHandlePercentage(ICommandContext ctx, string input)
|
||||
{
|
||||
var m = _percentRegex.Match(input);
|
||||
|
||||
if (m.Captures.Count == 0)
|
||||
return null;
|
||||
|
||||
if (!long.TryParse(m.Groups["num"].ToString(), out var percent))
|
||||
return null;
|
||||
|
||||
return (long)(await Cur(ctx) * (percent / 100.0f));
|
||||
}
|
||||
}
|
@@ -0,0 +1,32 @@
|
||||
#nullable disable
|
||||
using NadekoBot.Modules.Gambling.Bank;
|
||||
using NadekoBot.Modules.Gambling.Services;
|
||||
|
||||
namespace NadekoBot.Common.TypeReaders;
|
||||
|
||||
public sealed class ShmartBankAmountTypeReader : NadekoTypeReader<ShmartBankAmount>
|
||||
{
|
||||
private readonly IBankService _bank;
|
||||
private readonly ShmartBankInputAmountReader _tr;
|
||||
|
||||
public ShmartBankAmountTypeReader(IBankService bank, DbService db, GamblingConfigService gambling)
|
||||
{
|
||||
_bank = bank;
|
||||
_tr = new ShmartBankInputAmountReader(bank, db, gambling);
|
||||
}
|
||||
|
||||
public override async ValueTask<TypeReaderResult<ShmartBankAmount>> ReadAsync(ICommandContext ctx, string input)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(input))
|
||||
return TypeReaderResult.FromError<ShmartBankAmount>(CommandError.ParseFailed, "Input is empty.");
|
||||
|
||||
var result = await _tr.ReadAsync(ctx, input);
|
||||
|
||||
if (result.TryPickT0(out var val, out var err))
|
||||
{
|
||||
return TypeReaderResult.FromSuccess<ShmartBankAmount>(new(val));
|
||||
}
|
||||
|
||||
return TypeReaderResult.FromError<ShmartBankAmount>(CommandError.Unsuccessful, err.Value);
|
||||
}
|
||||
}
|
@@ -0,0 +1,21 @@
|
||||
using NadekoBot.Modules.Gambling.Bank;
|
||||
using NadekoBot.Modules.Gambling.Services;
|
||||
|
||||
namespace NadekoBot.Common.TypeReaders;
|
||||
|
||||
public sealed class ShmartBankInputAmountReader : BaseShmartInputAmountReader
|
||||
{
|
||||
private readonly IBankService _bank;
|
||||
|
||||
public ShmartBankInputAmountReader(IBankService bank, DbService db, GamblingConfigService gambling)
|
||||
: base(db, gambling)
|
||||
{
|
||||
_bank = bank;
|
||||
}
|
||||
|
||||
protected override Task<long> Cur(ICommandContext ctx)
|
||||
=> _bank.GetBalanceAsync(ctx.User.Id);
|
||||
|
||||
protected override Task<long> Max(ICommandContext ctx)
|
||||
=> Cur(ctx);
|
||||
}
|
@@ -0,0 +1,29 @@
|
||||
#nullable disable
|
||||
using NadekoBot.Modules.Gambling.Services;
|
||||
|
||||
namespace NadekoBot.Common.TypeReaders;
|
||||
|
||||
public sealed class ShmartNumberTypeReader : NadekoTypeReader<ShmartNumber>
|
||||
{
|
||||
private readonly BaseShmartInputAmountReader _tr;
|
||||
|
||||
public ShmartNumberTypeReader(DbService db, GamblingConfigService gambling)
|
||||
{
|
||||
_tr = new BaseShmartInputAmountReader(db, gambling);
|
||||
}
|
||||
|
||||
public override async ValueTask<TypeReaderResult<ShmartNumber>> ReadAsync(ICommandContext ctx, string input)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(input))
|
||||
return TypeReaderResult.FromError<ShmartNumber>(CommandError.ParseFailed, "Input is empty.");
|
||||
|
||||
var result = await _tr.ReadAsync(ctx, input);
|
||||
|
||||
if (result.TryPickT0(out var val, out var err))
|
||||
{
|
||||
return TypeReaderResult.FromSuccess<ShmartNumber>(new(val));
|
||||
}
|
||||
|
||||
return TypeReaderResult.FromError<ShmartNumber>(CommandError.Unsuccessful, err.Value);
|
||||
}
|
||||
}
|
@@ -1,99 +0,0 @@
|
||||
#nullable disable
|
||||
using NadekoBot.Db;
|
||||
using NadekoBot.Modules.Gambling.Services;
|
||||
using NCalc;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace NadekoBot.Common.TypeReaders;
|
||||
|
||||
public sealed class ShmartNumberTypeReader : NadekoTypeReader<ShmartNumber>
|
||||
{
|
||||
private static readonly Regex _percentRegex = new(@"^((?<num>100|\d{1,2})%)$", RegexOptions.Compiled);
|
||||
private readonly DbService _db;
|
||||
private readonly GamblingConfigService _gambling;
|
||||
|
||||
public ShmartNumberTypeReader(DbService db, GamblingConfigService gambling)
|
||||
{
|
||||
_db = db;
|
||||
_gambling = gambling;
|
||||
}
|
||||
|
||||
public override ValueTask<TypeReaderResult<ShmartNumber>> ReadAsync(ICommandContext context, string input)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(input))
|
||||
return new(TypeReaderResult.FromError<ShmartNumber>(CommandError.ParseFailed, "Input is empty."));
|
||||
|
||||
var i = input.Trim().ToUpperInvariant();
|
||||
|
||||
i = i.Replace("K", "000");
|
||||
|
||||
//can't add m because it will conflict with max atm
|
||||
|
||||
if (TryHandlePercentage(context, i, out var num))
|
||||
return new(TypeReaderResult.FromSuccess(new ShmartNumber(num, i)));
|
||||
try
|
||||
{
|
||||
var expr = new Expression(i, EvaluateOptions.IgnoreCase);
|
||||
expr.EvaluateParameter += (str, ev) => EvaluateParam(str, ev, context);
|
||||
var lon = (long)decimal.Parse(expr.Evaluate().ToString());
|
||||
return new(TypeReaderResult.FromSuccess(new ShmartNumber(lon, input)));
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return ValueTask.FromResult(
|
||||
TypeReaderResult.FromError<ShmartNumber>(CommandError.ParseFailed, $"Invalid input: {input}"));
|
||||
}
|
||||
}
|
||||
|
||||
private void EvaluateParam(string name, ParameterArgs args, ICommandContext ctx)
|
||||
{
|
||||
switch (name.ToUpperInvariant())
|
||||
{
|
||||
case "PI":
|
||||
args.Result = Math.PI;
|
||||
break;
|
||||
case "E":
|
||||
args.Result = Math.E;
|
||||
break;
|
||||
case "ALL":
|
||||
case "ALLIN":
|
||||
args.Result = Cur(ctx);
|
||||
break;
|
||||
case "HALF":
|
||||
args.Result = Cur(ctx) / 2;
|
||||
break;
|
||||
case "MAX":
|
||||
args.Result = Max(ctx);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private long Cur(ICommandContext ctx)
|
||||
{
|
||||
using var uow = _db.GetDbContext();
|
||||
return uow.DiscordUser.GetUserCurrency(ctx.User.Id);
|
||||
}
|
||||
|
||||
private long Max(ICommandContext ctx)
|
||||
{
|
||||
var settings = _gambling.Data;
|
||||
var max = settings.MaxBet;
|
||||
return max == 0 ? Cur(ctx) : max;
|
||||
}
|
||||
|
||||
private bool TryHandlePercentage(ICommandContext ctx, string input, out long num)
|
||||
{
|
||||
num = 0;
|
||||
var m = _percentRegex.Match(input);
|
||||
if (m.Captures.Count != 0)
|
||||
{
|
||||
if (!long.TryParse(m.Groups["num"].ToString(), out var percent))
|
||||
return false;
|
||||
|
||||
num = (long)(Cur(ctx) * (percent / 100.0f));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
@@ -108,8 +108,8 @@ public static class DiscordUserExtensions
|
||||
.Take(count)
|
||||
.ToList();
|
||||
|
||||
public static long GetUserCurrency(this DbSet<DiscordUser> users, ulong userId)
|
||||
=> users.AsNoTracking().FirstOrDefault(x => x.UserId == userId)?.CurrencyAmount ?? 0;
|
||||
public static async Task<long> GetUserCurrencyAsync(this DbSet<DiscordUser> users, ulong userId)
|
||||
=> (await users.FirstOrDefaultAsyncLinqToDB(x => x.UserId == userId))?.CurrencyAmount ?? 0;
|
||||
|
||||
public static void RemoveFromMany(this DbSet<DiscordUser> users, IEnumerable<ulong> ids)
|
||||
{
|
||||
|
@@ -1,5 +1,4 @@
|
||||
#nullable disable
|
||||
using NadekoBot.Common.Collections;
|
||||
using NadekoBot.Db.Models;
|
||||
|
||||
namespace NadekoBot.Services.Database.Models;
|
||||
|
@@ -5,4 +5,11 @@ public class ImageOnlyChannel : DbEntity
|
||||
{
|
||||
public ulong GuildId { get; set; }
|
||||
public ulong ChannelId { get; set; }
|
||||
public OnlyChannelType Type { get; set; }
|
||||
}
|
||||
|
||||
public enum OnlyChannelType
|
||||
{
|
||||
Image,
|
||||
Link
|
||||
}
|
@@ -4,11 +4,6 @@ using System.Diagnostics;
|
||||
|
||||
namespace NadekoBot.Services.Database.Models;
|
||||
|
||||
public interface IIndexed
|
||||
{
|
||||
int Index { get; set; }
|
||||
}
|
||||
|
||||
[DebuggerDisplay("{PrimaryTarget}{SecondaryTarget} {SecondaryTargetName} {State} {PrimaryTargetId}")]
|
||||
public class Permissionv2 : DbEntity, IIndexed
|
||||
{
|
||||
|
@@ -1,6 +1,4 @@
|
||||
#nullable disable
|
||||
using NadekoBot.Common.Collections;
|
||||
|
||||
namespace NadekoBot.Services.Database.Models;
|
||||
|
||||
public class Poll : DbEntity
|
||||
|
18
src/NadekoBot/Db/Models/XpShopOwnedItem.cs
Normal file
18
src/NadekoBot/Db/Models/XpShopOwnedItem.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
#nullable disable warnings
|
||||
using NadekoBot.Services.Database.Models;
|
||||
|
||||
namespace NadekoBot.Db.Models;
|
||||
|
||||
public class XpShopOwnedItem : DbEntity
|
||||
{
|
||||
public ulong UserId { get; set; }
|
||||
public XpShopItemType ItemType { get; set; }
|
||||
public bool IsUsing { get; set; }
|
||||
public string ItemKey { get; set; }
|
||||
}
|
||||
|
||||
public enum XpShopItemType
|
||||
{
|
||||
Background,
|
||||
Frame,
|
||||
}
|
@@ -454,6 +454,23 @@ public abstract class NadekoContext : DbContext
|
||||
});
|
||||
|
||||
#endregion
|
||||
|
||||
#region Xp Item Shop
|
||||
|
||||
modelBuilder.Entity<XpShopOwnedItem>(
|
||||
x =>
|
||||
{
|
||||
// user can own only one of each item
|
||||
x.HasIndex(model => new
|
||||
{
|
||||
model.UserId,
|
||||
model.ItemType,
|
||||
model.ItemKey
|
||||
})
|
||||
.IsUnique();
|
||||
});
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
|
@@ -20,6 +20,8 @@ public sealed class PostgreSqlContext : NadekoContext
|
||||
|
||||
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
||||
{
|
||||
AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true);
|
||||
|
||||
base.OnConfiguring(optionsBuilder);
|
||||
optionsBuilder
|
||||
.UseLowerCaseNamingConvention()
|
||||
|
@@ -8,7 +8,8 @@ global using Humanizer;
|
||||
// nadekobot
|
||||
global using NadekoBot;
|
||||
global using NadekoBot.Services;
|
||||
global using NadekoBot.Common;
|
||||
global using Nadeko.Common; // new project
|
||||
global using NadekoBot.Common; // old + nadekobot specific things
|
||||
global using NadekoBot.Common.Attributes;
|
||||
global using NadekoBot.Extensions;
|
||||
global using Nadeko.Snake;
|
||||
|
@@ -1,4 +1,5 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
namespace NadekoBot.Migrations;
|
||||
|
||||
@@ -6,11 +7,36 @@ public static class MigrationQueries
|
||||
{
|
||||
public static void MigrateRero(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.Sql(
|
||||
@"insert or ignore into reactionroles(guildid, channelid, messageid, emote, roleid, 'group', levelreq, dateadded)
|
||||
if (migrationBuilder.IsMySql())
|
||||
{
|
||||
migrationBuilder.Sql(
|
||||
@"INSERT IGNORE into reactionroles(guildid, channelid, messageid, emote, roleid, `group`, levelreq, dateadded)
|
||||
select guildid, channelid, messageid, emotename, roleid, exclusive, 0, reactionrolemessage.dateadded
|
||||
from reactionrole
|
||||
left join reactionrolemessage on reactionrolemessage.id = reactionrole.reactionrolemessageid
|
||||
left join guildconfigs on reactionrolemessage.guildconfigid = guildconfigs.id;");
|
||||
}
|
||||
else if (migrationBuilder.IsSqlite())
|
||||
{
|
||||
migrationBuilder.Sql(
|
||||
@"insert or ignore into reactionroles(guildid, channelid, messageid, emote, roleid, 'group', levelreq, dateadded)
|
||||
select guildid, channelid, messageid, emotename, roleid, exclusive, 0, reactionrolemessage.dateadded
|
||||
from reactionrole
|
||||
left join reactionrolemessage on reactionrolemessage.id = reactionrole.reactionrolemessageid
|
||||
left join guildconfigs on reactionrolemessage.guildconfigid = guildconfigs.id;");
|
||||
}
|
||||
else if (migrationBuilder.IsNpgsql())
|
||||
{
|
||||
migrationBuilder.Sql(@"insert into reactionroles(guildid, channelid, messageid, emote, roleid, ""group"", levelreq, dateadded)
|
||||
select guildid, channelid, messageid, emotename, roleid, exclusive::int, 0, reactionrolemessage.dateadded
|
||||
from reactionrole
|
||||
left join reactionrolemessage on reactionrolemessage.id = reactionrole.reactionrolemessageid
|
||||
left join guildconfigs on reactionrolemessage.guildconfigid = guildconfigs.id
|
||||
ON CONFLICT DO NOTHING;");
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotSupportedException("This database provider doesn't have an implementation for MigrateRero");
|
||||
}
|
||||
}
|
||||
}
|
3556
src/NadekoBot/Migrations/MySql/20220725155953_xpitemshop.Designer.cs
generated
Normal file
3556
src/NadekoBot/Migrations/MySql/20220725155953_xpitemshop.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
45
src/NadekoBot/Migrations/MySql/20220725155953_xpitemshop.cs
Normal file
45
src/NadekoBot/Migrations/MySql/20220725155953_xpitemshop.cs
Normal file
@@ -0,0 +1,45 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace NadekoBot.Migrations.Mysql
|
||||
{
|
||||
public partial class xpitemshop : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "xpshopowneditem",
|
||||
columns: table => new
|
||||
{
|
||||
id = table.Column<int>(type: "int", nullable: false)
|
||||
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
|
||||
userid = table.Column<ulong>(type: "bigint unsigned", nullable: false),
|
||||
itemtype = table.Column<int>(type: "int", nullable: false),
|
||||
isusing = table.Column<bool>(type: "tinyint(1)", nullable: false),
|
||||
itemkey = table.Column<string>(type: "varchar(255)", nullable: false)
|
||||
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||
dateadded = table.Column<DateTime>(type: "datetime(6)", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("pk_xpshopowneditem", x => x.id);
|
||||
})
|
||||
.Annotation("MySql:CharSet", "utf8mb4");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_xpshopowneditem_userid_itemtype_itemkey",
|
||||
table: "xpshopowneditem",
|
||||
columns: new[] { "userid", "itemtype", "itemkey" },
|
||||
unique: true);
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "xpshopowneditem");
|
||||
}
|
||||
}
|
||||
}
|
3560
src/NadekoBot/Migrations/MySql/20220727033931_linkonly-channels.Designer.cs
generated
Normal file
3560
src/NadekoBot/Migrations/MySql/20220727033931_linkonly-channels.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,26 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace NadekoBot.Migrations.Mysql
|
||||
{
|
||||
public partial class linkonlychannels : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "type",
|
||||
table: "imageonlychannels",
|
||||
type: "int",
|
||||
nullable: false,
|
||||
defaultValue: 0);
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "type",
|
||||
table: "imageonlychannels");
|
||||
}
|
||||
}
|
||||
}
|
@@ -16,7 +16,7 @@ namespace NadekoBot.Migrations.Mysql
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "6.0.6")
|
||||
.HasAnnotation("ProductVersion", "6.0.7")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 64);
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.BankUser", b =>
|
||||
@@ -366,6 +366,44 @@ namespace NadekoBot.Migrations.Mysql
|
||||
b.ToTable("streamonlinemessages", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.XpShopOwnedItem", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int")
|
||||
.HasColumnName("id");
|
||||
|
||||
b.Property<DateTime?>("DateAdded")
|
||||
.HasColumnType("datetime(6)")
|
||||
.HasColumnName("dateadded");
|
||||
|
||||
b.Property<bool>("IsUsing")
|
||||
.HasColumnType("tinyint(1)")
|
||||
.HasColumnName("isusing");
|
||||
|
||||
b.Property<string>("ItemKey")
|
||||
.IsRequired()
|
||||
.HasColumnType("varchar(255)")
|
||||
.HasColumnName("itemkey");
|
||||
|
||||
b.Property<int>("ItemType")
|
||||
.HasColumnType("int")
|
||||
.HasColumnName("itemtype");
|
||||
|
||||
b.Property<ulong>("UserId")
|
||||
.HasColumnType("bigint unsigned")
|
||||
.HasColumnName("userid");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("pk_xpshopowneditem");
|
||||
|
||||
b.HasIndex("UserId", "ItemType", "ItemKey")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("ix_xpshopowneditem_userid_itemtype_itemkey");
|
||||
|
||||
b.ToTable("xpshopowneditem", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiAltSetting", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
@@ -1353,6 +1391,10 @@ namespace NadekoBot.Migrations.Mysql
|
||||
.HasColumnType("bigint unsigned")
|
||||
.HasColumnName("guildid");
|
||||
|
||||
b.Property<int>("Type")
|
||||
.HasColumnType("int")
|
||||
.HasColumnName("type");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("pk_imageonlychannels");
|
||||
|
||||
|
3700
src/NadekoBot/Migrations/Postgresql/20220725155941_xpitemshop.Designer.cs
generated
Normal file
3700
src/NadekoBot/Migrations/Postgresql/20220725155941_xpitemshop.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,43 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace NadekoBot.Migrations.PostgreSql
|
||||
{
|
||||
public partial class xpitemshop : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "xpshopowneditem",
|
||||
columns: table => new
|
||||
{
|
||||
id = table.Column<int>(type: "integer", nullable: false)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
userid = table.Column<decimal>(type: "numeric(20,0)", nullable: false),
|
||||
itemtype = table.Column<int>(type: "integer", nullable: false),
|
||||
isusing = table.Column<bool>(type: "boolean", nullable: false),
|
||||
itemkey = table.Column<string>(type: "text", nullable: false),
|
||||
dateadded = table.Column<DateTime>(type: "timestamp with time zone", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("pk_xpshopowneditem", x => x.id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_xpshopowneditem_userid_itemtype_itemkey",
|
||||
table: "xpshopowneditem",
|
||||
columns: new[] { "userid", "itemtype", "itemkey" },
|
||||
unique: true);
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "xpshopowneditem");
|
||||
}
|
||||
}
|
||||
}
|
3704
src/NadekoBot/Migrations/Postgresql/20220727033944_linkonly-channels.Designer.cs
generated
Normal file
3704
src/NadekoBot/Migrations/Postgresql/20220727033944_linkonly-channels.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,26 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace NadekoBot.Migrations.PostgreSql
|
||||
{
|
||||
public partial class linkonlychannels : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "type",
|
||||
table: "imageonlychannels",
|
||||
type: "integer",
|
||||
nullable: false,
|
||||
defaultValue: 0);
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "type",
|
||||
table: "imageonlychannels");
|
||||
}
|
||||
}
|
||||
}
|
@@ -17,7 +17,7 @@ namespace NadekoBot.Migrations.PostgreSql
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "6.0.6")
|
||||
.HasAnnotation("ProductVersion", "6.0.7")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||
|
||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||
@@ -378,6 +378,46 @@ namespace NadekoBot.Migrations.PostgreSql
|
||||
b.ToTable("streamonlinemessages", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Db.Models.XpShopOwnedItem", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("id");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<DateTime?>("DateAdded")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("dateadded");
|
||||
|
||||
b.Property<bool>("IsUsing")
|
||||
.HasColumnType("boolean")
|
||||
.HasColumnName("isusing");
|
||||
|
||||
b.Property<string>("ItemKey")
|
||||
.IsRequired()
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("itemkey");
|
||||
|
||||
b.Property<int>("ItemType")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("itemtype");
|
||||
|
||||
b.Property<decimal>("UserId")
|
||||
.HasColumnType("numeric(20,0)")
|
||||
.HasColumnName("userid");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("pk_xpshopowneditem");
|
||||
|
||||
b.HasIndex("UserId", "ItemType", "ItemKey")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("ix_xpshopowneditem_userid_itemtype_itemkey");
|
||||
|
||||
b.ToTable("xpshopowneditem", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiAltSetting", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
@@ -1417,6 +1457,10 @@ namespace NadekoBot.Migrations.PostgreSql
|
||||
.HasColumnType("numeric(20,0)")
|
||||
.HasColumnName("guildid");
|
||||
|
||||
b.Property<int>("Type")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("type");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("pk_imageonlychannels");
|
||||
|
||||
|
2855
src/NadekoBot/Migrations/Sqlite/20220725112348_xpitemshop.Designer.cs
generated
Normal file
2855
src/NadekoBot/Migrations/Sqlite/20220725112348_xpitemshop.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
42
src/NadekoBot/Migrations/Sqlite/20220725112348_xpitemshop.cs
Normal file
42
src/NadekoBot/Migrations/Sqlite/20220725112348_xpitemshop.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace NadekoBot.Migrations
|
||||
{
|
||||
public partial class xpitemshop : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "XpShopOwnedItem",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||
.Annotation("Sqlite:Autoincrement", true),
|
||||
UserId = table.Column<ulong>(type: "INTEGER", nullable: false),
|
||||
ItemType = table.Column<int>(type: "INTEGER", nullable: false),
|
||||
IsUsing = table.Column<bool>(type: "INTEGER", nullable: false),
|
||||
ItemKey = table.Column<string>(type: "TEXT", nullable: false),
|
||||
DateAdded = table.Column<DateTime>(type: "TEXT", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_XpShopOwnedItem", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_XpShopOwnedItem_UserId_ItemType_ItemKey",
|
||||
table: "XpShopOwnedItem",
|
||||
columns: new[] { "UserId", "ItemType", "ItemKey" },
|
||||
unique: true);
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "XpShopOwnedItem");
|
||||
}
|
||||
}
|
||||
}
|
2858
src/NadekoBot/Migrations/Sqlite/20220727005807_linkonly-channels.Designer.cs
generated
Normal file
2858
src/NadekoBot/Migrations/Sqlite/20220727005807_linkonly-channels.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,26 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace NadekoBot.Migrations
|
||||
{
|
||||
public partial class linkonlychannels : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "Type",
|
||||
table: "ImageOnlyChannels",
|
||||
type: "INTEGER",
|
||||
nullable: false,
|
||||
defaultValue: 0);
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "Type",
|
||||
table: "ImageOnlyChannels");
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user