public static ClientZoneInfo Create(IReadOnlyZoneInfo zoneInfo) => new ClientZoneInfo { bitmapLayerOne = TilesetProvider .GetAnimatedCellBitmapSetIdFor(zoneInfo, x => x.LayerOne), bitmapLayerTwo = TilesetProvider .GetAnimatedCellBitmapSetIdFor(zoneInfo, x => x.LayerTwo.WithResultIfHasMatch(y => y)), x = zoneInfo.Point.X, y = zoneInfo.Point.Y };
public GameServer(ISimulationSession simulationSession, string url, bool controlVehicles) { if (string.IsNullOrWhiteSpace(url)) { throw new ArgumentException("", nameof(url)); } _simulationSession = simulationSession ?? throw new ArgumentNullException(nameof(simulationSession)); _url = url; _controlVehicles = controlVehicles; List <ClientZoneInfo> previous = null; _simulationSession.OnAreaMessage += SimulationSession_OnAreaMessage; _simulationSession.OnYearAndOrMonthChanged += SimulationSession_OnYearAndOrMonthChanged; _simulationSession.OnCityBudgetValueChanged += SimulationSession_OnCityBudgetValueChanged; _simulationSession.OnAreaHotMessage += SimulationSession_OnAreaHotMessage; var zoneInfoBatchLooper = new LoopBatchEnumerator <IReadOnlyZoneInfo>(_simulationSession.Area.EnumerateZoneInfos().ToList()); var dataMeterStateManager = new DataMeterPublishStateManager(simulationSession); _dataMeterStateLooper = new NeverEndingTask("Data meter state submission", async() => { foreach (var x in dataMeterStateManager.DataMeterPublishStates) { await Startup.WithSimulationHub(async hub => { foreach (var batch in x.GetChanged().GetBatched(100)) { await hub .Clients .Group(SimulationHub.GetDataMeterGroupName(x.DataMeter.WebId)) .SendAsync("submitDataMeterInfos", batch); } }); } }, _cancellationTokenSource.Token, 10); _looper = new NeverEndingTask("SignalR Game state submission", async() => { await Startup.WithSimulationHub(async simulationHub => { await simulationHub .Clients .All .SendAsync("submitZoneInfos", zoneInfoBatchLooper.GetBatch().Select(ClientZoneInfo.Create), _cancellationTokenSource.Token); var zoneInfos = _simulationSession.Area.EnumerateZoneInfos() .Select(ClientZoneInfo.Create) .ToList(); var toBeSubmitted = zoneInfos; if (previous != null) { var previousUids = previous.Select(x => x.GetIdentityString()).ToHashSet(); toBeSubmitted = zoneInfos.Where(z => !previousUids.Contains(z.GetIdentityString())).ToList(); } foreach (var toBeSubmittedBatch in toBeSubmitted.GetBatched(20)) { await simulationHub .Clients .All .SendAsync("submitZoneInfos", toBeSubmittedBatch); } previous = zoneInfos; try { var list = new List <ClientVehiclePositionInfo>(); foreach (var vehicleController in _simulationSession.Area.EnumerateVehicleControllers()) { vehicleController .ForEachActiveVehicle(_controlVehicles, vehicle => { list.AddRange(TilesetProvider .GetBitmapsAndPointsFor(vehicle) .Select(ClientVehiclePositionInfo.Create) ); }); } await simulationHub .Clients .All .SendAsync("submitVehicleStates", list); } catch (Exception ex) { Logger.Instance.WriteLine("Possible race condition-based exception:: " + ex); } }); }, _cancellationTokenSource.Token, 10); if (Instance == null) { Instance = this; } else { throw new InvalidOperationException(); } }