public void Start() { _logger.Trace("Start"); _logger.Info("Connecting to Discord..."); _client.ConnectAsync(); }
public async Task StartAsync() { _logger.Trace($"FilterBot::Start"); if (_client == null) { _logger.Error($"Really don't know how this happened?"); return; } var http = new HttpServer(_config, _logger); http.PokemonReceived += PokemonReceived; http.RaidReceived += RaidReceived; if (_timer == null) { _timer = new Timer(1000 * 60 * 15); _timer.Elapsed += MinuteTimerEventHandler; _timer.Start(); } _logger.Info("Connecting to discord server..."); await Utils.Wait(500); await _client.ConnectAsync(); }
private void LoadGeofences() { foreach (var(serverId, serverConfig) in _config.Instance.Servers) { serverConfig.Geofences.Clear(); var geofenceFiles = serverConfig.GeofenceFiles; var geofences = new List <GeofenceItem>(); if (geofenceFiles != null && geofenceFiles.Any()) { foreach (var file in geofenceFiles) { var filePath = Path.Combine(Strings.GeofenceFolder, file); try { var fileGeofences = GeofenceItem.FromFile(filePath); geofences.AddRange(fileGeofences); _logger.Info($"Successfully loaded {fileGeofences.Count} geofences from {file}"); } catch (Exception ex) { _logger.Error($"Could not load Geofence file {file} (for server {serverId}):"); _logger.Error(ex); } } } serverConfig.Geofences.AddRange(geofences); } }
private void AssignGuildMembersToRole(DiscordMessage message, List <string> roles, bool defaultCityFeed) { #pragma warning disable RECS0165 new System.Threading.Thread(async x => #pragma warning restore RECS0165 { var guild = message.Channel.Guild; var success = 0; var errors = 0; var failed = new List <string>(); await message.RespondAsync ( defaultCityFeed ? $"Starting default city feed assignment for all users of guild **{guild.Name}**." : $"Starting {string.Join(",", roles)} role(s) assignment to all users of guild **{guild.Name}**." ); foreach (var member in guild.Members) { try { foreach (var role in roles) { var discordRole = _client.GetRoleFromName(role); if (discordRole == null) { //Failed to find role. _logger.Error($"Failed to find city role {role}, please make sure it exists."); continue; } await member.GrantRoleAsync(discordRole, $"{discordRole.Name} role assignment."); _logger.Info($"Assigned {member.Username} to role {discordRole.Name}."); } success++; } catch (Exception ex) { errors++; failed.Add(member.Username); _logger.Error(ex); } } _logger.Info($"Finished assigning {string.Join(",", roles)} roles."); await message.RespondAsync ( $"{success}/{guild.MemberCount} members were assigned the " + (defaultCityFeed ? "default city feed" : string.Join(",", roles)) + $" roles and {errors} member's roles were not set." + (failed.Count == 0 ? "" : "\r\nList of users role assignment failed:\r\n" + string.Join(Environment.NewLine, failed)) ); }) { IsBackground = true }.Start(); }
private AlarmList LoadAlarms(string alarmsFilePath) { _logger.Trace($"WebhookManager::LoadAlarms [AlarmsFilePath={alarmsFilePath}]"); if (!File.Exists(alarmsFilePath)) { _logger.Error($"Failed to load file alarms file '{alarmsFilePath}'..."); return(null); } var alarmData = File.ReadAllText(alarmsFilePath); if (string.IsNullOrEmpty(alarmData)) { _logger.Error($"Failed to load '{alarmsFilePath}', file is empty..."); return(null); } var alarms = JsonConvert.DeserializeObject <AlarmList>(alarmData); if (alarms == null) { _logger.Error($"Failed to deserialize the alarms file '{alarmsFilePath}', make sure you don't have any json syntax errors."); return(null); } _logger.Info($"Alarms file {alarmsFilePath} was loaded successfully."); alarms.Alarms.ForEach(x => { if (x.Geofences != null) { foreach (var geofenceName in x.Geofences) { var geofences = Geofences.Where(g => g.Name.Equals(geofenceName, StringComparison.OrdinalIgnoreCase) || g.Filename.Equals(geofenceName, StringComparison.OrdinalIgnoreCase)).ToList(); if (geofences.Any()) { x.GeofenceItems.AddRange(geofences); } else { _logger.Warn($"No geofences were found matching the name or filename \"{geofenceName}\" (for alarm \"{x.Name}\")"); } } } x.LoadAlerts(); x.LoadFilters(); }); return(alarms); }
public void ParseData(string data) { try { if (string.IsNullOrEmpty(data)) { return; } //File.AppendAllText("debug.txt", data + "\r\n"); var obj = JsonConvert.DeserializeObject <dynamic>(data); if (obj == null) { return; } foreach (dynamic part in obj) { string type = Convert.ToString(part["type"]); dynamic message = part["message"]; switch (type) { case "pokemon": ParsePokemon(message); break; //case "gym": // ParseGym(message); // break; //case "gym-info": //case "gym_details": // ParseGymInfo(message); // break; //case "egg": case "raid": ParseRaid(message); break; //case "tth": //case "scheduler": // ParseTth(message); // break; } } } catch (Exception ex) { Utils.LogError(ex); _logger.Error(ex); _logger.Info("{0}", Convert.ToString(data)); } }
private AlarmList LoadAlarms(string alarmsFilePath) { _logger.Trace($"WebhookManager::LoadAlarms [AlarmsFilePath={alarmsFilePath}]"); if (!File.Exists(alarmsFilePath)) { _logger.Error($"Failed to load file alarms file '{alarmsFilePath}'..."); return(null); } var alarmData = File.ReadAllText(alarmsFilePath); if (string.IsNullOrEmpty(alarmData)) { _logger.Error($"Failed to load '{alarmsFilePath}', file is empty..."); return(null); } var alarms = JsonConvert.DeserializeObject <AlarmList>(alarmData); if (alarms == null) { _logger.Error($"Failed to deserialize the alarms file '{alarmsFilePath}', make sure you don't have any json syntax errors."); return(null); } _logger.Info($"Alarms file {alarmsFilePath} was loaded successfully."); alarms.Alarms.ForEach(x => { var geofences = x.LoadGeofence(); for (var i = 0; i < geofences.Count; i++) { var geofence = geofences[i]; if (!Geofences.ContainsKey(geofence.Name)) { Geofences.Add(geofence.Name, geofence); _logger.Debug($"Geofence file loaded for {x.Name}..."); } } x.LoadAlerts(); x.LoadFilters(); }); return(alarms); }
/// <summary> /// Instantiates a new <see cref="DatabaseMigrator"/> class /// </summary> public DatabaseMigrator() { // Create the metadata table Execute(Strings.SQL_CREATE_TABLE_METADATA).GetAwaiter().GetResult(); // Get current version from metadata table var currentVersion = int.Parse(GetMetadata("DB_VERSION")?.Value ?? "0"); // Get newest version from migration files var newestVersion = GetNewestDbVersion(); _logger.Info($"Current: {currentVersion}, Latest: {newestVersion}"); // Attempt to migrate the database Migrate(currentVersion, newestVersion).GetAwaiter().GetResult(); }
public async Task CleanDepartedAsync(CommandContext ctx) { _logger.Debug($"Checking if there are any subscriptions for members that are no longer apart of the server..."); var removed = 0; var users = _dep.SubscriptionProcessor?.Manager?.Subscriptions;// GetUserSubscriptions(); for (var i = 0; i < users.Count; i++) { var user = users[i]; var discordUser = ctx.Client.GetMemberById(_dep.WhConfig.Discord.GuildId, user.UserId); var isSupporter = ctx.Client.HasSupporterRole(_dep.WhConfig.Discord.GuildId, user.UserId, _dep.WhConfig.Discord.DonorRoleIds); if (discordUser == null || !isSupporter) { _logger.Debug($"Removing user {user.UserId} subscription settings because they are no longer a member of the server."); if (!_dep.SubscriptionProcessor.Manager.RemoveAllUserSubscriptions(user.UserId)) { _logger.Warn($"Could not remove user {user.UserId} subscription settings from the database."); continue; } _logger.Info($"Removed {user.UserId} and subscriptions from database."); removed++; } } await ctx.RespondEmbed($"Removed {removed.ToString("N0")} of {users.Count.ToString("N0")} total members."); }
public async Task CleanDepartedAsync(CommandContext ctx) { _logger.Debug($"Checking if there are any subscriptions for members that are no longer apart of the server..."); var guildId = ctx.Guild?.Id ?? ctx.Client.Guilds.Keys.FirstOrDefault(x => _dep.WhConfig.Servers.ContainsKey(x)); var removed = 0; var users = _dep.SubscriptionProcessor?.Manager?.Subscriptions; for (var i = 0; i < users.Count; i++) { var user = users[i]; var discordUser = ctx.Client.GetMemberById(guildId, user.UserId); var isSupporter = ctx.Client.HasSupporterRole(guildId, user.UserId, _dep.WhConfig.Servers[guildId].DonorRoleIds); if (discordUser == null || !isSupporter) { _logger.Debug($"Removing user {user.UserId} subscription settings because they are no longer a member of the server."); if (!SubscriptionManager.RemoveAllUserSubscriptions(guildId, user.UserId)) { _logger.Warn($"Unable to remove user {user.UserId} subscription settings from the database."); continue; } _logger.Info($"Removed {user.UserId} and subscriptions from database."); removed++; } } await ctx.RespondEmbed(Translator.Instance.Translate("REMOVED_TOTAL_DEPARTED_MEMBERS").FormatText(removed.ToString("N0"), users.Count.ToString("N0"))); }
public bool RemoveAllQuests(ulong userId) { _logger.Info($"SubscriptionManager::RemoveAllQuests [UserId={userId}]"); using (var conn = DataAccessLayer.CreateFactory().Open()) { var subscription = conn.LoadSingleById <SubscriptionObject>(userId); if (subscription == null) { //Not subscribed. return(true); } var result = conn.DeleteAll(subscription.Quests); return(result > 0); } }
private bool CreateDefaultTables() { _logger.Trace($"SubscriptionManager::CreateDefaultTables"); if (!IsDbConnectionOpen()) { throw new Exception("Not connected to database."); } try { /* * var conn = GetConnection(); * if (!conn.CreateTableIfNotExists<Metadata>()) * { * _logger.Debug($"Table Metadata already exists."); * } * if (!conn.CreateTableIfNotExists<SubscriptionObject>()) * { * _logger.Debug($"Table SubscriptionObject already exists."); * } * if (!conn.CreateTableIfNotExists<PokemonSubscription>()) * { * _logger.Debug($"Table PokemonSubscription already exists."); * } * if (!conn.CreateTableIfNotExists<PvPSubscription>()) * { * _logger.Debug($"Table PvPSubscription already exists."); * } * if (!conn.CreateTableIfNotExists<RaidSubscription>()) * { * _logger.Debug($"Table RaidSubscription already exists."); * } * if (!conn.CreateTableIfNotExists<GymSubscription>()) * { * _logger.Debug($"Table GymSubscription already exists."); * } * if (!conn.CreateTableIfNotExists<QuestSubscription>()) * { * _logger.Debug($"Table QuestSubscription already exists."); * } * if (!conn.CreateTableIfNotExists<InvasionSubscription>()) * { * _logger.Debug($"Table InvasionSubscription already exists."); * } */ _logger.Info($"Database tables created."); return(true); } catch (Exception ex) { _logger.Error(ex); } return(false); }
private async Task Client_Ready(ReadyEventArgs e) { _logger.Trace($"Bot::Client_Ready [{e.Client.CurrentUser.Username}]"); //var version = AssemblyUtils.AssemblyVersion; //var cleanedVersion = version.Substring(0, version.LastIndexOf('.')); await _client.UpdateStatusAsync(new DiscordGame($"Reporting raids...")); foreach (var user in _client.Presences) { _logger.Info($"User: {user.Key}: {user.Value.User.Username}"); } }
/// <summary> /// Instantiates a new <see cref="DatabaseMigrator"/> class /// </summary> public DatabaseMigrator() { // Create directory if not exists var dir = Path.GetDirectoryName(CurrentDatabaseVersionPath); if (!Directory.Exists(dir)) { Directory.CreateDirectory(dir); } // Get current version from metadata table var currentVersion = GetCurrentVersion(); if (currentVersion == 0) { var result = SetCurrentVersion(currentVersion); if (!result) { _logger.Error($"Failed to set current database version: {currentVersion}"); Environment.Exit(-1); } } // Get newest version from migration files var newestVersion = GetNewestDbVersion(); _logger.Info($"Current: {currentVersion}, Latest: {newestVersion}"); // Attempt to migrate the database if (currentVersion < newestVersion) { // Wait 30 seconds and let user know we are about to migrate the database and for them to make // a backup until we handle backups and rollbacks. _logger.Info("MIGRATION IS ABOUT TO START IN 30 SECONDS, PLEASE MAKE SURE YOU HAVE A BACKUP!!!"); Thread.Sleep(30 * 1000); } Migrate(currentVersion, newestVersion).GetAwaiter().GetResult(); }
/// <summary> /// Instantiates a new <see cref="DatabaseMigrator"/> class /// </summary> public DatabaseMigrator() { // Create the metadata table Execute(Strings.SQL_CREATE_TABLE_METADATA).GetAwaiter().GetResult(); // Get current version from metadata table var currentVersion = int.Parse(GetMetadata("DB_VERSION")?.Value ?? "0"); // Get newest version from migration files var newestVersion = GetNewestDbVersion(); _logger.Info($"Current: {currentVersion}, Latest: {newestVersion}"); // Attempt to migrate the database if (currentVersion < newestVersion) { // Wait 30 seconds and let user know we are about to migrate the database and for them to make // a backup until we handle backups and rollbacks. _logger.Info("MIGRATION IS ABOUT TO START IN 30 SECONDS, PLEASE MAKE SURE YOU HAVE A BACKUP!!!"); Thread.Sleep(30 * 1000); } Migrate(currentVersion, newestVersion).GetAwaiter().GetResult(); }
public bool Resign(string megaLink, string version) { var fileName = $"J{version}.ipa"; var releaseName = Path.Combine(ReleasesFolder, fileName); var releaseNameSigned = Path.Combine( ReleasesFolder, Path.GetFileNameWithoutExtension(fileName) + "Signed.ipa" ); SignedReleaseFileName = releaseNameSigned; if (File.Exists(releaseName)) { // Already exists _logger.Info($"Latest ipa already downloaded, skipping..."); } else { // Download new version _logger.Info($"Downloading IPA from {megaLink} to {releaseName}"); if (!DownloadFile(megaLink, releaseName)) { _logger.Warn($"Failed to download IPA from {megaLink}, is megatools installed?"); return(false); } } if (File.Exists(releaseNameSigned)) { _logger.Info($"Signed IPA of latest already exists!"); // Already exists return(true); } var result = InternalResignApp(releaseName, releaseNameSigned); if (!result) { _logger.Error($"Unknown error occurred while resigning ipa file {releaseName}"); } //Deploy(releaseNameSigned, Strings.All); return(result); }
public void Start() { _logger.Trace("Start"); _logger.Info("Connecting to Discord..."); // TODO: Fails on M1 while debugging _client.ConnectAsync(); _server.Start(); }
/// <summary> /// Discord bot class /// </summary> /// <param name="config">Configuration settings</param> public Bot(Config whConfig) { _logger.Trace($"WhConfig [Servers={whConfig.Servers.Count}]"); _servers = new Dictionary <ulong, DiscordClient>(); _whConfig = whConfig; // Set unhandled exception event handler AppDomain.CurrentDomain.UnhandledException += UnhandledExceptionHandler; // Create a DiscordClient object per Discord server in config var keys = _whConfig.Servers.Keys.ToList(); for (var i = 0; i < keys.Count; i++) { var guildId = keys[i]; var server = _whConfig.Servers[guildId]; var client = new DiscordClient(new DiscordConfiguration { AutomaticGuildSync = true, AutoReconnect = true, EnableCompression = true, Token = server.Token, TokenType = TokenType.Bot, UseInternalLogHandler = true }); // If you are on Windows 7 and using .NETFX, install // DSharpPlus.WebSocket.WebSocket4Net from NuGet, // add appropriate usings, and uncomment the following // line //client.SetWebSocketClient<WebSocket4NetClient>(); // If you are on Windows 7 and using .NET Core, install // DSharpPlus.WebSocket.WebSocket4NetCore from NuGet, // add appropriate usings, and uncomment the following // line //client.SetWebSocketClient<WebSocket4NetCoreClient>(); // If you are using Mono, install // DSharpPlus.WebSocket.WebSocketSharp from NuGet, // add appropriate usings, and uncomment the following // line //client.SetWebSocketClient<WebSocketSharpClient>(); client.Ready += Client_Ready; client.GuildAvailable += Client_GuildAvailable; //_client.MessageCreated += Client_MessageCreated; client.ClientErrored += Client_ClientErrored; client.DebugLogger.LogMessageReceived += DebugLogger_LogMessageReceived; _logger.Info($"Configured Discord server {guildId}"); if (!_servers.ContainsKey(guildId)) { _servers.Add(guildId, client); } // Wait 3 seconds between initializing Discord clients Task.Delay(3000).GetAwaiter().GetResult(); } }
public Bot(WhConfig whConfig, string alarmsFilePath) { _logger.Trace($"WhConfig={whConfig.Discord.GuildId}, OwnerId={whConfig.Discord.OwnerId}, GuildId={whConfig.Discord.GuildId}, WebhookPort={whConfig.WebhookPort}"); _lang = new Translator(); _whConfig = whConfig; DataAccessLayer.ConnectionString = _whConfig.ConnectionStrings.Main; DataAccessLayer.ScannerConnectionString = _whConfig.ConnectionStrings.Scanner; AppDomain.CurrentDomain.UnhandledException += async(sender, e) => { _logger.Debug("Unhandled exception caught."); _logger.Error((Exception)e.ExceptionObject); if (e.IsTerminating) { if (_client != null) { var owner = await _client.GetUserAsync(_whConfig.Discord.OwnerId); if (owner == null) { _logger.Warn($"Failed to get owner from id {_whConfig.Discord.OwnerId}."); return; } await _client.SendDirectMessage(owner, Strings.CrashMessage, null); } } }; _gyms = new Dictionary <string, GymDetailsData>(); _whm = new WebhookManager(_whConfig, alarmsFilePath); _whm.PokemonAlarmTriggered += OnPokemonAlarmTriggered; _whm.RaidAlarmTriggered += OnRaidAlarmTriggered; _whm.QuestAlarmTriggered += OnQuestAlarmTriggered; _whm.PokestopAlarmTriggered += OnPokestopAlarmTriggered; _whm.GymAlarmTriggered += OnGymAlarmTriggered; _whm.GymDetailsAlarmTriggered += OnGymDetailsAlarmTriggered; _whm.WeatherAlarmTriggered += OnWeatherAlarmTriggered; if (_whConfig.Discord.EnableSubscriptions) { _whm.PokemonSubscriptionTriggered += OnPokemonSubscriptionTriggered; _whm.RaidSubscriptionTriggered += OnRaidSubscriptionTriggered; _whm.QuestSubscriptionTriggered += OnQuestSubscriptionTriggered; _whm.InvasionSubscriptionTriggered += OnInvasionSubscriptionTriggered; } _logger.Info("WebhookManager is running..."); var midnight = new DandTSoftware.Timers.MidnightTimer(); midnight.TimeReached += async(e) => await ResetQuests(); midnight.Start(); _client = new DiscordClient(new DiscordConfiguration { AutomaticGuildSync = true, AutoReconnect = true, EnableCompression = true, Token = _whConfig.Discord.Token, TokenType = TokenType.Bot, UseInternalLogHandler = true }); _client.Ready += Client_Ready; //_client.MessageCreated += Client_MessageCreated; _client.ClientErrored += Client_ClientErrored; _client.DebugLogger.LogMessageReceived += DebugLogger_LogMessageReceived; _interactivity = _client.UseInteractivity ( new InteractivityConfiguration { // default pagination behaviour to just ignore the reactions PaginationBehaviour = TimeoutBehaviour.Ignore, // default pagination timeout to 5 minutes PaginationTimeout = TimeSpan.FromMinutes(5), //TODO: Set prod // default timeout for other actions to 2 minutes Timeout = TimeSpan.FromMinutes(2) //TODO: Set prod } ); if (_whConfig.Discord.EnableSubscriptions) { _subProcessor = new SubscriptionProcessor(_client, _whConfig, _whm); } DependencyCollection dep; using (var d = new DependencyCollectionBuilder()) { d.AddInstance(_dep = new Dependencies(_interactivity, _whm, _subProcessor, _whConfig, _lang, new StripeService(_whConfig.StripeApiKey))); dep = d.Build(); } _commands = _client.UseCommandsNext ( new CommandsNextConfiguration { StringPrefix = _whConfig.Discord.CommandPrefix?.ToString(), EnableDms = true, EnableMentionPrefix = string.IsNullOrEmpty(_whConfig.Discord.CommandPrefix), EnableDefaultHelp = false, CaseSensitive = false, IgnoreExtraArguments = true, Dependencies = dep } ); _commands.CommandExecuted += Commands_CommandExecuted; _commands.CommandErrored += Commands_CommandErrored; _commands.RegisterCommands <Owner>(); _commands.RegisterCommands <CommunityDay>(); _commands.RegisterCommands <Nests>(); _commands.RegisterCommands <ShinyStats>(); _commands.RegisterCommands <Gyms>(); _commands.RegisterCommands <Quests>(); if (_whConfig.Discord.EnableSubscriptions) { _commands.RegisterCommands <Notifications>(); } if (_whConfig.Discord.EnableCities) { _commands.RegisterCommands <Feeds>(); } }
public async Task ProcessPokemonSubscription(PokemonData pkmn) { if (!MasterFile.Instance.Pokedex.ContainsKey(pkmn.Id)) { return; } var loc = _whm.GetGeofence(pkmn.Latitude, pkmn.Longitude); if (loc == null) { //_logger.Warn($"Failed to lookup city from coordinates {pkmn.Latitude},{pkmn.Longitude} {db.Pokemon[pkmn.Id].Name} {pkmn.IV}, skipping..."); return; } var subscriptions = Manager.GetUserSubscriptionsByPokemonId(pkmn.Id); if (subscriptions == null) { _logger.Warn($"Failed to get subscriptions from database table."); return; } SubscriptionObject user; PokemonSubscription subscribedPokemon; DiscordMember member = null; var pokemon = MasterFile.GetPokemon(pkmn.Id, pkmn.FormId); var matchesIV = false; var matchesLvl = false; var matchesGender = false; var matchesIVList = false; for (var i = 0; i < subscriptions.Count; i++) { try { user = subscriptions[i]; if (user == null) { continue; } if (!user.Enabled) { continue; } if (!_whConfig.Servers.ContainsKey(user.GuildId)) { continue; } if (!_whConfig.Servers[user.GuildId].Subscriptions.Enabled) { continue; } if (!_servers.ContainsKey(user.GuildId)) { continue; } var client = _servers[user.GuildId]; try { member = await client.GetMemberById(user.GuildId, user.UserId); } catch (Exception ex) { _logger.Debug($"FAILED TO GET MEMBER BY ID {user.UserId}"); _logger.Error(ex); continue; } if (member?.Roles == null || loc == null) { continue; } if (!member.HasSupporterRole(_whConfig.Servers[user.GuildId].DonorRoleIds)) { _logger.Debug($"User {member?.Username} ({user.UserId}) is not a supporter, skipping pokemon {pokemon.Name}..."); // Automatically disable users subscriptions if not supporter to prevent issues user.Enabled = false; user.Save(false); continue; } var form = Translator.Instance.GetFormName(pkmn.FormId); subscribedPokemon = user.Pokemon.FirstOrDefault(x => x.PokemonId == pkmn.Id && (string.IsNullOrEmpty(x.Form) || (!string.IsNullOrEmpty(x.Form) && string.Compare(x.Form, form, true) == 0)) ); // Not subscribed to Pokemon if (subscribedPokemon == null) { _logger.Info($"User {member.Username} not subscribed to Pokemon {pokemon.Name} (Form: {form})."); continue; } matchesIV = Filters.MatchesIV(pkmn.IV, subscribedPokemon.MinimumIV); //var matchesCP = _whm.Filters.MatchesCpFilter(pkmn.CP, subscribedPokemon.MinimumCP); matchesLvl = Filters.MatchesLvl(pkmn.Level, (uint)subscribedPokemon.MinimumLevel, (uint)subscribedPokemon.MaximumLevel); matchesGender = Filters.MatchesGender(pkmn.Gender, subscribedPokemon.Gender); matchesIVList = subscribedPokemon.IVList?.Contains($"{pkmn.Attack}/{pkmn.Defense}/{pkmn.Stamina}") ?? false; if (!( (/*!subscribedPokemon.HasStats && */ matchesIV && matchesLvl && matchesGender) || (subscribedPokemon.HasStats && matchesIVList) )) { continue; } var distanceMatches = user.DistanceM > 0 && user.DistanceM > new Coordinates(user.Latitude, user.Longitude).DistanceTo(new Coordinates(pkmn.Latitude, pkmn.Longitude)); var geofenceMatches = subscribedPokemon.Areas.Select(x => x.ToLower()).Contains(loc.Name.ToLower()); // If set distance does not match and no geofences match, then skip Pokemon... if (!distanceMatches && !geofenceMatches) { continue; } var embed = await pkmn.GeneratePokemonMessage(user.GuildId, client, _whConfig, null, loc.Name); foreach (var emb in embed.Embeds) { _queue.Enqueue(new NotificationItem(user, member, emb, pokemon.Name, loc.Name, pkmn)); } Statistics.Instance.SubscriptionPokemonSent++; Thread.Sleep(5); } catch (Exception ex) { _logger.Error(ex); } } subscriptions.Clear(); subscriptions = null; member = null; user = null; loc = null; pokemon = null; await Task.CompletedTask; }
public async Task ProcessRaidSubscription(RaidData raid) { if (!MasterFile.Instance.Pokedex.ContainsKey(raid.PokemonId)) { return; } // Cache the result per-guild so that geospatial stuff isn't queried for every single subscription below Dictionary <ulong, GeofenceItem> locationCache = new Dictionary <ulong, GeofenceItem>(); GeofenceItem GetGeofence(ulong guildId) { if (!locationCache.TryGetValue(guildId, out var geofence)) { geofence = _whm.GetGeofence(guildId, raid.Latitude, raid.Longitude); locationCache.Add(guildId, geofence); } return(geofence); } var subscriptions = Manager.GetUserSubscriptionsByRaidBossId(raid.PokemonId); if (subscriptions == null) { _logger.Warn($"Failed to get subscriptions from database table."); return; } SubscriptionObject user; var pokemon = MasterFile.GetPokemon(raid.PokemonId, raid.Form); for (int i = 0; i < subscriptions.Count; i++) { //var start = DateTime.Now; try { user = subscriptions[i]; if (user == null) { continue; } if (!user.Enabled) { continue; } if (!_whConfig.Instance.Servers.ContainsKey(user.GuildId)) { continue; } if (!_whConfig.Instance.Servers[user.GuildId].Subscriptions.Enabled) { continue; } if (!_servers.ContainsKey(user.GuildId)) { continue; } var client = _servers[user.GuildId]; var member = await client.GetMemberById(user.GuildId, user.UserId); if (member == null) { _logger.Warn($"Failed to find member with id {user.UserId}."); continue; } if (!member.HasSupporterRole(_whConfig.Instance.Servers[user.GuildId].DonorRoleIds)) { _logger.Info($"User {user.UserId} is not a supporter, skipping raid boss {pokemon.Name}..."); // Automatically disable users subscriptions if not supporter to prevent issues //user.Enabled = false; //user.Save(false); continue; } var form = Translator.Instance.GetFormName(raid.Form); var subPkmn = user.Raids.FirstOrDefault(x => x.PokemonId == raid.PokemonId && (string.IsNullOrEmpty(x.Form) || (!string.IsNullOrEmpty(x.Form) && string.Compare(x.Form, form, true) == 0)) ); // Not subscribed to Pokemon if (subPkmn == null) { //_logger.Debug($"Skipping notification for user {member.DisplayName} ({member.Id}) for raid boss {pokemon.Name}, raid is in city '{loc.Name}'."); continue; } var geofence = GetGeofence(user.GuildId); if (geofence == null) { //_logger.Warn($"Failed to lookup city from coordinates {pkmn.Latitude},{pkmn.Longitude} {db.Pokemon[pkmn.Id].Name} {pkmn.IV}, skipping..."); continue; } var distanceMatches = user.DistanceM > 0 && user.DistanceM > new Coordinates(user.Latitude, user.Longitude).DistanceTo(new Coordinates(raid.Latitude, raid.Longitude)); var geofenceMatches = subPkmn.Areas.Select(x => x.ToLower()).Contains(geofence.Name.ToLower()); // If set distance does not match and no geofences match, then skip Pokemon... if (!distanceMatches && !geofenceMatches) { continue; } var embed = raid.GenerateRaidMessage(user.GuildId, client, _whConfig.Instance, null, geofence.Name); //var end = DateTime.Now; //_logger.Debug($"Took {end} to process raid subscription for user {user.UserId}"); embed.Embeds.ForEach(x => _queue.Enqueue(new NotificationItem(user, member, x, pokemon.Name, geofence.Name))); Statistics.Instance.SubscriptionRaidsSent++; Thread.Sleep(5); } catch (Exception ex) { _logger.Error(ex); } } subscriptions.Clear(); subscriptions = null; user = null; await Task.CompletedTask; }
public async Task ProcessRaidSubscription(RaidData raid) { if (!MasterFile.Instance.Pokedex.ContainsKey(raid.PokemonId)) { return; } var loc = _whm.GetGeofence(raid.Latitude, raid.Longitude); if (loc == null) { //_logger.Warn($"Failed to lookup city for coordinates {raid.Latitude},{raid.Longitude}, skipping..."); return; } var subscriptions = Manager.GetUserSubscriptionsByRaidBossId(raid.PokemonId); if (subscriptions == null) { _logger.Warn($"Failed to get subscriptions from database table."); return; } SubscriptionObject user; var pokemon = MasterFile.GetPokemon(raid.PokemonId, raid.Form); for (int i = 0; i < subscriptions.Count; i++) { try { user = subscriptions[i]; if (user == null) { continue; } if (!user.Enabled) { continue; } if (!_whConfig.Servers.ContainsKey(user.GuildId)) { continue; } if (!_whConfig.Servers[user.GuildId].EnableSubscriptions) { continue; } if (!_servers.ContainsKey(user.GuildId)) { continue; } var client = _servers[user.GuildId]; var member = await client.GetMemberById(user.GuildId, user.UserId); if (member == null) { _logger.Warn($"Failed to find member with id {user.UserId}."); continue; } if (!member.HasSupporterRole(_whConfig.Servers[user.GuildId].DonorRoleIds)) { _logger.Info($"User {user.UserId} is not a supporter, skipping raid boss {pokemon.Name}..."); continue; } // Only check distance if user has it set if (user.DistanceM > 0) { var distance = new Coordinates(user.Latitude, user.Longitude).DistanceTo(new Coordinates(raid.Latitude, raid.Longitude)); if (user.DistanceM < distance) { //Skip if distance is set and is not met. _logger.Debug($"Skipping notification for user {member.DisplayName} ({member.Id}) for raid boss {pokemon.Name}, raid is farther than set distance of '{user.DistanceM} meters."); continue; } } if (user.Gyms.Count > 0 && (!user.Gyms?.Exists(x => !string.IsNullOrEmpty(x?.Name) && ( (raid.GymName?.ToLower()?.Contains(x.Name?.ToLower()) ?? false) || (raid.GymName?.ToLower()?.StartsWith(x.Name?.ToLower()) ?? false) ) ) ?? false)) { //Skip if list is not empty and gym is not in list. _logger.Debug($"Skipping notification for user {member.DisplayName} ({member.Id}) for raid boss {pokemon.Name}, raid '{raid.GymName}' is not in list of subscribed gyms."); continue; } var form = Translator.Instance.GetFormName(raid.Form); var exists = user.Raids.FirstOrDefault(x => x.PokemonId == raid.PokemonId && (string.IsNullOrEmpty(x.Form) || string.Compare(x.Form, form, true) == 0) && (string.IsNullOrEmpty(x.City) || (!string.IsNullOrEmpty(x.City) && string.Compare(loc.Name, x.City, true) == 0)) ) != null; if (!exists) { //_logger.Debug($"Skipping notification for user {member.DisplayName} ({member.Id}) for raid boss {pokemon.Name}, raid is in city '{loc.Name}'."); continue; } var embed = raid.GenerateRaidMessage(user.GuildId, client, _whConfig, null, loc.Name); foreach (var emb in embed.Embeds) { _queue.Enqueue(new NotificationItem(user, member, emb, pokemon.Name, loc.Name)); } Statistics.Instance.SubscriptionRaidsSent++; Thread.Sleep(5); } catch (Exception ex) { _logger.Error(ex); } } subscriptions.Clear(); subscriptions = null; user = null; loc = null; await Task.CompletedTask; }
private async Task Client_Ready(ReadyEventArgs e) { _logger.Info($"Connected."); await _client.UpdateStatusAsync(new DiscordGame("Your lobby is waiting...")); }
public async Task DeployPoGoAsync(CommandContext ctx, [Description("iPhone names i.e. `iPhoneAB1SE`. Comma delimiter supported `iPhoneAB1SE,iPhoneCD2SE`"), RemainingText] string phoneNames = Strings.All) { if (!ctx.Member.HasRequiredRoles(_dep.Config.RequiredRoles)) { await ctx.RespondAsync($":no_entry: {ctx.User.Username} Unauthorized permissions."); return; } if (!ctx.Channel.Id.IsValidChannel(_dep.Config.ChannelIds)) { return; } var devices = Device.GetAll(); var deployAppDevices = new List <string>(phoneNames.RemoveSpaces()); if (string.Compare(phoneNames, Strings.All, true) == 0) { deployAppDevices = devices.Keys.ToList(); } var appPath = IpaDeployer.GetLatestAppPath(); if (string.IsNullOrEmpty(appPath)) { await ctx.RespondAsync($"No signed app found, make sure to run 'resign' command first."); return; } var deployer = new IpaDeployer(_dep.Config.Developer, _dep.Config.ProvisioningProfile); _logger.Debug($"Using app {appPath} for deployment."); //deployer.Deploy(appPath); Parallel.ForEach(deployAppDevices, async deviceName => { if (!devices.ContainsKey(deviceName)) { _logger.Warn($"{deviceName} does not exist in device list, skipping deploy pogo."); } else { var device = devices[deviceName]; var args = $"--id {device.Uuid} --bundle {appPath}"; _logger.Info($"Deploying to device {device.Name} ({device.Uuid})..."); var output = Shell.Execute("ios-deploy", args, out var exitCode, true); _logger.Debug($"{device.Name} ({device.Uuid}) Deployment output: {output}"); var success = output.ToLower().Contains($"[100%] installed package {appPath}"); if (success) { await ctx.RespondAsync($"Deployed {appPath} to {device.Name} ({device.Uuid}) successfully."); } else { if (output.Length > 2000) { output = string.Join("", output.TakeLast(1900)); } await ctx.RespondAsync($"Failed to deploy {appPath} to {device.Name} ({device.Uuid})\nOutput: {output}"); } } }); }
public async Task ProcessAlarms(PokemonData pkmn, Dictionary <string, List <AlarmObject> > alarms) { if (pkmn == null) { return; } if (alarms == null || alarms.Count == 0) { return; } if (_db == null) { _logger.Error($"Database is not initialized..."); return; } if (!_db.Pokemon.ContainsKey(pkmn.Id.ToString())) { return; } var pokemon = _db.Pokemon[pkmn.Id.ToString()]; if (pokemon == null) { return; } if (_client == null) { return; } foreach (var item in alarms) { foreach (var alarm in item.Value) { //if (string.Compare(alarm.Geofence.Name, item.Key, true) != 0) // continue; if (!MatchesGeofenceFilter(alarm.Geofence, new Location(pkmn.Latitude, pkmn.Longitude))) { continue; } if (!_filters.AlarmMatchesIV(pkmn.IV, alarm.Filters)) { continue; } var embed = BuildEmbedPokemonFromAlarm(pkmn, alarm); if (embed == null) { continue; } _logger.Info($"Notifying alarm {alarm.Name} that a {pokemon.Name} {pkmn.CP}CP {pkmn.IV} IV L{pkmn.Level} has spawned..."); Notify(pokemon.Name, embed); await _client.SendMessage(alarm.Webhook, null, embed); } } }
public async Task ProcessPokemonSubscription(PokemonData pkmn) { if (!MasterFile.Instance.Pokedex.ContainsKey(pkmn.Id)) { return; } var loc = _whm.GetGeofence(pkmn.Latitude, pkmn.Longitude); if (loc == null) { //_logger.Warn($"Failed to lookup city from coordinates {pkmn.Latitude},{pkmn.Longitude} {db.Pokemon[pkmn.Id].Name} {pkmn.IV}, skipping..."); return; } var subscriptions = Manager.GetUserSubscriptionsByPokemonId(pkmn.Id); if (subscriptions == null) { _logger.Warn($"Failed to get subscriptions from database table."); return; } SubscriptionObject user; PokemonSubscription subscribedPokemon; DiscordMember member = null; var pokemon = MasterFile.GetPokemon(pkmn.Id, pkmn.FormId); var matchesIV = false; var matchesLvl = false; var matchesGender = false; var matchesIVList = false; for (var i = 0; i < subscriptions.Count; i++) { try { user = subscriptions[i]; if (user == null) { continue; } if (!user.Enabled) { continue; } if (!_whConfig.Servers.ContainsKey(user.GuildId)) { continue; } if (!_whConfig.Servers[user.GuildId].EnableSubscriptions) { continue; } if (!_servers.ContainsKey(user.GuildId)) { continue; } var client = _servers[user.GuildId]; try { member = await client.GetMemberById(user.GuildId, user.UserId); } catch (Exception ex) { _logger.Debug($"FAILED TO GET MEMBER BY ID {user.UserId}"); _logger.Error(ex); continue; } if (!member.HasSupporterRole(_whConfig.Servers[user.GuildId].DonorRoleIds)) { _logger.Debug($"User {member?.Username} ({user.UserId}) is not a supporter, skipping pokemon {pokemon.Name}..."); continue; } if (member?.Roles == null || loc == null) { continue; } if (!member.Roles.Select(x => x?.Name?.ToLower()).Contains(loc?.Name?.ToLower())) { //_logger.Info($"User {member.Username} does not have city role {loc.Name}, skipping pokemon {pokemon.Name}."); continue; } /* * var exists = user.Pokemon.Exists(x => string.IsNullOrEmpty(x.City) || (!string.IsNullOrEmpty(x.City) && string.Compare(loc.Name, x.City, true) == 0)); * if (!exists) * { * //_logger.Debug($"Skipping notification for user {member.DisplayName} ({member.Id}) for Pokemon {pokemon.PokemonId} because the Pokemon is in city '{loc.Name}'."); * continue; * } */ // Only check distance if user has it set if (user.DistanceM > 0) { var distance = new Coordinates(user.Latitude, user.Longitude).DistanceTo(new Coordinates(pkmn.Latitude, pkmn.Longitude)); if (user.DistanceM < distance) { //Skip if distance is set and is not with specified distance. //_logger.Debug($"Skipping notification for user {member.DisplayName} ({member.Id}) for Pokemon {pokemon.Name}, Pokemon is farther than set distance of '{user.DistanceM:N0}' meters at '{distance:N0}' meters away."); continue; } _logger.Debug($"Distance matches for user {member.DisplayName} ({member.Id}) for Pokemon {pokemon.Name}: {distance}/{user.DistanceM}"); } var form = Translator.Instance.GetFormName(pkmn.FormId); subscribedPokemon = user.Pokemon.FirstOrDefault(x => x.PokemonId == pkmn.Id && (string.IsNullOrEmpty(x.Form) || (!string.IsNullOrEmpty(x.Form) && string.Compare(x.Form, form, true) == 0)) && (string.IsNullOrEmpty(x.City) || (!string.IsNullOrEmpty(x.City) && string.Compare(loc.Name, x.City, true) == 0)) ); if (subscribedPokemon == null) { _logger.Info($"User {member.Username} not subscribed to Pokemon {pokemon.Name} (Form: {form})."); continue; } matchesIV = Filters.MatchesIV(pkmn.IV, subscribedPokemon.MinimumIV); //var matchesCP = _whm.Filters.MatchesCpFilter(pkmn.CP, subscribedPokemon.MinimumCP); matchesLvl = Filters.MatchesLvl(pkmn.Level, (uint)subscribedPokemon.MinimumLevel, (uint)subscribedPokemon.MaximumLevel); matchesGender = Filters.MatchesGender(pkmn.Gender, subscribedPokemon.Gender); matchesIVList = subscribedPokemon.IVList?.Contains($"{pkmn.Attack}/{pkmn.Defense}/{pkmn.Stamina}") ?? false; if (!( (/*!subscribedPokemon.HasStats && */ matchesIV && matchesLvl && matchesGender) || (subscribedPokemon.HasStats && matchesIVList) )) { continue; } var embed = await pkmn.GeneratePokemonMessage(user.GuildId, client, _whConfig, null, loc.Name); foreach (var emb in embed.Embeds) { _queue.Enqueue(new NotificationItem(user, member, emb, pokemon.Name, loc.Name, pkmn)); } Statistics.Instance.SubscriptionPokemonSent++; Thread.Sleep(5); } catch (Exception ex) { _logger.Error(ex); } } subscriptions.Clear(); subscriptions = null; member = null; user = null; loc = null; pokemon = null; await Task.CompletedTask; }
/// <summary> /// Discord bot class /// </summary> /// <param name="whConfig">Configuration settings</param> public Bot(WhConfigHolder whConfig) { _logger.Trace($"WhConfig [Servers={whConfig.Instance.Servers.Count}, Port={whConfig.Instance.WebhookPort}]"); _servers = new Dictionary <ulong, DiscordClient>(); _whConfig = whConfig; _whm = new WebhookController(_whConfig); // Build form lists for icons IconFetcher.Instance.SetIconStyles(_whConfig.Instance.IconStyles); // Set translation language Translator.Instance.SetLocale(_whConfig.Instance.Locale); // Set database connection strings to static properties so we can access within our extension classes DataAccessLayer.ConnectionString = _whConfig.Instance.Database.Main.ToString(); DataAccessLayer.ScannerConnectionString = _whConfig.Instance.Database.Scanner.ToString(); // Set unhandled exception event handler AppDomain.CurrentDomain.UnhandledException += UnhandledExceptionHandler; // Initialize and start midnight reset timer var midnight = new DandTSoftware.Timers.MidnightTimer(); midnight.TimeReached += async(e) => await OnMidnightTimer(); midnight.Start(); // Initialize the subscription processor if at least one Discord server wants custom notifications // and start database migrator if (_whConfig.Instance.Servers.Values.ToList().Exists(x => x.Subscriptions.Enabled)) { // Start database migrator var migrator = new DatabaseMigrator(); while (!migrator.Finished) { Thread.Sleep(50); } _subProcessor = new SubscriptionProcessor(_servers, _whConfig, _whm); } // Create a DiscordClient object per Discord server in config foreach (var(guildId, serverConfig) in _whConfig.Instance.Servers) { serverConfig.LoadDmAlerts(); var client = new DiscordClient(new DiscordConfiguration { AutomaticGuildSync = true, AutoReconnect = true, EnableCompression = true, Token = serverConfig.Token, TokenType = TokenType.Bot, UseInternalLogHandler = true }); // If you are on Windows 7 and using .NETFX, install // DSharpPlus.WebSocket.WebSocket4Net from NuGet, // add appropriate usings, and uncomment the following // line //client.SetWebSocketClient<WebSocket4NetClient>(); // If you are on Windows 7 and using .NET Core, install // DSharpPlus.WebSocket.WebSocket4NetCore from NuGet, // add appropriate usings, and uncomment the following // line //client.SetWebSocketClient<WebSocket4NetCoreClient>(); // If you are using Mono, install // DSharpPlus.WebSocket.WebSocketSharp from NuGet, // add appropriate usings, and uncomment the following // line //client.SetWebSocketClient<WebSocketSharpClient>(); client.Ready += Client_Ready; client.GuildAvailable += Client_GuildAvailable; client.GuildMemberUpdated += Client_GuildMemberUpdated; //_client.MessageCreated += Client_MessageCreated; client.ClientErrored += Client_ClientErrored; client.DebugLogger.LogMessageReceived += DebugLogger_LogMessageReceived; // Configure Discord interactivity module var interactivity = client.UseInteractivity ( new InteractivityConfiguration { // default pagination behaviour to just ignore the reactions PaginationBehaviour = TimeoutBehaviour.Ignore, // default pagination timeout to 5 minutes PaginationTimeout = TimeSpan.FromMinutes(5), // default timeout for other actions to 2 minutes Timeout = TimeSpan.FromMinutes(2) } ); // Build the dependency collection which will contain our objects that can be globally used within each command module DependencyCollection dep; using (var d = new DependencyCollectionBuilder()) { d.AddInstance(new Dependencies(interactivity, _whm, _subProcessor, _whConfig, new StripeService(_whConfig.Instance.StripeApiKey))); dep = d.Build(); } // Discord commands configuration var commands = client.UseCommandsNext ( new CommandsNextConfiguration { StringPrefix = serverConfig.CommandPrefix?.ToString(), EnableDms = true, // If command prefix is null, allow for mention prefix EnableMentionPrefix = string.IsNullOrEmpty(serverConfig.CommandPrefix), // Use DSharpPlus's built-in help formatter EnableDefaultHelp = true, CaseSensitive = false, IgnoreExtraArguments = true, Dependencies = dep } ); commands.CommandExecuted += Commands_CommandExecuted; commands.CommandErrored += Commands_CommandErrored; // Register Discord command handler classes commands.RegisterCommands <Owner>(); commands.RegisterCommands <Event>(); commands.RegisterCommands <Nests>(); commands.RegisterCommands <ShinyStats>(); commands.RegisterCommands <Gyms>(); commands.RegisterCommands <Quests>(); commands.RegisterCommands <Settings>(); if (serverConfig.Subscriptions.Enabled) { commands.RegisterCommands <Notifications>(); } if (serverConfig.EnableCities) { commands.RegisterCommands <Feeds>(); } _logger.Info($"Configured Discord server {guildId}"); if (!_servers.ContainsKey(guildId)) { _servers.Add(guildId, client); } // Wait 3 seconds between initializing Discord clients Task.Delay(3000).GetAwaiter().GetResult(); } RegisterConfigMonitor(); }
private void InitializeTimer() { try { #pragma warning disable RECS0165 _timer = new Timer(async x => #pragma warning restore RECS0165 { foreach (var user in _db.Reminders) { var itemsToRemove = new List <Reminder>(); foreach (var reminder in user.Value) { _logger.Info($"Reminder for user {user.Key} {DateTime.UtcNow.Subtract(reminder.Time)} time left."); if (reminder.Time.CompareTo(DateTime.UtcNow) <= 0) { var userToRemind = await _client.GetUser(user.Key); if (userToRemind == null) { _logger.Error($"Failed to find discord user with id '{user.Key}'."); continue; } _logger.Info($"NOTIFYING USER OF REMINDER: {reminder.Message}"); if (reminder.Where == 0) { await _client.SendDirectMessage(userToRemind, $":alarm_clock: **Reminder:** {reminder.Message}", null); } else { var channel = await _client.GetChannel(reminder.Where); if (channel == null) { _logger.Error($"Failed to find channel {reminder.Where} that reminder should be sent to, sending via DM instead..."); await _client.SendDirectMessage(userToRemind, $":alarm_clock: **Reminder:** {reminder.Message}", null); } else { await channel.SendMessageAsync($":alarm_clock: {userToRemind.Mention} **Reminder:** {reminder.Message}"); } } itemsToRemove.Add(reminder); } } foreach (var remove in itemsToRemove) { user.Value.Remove(remove); } _db.Reminders.TryUpdate(user.Key, user.Value, user.Value); } ChangeToClosestInterval(); _db.Save(); }, null, TimeSpan.FromSeconds(INITIAL_DELAY), // Time that message should fire after bot has started TimeSpan.FromSeconds(INITIAL_DELAY)); //time after which message should repeat (timout.infinite for no repeat) } catch (Exception ex) { Utils.LogError(ex); } }
public async Task ProcessPokemonSubscription(PokemonData pkmn) { if (!_whConfig.Discord.EnableSubscriptions) { return; } var db = Database.Instance; if (!db.Pokemon.ContainsKey(pkmn.Id)) { return; } var loc = _whm.GetGeofence(pkmn.Latitude, pkmn.Longitude); if (loc == null) { //_logger.Warn($"Failed to lookup city from coordinates {pkmn.Latitude},{pkmn.Longitude} {db.Pokemon[pkmn.Id].Name} {pkmn.IV}, skipping..."); return; } var subscriptions = Manager.GetUserSubscriptionsByPokemonId(pkmn.Id); if (subscriptions == null) { _logger.Warn($"Failed to get subscriptions from database table."); return; } SubscriptionObject user; PokemonSubscription subscribedPokemon; DiscordMember member = null; var pokemon = db.Pokemon[pkmn.Id]; var matchesIV = false; var matchesLvl = false; var matchesGender = false; var matchesAttack = false; var matchesDefense = false; var matchesStamina = false; for (var i = 0; i < subscriptions.Count; i++) { try { user = subscriptions[i]; if (user == null) { continue; } if (!user.Enabled) { continue; } try { member = await _client.GetMemberById(_whConfig.Discord.GuildId, user.UserId); } catch (Exception ex) { _logger.Debug($"FAILED TO GET MEMBER BY ID {user.UserId}"); _logger.Error(ex); continue; } if (!member.HasSupporterRole(_whConfig.Discord.DonorRoleIds)) { _logger.Debug($"User {member?.Username} ({user.UserId}) is not a supporter, skipping pokemon {pokemon.Name}..."); continue; } if (member?.Roles == null || loc == null) { continue; } if (!member.Roles.Select(x => x?.Name?.ToLower()).Contains(loc?.Name?.ToLower())) { //_logger.Info($"User {member.Username} does not have city role {loc.Name}, skipping pokemon {pokemon.Name}."); continue; } if (user.DistanceM > 0) { var distance = new Coordinates(user.Latitude, user.Longitude).DistanceTo(new Coordinates(pkmn.Latitude, pkmn.Longitude)); if (user.DistanceM < distance) { //Skip if distance is set and is not with specified distance. _logger.Debug($"Skipping notification for user {member.DisplayName} ({member.Id}) for Pokemon {pokemon.Name}, Pokemon is farther than set distance of '{user.DistanceM} meters."); continue; } } var form = pkmn.Id.GetPokemonForm(pkmn.FormId.ToString()); subscribedPokemon = user.Pokemon.FirstOrDefault(x => x.PokemonId == pkmn.Id && ((x.Form == null || x.Form == string.Empty) || string.Compare(x.Form, form, true) == 0)); if (subscribedPokemon == null) { _logger.Info($"User {member.Username} not subscribed to Pokemon {pokemon.Name} (Form: {form})."); continue; } matchesIV = _whm.Filters.MatchesIV(pkmn.IV, subscribedPokemon.MinimumIV); //var matchesCP = _whm.Filters.MatchesCpFilter(pkmn.CP, subscribedPokemon.MinimumCP); matchesLvl = _whm.Filters.MatchesLvl(pkmn.Level, subscribedPokemon.MinimumLevel); matchesGender = _whm.Filters.MatchesGender(pkmn.Gender, subscribedPokemon.Gender); matchesAttack = _whm.Filters.MatchesAttack(pkmn.Attack, subscribedPokemon.Attack); matchesDefense = _whm.Filters.MatchesDefense(pkmn.Defense, subscribedPokemon.Defense); matchesStamina = _whm.Filters.MatchesStamina(pkmn.Stamina, subscribedPokemon.Stamina); if (!( (!subscribedPokemon.HasStats && matchesIV && matchesLvl && matchesGender) || (subscribedPokemon.HasStats && matchesAttack && matchesDefense && matchesStamina) )) { continue; } //_logger.Debug($"Notifying user {member.Username} that a {pokemon.Name} {pkmn.CP}CP {pkmn.IV} IV L{pkmn.Level} has spawned..."); var iconStyle = Manager.GetUserIconStyle(user); var embed = await pkmn.GeneratePokemonMessage(_client, _whConfig, pkmn, null, loc.Name, string.Format(_whConfig.IconStyles[iconStyle], pkmn.Id, pkmn.FormId)); _queue.Enqueue(new Tuple <DiscordUser, string, DiscordEmbed>(member, pokemon.Name, embed)); //if (!Manager.AddPokemonStatistic(member.Id, pkmn)) //{ // _logger.Warn($"Failed to add {pokemon.Name} Pokemon statistic for user {user.Id}."); //} Statistics.Instance.SubscriptionPokemonSent++; Thread.Sleep(5); } catch (Exception ex) { _logger.Error(ex); } } subscriptions.Clear(); subscriptions = null; member = null; user = null; loc = null; pokemon = null; db = null; await Task.CompletedTask; }