コード例 #1
0
            internal static void Restart(ulong channelId, string?restartMsg)
            {
                Config.Log.Info($"Saving channelId {channelId} into settings...");
                using var db = new BotDb();
                var ch = db.BotState.FirstOrDefault(k => k.Key == "bot-restart-channel");

                if (ch is null)
                {
                    ch = new BotState {
                        Key = "bot-restart-channel", Value = channelId.ToString()
                    };
                    db.BotState.Add(ch);
                }
                else
                {
                    ch.Value = channelId.ToString();
                }
                var msg = db.BotState.FirstOrDefault(k => k.Key == "bot-restart-msg");

                if (msg is null)
                {
                    msg = new BotState {
                        Key = "bot-restart-msg", Value = restartMsg
                    };
                    db.BotState.Add(msg);
                }
                else
                {
                    msg.Value = restartMsg;
                }
                db.SaveChanges();
                Config.TelemetryClient?.TrackEvent("Restart");
                RestartNoSaving();
            }
コード例 #2
0
        public override void Run(List <DataObject> result)
        {
            List <MessageBase> messages = result.OfType <MessageBase>().ToList();

            if (!messages.Any())
            {
                return;
            }

            int[] messageIds = messages.Select(s => s.MessageId).ToArray();

            using (BotDb db = new BotDb())
            {
                HashSet <int> existing = db.Messages.Where(s => messageIds.Contains(s.MessageId)).Select(s => s.MessageId).ToHashset();

                foreach (MessageBase message in messages.Where(s => !existing.Contains(s.MessageId)))
                {
                    db.Messages.Add(new DbMessage
                    {
                        MessageId = message.MessageId,
                        Message   = message,
                        TabType   = message.TabType
                    });
                }

                db.SaveChanges();
            }
        }
コード例 #3
0
        public override void Run(List <DataObject> result)
        {
            List <EspionageReport> reports = result.OfType <EspionageReport>().ToList();

            if (!reports.Any())
            {
                return;
            }

            using (BotDb db = new BotDb())
            {
                long[] locIds = reports.Select(s => s.Coordinate.Id).ToArray();
                Dictionary <long, DbPlanet> existing = db.Planets.Where(s => locIds.Contains(s.LocationId)).ToDictionary(s => s.LocationId);

                foreach (EspionageReport report in reports)
                {
                    Logger.Instance.Log(LogLevel.Info, $"Saving esp report on {report.Coordinate}, level: {report.Details}");

                    DbPlanet item;
                    if (!existing.TryGetValue(report.Coordinate, out item))
                    {
                        item = new DbPlanet
                        {
                            Coordinate = report.Coordinate
                        };

                        db.Planets.Add(item);
                    }

                    if (report.Details.HasFlag(ReportDetails.Resources))
                    {
                        item.Resources         = report.Resources;
                        item.LastResourcesTime = report.Sent;
                    }

                    if (report.Details.HasFlag(ReportDetails.Buildings))
                    {
                        item.PlanetInfo.Buildings = report.DetectedBuildings;
                        item.LastBuildingsTime    = report.Sent;
                    }

                    if (report.Details.HasFlag(ReportDetails.Defense))
                    {
                        item.PlanetInfo.Defences = report.DetectedDefence;
                        item.LastDefencesTime    = report.Sent;
                    }

                    if (report.Details.HasFlag(ReportDetails.Ships))
                    {
                        item.PlanetInfo.Ships = report.DetectedShips;
                        item.LastShipsTime    = report.Sent;
                    }
                }

                db.SaveChanges();
            }
        }
コード例 #4
0
 public static void Clear()
 {
     lock (DisabledCommands)
     {
         DisabledCommands.Clear();
         using var db = new BotDb();
         db.DisabledCommands.RemoveRange(db.DisabledCommands);
         db.SaveChanges();
     }
 }
コード例 #5
0
        public override void Run(List <DataObject> result)
        {
            using (BotDb db = new BotDb())
            {
                var logs = FromGalaxy(result).ToList();

                var newLogs = logs.Where(log => !db.PlanetActivityLog.Where(existing => existing.LocationId == log.LocationId && existing.CreatedOn == log.CreatedOn).Any());
                db.PlanetActivityLog.AddRange(newLogs);
                db.SaveChanges();
            }
        }
コード例 #6
0
 public static void Disable(string command)
 {
     lock (DisabledCommands)
         if (DisabledCommands.Add(command))
         {
             using var db = new BotDb();
             db.DisabledCommands.Add(new DisabledCommand {
                 Command = command
             });
             db.SaveChanges();
         }
 }
コード例 #7
0
        private void ProcessData(PlayersContainer model)
        {
            using (BotDb db = new BotDb())
            {
                Dictionary <int, Db.Player> allPlayers = db.Players.ToDictionary(s => s.PlayerId);
                List <Db.Player>            newPlayers = new List <Db.Player>();

                for (int i = 0; i < model.Players.Length; i++)
                {
                    var       player = model.Players[i];
                    Db.Player dbPlayer;
                    if (!allPlayers.TryGetValue(player.Id, out dbPlayer))
                    {
                        dbPlayer = new Db.Player
                        {
                            PlayerId = player.Id
                        };

                        newPlayers.Add(dbPlayer);
                        allPlayers[player.Id] = dbPlayer;
                    }

                    dbPlayer.Name   = player.Name;
                    dbPlayer.Status = ParseStatus(player.Status);

                    if (i % 250 == 0)
                    {
                        db.Players.AddRange(newPlayers);

                        db.SaveChanges();

                        newPlayers.Clear();
                    }
                }

                db.Players.AddRange(newPlayers);

                db.SaveChanges();
            }
        }
コード例 #8
0
            private void Run(CommandQueueElement next, BotDb db)
            {
                lock (_lock)
                {
                    if (next.Id == 0)
                    {
                        db.CommandQueue.Add(next);
                        db.SaveChanges();
                    }
                    else
                    {
                        db.CommandQueue.Attach(next);
                    }
                    // Execute
                    if ((next.ScheduledAt ?? DateTimeOffset.Now) <= DateTimeOffset.Now)
                    {
                        Logger.Instance.Log(LogLevel.Debug, $"Running {next.Command} (id: {next.Id})");
                        CommandQueueElement following = next.Command.RunInternal();
                        next.ScheduledAt = null;
                        Logger.Instance.Log(LogLevel.Debug, $"Finished {next.Command} (id: {next.Id})");

                        if (following != null)
                        {
                            if (following.Command == next.Command)
                            {
                                next.ScheduledAt = following.ScheduledAt;
                                Logger.Instance.Log(LogLevel.Debug, $"Requeueing {next.Command} (id: {next.Id})");
                            }
                            else
                            {
                                db.CommandQueue.Add(following);
                                Logger.Instance.Log(LogLevel.Debug, $"Queueing {following.Command} (id: {following.Id}, by: {next.Id})");
                            }
                        }
                        db.SaveChanges();
                    }
                }
            }
