2017-07-17 19:42:36 +00:00
using System ;
2017-05-27 08:19:27 +00:00
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 ;
2017-07-17 19:42:36 +00:00
using Discord ;
using Discord.WebSocket ;
using NadekoBot.Common ;
using NadekoBot.Common.Collections ;
using NadekoBot.Extensions ;
using NadekoBot.Modules.Games.Common ;
using NadekoBot.Services ;
using NadekoBot.Services.Database.Models ;
using NadekoBot.Services.Impl ;
using Newtonsoft.Json ;
using NLog ;
2017-10-04 22:51:12 +00:00
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 ;
2017-05-27 08:19:27 +00:00
2017-07-17 19:42:36 +00:00
namespace NadekoBot.Modules.Games.Services
2017-05-27 08:19:27 +00:00
{
2017-10-04 22:51:12 +00:00
public class GamesService : INService , IUnloadableService
2017-05-27 08:19:27 +00:00
{
2017-07-20 03:10:39 +00:00
private readonly IBotConfigProvider _bc ;
2017-05-27 08:19:27 +00:00
public readonly ConcurrentDictionary < ulong , GirlRating > GirlRatings = new ConcurrentDictionary < ulong , GirlRating > ( ) ;
public readonly ImmutableArray < string > EightBallResponses ;
private readonly Timer _t ;
2017-08-22 03:48:45 +00:00
private readonly CommandHandler _cmd ;
2017-05-27 08:19:27 +00:00
private readonly NadekoStrings _strings ;
private readonly IImagesService _images ;
private readonly Logger _log ;
public readonly string TypingArticlesPath = "data/typing_articles2.json" ;
2017-05-30 04:54:59 +00:00
private readonly CommandHandler _cmdHandler ;
2017-05-27 08:19:27 +00:00
public List < TypingArticle > TypingArticles { get ; } = new List < TypingArticle > ( ) ;
2017-10-04 22:51:12 +00:00
//channelId, game
public ConcurrentDictionary < ulong , Acrophobia > AcrophobiaGames { get ; } = new ConcurrentDictionary < ulong , Acrophobia > ( ) ;
public ConcurrentDictionary < ulong , Connect4Game > Connect4Games { get ; } = new ConcurrentDictionary < ulong , Connect4Game > ( ) ;
2017-10-09 00:52:46 +00:00
2017-10-04 22:51:12 +00:00
public ConcurrentDictionary < ulong , Hangman > HangmanGames { get ; } = new ConcurrentDictionary < ulong , Hangman > ( ) ;
2017-10-09 00:52:46 +00:00
public TermPool TermPool { get ; } = new TermPool ( ) ;
2017-10-04 22:51:12 +00:00
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 > ( ) ;
2017-10-13 00:21:39 +00:00
public GamesService ( CommandHandler cmd , IBotConfigProvider bc , NadekoBot bot ,
2017-05-30 04:54:59 +00:00
NadekoStrings strings , IImagesService images , CommandHandler cmdHandler )
2017-05-27 08:19:27 +00:00
{
_bc = bc ;
2017-08-22 03:48:45 +00:00
_cmd = cmd ;
2017-05-27 08:19:27 +00:00
_strings = strings ;
_images = images ;
2017-05-30 04:54:59 +00:00
_cmdHandler = cmdHandler ;
2017-05-27 08:19:27 +00:00
_log = LogManager . GetCurrentClassLogger ( ) ;
//8ball
2017-07-20 03:10:39 +00:00
EightBallResponses = _bc . BotConfig . EightBallResponses . Select ( ebr = > ebr . Text ) . ToImmutableArray ( ) ;
2017-05-27 08:19:27 +00:00
//girl ratings
_t = new Timer ( ( _ ) = >
{
GirlRatings . Clear ( ) ;
} , null , TimeSpan . FromDays ( 1 ) , TimeSpan . FromDays ( 1 ) ) ;
//plantpick
2017-08-22 03:48:45 +00:00
_cmd . OnMessageNoTrigger + = PotentialFlowerGeneration ;
2017-10-13 00:21:39 +00:00
GenerationChannels = new ConcurrentHashSet < ulong > ( bot
. AllGuildConfigs
2017-05-27 08:19:27 +00:00
. 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 > ( ) ;
}
}
2017-10-04 22:51:12 +00:00
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 ( ) ) ;
}
2017-05-29 04:13:22 +00:00
public void AddTypingArticle ( IUser user , string text )
2017-05-27 08:19:27 +00:00
{
2017-05-29 04:13:22 +00:00
TypingArticles . Add ( new TypingArticle
2017-05-27 08:19:27 +00:00
{
2017-05-29 04:13:22 +00:00
Title = $"Text added on {DateTime.UtcNow} by {user}" ,
Text = text . SanitizeMentions ( ) ,
} ) ;
2017-05-27 08:19:27 +00:00
2017-05-29 04:13:22 +00:00
File . WriteAllText ( TypingArticlesPath , JsonConvert . SerializeObject ( TypingArticles ) ) ;
2017-05-27 08:19:27 +00:00
}
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 > ( ) ;
2017-05-29 04:13:22 +00:00
private ConcurrentDictionary < ulong , object > _locks { get ; } = new ConcurrentDictionary < ulong , object > ( ) ;
2017-05-27 08:19:27 +00:00
2017-05-29 04:13:22 +00:00
public ( string Name , ImmutableArray < byte > Data ) GetRandomCurrencyImage ( )
2017-05-27 08:19:27 +00:00
{
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 ) ;
2017-08-22 03:48:45 +00:00
private Task PotentialFlowerGeneration ( IUserMessage imsg )
2017-05-27 08:19:27 +00:00
{
var msg = imsg as SocketUserMessage ;
if ( msg = = null | | msg . Author . IsBot )
2017-06-15 23:55:14 +00:00
return Task . CompletedTask ;
2017-05-27 08:19:27 +00:00
var channel = imsg . Channel as ITextChannel ;
if ( channel = = null )
2017-06-15 23:55:14 +00:00
return Task . CompletedTask ;
2017-05-27 08:19:27 +00:00
if ( ! GenerationChannels . Contains ( channel . Id ) )
2017-06-15 23:55:14 +00:00
return Task . CompletedTask ;
2017-05-27 08:19:27 +00:00
2017-06-05 22:46:58 +00:00
var _ = Task . Run ( async ( ) = >
{
try
2017-05-29 04:13:22 +00:00
{
2017-06-05 22:46:58 +00:00
var lastGeneration = LastGenerations . GetOrAdd ( channel . Id , DateTime . MinValue ) ;
var rng = new NadekoRandom ( ) ;
2017-05-27 08:19:27 +00:00
2017-07-20 03:10:39 +00:00
if ( DateTime . UtcNow - TimeSpan . FromSeconds ( _bc . BotConfig . CurrencyGenerationCooldown ) < lastGeneration ) //recently generated in this channel, don't generate again
2017-06-05 22:46:58 +00:00
return ;
2017-07-20 03:10:39 +00:00
var num = rng . Next ( 1 , 101 ) + _bc . BotConfig . CurrencyGenerationChance * 100 ;
2017-06-12 23:40:39 +00:00
if ( num > 100 & & LastGenerations . TryUpdate ( channel . Id , DateTime . UtcNow , lastGeneration ) )
2017-05-27 08:19:27 +00:00
{
2017-07-20 03:10:39 +00:00
var dropAmount = _bc . BotConfig . CurrencyDropAmount ;
var dropAmountMax = _bc . BotConfig . CurrencyDropAmountMax ;
2017-06-13 23:21:31 +00:00
if ( dropAmountMax ! = null & & dropAmountMax > dropAmount )
dropAmount = new NadekoRandom ( ) . Next ( dropAmount , dropAmountMax . Value + 1 ) ;
2017-05-29 04:13:22 +00:00
2017-06-05 22:46:58 +00:00
if ( dropAmount > 0 )
{
var msgs = new IUserMessage [ dropAmount ] ;
var prefix = _cmdHandler . GetPrefix ( channel . Guild . Id ) ;
var toSend = dropAmount = = 1
2017-07-20 03:10:39 +00:00
? GetText ( channel , "curgen_sn" , _bc . BotConfig . CurrencySign )
2017-06-05 22:46:58 +00:00
+ " " + GetText ( channel , "pick_sn" , prefix )
2017-07-20 03:10:39 +00:00
: GetText ( channel , "curgen_pl" , dropAmount , _bc . BotConfig . CurrencySign )
2017-06-05 22:46:58 +00:00
+ " " + 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 ; } ) ;
2017-05-27 08:19:27 +00:00
}
}
}
2017-06-05 22:46:58 +00:00
catch ( Exception ex )
{
LogManager . GetCurrentClassLogger ( ) . Warn ( ex ) ;
}
} ) ;
2017-06-15 23:55:14 +00:00
return Task . CompletedTask ;
2017-05-27 08:19:27 +00:00
}
}
}