mirror of
https://gitlab.com/Kwoth/nadekobot.git
synced 2025-09-10 17:28:27 -04:00
Merge branch '4.3' into 'v4'
Base for 4.3 work. See merge request Kwoth/nadekobot!259
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,5 +1,7 @@
|
|||||||
#Manually added files
|
#Manually added files
|
||||||
|
|
||||||
|
src/NadekoBot/data/last_known_version.txt
|
||||||
|
|
||||||
# medusa stuff
|
# medusa stuff
|
||||||
!src/NadekoBot/data/medusae/medusa.yml
|
!src/NadekoBot/data/medusae/medusa.yml
|
||||||
src/NadekoBot/data/medusae/**
|
src/NadekoBot/data/medusae/**
|
||||||
|
56
CHANGELOG.md
56
CHANGELOG.md
@@ -2,6 +2,62 @@
|
|||||||
|
|
||||||
Experimental changelog. Mostly based on [keepachangelog](https://keepachangelog.com/en/1.0.0/) except date format. a-c-f-r-o
|
Experimental changelog. Mostly based on [keepachangelog](https://keepachangelog.com/en/1.0.0/) except date format. a-c-f-r-o
|
||||||
|
|
||||||
|
## [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 `.imageonly` 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 checkforupdates <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
|
## [4.2.15] - 12.07.2022
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
@@ -12,6 +12,7 @@ ProjectSection(SolutionItems) = preProject
|
|||||||
README.md = README.md
|
README.md = README.md
|
||||||
.gitlab-ci.yml = .gitlab-ci.yml
|
.gitlab-ci.yml = .gitlab-ci.yml
|
||||||
Dockerfile = Dockerfile
|
Dockerfile = Dockerfile
|
||||||
|
NuGet.Config = NuGet.Config
|
||||||
EndProjectSection
|
EndProjectSection
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NadekoBot", "src\NadekoBot\NadekoBot.csproj", "{45EC1473-C678-4857-A544-07DFE0D0B478}"
|
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
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nadeko.Medusa", "src\Nadeko.Medusa\Nadeko.Medusa.csproj", "{E685977E-31A4-46F4-A5D7-4E3E39E82E43}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nadeko.Medusa", "src\Nadeko.Medusa\Nadeko.Medusa.csproj", "{E685977E-31A4-46F4-A5D7-4E3E39E82E43}"
|
||||||
EndProject
|
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
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
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}.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.ActiveCfg = Release|Any CPU
|
||||||
{E685977E-31A4-46F4-A5D7-4E3E39E82E43}.Release|Any CPU.Build.0 = 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
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
@@ -92,6 +109,8 @@ Global
|
|||||||
{3BC3BDF8-1A0B-45EB-AB2B-C0891D4D37B8} = {04929013-5BAB-42B0-B9B2-8F2BB8F16AF2}
|
{3BC3BDF8-1A0B-45EB-AB2B-C0891D4D37B8} = {04929013-5BAB-42B0-B9B2-8F2BB8F16AF2}
|
||||||
{3BC82CFE-BEE7-451F-986B-17EDD1570C4F} = {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}
|
{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
|
EndGlobalSection
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
SolutionGuid = {5F3F555C-855F-4BE8-B526-D062D3E8ACA4}
|
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>
|
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>>
|
public class AsyncLazy<T> : Lazy<Task<T>>
|
||||||
{
|
{
|
@@ -1,14 +1,9 @@
|
|||||||
#nullable enable
|
using System.Diagnostics;
|
||||||
#pragma warning disable
|
|
||||||
// License MIT
|
|
||||||
// Source: https://github.com/i3arnon/ConcurrentHashSet
|
|
||||||
|
|
||||||
using System.Diagnostics;
|
|
||||||
|
|
||||||
namespace System.Collections.Generic;
|
namespace System.Collections.Generic;
|
||||||
|
|
||||||
[DebuggerDisplay("{_backingStore.Count}")]
|
[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;
|
private readonly ConcurrentDictionary<T, bool> _backingStore;
|
||||||
|
|
@@ -1,8 +1,11 @@
|
|||||||
#nullable disable
|
using System.Collections;
|
||||||
using NadekoBot.Services.Database.Models;
|
|
||||||
using System.Collections;
|
|
||||||
|
|
||||||
namespace NadekoBot.Common.Collections;
|
namespace Nadeko.Common;
|
||||||
|
|
||||||
|
public interface IIndexed
|
||||||
|
{
|
||||||
|
int Index { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
public class IndexedCollection<T> : IList<T>
|
public class IndexedCollection<T> : IList<T>
|
||||||
where T : class, IIndexed
|
where T : class, IIndexed
|
@@ -1,6 +1,4 @@
|
|||||||
using System.Buffers;
|
namespace Nadeko.Common;
|
||||||
|
|
||||||
namespace NadekoBot.Extensions;
|
|
||||||
|
|
||||||
// made for expressions because they almost never get added
|
// made for expressions because they almost never get added
|
||||||
// and they get looped through constantly
|
// 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)
|
public static TOut[] Map<TIn, TOut>(this TIn[] arr, Func<TIn, TOut> f)
|
||||||
=> Array.ConvertAll(arr, x => f(x));
|
=> 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)
|
public static TOut[] Map<TIn, TOut>(this IReadOnlyCollection<TIn> col, Func<TIn, TOut> f)
|
||||||
{
|
{
|
||||||
var toReturn = new TOut[col.Count];
|
var toReturn = new TOut[col.Count];
|
@@ -1,8 +1,6 @@
|
|||||||
using NadekoBot.Common.Collections;
|
|
||||||
using NadekoBot.Services.Database.Models;
|
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
|
|
||||||
namespace NadekoBot.Extensions;
|
namespace Nadeko.Common;
|
||||||
|
|
||||||
public static class EnumerableExtensions
|
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<TIn, out TOut>(in TIn a);
|
||||||
public delegate TOut PipeFunc<TIn1, TIn2, out TOut>(in TIn1 a, in TIn2 b);
|
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.Events;
|
||||||
using Serilog.Sinks.SystemConsole.Themes;
|
using Serilog.Sinks.SystemConsole.Themes;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using Serilog;
|
||||||
|
|
||||||
namespace NadekoBot.Services;
|
namespace Nadeko.Common;
|
||||||
|
|
||||||
public static class LogSetup
|
public static class LogSetup
|
||||||
{
|
{
|
@@ -1,5 +1,4 @@
|
|||||||
#nullable disable
|
namespace Nadeko.Common;
|
||||||
namespace NadekoBot.Services;
|
|
||||||
|
|
||||||
public static class StandardConversions
|
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 proper invalid input check (character array input out of range)
|
||||||
// needs negative number support
|
// needs negative number support
|
||||||
@@ -90,7 +89,7 @@ public readonly struct kwum : IEquatable<kwum>
|
|||||||
return new(chars);
|
return new(chars);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool Equals(object obj)
|
public override bool Equals(object? obj)
|
||||||
=> obj is kwum kw && kw == this;
|
=> obj is kwum kw && kw == this;
|
||||||
|
|
||||||
public bool Equals(kwum other)
|
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
|
#nullable disable
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
|
|
||||||
namespace NadekoBot.Common;
|
namespace Nadeko.Common;
|
||||||
|
|
||||||
public class NadekoRandom : Random
|
public class NadekoRandom : Random
|
||||||
{
|
{
|
||||||
@@ -26,6 +26,20 @@ public class NadekoRandom : Random
|
|||||||
return Math.Abs(BitConverter.ToInt32(bytes, 0)) % maxValue;
|
return Math.Abs(BitConverter.ToInt32(bytes, 0)) % maxValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public byte Next(byte minValue, byte maxValue)
|
||||||
|
{
|
||||||
|
if (minValue > maxValue)
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(maxValue));
|
||||||
|
|
||||||
|
if (minValue == maxValue)
|
||||||
|
return minValue;
|
||||||
|
|
||||||
|
var bytes = new byte[1];
|
||||||
|
_rng.GetBytes(bytes);
|
||||||
|
|
||||||
|
return (byte)((bytes[0] % (maxValue - minValue)) + minValue);
|
||||||
|
}
|
||||||
|
|
||||||
public override int Next(int minValue, int maxValue)
|
public override int Next(int minValue, int maxValue)
|
||||||
{
|
{
|
||||||
if (minValue > maxValue)
|
if (minValue > maxValue)
|
@@ -1,6 +1,7 @@
|
|||||||
using System.Threading.Channels;
|
using System.Threading.Channels;
|
||||||
|
using Serilog;
|
||||||
|
|
||||||
namespace NadekoBot.Common;
|
namespace Nadeko.Common;
|
||||||
|
|
||||||
public sealed class QueueRunner
|
public sealed class QueueRunner
|
||||||
{
|
{
|
@@ -1,14 +1,11 @@
|
|||||||
#nullable disable
|
namespace Nadeko.Common;
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace NadekoBot.Common;
|
public readonly struct ShmartNumber : IEquatable<ShmartNumber>
|
||||||
|
|
||||||
public struct ShmartNumber : IEquatable<ShmartNumber>
|
|
||||||
{
|
{
|
||||||
public long Value { get; }
|
public long Value { get; }
|
||||||
public string Input { get; }
|
public string? Input { get; }
|
||||||
|
|
||||||
public ShmartNumber(long val, string input = null)
|
public ShmartNumber(long val, string? input = null)
|
||||||
{
|
{
|
||||||
Value = val;
|
Value = val;
|
||||||
Input = input;
|
Input = input;
|
||||||
@@ -26,14 +23,14 @@ public struct ShmartNumber : IEquatable<ShmartNumber>
|
|||||||
public override string ToString()
|
public override string ToString()
|
||||||
=> Value.ToString();
|
=> Value.ToString();
|
||||||
|
|
||||||
public override bool Equals(object obj)
|
public override bool Equals(object? obj)
|
||||||
=> obj is ShmartNumber sn && Equals(sn);
|
=> obj is ShmartNumber sn && Equals(sn);
|
||||||
|
|
||||||
public bool Equals(ShmartNumber other)
|
public bool Equals(ShmartNumber other)
|
||||||
=> other.Value == Value;
|
=> other.Value == Value;
|
||||||
|
|
||||||
public override int GetHashCode()
|
public override int GetHashCode()
|
||||||
=> Value.GetHashCode() ^ Input.GetHashCode(StringComparison.InvariantCulture);
|
=> Value.GetHashCode();
|
||||||
|
|
||||||
public static bool operator ==(ShmartNumber left, ShmartNumber right)
|
public static bool operator ==(ShmartNumber left, ShmartNumber right)
|
||||||
=> left.Equals(right);
|
=> left.Equals(right);
|
@@ -1,5 +1,5 @@
|
|||||||
#nullable disable
|
#nullable disable
|
||||||
namespace NadekoBot.Modules.Gambling.Common;
|
namespace Nadeko.Econ;
|
||||||
|
|
||||||
public class Deck
|
public class Deck
|
||||||
{
|
{
|
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 = _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(0, 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[]
|
||||||
|
{
|
||||||
|
_rng.Next(0, 6),
|
||||||
|
_rng.Next(0, 6),
|
||||||
|
_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>
|
@@ -12,7 +12,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<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="Serilog" Version="2.11.0" />
|
||||||
<PackageReference Include="YamlDotNet" Version="11.2.1" />
|
<PackageReference Include="YamlDotNet" Version="11.2.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
@@ -9,7 +9,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<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" Version="2.11.0" />
|
||||||
<PackageReference Include="Serilog.Sinks.Console" Version="4.0.1" />
|
<PackageReference Include="Serilog.Sinks.Console" Version="4.0.1" />
|
||||||
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
|
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
|
||||||
|
@@ -1,336 +1,336 @@
|
|||||||
#nullable enable
|
// #nullable enable
|
||||||
using System;
|
// using System;
|
||||||
using System.CodeDom.Compiler;
|
// using System.CodeDom.Compiler;
|
||||||
using System.Collections.Generic;
|
// using System.Collections.Generic;
|
||||||
using System.Collections.Immutable;
|
// using System.Collections.Immutable;
|
||||||
using System.Collections.ObjectModel;
|
// using System.Collections.ObjectModel;
|
||||||
using System.Diagnostics;
|
// using System.Diagnostics;
|
||||||
using System.IO;
|
// using System.IO;
|
||||||
using System.Linq;
|
// using System.Linq;
|
||||||
using System.Text;
|
// using System.Text;
|
||||||
using System.Threading;
|
// using System.Threading;
|
||||||
using Microsoft.CodeAnalysis;
|
// using Microsoft.CodeAnalysis;
|
||||||
using Microsoft.CodeAnalysis.CSharp;
|
// using Microsoft.CodeAnalysis.CSharp;
|
||||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
// using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||||
using Microsoft.CodeAnalysis.Text;
|
// using Microsoft.CodeAnalysis.Text;
|
||||||
|
//
|
||||||
namespace NadekoBot.Generators.Command;
|
// namespace NadekoBot.Generators.Command;
|
||||||
|
//
|
||||||
[Generator]
|
// [Generator]
|
||||||
public class CommandAttributesGenerator : IIncrementalGenerator
|
// public class CommandAttributesGenerator : IIncrementalGenerator
|
||||||
{
|
// {
|
||||||
public const string ATTRIBUTE = @"// <AutoGenerated />
|
// public const string ATTRIBUTE = @"// <AutoGenerated />
|
||||||
|
//
|
||||||
namespace NadekoBot.Common;
|
// namespace NadekoBot.Common;
|
||||||
|
//
|
||||||
[System.AttributeUsage(System.AttributeTargets.Method)]
|
// [System.AttributeUsage(System.AttributeTargets.Method)]
|
||||||
public class CmdAttribute : System.Attribute
|
// public class CmdAttribute : System.Attribute
|
||||||
{
|
// {
|
||||||
|
//
|
||||||
}";
|
// }";
|
||||||
|
//
|
||||||
public class MethodModel
|
// public class MethodModel
|
||||||
{
|
// {
|
||||||
public string? Namespace { get; }
|
// public string? Namespace { get; }
|
||||||
public IReadOnlyCollection<string> Classes { get; }
|
// public IReadOnlyCollection<string> Classes { get; }
|
||||||
public string ReturnType { get; }
|
// public string ReturnType { get; }
|
||||||
public string MethodName { get; }
|
// public string MethodName { get; }
|
||||||
public IEnumerable<string> Params { get; }
|
// public IEnumerable<string> Params { get; }
|
||||||
|
//
|
||||||
public MethodModel(string? ns, IReadOnlyCollection<string> classes, string returnType, string methodName, IEnumerable<string> @params)
|
// public MethodModel(string? ns, IReadOnlyCollection<string> classes, string returnType, string methodName, IEnumerable<string> @params)
|
||||||
{
|
// {
|
||||||
Namespace = ns;
|
// Namespace = ns;
|
||||||
Classes = classes;
|
// Classes = classes;
|
||||||
ReturnType = returnType;
|
// ReturnType = returnType;
|
||||||
MethodName = methodName;
|
// MethodName = methodName;
|
||||||
Params = @params;
|
// Params = @params;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
public class FileModel
|
// public class FileModel
|
||||||
{
|
// {
|
||||||
public string? Namespace { get; }
|
// public string? Namespace { get; }
|
||||||
public IReadOnlyCollection<string> ClassHierarchy { get; }
|
// public IReadOnlyCollection<string> ClassHierarchy { get; }
|
||||||
public IReadOnlyCollection<MethodModel> Methods { get; }
|
// public IReadOnlyCollection<MethodModel> Methods { get; }
|
||||||
|
//
|
||||||
public FileModel(string? ns, IReadOnlyCollection<string> classHierarchy, IReadOnlyCollection<MethodModel> methods)
|
// public FileModel(string? ns, IReadOnlyCollection<string> classHierarchy, IReadOnlyCollection<MethodModel> methods)
|
||||||
{
|
// {
|
||||||
Namespace = ns;
|
// Namespace = ns;
|
||||||
ClassHierarchy = classHierarchy;
|
// ClassHierarchy = classHierarchy;
|
||||||
Methods = methods;
|
// Methods = methods;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
public void Initialize(IncrementalGeneratorInitializationContext context)
|
// public void Initialize(IncrementalGeneratorInitializationContext context)
|
||||||
{
|
// {
|
||||||
// #if DEBUG
|
// // #if DEBUG
|
||||||
// if (!Debugger.IsAttached)
|
// // if (!Debugger.IsAttached)
|
||||||
// Debugger.Launch();
|
// // Debugger.Launch();
|
||||||
// // SpinWait.SpinUntil(() => Debugger.IsAttached);
|
// // // SpinWait.SpinUntil(() => Debugger.IsAttached);
|
||||||
// #endif
|
// // #endif
|
||||||
context.RegisterPostInitializationOutput(static ctx => ctx.AddSource(
|
// context.RegisterPostInitializationOutput(static ctx => ctx.AddSource(
|
||||||
"CmdAttribute.g.cs",
|
// "CmdAttribute.g.cs",
|
||||||
SourceText.From(ATTRIBUTE, Encoding.UTF8)));
|
// SourceText.From(ATTRIBUTE, Encoding.UTF8)));
|
||||||
|
//
|
||||||
var methods = context.SyntaxProvider
|
// var methods = context.SyntaxProvider
|
||||||
.CreateSyntaxProvider(
|
// .CreateSyntaxProvider(
|
||||||
static (node, _) => node is MethodDeclarationSyntax { AttributeLists.Count: > 0 },
|
// static (node, _) => node is MethodDeclarationSyntax { AttributeLists.Count: > 0 },
|
||||||
static (ctx, cancel) => Transform(ctx, cancel))
|
// static (ctx, cancel) => Transform(ctx, cancel))
|
||||||
.Where(static m => m is not null)
|
// .Where(static m => m is not null)
|
||||||
.Where(static m => m?.ChildTokens().Any(static x => x.IsKind(SyntaxKind.PublicKeyword)) ?? false);
|
// .Where(static m => m?.ChildTokens().Any(static x => x.IsKind(SyntaxKind.PublicKeyword)) ?? false);
|
||||||
|
//
|
||||||
var compilationMethods = context.CompilationProvider.Combine(methods.Collect());
|
// var compilationMethods = context.CompilationProvider.Combine(methods.Collect());
|
||||||
|
//
|
||||||
context.RegisterSourceOutput(compilationMethods,
|
// context.RegisterSourceOutput(compilationMethods,
|
||||||
static (ctx, tuple) => RegisterAction(in ctx, tuple.Left, in tuple.Right));
|
// static (ctx, tuple) => RegisterAction(in ctx, tuple.Left, in tuple.Right));
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
private static void RegisterAction(in SourceProductionContext ctx,
|
// private static void RegisterAction(in SourceProductionContext ctx,
|
||||||
Compilation comp,
|
// Compilation comp,
|
||||||
in ImmutableArray<MethodDeclarationSyntax?> methods)
|
// in ImmutableArray<MethodDeclarationSyntax?> methods)
|
||||||
{
|
// {
|
||||||
if (methods is { IsDefaultOrEmpty: true })
|
// if (methods is { IsDefaultOrEmpty: true })
|
||||||
return;
|
// return;
|
||||||
|
//
|
||||||
var models = GetModels(comp, methods, ctx.CancellationToken);
|
// var models = GetModels(comp, methods, ctx.CancellationToken);
|
||||||
|
//
|
||||||
foreach (var model in models)
|
// foreach (var model in models)
|
||||||
{
|
// {
|
||||||
var name = $"{model.Namespace}.{string.Join(".", model.ClassHierarchy)}.g.cs";
|
// var name = $"{model.Namespace}.{string.Join(".", model.ClassHierarchy)}.g.cs";
|
||||||
try
|
// try
|
||||||
{
|
// {
|
||||||
var source = GetSourceText(model);
|
// var source = GetSourceText(model);
|
||||||
ctx.AddSource(name, SourceText.From(source, Encoding.UTF8));
|
// ctx.AddSource(name, SourceText.From(source, Encoding.UTF8));
|
||||||
}
|
// }
|
||||||
catch (Exception ex)
|
// catch (Exception ex)
|
||||||
{
|
// {
|
||||||
Console.WriteLine($"Error writing source file {name}\n" + ex);
|
// Console.WriteLine($"Error writing source file {name}\n" + ex);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
private static string GetSourceText(FileModel model)
|
// private static string GetSourceText(FileModel model)
|
||||||
{
|
// {
|
||||||
using var sw = new StringWriter();
|
// using var sw = new StringWriter();
|
||||||
using var tw = new IndentedTextWriter(sw);
|
// using var tw = new IndentedTextWriter(sw);
|
||||||
|
//
|
||||||
tw.WriteLine("// <AutoGenerated />");
|
// tw.WriteLine("// <AutoGenerated />");
|
||||||
tw.WriteLine("#pragma warning disable CS1066");
|
// tw.WriteLine("#pragma warning disable CS1066");
|
||||||
|
//
|
||||||
if (model.Namespace is not null)
|
// if (model.Namespace is not null)
|
||||||
{
|
// {
|
||||||
tw.WriteLine($"namespace {model.Namespace};");
|
// tw.WriteLine($"namespace {model.Namespace};");
|
||||||
tw.WriteLine();
|
// tw.WriteLine();
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
foreach (var className in model.ClassHierarchy)
|
// foreach (var className in model.ClassHierarchy)
|
||||||
{
|
// {
|
||||||
tw.WriteLine($"public partial class {className}");
|
// tw.WriteLine($"public partial class {className}");
|
||||||
tw.WriteLine("{");
|
// tw.WriteLine("{");
|
||||||
tw.Indent ++;
|
// tw.Indent ++;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
foreach (var method in model.Methods)
|
// foreach (var method in model.Methods)
|
||||||
{
|
// {
|
||||||
tw.WriteLine("[NadekoCommand]");
|
// tw.WriteLine("[NadekoCommand]");
|
||||||
tw.WriteLine("[NadekoDescription]");
|
// tw.WriteLine("[NadekoDescription]");
|
||||||
tw.WriteLine("[Aliases]");
|
// tw.WriteLine("[Aliases]");
|
||||||
tw.WriteLine($"public partial {method.ReturnType} {method.MethodName}({string.Join(", ", method.Params)});");
|
// tw.WriteLine($"public partial {method.ReturnType} {method.MethodName}({string.Join(", ", method.Params)});");
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
foreach (var _ in model.ClassHierarchy)
|
// foreach (var _ in model.ClassHierarchy)
|
||||||
{
|
// {
|
||||||
tw.Indent --;
|
// tw.Indent --;
|
||||||
tw.WriteLine("}");
|
// tw.WriteLine("}");
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
tw.Flush();
|
// tw.Flush();
|
||||||
return sw.ToString();
|
// return sw.ToString();
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
private static IReadOnlyCollection<FileModel> GetModels(Compilation compilation,
|
// private static IReadOnlyCollection<FileModel> GetModels(Compilation compilation,
|
||||||
in ImmutableArray<MethodDeclarationSyntax?> inputMethods,
|
// in ImmutableArray<MethodDeclarationSyntax?> inputMethods,
|
||||||
CancellationToken cancel)
|
// CancellationToken cancel)
|
||||||
{
|
// {
|
||||||
var models = new List<FileModel>();
|
// var models = new List<FileModel>();
|
||||||
|
//
|
||||||
var methods = inputMethods
|
// var methods = inputMethods
|
||||||
.Where(static x => x is not null)
|
// .Where(static x => x is not null)
|
||||||
.Distinct();
|
// .Distinct();
|
||||||
|
//
|
||||||
var methodModels = methods
|
// var methodModels = methods
|
||||||
.Select(x => MethodDeclarationToMethodModel(compilation, x!))
|
// .Select(x => MethodDeclarationToMethodModel(compilation, x!))
|
||||||
.Where(static x => x is not null)
|
// .Where(static x => x is not null)
|
||||||
.Cast<MethodModel>();
|
// .Cast<MethodModel>();
|
||||||
|
//
|
||||||
var groups = methodModels
|
// var groups = methodModels
|
||||||
.GroupBy(static x => $"{x.Namespace}.{string.Join(".", x.Classes)}");
|
// .GroupBy(static x => $"{x.Namespace}.{string.Join(".", x.Classes)}");
|
||||||
|
//
|
||||||
foreach (var group in groups)
|
// foreach (var group in groups)
|
||||||
{
|
// {
|
||||||
if (cancel.IsCancellationRequested)
|
// if (cancel.IsCancellationRequested)
|
||||||
return new Collection<FileModel>();
|
// return new Collection<FileModel>();
|
||||||
|
//
|
||||||
if (group is null)
|
// if (group is null)
|
||||||
continue;
|
// continue;
|
||||||
|
//
|
||||||
var elems = group.ToList();
|
// var elems = group.ToList();
|
||||||
if (elems.Count is 0)
|
// if (elems.Count is 0)
|
||||||
continue;
|
// continue;
|
||||||
|
//
|
||||||
var model = new FileModel(
|
// var model = new FileModel(
|
||||||
methods: elems,
|
// methods: elems,
|
||||||
ns: elems[0].Namespace,
|
// ns: elems[0].Namespace,
|
||||||
classHierarchy: elems![0].Classes
|
// classHierarchy: elems![0].Classes
|
||||||
);
|
// );
|
||||||
|
//
|
||||||
models.Add(model);
|
// models.Add(model);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
|
//
|
||||||
return models;
|
// return models;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
private static MethodModel? MethodDeclarationToMethodModel(Compilation comp, MethodDeclarationSyntax decl)
|
// private static MethodModel? MethodDeclarationToMethodModel(Compilation comp, MethodDeclarationSyntax decl)
|
||||||
{
|
// {
|
||||||
// SpinWait.SpinUntil(static () => Debugger.IsAttached);
|
// // SpinWait.SpinUntil(static () => Debugger.IsAttached);
|
||||||
|
//
|
||||||
SemanticModel semanticModel;
|
// SemanticModel semanticModel;
|
||||||
try
|
// try
|
||||||
{
|
// {
|
||||||
semanticModel = comp.GetSemanticModel(decl.SyntaxTree);
|
// semanticModel = comp.GetSemanticModel(decl.SyntaxTree);
|
||||||
}
|
// }
|
||||||
catch
|
// catch
|
||||||
{
|
// {
|
||||||
// for some reason this method can throw "Not part of this compilation" argument exception
|
// // for some reason this method can throw "Not part of this compilation" argument exception
|
||||||
return null;
|
// return null;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
var methodModel = new MethodModel(
|
// var methodModel = new MethodModel(
|
||||||
@params: decl.ParameterList.Parameters
|
// @params: decl.ParameterList.Parameters
|
||||||
.Where(p => p.Type is not null)
|
// .Where(p => p.Type is not null)
|
||||||
.Select(p =>
|
// .Select(p =>
|
||||||
{
|
// {
|
||||||
var prefix = p.Modifiers.Any(static x => x.IsKind(SyntaxKind.ParamsKeyword))
|
// var prefix = p.Modifiers.Any(static x => x.IsKind(SyntaxKind.ParamsKeyword))
|
||||||
? "params "
|
// ? "params "
|
||||||
: string.Empty;
|
// : string.Empty;
|
||||||
|
//
|
||||||
var type = semanticModel
|
// var type = semanticModel
|
||||||
.GetTypeInfo(p.Type!)
|
// .GetTypeInfo(p.Type!)
|
||||||
.Type
|
// .Type
|
||||||
?.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
|
// ?.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
|
||||||
|
//
|
||||||
|
//
|
||||||
var name = p.Identifier.Text;
|
// var name = p.Identifier.Text;
|
||||||
|
//
|
||||||
var suffix = string.Empty;
|
// var suffix = string.Empty;
|
||||||
if (p.Default is not null)
|
// if (p.Default is not null)
|
||||||
{
|
// {
|
||||||
if (p.Default.Value is LiteralExpressionSyntax)
|
// if (p.Default.Value is LiteralExpressionSyntax)
|
||||||
{
|
// {
|
||||||
suffix = " = " + p.Default.Value;
|
// suffix = " = " + p.Default.Value;
|
||||||
}
|
// }
|
||||||
else if (p.Default.Value is MemberAccessExpressionSyntax maes)
|
// else if (p.Default.Value is MemberAccessExpressionSyntax maes)
|
||||||
{
|
// {
|
||||||
var maesSemModel = comp.GetSemanticModel(maes.SyntaxTree);
|
// var maesSemModel = comp.GetSemanticModel(maes.SyntaxTree);
|
||||||
var sym = maesSemModel.GetSymbolInfo(maes.Name);
|
// var sym = maesSemModel.GetSymbolInfo(maes.Name);
|
||||||
if (sym.Symbol is null)
|
// if (sym.Symbol is null)
|
||||||
{
|
// {
|
||||||
suffix = " = " + p.Default.Value;
|
// suffix = " = " + p.Default.Value;
|
||||||
}
|
// }
|
||||||
else
|
// else
|
||||||
{
|
// {
|
||||||
suffix = " = " + sym.Symbol.ToDisplayString();
|
// suffix = " = " + sym.Symbol.ToDisplayString();
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
return $"{prefix}{type} {name}{suffix}";
|
// return $"{prefix}{type} {name}{suffix}";
|
||||||
})
|
// })
|
||||||
.ToList(),
|
// .ToList(),
|
||||||
methodName: decl.Identifier.Text,
|
// methodName: decl.Identifier.Text,
|
||||||
returnType: decl.ReturnType.ToString(),
|
// returnType: decl.ReturnType.ToString(),
|
||||||
ns: GetNamespace(decl),
|
// ns: GetNamespace(decl),
|
||||||
classes: GetClasses(decl)
|
// classes: GetClasses(decl)
|
||||||
);
|
// );
|
||||||
|
//
|
||||||
return methodModel;
|
// return methodModel;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
//https://github.com/andrewlock/NetEscapades.EnumGenerators/blob/main/src/NetEscapades.EnumGenerators/EnumGenerator.cs
|
// //https://github.com/andrewlock/NetEscapades.EnumGenerators/blob/main/src/NetEscapades.EnumGenerators/EnumGenerator.cs
|
||||||
static string? GetNamespace(MethodDeclarationSyntax declarationSyntax)
|
// static string? GetNamespace(MethodDeclarationSyntax declarationSyntax)
|
||||||
{
|
// {
|
||||||
// determine the namespace the class is declared in, if any
|
// // determine the namespace the class is declared in, if any
|
||||||
string? nameSpace = null;
|
// string? nameSpace = null;
|
||||||
var parentOfInterest = declarationSyntax.Parent;
|
// var parentOfInterest = declarationSyntax.Parent;
|
||||||
while (parentOfInterest is not null)
|
// while (parentOfInterest is not null)
|
||||||
{
|
// {
|
||||||
parentOfInterest = parentOfInterest.Parent;
|
// parentOfInterest = parentOfInterest.Parent;
|
||||||
|
//
|
||||||
if (parentOfInterest is BaseNamespaceDeclarationSyntax ns)
|
// if (parentOfInterest is BaseNamespaceDeclarationSyntax ns)
|
||||||
{
|
// {
|
||||||
nameSpace = ns.Name.ToString();
|
// nameSpace = ns.Name.ToString();
|
||||||
while (true)
|
// while (true)
|
||||||
{
|
// {
|
||||||
if (ns.Parent is not NamespaceDeclarationSyntax parent)
|
// if (ns.Parent is not NamespaceDeclarationSyntax parent)
|
||||||
{
|
// {
|
||||||
break;
|
// break;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
ns = parent;
|
// ns = parent;
|
||||||
nameSpace = $"{ns.Name}.{nameSpace}";
|
// nameSpace = $"{ns.Name}.{nameSpace}";
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
return nameSpace;
|
// return nameSpace;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
return nameSpace;
|
// return nameSpace;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
static IReadOnlyCollection<string> GetClasses(MethodDeclarationSyntax declarationSyntax)
|
// static IReadOnlyCollection<string> GetClasses(MethodDeclarationSyntax declarationSyntax)
|
||||||
{
|
// {
|
||||||
// determine the namespace the class is declared in, if any
|
// // determine the namespace the class is declared in, if any
|
||||||
var classes = new LinkedList<string>();
|
// var classes = new LinkedList<string>();
|
||||||
var parentOfInterest = declarationSyntax.Parent;
|
// var parentOfInterest = declarationSyntax.Parent;
|
||||||
while (parentOfInterest is not null)
|
// while (parentOfInterest is not null)
|
||||||
{
|
// {
|
||||||
if (parentOfInterest is ClassDeclarationSyntax cds)
|
// if (parentOfInterest is ClassDeclarationSyntax cds)
|
||||||
{
|
// {
|
||||||
classes.AddFirst(cds.Identifier.ToString());
|
// classes.AddFirst(cds.Identifier.ToString());
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
parentOfInterest = parentOfInterest.Parent;
|
// parentOfInterest = parentOfInterest.Parent;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
Debug.WriteLine($"Method {declarationSyntax.Identifier.Text} has {classes.Count} classes");
|
// Debug.WriteLine($"Method {declarationSyntax.Identifier.Text} has {classes.Count} classes");
|
||||||
|
//
|
||||||
return classes;
|
// return classes;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
private static MethodDeclarationSyntax? Transform(GeneratorSyntaxContext ctx, CancellationToken cancel)
|
// private static MethodDeclarationSyntax? Transform(GeneratorSyntaxContext ctx, CancellationToken cancel)
|
||||||
{
|
// {
|
||||||
var methodDecl = ctx.Node as MethodDeclarationSyntax;
|
// var methodDecl = ctx.Node as MethodDeclarationSyntax;
|
||||||
if (methodDecl is null)
|
// if (methodDecl is null)
|
||||||
return default;
|
// return default;
|
||||||
|
//
|
||||||
foreach (var attListSyntax in methodDecl.AttributeLists)
|
// foreach (var attListSyntax in methodDecl.AttributeLists)
|
||||||
{
|
// {
|
||||||
foreach (var attSyntax in attListSyntax.Attributes)
|
// foreach (var attSyntax in attListSyntax.Attributes)
|
||||||
{
|
// {
|
||||||
if (cancel.IsCancellationRequested)
|
// if (cancel.IsCancellationRequested)
|
||||||
return default;
|
// return default;
|
||||||
|
//
|
||||||
var symbol = ctx.SemanticModel.GetSymbolInfo(attSyntax).Symbol;
|
// var symbol = ctx.SemanticModel.GetSymbolInfo(attSyntax).Symbol;
|
||||||
if (symbol is not IMethodSymbol attSymbol)
|
// if (symbol is not IMethodSymbol attSymbol)
|
||||||
continue;
|
// continue;
|
||||||
|
//
|
||||||
if (attSymbol.ContainingType.ToDisplayString() == "NadekoBot.Common.CmdAttribute")
|
// if (attSymbol.ContainingType.ToDisplayString() == "NadekoBot.Common.CmdAttribute")
|
||||||
return methodDecl;
|
// return methodDecl;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
return default;
|
// return default;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
@@ -47,7 +47,7 @@ namespace NadekoBot.Tests
|
|||||||
|| !(type.GetCustomAttribute<GroupAttribute>(true) is null)) // or a submodule
|
|| !(type.GetCustomAttribute<GroupAttribute>(true) is null)) // or a submodule
|
||||||
.SelectMany(x => x.GetMethods()
|
.SelectMany(x => x.GetMethods()
|
||||||
.Where(mi => mi.CustomAttributes
|
.Where(mi => mi.CustomAttributes
|
||||||
.Any(ca => ca.AttributeType == typeof(NadekoCommandAttribute))))
|
.Any(ca => ca.AttributeType == typeof(CmdAttribute))))
|
||||||
.Select(x => x.Name.ToLowerInvariant())
|
.Select(x => x.Name.ToLowerInvariant())
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Nadeko.Common;
|
||||||
using NadekoBot.Extensions;
|
using NadekoBot.Extensions;
|
||||||
using NadekoBot.Services;
|
using NadekoBot.Services;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
using NadekoBot.Common.Collections;
|
using Nadeko.Common;
|
||||||
using NadekoBot.Services.Database.Models;
|
using NadekoBot.Services.Database.Models;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using System;
|
using System;
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
using NadekoBot.Common;
|
using Nadeko.Common;
|
||||||
|
using NadekoBot.Common;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
|
||||||
namespace NadekoBot.Tests
|
namespace NadekoBot.Tests
|
||||||
|
@@ -14,6 +14,8 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Nadeko.Common\Nadeko.Common.csproj" />
|
||||||
|
<ProjectReference Include="..\Nadeko.Econ\Nadeko.Econ.csproj" />
|
||||||
<ProjectReference Include="..\NadekoBot\NadekoBot.csproj" />
|
<ProjectReference Include="..\NadekoBot\NadekoBot.csproj" />
|
||||||
</ItemGroup>
|
</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>
|
<ItemGroup>
|
||||||
<PackageReference Include="MorseCode.ITask" Version="2.0.3" />
|
<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>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
@@ -10,6 +10,7 @@ using System.Collections.Immutable;
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using Nadeko.Common;
|
||||||
using RunMode = Discord.Commands.RunMode;
|
using RunMode = Discord.Commands.RunMode;
|
||||||
|
|
||||||
namespace NadekoBot;
|
namespace NadekoBot;
|
||||||
|
@@ -3,11 +3,16 @@ using System.Runtime.CompilerServices;
|
|||||||
namespace NadekoBot.Common.Attributes;
|
namespace NadekoBot.Common.Attributes;
|
||||||
|
|
||||||
[AttributeUsage(AttributeTargets.Method)]
|
[AttributeUsage(AttributeTargets.Method)]
|
||||||
public sealed class NadekoCommandAttribute : CommandAttribute
|
public sealed class CmdAttribute : CommandAttribute
|
||||||
{
|
{
|
||||||
public string MethodName { get; }
|
public string MethodName { get; }
|
||||||
|
|
||||||
public NadekoCommandAttribute([CallerMemberName] string memberName = "")
|
public CmdAttribute([CallerMemberName] string memberName = "")
|
||||||
: base(CommandNameLoadHelper.GetCommandNameFor(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>
|
public sealed partial class BotConfig : ICloneable<BotConfig>
|
||||||
{
|
{
|
||||||
[Comment(@"DO NOT CHANGE")]
|
[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
|
[Comment(@"Most commands, when executed, have a small colored line
|
||||||
next to the response. The color depends whether the command
|
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")]
|
Allowed values: Simple, Normal, None")]
|
||||||
public ConsoleOutputType ConsoleOutputType { get; set; }
|
public ConsoleOutputType ConsoleOutputType { get; set; }
|
||||||
|
|
||||||
// [Comment(@"For what kind of updates will the bot check.
|
[Comment(@"Whether the bot will check for new releases every hour")]
|
||||||
// Allowed values: Release, Commit, None")]
|
public bool CheckForUpdates { get; set; } = true;
|
||||||
// public UpdateCheckType CheckForUpdates { get; set; }
|
|
||||||
|
|
||||||
// [Comment(@"How often will the bot check for updates, in hours")]
|
|
||||||
// public int CheckUpdateInterval { get; set; }
|
|
||||||
|
|
||||||
[Comment(@"Do you want any messages sent by users in Bot's DM to be forwarded to the owner(s)?")]
|
[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; }
|
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
|
#nullable disable
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
using Nadeko.Common;
|
||||||
|
|
||||||
namespace NadekoBot.Common;
|
namespace NadekoBot.Common;
|
||||||
|
|
||||||
|
@@ -1,4 +1,6 @@
|
|||||||
#nullable disable
|
#nullable disable
|
||||||
|
using Nadeko.Common;
|
||||||
|
|
||||||
namespace NadekoBot.Common.TypeReaders;
|
namespace NadekoBot.Common.TypeReaders;
|
||||||
|
|
||||||
public sealed class KwumTypeReader : NadekoTypeReader<kwum>
|
public sealed class KwumTypeReader : NadekoTypeReader<kwum>
|
||||||
|
@@ -3,6 +3,7 @@ using NadekoBot.Db;
|
|||||||
using NadekoBot.Modules.Gambling.Services;
|
using NadekoBot.Modules.Gambling.Services;
|
||||||
using NCalc;
|
using NCalc;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
using Nadeko.Common;
|
||||||
|
|
||||||
namespace NadekoBot.Common.TypeReaders;
|
namespace NadekoBot.Common.TypeReaders;
|
||||||
|
|
||||||
|
@@ -1,5 +1,4 @@
|
|||||||
#nullable disable
|
#nullable disable
|
||||||
using NadekoBot.Common.Collections;
|
|
||||||
using NadekoBot.Db.Models;
|
using NadekoBot.Db.Models;
|
||||||
|
|
||||||
namespace NadekoBot.Services.Database.Models;
|
namespace NadekoBot.Services.Database.Models;
|
||||||
|
@@ -5,4 +5,11 @@ public class ImageOnlyChannel : DbEntity
|
|||||||
{
|
{
|
||||||
public ulong GuildId { get; set; }
|
public ulong GuildId { get; set; }
|
||||||
public ulong ChannelId { 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;
|
namespace NadekoBot.Services.Database.Models;
|
||||||
|
|
||||||
public interface IIndexed
|
|
||||||
{
|
|
||||||
int Index { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
[DebuggerDisplay("{PrimaryTarget}{SecondaryTarget} {SecondaryTargetName} {State} {PrimaryTargetId}")]
|
[DebuggerDisplay("{PrimaryTarget}{SecondaryTarget} {SecondaryTargetName} {State} {PrimaryTargetId}")]
|
||||||
public class Permissionv2 : DbEntity, IIndexed
|
public class Permissionv2 : DbEntity, IIndexed
|
||||||
{
|
{
|
||||||
|
@@ -1,6 +1,4 @@
|
|||||||
#nullable disable
|
#nullable disable
|
||||||
using NadekoBot.Common.Collections;
|
|
||||||
|
|
||||||
namespace NadekoBot.Services.Database.Models;
|
namespace NadekoBot.Services.Database.Models;
|
||||||
|
|
||||||
public class Poll : DbEntity
|
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
|
#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
|
#if DEBUG
|
||||||
|
@@ -8,7 +8,8 @@ global using Humanizer;
|
|||||||
// nadekobot
|
// nadekobot
|
||||||
global using NadekoBot;
|
global using NadekoBot;
|
||||||
global using NadekoBot.Services;
|
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.Common.Attributes;
|
||||||
global using NadekoBot.Extensions;
|
global using NadekoBot.Extensions;
|
||||||
global using Nadeko.Snake;
|
global using Nadeko.Snake;
|
||||||
|
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
|
#pragma warning disable 612, 618
|
||||||
modelBuilder
|
modelBuilder
|
||||||
.HasAnnotation("ProductVersion", "6.0.6")
|
.HasAnnotation("ProductVersion", "6.0.7")
|
||||||
.HasAnnotation("Relational:MaxIdentifierLength", 64);
|
.HasAnnotation("Relational:MaxIdentifierLength", 64);
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Db.Models.BankUser", b =>
|
modelBuilder.Entity("NadekoBot.Db.Models.BankUser", b =>
|
||||||
@@ -366,6 +366,44 @@ namespace NadekoBot.Migrations.Mysql
|
|||||||
b.ToTable("streamonlinemessages", (string)null);
|
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 =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiAltSetting", b =>
|
||||||
{
|
{
|
||||||
b.Property<int>("Id")
|
b.Property<int>("Id")
|
||||||
@@ -1353,6 +1391,10 @@ namespace NadekoBot.Migrations.Mysql
|
|||||||
.HasColumnType("bigint unsigned")
|
.HasColumnType("bigint unsigned")
|
||||||
.HasColumnName("guildid");
|
.HasColumnName("guildid");
|
||||||
|
|
||||||
|
b.Property<int>("Type")
|
||||||
|
.HasColumnType("int")
|
||||||
|
.HasColumnName("type");
|
||||||
|
|
||||||
b.HasKey("Id")
|
b.HasKey("Id")
|
||||||
.HasName("pk_imageonlychannels");
|
.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
|
#pragma warning disable 612, 618
|
||||||
modelBuilder
|
modelBuilder
|
||||||
.HasAnnotation("ProductVersion", "6.0.6")
|
.HasAnnotation("ProductVersion", "6.0.7")
|
||||||
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||||
|
|
||||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||||
@@ -378,6 +378,46 @@ namespace NadekoBot.Migrations.PostgreSql
|
|||||||
b.ToTable("streamonlinemessages", (string)null);
|
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 =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiAltSetting", b =>
|
||||||
{
|
{
|
||||||
b.Property<int>("Id")
|
b.Property<int>("Id")
|
||||||
@@ -1417,6 +1457,10 @@ namespace NadekoBot.Migrations.PostgreSql
|
|||||||
.HasColumnType("numeric(20,0)")
|
.HasColumnType("numeric(20,0)")
|
||||||
.HasColumnName("guildid");
|
.HasColumnName("guildid");
|
||||||
|
|
||||||
|
b.Property<int>("Type")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasColumnName("type");
|
||||||
|
|
||||||
b.HasKey("Id")
|
b.HasKey("Id")
|
||||||
.HasName("pk_imageonlychannels");
|
.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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -15,7 +15,7 @@ namespace NadekoBot.Migrations
|
|||||||
protected override void BuildModel(ModelBuilder modelBuilder)
|
protected override void BuildModel(ModelBuilder modelBuilder)
|
||||||
{
|
{
|
||||||
#pragma warning disable 612, 618
|
#pragma warning disable 612, 618
|
||||||
modelBuilder.HasAnnotation("ProductVersion", "6.0.6");
|
modelBuilder.HasAnnotation("ProductVersion", "6.0.7");
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Db.Models.BankUser", b =>
|
modelBuilder.Entity("NadekoBot.Db.Models.BankUser", b =>
|
||||||
{
|
{
|
||||||
@@ -288,6 +288,36 @@ namespace NadekoBot.Migrations
|
|||||||
b.ToTable("StreamOnlineMessages");
|
b.ToTable("StreamOnlineMessages");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("NadekoBot.Db.Models.XpShopOwnedItem", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<bool>("IsUsing")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("ItemKey")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("ItemType")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<ulong>("UserId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("UserId", "ItemType", "ItemKey")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("XpShopOwnedItem");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiAltSetting", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiAltSetting", b =>
|
||||||
{
|
{
|
||||||
b.Property<int>("Id")
|
b.Property<int>("Id")
|
||||||
@@ -1058,6 +1088,9 @@ namespace NadekoBot.Migrations
|
|||||||
b.Property<ulong>("GuildId")
|
b.Property<ulong>("GuildId")
|
||||||
.HasColumnType("INTEGER");
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("Type")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
b.HasKey("Id");
|
b.HasKey("Id");
|
||||||
|
|
||||||
b.HasIndex("ChannelId")
|
b.HasIndex("ChannelId")
|
||||||
|
@@ -32,29 +32,42 @@ public partial class Administration : NadekoModule<AdministrationService>
|
|||||||
Inherit
|
Inherit
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly ImageOnlyChannelService _imageOnly;
|
private readonly SomethingOnlyChannelService _somethingOnly;
|
||||||
|
|
||||||
public Administration(ImageOnlyChannelService imageOnly)
|
public Administration(SomethingOnlyChannelService somethingOnly)
|
||||||
=> _imageOnly = imageOnly;
|
=> _somethingOnly = somethingOnly;
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[UserPerm(GuildPerm.Administrator)]
|
[UserPerm(GuildPerm.Administrator)]
|
||||||
[BotPerm(GuildPerm.ManageGuild)]
|
[BotPerm(GuildPerm.ManageGuild)]
|
||||||
public async partial Task ImageOnlyChannel(StoopidTime time = null)
|
public async Task ImageOnlyChannel(StoopidTime time = null)
|
||||||
{
|
{
|
||||||
var newValue = _imageOnly.ToggleImageOnlyChannel(ctx.Guild.Id, ctx.Channel.Id);
|
var newValue = await _somethingOnly.ToggleImageOnlyChannelAsync(ctx.Guild.Id, ctx.Channel.Id);
|
||||||
if (newValue)
|
if (newValue)
|
||||||
await ReplyConfirmLocalizedAsync(strs.imageonly_enable);
|
await ReplyConfirmLocalizedAsync(strs.imageonly_enable);
|
||||||
else
|
else
|
||||||
await ReplyPendingLocalizedAsync(strs.imageonly_disable);
|
await ReplyPendingLocalizedAsync(strs.imageonly_disable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Cmd]
|
||||||
|
[RequireContext(ContextType.Guild)]
|
||||||
|
[UserPerm(GuildPerm.Administrator)]
|
||||||
|
[BotPerm(GuildPerm.ManageGuild)]
|
||||||
|
public async Task LinkOnlyChannel(StoopidTime time = null)
|
||||||
|
{
|
||||||
|
var newValue = await _somethingOnly.ToggleLinkOnlyChannelAsync(ctx.Guild.Id, ctx.Channel.Id);
|
||||||
|
if (newValue)
|
||||||
|
await ReplyConfirmLocalizedAsync(strs.linkonly_enable);
|
||||||
|
else
|
||||||
|
await ReplyPendingLocalizedAsync(strs.linkonly_disable);
|
||||||
|
}
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[UserPerm(ChannelPerm.ManageChannels)]
|
[UserPerm(ChannelPerm.ManageChannels)]
|
||||||
[BotPerm(ChannelPerm.ManageChannels)]
|
[BotPerm(ChannelPerm.ManageChannels)]
|
||||||
public async partial Task Slowmode(StoopidTime time = null)
|
public async Task Slowmode(StoopidTime time = null)
|
||||||
{
|
{
|
||||||
var seconds = (int?)time?.Time.TotalSeconds ?? 0;
|
var seconds = (int?)time?.Time.TotalSeconds ?? 0;
|
||||||
if (time is not null && (time.Time < TimeSpan.FromSeconds(0) || time.Time > TimeSpan.FromHours(6)))
|
if (time is not null && (time.Time < TimeSpan.FromSeconds(0) || time.Time > TimeSpan.FromHours(6)))
|
||||||
@@ -73,7 +86,7 @@ public partial class Administration : NadekoModule<AdministrationService>
|
|||||||
[UserPerm(GuildPerm.Administrator)]
|
[UserPerm(GuildPerm.Administrator)]
|
||||||
[BotPerm(GuildPerm.ManageMessages)]
|
[BotPerm(GuildPerm.ManageMessages)]
|
||||||
[Priority(2)]
|
[Priority(2)]
|
||||||
public async partial Task Delmsgoncmd(List _)
|
public async Task Delmsgoncmd(List _)
|
||||||
{
|
{
|
||||||
var guild = (SocketGuild)ctx.Guild;
|
var guild = (SocketGuild)ctx.Guild;
|
||||||
var (enabled, channels) = _service.GetDelMsgOnCmdData(ctx.Guild.Id);
|
var (enabled, channels) = _service.GetDelMsgOnCmdData(ctx.Guild.Id);
|
||||||
@@ -104,7 +117,7 @@ public partial class Administration : NadekoModule<AdministrationService>
|
|||||||
[UserPerm(GuildPerm.Administrator)]
|
[UserPerm(GuildPerm.Administrator)]
|
||||||
[BotPerm(GuildPerm.ManageMessages)]
|
[BotPerm(GuildPerm.ManageMessages)]
|
||||||
[Priority(1)]
|
[Priority(1)]
|
||||||
public async partial Task Delmsgoncmd(Server _ = Server.Server)
|
public async Task Delmsgoncmd(Server _ = Server.Server)
|
||||||
{
|
{
|
||||||
if (_service.ToggleDeleteMessageOnCommand(ctx.Guild.Id))
|
if (_service.ToggleDeleteMessageOnCommand(ctx.Guild.Id))
|
||||||
{
|
{
|
||||||
@@ -123,7 +136,7 @@ public partial class Administration : NadekoModule<AdministrationService>
|
|||||||
[UserPerm(GuildPerm.Administrator)]
|
[UserPerm(GuildPerm.Administrator)]
|
||||||
[BotPerm(GuildPerm.ManageMessages)]
|
[BotPerm(GuildPerm.ManageMessages)]
|
||||||
[Priority(0)]
|
[Priority(0)]
|
||||||
public partial Task Delmsgoncmd(Channel _, State s, ITextChannel ch)
|
public Task Delmsgoncmd(Channel _, State s, ITextChannel ch)
|
||||||
=> Delmsgoncmd(_, s, ch.Id);
|
=> Delmsgoncmd(_, s, ch.Id);
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
@@ -131,7 +144,7 @@ public partial class Administration : NadekoModule<AdministrationService>
|
|||||||
[UserPerm(GuildPerm.Administrator)]
|
[UserPerm(GuildPerm.Administrator)]
|
||||||
[BotPerm(GuildPerm.ManageMessages)]
|
[BotPerm(GuildPerm.ManageMessages)]
|
||||||
[Priority(1)]
|
[Priority(1)]
|
||||||
public async partial Task Delmsgoncmd(Channel _, State s, ulong? chId = null)
|
public async Task Delmsgoncmd(Channel _, State s, ulong? chId = null)
|
||||||
{
|
{
|
||||||
var actualChId = chId ?? ctx.Channel.Id;
|
var actualChId = chId ?? ctx.Channel.Id;
|
||||||
await _service.SetDelMsgOnCmdState(ctx.Guild.Id, actualChId, s);
|
await _service.SetDelMsgOnCmdState(ctx.Guild.Id, actualChId, s);
|
||||||
@@ -148,7 +161,7 @@ public partial class Administration : NadekoModule<AdministrationService>
|
|||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[UserPerm(GuildPerm.DeafenMembers)]
|
[UserPerm(GuildPerm.DeafenMembers)]
|
||||||
[BotPerm(GuildPerm.DeafenMembers)]
|
[BotPerm(GuildPerm.DeafenMembers)]
|
||||||
public async partial Task Deafen(params IGuildUser[] users)
|
public async Task Deafen(params IGuildUser[] users)
|
||||||
{
|
{
|
||||||
await _service.DeafenUsers(true, users);
|
await _service.DeafenUsers(true, users);
|
||||||
await ReplyConfirmLocalizedAsync(strs.deafen);
|
await ReplyConfirmLocalizedAsync(strs.deafen);
|
||||||
@@ -158,7 +171,7 @@ public partial class Administration : NadekoModule<AdministrationService>
|
|||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[UserPerm(GuildPerm.DeafenMembers)]
|
[UserPerm(GuildPerm.DeafenMembers)]
|
||||||
[BotPerm(GuildPerm.DeafenMembers)]
|
[BotPerm(GuildPerm.DeafenMembers)]
|
||||||
public async partial Task UnDeafen(params IGuildUser[] users)
|
public async Task UnDeafen(params IGuildUser[] users)
|
||||||
{
|
{
|
||||||
await _service.DeafenUsers(false, users);
|
await _service.DeafenUsers(false, users);
|
||||||
await ReplyConfirmLocalizedAsync(strs.undeafen);
|
await ReplyConfirmLocalizedAsync(strs.undeafen);
|
||||||
@@ -168,7 +181,7 @@ public partial class Administration : NadekoModule<AdministrationService>
|
|||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[UserPerm(GuildPerm.ManageChannels)]
|
[UserPerm(GuildPerm.ManageChannels)]
|
||||||
[BotPerm(GuildPerm.ManageChannels)]
|
[BotPerm(GuildPerm.ManageChannels)]
|
||||||
public async partial Task DelVoiChanl([Leftover] IVoiceChannel voiceChannel)
|
public async Task DelVoiChanl([Leftover] IVoiceChannel voiceChannel)
|
||||||
{
|
{
|
||||||
await voiceChannel.DeleteAsync();
|
await voiceChannel.DeleteAsync();
|
||||||
await ReplyConfirmLocalizedAsync(strs.delvoich(Format.Bold(voiceChannel.Name)));
|
await ReplyConfirmLocalizedAsync(strs.delvoich(Format.Bold(voiceChannel.Name)));
|
||||||
@@ -178,7 +191,7 @@ public partial class Administration : NadekoModule<AdministrationService>
|
|||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[UserPerm(GuildPerm.ManageChannels)]
|
[UserPerm(GuildPerm.ManageChannels)]
|
||||||
[BotPerm(GuildPerm.ManageChannels)]
|
[BotPerm(GuildPerm.ManageChannels)]
|
||||||
public async partial Task CreatVoiChanl([Leftover] string channelName)
|
public async Task CreatVoiChanl([Leftover] string channelName)
|
||||||
{
|
{
|
||||||
var ch = await ctx.Guild.CreateVoiceChannelAsync(channelName);
|
var ch = await ctx.Guild.CreateVoiceChannelAsync(channelName);
|
||||||
await ReplyConfirmLocalizedAsync(strs.createvoich(Format.Bold(ch.Name)));
|
await ReplyConfirmLocalizedAsync(strs.createvoich(Format.Bold(ch.Name)));
|
||||||
@@ -188,7 +201,7 @@ public partial class Administration : NadekoModule<AdministrationService>
|
|||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[UserPerm(GuildPerm.ManageChannels)]
|
[UserPerm(GuildPerm.ManageChannels)]
|
||||||
[BotPerm(GuildPerm.ManageChannels)]
|
[BotPerm(GuildPerm.ManageChannels)]
|
||||||
public async partial Task DelTxtChanl([Leftover] ITextChannel toDelete)
|
public async Task DelTxtChanl([Leftover] ITextChannel toDelete)
|
||||||
{
|
{
|
||||||
await toDelete.DeleteAsync();
|
await toDelete.DeleteAsync();
|
||||||
await ReplyConfirmLocalizedAsync(strs.deltextchan(Format.Bold(toDelete.Name)));
|
await ReplyConfirmLocalizedAsync(strs.deltextchan(Format.Bold(toDelete.Name)));
|
||||||
@@ -198,7 +211,7 @@ public partial class Administration : NadekoModule<AdministrationService>
|
|||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[UserPerm(GuildPerm.ManageChannels)]
|
[UserPerm(GuildPerm.ManageChannels)]
|
||||||
[BotPerm(GuildPerm.ManageChannels)]
|
[BotPerm(GuildPerm.ManageChannels)]
|
||||||
public async partial Task CreaTxtChanl([Leftover] string channelName)
|
public async Task CreaTxtChanl([Leftover] string channelName)
|
||||||
{
|
{
|
||||||
var txtCh = await ctx.Guild.CreateTextChannelAsync(channelName);
|
var txtCh = await ctx.Guild.CreateTextChannelAsync(channelName);
|
||||||
await ReplyConfirmLocalizedAsync(strs.createtextchan(Format.Bold(txtCh.Name)));
|
await ReplyConfirmLocalizedAsync(strs.createtextchan(Format.Bold(txtCh.Name)));
|
||||||
@@ -208,7 +221,7 @@ public partial class Administration : NadekoModule<AdministrationService>
|
|||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[UserPerm(GuildPerm.ManageChannels)]
|
[UserPerm(GuildPerm.ManageChannels)]
|
||||||
[BotPerm(GuildPerm.ManageChannels)]
|
[BotPerm(GuildPerm.ManageChannels)]
|
||||||
public async partial Task SetTopic([Leftover] string topic = null)
|
public async Task SetTopic([Leftover] string topic = null)
|
||||||
{
|
{
|
||||||
var channel = (ITextChannel)ctx.Channel;
|
var channel = (ITextChannel)ctx.Channel;
|
||||||
topic ??= "";
|
topic ??= "";
|
||||||
@@ -220,7 +233,7 @@ public partial class Administration : NadekoModule<AdministrationService>
|
|||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[UserPerm(GuildPerm.ManageChannels)]
|
[UserPerm(GuildPerm.ManageChannels)]
|
||||||
[BotPerm(GuildPerm.ManageChannels)]
|
[BotPerm(GuildPerm.ManageChannels)]
|
||||||
public async partial Task SetChanlName([Leftover] string name)
|
public async Task SetChanlName([Leftover] string name)
|
||||||
{
|
{
|
||||||
var channel = (ITextChannel)ctx.Channel;
|
var channel = (ITextChannel)ctx.Channel;
|
||||||
await channel.ModifyAsync(c => c.Name = name);
|
await channel.ModifyAsync(c => c.Name = name);
|
||||||
@@ -231,7 +244,7 @@ public partial class Administration : NadekoModule<AdministrationService>
|
|||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[UserPerm(GuildPerm.ManageChannels)]
|
[UserPerm(GuildPerm.ManageChannels)]
|
||||||
[BotPerm(GuildPerm.ManageChannels)]
|
[BotPerm(GuildPerm.ManageChannels)]
|
||||||
public async partial Task NsfwToggle()
|
public async Task NsfwToggle()
|
||||||
{
|
{
|
||||||
var channel = (ITextChannel)ctx.Channel;
|
var channel = (ITextChannel)ctx.Channel;
|
||||||
var isEnabled = channel.IsNsfw;
|
var isEnabled = channel.IsNsfw;
|
||||||
@@ -248,13 +261,13 @@ public partial class Administration : NadekoModule<AdministrationService>
|
|||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[UserPerm(ChannelPerm.ManageMessages)]
|
[UserPerm(ChannelPerm.ManageMessages)]
|
||||||
[Priority(0)]
|
[Priority(0)]
|
||||||
public partial Task Edit(ulong messageId, [Leftover] string text)
|
public Task Edit(ulong messageId, [Leftover] string text)
|
||||||
=> Edit((ITextChannel)ctx.Channel, messageId, text);
|
=> Edit((ITextChannel)ctx.Channel, messageId, text);
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[Priority(1)]
|
[Priority(1)]
|
||||||
public async partial Task Edit(ITextChannel channel, ulong messageId, [Leftover] string text)
|
public async Task Edit(ITextChannel channel, ulong messageId, [Leftover] string text)
|
||||||
{
|
{
|
||||||
var userPerms = ((SocketGuildUser)ctx.User).GetPermissions(channel);
|
var userPerms = ((SocketGuildUser)ctx.User).GetPermissions(channel);
|
||||||
var botPerms = ((SocketGuild)ctx.Guild).CurrentUser.GetPermissions(channel);
|
var botPerms = ((SocketGuild)ctx.Guild).CurrentUser.GetPermissions(channel);
|
||||||
@@ -277,12 +290,12 @@ public partial class Administration : NadekoModule<AdministrationService>
|
|||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[UserPerm(ChannelPerm.ManageMessages)]
|
[UserPerm(ChannelPerm.ManageMessages)]
|
||||||
[BotPerm(ChannelPerm.ManageMessages)]
|
[BotPerm(ChannelPerm.ManageMessages)]
|
||||||
public partial Task Delete(ulong messageId, StoopidTime time = null)
|
public Task Delete(ulong messageId, StoopidTime time = null)
|
||||||
=> Delete((ITextChannel)ctx.Channel, messageId, time);
|
=> Delete((ITextChannel)ctx.Channel, messageId, time);
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
public async partial Task Delete(ITextChannel channel, ulong messageId, StoopidTime time = null)
|
public async Task Delete(ITextChannel channel, ulong messageId, StoopidTime time = null)
|
||||||
=> await InternalMessageAction(channel, messageId, time, msg => msg.DeleteAsync());
|
=> await InternalMessageAction(channel, messageId, time, msg => msg.DeleteAsync());
|
||||||
|
|
||||||
private async Task InternalMessageAction(
|
private async Task InternalMessageAction(
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
#nullable disable
|
#nullable disable
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Nadeko.Common;
|
||||||
using NadekoBot.Db;
|
using NadekoBot.Db;
|
||||||
using NadekoBot.Services.Database.Models;
|
using NadekoBot.Services.Database.Models;
|
||||||
|
|
||||||
@@ -41,11 +42,11 @@ public class AdministrationService : INService
|
|||||||
|
|
||||||
private Task DelMsgOnCmd_Handler(IUserMessage msg, CommandInfo cmd)
|
private Task DelMsgOnCmd_Handler(IUserMessage msg, CommandInfo cmd)
|
||||||
{
|
{
|
||||||
|
if (msg.Channel is not ITextChannel channel)
|
||||||
|
return Task.CompletedTask;
|
||||||
|
|
||||||
_ = Task.Run(async () =>
|
_ = Task.Run(async () =>
|
||||||
{
|
{
|
||||||
if (msg.Channel is not SocketTextChannel channel)
|
|
||||||
return;
|
|
||||||
|
|
||||||
//wat ?!
|
//wat ?!
|
||||||
if (DeleteMessagesOnCommandChannels.TryGetValue(channel.Id, out var state))
|
if (DeleteMessagesOnCommandChannels.TryGetValue(channel.Id, out var state))
|
||||||
{
|
{
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
#nullable disable
|
#nullable disable
|
||||||
|
using Nadeko.Common;
|
||||||
using NadekoBot.Modules.Administration.Services;
|
using NadekoBot.Modules.Administration.Services;
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Administration;
|
namespace NadekoBot.Modules.Administration;
|
||||||
@@ -12,7 +13,7 @@ public partial class Administration
|
|||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[UserPerm(GuildPerm.ManageRoles)]
|
[UserPerm(GuildPerm.ManageRoles)]
|
||||||
[BotPerm(GuildPerm.ManageRoles)]
|
[BotPerm(GuildPerm.ManageRoles)]
|
||||||
public async partial Task AutoAssignRole([Leftover] IRole role)
|
public async Task AutoAssignRole([Leftover] IRole role)
|
||||||
{
|
{
|
||||||
var guser = (IGuildUser)ctx.User;
|
var guser = (IGuildUser)ctx.User;
|
||||||
if (role.Id == ctx.Guild.EveryoneRole.Id)
|
if (role.Id == ctx.Guild.EveryoneRole.Id)
|
||||||
@@ -38,7 +39,7 @@ public partial class Administration
|
|||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[UserPerm(GuildPerm.ManageRoles)]
|
[UserPerm(GuildPerm.ManageRoles)]
|
||||||
[BotPerm(GuildPerm.ManageRoles)]
|
[BotPerm(GuildPerm.ManageRoles)]
|
||||||
public async partial Task AutoAssignRole()
|
public async Task AutoAssignRole()
|
||||||
{
|
{
|
||||||
if (!_service.TryGetRoles(ctx.Guild.Id, out var roles))
|
if (!_service.TryGetRoles(ctx.Guild.Id, out var roles))
|
||||||
{
|
{
|
||||||
|
@@ -5,6 +5,7 @@ using NadekoBot.Db;
|
|||||||
using NadekoBot.Services.Database.Models;
|
using NadekoBot.Services.Database.Models;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Threading.Channels;
|
using System.Threading.Channels;
|
||||||
|
using Nadeko.Common;
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Administration.Services;
|
namespace NadekoBot.Modules.Administration.Services;
|
||||||
|
|
||||||
|
@@ -32,7 +32,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
[OwnerOnly]
|
[OwnerOnly]
|
||||||
public partial Task SqlSelect([Leftover] string sql)
|
public Task SqlSelect([Leftover] string sql)
|
||||||
{
|
{
|
||||||
var result = _service.SelectSql(sql);
|
var result = _service.SelectSql(sql);
|
||||||
|
|
||||||
@@ -56,7 +56,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
[OwnerOnly]
|
[OwnerOnly]
|
||||||
public async partial Task SqlExec([Leftover] string sql)
|
public async Task SqlExec([Leftover] string sql)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -78,37 +78,37 @@ namespace NadekoBot.Modules.Administration
|
|||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
[OwnerOnly]
|
[OwnerOnly]
|
||||||
public partial Task DeleteWaifus()
|
public Task DeleteWaifus()
|
||||||
=> ConfirmActionInternalAsync("Delete Waifus", () => _service.DeleteWaifus());
|
=> ConfirmActionInternalAsync("Delete Waifus", () => _service.DeleteWaifus());
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
[OwnerOnly]
|
[OwnerOnly]
|
||||||
public async partial Task DeleteWaifu(IUser user)
|
public async Task DeleteWaifu(IUser user)
|
||||||
=> await DeleteWaifu(user.Id);
|
=> await DeleteWaifu(user.Id);
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
[OwnerOnly]
|
[OwnerOnly]
|
||||||
public partial Task DeleteWaifu(ulong userId)
|
public Task DeleteWaifu(ulong userId)
|
||||||
=> ConfirmActionInternalAsync($"Delete Waifu {userId}", () => _service.DeleteWaifu(userId));
|
=> ConfirmActionInternalAsync($"Delete Waifu {userId}", () => _service.DeleteWaifu(userId));
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
[OwnerOnly]
|
[OwnerOnly]
|
||||||
public partial Task DeleteCurrency()
|
public Task DeleteCurrency()
|
||||||
=> ConfirmActionInternalAsync("Delete Currency", () => _service.DeleteCurrency());
|
=> ConfirmActionInternalAsync("Delete Currency", () => _service.DeleteCurrency());
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
[OwnerOnly]
|
[OwnerOnly]
|
||||||
public partial Task DeletePlaylists()
|
public Task DeletePlaylists()
|
||||||
=> ConfirmActionInternalAsync("Delete Playlists", () => _service.DeletePlaylists());
|
=> ConfirmActionInternalAsync("Delete Playlists", () => _service.DeletePlaylists());
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
[OwnerOnly]
|
[OwnerOnly]
|
||||||
public partial Task DeleteXp()
|
public Task DeleteXp()
|
||||||
=> ConfirmActionInternalAsync("Delete Xp", () => _service.DeleteXp());
|
=> ConfirmActionInternalAsync("Delete Xp", () => _service.DeleteXp());
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
[OwnerOnly]
|
[OwnerOnly]
|
||||||
public async partial Task PurgeUser(ulong userId)
|
public async Task PurgeUser(ulong userId)
|
||||||
{
|
{
|
||||||
var embed = _eb.Create()
|
var embed = _eb.Create()
|
||||||
.WithDescription(GetText(strs.purge_user_confirm(Format.Bold(userId.ToString()))));
|
.WithDescription(GetText(strs.purge_user_confirm(Format.Bold(userId.ToString()))));
|
||||||
@@ -122,7 +122,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
[OwnerOnly]
|
[OwnerOnly]
|
||||||
public partial Task PurgeUser([Leftover] IUser user)
|
public Task PurgeUser([Leftover] IUser user)
|
||||||
=> PurgeUser(user.Id);
|
=> PurgeUser(user.Id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -12,7 +12,7 @@ public partial class Administration
|
|||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[UserPerm(GuildPerm.Administrator)]
|
[UserPerm(GuildPerm.Administrator)]
|
||||||
[BotPerm(GuildPerm.MoveMembers)]
|
[BotPerm(GuildPerm.MoveMembers)]
|
||||||
public async partial Task GameVoiceChannel()
|
public async Task GameVoiceChannel()
|
||||||
{
|
{
|
||||||
var vch = ((IGuildUser)ctx.User).VoiceChannel;
|
var vch = ((IGuildUser)ctx.User).VoiceChannel;
|
||||||
|
|
||||||
|
@@ -8,7 +8,7 @@ public partial class Administration
|
|||||||
[Cmd]
|
[Cmd]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[UserPerm(GuildPerm.ManageGuild)]
|
[UserPerm(GuildPerm.ManageGuild)]
|
||||||
public async partial Task Boost()
|
public async Task Boost()
|
||||||
{
|
{
|
||||||
var enabled = await _service.ToggleBoost(ctx.Guild.Id, ctx.Channel.Id);
|
var enabled = await _service.ToggleBoost(ctx.Guild.Id, ctx.Channel.Id);
|
||||||
|
|
||||||
@@ -21,7 +21,7 @@ public partial class Administration
|
|||||||
[Cmd]
|
[Cmd]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[UserPerm(GuildPerm.ManageGuild)]
|
[UserPerm(GuildPerm.ManageGuild)]
|
||||||
public async partial Task BoostDel(int timer = 30)
|
public async Task BoostDel(int timer = 30)
|
||||||
{
|
{
|
||||||
if (timer is < 0 or > 600)
|
if (timer is < 0 or > 600)
|
||||||
return;
|
return;
|
||||||
@@ -37,7 +37,7 @@ public partial class Administration
|
|||||||
[Cmd]
|
[Cmd]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[UserPerm(GuildPerm.ManageGuild)]
|
[UserPerm(GuildPerm.ManageGuild)]
|
||||||
public async partial Task BoostMsg([Leftover] string? text = null)
|
public async Task BoostMsg([Leftover] string? text = null)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(text))
|
if (string.IsNullOrWhiteSpace(text))
|
||||||
{
|
{
|
||||||
@@ -56,7 +56,7 @@ public partial class Administration
|
|||||||
[Cmd]
|
[Cmd]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[UserPerm(GuildPerm.ManageGuild)]
|
[UserPerm(GuildPerm.ManageGuild)]
|
||||||
public async partial Task GreetDel(int timer = 30)
|
public async Task GreetDel(int timer = 30)
|
||||||
{
|
{
|
||||||
if (timer is < 0 or > 600)
|
if (timer is < 0 or > 600)
|
||||||
return;
|
return;
|
||||||
@@ -72,7 +72,7 @@ public partial class Administration
|
|||||||
[Cmd]
|
[Cmd]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[UserPerm(GuildPerm.ManageGuild)]
|
[UserPerm(GuildPerm.ManageGuild)]
|
||||||
public async partial Task Greet()
|
public async Task Greet()
|
||||||
{
|
{
|
||||||
var enabled = await _service.SetGreet(ctx.Guild.Id, ctx.Channel.Id);
|
var enabled = await _service.SetGreet(ctx.Guild.Id, ctx.Channel.Id);
|
||||||
|
|
||||||
@@ -85,7 +85,7 @@ public partial class Administration
|
|||||||
[Cmd]
|
[Cmd]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[UserPerm(GuildPerm.ManageGuild)]
|
[UserPerm(GuildPerm.ManageGuild)]
|
||||||
public async partial Task GreetMsg([Leftover] string? text = null)
|
public async Task GreetMsg([Leftover] string? text = null)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(text))
|
if (string.IsNullOrWhiteSpace(text))
|
||||||
{
|
{
|
||||||
@@ -105,7 +105,7 @@ public partial class Administration
|
|||||||
[Cmd]
|
[Cmd]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[UserPerm(GuildPerm.ManageGuild)]
|
[UserPerm(GuildPerm.ManageGuild)]
|
||||||
public async partial Task GreetDm()
|
public async Task GreetDm()
|
||||||
{
|
{
|
||||||
var enabled = await _service.SetGreetDm(ctx.Guild.Id);
|
var enabled = await _service.SetGreetDm(ctx.Guild.Id);
|
||||||
|
|
||||||
@@ -118,7 +118,7 @@ public partial class Administration
|
|||||||
[Cmd]
|
[Cmd]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[UserPerm(GuildPerm.ManageGuild)]
|
[UserPerm(GuildPerm.ManageGuild)]
|
||||||
public async partial Task GreetDmMsg([Leftover] string? text = null)
|
public async Task GreetDmMsg([Leftover] string? text = null)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(text))
|
if (string.IsNullOrWhiteSpace(text))
|
||||||
{
|
{
|
||||||
@@ -137,7 +137,7 @@ public partial class Administration
|
|||||||
[Cmd]
|
[Cmd]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[UserPerm(GuildPerm.ManageGuild)]
|
[UserPerm(GuildPerm.ManageGuild)]
|
||||||
public async partial Task Bye()
|
public async Task Bye()
|
||||||
{
|
{
|
||||||
var enabled = await _service.SetBye(ctx.Guild.Id, ctx.Channel.Id);
|
var enabled = await _service.SetBye(ctx.Guild.Id, ctx.Channel.Id);
|
||||||
|
|
||||||
@@ -150,7 +150,7 @@ public partial class Administration
|
|||||||
[Cmd]
|
[Cmd]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[UserPerm(GuildPerm.ManageGuild)]
|
[UserPerm(GuildPerm.ManageGuild)]
|
||||||
public async partial Task ByeMsg([Leftover] string? text = null)
|
public async Task ByeMsg([Leftover] string? text = null)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(text))
|
if (string.IsNullOrWhiteSpace(text))
|
||||||
{
|
{
|
||||||
@@ -169,7 +169,7 @@ public partial class Administration
|
|||||||
[Cmd]
|
[Cmd]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[UserPerm(GuildPerm.ManageGuild)]
|
[UserPerm(GuildPerm.ManageGuild)]
|
||||||
public async partial Task ByeDel(int timer = 30)
|
public async Task ByeDel(int timer = 30)
|
||||||
{
|
{
|
||||||
await _service.SetByeDel(ctx.Guild.Id, timer);
|
await _service.SetByeDel(ctx.Guild.Id, timer);
|
||||||
|
|
||||||
@@ -184,7 +184,7 @@ public partial class Administration
|
|||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[UserPerm(GuildPerm.ManageGuild)]
|
[UserPerm(GuildPerm.ManageGuild)]
|
||||||
[Ratelimit(5)]
|
[Ratelimit(5)]
|
||||||
public async partial Task ByeTest([Leftover] IGuildUser? user = null)
|
public async Task ByeTest([Leftover] IGuildUser? user = null)
|
||||||
{
|
{
|
||||||
user ??= (IGuildUser)ctx.User;
|
user ??= (IGuildUser)ctx.User;
|
||||||
|
|
||||||
@@ -198,7 +198,7 @@ public partial class Administration
|
|||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[UserPerm(GuildPerm.ManageGuild)]
|
[UserPerm(GuildPerm.ManageGuild)]
|
||||||
[Ratelimit(5)]
|
[Ratelimit(5)]
|
||||||
public async partial Task GreetTest([Leftover] IGuildUser? user = null)
|
public async Task GreetTest([Leftover] IGuildUser? user = null)
|
||||||
{
|
{
|
||||||
user ??= (IGuildUser)ctx.User;
|
user ??= (IGuildUser)ctx.User;
|
||||||
|
|
||||||
@@ -212,7 +212,7 @@ public partial class Administration
|
|||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[UserPerm(GuildPerm.ManageGuild)]
|
[UserPerm(GuildPerm.ManageGuild)]
|
||||||
[Ratelimit(5)]
|
[Ratelimit(5)]
|
||||||
public async partial Task GreetDmTest([Leftover] IGuildUser? user = null)
|
public async Task GreetDmTest([Leftover] IGuildUser? user = null)
|
||||||
{
|
{
|
||||||
user ??= (IGuildUser)ctx.User;
|
user ??= (IGuildUser)ctx.User;
|
||||||
|
|
||||||
|
@@ -191,6 +191,11 @@ public class GreetService : INService, IReadyExecutor
|
|||||||
if (conf.AutoDeleteByeMessagesTimer > 0)
|
if (conf.AutoDeleteByeMessagesTimer > 0)
|
||||||
toDelete.DeleteAfter(conf.AutoDeleteByeMessagesTimer);
|
toDelete.DeleteAfter(conf.AutoDeleteByeMessagesTimer);
|
||||||
}
|
}
|
||||||
|
catch (HttpException ex) when (ex.DiscordCode == DiscordErrorCode.InsufficientPermissions)
|
||||||
|
{
|
||||||
|
Log.Warning(ex, "Missing permissions to send a bye message, the bye message will be disabled on server: {GuildId}", channel.GuildId);
|
||||||
|
await SetBye(channel.GuildId, channel.Id, false);
|
||||||
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Log.Warning(ex, "Error embeding bye message");
|
Log.Warning(ex, "Error embeding bye message");
|
||||||
@@ -219,6 +224,11 @@ public class GreetService : INService, IReadyExecutor
|
|||||||
if (conf.AutoDeleteGreetMessagesTimer > 0)
|
if (conf.AutoDeleteGreetMessagesTimer > 0)
|
||||||
toDelete.DeleteAfter(conf.AutoDeleteGreetMessagesTimer);
|
toDelete.DeleteAfter(conf.AutoDeleteGreetMessagesTimer);
|
||||||
}
|
}
|
||||||
|
catch (HttpException ex) when (ex.DiscordCode == DiscordErrorCode.InsufficientPermissions)
|
||||||
|
{
|
||||||
|
Log.Warning(ex, "Missing permissions to send a bye message, the greet message will be disabled on server: {GuildId}", channel.GuildId);
|
||||||
|
await SetGreet(channel.GuildId, channel.Id, false);
|
||||||
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Log.Warning(ex, "Error embeding greet message");
|
Log.Warning(ex, "Error embeding greet message");
|
||||||
|
@@ -4,16 +4,18 @@ using Microsoft.Extensions.Caching.Memory;
|
|||||||
using NadekoBot.Common.ModuleBehaviors;
|
using NadekoBot.Common.ModuleBehaviors;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Threading.Channels;
|
using System.Threading.Channels;
|
||||||
|
using NadekoBot.Services.Database.Models;
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Administration.Services;
|
namespace NadekoBot.Modules.Administration.Services;
|
||||||
|
|
||||||
public sealed class ImageOnlyChannelService : IExecOnMessage
|
public sealed class SomethingOnlyChannelService : IExecOnMessage
|
||||||
{
|
{
|
||||||
public int Priority { get; } = 0;
|
public int Priority { get; } = 0;
|
||||||
private readonly IMemoryCache _ticketCache;
|
private readonly IMemoryCache _ticketCache;
|
||||||
private readonly DiscordSocketClient _client;
|
private readonly DiscordSocketClient _client;
|
||||||
private readonly DbService _db;
|
private readonly DbService _db;
|
||||||
private readonly ConcurrentDictionary<ulong, ConcurrentHashSet<ulong>> _enabledOn;
|
private readonly ConcurrentDictionary<ulong, ConcurrentHashSet<ulong>> _imageOnly;
|
||||||
|
private readonly ConcurrentDictionary<ulong, ConcurrentHashSet<ulong>> _linkOnly;
|
||||||
|
|
||||||
private readonly Channel<IUserMessage> _deleteQueue = Channel.CreateBounded<IUserMessage>(
|
private readonly Channel<IUserMessage> _deleteQueue = Channel.CreateBounded<IUserMessage>(
|
||||||
new BoundedChannelOptions(100)
|
new BoundedChannelOptions(100)
|
||||||
@@ -24,14 +26,23 @@ public sealed class ImageOnlyChannelService : IExecOnMessage
|
|||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
public ImageOnlyChannelService(IMemoryCache ticketCache, DiscordSocketClient client, DbService db)
|
public SomethingOnlyChannelService(IMemoryCache ticketCache, DiscordSocketClient client, DbService db)
|
||||||
{
|
{
|
||||||
_ticketCache = ticketCache;
|
_ticketCache = ticketCache;
|
||||||
_client = client;
|
_client = client;
|
||||||
_db = db;
|
_db = db;
|
||||||
|
|
||||||
using var uow = _db.GetDbContext();
|
using var uow = _db.GetDbContext();
|
||||||
_enabledOn = uow.ImageOnlyChannels.ToList()
|
_imageOnly = uow.ImageOnlyChannels
|
||||||
|
.Where(x => x.Type == OnlyChannelType.Image)
|
||||||
|
.ToList()
|
||||||
|
.GroupBy(x => x.GuildId)
|
||||||
|
.ToDictionary(x => x.Key, x => new ConcurrentHashSet<ulong>(x.Select(y => y.ChannelId)))
|
||||||
|
.ToConcurrent();
|
||||||
|
|
||||||
|
_linkOnly = uow.ImageOnlyChannels
|
||||||
|
.Where(x => x.Type == OnlyChannelType.Link)
|
||||||
|
.ToList()
|
||||||
.GroupBy(x => x.GuildId)
|
.GroupBy(x => x.GuildId)
|
||||||
.ToDictionary(x => x.Key, x => new ConcurrentHashSet<ulong>(x.Select(y => y.ChannelId)))
|
.ToDictionary(x => x.Key, x => new ConcurrentHashSet<ulong>(x.Select(y => y.ChannelId)))
|
||||||
.ToConcurrent();
|
.ToConcurrent();
|
||||||
@@ -41,15 +52,13 @@ public sealed class ImageOnlyChannelService : IExecOnMessage
|
|||||||
_client.ChannelDestroyed += ClientOnChannelDestroyed;
|
_client.ChannelDestroyed += ClientOnChannelDestroyed;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Task ClientOnChannelDestroyed(SocketChannel ch)
|
private async Task ClientOnChannelDestroyed(SocketChannel ch)
|
||||||
{
|
{
|
||||||
if (ch is not IGuildChannel gch)
|
if (ch is not IGuildChannel gch)
|
||||||
return Task.CompletedTask;
|
return;
|
||||||
|
|
||||||
if (_enabledOn.TryGetValue(gch.GuildId, out var channels) && channels.TryRemove(ch.Id))
|
if (_imageOnly.TryGetValue(gch.GuildId, out var channels) && channels.TryRemove(ch.Id))
|
||||||
ToggleImageOnlyChannel(gch.GuildId, ch.Id, true);
|
await ToggleImageOnlyChannelAsync(gch.GuildId, ch.Id, true);
|
||||||
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task DeleteQueueRunner()
|
private async Task DeleteQueueRunner()
|
||||||
@@ -65,31 +74,68 @@ public sealed class ImageOnlyChannelService : IExecOnMessage
|
|||||||
catch (HttpException ex) when (ex.HttpCode == HttpStatusCode.Forbidden)
|
catch (HttpException ex) when (ex.HttpCode == HttpStatusCode.Forbidden)
|
||||||
{
|
{
|
||||||
// disable if bot can't delete messages in the channel
|
// disable if bot can't delete messages in the channel
|
||||||
ToggleImageOnlyChannel(((ITextChannel)toDelete.Channel).GuildId, toDelete.Channel.Id, true);
|
await ToggleImageOnlyChannelAsync(((ITextChannel)toDelete.Channel).GuildId, toDelete.Channel.Id, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool ToggleImageOnlyChannel(ulong guildId, ulong channelId, bool forceDisable = false)
|
public async Task<bool> ToggleImageOnlyChannelAsync(ulong guildId, ulong channelId, bool forceDisable = false)
|
||||||
{
|
{
|
||||||
var newState = false;
|
var newState = false;
|
||||||
using var uow = _db.GetDbContext();
|
await using var uow = _db.GetDbContext();
|
||||||
if (forceDisable || (_enabledOn.TryGetValue(guildId, out var channels) && channels.TryRemove(channelId)))
|
if (forceDisable || (_imageOnly.TryGetValue(guildId, out var channels) && channels.TryRemove(channelId)))
|
||||||
uow.ImageOnlyChannels.Delete(x => x.ChannelId == channelId);
|
{
|
||||||
|
await uow.ImageOnlyChannels.DeleteAsync(x => x.ChannelId == channelId && x.Type == OnlyChannelType.Image);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
await uow.ImageOnlyChannels.DeleteAsync(x => x.ChannelId == channelId);
|
||||||
uow.ImageOnlyChannels.Add(new()
|
uow.ImageOnlyChannels.Add(new()
|
||||||
{
|
{
|
||||||
GuildId = guildId,
|
GuildId = guildId,
|
||||||
ChannelId = channelId
|
ChannelId = channelId,
|
||||||
|
Type = OnlyChannelType.Image
|
||||||
});
|
});
|
||||||
|
|
||||||
channels = _enabledOn.GetOrAdd(guildId, new ConcurrentHashSet<ulong>());
|
if (_linkOnly.TryGetValue(guildId, out var chs))
|
||||||
|
chs.TryRemove(channelId);
|
||||||
|
|
||||||
|
channels = _imageOnly.GetOrAdd(guildId, new ConcurrentHashSet<ulong>());
|
||||||
channels.Add(channelId);
|
channels.Add(channelId);
|
||||||
newState = true;
|
newState = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
uow.SaveChanges();
|
await uow.SaveChangesAsync();
|
||||||
|
return newState;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> ToggleLinkOnlyChannelAsync(ulong guildId, ulong channelId, bool forceDisable = false)
|
||||||
|
{
|
||||||
|
var newState = false;
|
||||||
|
await using var uow = _db.GetDbContext();
|
||||||
|
if (forceDisable || (_linkOnly.TryGetValue(guildId, out var channels) && channels.TryRemove(channelId)))
|
||||||
|
{
|
||||||
|
await uow.ImageOnlyChannels.DeleteAsync(x => x.ChannelId == channelId && x.Type == OnlyChannelType.Link);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await uow.ImageOnlyChannels.DeleteAsync(x => x.ChannelId == channelId);
|
||||||
|
uow.ImageOnlyChannels.Add(new()
|
||||||
|
{
|
||||||
|
GuildId = guildId,
|
||||||
|
ChannelId = channelId,
|
||||||
|
Type = OnlyChannelType.Link
|
||||||
|
});
|
||||||
|
|
||||||
|
if (_imageOnly.TryGetValue(guildId, out var chs))
|
||||||
|
chs.TryRemove(channelId);
|
||||||
|
|
||||||
|
channels = _linkOnly.GetOrAdd(guildId, new ConcurrentHashSet<ulong>());
|
||||||
|
channels.Add(channelId);
|
||||||
|
newState = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
await uow.SaveChangesAsync();
|
||||||
return newState;
|
return newState;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,11 +144,27 @@ public sealed class ImageOnlyChannelService : IExecOnMessage
|
|||||||
if (msg.Channel is not ITextChannel tch)
|
if (msg.Channel is not ITextChannel tch)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (_imageOnly.TryGetValue(tch.GuildId, out var chs) && chs.Contains(msg.Channel.Id))
|
||||||
|
return await HandleOnlyChannel(tch, msg, OnlyChannelType.Image);
|
||||||
|
|
||||||
|
if (_linkOnly.TryGetValue(tch.GuildId, out chs) && chs.Contains(msg.Channel.Id))
|
||||||
|
return await HandleOnlyChannel(tch, msg, OnlyChannelType.Link);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<bool> HandleOnlyChannel(ITextChannel tch, IUserMessage msg, OnlyChannelType type)
|
||||||
|
{
|
||||||
|
if (type == OnlyChannelType.Image)
|
||||||
|
{
|
||||||
if (msg.Attachments.Any(x => x is { Height: > 0, Width: > 0 }))
|
if (msg.Attachments.Any(x => x is { Height: > 0, Width: > 0 }))
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
if (!_enabledOn.TryGetValue(tch.GuildId, out var chs) || !chs.Contains(msg.Channel.Id))
|
else
|
||||||
|
{
|
||||||
|
if (msg.Content.TryGetUrlPath(out _))
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
var user = await tch.Guild.GetUserAsync(msg.Author.Id)
|
var user = await tch.Guild.GetUserAsync(msg.Author.Id)
|
||||||
?? await _client.Rest.GetGuildUserAsync(tch.GuildId, msg.Author.Id);
|
?? await _client.Rest.GetGuildUserAsync(tch.GuildId, msg.Author.Id);
|
||||||
@@ -113,7 +175,7 @@ public sealed class ImageOnlyChannelService : IExecOnMessage
|
|||||||
// ignore owner and admin
|
// ignore owner and admin
|
||||||
if (user.Id == tch.Guild.OwnerId || user.GuildPermissions.Administrator)
|
if (user.Id == tch.Guild.OwnerId || user.GuildPermissions.Administrator)
|
||||||
{
|
{
|
||||||
Log.Information("Image-Only: Ignoring owner od admin ({ChannelId})", msg.Channel.Id);
|
Log.Information("{Type}-Only Channel: Ignoring owner od admin ({ChannelId})", type, msg.Channel.Id);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,7 +186,11 @@ public sealed class ImageOnlyChannelService : IExecOnMessage
|
|||||||
|
|
||||||
if (!botUser.GetPermissions(tch).ManageChannel)
|
if (!botUser.GetPermissions(tch).ManageChannel)
|
||||||
{
|
{
|
||||||
ToggleImageOnlyChannel(tch.GuildId, tch.Id, true);
|
if(type == OnlyChannelType.Image)
|
||||||
|
await ToggleImageOnlyChannelAsync(tch.GuildId, tch.Id, true);
|
||||||
|
else
|
||||||
|
await ToggleImageOnlyChannelAsync(tch.GuildId, tch.Id, true);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,7 +198,8 @@ public sealed class ImageOnlyChannelService : IExecOnMessage
|
|||||||
if (shouldLock)
|
if (shouldLock)
|
||||||
{
|
{
|
||||||
await tch.AddPermissionOverwriteAsync(msg.Author, new(sendMessages: PermValue.Deny));
|
await tch.AddPermissionOverwriteAsync(msg.Author, new(sendMessages: PermValue.Deny));
|
||||||
Log.Warning("Image-Only: User {User} [{UserId}] has been banned from typing in the channel [{ChannelId}]",
|
Log.Warning("{Type}-Only Channel: User {User} [{UserId}] has been banned from typing in the channel [{ChannelId}]",
|
||||||
|
type,
|
||||||
msg.Author,
|
msg.Author,
|
||||||
msg.Author.Id,
|
msg.Author.Id,
|
||||||
msg.Channel.Id);
|
msg.Channel.Id);
|
||||||
|
@@ -41,7 +41,7 @@ public partial class Administration
|
|||||||
[Cmd]
|
[Cmd]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[Priority(0)]
|
[Priority(0)]
|
||||||
public async partial Task LanguageSet()
|
public async Task LanguageSet()
|
||||||
=> await ReplyConfirmLocalizedAsync(strs.lang_set_show(Format.Bold(Culture.ToString()),
|
=> await ReplyConfirmLocalizedAsync(strs.lang_set_show(Format.Bold(Culture.ToString()),
|
||||||
Format.Bold(Culture.NativeName)));
|
Format.Bold(Culture.NativeName)));
|
||||||
|
|
||||||
@@ -49,7 +49,7 @@ public partial class Administration
|
|||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[UserPerm(GuildPerm.Administrator)]
|
[UserPerm(GuildPerm.Administrator)]
|
||||||
[Priority(1)]
|
[Priority(1)]
|
||||||
public async partial Task LanguageSet(string name)
|
public async Task LanguageSet(string name)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -74,7 +74,7 @@ public partial class Administration
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
public async partial Task LanguageSetDefault()
|
public async Task LanguageSetDefault()
|
||||||
{
|
{
|
||||||
var cul = _localization.DefaultCultureInfo;
|
var cul = _localization.DefaultCultureInfo;
|
||||||
await ReplyErrorLocalizedAsync(strs.lang_set_bot_show(cul, cul.NativeName));
|
await ReplyErrorLocalizedAsync(strs.lang_set_bot_show(cul, cul.NativeName));
|
||||||
@@ -82,7 +82,7 @@ public partial class Administration
|
|||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
[OwnerOnly]
|
[OwnerOnly]
|
||||||
public async partial Task LanguageSetDefault(string name)
|
public async Task LanguageSetDefault(string name)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -108,7 +108,7 @@ public partial class Administration
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
public async partial Task LanguagesList()
|
public async Task LanguagesList()
|
||||||
=> await ctx.Channel.EmbedAsync(_eb.Create()
|
=> await ctx.Channel.EmbedAsync(_eb.Create()
|
||||||
.WithOkColor()
|
.WithOkColor()
|
||||||
.WithTitle(GetText(strs.lang_list))
|
.WithTitle(GetText(strs.lang_list))
|
||||||
|
@@ -26,7 +26,7 @@ public partial class Administration
|
|||||||
[Cmd]
|
[Cmd]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[UserPerm(GuildPerm.ManageRoles)]
|
[UserPerm(GuildPerm.ManageRoles)]
|
||||||
public async partial Task MuteRole([Leftover] IRole role = null)
|
public async Task MuteRole([Leftover] IRole role = null)
|
||||||
{
|
{
|
||||||
if (role is null)
|
if (role is null)
|
||||||
{
|
{
|
||||||
@@ -51,7 +51,7 @@ public partial class Administration
|
|||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[UserPerm(GuildPerm.ManageRoles | GuildPerm.MuteMembers)]
|
[UserPerm(GuildPerm.ManageRoles | GuildPerm.MuteMembers)]
|
||||||
[Priority(0)]
|
[Priority(0)]
|
||||||
public async partial Task Mute(IGuildUser target, [Leftover] string reason = "")
|
public async Task Mute(IGuildUser target, [Leftover] string reason = "")
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -72,7 +72,7 @@ public partial class Administration
|
|||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[UserPerm(GuildPerm.ManageRoles | GuildPerm.MuteMembers)]
|
[UserPerm(GuildPerm.ManageRoles | GuildPerm.MuteMembers)]
|
||||||
[Priority(1)]
|
[Priority(1)]
|
||||||
public async partial Task Mute(StoopidTime time, IGuildUser user, [Leftover] string reason = "")
|
public async Task Mute(StoopidTime time, IGuildUser user, [Leftover] string reason = "")
|
||||||
{
|
{
|
||||||
if (time.Time < TimeSpan.FromMinutes(1) || time.Time > TimeSpan.FromDays(49))
|
if (time.Time < TimeSpan.FromMinutes(1) || time.Time > TimeSpan.FromDays(49))
|
||||||
return;
|
return;
|
||||||
@@ -95,7 +95,7 @@ public partial class Administration
|
|||||||
[Cmd]
|
[Cmd]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[UserPerm(GuildPerm.ManageRoles | GuildPerm.MuteMembers)]
|
[UserPerm(GuildPerm.ManageRoles | GuildPerm.MuteMembers)]
|
||||||
public async partial Task Unmute(IGuildUser user, [Leftover] string reason = "")
|
public async Task Unmute(IGuildUser user, [Leftover] string reason = "")
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -112,7 +112,7 @@ public partial class Administration
|
|||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[UserPerm(GuildPerm.ManageRoles)]
|
[UserPerm(GuildPerm.ManageRoles)]
|
||||||
[Priority(0)]
|
[Priority(0)]
|
||||||
public async partial Task ChatMute(IGuildUser user, [Leftover] string reason = "")
|
public async Task ChatMute(IGuildUser user, [Leftover] string reason = "")
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -133,7 +133,7 @@ public partial class Administration
|
|||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[UserPerm(GuildPerm.ManageRoles)]
|
[UserPerm(GuildPerm.ManageRoles)]
|
||||||
[Priority(1)]
|
[Priority(1)]
|
||||||
public async partial Task ChatMute(StoopidTime time, IGuildUser user, [Leftover] string reason = "")
|
public async Task ChatMute(StoopidTime time, IGuildUser user, [Leftover] string reason = "")
|
||||||
{
|
{
|
||||||
if (time.Time < TimeSpan.FromMinutes(1) || time.Time > TimeSpan.FromDays(49))
|
if (time.Time < TimeSpan.FromMinutes(1) || time.Time > TimeSpan.FromDays(49))
|
||||||
return;
|
return;
|
||||||
@@ -156,7 +156,7 @@ public partial class Administration
|
|||||||
[Cmd]
|
[Cmd]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[UserPerm(GuildPerm.ManageRoles)]
|
[UserPerm(GuildPerm.ManageRoles)]
|
||||||
public async partial Task ChatUnmute(IGuildUser user, [Leftover] string reason = "")
|
public async Task ChatUnmute(IGuildUser user, [Leftover] string reason = "")
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -173,7 +173,7 @@ public partial class Administration
|
|||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[UserPerm(GuildPerm.MuteMembers)]
|
[UserPerm(GuildPerm.MuteMembers)]
|
||||||
[Priority(0)]
|
[Priority(0)]
|
||||||
public async partial Task VoiceMute(IGuildUser user, [Leftover] string reason = "")
|
public async Task VoiceMute(IGuildUser user, [Leftover] string reason = "")
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -193,7 +193,7 @@ public partial class Administration
|
|||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[UserPerm(GuildPerm.MuteMembers)]
|
[UserPerm(GuildPerm.MuteMembers)]
|
||||||
[Priority(1)]
|
[Priority(1)]
|
||||||
public async partial Task VoiceMute(StoopidTime time, IGuildUser user, [Leftover] string reason = "")
|
public async Task VoiceMute(StoopidTime time, IGuildUser user, [Leftover] string reason = "")
|
||||||
{
|
{
|
||||||
if (time.Time < TimeSpan.FromMinutes(1) || time.Time > TimeSpan.FromDays(49))
|
if (time.Time < TimeSpan.FromMinutes(1) || time.Time > TimeSpan.FromDays(49))
|
||||||
return;
|
return;
|
||||||
@@ -215,7 +215,7 @@ public partial class Administration
|
|||||||
[Cmd]
|
[Cmd]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[UserPerm(GuildPerm.MuteMembers)]
|
[UserPerm(GuildPerm.MuteMembers)]
|
||||||
public async partial Task VoiceUnmute(IGuildUser user, [Leftover] string reason = "")
|
public async Task VoiceUnmute(IGuildUser user, [Leftover] string reason = "")
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
#nullable disable
|
#nullable disable
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Nadeko.Common;
|
||||||
using NadekoBot.Db;
|
using NadekoBot.Db;
|
||||||
using NadekoBot.Services.Database.Models;
|
using NadekoBot.Services.Database.Models;
|
||||||
|
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
#nullable disable
|
#nullable disable
|
||||||
|
using Nadeko.Common;
|
||||||
using NadekoBot.Common.TypeReaders;
|
using NadekoBot.Common.TypeReaders;
|
||||||
using NadekoBot.Modules.Administration.Services;
|
using NadekoBot.Modules.Administration.Services;
|
||||||
|
|
||||||
@@ -14,7 +15,7 @@ public partial class Administration
|
|||||||
[Cmd]
|
[Cmd]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[UserPerm(GuildPerm.Administrator)]
|
[UserPerm(GuildPerm.Administrator)]
|
||||||
public async partial Task DiscordPermOverride(CommandOrExprInfo cmd, params GuildPerm[] perms)
|
public async Task DiscordPermOverride(CommandOrExprInfo cmd, params GuildPerm[] perms)
|
||||||
{
|
{
|
||||||
if (perms is null || perms.Length == 0)
|
if (perms is null || perms.Length == 0)
|
||||||
{
|
{
|
||||||
@@ -33,7 +34,7 @@ public partial class Administration
|
|||||||
[Cmd]
|
[Cmd]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[UserPerm(GuildPerm.Administrator)]
|
[UserPerm(GuildPerm.Administrator)]
|
||||||
public async partial Task DiscordPermOverrideReset()
|
public async Task DiscordPermOverrideReset()
|
||||||
{
|
{
|
||||||
var result = await PromptUserConfirmAsync(_eb.Create()
|
var result = await PromptUserConfirmAsync(_eb.Create()
|
||||||
.WithOkColor()
|
.WithOkColor()
|
||||||
@@ -50,7 +51,7 @@ public partial class Administration
|
|||||||
[Cmd]
|
[Cmd]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[UserPerm(GuildPerm.Administrator)]
|
[UserPerm(GuildPerm.Administrator)]
|
||||||
public async partial Task DiscordPermOverrideList(int page = 1)
|
public async Task DiscordPermOverrideList(int page = 1)
|
||||||
{
|
{
|
||||||
if (--page < 0)
|
if (--page < 0)
|
||||||
return;
|
return;
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user