コード例 #9
0
        private void ProcessData(HighscoreContainer model)
        {
            using (BotDb db = new BotDb())
            {
                Dictionary <int, Db.Player> allPlayers = db.Players.ToDictionary(s => s.PlayerId);

                for (int i = 0; i < model.Highscores.Length; i++)
                {
                    var       highscore = model.Highscores[i];
                    Db.Player dbPlayer;
                    if (allPlayers.TryGetValue(highscore.Id, out dbPlayer))
                    {
                        dbPlayer.Ranking = highscore.Position;

                        if (i % 250 == 0)
                        {
                            db.SaveChanges();
                        }
                    }
                }
                db.SaveChanges();
            }
        }
コード例 #10
0
        public static void Enable(string command)
        {
            lock (DisabledCommands)
                if (DisabledCommands.Remove(command))
                {
                    using var db = new BotDb();
                    var cmd = db.DisabledCommands.FirstOrDefault(c => c.Command == command);
                    if (cmd == null)
                    {
                        return;
                    }

                    db.DisabledCommands.Remove(cmd);
                    db.SaveChanges();
                }
        }
コード例 #11
0
        public override void Run(List <DataObject> result)
        {
            GalaxyPageSystem systemDetails = result.OfType <GalaxyPageSystem>().FirstOrDefault();

            if (systemDetails == null)
            {
                return;
            }

            using (BotDb db = new BotDb())
            {
                long lower = systemDetails.System.LowerCoordinate;
                long upper = systemDetails.System.UpperCoordinate;

                Dictionary <long, DebrisField> toRemove = db.DebrisFields.Where(s => lower <= s.LocationId && s.LocationId <= upper).ToDictionary(s => s.LocationId);

                foreach (GalaxyPageInfoItem item in result.OfType <GalaxyPageInfoItem>())
                {
                    if (item.DebrisField.Total <= 0)
                    {
                        continue;
                    }

                    DebrisField field;
                    if (!toRemove.TryRemove(item.Planet.Coordinate, out field))
                    {
                        field = new DebrisField
                        {
                            Coordinate = item.Planet.Coordinate
                        };

                        db.DebrisFields.Add(field);
                    }

                    field.LastSeen  = DateTimeOffset.Now;
                    field.Resources = item.DebrisField;
                }

                db.DebrisFields.RemoveRange(toRemove.Values);
                db.SaveChanges();
            }
        }
コード例 #12
0
ファイル: Sudo.Bot.cs プロジェクト: xenia-canary/discord-bot
 internal static void Restart(ulong channelId)
 {
     if (SandboxDetector.Detect() == SandboxType.Docker)
     {
         Config.Log.Info($"Saving channelId {channelId} into settings...");
         using var db = new BotDb();
         var ch = db.BotState.FirstOrDefault(k => k.Key == "bot-restart-channel");
         if (ch is null)
         {
             ch = new BotState {
                 Key = "bot-restart-channel", Value = channelId.ToString()
             };
             db.BotState.Add(ch);
         }
         else
         {
             ch.Value = channelId.ToString();
         }
         db.SaveChanges();
     }
     RestartNoSaving(channelId);
 }
