예제 #1
0
    public void OnGUI()
    {
        Event     currentEvent     = Event.current;
        EventType currentEventType = currentEvent.type;

        _view = BeginScrollView(
            _view,
            false,
            false,
            GUIStyle.none,
            GUI.skin.verticalScrollbar,
            GUI.skin.scrollView,
            GUILayout.Width(EditorGUIUtility.currentViewWidth),
            GUILayout.ExpandHeight(true));

        if (currentEventType == EventType.DragUpdated)
        {
            // Indicate that we don't accept drags ourselves
            DragAndDrop.visualMode = DragAndDropVisualMode.Rejected;
        }

        using (var h = new HorizontalScope())
        {
            _connectionString = TextField(_connectionString);
            if (GUILayout.Button("Connect"))
            {
                EditorPrefs.SetString("RethinkDB.URL", _connectionString);
                _queryStatus = RethinkConnection.RethinkConnect(_databaseCache, _connectionString);
            }
        }
        using (var h = new HorizontalScope())
        {
            if (GUILayout.Button("Connect All"))
            {
                EditorPrefs.SetString("RethinkDB.URL", _connectionString);
                _queryStatus = RethinkConnection.RethinkConnect(_databaseCache, _connectionString, true, false);
            }

            if (GUILayout.Button("Save"))
            {
                _databaseCache.Save(new DirectoryInfo(Application.dataPath).Parent.FullName);
            }
        }

        using (new HorizontalScope())
        {
            if (GUILayout.Button("Delete Orphaned Blueprints"))
            {
                int count = 0;
                foreach (var blueprintData in _databaseCache.GetAll <BlueprintData>().ToArray())
                {
                    if (_databaseCache.Get(blueprintData.Item) == null)
                    {
                        _databaseCache.Delete(blueprintData);
                        count++;
                    }
                }
                Debug.Log($"Deleted {count} orphaned blueprints!");
            }
        }

        if (_queryStatus != null && _queryStatus.RetrievedItems < _queryStatus.GalaxyEntries + _queryStatus.ItemsEntries)
        {
            var progressRect = GetControlRect(false, 20);
            EditorGUI.ProgressBar(progressRect, (float)_queryStatus.RetrievedItems / (_queryStatus.GalaxyEntries + _queryStatus.ItemsEntries), "Sync Progress");
        }
        // else
        // {
        //     if(_itemBlueprints == null)
        //         _itemBlueprints = _databaseCache.GetAll<ItemData>()
        //             .Select(itemData => new {itemData, blueprints = _databaseCache.GetAll<BlueprintData>()
        //                 .Where(blueprintData => blueprintData.Item == itemData.ID)
        //                 .Select(bp => bp.ID)
        //                 .ToList()})
        //             .ToDictionary(x => x.itemData.ID, x => x.blueprints);
        // }
        GUILayout.Space(5);

        // if(GUILayout.Button("Log Cache Count"))
        //     Debug.Log($"Cache contains {_databaseCache.AllEntries.Count()} elements");

        using (var h = new HorizontalScope(ListItemStyle))
        {
            _itemsFoldout = Foldout(_itemsFoldout, "Items", true);
        }
        if (_itemsFoldout)
        {
            var items = _databaseCache.AllEntries.Where(item => item is ItemData).Cast <ItemData>().ToArray();
            for (var i = 0; i < _itemTypes.Length; i++)
            {
                using (var h = new HorizontalScope(ListItemStyle))
                {
                    GUILayout.Space(10);
                    _itemTypeFoldouts[i] = Foldout(_itemTypeFoldouts[i],
                                                   ((NameAttribute)_itemTypes[i].GetCustomAttribute(typeof(NameAttribute)))?.Name ?? FormatTypeName(_itemTypes[i].Name),
                                                   true);
                }
                if (_itemTypeFoldouts[i])
                {
                    var typedItems = items.Where(e => e.GetType() == _itemTypes[i]).OrderBy(item => item.Name);
                    IEnumerable <IGrouping <string, ItemData> > itemGroups = new List <IGrouping <string, ItemData> >();
                    if (_itemTypes[i] == typeof(SimpleCommodityData))
                    {
                        itemGroups = typedItems.GroupBy(item => Enum.GetName(typeof(SimpleCommodityCategory), (item as SimpleCommodityData).Category));
                    }
                    else if (_itemTypes[i] == typeof(CompoundCommodityData))
                    {
                        itemGroups = typedItems.GroupBy(item => Enum.GetName(typeof(CompoundCommodityCategory), (item as CompoundCommodityData).Category));
                    }
                    else if (_itemTypes[i] == typeof(GearData))
                    {
                        itemGroups = typedItems.GroupBy(item => Enum.GetName(typeof(HardpointType), (item as GearData).Hardpoint));
                    }
                    else if (_itemTypes[i] == typeof(HullData))
                    {
                        itemGroups = typedItems.GroupBy(item => Enum.GetName(typeof(HullType), (item as HullData).HullType));
                    }

                    foreach (var itemGroup in itemGroups)
                    {
                        using (var h = new HorizontalScope(ListItemStyle))
                        {
                            GUILayout.Space(20);
                            if (Foldout(_itemGroupFoldouts.Contains(itemGroup.Key), FormatTypeName(itemGroup.Key), true))
                            {
                                _itemGroupFoldouts.Add(itemGroup.Key);
                            }
                            else
                            {
                                _itemGroupFoldouts.Remove(itemGroup.Key);
                            }
                        }

                        if (_itemGroupFoldouts.Contains(itemGroup.Key))
                        {
                            foreach (var item in itemGroup)
                            {
                                var style    = ListItemStyle;
                                var selected = SelectedItem == item.ID;
                                using (new HorizontalScope(selected?SelectedStyle:style))
                                {
                                    using (var h = new HorizontalScope())
                                    {
                                        if (h.rect.Contains(currentEvent.mousePosition))
                                        {
                                            if (currentEventType == EventType.MouseDrag)
                                            {
                                                DragAndDrop.PrepareStartDrag();
                                                DragAndDrop.SetGenericData("Item", item.ID);
                                                DragAndDrop.StartDrag("Database Item");
                                            }
                                            else if (currentEventType == EventType.MouseUp)
                                            {
                                                Select(item);
                                            }
                                        }

                                        GUILayout.Space(30);
                                        GUILayout.Label(item.Name, selected ? EditorStyles.whiteLabel : GUI.skin.label);
                                    }

                                    using (var h = new HorizontalScope(GUILayout.Width(15)))
                                    {
                                        if (GUI.Button(h.rect, GUIContent.none, GUIStyle.none))
                                        {
                                            if (_itemBlueprintFoldouts.Contains(item.ID))
                                            {
                                                _itemBlueprintFoldouts.Remove(item.ID);
                                            }
                                            else
                                            {
                                                _itemBlueprintFoldouts.Add(item.ID);
                                            }
                                        }
                                        GUILayout.Label(_itemBlueprints[item.ID].Count.ToString());
                                        var rect = GetControlRect(false, GUILayout.Width(EditorGUIUtility.singleLineHeight));
                                        if (Event.current.type == EventType.Repaint)
                                        {
                                            var controlId = GUIUtility.GetControlID(1337, FocusType.Keyboard, position);
                                            EditorStyles.foldout.Draw(rect, GUIContent.none, controlId, _itemBlueprintFoldouts.Contains(item.ID));
                                        }
                                    }
                                }

                                if (_itemBlueprintFoldouts.Contains(item.ID))
                                {
                                    foreach (var blueprintData in _itemBlueprints[item.ID]
                                             .Select(id => _databaseCache.Get <BlueprintData>(id))
                                             .OrderBy(bp => bp.Quality))
                                    {
                                        var blueprintStyle    = ListItemStyle;
                                        var blueprintSelected = SelectedItem == blueprintData.ID;
                                        using (var h = new HorizontalScope(blueprintSelected ? SelectedStyle : blueprintStyle))
                                        {
                                            if (h.rect.Contains(currentEvent.mousePosition))
                                            {
                                                if (currentEventType == EventType.MouseDrag)
                                                {
                                                    DragAndDrop.PrepareStartDrag();
                                                    DragAndDrop.SetGenericData("Item", blueprintData.ID);
                                                    DragAndDrop.StartDrag("Database Item");
                                                }
                                                else if (currentEventType == EventType.MouseUp)
                                                {
                                                    Select(blueprintData);
                                                }
                                            }

                                            GUILayout.Space(40);
                                            GUILayout.Label(blueprintData.Name,
                                                            blueprintSelected ? EditorStyles.whiteLabel : GUI.skin.label);
                                        }
                                    }

                                    using (var h = new HorizontalScope(ListItemStyle))
                                    {
                                        if (GUI.Button(h.rect, GUIContent.none, GUIStyle.none))
                                        {
                                            var blueprint = new BlueprintData
                                            {
                                                Item = item.ID,
                                                Name = item.Name
                                            };
                                            _databaseCache.Add(blueprint);
                                            Select(blueprint);
                                        }
                                        GUILayout.Space(40);
                                        GUILayout.Label("New Blueprint");
                                        var rect = GetControlRect(false, GUILayout.Width(EditorGUIUtility.singleLineHeight));
                                        GUI.DrawTexture(rect, Icons.Instance.plus, ScaleMode.StretchToFill, true, 1, LabelColor,
                                                        0, 0);
                                    }
                                }
                            }

                            using (var h = new HorizontalScope(ListItemStyle))
                            {
                                if (GUI.Button(h.rect, GUIContent.none, GUIStyle.none))
                                {
                                    CreateItem(_itemTypes[i], newItem =>
                                    {
                                        if (newItem is SimpleCommodityData simpleCommodityData)
                                        {
                                            simpleCommodityData.Category =
                                                (SimpleCommodityCategory)Enum.Parse(typeof(SimpleCommodityCategory),
                                                                                    itemGroup.Key);
                                            simpleCommodityData.Name = $"New {itemGroup.Key}";
                                        }
                                        else if (newItem is CompoundCommodityData compoundCommodityData)
                                        {
                                            compoundCommodityData.Category =
                                                (CompoundCommodityCategory)Enum.Parse(
                                                    typeof(CompoundCommodityCategory), itemGroup.Key);
                                            compoundCommodityData.Name = $"New {itemGroup.Key}";
                                        }
                                        else if (newItem is GearData gearData)
                                        {
                                            gearData.Hardpoint =
                                                (HardpointType)Enum.Parse(typeof(HardpointType), itemGroup.Key);
                                            gearData.Name = $"New {itemGroup.Key}";
                                        }
                                        else if (newItem is HullData hullData)
                                        {
                                            hullData.HullType = (HullType)Enum.Parse(typeof(HullType), itemGroup.Key);
                                            hullData.Name     = $"New {itemGroup.Key}";
                                        }
                                    });
                                }
                                GUILayout.Space(30);
                                GUILayout.Label("New " + itemGroup.Key);
                                var rect = GetControlRect(false, GUILayout.Width(EditorGUIUtility.singleLineHeight));
                                GUI.DrawTexture(rect, Icons.Instance.plus, ScaleMode.StretchToFill, true, 1, LabelColor, 0, 0);
                            }
                        }
                    }

                    if (!itemGroups.Any())
                    {
                        using (var h = new HorizontalScope(ListItemStyle))
                        {
                            if (GUI.Button(h.rect, GUIContent.none, GUIStyle.none))
                            {
                                CreateItem(_itemTypes[i]);
                            }
                            GUILayout.Space(20);
                            GUILayout.Label("New " + _itemTypes[i].Name);
                            var rect = GetControlRect(false, GUILayout.Width(EditorGUIUtility.singleLineHeight));
                            GUI.DrawTexture(rect, Icons.Instance.plus, ScaleMode.StretchToFill, true, 1, LabelColor, 0, 0);
                        }
                    }
                }
            }
        }

        var entries = _databaseCache.AllEntries.Where(item => !(item is ItemData)).ToArray();

        for (var i = 0; i < _entryTypes.Length; i++)
        {
            using (var h = new HorizontalScope(ListItemStyle))
            {
                _entryFoldouts[i] = Foldout(_entryFoldouts[i],
                                            ((NameAttribute)_entryTypes[i].GetCustomAttribute(typeof(NameAttribute)))?.Name ?? FormatTypeName(_entryTypes[i].Name),
                                            true);
            }

            if (_entryFoldouts[i])
            {
                int index = 0;
                foreach (var entry in entries.Where(e => e.GetType() == _entryTypes[i]).OrderBy(entry => entry is INamedEntry namedEntry ? namedEntry.EntryName : entry.ID.ToString()))
                {
                    index++;
                    var style    = ListItemStyle;
                    var selected = SelectedItem == entry.ID;
                    using (var h = new HorizontalScope(selected?SelectedStyle:style))
                    {
                        if (h.rect.Contains(currentEvent.mousePosition))
                        {
                            if (currentEventType == EventType.MouseDrag)
                            {
                                DragAndDrop.PrepareStartDrag();
                                DragAndDrop.SetGenericData("Item", entry.ID);
                                DragAndDrop.StartDrag("Database Item");
                            }
                            else if (currentEventType == EventType.MouseUp)
                            {
                                Select(entry);
                            }
                        }
                        GUILayout.Space(10);
                        GUILayout.Label((entry as INamedEntry)?.EntryName ?? index.ToString(), selected ? EditorStyles.whiteLabel : GUI.skin.label);
                    }
                }

                using (var h = new HorizontalScope(ListItemStyle))
                {
                    if (GUI.Button(h.rect, GUIContent.none, GUIStyle.none))
                    {
                        CreateItem(_entryTypes[i]);
                    }
                    GUILayout.Space(10);
                    GUILayout.Label("New " + _entryTypes[i].Name);
                    var rect = GetControlRect(false, GUILayout.Width(EditorGUIUtility.singleLineHeight));
                    GUI.DrawTexture(rect, Icons.Instance.plus, ScaleMode.StretchToFill, true, 1, LabelColor, 0, 0);
                }
            }
        }

        EndScrollView();
    }
