示例#1
0
        /// <summary>
        /// Gets (or creates) a DataPackage (collection of data around a map)
        /// Grabs data for a type/map
        /// Updates/creates set of data in DataPackage IndividualMaps with new data
        /// Makes master data stale
        /// When required, stale data will regenerate to master list
        /// Means that we only ever update individual maps, if required - rather than requiry all if we are requested to refresh one
        /// Also means we only update stale data when required (rather than every time, if we are e.g. loading multiple maps we do this at the end)
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="map"></param>
        /// <param name="uri"></param>
        /// <param name="metaData"></param>
        /// <returns></returns>
        public async Task <int> GetDataAsync(string rawServerTimestamp, DateTime serverTimestamp, Dictionary <string, DataPackage> dataPackages, ServerConfig serverConfig, MainWindow mainWindow, bool forceLocalLoad)
        {
            // Note we DON'T currently do any parallel loading of data from the server to help cut down on server traffic. Lovely that we might
            // download data for all maps at once - but we don't want to eat into all the servers bandwidth and players are potentially affected! (E.g. web server is running on same pc as Ark Server)
            // ToDo: Make this a config option to enable/disable parallel download

            string mapName = MapName;

            try
            {
                string      metaDataType = MetaData.ArkEntityType;
                DataPackage dataPackage;

                if (dataPackages.ContainsKey(metaDataType))
                {
                    dataPackage = dataPackages[metaDataType];
                    UIMapSelection.CacheState = "Updating existing data package";
                }
                else
                {
                    dataPackage = new DataPackage()
                    {
                        Metadata       = MetaData,
                        IndividualMaps = new Dictionary <string, MapPackage>()
                    };
                    dataPackages.Add(metaDataType, dataPackage);

                    UIMapSelection.CacheState = "New data package";
                }

                UIMapSelection.DisplayState = "...Downloading";
                mainWindow.Dispatcher.Invoke(() => Globals.MainWindow.MapsToInclude.Items.Refresh());

                IEnumerable <IArkEntity> result;
#if DEBUG
                // Local debugging test - load data from local file
                if (forceLocalLoad)
                {
                    result = (IEnumerable <IArkEntity>)JsonSerializer.Deserialize(File.ReadAllText("./temp.json"), typeof(List <>).MakeGenericType(MetaData.JsonClassType));
                }
                else
#endif
                result = (IEnumerable <IArkEntity>) await Web.HttpClient.GetFromJsonAsync(DataUri, typeof(List <>).MakeGenericType(MetaData.JsonClassType));

                // Extra processing of data goes here - e.g. calculating extra data values not in JSON and not part of JSON import translations
                // E.g. colour sort data, as we can't easily read single json colour values into 2 properties at once during import
                if (typeof(IArkEntityWithCreature).IsAssignableFrom(result.GetType().GetGenericArguments()[0]))
                {
                    // It's a creature! it has colours :)
                    foreach (IArkEntityWithCreature creature in result)
                    {
                        creature.C0_Sort = creature.C0?.SortOrder ?? -1;   // Colour.SortKeyFromColor(creature.C0);
                        creature.C1_Sort = creature.C1?.SortOrder ?? -1;
                        creature.C2_Sort = creature.C2?.SortOrder ?? -1;
                        creature.C3_Sort = creature.C3?.SortOrder ?? -1;
                        creature.C4_Sort = creature.C4?.SortOrder ?? -1;
                        creature.C5_Sort = creature.C5?.SortOrder ?? -1;
                    }
                }

                UIMapSelection.DisplayState = "...Decoding";
                mainWindow.Dispatcher.Invoke(() => Globals.MainWindow.MapsToInclude.Items.Refresh());

                DataTablePlus newData       = new(result, MetaData.JsonClassType, mapName, MetaData);
                MapPackage    newMapPackage = new()
                {
                    Data = newData
                };

                UIMapSelection.DisplayState = "Loaded";
                mainWindow.Dispatcher.Invoke(() => Globals.MainWindow.MapsToInclude.Items.Refresh());

                // Only calculate timestamps if they haven't already just been snagged
                if (rawServerTimestamp == string.Empty)
                {
                    DataTimestamp jsonTimestamp = await Web.HttpClient.GetFromJsonAsync <DataTimestamp>(TimestampUri);

                    rawServerTimestamp = jsonTimestamp.Date;
                    if (DateTime.TryParseExact(rawServerTimestamp, "yyyyMMdd_HHmm", CultureInfo.InvariantCulture, DateTimeStyles.None, out serverTimestamp))
                    {
                        Debug.Print($"GetDataAsync updating from web site into newMapPackage.Timestamp from {newMapPackage.Timestamp} to {serverTimestamp} : {mapName}.{metaDataType}");
                        newMapPackage.Timestamp = serverTimestamp;
                    }
                    else
                    {
                        MessageBox.Show($"Error reading timestamp for {mapName}.{metaDataType}, value returned: '{rawServerTimestamp}'", "Date error", MessageBoxButton.OK, MessageBoxImage.Error);
                        UIMapSelection.CacheState = "Timestamp error";
                        mainWindow.Dispatcher.Invoke(() => Globals.MainWindow.MapsToInclude.Items.Refresh());
                    }
                }
                else
                {
                    Debug.Print($"GetDataAsync updating from cached timestamp into newMapPackage.Timestamp from {newMapPackage.Timestamp} to {serverTimestamp} : {mapName}.{metaDataType}");
                    newMapPackage.Timestamp = serverTimestamp;
                }
                newMapPackage.RawTimestamp = rawServerTimestamp;
                newMapPackage.ApproxNextServerUpdateTimestamp = newMapPackage.Timestamp.AddMinutes(serverConfig.RefreshRate);

                var maps = dataPackage.IndividualMaps;
                if (maps.ContainsKey(mapName))
                {
                    maps[mapName] = newMapPackage;
                }
                else
                {
                    maps.Add(mapName, newMapPackage);
                }

                Debug.Print($"GetDataAsync CurrentDataPackage == dataPackage {mainWindow.CurrentDataPackage == dataPackage} to trigger visual refresh");

                mainWindow.Dispatcher.Invoke(() => { mainWindow.MapData.ItemsSource = mainWindow.CurrentDataPackage?.IndividualMaps.ToList(); }); //This SHOULD work but doesn't visually --> if (CurrentDataPackage == dataPackage) ExtraInfoMapData.Items.Refresh(); });

                dataPackage.DataIsStale = true;

                return(newData.Rows.Count);
            }
            catch (HttpRequestException ex)
            {
                Errors.ReportProblem(ex, $"Error retrieving JSON data for { MetaData.Description} on {mapName}: {ex.StatusCode}");
                UIMapSelection.CacheState = "Retrieval error";
            }
            catch (NotSupportedException ex)
            {
                Errors.ReportProblem(ex, $"Invalid content type in JSON data for { MetaData.Description} on {mapName}");
                UIMapSelection.CacheState = "Content error";
            }
            catch (JsonException ex)
            {
                Errors.ReportProblem(ex, $"Invalid JSON retrieving JSON data for { MetaData.Description} on {mapName}");
                UIMapSelection.CacheState = "JSON error";
            }
            catch (Exception ex)
            {
                Errors.ReportProblem(ex, $"Problem loading JSON data for { MetaData.Description} on {mapName}");
                UIMapSelection.CacheState = "Loading error";
            }

            UIMapSelection.DisplayState = "Error";

            return(-1);
        }