コード例 #13
0
        internal static async Task Main(string[] args)
        {
            Config.TelemetryClient?.TrackEvent("startup");

            Console.WriteLine("Confinement: " + SandboxDetector.Detect());
            if (args.Length > 0 && args[0] == "--dry-run")
            {
                Console.WriteLine("Database path: " + Path.GetDirectoryName(Path.GetFullPath(DbImporter.GetDbPath("fake.db", Environment.SpecialFolder.ApplicationData))));
                if (Assembly.GetEntryAssembly().GetCustomAttribute <UserSecretsIdAttribute>() != null)
                {
                    Console.WriteLine("Bot config path: " + Path.GetDirectoryName(Path.GetFullPath(Config.GoogleApiConfigPath)));
                }
                return;
            }

            if (Process.GetCurrentProcess().Id == 0)
            {
                Config.Log.Info("Well, this was unexpected");
            }
            var singleInstanceCheckThread = new Thread(() =>
            {
                using var instanceLock = new Mutex(false, @"Global\RPCS3 Compatibility Bot");
                if (instanceLock.WaitOne(1000))
                {
                    try
                    {
                        InstanceCheck.Release();
                        ShutdownCheck.Wait();
                    }
                    finally
                    {
                        instanceLock.ReleaseMutex();
                    }
                }
            });

            try
            {
                singleInstanceCheckThread.Start();
                if (!await InstanceCheck.WaitAsync(1000).ConfigureAwait(false))
                {
                    Config.Log.Fatal("Another instance is already running.");
                    return;
                }

                if (string.IsNullOrEmpty(Config.Token) || Config.Token.Length < 16)
                {
                    Config.Log.Fatal("No token was specified.");
                    return;
                }

                if (SandboxDetector.Detect() == SandboxType.Docker)
                {
                    Config.Log.Info("Checking for updates...");
                    try
                    {
                        var(updated, stdout) = await Sudo.Bot.UpdateAsync().ConfigureAwait(false);

                        if (!string.IsNullOrEmpty(stdout) && updated)
                        {
                            Config.Log.Debug(stdout);
                        }
                        if (updated)
                        {
                            Sudo.Bot.Restart(InvalidChannelId, "Restarted due to new bot updates not present in this Docker image");
                            return;
                        }
                    }
                    catch (Exception e)
                    {
                        Config.Log.Error(e, "Failed to check for updates");
                    }
                }

                using (var db = new BotDb())
                    if (!await DbImporter.UpgradeAsync(db, Config.Cts.Token))
                    {
                        return;
                    }

                using (var db = new ThumbnailDb())
                    if (!await DbImporter.UpgradeAsync(db, Config.Cts.Token))
                    {
                        return;
                    }

                await SqlConfiguration.RestoreAsync().ConfigureAwait(false);

                Config.Log.Debug("Restored configuration variables from persistent storage");

                await StatsStorage.RestoreAsync().ConfigureAwait(false);

                Config.Log.Debug("Restored stats from persistent storage");

                var backgroundTasks = Task.WhenAll(
                    AmdDriverVersionProvider.RefreshAsync(),
#if !DEBUG
                    new PsnScraper().RunAsync(Config.Cts.Token),
                    GameTdbScraper.RunAsync(Config.Cts.Token),
#endif
                    StatsStorage.BackgroundSaveAsync(),
                    CompatList.ImportCompatListAsync()
                    );

                try
                {
                    if (!Directory.Exists(Config.IrdCachePath))
                    {
                        Directory.CreateDirectory(Config.IrdCachePath);
                    }
                }
                catch (Exception e)
                {
                    Config.Log.Warn(e, $"Failed to create new folder {Config.IrdCachePath}: {e.Message}");
                }

                var config = new DiscordConfiguration
                {
                    Token            = Config.Token,
                    TokenType        = TokenType.Bot,
                    MessageCacheSize = Config.MessageCacheSize,
                    LoggerFactory    = Config.LoggerFactory,
                };
                using var client = new DiscordClient(config);
                var commands = client.UseCommandsNext(new CommandsNextConfiguration
                {
                    StringPrefixes = new[] { Config.CommandPrefix, Config.AutoRemoveCommandPrefix },
                    Services       = new ServiceCollection().BuildServiceProvider(),
                });
                commands.RegisterConverter(new TextOnlyDiscordChannelConverter());
                commands.RegisterCommands <Misc>();
                commands.RegisterCommands <CompatList>();
                commands.RegisterCommands <Sudo>();
                commands.RegisterCommands <CommandsManagement>();
                commands.RegisterCommands <ContentFilters>();
                commands.RegisterCommands <Warnings>();
                commands.RegisterCommands <Explain>();
                commands.RegisterCommands <Psn>();
                commands.RegisterCommands <Invites>();
                commands.RegisterCommands <Moderation>();
                commands.RegisterCommands <Ird>();
                commands.RegisterCommands <BotMath>();
                commands.RegisterCommands <Pr>();
                commands.RegisterCommands <Events>();
                commands.RegisterCommands <E3>();
                commands.RegisterCommands <Cyberpunk2077>();
                commands.RegisterCommands <Rpcs3Ama>();
                commands.RegisterCommands <BotStats>();
                commands.RegisterCommands <Syscall>();
                commands.RegisterCommands <ForcedNicknames>();
                commands.RegisterCommands <Minesweeper>();

                if (!string.IsNullOrEmpty(Config.AzureComputerVisionKey))
                {
                    commands.RegisterCommands <Vision>();
                }

                commands.CommandErrored += UnknownCommandHandler.OnError;

                client.UseInteractivity(new InteractivityConfiguration());

                client.Ready += async(c, _) =>
                {
                    var admin = await c.GetUserAsync(Config.BotAdminId).ConfigureAwait(false);

                    Config.Log.Info("Bot is ready to serve!");
                    Config.Log.Info("");
                    Config.Log.Info($"Bot user id : {c.CurrentUser.Id} ({c.CurrentUser.Username})");
                    Config.Log.Info($"Bot admin id : {Config.BotAdminId} ({admin.Username ?? "???"}#{admin.Discriminator ?? "????"})");
                    Config.Log.Info("");
                };
                client.GuildAvailable += async(c, gaArgs) =>
                {
                    await BotStatusMonitor.RefreshAsync(c).ConfigureAwait(false);

                    Watchdog.DisconnectTimestamps.Clear();
                    Watchdog.TimeSinceLastIncomingMessage.Restart();
                    if (gaArgs.Guild.Id != Config.BotGuildId)
                    {
#if DEBUG
                        Config.Log.Warn($"Unknown discord server {gaArgs.Guild.Id} ({gaArgs.Guild.Name})");
#else
                        Config.Log.Warn($"Unknown discord server {gaArgs.Guild.Id} ({gaArgs.Guild.Name}), leaving...");
                        await gaArgs.Guild.LeaveAsync().ConfigureAwait(false);
#endif
                        return;
                    }

                    Config.Log.Info($"Server {gaArgs.Guild.Name} is available now");
                    Config.Log.Info($"Checking moderation backlogs in {gaArgs.Guild.Name}...");
                    try
                    {
                        await Task.WhenAll(
                            Starbucks.CheckBacklogAsync(c, gaArgs.Guild).ContinueWith(_ => Config.Log.Info($"Starbucks backlog checked in {gaArgs.Guild.Name}."), TaskScheduler.Default),
                            DiscordInviteFilter.CheckBacklogAsync(c, gaArgs.Guild).ContinueWith(_ => Config.Log.Info($"Discord invites backlog checked in {gaArgs.Guild.Name}."), TaskScheduler.Default)
                            ).ConfigureAwait(false);
                    }
                    catch (Exception e)
                    {
                        Config.Log.Warn(e, "Error running backlog tasks");
                    }
                    Config.Log.Info($"All moderation backlogs checked in {gaArgs.Guild.Name}.");
                };
                client.GuildAvailable   += (c, _) => UsernameValidationMonitor.MonitorAsync(c, true);
                client.GuildUnavailable += (_, guArgs) =>
                {
                    Config.Log.Warn($"{guArgs.Guild.Name} is unavailable");
                    return(Task.CompletedTask);
                };
#if !DEBUG
/*
 *              client.GuildDownloadCompleted += async gdcArgs =>
 *                                               {
 *                                                   foreach (var guild in gdcArgs.Guilds)
 *                                                       await ModProvider.SyncRolesAsync(guild.Value).ConfigureAwait(false);
 *                                               };
 */
#endif
                client.MessageReactionAdded += Starbucks.Handler;
                client.MessageReactionAdded += ContentFilterMonitor.OnReaction;

                client.MessageCreated += (_, __) => { Watchdog.TimeSinceLastIncomingMessage.Restart(); return(Task.CompletedTask); };
                client.MessageCreated += ContentFilterMonitor.OnMessageCreated; // should be first
                client.MessageCreated += GlobalMessageCache.OnMessageCreated;
                var mediaScreenshotMonitor = new MediaScreenshotMonitor(client);
                if (!string.IsNullOrEmpty(Config.AzureComputerVisionKey))
                {
                    client.MessageCreated += mediaScreenshotMonitor.OnMessageCreated;
                }
                client.MessageCreated += ProductCodeLookup.OnMessageCreated;
                client.MessageCreated += LogParsingHandler.OnMessageCreated;
                client.MessageCreated += LogAsTextMonitor.OnMessageCreated;
                client.MessageCreated += DiscordInviteFilter.OnMessageCreated;
                client.MessageCreated += PostLogHelpHandler.OnMessageCreated;
                client.MessageCreated += BotReactionsHandler.OnMessageCreated;
                client.MessageCreated += GithubLinksHandler.OnMessageCreated;
                client.MessageCreated += NewBuildsMonitor.OnMessageCreated;
                client.MessageCreated += TableFlipMonitor.OnMessageCreated;
                client.MessageCreated += IsTheGamePlayableHandler.OnMessageCreated;
                client.MessageCreated += EmpathySimulationHandler.OnMessageCreated;

                client.MessageUpdated += GlobalMessageCache.OnMessageUpdated;
                client.MessageUpdated += ContentFilterMonitor.OnMessageUpdated;
                client.MessageUpdated += DiscordInviteFilter.OnMessageUpdated;
                client.MessageUpdated += EmpathySimulationHandler.OnMessageUpdated;

                client.MessageDeleted += GlobalMessageCache.OnMessageDeleted;
                if (Config.DeletedMessagesLogChannelId > 0)
                {
                    client.MessageDeleted += DeletedMessagesMonitor.OnMessageDeleted;
                }
                client.MessageDeleted += ThumbnailCacheMonitor.OnMessageDeleted;
                client.MessageDeleted += EmpathySimulationHandler.OnMessageDeleted;

                client.MessagesBulkDeleted += GlobalMessageCache.OnMessagesBulkDeleted;

                client.UserUpdated += UsernameSpoofMonitor.OnUserUpdated;
                client.UserUpdated += UsernameZalgoMonitor.OnUserUpdated;

                client.GuildMemberAdded += Greeter.OnMemberAdded;
                client.GuildMemberAdded += UsernameSpoofMonitor.OnMemberAdded;
                client.GuildMemberAdded += UsernameZalgoMonitor.OnMemberAdded;
                client.GuildMemberAdded += UsernameValidationMonitor.OnMemberAdded;

                client.GuildMemberUpdated += UsernameSpoofMonitor.OnMemberUpdated;
                client.GuildMemberUpdated += UsernameZalgoMonitor.OnMemberUpdated;
                client.GuildMemberUpdated += UsernameValidationMonitor.OnMemberUpdated;

                Watchdog.DisconnectTimestamps.Enqueue(DateTime.UtcNow);

                try
                {
                    await client.ConnectAsync().ConfigureAwait(false);
                }
                catch (Exception e)
                {
                    Config.Log.Error(e, "Failed to connect to Discord: " + e.Message);
                    throw;
                }

                ulong? channelId  = null;
                string restartMsg = null;
                using (var db = new BotDb())
                {
                    var chState = db.BotState.FirstOrDefault(k => k.Key == "bot-restart-channel");
                    if (chState != null)
                    {
                        if (ulong.TryParse(chState.Value, out var ch))
                        {
                            channelId = ch;
                        }
                        db.BotState.Remove(chState);
                    }
                    var msgState = db.BotState.FirstOrDefault(i => i.Key == "bot-restart-msg");
                    if (msgState != null)
                    {
                        restartMsg = msgState.Value;
                        db.BotState.Remove(msgState);
                    }
                    db.SaveChanges();
                }
                if (string.IsNullOrEmpty(restartMsg))
                {
                    restartMsg = null;
                }

                if (channelId.HasValue)
                {
                    Config.Log.Info($"Found channelId {channelId}");
                    DiscordChannel channel;
                    if (channelId == InvalidChannelId)
                    {
                        channel = await client.GetChannelAsync(Config.ThumbnailSpamId).ConfigureAwait(false);

                        await channel.SendMessageAsync(restartMsg ?? "Bot has suffered some catastrophic failure and was restarted").ConfigureAwait(false);
                    }
                    else
                    {
                        channel = await client.GetChannelAsync(channelId.Value).ConfigureAwait(false);

                        await channel.SendMessageAsync("Bot is up and running").ConfigureAwait(false);
                    }
                }
                else
                {
                    Config.Log.Debug($"Args count: {args.Length}");
                    var pArgs = args.Select(a => a == Config.Token ? "<Token>" : $"[{a}]");
                    Config.Log.Debug("Args: " + string.Join(" ", pArgs));
                }

                Config.Log.Debug("Running RPCS3 update check thread");
                backgroundTasks = Task.WhenAll(
                    backgroundTasks,
                    NewBuildsMonitor.MonitorAsync(client),
                    Watchdog.Watch(client),
                    InviteWhitelistProvider.CleanupAsync(client),
                    UsernameValidationMonitor.MonitorAsync(client),
                    Psn.Check.MonitorFwUpdates(client, Config.Cts.Token),
                    Watchdog.SendMetrics(client),
                    Watchdog.CheckGCStats(),
                    mediaScreenshotMonitor.ProcessWorkQueue()
                    );

                while (!Config.Cts.IsCancellationRequested)
                {
                    if (client.Ping > 1000)
                    {
                        Config.Log.Warn($"High ping detected: {client.Ping}");
                    }
                    await Task.Delay(TimeSpan.FromMinutes(1), Config.Cts.Token).ContinueWith(dt => { /* in case it was cancelled */ }, TaskScheduler.Default).ConfigureAwait(false);
                }
                await backgroundTasks.ConfigureAwait(false);
            }
            catch (Exception e)
            {
                if (!Config.inMemorySettings.ContainsKey("shutdown"))
                {
                    Config.Log.Fatal(e, "Experienced catastrophic failure, attempting to restart...");
                }
            }
            finally
            {
                Config.TelemetryClient?.Flush();
                ShutdownCheck.Release();
                if (singleInstanceCheckThread.IsAlive)
                {
                    singleInstanceCheckThread.Join(100);
                }
            }
            if (!Config.inMemorySettings.ContainsKey("shutdown"))
            {
                Sudo.Bot.Restart(InvalidChannelId, null);
            }
        }