예제 #2
0
    public void Start()
    {
        _timer = new Stopwatch();
        _timer.Start();

        EventBasedNetListener listener = new EventBasedNetListener();

        _netManager = new NetManager(listener)
        {
            UnsyncedEvents  = true,
            NatPunchEnabled = true,
        };
        _netManager.Start(3075);

        listener.NetworkErrorEvent += (point, code) => Logger.Log(LogLevel.Debug, $"{point.Address}: Error {code}");

        listener.ConnectionRequestEvent += request => request.AcceptIfKey("aetheria-cc65a44d");

        listener.PeerConnectedEvent += peer =>
        {
            Logger.Log(LogLevel.Debug, $"User Connected: {peer.EndPoint}"); // Show peer ip
            _users[peer.Id] = new User {
                Peer = peer
            };
        };

        listener.PeerDisconnectedEvent += (peer, info) =>
        {
            Logger.Log(LogLevel.Debug, $"User Disconnected: {peer.EndPoint}"); // Show peer ip

//            foreach (var verifiedUser in _users.Values.Where(IsVerified))
//                verifiedUser.Peer.Send("PlayerLeft", SessionData(verifiedUser.Peer).Username);

            _users.Remove(peer.Id);
        };

        listener.NetworkLatencyUpdateEvent += (peer, latency) =>
        {
//            Logger($"Received Ping: {latency}");
            _users[peer.Id].Latency = latency;
        };

        listener.NetworkReceiveEvent += (peer, reader, method) =>
        {
            var bytes   = reader.GetRemainingBytes();
            var message = MessagePackSerializer.Deserialize <Message>(bytes);
            Logger.Log(LogLevel.Information, $"Received message: {MessagePackSerializer.ConvertToJson(new ReadOnlyMemory<byte>(bytes))}");
            if (message == null)
            {
                return;
            }
            message.Peer = peer;
            var user = _users[peer.Id];
            var type = message.GetType();

            if (type == typeof(LoginMessage) || type == typeof(RegisterMessage) || type == typeof(VerifyMessage))
            {
                if (IsVerified(user))
                {
                    peer.Send(new LoginSuccessMessage {
                        Session = _users[peer.Id].SessionGuid
                    });
                    return;
                }

                Guid sessionGuid;
                switch (message)
                {
                case RegisterMessage register when !IsValidUsername(register.Name):
                    peer.Send(new ErrorMessage {
                        Error = "Username Invalid"
                    });
                    return;

                case RegisterMessage register when !IsValidEmail(register.Email):
                    peer.Send(new ErrorMessage {
                        Error = "Email Invalid"
                    });
                    return;

                case RegisterMessage register:
                {
                    sessionGuid = Guid.NewGuid();
                    peer.Send(new LoginSuccessMessage {
                            Session = sessionGuid
                        });

                    var newUserData = new Player
                    {
                        ID       = Guid.NewGuid(),
                        Email    = register.Email,
                        Password = Argon2.Hash(register.Password, null, memoryCost: 16384),
                        Username = register.Name
                    };
                    _database.Add(newUserData);

                    _sessions[sessionGuid] = new Session {
                        Data = newUserData, LastUpdate = DateTime.Now
                    };
                    if (!_users.ContainsKey(peer.Id))
                    {
                        return;
                    }
                    _users[peer.Id].SessionGuid = sessionGuid;
                    break;
                }

                case VerifyMessage verify when _sessions.ContainsKey(verify.Session):
                    _users[peer.Id].SessionGuid = verify.Session;

                    peer.Send(new LoginSuccessMessage {
                        Session = verify.Session
                    });
                    return;

                case LoginMessage login:
                {
                    var isEmail  = IsValidEmail(login.Auth);
                    var userData = _database.GetAll <Player>().FirstOrDefault(x =>
                                                                              (isEmail ? x.Email : x.Username) == login.Auth);

                    if (userData == null)
                    {
                        peer.Send(new ErrorMessage {
                                Error = isEmail ? "Email Not Found" : "Username Not Found"
                            });
                        return;
                    }

                    if (!Argon2.Verify(userData.Password, login.Password))
                    {
                        peer.Send(new ErrorMessage {
                                Error = "Password Incorrect"
                            });
                        return;
                    }

                    sessionGuid = Guid.NewGuid();
                    peer.Send(new LoginSuccessMessage {
                            Session = sessionGuid
                        });

                    _sessions.Add(sessionGuid, new Session {
                            Data = userData, LastUpdate = DateTime.Now
                        });
                    // TODO: Intermittent: users getting disconnected before getting here, check that key exists!
                    if (!_users.ContainsKey(peer.Id))
                    {
                        return;
                    }
                    _users[peer.Id].SessionGuid = sessionGuid;
                    break;
                }
                }
            }
            else
            {
                if (IsVerified(user))
                {
                    if (_messageCallbacks.ContainsKey(type))
                    {
                        typeof(ActionCollection <>).MakeGenericType(new[] { type }).GetMethod("Invoke")
                        .Invoke(_messageCallbacks[type], new object[] { message });
                    }
                    else
                    {
                        Logger.Log(LogLevel.Warning, $"Received {type.Name} message but no one is listening for it so I'll just leave it here ¯\\_(ツ)_/¯\n{MessagePackSerializer.ConvertToJson(new ReadOnlyMemory<byte>(bytes))}");
                    }
                    _sessions[_users[peer.Id].SessionGuid].LastUpdate = DateTime.Now;
                }
                else
                {
                    peer.Send(new ErrorMessage {
                        Error = "User Not Verified"
                    });
                }
            }
        };

        AddMessageListener <ChatMessage>(message =>
        {
            foreach (var verifiedUser in _users.Values.Where(IsVerified))
            {
                verifiedUser.Peer.Send(new ChatBroadcastMessage {
                    User = SessionData(message.Peer).Username, Text = message.Text
                });
            }
        });

        AddMessageListener <ChangeNameMessage>(message =>
        {
            SessionData(message.Peer).Username = message.Name;
            _database.Add(SessionData(message.Peer));
        });

        // Observable.Timer(DateTimeOffset.Now, TimeSpan.FromSeconds(30)).Subscribe(_ =>
        // {
        //     foreach (var s in _sessions.ToArray())
        //     {
        //         if (DateTime.Now.Subtract(s.Value.LastUpdate).TotalSeconds > s.Value.DurationSeconds)
        //             _sessions.Remove(s.Key);
        //     }
        // });

        Logger.LogInformation("LiteNetLib is now open to new connections. Please be gentle.");
    }
