diff --git a/CHANGELOG.md b/CHANGELOG.md index 915334ce0..502fd7bea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,8 @@ Experimental changelog. Mostly based on [keepachangelog](https://keepachangelog. - Added `.clubrename` command to uh rename your club - For self-hosters: - Added `.sqlselectcsv` which will return results in a csv file instead of an embed. + - You can now configure whether nadeko ignores other bots in `bot.yml` + - You can now configure shop sale cut in `gambling.yml` - Added a page parameter to `.feedlist` - Added seconds/sec/s to .convert command diff --git a/src/NadekoBot/Modules/Gambling/GamblingConfig.cs b/src/NadekoBot/Modules/Gambling/GamblingConfig.cs index cc217a930..90385f0b9 100644 --- a/src/NadekoBot/Modules/Gambling/GamblingConfig.cs +++ b/src/NadekoBot/Modules/Gambling/GamblingConfig.cs @@ -42,6 +42,9 @@ public sealed partial class GamblingConfig : ICloneable [Comment("""How much will each user's owned currency decay over time.""")] public DecayConfig Decay { get; set; } + + [Comment("""What is the bot's cut on some transactions""")] + public BotCutConfig BotCuts { get; set; } [Comment("""Settings for LuckyLadder command""")] public LuckyLadderSettings LuckyLadder { get; set; } @@ -75,6 +78,7 @@ public sealed partial class GamblingConfig : ICloneable Decay = new(); Slots = new(); LuckyLadder = new(); + BotCuts = new(); } } @@ -384,4 +388,17 @@ public sealed partial class BetRollPair { public int WhenAbove { get; set; } public float MultiplyBy { get; set; } +} + +[Cloneable] +public sealed partial class BotCutConfig +{ + [Comment(""" + Shop sale cut percentage. + Whenever a user buys something from the shop, bot will take a cut equal to this percentage. + The rest goes to the user who posted the item/role/whatever to the shop. + This is a good way to reduce the amount of currency in circulation therefore keeping the inflation in check. + Default 0.1 (10%). + """)] + public decimal ShopSaleCut { get; set; } = 0.1m; } \ No newline at end of file diff --git a/src/NadekoBot/Modules/Gambling/GamblingConfigService.cs b/src/NadekoBot/Modules/Gambling/GamblingConfigService.cs index 3f4bbefe6..ecee8f005 100644 --- a/src/NadekoBot/Modules/Gambling/GamblingConfigService.cs +++ b/src/NadekoBot/Modules/Gambling/GamblingConfigService.cs @@ -182,5 +182,13 @@ public sealed class GamblingConfigService : ConfigServiceBase c.Version = 6; }); } + + if (data.Version < 7) + { + ModifyConfig(c => + { + c.Version = 7; + }); + } } } \ No newline at end of file diff --git a/src/NadekoBot/Modules/Gambling/Shop/ShopCommands.cs b/src/NadekoBot/Modules/Gambling/Shop/ShopCommands.cs index 7d7bd23cd..adc85b423 100644 --- a/src/NadekoBot/Modules/Gambling/Shop/ShopCommands.cs +++ b/src/NadekoBot/Modules/Gambling/Shop/ShopCommands.cs @@ -283,8 +283,8 @@ public partial class Gambling } } - private static long GetProfitAmount(int price) - => (int)Math.Ceiling(0.90 * price); + private long GetProfitAmount(int price) + => (int)Math.Ceiling((1.0m - Config.BotCuts.ShopSaleCut) * price); [Cmd] [RequireContext(ContextType.Guild)] diff --git a/src/NadekoBot/_common/Configs/BotConfig.cs b/src/NadekoBot/_common/Configs/BotConfig.cs index 193c002ca..6bb655a7f 100644 --- a/src/NadekoBot/_common/Configs/BotConfig.cs +++ b/src/NadekoBot/_common/Configs/BotConfig.cs @@ -13,7 +13,7 @@ namespace NadekoBot.Common.Configs; public sealed partial class BotConfig : ICloneable { [Comment("""DO NOT CHANGE""")] - public int Version { get; set; } = 6; + public int Version { get; set; } = 7; [Comment(""" Most commands, when executed, have a small colored line @@ -51,6 +51,14 @@ public sealed partial class BotConfig : ICloneable This option will only work when ForwardToAllOwners is set to false """)] public ulong? ForwardToChannel { get; set; } + + [Comment(""" + Should the bot ignore messages from other bots? + Settings this to false might get your bot banned if it gets into a spam loop with another bot. + This will only affect command executions, other features will still block bots from access. + Default true + """)] + public bool IgnoreOtherBots { get; set; } [Comment(""" When a user DMs the bot with a message which is not a command diff --git a/src/NadekoBot/_common/Services/CommandHandler.cs b/src/NadekoBot/_common/Services/CommandHandler.cs index 61e24b164..8728b22f3 100644 --- a/src/NadekoBot/_common/Services/CommandHandler.cs +++ b/src/NadekoBot/_common/Services/CommandHandler.cs @@ -23,7 +23,7 @@ public class CommandHandler : INService, IReadyExecutor, ICommandHandler private readonly DiscordSocketClient _client; private readonly CommandService _commandService; - private readonly BotConfigService _bss; + private readonly BotConfigService _bcs; private readonly IBot _bot; private readonly IBehaviorHandler _behaviorHandler; private readonly IServiceProvider _services; @@ -31,21 +31,24 @@ public class CommandHandler : INService, IReadyExecutor, ICommandHandler private readonly ConcurrentDictionary _prefixes; private readonly DbService _db; + + private readonly BotConfig _bc; // private readonly InteractionService _interactions; public CommandHandler( DiscordSocketClient client, DbService db, CommandService commandService, - BotConfigService bss, + BotConfigService bcs, IBot bot, IBehaviorHandler behaviorHandler, // InteractionService interactions, IServiceProvider services) { - _client = client; - _commandService = commandService; - _bss = bss; + _client = client; + _commandService = commandService; + _bc = bcs.Data; + _bcs = bcs; _bot = bot; _behaviorHandler = behaviorHandler; _db = db; @@ -55,7 +58,6 @@ public class CommandHandler : INService, IReadyExecutor, ICommandHandler _prefixes = bot.AllGuildConfigs.Where(x => x.Prefix is not null) .ToDictionary(x => x.GuildId, x => x.Prefix) .ToConcurrent(); - } public async Task OnReadyAsync() @@ -72,7 +74,7 @@ public class CommandHandler : INService, IReadyExecutor, ICommandHandler public string GetPrefix(ulong? id = null) { if (id is null || !_prefixes.TryGetValue(id.Value, out var prefix)) - return _bss.Data.Prefix; + return _bcs.Data.Prefix; return prefix; } @@ -82,7 +84,7 @@ public class CommandHandler : INService, IReadyExecutor, ICommandHandler if (string.IsNullOrWhiteSpace(prefix)) throw new ArgumentNullException(nameof(prefix)); - _bss.ModifyConfig(bs => + _bcs.ModifyConfig(bs => { bs.Prefix = prefix; }); @@ -146,15 +148,15 @@ public class CommandHandler : INService, IReadyExecutor, ICommandHandler private Task LogSuccessfulExecution(IUserMessage usrMsg, ITextChannel channel, params int[] execPoints) { - if (_bss.Data.ConsoleOutputType == ConsoleOutputType.Normal) + if (_bcs.Data.ConsoleOutputType == ConsoleOutputType.Normal) { Log.Information(""" - Command Executed after {ExecTime}s - User: {User} - Server: {Server} - Channel: {Channel} - Message: {Message} - """, + Command Executed after {ExecTime}s + User: {User} + Server: {Server} + Channel: {Channel} + Message: {Message} + """, string.Join("/", execPoints.Select(x => (x * ONE_THOUSANDTH).ToString("F3"))), usrMsg.Author + " [" + usrMsg.Author.Id + "]", channel is null ? "PRIVATE" : channel.Guild.Name + " [" + channel.Guild.Id + "]", @@ -179,16 +181,16 @@ public class CommandHandler : INService, IReadyExecutor, ICommandHandler ITextChannel channel, params int[] execPoints) { - if (_bss.Data.ConsoleOutputType == ConsoleOutputType.Normal) + if (_bcs.Data.ConsoleOutputType == ConsoleOutputType.Normal) { Log.Warning(""" - Command Errored after {ExecTime}s - User: {User} - Server: {Guild} - Channel: {Channel} - Message: {Message} - Error: {ErrorMessage} - """, + Command Errored after {ExecTime}s + User: {User} + Server: {Guild} + Channel: {Channel} + Message: {Message} + Error: {ErrorMessage} + """, string.Join("/", execPoints.Select(x => (x * ONE_THOUSANDTH).ToString("F3"))), usrMsg.Author + " [" + usrMsg.Author.Id + "]", channel is null ? "DM" : channel.Guild.Name + " [" + channel.Guild.Id + "]", @@ -199,9 +201,9 @@ public class CommandHandler : INService, IReadyExecutor, ICommandHandler else { Log.Warning(""" - Err | g:{GuildId} | c: {ChannelId} | u: {UserId} | msg: {Message} - Err: {ErrorMessage} - """, + Err | g:{GuildId} | c: {ChannelId} | u: {UserId} | msg: {Message} + Err: {ErrorMessage} + """, channel?.Guild.Id.ToString() ?? "-", channel?.Id.ToString() ?? "-", usrMsg.Author.Id, @@ -212,8 +214,15 @@ public class CommandHandler : INService, IReadyExecutor, ICommandHandler private Task MessageReceivedHandler(SocketMessage msg) { - //no bots, wait until bot connected and initialized - if (msg.Author.IsBot || !_bot.IsReady) + if (!_bot.IsReady) + return Task.CompletedTask; + + if (_bc.IgnoreOtherBots) + { + if (msg.Author.IsBot) + return Task.CompletedTask; + } + else if (msg.Author.Id == _client.CurrentUser.Id) return Task.CompletedTask; if (msg is not SocketUserMessage usrMsg) @@ -267,7 +276,7 @@ public class CommandHandler : INService, IReadyExecutor, ICommandHandler isPrefixCommand ? 1 : prefix.Length, _services, MultiMatchHandling.Best); - + startTime = Environment.TickCount - startTime; // if a command is found @@ -287,10 +296,10 @@ public class CommandHandler : INService, IReadyExecutor, ICommandHandler { error = HumanizeError(error); LogErroredExecution(error, usrMsg, channel as ITextChannel, blockTime, startTime); - + if (guild is not null) await CommandErrored(info, channel as ITextChannel, error); - + return; } } @@ -355,9 +364,9 @@ public class CommandHandler : INService, IReadyExecutor, ICommandHandler { case MultiMatchHandling.Best: argList = parseResult.ArgValues - .Map(x => x.Values.MaxBy(y => y.Score)); + .Map(x => x.Values.MaxBy(y => y.Score)); paramList = parseResult.ParamValues - .Map(x => x.Values.MaxBy(y => y.Score)); + .Map(x => x.Values.MaxBy(y => y.Score)); parseResult = ParseResult.FromSuccess(argList, paramList); break; } diff --git a/src/NadekoBot/_common/Settings/BotConfigService.cs b/src/NadekoBot/_common/Settings/BotConfigService.cs index 62c5c6ea2..b3782eaf6 100644 --- a/src/NadekoBot/_common/Settings/BotConfigService.cs +++ b/src/NadekoBot/_common/Settings/BotConfigService.cs @@ -62,5 +62,12 @@ public sealed class BotConfigService : ConfigServiceBase { c.Version = 5; }); + + if(data.Version < 7) + ModifyConfig(c => + { + c.Version = 7; + c.IgnoreOtherBots = true; + }); } } \ No newline at end of file diff --git a/src/NadekoBot/data/bot.yml b/src/NadekoBot/data/bot.yml index b8f0fe760..5b0363fd0 100644 --- a/src/NadekoBot/data/bot.yml +++ b/src/NadekoBot/data/bot.yml @@ -1,5 +1,5 @@ # DO NOT CHANGE -version: 5 +version: 7 # Most commands, when executed, have a small colored line # next to the response. The color depends whether the command # is completed, errored or in progress (pending) @@ -7,7 +7,7 @@ version: 5 # To get color's hex, you can go here https://htmlcolorcodes.com/ # and copy the hex code fo your selected color (marked as #) color: -# Color used for embed responses when command successfully executes + # Color used for embed responses when command successfully executes ok: 00e584 # Color used for embed responses when command has an error error: ee281f @@ -28,6 +28,11 @@ forwardToAllOwners: false # Any messages sent by users in Bot's DM to be forwarded to the specified channel. # This option will only work when ForwardToAllOwners is set to false forwardToChannel: +# Should the bot ignore messages from other bots? +# Settings this to false might get your bot banned if it gets into a spam loop with another bot. +# This will only affect command executions, other features will still block bots from access. +# Default true +ignoreOtherBots: true # When a user DMs the bot with a message which is not a command # they will receive this message. Leave empty for no response. The string which will be sent whenever someone DMs the bot. # Supports embeds. How it looks: https://puu.sh/B0BLV.png diff --git a/src/NadekoBot/data/gambling.yml b/src/NadekoBot/data/gambling.yml index 0885379e8..7e54edf39 100644 --- a/src/NadekoBot/data/gambling.yml +++ b/src/NadekoBot/data/gambling.yml @@ -1,12 +1,12 @@ # DO NOT CHANGE -version: 6 +version: 7 # Currency settings currency: -# What is the emoji/character which represents the currency + # What is the emoji/character which represents the currency sign: "🌸" # What is the name of the currency name: Nadeko Flower - # For how long will the transactions be kept in the database (curtrs) + # For how long (in days) will the transactions be kept in the database (curtrs) # Set 0 to disable cleanup (keep transactions forever) transactionsLifetime: 0 # Minimum amount users can bet (>=0) @@ -16,13 +16,13 @@ minBet: 0 maxBet: 0 # Settings for betflip command betFlip: -# Bet multiplier if user guesses correctly + # Bet multiplier if user guesses correctly multiplier: 1.95 # Settings for betroll command betRoll: -# When betroll is played, user will roll a number 0-100. -# This setting will describe which multiplier is used for when the roll is higher than the given number. -# Doesn't have to be ordered. + # When betroll is played, user will roll a number 0-100. + # This setting will describe which multiplier is used for when the roll is higher than the given number. + # Doesn't have to be ordered. pairs: - whenAbove: 99 multiplyBy: 10 @@ -32,9 +32,9 @@ betRoll: multiplyBy: 2 # Automatic currency generation settings. generation: -# when currency is generated, should it also have a random password -# associated with it which users have to type after the .pick command -# in order to get it + # when currency is generated, should it also have a random password + # associated with it which users have to type after the .pick command + # in order to get it hasPassword: true # Every message sent has a certain % chance to generate the currency # specify the percentage here (1 being 100%, 0 being 0% - for example @@ -50,16 +50,16 @@ generation: # Settings for timely command # (letting people claim X amount of currency every Y hours) timely: -# How much currency will the users get every time they run .timely command -# setting to 0 or less will disable this feature + # How much currency will the users get every time they run .timely command + # setting to 0 or less will disable this feature amount: 120 # How often (in hours) can users claim currency with .timely command # setting to 0 or less will disable this feature cooldown: 12 # How much will each user's owned currency decay over time. decay: -# Percentage of user's current currency which will be deducted every 24h. -# 0 - 1 (1 is 100%, 0.5 50%, 0 disabled) + # Percentage of user's current currency which will be deducted every 24h. + # 0 - 1 (1 is 100%, 0.5 50%, 0 disabled) percent: 0 # Maximum amount of user's currency that can decay at each interval. 0 for unlimited. maxDecay: 0 @@ -67,9 +67,17 @@ decay: minThreshold: 99 # How often, in hours, does the decay run. Default is 24 hours hourInterval: 24 +# What is the bot's cut on some transactions +botCuts: + # Shop sale cut percentage. + # Whenever a user buys something from the shop, bot will take a cut equal to this percentage. + # The rest goes to the user who posted the item/role/whatever to the shop. + # This is a good way to reduce the amount of currency in circulation therefore keeping the inflation in check. + # Default 0.1 (10%). + shopSaleCut: 0.1 # Settings for LuckyLadder command luckyLadder: -# Self-Explanatory. Has to have 8 values, otherwise the command won't work. + # Self-Explanatory. Has to have 8 values, otherwise the command won't work. multipliers: - 2.4 - 1.7 @@ -81,12 +89,12 @@ luckyLadder: - 0.1 # Settings related to waifus waifu: -# Minimum price a waifu can have + # Minimum price a waifu can have minPrice: 50 multipliers: - # Multiplier for waifureset. Default 150. - # Formula (at the time of writing this): - # price = (waifu_price * 1.25f) + ((number_of_divorces + changes_of_heart + 2) * WaifuReset) rounded up + # Multiplier for waifureset. Default 150. + # Formula (at the time of writing this): + # price = (waifu_price * 1.25f) + ((number_of_divorces + changes_of_heart + 2) * WaifuReset) rounded up waifuReset: 150 # The minimum amount of currency that you have to pay # in order to buy a waifu who doesn't have a crush on you. @@ -117,9 +125,9 @@ waifu: # Settings for periodic waifu price decay. # Waifu price decays only if the waifu has no claimer. decay: - # Percentage (0 - 100) of the waifu value to reduce. - # Set 0 to disable - # For example if a waifu has a price of 500$, setting this value to 10 would reduce the waifu value by 10% (50$) + # Percentage (0 - 100) of the waifu value to reduce. + # Set 0 to disable + # For example if a waifu has a price of 500$, setting this value to 10 would reduce the waifu value by 10% (50$) percent: 0 # How often to decay waifu values, in hours hourInterval: 24 @@ -257,5 +265,5 @@ patreonCurrencyPerCent: 1 voteReward: 100 # Slot config slots: -# Hex value of the color which the numbers on the slot image will have. + # Hex value of the color which the numbers on the slot image will have. currencyFontColor: ff0000