コード例 #14
0
        public override void Run(List <DataObject> result)
        {
            List <EspionageReport> reports = result.OfType <EspionageReport>().ToList();

            if (!reports.Any())
            {
                return;
            }

            using (BotDb db = new BotDb())
            {
                long[] locIds = reports.Select(s => s.Coordinate.Id).ToArray();
                Dictionary <long, Planet> existing = db.Planets.Where(s => locIds.Contains(s.LocationId)).ToDictionary(s => s.LocationId);

                foreach (EspionageReport report in reports)
                {
                    Logger.Instance.Log(LogLevel.Info, $"Saving esp report on {report.Coordinate}, level: {report.Details}");

                    Planet item;
                    if (!existing.TryGetValue(report.Coordinate, out item))
                    {
                        item = new Planet
                        {
                            Coordinate = report.Coordinate
                        };

                        db.Planets.Add(item);
                    }

                    if (report.Details.HasFlag(ReportDetails.Resources) && (!item.LastResourcesTime.HasValue || report.Sent > item.LastResourcesTime))
                    {
                        item.Resources         = report.Resources;
                        item.LastResourcesTime = report.Sent;
                    }

                    if (report.Details.HasFlag(ReportDetails.Buildings) && item.Buildings.NeedsUpdate(report.Sent))
                    {
                        item.Buildings             = report.DetectedBuildings;
                        item.Buildings.LastUpdated = report.Sent;
                    }

                    if (report.Details.HasFlag(ReportDetails.Defense) && item.Defences.NeedsUpdate(report.Sent))
                    {
                        item.Defences             = report.DetectedDefence;
                        item.Defences.LastUpdated = report.Sent;
                    }

                    if (report.Details.HasFlag(ReportDetails.Ships) && item.Ships.NeedsUpdate(report.Sent))
                    {
                        item.Ships             = report.DetectedShips;
                        item.Ships.LastUpdated = report.Sent;
                    }

                    if (report.Details.HasFlag(ReportDetails.Research) && (item.Player?.Research.NeedsUpdate(report.Sent)).GetValueOrDefault(false))
                    {
                        item.Player.Research             = report.DetectedResearch;
                        item.Player.Research.LastUpdated = report.Sent;
                    }

                    if (report.Details.HasFlag(ReportDetails.Ships) && report.DetectedShips != null)
                    {
                        if (!db.PlanetShipLog.Where(s => s.LocationId == item.Coordinate.Id && s.CreatedOn == report.Sent).Any())
                        {
                            PlanetShipLog log = new PlanetShipLog()
                            {
                                Planet    = item,
                                Ships     = report.DetectedShips,
                                CreatedOn = report.Sent
                            };
                            db.PlanetShipLog.Add(log);
                        }
                    }

                    var strippedTime = report.Sent.TruncateToMinute();

                    if (!db.PlanetActivityLog.Where(s => s.LocationId == item.Coordinate.Id && s.CreatedOn == strippedTime).Any())
                    {
                        PlanetActivityLog log = new PlanetActivityLog()
                        {
                            Planet    = item,
                            Activity  = report.Activity,
                            CreatedOn = strippedTime
                        };
                        db.PlanetActivityLog.Add(log);
                    }
                }

                db.SaveChanges();
            }
        }
