Removed module projects because it can't work like that atm. Commented out package commands.
This commit is contained in:
145
NadekoBot.Core/Modules/Games/Services/ChatterbotService.cs
Normal file
145
NadekoBot.Core/Modules/Games/Services/ChatterbotService.cs
Normal file
@ -0,0 +1,145 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using Discord.WebSocket;
|
||||
using NadekoBot.Common.ModuleBehaviors;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Modules.Permissions.Common;
|
||||
using NadekoBot.Modules.Permissions.Services;
|
||||
using NadekoBot.Core.Services;
|
||||
using NadekoBot.Core.Services.Database.Models;
|
||||
using NadekoBot.Core.Services.Impl;
|
||||
using NLog;
|
||||
using NadekoBot.Modules.Games.Common.ChatterBot;
|
||||
|
||||
namespace NadekoBot.Modules.Games.Services
|
||||
{
|
||||
public class ChatterBotService : IEarlyBlockingExecutor, INService
|
||||
{
|
||||
private readonly DiscordSocketClient _client;
|
||||
private readonly Logger _log;
|
||||
private readonly PermissionService _perms;
|
||||
private readonly CommandHandler _cmd;
|
||||
private readonly NadekoStrings _strings;
|
||||
private readonly IBotCredentials _creds;
|
||||
|
||||
public ConcurrentDictionary<ulong, Lazy<IChatterBotSession>> ChatterBotGuilds { get; }
|
||||
|
||||
public ChatterBotService(DiscordSocketClient client, PermissionService perms,
|
||||
NadekoBot bot, CommandHandler cmd, NadekoStrings strings,
|
||||
IBotCredentials creds)
|
||||
{
|
||||
_client = client;
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
_perms = perms;
|
||||
_cmd = cmd;
|
||||
_strings = strings;
|
||||
_creds = creds;
|
||||
|
||||
ChatterBotGuilds = new ConcurrentDictionary<ulong, Lazy<IChatterBotSession>>(
|
||||
bot.AllGuildConfigs
|
||||
.Where(gc => gc.CleverbotEnabled)
|
||||
.ToDictionary(gc => gc.GuildId, gc => new Lazy<IChatterBotSession>(() => CreateSession(), true)));
|
||||
}
|
||||
|
||||
public IChatterBotSession CreateSession()
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(_creds.CleverbotApiKey))
|
||||
return new ChatterBotSession();
|
||||
else
|
||||
return new OfficialCleverbotSession(_creds.CleverbotApiKey);
|
||||
}
|
||||
|
||||
public string PrepareMessage(IUserMessage msg, out IChatterBotSession cleverbot)
|
||||
{
|
||||
var channel = msg.Channel as ITextChannel;
|
||||
cleverbot = null;
|
||||
|
||||
if (channel == null)
|
||||
return null;
|
||||
|
||||
if (!ChatterBotGuilds.TryGetValue(channel.Guild.Id, out Lazy<IChatterBotSession> lazyCleverbot))
|
||||
return null;
|
||||
|
||||
cleverbot = lazyCleverbot.Value;
|
||||
|
||||
var nadekoId = _client.CurrentUser.Id;
|
||||
var normalMention = $"<@{nadekoId}> ";
|
||||
var nickMention = $"<@!{nadekoId}> ";
|
||||
string message;
|
||||
if (msg.Content.StartsWith(normalMention))
|
||||
{
|
||||
message = msg.Content.Substring(normalMention.Length).Trim();
|
||||
}
|
||||
else if (msg.Content.StartsWith(nickMention))
|
||||
{
|
||||
message = msg.Content.Substring(nickMention.Length).Trim();
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
public async Task<bool> TryAsk(IChatterBotSession cleverbot, ITextChannel channel, string message)
|
||||
{
|
||||
await channel.TriggerTypingAsync().ConfigureAwait(false);
|
||||
|
||||
var response = await cleverbot.Think(message).ConfigureAwait(false);
|
||||
try
|
||||
{
|
||||
await channel.SendConfirmAsync(response.SanitizeMentions()).ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await channel.SendConfirmAsync(response.SanitizeMentions()).ConfigureAwait(false); // try twice :\
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public async Task<bool> TryExecuteEarly(DiscordSocketClient client, IGuild guild, IUserMessage usrMsg)
|
||||
{
|
||||
if (!(guild is SocketGuild sg))
|
||||
return false;
|
||||
try
|
||||
{
|
||||
var message = PrepareMessage(usrMsg, out IChatterBotSession cbs);
|
||||
if (message == null || cbs == null)
|
||||
return false;
|
||||
|
||||
var pc = _perms.GetCache(guild.Id);
|
||||
if (!pc.Permissions.CheckPermissions(usrMsg,
|
||||
"cleverbot",
|
||||
"Games".ToLowerInvariant(),
|
||||
out int index))
|
||||
{
|
||||
if (pc.Verbose)
|
||||
{
|
||||
var returnMsg = _strings.GetText("trigger", guild.Id, "Permissions".ToLowerInvariant(), index + 1, Format.Bold(pc.Permissions[index].GetCommand(_cmd.GetPrefix(guild), (SocketGuild)guild)));
|
||||
try { await usrMsg.Channel.SendErrorAsync(returnMsg).ConfigureAwait(false); } catch { }
|
||||
_log.Info(returnMsg);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
var cleverbotExecuted = await TryAsk(cbs, (ITextChannel)usrMsg.Channel, message).ConfigureAwait(false);
|
||||
if (cleverbotExecuted)
|
||||
{
|
||||
_log.Info($@"CleverBot Executed
|
||||
Server: {guild.Name} [{guild.Id}]
|
||||
Channel: {usrMsg.Channel?.Name} [{usrMsg.Channel?.Id}]
|
||||
UserId: {usrMsg.Author} [{usrMsg.Author.Id}]
|
||||
Message: {usrMsg.Content}");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex) { _log.Warn(ex, "Error in cleverbot"); }
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
215
NadekoBot.Core/Modules/Games/Services/GamesService.cs
Normal file
215
NadekoBot.Core/Modules/Games/Services/GamesService.cs
Normal file
@ -0,0 +1,215 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using Discord.WebSocket;
|
||||
using NadekoBot.Common;
|
||||
using NadekoBot.Common.Collections;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Modules.Games.Common;
|
||||
using NadekoBot.Core.Services;
|
||||
using NadekoBot.Core.Services.Database.Models;
|
||||
using NadekoBot.Core.Services.Impl;
|
||||
using Newtonsoft.Json;
|
||||
using NLog;
|
||||
using NadekoBot.Modules.Games.Common.Acrophobia;
|
||||
using NadekoBot.Modules.Games.Common.Connect4;
|
||||
using NadekoBot.Modules.Games.Common.Hangman;
|
||||
using NadekoBot.Modules.Games.Common.Trivia;
|
||||
using NadekoBot.Modules.Games.Common.Nunchi;
|
||||
|
||||
namespace NadekoBot.Modules.Games.Services
|
||||
{
|
||||
public class GamesService : INService, IUnloadableService
|
||||
{
|
||||
private readonly IBotConfigProvider _bc;
|
||||
|
||||
public readonly ConcurrentDictionary<ulong, GirlRating> GirlRatings = new ConcurrentDictionary<ulong, GirlRating>();
|
||||
public readonly ImmutableArray<string> EightBallResponses;
|
||||
|
||||
private readonly Timer _t;
|
||||
private readonly CommandHandler _cmd;
|
||||
private readonly NadekoStrings _strings;
|
||||
private readonly IImagesService _images;
|
||||
private readonly Logger _log;
|
||||
|
||||
public readonly string TypingArticlesPath = "data/typing_articles2.json";
|
||||
private readonly CommandHandler _cmdHandler;
|
||||
|
||||
public List<TypingArticle> TypingArticles { get; } = new List<TypingArticle>();
|
||||
|
||||
//channelId, game
|
||||
public ConcurrentDictionary<ulong, Acrophobia> AcrophobiaGames { get; } = new ConcurrentDictionary<ulong, Acrophobia>();
|
||||
public ConcurrentDictionary<ulong, Connect4Game> Connect4Games { get; } = new ConcurrentDictionary<ulong, Connect4Game>();
|
||||
|
||||
public ConcurrentDictionary<ulong, Hangman> HangmanGames { get; } = new ConcurrentDictionary<ulong, Hangman>();
|
||||
public TermPool TermPool { get; } = new TermPool();
|
||||
|
||||
public ConcurrentDictionary<ulong, TriviaGame> RunningTrivias { get; } = new ConcurrentDictionary<ulong, TriviaGame>();
|
||||
public Dictionary<ulong, TicTacToe> TicTacToeGames { get; } = new Dictionary<ulong, TicTacToe>();
|
||||
public ConcurrentDictionary<ulong, TypingGame> RunningContests { get; } = new ConcurrentDictionary<ulong, TypingGame>();
|
||||
public ConcurrentDictionary<ulong, Nunchi> NunchiGames { get; } = new ConcurrentDictionary<ulong, Common.Nunchi.Nunchi>();
|
||||
|
||||
public GamesService(CommandHandler cmd, IBotConfigProvider bc, NadekoBot bot,
|
||||
NadekoStrings strings, IImagesService images, CommandHandler cmdHandler)
|
||||
{
|
||||
_bc = bc;
|
||||
_cmd = cmd;
|
||||
_strings = strings;
|
||||
_images = images;
|
||||
_cmdHandler = cmdHandler;
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
|
||||
//8ball
|
||||
EightBallResponses = _bc.BotConfig.EightBallResponses.Select(ebr => ebr.Text).ToImmutableArray();
|
||||
|
||||
//girl ratings
|
||||
_t = new Timer((_) =>
|
||||
{
|
||||
GirlRatings.Clear();
|
||||
|
||||
}, null, TimeSpan.FromDays(1), TimeSpan.FromDays(1));
|
||||
|
||||
//plantpick
|
||||
_cmd.OnMessageNoTrigger += PotentialFlowerGeneration;
|
||||
GenerationChannels = new ConcurrentHashSet<ulong>(bot
|
||||
.AllGuildConfigs
|
||||
.SelectMany(c => c.GenerateCurrencyChannelIds.Select(obj => obj.ChannelId)));
|
||||
|
||||
try
|
||||
{
|
||||
TypingArticles = JsonConvert.DeserializeObject<List<TypingArticle>>(File.ReadAllText(TypingArticlesPath));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_log.Warn("Error while loading typing articles {0}", ex.ToString());
|
||||
TypingArticles = new List<TypingArticle>();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task Unload()
|
||||
{
|
||||
_t.Change(Timeout.Infinite, Timeout.Infinite);
|
||||
_cmd.OnMessageNoTrigger -= PotentialFlowerGeneration;
|
||||
|
||||
AcrophobiaGames.ForEach(x => x.Value.Dispose());
|
||||
AcrophobiaGames.Clear();
|
||||
Connect4Games.ForEach(x => x.Value.Dispose());
|
||||
Connect4Games.Clear();
|
||||
HangmanGames.ForEach(x => x.Value.Dispose());
|
||||
HangmanGames.Clear();
|
||||
await Task.WhenAll(RunningTrivias.Select(x => x.Value.StopGame()));
|
||||
RunningTrivias.Clear();
|
||||
|
||||
TicTacToeGames.Clear();
|
||||
|
||||
await Task.WhenAll(RunningContests.Select(x => x.Value.Stop()))
|
||||
.ConfigureAwait(false);
|
||||
RunningContests.Clear();
|
||||
NunchiGames.ForEach(x => x.Value.Dispose());
|
||||
NunchiGames.Clear();
|
||||
}
|
||||
|
||||
private void DisposeElems(IEnumerable<IDisposable> xs)
|
||||
{
|
||||
xs.ForEach(x => x.Dispose());
|
||||
}
|
||||
|
||||
public void AddTypingArticle(IUser user, string text)
|
||||
{
|
||||
TypingArticles.Add(new TypingArticle
|
||||
{
|
||||
Title = $"Text added on {DateTime.UtcNow} by {user}",
|
||||
Text = text.SanitizeMentions(),
|
||||
});
|
||||
|
||||
File.WriteAllText(TypingArticlesPath, JsonConvert.SerializeObject(TypingArticles));
|
||||
}
|
||||
|
||||
public ConcurrentHashSet<ulong> GenerationChannels { get; }
|
||||
//channelid/message
|
||||
public ConcurrentDictionary<ulong, List<IUserMessage>> PlantedFlowers { get; } = new ConcurrentDictionary<ulong, List<IUserMessage>>();
|
||||
//channelId/last generation
|
||||
public ConcurrentDictionary<ulong, DateTime> LastGenerations { get; } = new ConcurrentDictionary<ulong, DateTime>();
|
||||
|
||||
private ConcurrentDictionary<ulong, object> _locks { get; } = new ConcurrentDictionary<ulong, object>();
|
||||
|
||||
public (string Name, ImmutableArray<byte> Data) GetRandomCurrencyImage()
|
||||
{
|
||||
var rng = new NadekoRandom();
|
||||
return _images.Currency[rng.Next(0, _images.Currency.Length)];
|
||||
}
|
||||
|
||||
private string GetText(ITextChannel ch, string key, params object[] rep)
|
||||
=> _strings.GetText(key, ch.GuildId, "Games".ToLowerInvariant(), rep);
|
||||
|
||||
private Task PotentialFlowerGeneration(IUserMessage imsg)
|
||||
{
|
||||
var msg = imsg as SocketUserMessage;
|
||||
if (msg == null || msg.Author.IsBot)
|
||||
return Task.CompletedTask;
|
||||
|
||||
var channel = imsg.Channel as ITextChannel;
|
||||
if (channel == null)
|
||||
return Task.CompletedTask;
|
||||
|
||||
if (!GenerationChannels.Contains(channel.Id))
|
||||
return Task.CompletedTask;
|
||||
|
||||
var _ = Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var lastGeneration = LastGenerations.GetOrAdd(channel.Id, DateTime.MinValue);
|
||||
var rng = new NadekoRandom();
|
||||
|
||||
if (DateTime.UtcNow - TimeSpan.FromSeconds(_bc.BotConfig.CurrencyGenerationCooldown) < lastGeneration) //recently generated in this channel, don't generate again
|
||||
return;
|
||||
|
||||
var num = rng.Next(1, 101) + _bc.BotConfig.CurrencyGenerationChance * 100;
|
||||
if (num > 100 && LastGenerations.TryUpdate(channel.Id, DateTime.UtcNow, lastGeneration))
|
||||
{
|
||||
var dropAmount = _bc.BotConfig.CurrencyDropAmount;
|
||||
var dropAmountMax = _bc.BotConfig.CurrencyDropAmountMax;
|
||||
|
||||
if (dropAmountMax != null && dropAmountMax > dropAmount)
|
||||
dropAmount = new NadekoRandom().Next(dropAmount, dropAmountMax.Value + 1);
|
||||
|
||||
if (dropAmount > 0)
|
||||
{
|
||||
var msgs = new IUserMessage[dropAmount];
|
||||
var prefix = _cmdHandler.GetPrefix(channel.Guild.Id);
|
||||
var toSend = dropAmount == 1
|
||||
? GetText(channel, "curgen_sn", _bc.BotConfig.CurrencySign)
|
||||
+ " " + GetText(channel, "pick_sn", prefix)
|
||||
: GetText(channel, "curgen_pl", dropAmount, _bc.BotConfig.CurrencySign)
|
||||
+ " " + GetText(channel, "pick_pl", prefix);
|
||||
var file = GetRandomCurrencyImage();
|
||||
using (var fileStream = file.Data.ToStream())
|
||||
{
|
||||
var sent = await channel.SendFileAsync(
|
||||
fileStream,
|
||||
file.Name,
|
||||
toSend).ConfigureAwait(false);
|
||||
|
||||
msgs[0] = sent;
|
||||
}
|
||||
|
||||
PlantedFlowers.AddOrUpdate(channel.Id, msgs.ToList(), (id, old) => { old.AddRange(msgs); return old; });
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.GetCurrentClassLogger().Warn(ex);
|
||||
}
|
||||
});
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
}
|
71
NadekoBot.Core/Modules/Games/Services/PollService.cs
Normal file
71
NadekoBot.Core/Modules/Games/Services/PollService.cs
Normal file
@ -0,0 +1,71 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using Discord.WebSocket;
|
||||
using NadekoBot.Common.ModuleBehaviors;
|
||||
using NadekoBot.Modules.Games.Common;
|
||||
using NadekoBot.Core.Services;
|
||||
using NadekoBot.Core.Services.Impl;
|
||||
using NLog;
|
||||
|
||||
namespace NadekoBot.Modules.Games.Services
|
||||
{
|
||||
public class PollService : IEarlyBlockingExecutor, INService
|
||||
{
|
||||
public ConcurrentDictionary<ulong, Poll> ActivePolls = new ConcurrentDictionary<ulong, Poll>();
|
||||
private readonly Logger _log;
|
||||
private readonly DiscordSocketClient _client;
|
||||
private readonly NadekoStrings _strings;
|
||||
|
||||
public PollService(DiscordSocketClient client, NadekoStrings strings)
|
||||
{
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
_client = client;
|
||||
_strings = strings;
|
||||
}
|
||||
|
||||
public async Task<bool?> StartPoll(ITextChannel channel, IUserMessage msg, string arg)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(arg) || !arg.Contains(";"))
|
||||
return null;
|
||||
var data = arg.Split(';');
|
||||
if (data.Length < 3)
|
||||
return null;
|
||||
|
||||
var poll = new Poll(_client, _strings, msg, data[0], data.Skip(1));
|
||||
if (ActivePolls.TryAdd(channel.Guild.Id, poll))
|
||||
{
|
||||
poll.OnEnded += (gid) =>
|
||||
{
|
||||
ActivePolls.TryRemove(gid, out _);
|
||||
};
|
||||
|
||||
await poll.StartPoll().ConfigureAwait(false);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public async Task<bool> TryExecuteEarly(DiscordSocketClient client, IGuild guild, IUserMessage msg)
|
||||
{
|
||||
if (guild == null)
|
||||
return false;
|
||||
|
||||
if (!ActivePolls.TryGetValue(guild.Id, out var poll))
|
||||
return false;
|
||||
|
||||
try
|
||||
{
|
||||
return await poll.TryVote(msg).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_log.Warn(ex);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user