示例#2
0
        // Goes through each individual map and generates a new master set of data by merging them together
        public void MakeSureDataIsUpToDate()
        {
            if (!DataIsStale)
            {
                return;
            }

            if (IndividualMaps.Count == 0)
            {
                MapsDescription = "No maps loaded";
                return;
            }

            bool success  = false;
            int  attempts = 1;

            while (!success)
            {
                // it's possible for the data to be modified while we are processing it (e.g. background process is re-generating it)
                // which will throw an exception here. So we catch and handle this by trying again.
                try
                {
                    DataTable = new DataTablePlus();

                    // Set up copy of datatable structure only (no data)
                    var firstMap = IndividualMaps.First().Value;
                    // Following only copies structure + ColumnPositions etc. - doesn't copy rows of data. This will be handled in the foreach below, which also adds this maps data.
                    DataTable = firstMap.Data.DeepCopy();

                    MapsDescription = $"Showing data for {Metadata.Description}s";
                    Debug.Print($"Map data for {Metadata.Description}s is made up of...");

                    foreach (KeyValuePair <string, MapPackage> map in IndividualMaps)
                    {
                        MapPackage mapPackage = map.Value;
                        Debug.Print($"   {Metadata.ArkEntityType}.{map.Key} - {mapPackage.Data.Rows.Count}");

                        // ToDo: Check this isnt remerging the now cloned dataset into itself!
                        this.DataTable.Merge(mapPackage.Data);
                    }

                    success = true;
                }
                catch (Exception ex)
                {
                    Debug.Print($"Error generating map data - restarting");
                    attempts++;

                    Thread.Sleep(attempts * 100);

                    if (attempts > 5)
                    {
                        Errors.ReportProblem(ex, "Internal problem updating data. Map data might not be showing correctly. Will keep going though! Feel free to try again...");

                        success = true;
                    }
                }
            }

            Debug.Print($"...{this.DataTable.Rows.Count} total (took {attempts} attempts)");

            DataIsStale = false;
        }