コード例 #15
0
        public override void Run(List <DataObject> result)
        {
            OgamePageInfo current = result.OfType <OgamePageInfo>().FirstOrDefault();

            if (current == null)
            {
                return;
            }

            var playerPlanets = result.OfType <PlanetListItem>();

            PlanetResources resources = result.OfType <PlanetResources>().FirstOrDefault();
            var             buildings = result.OfType <DetectedBuilding>().ToDictionary(s => s.Building, s => s.Level);
            var             ships     = result.OfType <DetectedShip>().ToDictionary(s => s.Ship, s => s.Count);
            var             defences  = result.OfType <DetectedDefence>().ToDictionary(s => s.Building, s => s.Count);
            var             research  = result.OfType <DetectedResearch>().ToDictionary(s => s.Research, s => s.Level);

            using (BotDb db = new BotDb())
            {
                long[] locIds = playerPlanets.Select(s => s.Coordinate.Id).ToArray();
                Dictionary <long, Planet> existing = db.Planets.Where(s => locIds.Contains(s.LocationId)).ToDictionary(s => s.LocationId);

                if (!_isPlayerSeeded)
                {
                    if (!db.Players.Where(s => s.PlayerId == current.PlayerId).Any())
                    {
                        db.Players.Add(new Player()
                        {
                            PlayerId = current.PlayerId,
                            Name     = current.PlayerName,
                            Status   = PlayerStatus.None
                        });
                        db.SaveChanges();
                    }
                    _isPlayerSeeded = true;
                }


                foreach (var playerPlanet in playerPlanets)
                {
                    Planet item;

                    if (!existing.TryGetValue(playerPlanet.Coordinate.Id, out item))
                    {
                        item = new Planet()
                        {
                            Coordinate = playerPlanet.Coordinate,
                            Name       = playerPlanet.Name,
                            PlanetId   = playerPlanet.Id,
                            PlayerId   = current.PlayerId
                        };
                        db.Planets.Add(item);
                    }

                    if (resources.Coordinate.Id == playerPlanet.Coordinate.Id)
                    {
                        item.Resources = resources.Resources;
                    }

                    if (current.PlanetId == playerPlanet.Id)
                    {
                        if (ships.Count > 0)
                        {
                            item.Ships.FromPartialResult(ships);
                            item.Ships.LastUpdated = DateTimeOffset.UtcNow;
                        }
                        else if (defences.Count > 0)
                        {
                            item.Defences.FromPartialResult(defences);
                            item.Defences.LastUpdated = DateTimeOffset.UtcNow;
                        }
                        else if (buildings.Count > 0)
                        {
                            item.Buildings.FromPartialResult(buildings);
                            item.Buildings.LastUpdated = DateTimeOffset.UtcNow;
                        }
                        else if (research.Count > 0)
                        {
                            item.Player.Research.FromPartialResult(research);
                            item.Player.Research.LastUpdated = DateTimeOffset.UtcNow;
                        }
                    }
                    item.Name     = playerPlanet.Name;
                    item.PlayerId = current.PlayerId;
                    item.PlanetId = playerPlanet.Id;
                    db.SaveChanges();
                }
            }

            List <MessageBase> messages = result.OfType <MessageBase>().ToList();

            if (!messages.Any())
            {
                return;
            }

            int[] messageIds = messages.Select(s => s.MessageId).ToArray();

            using (BotDb db = new BotDb())
            {
                HashSet <int> existing = db.Messages.Where(s => messageIds.Contains(s.MessageId)).Select(s => s.MessageId).ToHashset();

                foreach (MessageBase message in messages.Where(s => !existing.Contains(s.MessageId)))
                {
                    db.Messages.Add(new Message
                    {
                        MessageId = message.MessageId,
                        Body      = message,
                        TabType   = message.TabType
                    });
                }

                db.SaveChanges();
            }
        }
