Packages can be loaded/unloaded. IUnloadableService interface added whose method Unload, if service implements it, will be called when the module is unloaded.
This commit is contained in:
parent
599245b1ca
commit
33ac43e1b5
@ -3,6 +3,7 @@ using System.Linq;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Discord.Commands;
|
using Discord.Commands;
|
||||||
using NadekoBot.Services;
|
using NadekoBot.Services;
|
||||||
|
using NadekoBot.Modules.CustomReactions.Services;
|
||||||
|
|
||||||
namespace NadekoBot.Common.TypeReaders
|
namespace NadekoBot.Common.TypeReaders
|
||||||
{
|
{
|
||||||
@ -28,38 +29,38 @@ namespace NadekoBot.Common.TypeReaders
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
//todo dependency on the module
|
//todo dependency on the module
|
||||||
//public class CommandOrCrTypeReader : CommandTypeReader
|
public class CommandOrCrTypeReader : CommandTypeReader
|
||||||
//{
|
{
|
||||||
// public override async Task<TypeReaderResult> Read(ICommandContext context, string input, IServiceProvider services)
|
public override async Task<TypeReaderResult> Read(ICommandContext context, string input, IServiceProvider services)
|
||||||
// {
|
{
|
||||||
// input = input.ToUpperInvariant();
|
input = input.ToUpperInvariant();
|
||||||
|
|
||||||
// var _crs = ((INServiceProvider)services).GetService<CustomReactionsService>();
|
var _crs = ((INServiceProvider)services).GetService<CustomReactionsService>();
|
||||||
|
|
||||||
// if (_crs.GlobalReactions.Any(x => x.Trigger.ToUpperInvariant() == input))
|
if (_crs.GlobalReactions.Any(x => x.Trigger.ToUpperInvariant() == input))
|
||||||
// {
|
{
|
||||||
// return TypeReaderResult.FromSuccess(new CommandOrCrInfo(input));
|
return TypeReaderResult.FromSuccess(new CommandOrCrInfo(input));
|
||||||
// }
|
}
|
||||||
// var guild = context.Guild;
|
var guild = context.Guild;
|
||||||
// if (guild != null)
|
if (guild != null)
|
||||||
// {
|
{
|
||||||
// if (_crs.GuildReactions.TryGetValue(guild.Id, out var crs))
|
if (_crs.GuildReactions.TryGetValue(guild.Id, out var crs))
|
||||||
// {
|
{
|
||||||
// if (crs.Concat(_crs.GlobalReactions).Any(x => x.Trigger.ToUpperInvariant() == input))
|
if (crs.Concat(_crs.GlobalReactions).Any(x => x.Trigger.ToUpperInvariant() == input))
|
||||||
// {
|
{
|
||||||
// return TypeReaderResult.FromSuccess(new CommandOrCrInfo(input));
|
return TypeReaderResult.FromSuccess(new CommandOrCrInfo(input));
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
|
||||||
// var cmd = await base.Read(context, input, services);
|
var cmd = await base.Read(context, input, services);
|
||||||
// if (cmd.IsSuccess)
|
if (cmd.IsSuccess)
|
||||||
// {
|
{
|
||||||
// return TypeReaderResult.FromSuccess(new CommandOrCrInfo(((CommandInfo)cmd.Values.First().Value).Name));
|
return TypeReaderResult.FromSuccess(new CommandOrCrInfo(((CommandInfo)cmd.Values.First().Value).Name));
|
||||||
// }
|
}
|
||||||
// return TypeReaderResult.FromError(CommandError.ParseFailed, "No such command or cr found.");
|
return TypeReaderResult.FromError(CommandError.ParseFailed, "No such command or cr found.");
|
||||||
// }
|
}
|
||||||
//}
|
}
|
||||||
|
|
||||||
public class CommandOrCrInfo
|
public class CommandOrCrInfo
|
||||||
{
|
{
|
||||||
|
64
NadekoBot.Core/Modules/Administration/ModuleCommands.cs
Normal file
64
NadekoBot.Core/Modules/Administration/ModuleCommands.cs
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
using Discord.Commands;
|
||||||
|
using NadekoBot.Common.Attributes;
|
||||||
|
using NadekoBot.Core.Modules.Administration.Services;
|
||||||
|
using NadekoBot.Extensions;
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace NadekoBot.Modules.Administration
|
||||||
|
{
|
||||||
|
public partial class Administration
|
||||||
|
{
|
||||||
|
[Group]
|
||||||
|
public class PackagesCommands : NadekoSubmodule<PackagesService>
|
||||||
|
{
|
||||||
|
private readonly NadekoBot _bot;
|
||||||
|
|
||||||
|
public PackagesCommands(NadekoBot bot)
|
||||||
|
{
|
||||||
|
_bot = bot;
|
||||||
|
}
|
||||||
|
|
||||||
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
|
[RequireContext(ContextType.Guild)]
|
||||||
|
public async Task PackageList()
|
||||||
|
{
|
||||||
|
_service.ReloadAvailablePackages();
|
||||||
|
await Context.Channel.SendConfirmAsync(string.Join("\n", _service.Packages));
|
||||||
|
}
|
||||||
|
|
||||||
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
|
[RequireContext(ContextType.Guild)]
|
||||||
|
[OwnerOnly]
|
||||||
|
public async Task PackageUnload(string name)
|
||||||
|
{
|
||||||
|
if (name.Contains(":") || name.Contains(".") || name.Contains("\\") || name.Contains("/") || name.Contains("~"))
|
||||||
|
return;
|
||||||
|
name = name.ToTitleCase();
|
||||||
|
var package = Assembly.LoadFrom(Path.Combine(AppContext.BaseDirectory,
|
||||||
|
"modules",
|
||||||
|
$"NadekoBot.Modules.{name}",
|
||||||
|
$"NadekoBot.Modules.{name}.dll"));
|
||||||
|
|
||||||
|
await _bot.UnloadPackage(name).ConfigureAwait(false);
|
||||||
|
await ReplyAsync(":ok:");
|
||||||
|
}
|
||||||
|
|
||||||
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
|
[RequireContext(ContextType.Guild)]
|
||||||
|
[OwnerOnly]
|
||||||
|
public async Task PackageLoad(string name)
|
||||||
|
{
|
||||||
|
if (name.Contains(".") || name.Contains("\\") || name.Contains("/") || name.Contains("~"))
|
||||||
|
return;
|
||||||
|
name = name.ToTitleCase();
|
||||||
|
|
||||||
|
await _bot.LoadPackage(name);
|
||||||
|
await ReplyAsync(":ok:");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -48,6 +48,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
[OwnerOnly]
|
[OwnerOnly]
|
||||||
public async Task StartupCommandAdd([Remainder] string cmdText)
|
public async Task StartupCommandAdd([Remainder] string cmdText)
|
||||||
{
|
{
|
||||||
|
//todo don't let .die be a startup command
|
||||||
var guser = ((IGuildUser)Context.User);
|
var guser = ((IGuildUser)Context.User);
|
||||||
var cmd = new StartupCommand()
|
var cmd = new StartupCommand()
|
||||||
{
|
{
|
||||||
|
@ -0,0 +1,31 @@
|
|||||||
|
using NadekoBot.Services;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
|
namespace NadekoBot.Core.Modules.Administration.Services
|
||||||
|
{
|
||||||
|
public class PackagesService : INService
|
||||||
|
{
|
||||||
|
public IEnumerable<string> Packages { get; private set; }
|
||||||
|
|
||||||
|
public PackagesService()
|
||||||
|
{
|
||||||
|
ReloadAvailablePackages();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ReloadAvailablePackages()
|
||||||
|
{
|
||||||
|
Packages = Directory.GetDirectories(Path.Combine(AppContext.BaseDirectory, "modules\\"), "NadekoBot.Modules.*", SearchOption.AllDirectories)
|
||||||
|
.SelectMany(x => Directory.GetFiles(x, "NadekoBot.Modules.*.dll"))
|
||||||
|
.Select(x => Path.GetFileNameWithoutExtension(x))
|
||||||
|
.Select(x =>
|
||||||
|
{
|
||||||
|
var m = Regex.Match(x, @"NadekoBot\.Modules\.(?<name>.*)");
|
||||||
|
return m.Groups["name"].Value;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -2,9 +2,6 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netcoreapp2.0</TargetFramework>
|
<TargetFramework>netcoreapp2.0</TargetFramework>
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
|
||||||
<LangVersion>latest</LangVersion>
|
<LangVersion>latest</LangVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
namespace NadekoBot.Services
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace NadekoBot.Services
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// All services must implement this interface in order to be auto-discovered by the DI system
|
/// All services must implement this interface in order to be auto-discovered by the DI system
|
||||||
@ -7,4 +9,12 @@
|
|||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// All services which require cleanup after they are unloaded must implement this interface
|
||||||
|
/// </summary>
|
||||||
|
public interface IUnloadableService
|
||||||
|
{
|
||||||
|
Task Unload();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -61,17 +61,6 @@ namespace NadekoBot
|
|||||||
if (shardId < 0)
|
if (shardId < 0)
|
||||||
throw new ArgumentOutOfRangeException(nameof(shardId));
|
throw new ArgumentOutOfRangeException(nameof(shardId));
|
||||||
|
|
||||||
//var obj = JsonConvert.DeserializeObject<Dictionary<string, CommandData2>>(File.ReadAllText("./data/command_strings.json"))
|
|
||||||
// .ToDictionary(x => x.Key, x => new CommandData2
|
|
||||||
// {
|
|
||||||
// Cmd = x.Value.Cmd,
|
|
||||||
// Desc = x.Value.Desc,
|
|
||||||
// Usage = x.Value.Usage.Select(y => y.Substring(1, y.Length - 2)).ToArray(),
|
|
||||||
// });
|
|
||||||
|
|
||||||
//File.WriteAllText("./data/command_strings.json", JsonConvert.SerializeObject(obj, Formatting.Indented));
|
|
||||||
|
|
||||||
|
|
||||||
LogSetup.SetupLogger();
|
LogSetup.SetupLogger();
|
||||||
_log = LogManager.GetCurrentClassLogger();
|
_log = LogManager.GetCurrentClassLogger();
|
||||||
TerribleElevatedPermissionCheck();
|
TerribleElevatedPermissionCheck();
|
||||||
@ -142,19 +131,17 @@ namespace NadekoBot
|
|||||||
//var localization = new Localization(_botConfig.Locale, AllGuildConfigs.ToDictionary(x => x.GuildId, x => x.Locale), Db);
|
//var localization = new Localization(_botConfig.Locale, AllGuildConfigs.ToDictionary(x => x.GuildId, x => x.Locale), Db);
|
||||||
|
|
||||||
//initialize Services
|
//initialize Services
|
||||||
Services = new NServiceProvider.ServiceProviderBuilder()
|
Services = new NServiceProvider()
|
||||||
.AddManual<IBotCredentials>(Credentials)
|
.AddManual<IBotCredentials>(Credentials)
|
||||||
.AddManual(_db)
|
.AddManual(_db)
|
||||||
.AddManual(Client)
|
.AddManual(Client)
|
||||||
.AddManual(CommandService)
|
.AddManual(CommandService)
|
||||||
.AddManual(botConfigProvider)
|
.AddManual(botConfigProvider)
|
||||||
//.AddManual<ILocalization>(localization)
|
|
||||||
.AddManual<IEnumerable<GuildConfig>>(AllGuildConfigs) //todo wrap this
|
.AddManual<IEnumerable<GuildConfig>>(AllGuildConfigs) //todo wrap this
|
||||||
.AddManual<NadekoBot>(this)
|
.AddManual<NadekoBot>(this)
|
||||||
.AddManual<IUnitOfWork>(uow)
|
.AddManual<IUnitOfWork>(uow)
|
||||||
.AddManual<IDataCache>(new RedisCache(Client.CurrentUser.Id))
|
.AddManual<IDataCache>(new RedisCache(Client.CurrentUser.Id));
|
||||||
.LoadFrom(Assembly.GetEntryAssembly())
|
Services.LoadFrom(Assembly.GetAssembly(typeof(CommandHandler)));
|
||||||
.Build();
|
|
||||||
|
|
||||||
var commandHandler = Services.GetService<CommandHandler>();
|
var commandHandler = Services.GetService<CommandHandler>();
|
||||||
commandHandler.AddServices(Services);
|
commandHandler.AddServices(Services);
|
||||||
@ -163,12 +150,13 @@ namespace NadekoBot
|
|||||||
CommandService.AddTypeReader<PermissionAction>(new PermissionActionTypeReader());
|
CommandService.AddTypeReader<PermissionAction>(new PermissionActionTypeReader());
|
||||||
CommandService.AddTypeReader<CommandInfo>(new CommandTypeReader());
|
CommandService.AddTypeReader<CommandInfo>(new CommandTypeReader());
|
||||||
//todo module dependency
|
//todo module dependency
|
||||||
//CommandService.AddTypeReader<CommandOrCrInfo>(new CommandOrCrTypeReader());
|
CommandService.AddTypeReader<CommandOrCrInfo>(new CommandOrCrTypeReader());
|
||||||
CommandService.AddTypeReader<ModuleInfo>(new ModuleTypeReader(CommandService));
|
CommandService.AddTypeReader<ModuleInfo>(new ModuleTypeReader(CommandService));
|
||||||
CommandService.AddTypeReader<ModuleOrCrInfo>(new ModuleOrCrTypeReader(CommandService));
|
CommandService.AddTypeReader<ModuleOrCrInfo>(new ModuleOrCrTypeReader(CommandService));
|
||||||
CommandService.AddTypeReader<IGuild>(new GuildTypeReader(Client));
|
CommandService.AddTypeReader<IGuild>(new GuildTypeReader(Client));
|
||||||
//CommandService.AddTypeReader<GuildDateTime>(new GuildDateTimeTypeReader());
|
//CommandService.AddTypeReader<GuildDateTime>(new GuildDateTimeTypeReader());
|
||||||
}
|
}
|
||||||
|
Services.Unload(typeof(IUnitOfWork)); // unload it after the startup
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task LoginAsync(string token)
|
private async Task LoginAsync(string token)
|
||||||
@ -372,5 +360,80 @@ namespace NadekoBot
|
|||||||
var sub = Services.GetService<IDataCache>().Redis.GetSubscriber();
|
var sub = Services.GetService<IDataCache>().Redis.GetSubscriber();
|
||||||
return sub.PublishAsync(Client.CurrentUser.Id + "_status.game_set", JsonConvert.SerializeObject(obj));
|
return sub.PublishAsync(Client.CurrentUser.Id + "_status.game_set", JsonConvert.SerializeObject(obj));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private readonly Dictionary<string, IEnumerable<ModuleInfo>> _packageModules = new Dictionary<string, IEnumerable<ModuleInfo>>();
|
||||||
|
private readonly Dictionary<string, IEnumerable<Type>> _packageTypes = new Dictionary<string, IEnumerable<Type>>();
|
||||||
|
private readonly SemaphoreSlim _packageLocker = new SemaphoreSlim(1, 1);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Unloads a package
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">Package name. Case sensitive.</param>
|
||||||
|
/// <returns>Whether the unload is successful.</returns>
|
||||||
|
public async Task<bool> UnloadPackage(string name)
|
||||||
|
{
|
||||||
|
await _packageLocker.WaitAsync().ConfigureAwait(false);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!_packageModules.TryGetValue(name, out var modules))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var i = 0;
|
||||||
|
foreach (var m in modules)
|
||||||
|
{
|
||||||
|
await CommandService.RemoveModuleAsync(m).ConfigureAwait(false);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
_log.Info("Unloaded {0} modules.", i);
|
||||||
|
|
||||||
|
if (_packageTypes.TryGetValue(name, out var types))
|
||||||
|
{
|
||||||
|
i = 0;
|
||||||
|
foreach (var t in types)
|
||||||
|
{
|
||||||
|
var obj = Services.Unload(t);
|
||||||
|
if (obj is IUnloadableService s)
|
||||||
|
await s.Unload().ConfigureAwait(false);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
_log.Info("Unloaded {0} types.", i);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_packageLocker.Release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Loads a package
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">Name of the package to load. Case sensitive.</param>
|
||||||
|
/// <returns>Whether the load is successful.</returns>
|
||||||
|
public async Task<bool> LoadPackage(string name)
|
||||||
|
{
|
||||||
|
await _packageLocker.WaitAsync().ConfigureAwait(false);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (_packageModules.ContainsKey(name))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var package = Assembly.LoadFile(Path.Combine(AppContext.BaseDirectory,
|
||||||
|
"modules",
|
||||||
|
$"NadekoBot.Modules.{name}",
|
||||||
|
$"NadekoBot.Modules.{name}.dll"));
|
||||||
|
var types = Services.LoadFrom(package);
|
||||||
|
var added = await CommandService.AddModulesAsync(package).ConfigureAwait(false);
|
||||||
|
_log.Info("Loaded {0} modules and {1} types.", added.Count(), types.Count());
|
||||||
|
_packageModules.Add(name, added);
|
||||||
|
_packageTypes.Add(name, types);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_packageLocker.Release();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Concurrent;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
@ -17,57 +16,83 @@ namespace NadekoBot.Services
|
|||||||
public interface INServiceProvider : IServiceProvider, IEnumerable<object>
|
public interface INServiceProvider : IServiceProvider, IEnumerable<object>
|
||||||
{
|
{
|
||||||
T GetService<T>();
|
T GetService<T>();
|
||||||
|
IEnumerable<Type> LoadFrom(Assembly assembly);
|
||||||
|
INServiceProvider AddManual<T>(T obj);
|
||||||
|
object Unload(Type t);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class NServiceProvider : INServiceProvider
|
public class NServiceProvider : INServiceProvider
|
||||||
{
|
{
|
||||||
public class ServiceProviderBuilder
|
private readonly object _locker = new object();
|
||||||
{
|
|
||||||
private ConcurrentDictionary<Type, object> _dict = new ConcurrentDictionary<Type, object>();
|
|
||||||
private readonly Logger _log;
|
private readonly Logger _log;
|
||||||
|
|
||||||
public ServiceProviderBuilder()
|
public readonly Dictionary<Type, object> _services = new Dictionary<Type, object>();
|
||||||
|
public IReadOnlyDictionary<Type, object> Services => _services;
|
||||||
|
|
||||||
|
public NServiceProvider()
|
||||||
{
|
{
|
||||||
_log = LogManager.GetCurrentClassLogger();
|
_log = LogManager.GetCurrentClassLogger();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ServiceProviderBuilder AddManual<T>(T obj)
|
public T GetService<T>()
|
||||||
{
|
{
|
||||||
_dict.TryAdd(typeof(T), obj);
|
return (T)((IServiceProvider)(this)).GetService(typeof(T));
|
||||||
|
}
|
||||||
|
|
||||||
|
object IServiceProvider.GetService(Type serviceType)
|
||||||
|
{
|
||||||
|
_services.TryGetValue(serviceType, out var toReturn);
|
||||||
|
return toReturn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public INServiceProvider AddManual<T>(T obj)
|
||||||
|
{
|
||||||
|
lock (_locker)
|
||||||
|
{
|
||||||
|
_services.TryAdd(typeof(T), obj);
|
||||||
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public NServiceProvider Build()
|
public IEnumerable<Type> LoadFrom(Assembly assembly)
|
||||||
{
|
{
|
||||||
return new NServiceProvider(_dict);
|
List<Type> addedTypes = new List<Type>();
|
||||||
}
|
|
||||||
|
|
||||||
public ServiceProviderBuilder LoadFrom(Assembly assembly)
|
Type[] allTypes;
|
||||||
|
try
|
||||||
{
|
{
|
||||||
var allTypes = assembly.GetTypes();
|
allTypes = assembly.GetTypes();
|
||||||
|
}
|
||||||
|
catch (ReflectionTypeLoadException ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine(ex.LoaderExceptions[0]);
|
||||||
|
return Enumerable.Empty<Type>();
|
||||||
|
}
|
||||||
var services = new Queue<Type>(allTypes
|
var services = new Queue<Type>(allTypes
|
||||||
.Where(x => x.GetInterfaces().Contains(typeof(INService))
|
.Where(x => x.GetInterfaces().Contains(typeof(INService))
|
||||||
&& !x.GetTypeInfo().IsInterface && !x.GetTypeInfo().IsAbstract
|
&& !x.GetTypeInfo().IsInterface && !x.GetTypeInfo().IsAbstract
|
||||||
|
|
||||||
#if GLOBAL_NADEKO
|
#if GLOBAL_NADEKO
|
||||||
&& x.GetTypeInfo().GetCustomAttribute<NoPublicBot>() == null
|
&& x.GetTypeInfo().GetCustomAttribute<NoPublicBot>() == null
|
||||||
#endif
|
#endif
|
||||||
)
|
)
|
||||||
.ToArray());
|
.ToArray());
|
||||||
|
|
||||||
|
addedTypes.AddRange(services);
|
||||||
|
|
||||||
var interfaces = new HashSet<Type>(allTypes
|
var interfaces = new HashSet<Type>(allTypes
|
||||||
.Where(x => x.GetInterfaces().Contains(typeof(INService))
|
.Where(x => x.GetInterfaces().Contains(typeof(INService))
|
||||||
&& x.GetTypeInfo().IsInterface));
|
&& x.GetTypeInfo().IsInterface));
|
||||||
|
|
||||||
var alreadyFailed = new Dictionary<Type, int>();
|
var alreadyFailed = new Dictionary<Type, int>();
|
||||||
|
lock (_locker)
|
||||||
|
{
|
||||||
var sw = Stopwatch.StartNew();
|
var sw = Stopwatch.StartNew();
|
||||||
var swInstance = new Stopwatch();
|
var swInstance = new Stopwatch();
|
||||||
while (services.Count > 0)
|
while (services.Count > 0)
|
||||||
{
|
{
|
||||||
var type = services.Dequeue(); //get a type i need to make an instance of
|
var type = services.Dequeue(); //get a type i need to make an instance of
|
||||||
|
|
||||||
if (_dict.TryGetValue(type, out _)) // if that type is already instantiated, skip
|
if (_services.TryGetValue(type, out _)) // if that type is already instantiated, skip
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var ctor = type.GetConstructors()[0];
|
var ctor = type.GetConstructors()[0];
|
||||||
@ -79,7 +104,7 @@ namespace NadekoBot.Services
|
|||||||
var args = new List<object>(argTypes.Length);
|
var args = new List<object>(argTypes.Length);
|
||||||
foreach (var arg in argTypes) //get constructor arguments from the dictionary of already instantiated types
|
foreach (var arg in argTypes) //get constructor arguments from the dictionary of already instantiated types
|
||||||
{
|
{
|
||||||
if (_dict.TryGetValue(arg, out var argObj)) //if i got current one, add it to the list of instances and move on
|
if (_services.TryGetValue(arg, out var argObj)) //if i got current one, add it to the list of instances and move on
|
||||||
args.Add(argObj);
|
args.Add(argObj);
|
||||||
else //if i failed getting it, add it to the end, and break
|
else //if i failed getting it, add it to the end, and break
|
||||||
{
|
{
|
||||||
@ -97,7 +122,7 @@ namespace NadekoBot.Services
|
|||||||
}
|
}
|
||||||
if (args.Count != argTypes.Length)
|
if (args.Count != argTypes.Length)
|
||||||
continue;
|
continue;
|
||||||
// _log.Info("Loading " + type.Name);
|
|
||||||
swInstance.Restart();
|
swInstance.Restart();
|
||||||
var instance = ctor.Invoke(args.ToArray());
|
var instance = ctor.Invoke(args.ToArray());
|
||||||
swInstance.Stop();
|
swInstance.Stop();
|
||||||
@ -105,34 +130,30 @@ namespace NadekoBot.Services
|
|||||||
_log.Info($"{type.Name} took {swInstance.Elapsed.TotalSeconds:F2}s to load.");
|
_log.Info($"{type.Name} took {swInstance.Elapsed.TotalSeconds:F2}s to load.");
|
||||||
var interfaceType = interfaces.FirstOrDefault(x => instance.GetType().GetInterfaces().Contains(x));
|
var interfaceType = interfaces.FirstOrDefault(x => instance.GetType().GetInterfaces().Contains(x));
|
||||||
if (interfaceType != null)
|
if (interfaceType != null)
|
||||||
_dict.TryAdd(interfaceType, instance);
|
{
|
||||||
|
addedTypes.Add(interfaceType);
|
||||||
|
_services.TryAdd(interfaceType, instance);
|
||||||
|
}
|
||||||
|
|
||||||
_dict.TryAdd(type, instance);
|
_services.TryAdd(type, instance);
|
||||||
}
|
}
|
||||||
sw.Stop();
|
sw.Stop();
|
||||||
_log.Info($"All services loaded in {sw.Elapsed.TotalSeconds:F2}s");
|
_log.Info($"All services loaded in {sw.Elapsed.TotalSeconds:F2}s");
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
return addedTypes;
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly ImmutableDictionary<Type, object> _services;
|
public object Unload(Type t)
|
||||||
|
|
||||||
private NServiceProvider() { }
|
|
||||||
public NServiceProvider(IDictionary<Type, object> services)
|
|
||||||
{
|
{
|
||||||
this._services = services.ToImmutableDictionary();
|
lock (_locker)
|
||||||
}
|
|
||||||
|
|
||||||
public T GetService<T>()
|
|
||||||
{
|
{
|
||||||
return (T)((IServiceProvider)(this)).GetService(typeof(T));
|
if (_services.TryGetValue(t, out var obj))
|
||||||
}
|
|
||||||
|
|
||||||
object IServiceProvider.GetService(Type serviceType)
|
|
||||||
{
|
{
|
||||||
_services.TryGetValue(serviceType, out var toReturn);
|
_services.Remove(t);
|
||||||
return toReturn;
|
return obj;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator() => _services.Values.GetEnumerator();
|
IEnumerator IEnumerable.GetEnumerator() => _services.Values.GetEnumerator();
|
||||||
|
@ -2,6 +2,13 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netcoreapp2.0</TargetFramework>
|
<TargetFramework>netcoreapp2.0</TargetFramework>
|
||||||
|
<LangVersion>latest</LangVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputPath>..\src\NadekoBot\bin\$(Configuration)\netcoreapp2.0\modules\$(AssemblyName)\</OutputPath>
|
||||||
|
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||||
|
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -2,6 +2,13 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netcoreapp2.0</TargetFramework>
|
<TargetFramework>netcoreapp2.0</TargetFramework>
|
||||||
|
<LangVersion>latest</LangVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputPath>..\src\NadekoBot\bin\$(Configuration)\netcoreapp2.0\modules\$(AssemblyName)\</OutputPath>
|
||||||
|
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||||
|
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -4,27 +4,24 @@ using Discord.WebSocket;
|
|||||||
using NadekoBot.Extensions;
|
using NadekoBot.Extensions;
|
||||||
using NadekoBot.Services;
|
using NadekoBot.Services;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using NadekoBot.Common.Attributes;
|
using NadekoBot.Common.Attributes;
|
||||||
using NadekoBot.Modules.Gambling.Common.AnimalRacing.Exceptions;
|
using NadekoBot.Modules.Gambling.Common.AnimalRacing.Exceptions;
|
||||||
using NadekoBot.Modules.Gambling.Common.AnimalRacing;
|
using NadekoBot.Modules.Gambling.Common.AnimalRacing;
|
||||||
|
using NadekoBot.Modules.Gambling.Services;
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Gambling
|
namespace NadekoBot.Modules.Gambling
|
||||||
{
|
{
|
||||||
public partial class Gambling
|
public partial class Gambling
|
||||||
{
|
{
|
||||||
[Group]
|
[Group]
|
||||||
public class AnimalRacingCommands : NadekoSubmodule
|
public class AnimalRacingCommands : NadekoSubmodule<AnimalRaceService>
|
||||||
{
|
{
|
||||||
private readonly IBotConfigProvider _bc;
|
private readonly IBotConfigProvider _bc;
|
||||||
private readonly CurrencyService _cs;
|
private readonly CurrencyService _cs;
|
||||||
private readonly DiscordSocketClient _client;
|
private readonly DiscordSocketClient _client;
|
||||||
|
|
||||||
|
|
||||||
public static ConcurrentDictionary<ulong, AnimalRace> AnimalRaces { get; } = new ConcurrentDictionary<ulong, AnimalRace>();
|
|
||||||
|
|
||||||
public AnimalRacingCommands(IBotConfigProvider bc, CurrencyService cs, DiscordSocketClient client)
|
public AnimalRacingCommands(IBotConfigProvider bc, CurrencyService cs, DiscordSocketClient client)
|
||||||
{
|
{
|
||||||
_bc = bc;
|
_bc = bc;
|
||||||
@ -39,7 +36,7 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
public Task Race()
|
public Task Race()
|
||||||
{
|
{
|
||||||
var ar = new AnimalRace(_cs, _bc.BotConfig.RaceAnimals.Shuffle().ToArray());
|
var ar = new AnimalRace(_cs, _bc.BotConfig.RaceAnimals.Shuffle().ToArray());
|
||||||
if (!AnimalRaces.TryAdd(Context.Guild.Id, ar))
|
if (!_service.AnimalRaces.TryAdd(Context.Guild.Id, ar))
|
||||||
return Context.Channel.SendErrorAsync(GetText("animal_race"), GetText("animal_race_already_started"));
|
return Context.Channel.SendErrorAsync(GetText("animal_race"), GetText("animal_race_already_started"));
|
||||||
|
|
||||||
ar.Initialize();
|
ar.Initialize();
|
||||||
@ -66,7 +63,7 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
Task Ar_OnEnded(AnimalRace race)
|
Task Ar_OnEnded(AnimalRace race)
|
||||||
{
|
{
|
||||||
_client.MessageReceived -= _client_MessageReceived;
|
_client.MessageReceived -= _client_MessageReceived;
|
||||||
AnimalRaces.TryRemove(Context.Guild.Id, out _);
|
_service.AnimalRaces.TryRemove(Context.Guild.Id, out _);
|
||||||
var winner = race.FinishedUsers[0];
|
var winner = race.FinishedUsers[0];
|
||||||
if (race.FinishedUsers[0].Bet > 0)
|
if (race.FinishedUsers[0].Bet > 0)
|
||||||
{
|
{
|
||||||
@ -126,7 +123,7 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
|
|
||||||
private Task Ar_OnStartingFailed(AnimalRace race)
|
private Task Ar_OnStartingFailed(AnimalRace race)
|
||||||
{
|
{
|
||||||
AnimalRaces.TryRemove(Context.Guild.Id, out _);
|
_service.AnimalRaces.TryRemove(Context.Guild.Id, out _);
|
||||||
return ReplyErrorLocalized("animal_race_failed");
|
return ReplyErrorLocalized("animal_race_failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,7 +131,7 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
public async Task JoinRace(int amount = 0)
|
public async Task JoinRace(int amount = 0)
|
||||||
{
|
{
|
||||||
if (!AnimalRaces.TryGetValue(Context.Guild.Id, out var ar))
|
if (!_service.AnimalRaces.TryGetValue(Context.Guild.Id, out var ar))
|
||||||
{
|
{
|
||||||
await ReplyErrorLocalized("race_not_exist").ConfigureAwait(false);
|
await ReplyErrorLocalized("race_not_exist").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
|
@ -17,6 +17,7 @@ using NadekoBot.Services.Database.Models;
|
|||||||
|
|
||||||
namespace NadekoBot.Modules.Gambling
|
namespace NadekoBot.Modules.Gambling
|
||||||
{
|
{
|
||||||
|
//todo mess, needs unload thing too - refactor
|
||||||
public partial class Gambling
|
public partial class Gambling
|
||||||
{
|
{
|
||||||
[Group]
|
[Group]
|
||||||
@ -274,7 +275,6 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
|
|
||||||
_log.Warn("Stopping flower reaction event because it expired.");
|
_log.Warn("Stopping flower reaction event because it expired.");
|
||||||
await End();
|
await End();
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,13 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netcoreapp2.0</TargetFramework>
|
<TargetFramework>netcoreapp2.0</TargetFramework>
|
||||||
|
<LangVersion>latest</LangVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputPath>..\src\NadekoBot\bin\$(Configuration)\netcoreapp2.0\modules\$(AssemblyName)\</OutputPath>
|
||||||
|
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||||
|
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
21
NadekoBot.Modules.Gambling/Services/AnimalRaceService.cs
Normal file
21
NadekoBot.Modules.Gambling/Services/AnimalRaceService.cs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
using System.Threading.Tasks;
|
||||||
|
using NadekoBot.Services;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using NadekoBot.Modules.Gambling.Common.AnimalRacing;
|
||||||
|
|
||||||
|
namespace NadekoBot.Modules.Gambling.Services
|
||||||
|
{
|
||||||
|
public class AnimalRaceService : INService, IUnloadableService
|
||||||
|
{
|
||||||
|
public ConcurrentDictionary<ulong, AnimalRace> AnimalRaces { get; } = new ConcurrentDictionary<ulong, AnimalRace>();
|
||||||
|
|
||||||
|
public Task Unload()
|
||||||
|
{
|
||||||
|
foreach (var kvp in AnimalRaces)
|
||||||
|
{
|
||||||
|
try { kvp.Value.Dispose(); } catch { }
|
||||||
|
}
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -176,7 +176,7 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
using (var file = _images.SlotEmojis[numbers[i]].ToStream())
|
using (var file = _images.SlotEmojis[numbers[i]].ToStream())
|
||||||
using (var randomImage = ImageSharp.Image.Load(file))
|
using (var randomImage = ImageSharp.Image.Load(file))
|
||||||
{
|
{
|
||||||
bgImage.DrawImage(randomImage, 100, default(Size), new Point(95 + 142 * i, 330));
|
bgImage.DrawImage(randomImage, 100, default, new Point(95 + 142 * i, 330));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -189,7 +189,7 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
using (var fs = _images.SlotNumbers[digit].ToStream())
|
using (var fs = _images.SlotNumbers[digit].ToStream())
|
||||||
using (var img = ImageSharp.Image.Load(fs))
|
using (var img = ImageSharp.Image.Load(fs))
|
||||||
{
|
{
|
||||||
bgImage.DrawImage(img, 100, default(Size), new Point(230 - n * 16, 462));
|
bgImage.DrawImage(img, 100, default, new Point(230 - n * 16, 462));
|
||||||
}
|
}
|
||||||
n++;
|
n++;
|
||||||
} while ((printWon /= 10) != 0);
|
} while ((printWon /= 10) != 0);
|
||||||
@ -202,7 +202,7 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
using (var fs = _images.SlotNumbers[digit].ToStream())
|
using (var fs = _images.SlotNumbers[digit].ToStream())
|
||||||
using (var img = ImageSharp.Image.Load(fs))
|
using (var img = ImageSharp.Image.Load(fs))
|
||||||
{
|
{
|
||||||
bgImage.DrawImage(img, 100, default(Size), new Point(395 - n * 16, 462));
|
bgImage.DrawImage(img, 100, default, new Point(395 - n * 16, 462));
|
||||||
}
|
}
|
||||||
n++;
|
n++;
|
||||||
} while ((printAmount /= 10) != 0);
|
} while ((printAmount /= 10) != 0);
|
||||||
|
@ -44,7 +44,7 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
Depraved,
|
Depraved,
|
||||||
Harlot
|
Harlot
|
||||||
}
|
}
|
||||||
|
//todo unclaimed waifus should lose 5% of their value a day
|
||||||
[Group]
|
[Group]
|
||||||
public class WaifuClaimCommands : NadekoSubmodule
|
public class WaifuClaimCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
|
@ -2,26 +2,23 @@
|
|||||||
using Discord.Commands;
|
using Discord.Commands;
|
||||||
using Discord.WebSocket;
|
using Discord.WebSocket;
|
||||||
using NadekoBot.Extensions;
|
using NadekoBot.Extensions;
|
||||||
using System.Collections.Concurrent;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using NadekoBot.Common.Attributes;
|
using NadekoBot.Common.Attributes;
|
||||||
using NadekoBot.Modules.Games.Common.Acrophobia;
|
using NadekoBot.Modules.Games.Common.Acrophobia;
|
||||||
|
using NadekoBot.Modules.Games.Services;
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Games
|
namespace NadekoBot.Modules.Games
|
||||||
{
|
{
|
||||||
public partial class Games
|
public partial class Games
|
||||||
{
|
{
|
||||||
[Group]
|
[Group]
|
||||||
public class AcropobiaCommands : NadekoSubmodule
|
public class AcropobiaCommands : NadekoSubmodule<GamesService>
|
||||||
{
|
{
|
||||||
private readonly DiscordSocketClient _client;
|
private readonly DiscordSocketClient _client;
|
||||||
|
|
||||||
//channelId, game
|
|
||||||
public static ConcurrentDictionary<ulong, Acrophobia> AcrophobiaGames { get; } = new ConcurrentDictionary<ulong, Acrophobia>();
|
|
||||||
|
|
||||||
public AcropobiaCommands(DiscordSocketClient client)
|
public AcropobiaCommands(DiscordSocketClient client)
|
||||||
{
|
{
|
||||||
_client = client;
|
_client = client;
|
||||||
@ -36,7 +33,7 @@ namespace NadekoBot.Modules.Games
|
|||||||
var channel = (ITextChannel)Context.Channel;
|
var channel = (ITextChannel)Context.Channel;
|
||||||
|
|
||||||
var game = new Acrophobia(submissionTime);
|
var game = new Acrophobia(submissionTime);
|
||||||
if (AcrophobiaGames.TryAdd(channel.Id, game))
|
if (_service.AcrophobiaGames.TryAdd(channel.Id, game))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -50,7 +47,7 @@ namespace NadekoBot.Modules.Games
|
|||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
_client.MessageReceived -= _client_MessageReceived;
|
_client.MessageReceived -= _client_MessageReceived;
|
||||||
AcrophobiaGames.TryRemove(channel.Id, out game);
|
_service.AcrophobiaGames.TryRemove(channel.Id, out game);
|
||||||
game.Dispose();
|
game.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
277
NadekoBot.Modules.Games/Common/TicTacToe.cs
Normal file
277
NadekoBot.Modules.Games/Common/TicTacToe.cs
Normal file
@ -0,0 +1,277 @@
|
|||||||
|
using Discord;
|
||||||
|
using Discord.WebSocket;
|
||||||
|
using NadekoBot.Extensions;
|
||||||
|
using NadekoBot.Services.Impl;
|
||||||
|
using System;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace NadekoBot.Modules.Games.Common
|
||||||
|
{
|
||||||
|
public class TicTacToe
|
||||||
|
{
|
||||||
|
enum Phase
|
||||||
|
{
|
||||||
|
Starting,
|
||||||
|
Started,
|
||||||
|
Ended
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly ITextChannel _channel;
|
||||||
|
private readonly IGuildUser[] _users;
|
||||||
|
private readonly int?[,] _state;
|
||||||
|
private Phase _phase;
|
||||||
|
private int _curUserIndex;
|
||||||
|
private readonly SemaphoreSlim _moveLock;
|
||||||
|
|
||||||
|
private IGuildUser _winner;
|
||||||
|
|
||||||
|
private readonly string[] _numbers = { ":one:", ":two:", ":three:", ":four:", ":five:", ":six:", ":seven:", ":eight:", ":nine:" };
|
||||||
|
|
||||||
|
public Action<TicTacToe> OnEnded;
|
||||||
|
|
||||||
|
private IUserMessage _previousMessage;
|
||||||
|
private Timer _timeoutTimer;
|
||||||
|
private readonly NadekoStrings _strings;
|
||||||
|
private readonly DiscordSocketClient _client;
|
||||||
|
|
||||||
|
public TicTacToe(NadekoStrings strings, DiscordSocketClient client, ITextChannel channel, IGuildUser firstUser)
|
||||||
|
{
|
||||||
|
_channel = channel;
|
||||||
|
_strings = strings;
|
||||||
|
_client = client;
|
||||||
|
|
||||||
|
_users = new[] { firstUser, null };
|
||||||
|
_state = new int?[,] {
|
||||||
|
{ null, null, null },
|
||||||
|
{ null, null, null },
|
||||||
|
{ null, null, null },
|
||||||
|
};
|
||||||
|
|
||||||
|
_phase = Phase.Starting;
|
||||||
|
_moveLock = new SemaphoreSlim(1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetText(string key, params object[] replacements) =>
|
||||||
|
_strings.GetText(key,
|
||||||
|
_channel.GuildId,
|
||||||
|
typeof(Games).Name.ToLowerInvariant(),
|
||||||
|
replacements);
|
||||||
|
|
||||||
|
public string GetState()
|
||||||
|
{
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
for (var i = 0; i < _state.GetLength(0); i++)
|
||||||
|
{
|
||||||
|
for (var j = 0; j < _state.GetLength(1); j++)
|
||||||
|
{
|
||||||
|
sb.Append(_state[i, j] == null ? _numbers[i * 3 + j] : GetIcon(_state[i, j]));
|
||||||
|
if (j < _state.GetLength(1) - 1)
|
||||||
|
sb.Append("┃");
|
||||||
|
}
|
||||||
|
if (i < _state.GetLength(0) - 1)
|
||||||
|
sb.AppendLine("\n──────────");
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public EmbedBuilder GetEmbed(string title = null)
|
||||||
|
{
|
||||||
|
var embed = new EmbedBuilder()
|
||||||
|
.WithOkColor()
|
||||||
|
.WithDescription(Environment.NewLine + GetState())
|
||||||
|
.WithAuthor(eab => eab.WithName(GetText("vs", _users[0], _users[1])));
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(title))
|
||||||
|
embed.WithTitle(title);
|
||||||
|
|
||||||
|
if (_winner == null)
|
||||||
|
{
|
||||||
|
if (_phase == Phase.Ended)
|
||||||
|
embed.WithFooter(efb => efb.WithText(GetText("ttt_no_moves")));
|
||||||
|
else
|
||||||
|
embed.WithFooter(efb => efb.WithText(GetText("ttt_users_move", _users[_curUserIndex])));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
embed.WithFooter(efb => efb.WithText(GetText("ttt_has_won", _winner)));
|
||||||
|
|
||||||
|
return embed;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetIcon(int? val)
|
||||||
|
{
|
||||||
|
switch (val)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return "❌";
|
||||||
|
case 1:
|
||||||
|
return "⭕";
|
||||||
|
case 2:
|
||||||
|
return "❎";
|
||||||
|
case 3:
|
||||||
|
return "🅾";
|
||||||
|
default:
|
||||||
|
return "⬛";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Start(IGuildUser user)
|
||||||
|
{
|
||||||
|
if (_phase == Phase.Started || _phase == Phase.Ended)
|
||||||
|
{
|
||||||
|
await _channel.SendErrorAsync(user.Mention + GetText("ttt_already_running")).ConfigureAwait(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (_users[0] == user)
|
||||||
|
{
|
||||||
|
await _channel.SendErrorAsync(user.Mention + GetText("ttt_against_yourself")).ConfigureAwait(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_users[1] = user;
|
||||||
|
|
||||||
|
_phase = Phase.Started;
|
||||||
|
|
||||||
|
_timeoutTimer = new Timer(async (_) =>
|
||||||
|
{
|
||||||
|
await _moveLock.WaitAsync();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (_phase == Phase.Ended)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_phase = Phase.Ended;
|
||||||
|
if (_users[1] != null)
|
||||||
|
{
|
||||||
|
_winner = _users[_curUserIndex ^= 1];
|
||||||
|
var del = _previousMessage?.DeleteAsync();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await _channel.EmbedAsync(GetEmbed(GetText("ttt_time_expired"))).ConfigureAwait(false);
|
||||||
|
if (del != null)
|
||||||
|
await del.ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
}
|
||||||
|
|
||||||
|
OnEnded?.Invoke(this);
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_moveLock.Release();
|
||||||
|
}
|
||||||
|
}, null, 15000, Timeout.Infinite);
|
||||||
|
|
||||||
|
_client.MessageReceived += Client_MessageReceived;
|
||||||
|
|
||||||
|
|
||||||
|
_previousMessage = await _channel.EmbedAsync(GetEmbed(GetText("game_started"))).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsDraw()
|
||||||
|
{
|
||||||
|
for (var i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
for (var j = 0; j < 3; j++)
|
||||||
|
{
|
||||||
|
if (_state[i, j] == null)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task Client_MessageReceived(SocketMessage msg)
|
||||||
|
{
|
||||||
|
var _ = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
await _moveLock.WaitAsync().ConfigureAwait(false);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var curUser = _users[_curUserIndex];
|
||||||
|
if (_phase == Phase.Ended || msg.Author?.Id != curUser.Id)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (int.TryParse(msg.Content, out var index) &&
|
||||||
|
--index >= 0 &&
|
||||||
|
index <= 9 &&
|
||||||
|
_state[index / 3, index % 3] == null)
|
||||||
|
{
|
||||||
|
_state[index / 3, index % 3] = _curUserIndex;
|
||||||
|
|
||||||
|
// i'm lazy
|
||||||
|
if (_state[index / 3, 0] == _state[index / 3, 1] && _state[index / 3, 1] == _state[index / 3, 2])
|
||||||
|
{
|
||||||
|
_state[index / 3, 0] = _curUserIndex + 2;
|
||||||
|
_state[index / 3, 1] = _curUserIndex + 2;
|
||||||
|
_state[index / 3, 2] = _curUserIndex + 2;
|
||||||
|
|
||||||
|
_phase = Phase.Ended;
|
||||||
|
}
|
||||||
|
else if (_state[0, index % 3] == _state[1, index % 3] && _state[1, index % 3] == _state[2, index % 3])
|
||||||
|
{
|
||||||
|
_state[0, index % 3] = _curUserIndex + 2;
|
||||||
|
_state[1, index % 3] = _curUserIndex + 2;
|
||||||
|
_state[2, index % 3] = _curUserIndex + 2;
|
||||||
|
|
||||||
|
_phase = Phase.Ended;
|
||||||
|
}
|
||||||
|
else if (_curUserIndex == _state[0, 0] && _state[0, 0] == _state[1, 1] && _state[1, 1] == _state[2, 2])
|
||||||
|
{
|
||||||
|
_state[0, 0] = _curUserIndex + 2;
|
||||||
|
_state[1, 1] = _curUserIndex + 2;
|
||||||
|
_state[2, 2] = _curUserIndex + 2;
|
||||||
|
|
||||||
|
_phase = Phase.Ended;
|
||||||
|
}
|
||||||
|
else if (_curUserIndex == _state[0, 2] && _state[0, 2] == _state[1, 1] && _state[1, 1] == _state[2, 0])
|
||||||
|
{
|
||||||
|
_state[0, 2] = _curUserIndex + 2;
|
||||||
|
_state[1, 1] = _curUserIndex + 2;
|
||||||
|
_state[2, 0] = _curUserIndex + 2;
|
||||||
|
|
||||||
|
_phase = Phase.Ended;
|
||||||
|
}
|
||||||
|
var reason = "";
|
||||||
|
|
||||||
|
if (_phase == Phase.Ended) // if user won, stop receiving moves
|
||||||
|
{
|
||||||
|
reason = GetText("ttt_matched_three");
|
||||||
|
_winner = _users[_curUserIndex];
|
||||||
|
_client.MessageReceived -= Client_MessageReceived;
|
||||||
|
OnEnded?.Invoke(this);
|
||||||
|
}
|
||||||
|
else if (IsDraw())
|
||||||
|
{
|
||||||
|
reason = GetText("ttt_a_draw");
|
||||||
|
_phase = Phase.Ended;
|
||||||
|
_client.MessageReceived -= Client_MessageReceived;
|
||||||
|
OnEnded?.Invoke(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
var sendstate = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
var del1 = msg.DeleteAsync();
|
||||||
|
var del2 = _previousMessage?.DeleteAsync();
|
||||||
|
try { _previousMessage = await _channel.EmbedAsync(GetEmbed(reason)); } catch { }
|
||||||
|
try { await del1; } catch { }
|
||||||
|
try { if (del2 != null) await del2; } catch { }
|
||||||
|
});
|
||||||
|
_curUserIndex ^= 1;
|
||||||
|
|
||||||
|
_timeoutTimer.Change(15000, Timeout.Infinite);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_moveLock.Release();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -4,7 +4,7 @@ using Discord.WebSocket;
|
|||||||
using NadekoBot.Common.Attributes;
|
using NadekoBot.Common.Attributes;
|
||||||
using NadekoBot.Extensions;
|
using NadekoBot.Extensions;
|
||||||
using NadekoBot.Modules.Games.Common.Connect4;
|
using NadekoBot.Modules.Games.Common.Connect4;
|
||||||
using System.Collections.Concurrent;
|
using NadekoBot.Modules.Games.Services;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@ -13,12 +13,11 @@ namespace NadekoBot.Modules.Games
|
|||||||
{
|
{
|
||||||
public partial class Games
|
public partial class Games
|
||||||
{
|
{
|
||||||
public class Connect4Commands : NadekoSubmodule
|
[Group]
|
||||||
|
public class Connect4Commands : NadekoSubmodule<GamesService>
|
||||||
{
|
{
|
||||||
public static ConcurrentDictionary<ulong, Connect4Game> Games = new ConcurrentDictionary<ulong, Connect4Game>();
|
|
||||||
private readonly DiscordSocketClient _client;
|
private readonly DiscordSocketClient _client;
|
||||||
|
|
||||||
//private readonly string[] numbers = new string[] { "⓪", " ①", "②", "③", "④", "⑤", "⑥", "⑦", "⑧", "⑨" };
|
|
||||||
private readonly string[] numbers = new string[] { ":one:", ":two:", ":three:", ":four:", ":five:", ":six:", ":seven:", ":eight:"};
|
private readonly string[] numbers = new string[] { ":one:", ":two:", ":three:", ":four:", ":five:", ":six:", ":seven:", ":eight:"};
|
||||||
|
|
||||||
public Connect4Commands(DiscordSocketClient client)
|
public Connect4Commands(DiscordSocketClient client)
|
||||||
@ -32,7 +31,7 @@ namespace NadekoBot.Modules.Games
|
|||||||
{
|
{
|
||||||
var newGame = new Connect4Game(Context.User.Id, Context.User.ToString());
|
var newGame = new Connect4Game(Context.User.Id, Context.User.ToString());
|
||||||
Connect4Game game;
|
Connect4Game game;
|
||||||
if ((game = Games.GetOrAdd(Context.Channel.Id, newGame)) != newGame)
|
if ((game = _service.Connect4Games.GetOrAdd(Context.Channel.Id, newGame)) != newGame)
|
||||||
{
|
{
|
||||||
if (game.CurrentPhase != Connect4Game.Phase.Joining)
|
if (game.CurrentPhase != Connect4Game.Phase.Joining)
|
||||||
return;
|
return;
|
||||||
@ -84,7 +83,7 @@ namespace NadekoBot.Modules.Games
|
|||||||
|
|
||||||
Task Game_OnGameFailedToStart(Connect4Game arg)
|
Task Game_OnGameFailedToStart(Connect4Game arg)
|
||||||
{
|
{
|
||||||
if (Games.TryRemove(Context.Channel.Id, out var toDispose))
|
if (_service.Connect4Games.TryRemove(Context.Channel.Id, out var toDispose))
|
||||||
{
|
{
|
||||||
_client.MessageReceived -= _client_MessageReceived;
|
_client.MessageReceived -= _client_MessageReceived;
|
||||||
toDispose.Dispose();
|
toDispose.Dispose();
|
||||||
@ -94,7 +93,7 @@ namespace NadekoBot.Modules.Games
|
|||||||
|
|
||||||
Task Game_OnGameEnded(Connect4Game arg, Connect4Game.Result result)
|
Task Game_OnGameEnded(Connect4Game arg, Connect4Game.Result result)
|
||||||
{
|
{
|
||||||
if (Games.TryRemove(Context.Channel.Id, out var toDispose))
|
if (_service.Connect4Games.TryRemove(Context.Channel.Id, out var toDispose))
|
||||||
{
|
{
|
||||||
_client.MessageReceived -= _client_MessageReceived;
|
_client.MessageReceived -= _client_MessageReceived;
|
||||||
toDispose.Dispose();
|
toDispose.Dispose();
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
using Discord.Commands;
|
using Discord.Commands;
|
||||||
using NadekoBot.Extensions;
|
using NadekoBot.Extensions;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Discord;
|
using Discord;
|
||||||
using Discord.WebSocket;
|
using Discord.WebSocket;
|
||||||
using NadekoBot.Common.Attributes;
|
using NadekoBot.Common.Attributes;
|
||||||
using NadekoBot.Modules.Games.Common.Hangman;
|
using NadekoBot.Modules.Games.Common.Hangman;
|
||||||
|
using NadekoBot.Modules.Games.Services;
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Games
|
namespace NadekoBot.Modules.Games
|
||||||
{
|
{
|
||||||
public partial class Games
|
public partial class Games
|
||||||
{
|
{
|
||||||
[Group]
|
[Group]
|
||||||
public class HangmanCommands : NadekoSubmodule
|
public class HangmanCommands : NadekoSubmodule<GamesService>
|
||||||
{
|
{
|
||||||
private readonly DiscordSocketClient _client;
|
private readonly DiscordSocketClient _client;
|
||||||
|
|
||||||
@ -22,9 +22,6 @@ namespace NadekoBot.Modules.Games
|
|||||||
_client = client;
|
_client = client;
|
||||||
}
|
}
|
||||||
|
|
||||||
//channelId, game
|
|
||||||
public static ConcurrentDictionary<ulong, Hangman> HangmanGames { get; } = new ConcurrentDictionary<ulong, Hangman>();
|
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
public async Task Hangmanlist()
|
public async Task Hangmanlist()
|
||||||
@ -38,7 +35,7 @@ namespace NadekoBot.Modules.Games
|
|||||||
{
|
{
|
||||||
var hm = new Hangman(type);
|
var hm = new Hangman(type);
|
||||||
|
|
||||||
if (!HangmanGames.TryAdd(Context.Channel.Id, hm))
|
if (!_service.HangmanGames.TryAdd(Context.Channel.Id, hm))
|
||||||
{
|
{
|
||||||
hm.Dispose();
|
hm.Dispose();
|
||||||
await ReplyErrorLocalized("hangman_running").ConfigureAwait(false);
|
await ReplyErrorLocalized("hangman_running").ConfigureAwait(false);
|
||||||
@ -61,7 +58,7 @@ namespace NadekoBot.Modules.Games
|
|||||||
await hm.EndedTask.ConfigureAwait(false);
|
await hm.EndedTask.ConfigureAwait(false);
|
||||||
|
|
||||||
_client.MessageReceived -= _client_MessageReceived;
|
_client.MessageReceived -= _client_MessageReceived;
|
||||||
HangmanGames.TryRemove(Context.Channel.Id, out _);
|
_service.HangmanGames.TryRemove(Context.Channel.Id, out _);
|
||||||
hm.Dispose();
|
hm.Dispose();
|
||||||
|
|
||||||
Task _client_MessageReceived(SocketMessage msg)
|
Task _client_MessageReceived(SocketMessage msg)
|
||||||
@ -127,7 +124,7 @@ namespace NadekoBot.Modules.Games
|
|||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
public async Task HangmanStop()
|
public async Task HangmanStop()
|
||||||
{
|
{
|
||||||
if (HangmanGames.TryRemove(Context.Channel.Id, out var removed))
|
if (_service.HangmanGames.TryRemove(Context.Channel.Id, out var removed))
|
||||||
{
|
{
|
||||||
await removed.Stop().ConfigureAwait(false);
|
await removed.Stop().ConfigureAwait(false);
|
||||||
await ReplyConfirmLocalized("hangman_stopped").ConfigureAwait(false);
|
await ReplyConfirmLocalized("hangman_stopped").ConfigureAwait(false);
|
||||||
|
@ -2,6 +2,13 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netcoreapp2.0</TargetFramework>
|
<TargetFramework>netcoreapp2.0</TargetFramework>
|
||||||
|
<LangVersion>latest</LangVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputPath>..\src\NadekoBot\bin\$(Configuration)\netcoreapp2.0\modules\$(AssemblyName)\</OutputPath>
|
||||||
|
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||||
|
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -3,8 +3,8 @@ using Discord.Commands;
|
|||||||
using Discord.WebSocket;
|
using Discord.WebSocket;
|
||||||
using NadekoBot.Common.Attributes;
|
using NadekoBot.Common.Attributes;
|
||||||
using NadekoBot.Modules.Games.Common.Nunchi;
|
using NadekoBot.Modules.Games.Common.Nunchi;
|
||||||
|
using NadekoBot.Modules.Games.Services;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
@ -12,9 +12,9 @@ namespace NadekoBot.Modules.Games
|
|||||||
{
|
{
|
||||||
public partial class Games
|
public partial class Games
|
||||||
{
|
{
|
||||||
public class NunchiCommands : NadekoSubmodule
|
[Group]
|
||||||
|
public class NunchiCommands : NadekoSubmodule<GamesService>
|
||||||
{
|
{
|
||||||
public static readonly ConcurrentDictionary<ulong, Nunchi> Games = new ConcurrentDictionary<ulong, Common.Nunchi.Nunchi>();
|
|
||||||
private readonly DiscordSocketClient _client;
|
private readonly DiscordSocketClient _client;
|
||||||
|
|
||||||
public NunchiCommands(DiscordSocketClient client)
|
public NunchiCommands(DiscordSocketClient client)
|
||||||
@ -30,7 +30,7 @@ namespace NadekoBot.Modules.Games
|
|||||||
Nunchi nunchi;
|
Nunchi nunchi;
|
||||||
|
|
||||||
//if a game was already active
|
//if a game was already active
|
||||||
if ((nunchi = Games.GetOrAdd(Context.Guild.Id, newNunchi)) != newNunchi)
|
if ((nunchi = _service.NunchiGames.GetOrAdd(Context.Guild.Id, newNunchi)) != newNunchi)
|
||||||
{
|
{
|
||||||
// join it
|
// join it
|
||||||
if (!await nunchi.Join(Context.User.Id, Context.User.ToString()))
|
if (!await nunchi.Join(Context.User.Id, Context.User.ToString()))
|
||||||
@ -57,7 +57,7 @@ namespace NadekoBot.Modules.Games
|
|||||||
var success = await nunchi.Initialize().ConfigureAwait(false);
|
var success = await nunchi.Initialize().ConfigureAwait(false);
|
||||||
if (!success)
|
if (!success)
|
||||||
{
|
{
|
||||||
if (Games.TryRemove(Context.Guild.Id, out var game))
|
if (_service.NunchiGames.TryRemove(Context.Guild.Id, out var game))
|
||||||
game.Dispose();
|
game.Dispose();
|
||||||
await ConfirmLocalized("nunchi_failed_to_start").ConfigureAwait(false);
|
await ConfirmLocalized("nunchi_failed_to_start").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
@ -85,7 +85,7 @@ namespace NadekoBot.Modules.Games
|
|||||||
|
|
||||||
Task Nunchi_OnGameEnded(Nunchi arg1, string arg2)
|
Task Nunchi_OnGameEnded(Nunchi arg1, string arg2)
|
||||||
{
|
{
|
||||||
if (Games.TryRemove(Context.Guild.Id, out var game))
|
if (_service.NunchiGames.TryRemove(Context.Guild.Id, out var game))
|
||||||
{
|
{
|
||||||
_client.MessageReceived -= _client_MessageReceived;
|
_client.MessageReceived -= _client_MessageReceived;
|
||||||
game.Dispose();
|
game.Dispose();
|
||||||
|
@ -22,19 +22,17 @@ namespace NadekoBot.Modules.Games
|
|||||||
/// https://discord.gg/0TYNJfCU4De7YIk8
|
/// https://discord.gg/0TYNJfCU4De7YIk8
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Group]
|
[Group]
|
||||||
public class PlantPickCommands : NadekoSubmodule
|
public class PlantPickCommands : NadekoSubmodule<GamesService>
|
||||||
{
|
{
|
||||||
private readonly CurrencyService _cs;
|
private readonly CurrencyService _cs;
|
||||||
private readonly IBotConfigProvider _bc;
|
private readonly IBotConfigProvider _bc;
|
||||||
private readonly GamesService _games;
|
|
||||||
private readonly DbService _db;
|
private readonly DbService _db;
|
||||||
|
|
||||||
public PlantPickCommands(IBotConfigProvider bc, CurrencyService cs, GamesService games,
|
public PlantPickCommands(IBotConfigProvider bc, CurrencyService cs,
|
||||||
DbService db)
|
DbService db)
|
||||||
{
|
{
|
||||||
_bc = bc;
|
_bc = bc;
|
||||||
_cs = cs;
|
_cs = cs;
|
||||||
_games = games;
|
|
||||||
_db = db;
|
_db = db;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,7 +47,7 @@ namespace NadekoBot.Modules.Games
|
|||||||
|
|
||||||
|
|
||||||
try { await Context.Message.DeleteAsync().ConfigureAwait(false); } catch { }
|
try { await Context.Message.DeleteAsync().ConfigureAwait(false); } catch { }
|
||||||
if (!_games.PlantedFlowers.TryRemove(channel.Id, out List<IUserMessage> msgs))
|
if (!_service.PlantedFlowers.TryRemove(channel.Id, out List<IUserMessage> msgs))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
await Task.WhenAll(msgs.Where(m => m != null).Select(toDelete => toDelete.DeleteAsync())).ConfigureAwait(false);
|
await Task.WhenAll(msgs.Where(m => m != null).Select(toDelete => toDelete.DeleteAsync())).ConfigureAwait(false);
|
||||||
@ -74,7 +72,7 @@ namespace NadekoBot.Modules.Games
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var imgData = _games.GetRandomCurrencyImage();
|
var imgData = _service.GetRandomCurrencyImage();
|
||||||
|
|
||||||
var msgToSend = GetText("planted",
|
var msgToSend = GetText("planted",
|
||||||
Format.Bold(Context.User.ToString()),
|
Format.Bold(Context.User.ToString()),
|
||||||
@ -95,7 +93,7 @@ namespace NadekoBot.Modules.Games
|
|||||||
var msgs = new IUserMessage[amount];
|
var msgs = new IUserMessage[amount];
|
||||||
msgs[0] = msg;
|
msgs[0] = msg;
|
||||||
|
|
||||||
_games.PlantedFlowers.AddOrUpdate(Context.Channel.Id, msgs.ToList(), (id, old) =>
|
_service.PlantedFlowers.AddOrUpdate(Context.Channel.Id, msgs.ToList(), (id, old) =>
|
||||||
{
|
{
|
||||||
old.AddRange(msgs);
|
old.AddRange(msgs);
|
||||||
return old;
|
return old;
|
||||||
@ -121,13 +119,13 @@ namespace NadekoBot.Modules.Games
|
|||||||
if (!guildConfig.GenerateCurrencyChannelIds.Contains(toAdd))
|
if (!guildConfig.GenerateCurrencyChannelIds.Contains(toAdd))
|
||||||
{
|
{
|
||||||
guildConfig.GenerateCurrencyChannelIds.Add(toAdd);
|
guildConfig.GenerateCurrencyChannelIds.Add(toAdd);
|
||||||
_games.GenerationChannels.Add(channel.Id);
|
_service.GenerationChannels.Add(channel.Id);
|
||||||
enabled = true;
|
enabled = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
guildConfig.GenerateCurrencyChannelIds.Remove(toAdd);
|
guildConfig.GenerateCurrencyChannelIds.Remove(toAdd);
|
||||||
_games.GenerationChannels.TryRemove(channel.Id);
|
_service.GenerationChannels.TryRemove(channel.Id);
|
||||||
enabled = false;
|
enabled = false;
|
||||||
}
|
}
|
||||||
await uow.CompleteAsync();
|
await uow.CompleteAsync();
|
||||||
|
@ -17,10 +17,15 @@ using NadekoBot.Services.Database.Models;
|
|||||||
using NadekoBot.Services.Impl;
|
using NadekoBot.Services.Impl;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using NLog;
|
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
|
namespace NadekoBot.Modules.Games.Services
|
||||||
{
|
{
|
||||||
public class GamesService : INService
|
public class GamesService : INService, IUnloadableService
|
||||||
{
|
{
|
||||||
private readonly IBotConfigProvider _bc;
|
private readonly IBotConfigProvider _bc;
|
||||||
|
|
||||||
@ -38,6 +43,15 @@ namespace NadekoBot.Modules.Games.Services
|
|||||||
|
|
||||||
public List<TypingArticle> TypingArticles { get; } = new List<TypingArticle>();
|
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 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, IEnumerable<GuildConfig> gcs,
|
public GamesService(CommandHandler cmd, IBotConfigProvider bc, IEnumerable<GuildConfig> gcs,
|
||||||
NadekoStrings strings, IImagesService images, CommandHandler cmdHandler)
|
NadekoStrings strings, IImagesService images, CommandHandler cmdHandler)
|
||||||
{
|
{
|
||||||
@ -74,6 +88,34 @@ namespace NadekoBot.Modules.Games.Services
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
public void AddTypingArticle(IUser user, string text)
|
||||||
{
|
{
|
||||||
TypingArticles.Add(new TypingArticle
|
TypingArticles.Add(new TypingArticle
|
||||||
|
@ -3,7 +3,6 @@ using Discord.Commands;
|
|||||||
using Discord.WebSocket;
|
using Discord.WebSocket;
|
||||||
using NadekoBot.Extensions;
|
using NadekoBot.Extensions;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using System.Collections.Concurrent;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@ -16,9 +15,8 @@ namespace NadekoBot.Modules.Games
|
|||||||
public partial class Games
|
public partial class Games
|
||||||
{
|
{
|
||||||
[Group]
|
[Group]
|
||||||
public class SpeedTypingCommands : NadekoSubmodule
|
public class SpeedTypingCommands : NadekoSubmodule<GamesService>
|
||||||
{
|
{
|
||||||
public static ConcurrentDictionary<ulong, TypingGame> RunningContests = new ConcurrentDictionary<ulong, TypingGame>();
|
|
||||||
private readonly GamesService _games;
|
private readonly GamesService _games;
|
||||||
private readonly DiscordSocketClient _client;
|
private readonly DiscordSocketClient _client;
|
||||||
|
|
||||||
@ -34,7 +32,7 @@ namespace NadekoBot.Modules.Games
|
|||||||
{
|
{
|
||||||
var channel = (ITextChannel)Context.Channel;
|
var channel = (ITextChannel)Context.Channel;
|
||||||
|
|
||||||
var game = RunningContests.GetOrAdd(channel.Guild.Id, id => new TypingGame(_games, _client, channel, Prefix));
|
var game = _service.RunningContests.GetOrAdd(channel.Guild.Id, id => new TypingGame(_games, _client, channel, Prefix));
|
||||||
|
|
||||||
if (game.IsActive)
|
if (game.IsActive)
|
||||||
{
|
{
|
||||||
@ -54,8 +52,7 @@ namespace NadekoBot.Modules.Games
|
|||||||
public async Task TypeStop()
|
public async Task TypeStop()
|
||||||
{
|
{
|
||||||
var channel = (ITextChannel)Context.Channel;
|
var channel = (ITextChannel)Context.Channel;
|
||||||
TypingGame game;
|
if (_service.RunningContests.TryRemove(channel.Guild.Id, out TypingGame game))
|
||||||
if (RunningContests.TryRemove(channel.Guild.Id, out game))
|
|
||||||
{
|
{
|
||||||
await game.Stop().ConfigureAwait(false);
|
await game.Stop().ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
|
@ -3,23 +3,21 @@ using Discord.Commands;
|
|||||||
using Discord.WebSocket;
|
using Discord.WebSocket;
|
||||||
using NadekoBot.Extensions;
|
using NadekoBot.Extensions;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using NadekoBot.Common.Attributes;
|
using NadekoBot.Common.Attributes;
|
||||||
using NadekoBot.Services.Impl;
|
using NadekoBot.Services.Impl;
|
||||||
|
using NadekoBot.Modules.Games.Services;
|
||||||
|
using NadekoBot.Modules.Games.Common;
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Games
|
namespace NadekoBot.Modules.Games
|
||||||
{
|
{
|
||||||
public partial class Games
|
public partial class Games
|
||||||
{
|
{
|
||||||
[Group]
|
[Group]
|
||||||
public class TicTacToeCommands : NadekoSubmodule
|
public class TicTacToeCommands : NadekoSubmodule<GamesService>
|
||||||
{
|
{
|
||||||
//channelId/game
|
|
||||||
private static readonly Dictionary<ulong, TicTacToe> _games = new Dictionary<ulong, TicTacToe>();
|
|
||||||
|
|
||||||
private readonly SemaphoreSlim _sem = new SemaphoreSlim(1, 1);
|
private readonly SemaphoreSlim _sem = new SemaphoreSlim(1, 1);
|
||||||
private readonly DiscordSocketClient _client;
|
private readonly DiscordSocketClient _client;
|
||||||
|
|
||||||
@ -37,7 +35,7 @@ namespace NadekoBot.Modules.Games
|
|||||||
await _sem.WaitAsync(1000);
|
await _sem.WaitAsync(1000);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (_games.TryGetValue(channel.Id, out TicTacToe game))
|
if (_service.TicTacToeGames.TryGetValue(channel.Id, out TicTacToe game))
|
||||||
{
|
{
|
||||||
var _ = Task.Run(async () =>
|
var _ = Task.Run(async () =>
|
||||||
{
|
{
|
||||||
@ -45,13 +43,13 @@ namespace NadekoBot.Modules.Games
|
|||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
game = new TicTacToe(base._strings, (DiscordSocketClient)this._client, channel, (IGuildUser)Context.User);
|
game = new TicTacToe(base._strings, this._client, channel, (IGuildUser)Context.User);
|
||||||
_games.Add(channel.Id, game);
|
_service.TicTacToeGames.Add(channel.Id, game);
|
||||||
await ReplyConfirmLocalized("ttt_created").ConfigureAwait(false);
|
await ReplyConfirmLocalized("ttt_created").ConfigureAwait(false);
|
||||||
|
|
||||||
game.OnEnded += (g) =>
|
game.OnEnded += (g) =>
|
||||||
{
|
{
|
||||||
_games.Remove(channel.Id);
|
_service.TicTacToeGames.Remove(channel.Id);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
@ -60,271 +58,5 @@ namespace NadekoBot.Modules.Games
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class TicTacToe
|
|
||||||
{
|
|
||||||
enum Phase
|
|
||||||
{
|
|
||||||
Starting,
|
|
||||||
Started,
|
|
||||||
Ended
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly ITextChannel _channel;
|
|
||||||
private readonly IGuildUser[] _users;
|
|
||||||
private readonly int?[,] _state;
|
|
||||||
private Phase _phase;
|
|
||||||
private int _curUserIndex;
|
|
||||||
private readonly SemaphoreSlim _moveLock;
|
|
||||||
|
|
||||||
private IGuildUser _winner;
|
|
||||||
|
|
||||||
private readonly string[] _numbers = { ":one:", ":two:", ":three:", ":four:", ":five:", ":six:", ":seven:", ":eight:", ":nine:" };
|
|
||||||
|
|
||||||
public Action<TicTacToe> OnEnded;
|
|
||||||
|
|
||||||
private IUserMessage _previousMessage;
|
|
||||||
private Timer _timeoutTimer;
|
|
||||||
private readonly NadekoStrings _strings;
|
|
||||||
private readonly DiscordSocketClient _client;
|
|
||||||
|
|
||||||
public TicTacToe(NadekoStrings strings, DiscordSocketClient client, ITextChannel channel, IGuildUser firstUser)
|
|
||||||
{
|
|
||||||
_channel = channel;
|
|
||||||
_strings = strings;
|
|
||||||
_client = client;
|
|
||||||
|
|
||||||
_users = new[] { firstUser, null };
|
|
||||||
_state = new int?[,] {
|
|
||||||
{ null, null, null },
|
|
||||||
{ null, null, null },
|
|
||||||
{ null, null, null },
|
|
||||||
};
|
|
||||||
|
|
||||||
_phase = Phase.Starting;
|
|
||||||
_moveLock = new SemaphoreSlim(1, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GetText(string key, params object[] replacements) =>
|
|
||||||
_strings.GetText(key,
|
|
||||||
_channel.GuildId,
|
|
||||||
typeof(Games).Name.ToLowerInvariant(),
|
|
||||||
replacements);
|
|
||||||
|
|
||||||
public string GetState()
|
|
||||||
{
|
|
||||||
var sb = new StringBuilder();
|
|
||||||
for (var i = 0; i < _state.GetLength(0); i++)
|
|
||||||
{
|
|
||||||
for (var j = 0; j < _state.GetLength(1); j++)
|
|
||||||
{
|
|
||||||
sb.Append(_state[i, j] == null ? _numbers[i * 3 + j] : GetIcon(_state[i, j]));
|
|
||||||
if (j < _state.GetLength(1) - 1)
|
|
||||||
sb.Append("┃");
|
|
||||||
}
|
|
||||||
if (i < _state.GetLength(0) - 1)
|
|
||||||
sb.AppendLine("\n──────────");
|
|
||||||
}
|
|
||||||
|
|
||||||
return sb.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public EmbedBuilder GetEmbed(string title = null)
|
|
||||||
{
|
|
||||||
var embed = new EmbedBuilder()
|
|
||||||
.WithOkColor()
|
|
||||||
.WithDescription(Environment.NewLine + GetState())
|
|
||||||
.WithAuthor(eab => eab.WithName(GetText("vs", _users[0], _users[1])));
|
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(title))
|
|
||||||
embed.WithTitle(title);
|
|
||||||
|
|
||||||
if (_winner == null)
|
|
||||||
{
|
|
||||||
if (_phase == Phase.Ended)
|
|
||||||
embed.WithFooter(efb => efb.WithText(GetText("ttt_no_moves")));
|
|
||||||
else
|
|
||||||
embed.WithFooter(efb => efb.WithText(GetText("ttt_users_move", _users[_curUserIndex])));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
embed.WithFooter(efb => efb.WithText(GetText("ttt_has_won", _winner)));
|
|
||||||
|
|
||||||
return embed;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string GetIcon(int? val)
|
|
||||||
{
|
|
||||||
switch (val)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
return "❌";
|
|
||||||
case 1:
|
|
||||||
return "⭕";
|
|
||||||
case 2:
|
|
||||||
return "❎";
|
|
||||||
case 3:
|
|
||||||
return "🅾";
|
|
||||||
default:
|
|
||||||
return "⬛";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task Start(IGuildUser user)
|
|
||||||
{
|
|
||||||
if (_phase == Phase.Started || _phase == Phase.Ended)
|
|
||||||
{
|
|
||||||
await _channel.SendErrorAsync(user.Mention + GetText("ttt_already_running")).ConfigureAwait(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if (_users[0] == user)
|
|
||||||
{
|
|
||||||
await _channel.SendErrorAsync(user.Mention + GetText("ttt_against_yourself")).ConfigureAwait(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_users[1] = user;
|
|
||||||
|
|
||||||
_phase = Phase.Started;
|
|
||||||
|
|
||||||
_timeoutTimer = new Timer(async (_) =>
|
|
||||||
{
|
|
||||||
await _moveLock.WaitAsync();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (_phase == Phase.Ended)
|
|
||||||
return;
|
|
||||||
|
|
||||||
_phase = Phase.Ended;
|
|
||||||
if (_users[1] != null)
|
|
||||||
{
|
|
||||||
_winner = _users[_curUserIndex ^= 1];
|
|
||||||
var del = _previousMessage?.DeleteAsync();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await _channel.EmbedAsync(GetEmbed(GetText("ttt_time_expired"))).ConfigureAwait(false);
|
|
||||||
if (del != null)
|
|
||||||
await del.ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
catch { }
|
|
||||||
}
|
|
||||||
|
|
||||||
OnEnded?.Invoke(this);
|
|
||||||
}
|
|
||||||
catch { }
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
_moveLock.Release();
|
|
||||||
}
|
|
||||||
}, null, 15000, Timeout.Infinite);
|
|
||||||
|
|
||||||
_client.MessageReceived += Client_MessageReceived;
|
|
||||||
|
|
||||||
|
|
||||||
_previousMessage = await _channel.EmbedAsync(GetEmbed(GetText("game_started"))).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool IsDraw()
|
|
||||||
{
|
|
||||||
for (var i = 0; i < 3; i++)
|
|
||||||
{
|
|
||||||
for (var j = 0; j < 3; j++)
|
|
||||||
{
|
|
||||||
if (_state[i, j] == null)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Task Client_MessageReceived(SocketMessage msg)
|
|
||||||
{
|
|
||||||
var _ = Task.Run(async () =>
|
|
||||||
{
|
|
||||||
await _moveLock.WaitAsync().ConfigureAwait(false);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var curUser = _users[_curUserIndex];
|
|
||||||
if (_phase == Phase.Ended || msg.Author?.Id != curUser.Id)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (int.TryParse(msg.Content, out var index) &&
|
|
||||||
--index >= 0 &&
|
|
||||||
index <= 9 &&
|
|
||||||
_state[index / 3, index % 3] == null)
|
|
||||||
{
|
|
||||||
_state[index / 3, index % 3] = _curUserIndex;
|
|
||||||
|
|
||||||
// i'm lazy
|
|
||||||
if (_state[index / 3, 0] == _state[index / 3, 1] && _state[index / 3, 1] == _state[index / 3, 2])
|
|
||||||
{
|
|
||||||
_state[index / 3, 0] = _curUserIndex + 2;
|
|
||||||
_state[index / 3, 1] = _curUserIndex + 2;
|
|
||||||
_state[index / 3, 2] = _curUserIndex + 2;
|
|
||||||
|
|
||||||
_phase = Phase.Ended;
|
|
||||||
}
|
|
||||||
else if (_state[0, index % 3] == _state[1, index % 3] && _state[1, index % 3] == _state[2, index % 3])
|
|
||||||
{
|
|
||||||
_state[0, index % 3] = _curUserIndex + 2;
|
|
||||||
_state[1, index % 3] = _curUserIndex + 2;
|
|
||||||
_state[2, index % 3] = _curUserIndex + 2;
|
|
||||||
|
|
||||||
_phase = Phase.Ended;
|
|
||||||
}
|
|
||||||
else if (_curUserIndex == _state[0, 0] && _state[0, 0] == _state[1, 1] && _state[1, 1] == _state[2, 2])
|
|
||||||
{
|
|
||||||
_state[0, 0] = _curUserIndex + 2;
|
|
||||||
_state[1, 1] = _curUserIndex + 2;
|
|
||||||
_state[2, 2] = _curUserIndex + 2;
|
|
||||||
|
|
||||||
_phase = Phase.Ended;
|
|
||||||
}
|
|
||||||
else if (_curUserIndex == _state[0, 2] && _state[0, 2] == _state[1, 1] && _state[1, 1] == _state[2, 0])
|
|
||||||
{
|
|
||||||
_state[0, 2] = _curUserIndex + 2;
|
|
||||||
_state[1, 1] = _curUserIndex + 2;
|
|
||||||
_state[2, 0] = _curUserIndex + 2;
|
|
||||||
|
|
||||||
_phase = Phase.Ended;
|
|
||||||
}
|
|
||||||
var reason = "";
|
|
||||||
|
|
||||||
if (_phase == Phase.Ended) // if user won, stop receiving moves
|
|
||||||
{
|
|
||||||
reason = GetText("ttt_matched_three");
|
|
||||||
_winner = _users[_curUserIndex];
|
|
||||||
_client.MessageReceived -= Client_MessageReceived;
|
|
||||||
OnEnded?.Invoke(this);
|
|
||||||
}
|
|
||||||
else if (IsDraw())
|
|
||||||
{
|
|
||||||
reason = GetText("ttt_a_draw");
|
|
||||||
_phase = Phase.Ended;
|
|
||||||
_client.MessageReceived -= Client_MessageReceived;
|
|
||||||
OnEnded?.Invoke(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
var sendstate = Task.Run(async () =>
|
|
||||||
{
|
|
||||||
var del1 = msg.DeleteAsync();
|
|
||||||
var del2 = _previousMessage?.DeleteAsync();
|
|
||||||
try { _previousMessage = await _channel.EmbedAsync(GetEmbed(reason)); } catch { }
|
|
||||||
try { await del1; } catch { }
|
|
||||||
try { if (del2 != null) await del2; } catch { }
|
|
||||||
});
|
|
||||||
_curUserIndex ^= 1;
|
|
||||||
|
|
||||||
_timeoutTimer.Change(15000, Timeout.Infinite);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
_moveLock.Release();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -3,24 +3,23 @@ using Discord.Commands;
|
|||||||
using Discord.WebSocket;
|
using Discord.WebSocket;
|
||||||
using NadekoBot.Extensions;
|
using NadekoBot.Extensions;
|
||||||
using NadekoBot.Services;
|
using NadekoBot.Services;
|
||||||
using System.Collections.Concurrent;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using NadekoBot.Common.Attributes;
|
using NadekoBot.Common.Attributes;
|
||||||
using NadekoBot.Modules.Games.Common.Trivia;
|
using NadekoBot.Modules.Games.Common.Trivia;
|
||||||
|
using NadekoBot.Modules.Games.Services;
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Games
|
namespace NadekoBot.Modules.Games
|
||||||
{
|
{
|
||||||
public partial class Games
|
public partial class Games
|
||||||
{
|
{
|
||||||
|
//todo move games to service, unload
|
||||||
[Group]
|
[Group]
|
||||||
public class TriviaCommands : NadekoSubmodule
|
public class TriviaCommands : NadekoSubmodule<GamesService>
|
||||||
{
|
{
|
||||||
private readonly CurrencyService _cs;
|
private readonly CurrencyService _cs;
|
||||||
private readonly DiscordSocketClient _client;
|
private readonly DiscordSocketClient _client;
|
||||||
private readonly IBotConfigProvider _bc;
|
private readonly IBotConfigProvider _bc;
|
||||||
|
|
||||||
public static ConcurrentDictionary<ulong, TriviaGame> RunningTrivias { get; } = new ConcurrentDictionary<ulong, TriviaGame>();
|
|
||||||
|
|
||||||
public TriviaCommands(DiscordSocketClient client, IBotConfigProvider bc, CurrencyService cs)
|
public TriviaCommands(DiscordSocketClient client, IBotConfigProvider bc, CurrencyService cs)
|
||||||
{
|
{
|
||||||
_cs = cs;
|
_cs = cs;
|
||||||
@ -48,7 +47,7 @@ namespace NadekoBot.Modules.Games
|
|||||||
var isPokemon = additionalArgs.Contains("pokemon");
|
var isPokemon = additionalArgs.Contains("pokemon");
|
||||||
|
|
||||||
var trivia = new TriviaGame(_strings, _client, _bc, _cs, channel.Guild, channel, showHints, winReq, isPokemon);
|
var trivia = new TriviaGame(_strings, _client, _bc, _cs, channel.Guild, channel, showHints, winReq, isPokemon);
|
||||||
if (RunningTrivias.TryAdd(channel.Guild.Id, trivia))
|
if (_service.RunningTrivias.TryAdd(channel.Guild.Id, trivia))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -56,7 +55,7 @@ namespace NadekoBot.Modules.Games
|
|||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
RunningTrivias.TryRemove(channel.Guild.Id, out trivia);
|
_service.RunningTrivias.TryRemove(channel.Guild.Id, out trivia);
|
||||||
await trivia.EnsureStopped().ConfigureAwait(false);
|
await trivia.EnsureStopped().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@ -72,8 +71,7 @@ namespace NadekoBot.Modules.Games
|
|||||||
{
|
{
|
||||||
var channel = (ITextChannel)Context.Channel;
|
var channel = (ITextChannel)Context.Channel;
|
||||||
|
|
||||||
TriviaGame trivia;
|
if (_service.RunningTrivias.TryGetValue(channel.Guild.Id, out TriviaGame trivia))
|
||||||
if (RunningTrivias.TryGetValue(channel.Guild.Id, out trivia))
|
|
||||||
{
|
{
|
||||||
await channel.SendConfirmAsync(GetText("leaderboard"), trivia.GetLeaderboard()).ConfigureAwait(false);
|
await channel.SendConfirmAsync(GetText("leaderboard"), trivia.GetLeaderboard()).ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
@ -88,8 +86,7 @@ namespace NadekoBot.Modules.Games
|
|||||||
{
|
{
|
||||||
var channel = (ITextChannel)Context.Channel;
|
var channel = (ITextChannel)Context.Channel;
|
||||||
|
|
||||||
TriviaGame trivia;
|
if (_service.RunningTrivias.TryGetValue(channel.Guild.Id, out TriviaGame trivia))
|
||||||
if (RunningTrivias.TryGetValue(channel.Guild.Id, out trivia))
|
|
||||||
{
|
{
|
||||||
await trivia.StopGame().ConfigureAwait(false);
|
await trivia.StopGame().ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
|
@ -30,22 +30,15 @@ namespace NadekoBot.Modules.Music
|
|||||||
private readonly IGoogleApiService _google;
|
private readonly IGoogleApiService _google;
|
||||||
private readonly DbService _db;
|
private readonly DbService _db;
|
||||||
|
|
||||||
public Music(DiscordSocketClient client, IBotCredentials creds, IGoogleApiService google,
|
public Music(DiscordSocketClient client,
|
||||||
|
IBotCredentials creds,
|
||||||
|
IGoogleApiService google,
|
||||||
DbService db)
|
DbService db)
|
||||||
{
|
{
|
||||||
_client = client;
|
_client = client;
|
||||||
_creds = creds;
|
_creds = creds;
|
||||||
_google = google;
|
_google = google;
|
||||||
_db = db;
|
_db = db;
|
||||||
|
|
||||||
//_client.UserVoiceStateUpdated += Client_UserVoiceStateUpdated;
|
|
||||||
_client.LeftGuild += _client_LeftGuild;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Task _client_LeftGuild(SocketGuild arg)
|
|
||||||
{
|
|
||||||
var t = _service.DestroyPlayer(arg.Id);
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//todo changing server region is bugged again
|
//todo changing server region is bugged again
|
||||||
|
@ -2,10 +2,14 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netcoreapp2.0</TargetFramework>
|
<TargetFramework>netcoreapp2.0</TargetFramework>
|
||||||
|
<LangVersion>latest</LangVersion>
|
||||||
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
<PropertyGroup>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<OutputPath>..\src\NadekoBot\bin\$(Configuration)\netcoreapp2.0\modules\$(AssemblyName)\</OutputPath>
|
||||||
|
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||||
|
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -18,7 +18,7 @@ using NadekoBot.Modules.Music.Common.SongResolver;
|
|||||||
|
|
||||||
namespace NadekoBot.Modules.Music.Services
|
namespace NadekoBot.Modules.Music.Services
|
||||||
{
|
{
|
||||||
public class MusicService : INService
|
public class MusicService : INService, IUnloadableService
|
||||||
{
|
{
|
||||||
public const string MusicDataPath = "data/musicdata";
|
public const string MusicDataPath = "data/musicdata";
|
||||||
|
|
||||||
@ -47,13 +47,25 @@ namespace NadekoBot.Modules.Music.Services
|
|||||||
_creds = creds;
|
_creds = creds;
|
||||||
_log = LogManager.GetCurrentClassLogger();
|
_log = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
|
_client.LeftGuild += _client_LeftGuild;
|
||||||
|
|
||||||
try { Directory.Delete(MusicDataPath, true); } catch { }
|
try { Directory.Delete(MusicDataPath, true); } catch { }
|
||||||
|
|
||||||
_defaultVolumes = new ConcurrentDictionary<ulong, float>(gcs.ToDictionary(x => x.GuildId, x => x.DefaultMusicVolume));
|
_defaultVolumes = new ConcurrentDictionary<ulong, float>(gcs.ToDictionary(x => x.GuildId, x => x.DefaultMusicVolume));
|
||||||
|
|
||||||
Directory.CreateDirectory(MusicDataPath);
|
Directory.CreateDirectory(MusicDataPath);
|
||||||
|
}
|
||||||
|
|
||||||
//_t = new Timer(_ => _log.Info(MusicPlayers.Count(x => x.Value.Current.Current != null)), null, TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(5));
|
public Task Unload()
|
||||||
|
{
|
||||||
|
_client.LeftGuild -= _client_LeftGuild;
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task _client_LeftGuild(SocketGuild arg)
|
||||||
|
{
|
||||||
|
var t = DestroyPlayer(arg.Id);
|
||||||
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
public float GetDefaultVolume(ulong guildId)
|
public float GetDefaultVolume(ulong guildId)
|
||||||
|
@ -19,6 +19,7 @@ namespace NadekoBot.Modules.NSFW
|
|||||||
// thanks to halitalf for adding autoboob and autobutt features :D
|
// thanks to halitalf for adding autoboob and autobutt features :D
|
||||||
public class NSFW : NadekoTopLevelModule<SearchesService>
|
public class NSFW : NadekoTopLevelModule<SearchesService>
|
||||||
{
|
{
|
||||||
|
//todo clear when module unloaded
|
||||||
private static readonly ConcurrentDictionary<ulong, Timer> _autoHentaiTimers = new ConcurrentDictionary<ulong, Timer>();
|
private static readonly ConcurrentDictionary<ulong, Timer> _autoHentaiTimers = new ConcurrentDictionary<ulong, Timer>();
|
||||||
private static readonly ConcurrentDictionary<ulong, Timer> _autoBoobTimers = new ConcurrentDictionary<ulong, Timer>();
|
private static readonly ConcurrentDictionary<ulong, Timer> _autoBoobTimers = new ConcurrentDictionary<ulong, Timer>();
|
||||||
private static readonly ConcurrentDictionary<ulong, Timer> _autoButtTimers = new ConcurrentDictionary<ulong, Timer>();
|
private static readonly ConcurrentDictionary<ulong, Timer> _autoButtTimers = new ConcurrentDictionary<ulong, Timer>();
|
||||||
|
@ -2,6 +2,13 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netcoreapp2.0</TargetFramework>
|
<TargetFramework>netcoreapp2.0</TargetFramework>
|
||||||
|
<LangVersion>latest</LangVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputPath>..\src\NadekoBot\bin\$(Configuration)\netcoreapp2.0\modules\$(AssemblyName)\</OutputPath>
|
||||||
|
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||||
|
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -2,6 +2,13 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netcoreapp2.0</TargetFramework>
|
<TargetFramework>netcoreapp2.0</TargetFramework>
|
||||||
|
<LangVersion>latest</LangVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputPath>..\src\NadekoBot\bin\$(Configuration)\netcoreapp2.0\modules\$(AssemblyName)\</OutputPath>
|
||||||
|
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||||
|
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -2,6 +2,13 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netcoreapp2.0</TargetFramework>
|
<TargetFramework>netcoreapp2.0</TargetFramework>
|
||||||
|
<LangVersion>latest</LangVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputPath>..\src\NadekoBot\bin\$(Configuration)\netcoreapp2.0\modules\$(AssemblyName)\</OutputPath>
|
||||||
|
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||||
|
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -13,7 +13,7 @@ using NLog;
|
|||||||
|
|
||||||
namespace NadekoBot.Modules.Utility.Services
|
namespace NadekoBot.Modules.Utility.Services
|
||||||
{
|
{
|
||||||
public class ConverterService : INService
|
public class ConverterService : INService, IUnloadableService
|
||||||
{
|
{
|
||||||
public List<ConvertUnit> Units { get; } = new List<ConvertUnit>();
|
public List<ConvertUnit> Units { get; } = new List<ConvertUnit>();
|
||||||
private readonly Logger _log;
|
private readonly Logger _log;
|
||||||
@ -122,6 +122,12 @@ namespace NadekoBot.Modules.Utility.Services
|
|||||||
_log.Warn("Failed updating currency. Ignore this.");
|
_log.Warn("Failed updating currency. Ignore this.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Task Unload()
|
||||||
|
{
|
||||||
|
_currencyUpdater.Change(Timeout.Infinite, Timeout.Infinite);
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class MeasurementUnit
|
public class MeasurementUnit
|
||||||
|
@ -33,7 +33,7 @@ namespace NadekoBot.Modules.Utility.Services
|
|||||||
.Where(x => x.Guild != null)));
|
.Where(x => x.Guild != null)));
|
||||||
})
|
})
|
||||||
.Where(x => x.Item2 != null)
|
.Where(x => x.Item2 != null)
|
||||||
.ToDictionary(x => x.Item1, x => x.Item2));
|
.ToDictionary(x => x.GuildId, x => x.Item2));
|
||||||
RepeaterReady = true;
|
RepeaterReady = true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ using NLog;
|
|||||||
|
|
||||||
namespace NadekoBot.Modules.Utility.Services
|
namespace NadekoBot.Modules.Utility.Services
|
||||||
{
|
{
|
||||||
public class PatreonRewardsService : INService
|
public class PatreonRewardsService : INService, IUnloadableService
|
||||||
{
|
{
|
||||||
private readonly SemaphoreSlim getPledgesLocker = new SemaphoreSlim(1, 1);
|
private readonly SemaphoreSlim getPledgesLocker = new SemaphoreSlim(1, 1);
|
||||||
|
|
||||||
@ -33,15 +33,16 @@ namespace NadekoBot.Modules.Utility.Services
|
|||||||
|
|
||||||
private readonly string cacheFileName = "./patreon-rewards.json";
|
private readonly string cacheFileName = "./patreon-rewards.json";
|
||||||
|
|
||||||
public PatreonRewardsService(IBotCredentials creds, DbService db, CurrencyService currency,
|
public PatreonRewardsService(IBotCredentials creds, DbService db,
|
||||||
|
CurrencyService currency,
|
||||||
DiscordSocketClient client)
|
DiscordSocketClient client)
|
||||||
{
|
{
|
||||||
|
_log = LogManager.GetCurrentClassLogger();
|
||||||
_creds = creds;
|
_creds = creds;
|
||||||
_db = db;
|
_db = db;
|
||||||
_currency = currency;
|
_currency = currency;
|
||||||
if (string.IsNullOrWhiteSpace(creds.PatreonAccessToken))
|
if (string.IsNullOrWhiteSpace(creds.PatreonAccessToken))
|
||||||
return;
|
return;
|
||||||
_log = LogManager.GetCurrentClassLogger();
|
|
||||||
Updater = new Timer(async (load) => await RefreshPledges((bool)load),
|
Updater = new Timer(async (load) => await RefreshPledges((bool)load),
|
||||||
client.ShardId == 0, client.ShardId == 0 ? TimeSpan.Zero : TimeSpan.FromMinutes(2), Interval);
|
client.ShardId == 0, client.ShardId == 0 ? TimeSpan.Zero : TimeSpan.FromMinutes(2), Interval);
|
||||||
}
|
}
|
||||||
@ -171,5 +172,11 @@ namespace NadekoBot.Modules.Utility.Services
|
|||||||
claimLockJustInCase.Release();
|
claimLockJustInCase.Release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Task Unload()
|
||||||
|
{
|
||||||
|
Updater.Change(Timeout.Infinite, Timeout.Infinite);
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,10 +8,10 @@ using Discord.WebSocket;
|
|||||||
using NadekoBot.Common.Replacements;
|
using NadekoBot.Common.Replacements;
|
||||||
using NadekoBot.Extensions;
|
using NadekoBot.Extensions;
|
||||||
using NadekoBot.Services;
|
using NadekoBot.Services;
|
||||||
using NadekoBot.Services.Database;
|
|
||||||
using NadekoBot.Services.Database.Models;
|
using NadekoBot.Services.Database.Models;
|
||||||
using NadekoBot.Services.Impl;
|
using NadekoBot.Services.Impl;
|
||||||
using NLog;
|
using NLog;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Utility.Services
|
namespace NadekoBot.Modules.Utility.Services
|
||||||
{
|
{
|
||||||
@ -29,8 +29,10 @@ namespace NadekoBot.Modules.Utility.Services
|
|||||||
private readonly DiscordSocketClient _client;
|
private readonly DiscordSocketClient _client;
|
||||||
private readonly DbService _db;
|
private readonly DbService _db;
|
||||||
|
|
||||||
public RemindService(DiscordSocketClient client, IBotConfigProvider config, DbService db,
|
public RemindService(DiscordSocketClient client,
|
||||||
StartingGuildsService guilds, IUnitOfWork uow)
|
IBotConfigProvider config,
|
||||||
|
DbService db,
|
||||||
|
StartingGuildsService guilds)
|
||||||
{
|
{
|
||||||
_config = config;
|
_config = config;
|
||||||
_client = client;
|
_client = client;
|
||||||
@ -40,7 +42,11 @@ namespace NadekoBot.Modules.Utility.Services
|
|||||||
cancelSource = new CancellationTokenSource();
|
cancelSource = new CancellationTokenSource();
|
||||||
cancelAllToken = cancelSource.Token;
|
cancelAllToken = cancelSource.Token;
|
||||||
|
|
||||||
var reminders = uow.Reminders.GetIncludedReminders(guilds).ToList();
|
List<Reminder> reminders;
|
||||||
|
using (var uow = _db.UnitOfWork)
|
||||||
|
{
|
||||||
|
reminders = uow.Reminders.GetIncludedReminders(guilds).ToList();
|
||||||
|
}
|
||||||
RemindMessageFormat = _config.BotConfig.RemindMessageFormat;
|
RemindMessageFormat = _config.BotConfig.RemindMessageFormat;
|
||||||
|
|
||||||
foreach (var r in reminders)
|
foreach (var r in reminders)
|
||||||
|
@ -17,22 +17,24 @@ using Discord.Net;
|
|||||||
|
|
||||||
namespace NadekoBot.Modules.Utility.Services
|
namespace NadekoBot.Modules.Utility.Services
|
||||||
{
|
{
|
||||||
public class StreamRoleService : INService
|
public class StreamRoleService : INService, IUnloadableService
|
||||||
{
|
{
|
||||||
private readonly DbService _db;
|
private readonly DbService _db;
|
||||||
|
private readonly DiscordSocketClient _client;
|
||||||
private readonly ConcurrentDictionary<ulong, StreamRoleSettings> guildSettings;
|
private readonly ConcurrentDictionary<ulong, StreamRoleSettings> guildSettings;
|
||||||
private readonly Logger _log;
|
private readonly Logger _log;
|
||||||
|
|
||||||
public StreamRoleService(DiscordSocketClient client, DbService db, IEnumerable<GuildConfig> gcs)
|
public StreamRoleService(DiscordSocketClient client, DbService db, IEnumerable<GuildConfig> gcs)
|
||||||
{
|
{
|
||||||
this._db = db;
|
|
||||||
this._log = LogManager.GetCurrentClassLogger();
|
this._log = LogManager.GetCurrentClassLogger();
|
||||||
|
this._db = db;
|
||||||
|
this._client = client;
|
||||||
|
|
||||||
guildSettings = gcs.ToDictionary(x => x.GuildId, x => x.StreamRole)
|
guildSettings = gcs.ToDictionary(x => x.GuildId, x => x.StreamRole)
|
||||||
.Where(x => x.Value != null && x.Value.Enabled)
|
.Where(x => x.Value != null && x.Value.Enabled)
|
||||||
.ToConcurrent();
|
.ToConcurrent();
|
||||||
|
|
||||||
client.GuildMemberUpdated += Client_GuildMemberUpdated;
|
_client.GuildMemberUpdated += Client_GuildMemberUpdated;
|
||||||
|
|
||||||
var _ = Task.Run(async () =>
|
var _ = Task.Run(async () =>
|
||||||
{
|
{
|
||||||
@ -47,6 +49,12 @@ namespace NadekoBot.Modules.Utility.Services
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Task Unload()
|
||||||
|
{
|
||||||
|
_client.GuildMemberUpdated -= Client_GuildMemberUpdated;
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
private Task Client_GuildMemberUpdated(SocketGuildUser before, SocketGuildUser after)
|
private Task Client_GuildMemberUpdated(SocketGuildUser before, SocketGuildUser after)
|
||||||
{
|
{
|
||||||
var _ = Task.Run(async () =>
|
var _ = Task.Run(async () =>
|
||||||
|
@ -11,7 +11,7 @@ using NadekoBot.Services.Database.Models;
|
|||||||
|
|
||||||
namespace NadekoBot.Modules.Utility.Services
|
namespace NadekoBot.Modules.Utility.Services
|
||||||
{
|
{
|
||||||
public class VerboseErrorsService : INService
|
public class VerboseErrorsService : INService, IUnloadableService
|
||||||
{
|
{
|
||||||
private readonly ConcurrentHashSet<ulong> guildsEnabled;
|
private readonly ConcurrentHashSet<ulong> guildsEnabled;
|
||||||
private readonly DbService _db;
|
private readonly DbService _db;
|
||||||
@ -24,11 +24,17 @@ namespace NadekoBot.Modules.Utility.Services
|
|||||||
_ch = ch;
|
_ch = ch;
|
||||||
_hs = hs;
|
_hs = hs;
|
||||||
|
|
||||||
ch.CommandErrored += LogVerboseError;
|
_ch.CommandErrored += LogVerboseError;
|
||||||
|
|
||||||
guildsEnabled = new ConcurrentHashSet<ulong>(gcs.Where(x => x.VerboseErrors).Select(x => x.GuildId));
|
guildsEnabled = new ConcurrentHashSet<ulong>(gcs.Where(x => x.VerboseErrors).Select(x => x.GuildId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Task Unload()
|
||||||
|
{
|
||||||
|
_ch.CommandErrored -= LogVerboseError;
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
private async Task LogVerboseError(CommandInfo cmd, ITextChannel channel, string reason)
|
private async Task LogVerboseError(CommandInfo cmd, ITextChannel channel, string reason)
|
||||||
{
|
{
|
||||||
if (channel == null || !guildsEnabled.Contains(channel.GuildId))
|
if (channel == null || !guildsEnabled.Contains(channel.GuildId))
|
||||||
@ -73,6 +79,5 @@ namespace NadekoBot.Modules.Utility.Services
|
|||||||
|
|
||||||
return enabled;
|
return enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -99,8 +99,7 @@ namespace NadekoBot.Modules.Xp
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ClubInfo club;
|
if (!_service.GetClubByName(clubName, out ClubInfo club))
|
||||||
if (!_service.GetClubByName(clubName, out club))
|
|
||||||
{
|
{
|
||||||
await ReplyErrorLocalized("club_not_exists").ConfigureAwait(false);
|
await ReplyErrorLocalized("club_not_exists").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
|
@ -2,12 +2,19 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netcoreapp2.0</TargetFramework>
|
<TargetFramework>netcoreapp2.0</TargetFramework>
|
||||||
|
<LangVersion>latest</LangVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Discord.Net" Version="2.0.0-alpha-build-00832" />
|
<PackageReference Include="Discord.Net" Version="2.0.0-alpha-build-00832" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputPath>..\src\NadekoBot\bin\$(Configuration)\netcoreapp2.0\modules\$(AssemblyName)\</OutputPath>
|
||||||
|
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||||
|
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\NadekoBot.Core\NadekoBot.Core.csproj" />
|
<ProjectReference Include="..\NadekoBot.Core\NadekoBot.Core.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
@ -4,8 +4,6 @@ using NadekoBot.Services.Database.Models;
|
|||||||
using Discord;
|
using Discord;
|
||||||
using NadekoBot.Modules.Xp.Common;
|
using NadekoBot.Modules.Xp.Common;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Xp.Services
|
namespace NadekoBot.Modules.Xp.Services
|
||||||
{
|
{
|
||||||
|
@ -26,7 +26,7 @@ using ImageSharp.Drawing.Brushes;
|
|||||||
|
|
||||||
namespace NadekoBot.Modules.Xp.Services
|
namespace NadekoBot.Modules.Xp.Services
|
||||||
{
|
{
|
||||||
public class XpService : INService
|
public class XpService : INService, IUnloadableService
|
||||||
{
|
{
|
||||||
private enum NotifOf { Server, Global } // is it a server level-up or global level-up notification
|
private enum NotifOf { Server, Global } // is it a server level-up or global level-up notification
|
||||||
|
|
||||||
@ -55,7 +55,9 @@ namespace NadekoBot.Modules.Xp.Services
|
|||||||
private readonly ConcurrentQueue<UserCacheItem> _addMessageXp
|
private readonly ConcurrentQueue<UserCacheItem> _addMessageXp
|
||||||
= new ConcurrentQueue<UserCacheItem>();
|
= new ConcurrentQueue<UserCacheItem>();
|
||||||
|
|
||||||
private readonly Timer updateXpTimer;
|
private readonly Timer _updateXpTimer;
|
||||||
|
private readonly CancellationTokenSource _clearRewardTimerTokenSource;
|
||||||
|
private readonly Task _clearRewardTimer;
|
||||||
private readonly HttpClient http = new HttpClient();
|
private readonly HttpClient http = new HttpClient();
|
||||||
private FontFamily _usernameFontFamily;
|
private FontFamily _usernameFontFamily;
|
||||||
private FontFamily _clubFontFamily;
|
private FontFamily _clubFontFamily;
|
||||||
@ -115,7 +117,7 @@ namespace NadekoBot.Modules.Xp.Services
|
|||||||
|
|
||||||
_cmd.OnMessageNoTrigger += _cmd_OnMessageNoTrigger;
|
_cmd.OnMessageNoTrigger += _cmd_OnMessageNoTrigger;
|
||||||
|
|
||||||
updateXpTimer = new Timer(async _ =>
|
_updateXpTimer = new Timer(async _ =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -242,18 +244,19 @@ namespace NadekoBot.Modules.Xp.Services
|
|||||||
}
|
}
|
||||||
}, null, TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(5));
|
}, null, TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(5));
|
||||||
|
|
||||||
|
_clearRewardTimerTokenSource = new CancellationTokenSource();
|
||||||
|
var token = _clearRewardTimerTokenSource.Token;
|
||||||
//just a first line, in order to prevent queries. But since other shards can try to do this too,
|
//just a first line, in order to prevent queries. But since other shards can try to do this too,
|
||||||
//i'll check in the db too.
|
//i'll check in the db too.
|
||||||
var clearRewardTimer = Task.Run(async () =>
|
_clearRewardTimer = Task.Run(async () =>
|
||||||
{
|
{
|
||||||
while (true)
|
while (!token.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
_rewardedUsers.Clear();
|
_rewardedUsers.Clear();
|
||||||
|
|
||||||
await Task.Delay(TimeSpan.FromMinutes(_bc.BotConfig.XpMinutesTimeout));
|
await Task.Delay(TimeSpan.FromMinutes(_bc.BotConfig.XpMinutesTimeout));
|
||||||
}
|
}
|
||||||
});
|
}, token);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<XpRoleReward> GetRoleRewards(ulong id)
|
public IEnumerable<XpRoleReward> GetRoleRewards(ulong id)
|
||||||
@ -751,5 +754,17 @@ namespace NadekoBot.Modules.Xp.Services
|
|||||||
|
|
||||||
return new PathCollection(cornerToptLeft, cornerBottomLeft, cornerTopRight, cornerBottomRight);
|
return new PathCollection(cornerToptLeft, cornerBottomLeft, cornerTopRight, cornerBottomRight);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Task Unload()
|
||||||
|
{
|
||||||
|
_cmd.OnMessageNoTrigger -= _cmd_OnMessageNoTrigger;
|
||||||
|
|
||||||
|
if (!_clearRewardTimerTokenSource.IsCancellationRequested)
|
||||||
|
_clearRewardTimerTokenSource.Cancel();
|
||||||
|
|
||||||
|
_updateXpTimer.Change(Timeout.Infinite, Timeout.Infinite);
|
||||||
|
_clearRewardTimerTokenSource.Dispose();
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
using Discord;
|
using Discord;
|
||||||
using Discord.Commands;
|
using Discord.Commands;
|
||||||
using Discord.WebSocket;
|
using Discord.WebSocket;
|
||||||
using NadekoBot.Common;
|
|
||||||
using NadekoBot.Common.Attributes;
|
using NadekoBot.Common.Attributes;
|
||||||
using NadekoBot.Extensions;
|
using NadekoBot.Extensions;
|
||||||
using NadekoBot.Modules.Xp.Common;
|
using NadekoBot.Modules.Xp.Common;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
# Visual Studio 15
|
# Visual Studio 15
|
||||||
VisualStudioVersion = 15.0.26730.3
|
VisualStudioVersion = 15.0.26730.16
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{04929013-5BAB-42B0-B9B2-8F2BB8F16AF2}"
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{04929013-5BAB-42B0-B9B2-8F2BB8F16AF2}"
|
||||||
EndProject
|
EndProject
|
||||||
@ -13,25 +13,23 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
|
|||||||
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}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NadekoBot.Modules.CustomReactions", "NadekoBot.Modules.CustomReactions\NadekoBot.Modules.CustomReactions.csproj", "{60F1217E-5E01-42DC-9B86-0FE910EDE081}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NadekoBot.Core", "NadekoBot.Core\NadekoBot.Core.csproj", "{A6CCEFBD-DCF2-482C-9643-47664683548F}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NadekoBot.Core", "NadekoBot.Core\NadekoBot.Core.csproj", "{A6CCEFBD-DCF2-482C-9643-47664683548F}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NadekoBot.Modules.Xp", "NadekoBot.Modules.Xp\NadekoBot.Modules.Xp.csproj", "{41A2DEBA-E8AE-4EC8-A58F-01C4B6E599E5}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NadekoBot.Modules.Xp", "NadekoBot.Modules.Xp\NadekoBot.Modules.Xp.csproj", "{41A2DEBA-E8AE-4EC8-A58F-01C4B6E599E5}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NadekoBot.Modules.Utility", "NadekoBot.Modules.Utility\NadekoBot.Modules.Utility.csproj", "{07606931-CB55-4D20-8369-4E086B00EC52}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NadekoBot.Modules.Utility", "NadekoBot.Modules.Utility\NadekoBot.Modules.Utility.csproj", "{07606931-CB55-4D20-8369-4E086B00EC52}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NadekoBot.Modules.Searches", "NadekoBot.Module.Searches\NadekoBot.Modules.Searches.csproj", "{8BEE9984-3EB3-45BE-A5CF-0DB912626B81}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NadekoBot.Modules.Searches", "NadekoBot.Module.Searches\NadekoBot.Modules.Searches.csproj", "{8BEE9984-3EB3-45BE-A5CF-0DB912626B81}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NadekoBot.Modules.Nsfw", "NadekoBot.Modules.Nsfw\NadekoBot.Modules.Nsfw.csproj", "{75ED72EC-7AB3-4B12-A2DA-3655C740B356}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NadekoBot.Modules.Nsfw", "NadekoBot.Modules.Nsfw\NadekoBot.Modules.Nsfw.csproj", "{75ED72EC-7AB3-4B12-A2DA-3655C740B356}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NadekoBot.Modules.Games", "NadekoBot.Modules.Games\NadekoBot.Modules.Games.csproj", "{FF6BDE61-24B4-4DC2-99EE-409EA1650180}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NadekoBot.Modules.Games", "NadekoBot.Modules.Games\NadekoBot.Modules.Games.csproj", "{FF6BDE61-24B4-4DC2-99EE-409EA1650180}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NadekoBot.Modules.Gambling", "NadekoBot.Modules.Gambling\NadekoBot.Modules.Gambling.csproj", "{6436A700-694E-412C-92AE-B793FCD44E84}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NadekoBot.Modules.Gambling", "NadekoBot.Modules.Gambling\NadekoBot.Modules.Gambling.csproj", "{6436A700-694E-412C-92AE-B793FCD44E84}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NadekoBot.Modules.Pokemon", "NadekoBot.Modules.Pokemon\NadekoBot.Modules.Pokemon.csproj", "{30463C26-555B-4760-9459-A16DFA015DFA}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NadekoBot.Modules.Pokemon", "NadekoBot.Modules.Pokemon\NadekoBot.Modules.Pokemon.csproj", "{30463C26-555B-4760-9459-A16DFA015DFA}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NadekoBot.Modules.Music", "NadekoBot.Modules.Music\NadekoBot.Modules.Music.csproj", "{674E28A6-30B1-413D-BBD3-E5F71614A00F}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NadekoBot.Modules.Music", "NadekoBot.Modules.Music\NadekoBot.Modules.Music.csproj", "{674E28A6-30B1-413D-BBD3-E5F71614A00F}"
|
||||||
EndProject
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
@ -46,12 +44,6 @@ Global
|
|||||||
{45EC1473-C678-4857-A544-07DFE0D0B478}.GlobalNadeko|Any CPU.Build.0 = Release|Any CPU
|
{45EC1473-C678-4857-A544-07DFE0D0B478}.GlobalNadeko|Any CPU.Build.0 = Release|Any CPU
|
||||||
{45EC1473-C678-4857-A544-07DFE0D0B478}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{45EC1473-C678-4857-A544-07DFE0D0B478}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{45EC1473-C678-4857-A544-07DFE0D0B478}.Release|Any CPU.Build.0 = Release|Any CPU
|
{45EC1473-C678-4857-A544-07DFE0D0B478}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{60F1217E-5E01-42DC-9B86-0FE910EDE081}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{60F1217E-5E01-42DC-9B86-0FE910EDE081}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{60F1217E-5E01-42DC-9B86-0FE910EDE081}.GlobalNadeko|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{60F1217E-5E01-42DC-9B86-0FE910EDE081}.GlobalNadeko|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{60F1217E-5E01-42DC-9B86-0FE910EDE081}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{60F1217E-5E01-42DC-9B86-0FE910EDE081}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{A6CCEFBD-DCF2-482C-9643-47664683548F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{A6CCEFBD-DCF2-482C-9643-47664683548F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{A6CCEFBD-DCF2-482C-9643-47664683548F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{A6CCEFBD-DCF2-482C-9643-47664683548F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{A6CCEFBD-DCF2-482C-9643-47664683548F}.GlobalNadeko|Any CPU.ActiveCfg = Debug|Any CPU
|
{A6CCEFBD-DCF2-482C-9643-47664683548F}.GlobalNadeko|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
@ -112,7 +104,6 @@ Global
|
|||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(NestedProjects) = preSolution
|
GlobalSection(NestedProjects) = preSolution
|
||||||
{45EC1473-C678-4857-A544-07DFE0D0B478} = {04929013-5BAB-42B0-B9B2-8F2BB8F16AF2}
|
{45EC1473-C678-4857-A544-07DFE0D0B478} = {04929013-5BAB-42B0-B9B2-8F2BB8F16AF2}
|
||||||
{60F1217E-5E01-42DC-9B86-0FE910EDE081} = {04929013-5BAB-42B0-B9B2-8F2BB8F16AF2}
|
|
||||||
{A6CCEFBD-DCF2-482C-9643-47664683548F} = {04929013-5BAB-42B0-B9B2-8F2BB8F16AF2}
|
{A6CCEFBD-DCF2-482C-9643-47664683548F} = {04929013-5BAB-42B0-B9B2-8F2BB8F16AF2}
|
||||||
{41A2DEBA-E8AE-4EC8-A58F-01C4B6E599E5} = {04929013-5BAB-42B0-B9B2-8F2BB8F16AF2}
|
{41A2DEBA-E8AE-4EC8-A58F-01C4B6E599E5} = {04929013-5BAB-42B0-B9B2-8F2BB8F16AF2}
|
||||||
{07606931-CB55-4D20-8369-4E086B00EC52} = {04929013-5BAB-42B0-B9B2-8F2BB8F16AF2}
|
{07606931-CB55-4D20-8369-4E086B00EC52} = {04929013-5BAB-42B0-B9B2-8F2BB8F16AF2}
|
||||||
|
@ -4,16 +4,13 @@
|
|||||||
<TargetFramework>netcoreapp2.0</TargetFramework>
|
<TargetFramework>netcoreapp2.0</TargetFramework>
|
||||||
<RuntimeFrameworkVersion>2.0.0</RuntimeFrameworkVersion>
|
<RuntimeFrameworkVersion>2.0.0</RuntimeFrameworkVersion>
|
||||||
<OutputType>exe</OutputType>
|
<OutputType>exe</OutputType>
|
||||||
<AssetTargetFallback>$(AssetTargetFallback);dnxcore50;portable-net45+win8+wpa81</AssetTargetFallback>
|
|
||||||
<ApplicationIcon>nadeko_icon.ico</ApplicationIcon>
|
<ApplicationIcon>nadeko_icon.ico</ApplicationIcon>
|
||||||
<RuntimeIdentifiers>win7-x64<!--;ubuntu.14.04-x64;osx.10.10-x64 --></RuntimeIdentifiers>
|
|
||||||
<Configurations>Debug;Release;global_nadeko</Configurations>
|
|
||||||
<LangVersion>latest</LangVersion>
|
<LangVersion>latest</LangVersion>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition=" '$(Version)' == '' ">
|
<PropertyGroup Condition=" '$(Version)' == '' ">
|
||||||
<VersionPrefix Condition=" '$(VersionPrefix)' == '' ">1.9.1</VersionPrefix>
|
<VersionPrefix Condition=" '$(VersionPrefix)' == '' ">2.0.0</VersionPrefix>
|
||||||
<Version Condition=" '$(VersionSuffix)' != '' ">$(VersionPrefix).$(VersionSuffix)</Version>
|
<Version Condition=" '$(VersionSuffix)' != '' ">$(VersionPrefix).$(VersionSuffix)</Version>
|
||||||
<Version Condition=" '$(Version)' == '' ">$(VersionPrefix)</Version>
|
<Version Condition=" '$(Version)' == '' ">$(VersionPrefix)</Version>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
@ -23,6 +20,12 @@
|
|||||||
<None Update="credentials_example.json">
|
<None Update="credentials_example.json">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
|
<None Update="data\**\*">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
<None Update="_strings\*">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
<None Update="libsodium.dll;opus.dll;libsodium.so;libopus.so">
|
<None Update="libsodium.dll;opus.dll;libsodium.so;libopus.so">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
@ -66,6 +69,5 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\..\NadekoBot.Core\NadekoBot.Core.csproj" />
|
<ProjectReference Include="..\..\NadekoBot.Core\NadekoBot.Core.csproj" />
|
||||||
<ProjectReference Include="..\..\NadekoBot.Modules.CustomReactions\NadekoBot.Modules.CustomReactions.csproj" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
@ -1,18 +1,20 @@
|
|||||||
namespace NadekoBot
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace NadekoBot
|
||||||
{
|
{
|
||||||
public class Program
|
public class Program
|
||||||
{
|
{
|
||||||
public static void Main(string[] args)
|
public static Task Main(string[] args)
|
||||||
{
|
{
|
||||||
if (args.Length == 3 && int.TryParse(args[0], out int shardId) && int.TryParse(args[1], out int parentProcessId))
|
if (args.Length == 3 && int.TryParse(args[0], out int shardId) && int.TryParse(args[1], out int parentProcessId))
|
||||||
{
|
{
|
||||||
int? port = null;
|
int? port = null;
|
||||||
if (int.TryParse(args[2], out var outPort))
|
if (int.TryParse(args[2], out var outPort))
|
||||||
port = outPort;
|
port = outPort;
|
||||||
new NadekoBot(shardId, parentProcessId, outPort).RunAndBlockAsync(args).GetAwaiter().GetResult();
|
return new NadekoBot(shardId, parentProcessId, outPort).RunAndBlockAsync(args);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
new NadekoBot(0, 0).RunAndBlockAsync(args).GetAwaiter().GetResult();
|
return new NadekoBot(0, 0).RunAndBlockAsync(args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user