예제 #3
0
        static async Task Main(string[] args)
        {
            var serilogger = new LoggerConfiguration()
                             .WriteTo.File("log.txt", rollingInterval: RollingInterval.Day)
                             .CreateLogger();
            var loggerFactory = LoggerFactory.Create(builder =>
            {
                builder
                // .AddFilter("Microsoft", LogLevel.Warning)
                // .AddFilter("System", LogLevel.Warning)
                // .AddFilter("LoggingConsoleApp.Program", LogLevel.Debug)
                .AddSerilog(serilogger)
                .AddConsole();
            });

            _logger = loggerFactory.CreateLogger <Program>();

            // Register extensions to Json.NET Serialization
            JsonConvert.DefaultSettings = () => new JsonSerializerSettings
            {
                Converters = new List <JsonConverter>
                {
                    new MathJsonConverter(),
                    Converter.DateTimeConverter,
                    Converter.BinaryConverter,
                    Converter.GroupingConverter,
                    Converter.PocoExprConverter
                }
            };
            Converter.Serializer.Converters.Add(new MathJsonConverter());

            // Register extensions to MessagePack Serialization
            var resolver = CompositeResolver.Create(
                MathResolver.Instance,
                NativeGuidResolver.Instance,
                StandardResolver.Instance
                );
            var options = MessagePackSerializerOptions.Standard.WithResolver(resolver);

            MessagePackSerializer.DefaultOptions = options;

            var connection = R.Connection().Hostname("asgard.gamecult.games")
                             .Port(RethinkDBConstants.DefaultPort).Timeout(60).Connect();

            var cache = new DatabaseCache();

            // When entries are changed locally, push the changes to RethinkDB
            cache.OnDataUpdateLocal += async entry =>
            {
                var table  = entry.GetType().GetCustomAttribute <RethinkTableAttribute>()?.TableName ?? "Other";
                var result = await R.Db("Aetheria").Table(table).Update(entry).RunAsync(connection);

                _logger.Log(LogLevel.Information, $"Uploaded entry to RethinkDB: {entry.ID} result: {result}");
            };

            cache.OnDataInsertLocal += async entry =>
            {
                var table    = entry.GetType().GetCustomAttribute <RethinkTableAttribute>()?.TableName ?? "Other";
                var inserted = false;
                for (int i = 0; i < 5 && !inserted; i++)
                {
                    try
                    {
                        var result = await R.Db("Aetheria").Table(table).Insert(entry).RunAsync(connection);

                        _logger.Log(LogLevel.Information, $"Inserted entry to RethinkDB: {entry.ID} result: {result}");
                        inserted = true;
                    }
                    catch (Exception e)
                    {
                        _logger.LogError(e, e.Message);
                    }
                }
                if (!inserted)
                {
                    _logger.LogError("Failed to insert after 5 attempts!");
                }
            };

            cache.OnDataDeleteLocal += async entry =>
            {
                var table  = entry.GetType().GetCustomAttribute <RethinkTableAttribute>()?.TableName ?? "Other";
                var result = await R.Db("Aetheria").Table(table).Get(entry.ID).Delete().RunAsync(connection);

                _logger.Log(LogLevel.Information, $"Deleted entry from RethinkDB: {entry.ID} result: {result}");
            };

            // Get data from RethinkDB
            await GetTable("Items", connection, cache);
            await GetTable("Galaxy", connection, cache);
            await GetTable("Users", connection, cache);

            // Subscribe to changes from RethinkDB
            SubscribeTable("Items", connection, cache);
            SubscribeTable("Galaxy", connection, cache);
            SubscribeTable("Users", connection, cache);

            var server = new MasterServer(cache)
            {
                Logger = _logger
            };

            server.Start();

            var context = new GameContext(cache, s => _logger.Log(LogLevel.Information, s));

            context.MapLayers = cache.GetAll <GalaxyMapLayerData>().ToDictionary(m => m.Name);

            server.AddMessageListener <GalaxyRequestMessage>(galaxyRequest => galaxyRequest.Peer.Send(
                                                                 new GalaxyResponseMessage
            {
                Zones = cache.GetAll <ZoneData>().Select(zd =>
                                                         new GalaxyResponseZone
                {
                    Name     = zd.Name,
                    Position = zd.Position,
                    ZoneID   = zd.ID,
                    Links    = zd.Wormholes?.ToArray() ?? Array.Empty <Guid>()
                }).ToArray(),
                GlobalData  = context.GlobalData,
                StarDensity = context.MapLayers["StarDensity"]
            }));

            server.AddMessageListener <BlueprintsRequestMessage>(blueprintRequest => blueprintRequest.Peer.Send(
                                                                     new BlueprintsResponseMessage
            {
                Blueprints = cache.GetAll <BlueprintData>().ToArray()
            }));

            server.AddMessageListener <ZoneRequestMessage>(zoneRequest =>
            {
                var zone = cache.Get <ZoneData>(zoneRequest.ZoneID);

                // Zone has not been populated, generate the contents now!
                if (!zone.Visited)
                {
                    zone.Visited = true;
                    OrbitData[] orbits;
                    PlanetData[] planets;
                    ZoneGenerator.GenerateZone(
                        global: context.GlobalData,
                        zone: zone,
                        mapLayers: context.MapLayers.Values,
                        resources: cache.GetAll <SimpleCommodityData>().Where(i => i.ResourceDensity.Any()),
                        orbitData: out orbits,
                        planetsData: out planets);
                    cache.AddAll(orbits);
                    cache.AddAll(planets);
                    cache.Add(zone);
                }
                zoneRequest.Peer.Send(
                    new ZoneResponseMessage
                {
                    Zone     = zone,
                    Contents = zone.Orbits.Select(id => cache.Get(id))
                               .Concat(zone.Planets.Select(id => cache.Get(id)))
                               .Concat(zone.Stations.Select(id => cache.Get(id))).ToArray()
                });
            });

            Observable.Timer(DateTimeOffset.Now, TimeSpan.FromSeconds(60)).SubscribeOn(NewThreadScheduler.Default).Subscribe(_ =>
            {
                _logger.Log(LogLevel.Information, R.Now().Run <DateTime>(connection).ToString() as string);
            });

            while (true)
            {
                Thread.Sleep(100);
            }
        }