コード例 #16
0
        public override void Run(List <DataObject> result)
        {
            GalaxyPageSystem systemDetails = result.OfType <GalaxyPageSystem>().FirstOrDefault();

            if (systemDetails == null)
            {
                return;
            }

            using (BotDb db = new BotDb())
            {
                int        systemId = systemDetails.System;
                GalaxyScan scanInfo = db.Scans.SingleOrDefault(s => s.LocationId == systemId);

                if (scanInfo == null)
                {
                    scanInfo = new GalaxyScan
                    {
                        SystemCoordinate = systemDetails.System
                    };

                    db.Scans.Add(scanInfo);
                }

                scanInfo.LastScan = DateTimeOffset.Now;

                // Prep players
                int[] playerIds = result.OfType <GalaxyPageInfoItem>().Select(s => s.PlayerId).ToArray();
                Dictionary <int, Player> players = db.Players.Where(s => playerIds.Contains(s.PlayerId)).ToDictionary(s => s.PlayerId);

                // Individual items
                long systemLower = systemDetails.System.LowerCoordinate;
                long systemUpper = systemDetails.System.UpperCoordinate;

                Dictionary <long, Planet> toRemove = db.Planets.Where(s => systemLower <= s.LocationId && s.LocationId <= systemUpper).ToDictionary(s => s.LocationId);

                foreach (GalaxyPageInfoItem row in result.OfType <GalaxyPageInfoItem>())
                {
                    Player player = null;

                    // not self
                    if (row.PlayerId != -1)
                    {
                        if (!players.TryGetValue(row.PlayerId, out player))
                        {
                            player = new Player
                            {
                                PlayerId = row.PlayerId
                            };

                            db.Players.Add(player);
                            players[row.PlayerId] = player;
                        }

                        player.Name   = row.PlayerName;
                        player.Status = row.PlayerStatus;
                    }

                    Planet planet;
                    if (!toRemove.TryRemove(row.Planet.Coordinate, out planet))
                    {
                        planet = new Planet
                        {
                            Coordinate = row.Planet.Coordinate
                        };

                        db.Planets.Add(planet);
                    }

                    planet.Name = row.Planet.Name;
                    if (player != null)
                    {
                        planet.Player = player;
                    }

                    if (row.Moon != null)
                    {
                        Planet moon;
                        if (!toRemove.TryRemove(row.Moon.Coordinate, out moon))
                        {
                            moon = new Planet
                            {
                                Coordinate = row.Moon.Coordinate
                            };

                            db.Planets.Add(moon);
                        }

                        moon.Name   = row.Moon.Name;
                        moon.Player = player;
                    }
                }

                db.Planets.RemoveRange(toRemove.Values);
                toRemove.Clear();

                db.SaveChanges();
            }
        }
コード例 #17
0
        internal static async Task Main(string[] args)
        {
            Console.WriteLine("Confinement: " + SandboxDetector.Detect());
            if (args.Length > 0 && args[0] == "--dry-run")
            {
                Console.WriteLine("Database path: " + Path.GetDirectoryName(Path.GetFullPath(DbImporter.GetDbPath("fake.db", Environment.SpecialFolder.ApplicationData))));
                if (Assembly.GetEntryAssembly().GetCustomAttribute <UserSecretsIdAttribute>() != null)
                {
                    Console.WriteLine("Bot config path: " + Path.GetDirectoryName(Path.GetFullPath(Config.GoogleApiConfigPath)));
                }
                return;
            }

            var singleInstanceCheckThread = new Thread(() =>
            {
                using var instanceLock = new Mutex(false, @"Global\RPCS3 Compatibility Bot");
                if (instanceLock.WaitOne(1000))
                {
                    try
                    {
                        InstanceCheck.Release();
                        ShutdownCheck.Wait();
                    }
                    finally
                    {
                        instanceLock.ReleaseMutex();
                    }
                }
            });

            try
            {
                singleInstanceCheckThread.Start();
                if (!await InstanceCheck.WaitAsync(1000).ConfigureAwait(false))
                {
                    Config.Log.Fatal("Another instance is already running.");
                    return;
                }

                if (string.IsNullOrEmpty(Config.Token) || Config.Token.Length < 16)
                {
                    Config.Log.Fatal("No token was specified.");
                    return;
                }

                if (SandboxDetector.Detect() == SandboxType.Docker)
                {
                    Config.Log.Info("Checking for updates...");
                    try
                    {
                        var(updated, stdout) = await Sudo.Bot.UpdateAsync().ConfigureAwait(false);

                        if (!string.IsNullOrEmpty(stdout) && updated)
                        {
                            Config.Log.Debug(stdout);
                        }
                        if (updated)
                        {
                            Sudo.Bot.RestartNoSaving(0);
                            return;
                        }
                    }
                    catch (Exception e)
                    {
                        Config.Log.Error(e, "Failed to check for updates");
                    }
                }

                using (var db = new BotDb())
                    if (!await DbImporter.UpgradeAsync(db, Config.Cts.Token))
                    {
                        return;
                    }

                using (var db = new ThumbnailDb())
                    if (!await DbImporter.UpgradeAsync(db, Config.Cts.Token))
                    {
                        return;
                    }

                await StatsStorage.RestoreAsync().ConfigureAwait(false);

                Config.Log.Debug("Restored stats from persistent storage");

                var backgroundTasks = Task.WhenAll(
                    AmdDriverVersionProvider.RefreshAsync(),
                    new PsnScraper().RunAsync(Config.Cts.Token),
                    GameTdbScraper.RunAsync(Config.Cts.Token),
                    new AppveyorClient.Client().GetBuildAsync(Guid.NewGuid().ToString(), Config.Cts.Token),
                    StatsStorage.BackgroundSaveAsync()
                    );

                try
                {
                    if (!Directory.Exists(Config.IrdCachePath))
                    {
                        Directory.CreateDirectory(Config.IrdCachePath);
                    }
                }
                catch (Exception e)
                {
                    Config.Log.Warn(e, $"Failed to create new folder {Config.IrdCachePath}: {e.Message}");
                }

                var config = new DiscordConfiguration
                {
                    Token     = Config.Token,
                    TokenType = TokenType.Bot,
                };
                using var client = new DiscordClient(config);
                var commands = client.UseCommandsNext(new CommandsNextConfiguration
                {
                    StringPrefixes = new[] { Config.CommandPrefix, Config.AutoRemoveCommandPrefix },
                    Services       = new ServiceCollection().BuildServiceProvider(),
                });
                commands.RegisterConverter(new TextOnlyDiscordChannelConverter());
                commands.RegisterCommands <Misc>();
                commands.RegisterCommands <CompatList>();
                commands.RegisterCommands <Sudo>();
                commands.RegisterCommands <CommandsManagement>();
                commands.RegisterCommands <ContentFilters>();
                commands.RegisterCommands <Warnings>();
                commands.RegisterCommands <Explain>();
                commands.RegisterCommands <Psn>();
                commands.RegisterCommands <Invites>();
                commands.RegisterCommands <Moderation>();
                commands.RegisterCommands <Ird>();
                commands.RegisterCommands <BotMath>();
                commands.RegisterCommands <Pr>();
                commands.RegisterCommands <Events>();
                commands.RegisterCommands <E3>();
                commands.RegisterCommands <Cyberpunk2077>();
                commands.RegisterCommands <Rpcs3Ama>();
                commands.RegisterCommands <BotStats>();
                commands.RegisterCommands <Syscall>();
                commands.RegisterCommands <ForcedNicknames>();

                commands.CommandErrored += UnknownCommandHandler.OnError;

                var interactivityConfig = new InteractivityConfiguration {
                };
                client.UseInteractivity(interactivityConfig);

                client.Ready += async r =>
                {
                    Config.Log.Info("Bot is ready to serve!");
                    Config.Log.Info("");
                    Config.Log.Info($"Bot user id : {r.Client.CurrentUser.Id} ({r.Client.CurrentUser.Username})");
                    Config.Log.Info($"Bot admin id : {Config.BotAdminId} ({(await r.Client.GetUserAsync(Config.BotAdminId)).Username})");
                    Config.Log.Info("");
                };
                client.GuildAvailable += async gaArgs =>
                {
                    await BotStatusMonitor.RefreshAsync(gaArgs.Client).ConfigureAwait(false);

                    Watchdog.DisconnectTimestamps.Clear();
                    Watchdog.TimeSinceLastIncomingMessage.Restart();
                    if (gaArgs.Guild.Id != Config.BotGuildId)
                    {
#if DEBUG
                        Config.Log.Warn($"Unknown discord server {gaArgs.Guild.Id} ({gaArgs.Guild.Name})");
#else
                        Config.Log.Warn($"Unknown discord server {gaArgs.Guild.Id} ({gaArgs.Guild.Name}), leaving...");
                        await gaArgs.Guild.LeaveAsync().ConfigureAwait(false);
#endif
                        return;
                    }

                    Config.Log.Info($"Server {gaArgs.Guild.Name} is available now");
                    Config.Log.Info($"Checking moderation backlogs in {gaArgs.Guild.Name}...");
                    try
                    {
                        await Task.WhenAll(
                            Starbucks.CheckBacklogAsync(gaArgs.Client, gaArgs.Guild).ContinueWith(_ => Config.Log.Info($"Starbucks backlog checked in {gaArgs.Guild.Name}."), TaskScheduler.Default),
                            DiscordInviteFilter.CheckBacklogAsync(gaArgs.Client, gaArgs.Guild).ContinueWith(_ => Config.Log.Info($"Discord invites backlog checked in {gaArgs.Guild.Name}."), TaskScheduler.Default)
                            ).ConfigureAwait(false);
                    }
                    catch (Exception e)
                    {
                        Config.Log.Warn(e, "Error running backlog tasks");
                    }
                    Config.Log.Info($"All moderation backlogs checked in {gaArgs.Guild.Name}.");
                };
                client.GuildAvailable   += gaArgs => UsernameValidationMonitor.MonitorAsync(gaArgs.Client, true);
                client.GuildUnavailable += guArgs =>
                {
                    Config.Log.Warn($"{guArgs.Guild.Name} is unavailable");
                    return(Task.CompletedTask);
                };

                client.MessageReactionAdded += Starbucks.Handler;
                client.MessageReactionAdded += ContentFilterMonitor.OnReaction;

                client.MessageCreated += _ => { Watchdog.TimeSinceLastIncomingMessage.Restart(); return(Task.CompletedTask); };
                client.MessageCreated += ContentFilterMonitor.OnMessageCreated; // should be first
                client.MessageCreated += ProductCodeLookup.OnMessageCreated;
                client.MessageCreated += LogParsingHandler.OnMessageCreated;
                client.MessageCreated += LogAsTextMonitor.OnMessageCreated;
                client.MessageCreated += DiscordInviteFilter.OnMessageCreated;
                client.MessageCreated += PostLogHelpHandler.OnMessageCreated;
                client.MessageCreated += BotReactionsHandler.OnMessageCreated;
                client.MessageCreated += AppveyorLinksHandler.OnMessageCreated;
                client.MessageCreated += GithubLinksHandler.OnMessageCreated;
                client.MessageCreated += NewBuildsMonitor.OnMessageCreated;
                client.MessageCreated += TableFlipMonitor.OnMessageCreated;
                client.MessageCreated += IsTheGamePlayableHandler.OnMessageCreated;
                client.MessageCreated += EmpathySimulationHandler.OnMessageCreated;

                client.MessageUpdated += ContentFilterMonitor.OnMessageUpdated;
                client.MessageUpdated += DiscordInviteFilter.OnMessageUpdated;
                client.MessageUpdated += EmpathySimulationHandler.OnMessageUpdated;

                client.MessageDeleted += ThumbnailCacheMonitor.OnMessageDeleted;
                client.MessageDeleted += EmpathySimulationHandler.OnMessageDeleted;

                client.UserUpdated += UsernameSpoofMonitor.OnUserUpdated;
                client.UserUpdated += UsernameZalgoMonitor.OnUserUpdated;

                client.GuildMemberAdded += Greeter.OnMemberAdded;
                client.GuildMemberAdded += UsernameSpoofMonitor.OnMemberAdded;
                client.GuildMemberAdded += UsernameZalgoMonitor.OnMemberAdded;
                client.GuildMemberAdded += UsernameValidationMonitor.OnMemberAdded;

                client.GuildMemberUpdated += UsernameSpoofMonitor.OnMemberUpdated;
                client.GuildMemberUpdated += UsernameZalgoMonitor.OnMemberUpdated;
                client.GuildMemberUpdated += UsernameValidationMonitor.OnMemberUpdated;

                client.DebugLogger.LogMessageReceived += (sender, eventArgs) =>
                {
                    Action <Exception, string> logLevel = Config.Log.Info;
                    if (eventArgs.Level == LogLevel.Debug)
                    {
                        logLevel = Config.Log.Debug;
                    }
                    else if (eventArgs.Level == LogLevel.Info)
                    {
                        //logLevel = Config.Log.Info;
                        if (eventArgs.Message?.Contains("Session resumed") ?? false)
                        {
                            Watchdog.DisconnectTimestamps.Clear();
                        }
                    }
                    else if (eventArgs.Level == LogLevel.Warning)
                    {
                        logLevel = Config.Log.Warn;
                        if (eventArgs.Message?.Contains("Dispatch:PRESENCES_REPLACE") ?? false)
                        {
                            BotStatusMonitor.RefreshAsync(client).ConfigureAwait(false).GetAwaiter().GetResult();
                        }
                    }
                    else if (eventArgs.Level == LogLevel.Error)
                    {
                        logLevel = Config.Log.Error;
                    }
                    else if (eventArgs.Level == LogLevel.Critical)
                    {
                        logLevel = Config.Log.Fatal;
                        if ((eventArgs.Message?.Contains("Socket connection terminated") ?? false) ||
                            (eventArgs.Message?.Contains("heartbeats were skipped. Issuing reconnect.") ?? false))
                        {
                            Watchdog.DisconnectTimestamps.Enqueue(DateTime.UtcNow);
                        }
                    }
                    logLevel(eventArgs.Exception, eventArgs.Message);
                };
                Watchdog.DisconnectTimestamps.Enqueue(DateTime.UtcNow);

                try
                {
                    await client.ConnectAsync().ConfigureAwait(false);
                }
                catch (Exception e)
                {
                    Config.Log.Error(e, "Failed to connect to Discord: " + e.Message);
                    throw;
                }

                ulong?channelId = null;
                if (SandboxDetector.Detect() == SandboxType.Docker)
                {
                    using var db = new BotDb();
                    var chState = db.BotState.FirstOrDefault(k => k.Key == "bot-restart-channel");
                    if (chState != null)
                    {
                        if (ulong.TryParse(chState.Value, out var ch))
                        {
                            channelId = ch;
                        }
                        db.BotState.Remove(chState);
                        db.SaveChanges();
                    }
                }
                if (args.LastOrDefault() is string strCh && ulong.TryParse(strCh, out var chId))
                {
                    channelId = chId;
                }

                if (channelId.HasValue)
                {
                    Config.Log.Info($"Found channelId {channelId}");
                    DiscordChannel channel;
                    if (channelId == InvalidChannelId)
                    {
                        channel = await client.GetChannelAsync(Config.ThumbnailSpamId).ConfigureAwait(false);

                        await channel.SendMessageAsync("Bot has suffered some catastrophic failure and was restarted").ConfigureAwait(false);
                    }
                    else
                    {
                        channel = await client.GetChannelAsync(channelId.Value).ConfigureAwait(false);

                        await channel.SendMessageAsync("Bot is up and running").ConfigureAwait(false);
                    }
                }
                else
                {
                    Config.Log.Debug($"Args count: {args.Length}");
                    var pArgs = args.Select(a => a == Config.Token ? "<Token>" : $"[{a}]");
                    Config.Log.Debug("Args: " + string.Join(" ", pArgs));
                }

                Config.Log.Debug("Running RPCS3 update check thread");
                backgroundTasks = Task.WhenAll(
                    backgroundTasks,
                    NewBuildsMonitor.MonitorAsync(client),
                    Watchdog.Watch(client),
                    InviteWhitelistProvider.CleanupAsync(client),
                    UsernameValidationMonitor.MonitorAsync(client)
                    );

                while (!Config.Cts.IsCancellationRequested)
                {
                    if (client.Ping > 1000)
                    {
                        Config.Log.Warn($"High ping detected: {client.Ping}");
                    }
                    await Task.Delay(TimeSpan.FromMinutes(1), Config.Cts.Token).ContinueWith(dt => { /* in case it was cancelled */ }, TaskScheduler.Default).ConfigureAwait(false);
                }
                await backgroundTasks.ConfigureAwait(false);
            }
            catch (Exception e)
            {
                if (!Config.inMemorySettings.ContainsKey("shutdown"))
                {
                    Config.Log.Fatal(e, "Experienced catastrophic failure, attempting to restart...");
                }
            }
            finally
            {
                ShutdownCheck.Release();
                if (singleInstanceCheckThread.IsAlive)
                {
                    singleInstanceCheckThread.Join(100);
                }
            }
            if (!Config.inMemorySettings.ContainsKey("shutdown"))
            {
                Sudo.Bot.Restart(InvalidChannelId);
            }
        }
コード例 #18
0
        private void ProcessData(Universe model)
        {
            using (BotDb db = new BotDb())
            {
                Dictionary <long, Db.Planet> allPlanets = db.Planets.ToDictionary(s => s.LocationId);
                Dictionary <int, Db.Player>  allPlayers = db.Players.ToDictionary(s => s.PlayerId);

                List <Db.Planet> newPlanets = new List <Db.Planet>();
                List <Db.Player> newPlayers = new List <Db.Player>();

                for (int i = 0; i < model.Planets.Length; i++)
                {
                    OgameApi.Objects.Planet planet = model.Planets[i];
                    Coordinate planetCoords        = Coordinate.Parse(planet.Coords, CoordinateType.Planet);

                    Db.Planet dbPlanet;
                    if (!allPlanets.TryGetValue(planetCoords.Id, out dbPlanet))
                    {
                        dbPlanet = new Db.Planet
                        {
                            Coordinate = planetCoords
                        };

                        newPlanets.Add(dbPlanet);
                        allPlanets[planetCoords.Id] = dbPlanet;
                    }

                    dbPlanet.Name     = planet.Name;
                    dbPlanet.PlayerId = planet.Player;

                    if (planet.Moon != null)
                    {
                        Coordinate moonCoords = Coordinate.Create(planetCoords, CoordinateType.Moon);

                        Db.Planet dbMoon;
                        if (!allPlanets.TryGetValue(moonCoords.Id, out dbMoon))
                        {
                            dbMoon = new Db.Planet
                            {
                                Coordinate = moonCoords
                            };

                            newPlanets.Add(dbMoon);
                            allPlanets[moonCoords.Id] = dbMoon;
                        }

                        dbMoon.Name = planet.Moon.Name;
                    }

                    Db.Player dbPlayer;
                    if (!allPlayers.TryGetValue(planet.Player, out dbPlayer))
                    {
                        dbPlayer = new Db.Player
                        {
                            PlayerId = planet.Player
                        };

                        newPlayers.Add(dbPlayer);
                        allPlayers[dbPlayer.PlayerId] = dbPlayer;
                    }

                    if (i % 250 == 0)
                    {
                        db.Planets.AddRange(newPlanets);
                        db.Players.AddRange(newPlayers);

                        db.SaveChanges();

                        newPlanets.Clear();
                        newPlayers.Clear();
                    }
                }

                db.Planets.AddRange(newPlanets);
                db.Players.AddRange(newPlayers);

                db.SaveChanges();
            }
        }