diff --git a/Elite/App.xaml.cs b/Elite/App.xaml.cs index fe3e9b3..2c0ce0a 100644 --- a/Elite/App.xaml.cs +++ b/Elite/App.xaml.cs @@ -148,6 +148,14 @@ private static void RefreshJson(SplashScreenWindow splashScreen = null) splashScreen?.Dispatcher.Invoke(() => splashScreen.ProgressText.Text = "Loading Tritium Sell Stations..."); MiningStations.FullMiningStationsList[MiningStations.MaterialTypes.TritiumSell] = MiningStations.GetAllMiningStations(@"Data\tritiumstations.json"); + + + splashScreen?.Dispatcher.Invoke(() => splashScreen.ProgressText.Text = "Loading Galnet News feed..."); + Galnet.GalnetList = Galnet.GetGalnet(@"Data\galnet.json"); + + splashScreen?.Dispatcher.Invoke(() => splashScreen.ProgressText.Text = "Loading Galnet Images..."); + Galnet.GetGalnetImages(Galnet.GalnetList); + } if (splashScreen == null) @@ -264,7 +272,7 @@ protected override void OnStartup(StartupEventArgs evtArgs) Engine.Razor.Compile("ship.cshtml", null); Engine.Razor.Compile("navigation.cshtml", null); Engine.Razor.Compile("target.cshtml", null); - Engine.Razor.Compile("missions.cshtml", null); + Engine.Razor.Compile("galnet.cshtml", null); Engine.Razor.Compile("poi.cshtml", null); Engine.Razor.Compile("galaxy.cshtml", null); @@ -274,6 +282,7 @@ protected override void OnStartup(StartupEventArgs evtArgs) Engine.Razor.Compile("cargo.cshtml", null); Engine.Razor.Compile("engineer.cshtml", null); Engine.Razor.Compile("mining.cshtml", null); + Engine.Razor.Compile("missions.cshtml", null); Engine.Razor.Compile("events.cshtml", null); CssData = TheArtOfDev.HtmlRenderer.WinForms.HtmlRender.ParseStyleSheet( diff --git a/Elite/Elite.csproj b/Elite/Elite.csproj index e9e8e3a..cada628 100644 --- a/Elite/Elite.csproj +++ b/Elite/Elite.csproj @@ -57,7 +57,7 @@ ..\packages\Costura.Fody.4.1.0\lib\net40\Costura.dll - ..\packages\CsvHelper.15.0.5\lib\net47\CsvHelper.dll + ..\packages\CsvHelper.15.0.6\lib\net47\CsvHelper.dll ..\packages\Hardcodet.NotifyIcon.Wpf.1.0.8\lib\net451\Hardcodet.Wpf.TaskbarNotification.dll @@ -71,8 +71,8 @@ ..\packages\ini-parser.2.5.2\lib\net20\INIFileParser.dll - - ..\packages\log4net.2.0.10\lib\net45\log4net.dll + + ..\packages\log4net.2.0.11\lib\net45\log4net.dll ..\packages\Microsoft.Bcl.AsyncInterfaces.1.1.1\lib\net461\Microsoft.Bcl.AsyncInterfaces.dll @@ -128,6 +128,7 @@ MSBuild:Compile Designer + @@ -201,6 +202,9 @@ Always + + Always + Always @@ -262,6 +266,9 @@ Always + + Always + Always @@ -435,6 +442,7 @@ EliteJournalReader + diff --git a/Elite/FipPanel.cs b/Elite/FipPanel.cs index d3568ea..05f2d49 100644 --- a/Elite/FipPanel.cs +++ b/Elite/FipPanel.cs @@ -49,7 +49,7 @@ public enum LcdTab Commander = 1, Navigation = 2, Target = 3, - Missions = 4, + Galnet = 4, ShipMenu = 5, // ship -> LocationsMenu = 6, // locations -> @@ -60,7 +60,7 @@ public enum LcdTab Materials = 9, Cargo = 10, Engineer = 11, - Events = 12, + Missions = 12, //--------------- @@ -659,9 +659,8 @@ public void HandleJoystickButton(JoystickButton joystickButton, bool state, bool switch (_currentTabCursor) { - - case LcdTab.Events: - //Events > Engineer > Cargo > Materials > Ship > ShipBack + case LcdTab.Missions: + //Missions > Engineer > Cargo > Materials > Ship > ShipBack _currentTabCursor -= 1; @@ -676,7 +675,7 @@ public void HandleJoystickButton(JoystickButton joystickButton, bool state, bool _currentTabCursor = LcdTab.LocationsMenu; break; case LcdTab.ShipBack: - _currentTabCursor = LcdTab.Events; + _currentTabCursor = LcdTab.Missions; break; case LcdTab.LocationsBack: _currentTabCursor = LcdTab.Mining; @@ -708,7 +707,7 @@ public void HandleJoystickButton(JoystickButton joystickButton, bool state, bool { case LcdTab.Cargo: - //ShipBack > Ship > Materials > Cargo > Engineer > Events + //ShipBack > Ship > Materials > Cargo > Engineer > Missions _currentTabCursor += 1; @@ -722,7 +721,7 @@ public void HandleJoystickButton(JoystickButton joystickButton, bool state, bool case LcdTab.LocationsMenu: _currentTabCursor = LcdTab.Commander; break; - case LcdTab.Events: + case LcdTab.Missions: _currentTabCursor = LcdTab.ShipBack; break; case LcdTab.Mining: @@ -876,7 +875,8 @@ private void SoftButtonCallback(IntPtr device, IntPtr buttons, IntPtr context) if (state && (CurrentTab == LcdTab.POI || CurrentTab == LcdTab.Powers || CurrentTab == LcdTab.Materials || CurrentTab == LcdTab.Galaxy || CurrentTab == LcdTab.Ship || CurrentTab == LcdTab.Mining || - CurrentTab == LcdTab.Navigation || CurrentTab == LcdTab.Engineer)) + CurrentTab == LcdTab.Navigation || CurrentTab == LcdTab.Engineer || + CurrentTab == LcdTab.Galnet)) { _currentCard[(int) CurrentTab]++; @@ -892,7 +892,8 @@ private void SoftButtonCallback(IntPtr device, IntPtr buttons, IntPtr context) if (state && (CurrentTab == LcdTab.POI || CurrentTab == LcdTab.Powers || CurrentTab == LcdTab.Materials || CurrentTab == LcdTab.Galaxy || CurrentTab == LcdTab.Ship || CurrentTab == LcdTab.Mining || - CurrentTab == LcdTab.Navigation || CurrentTab == LcdTab.Engineer)) + CurrentTab == LcdTab.Navigation || CurrentTab == LcdTab.Engineer || + CurrentTab == LcdTab.Galnet)) { _currentCard[(int) CurrentTab]--; _currentZoomLevel[(int) CurrentTab]--; @@ -973,7 +974,7 @@ private void SoftButtonCallback(IntPtr device, IntPtr buttons, IntPtr context) mustRefresh = SetTab(LcdTab.Target); break; case 256: - mustRefresh = SetTab(LcdTab.Missions); + mustRefresh = SetTab(LcdTab.Galnet); break; case 512: mustRefresh = true; @@ -1022,7 +1023,7 @@ private void SoftButtonCallback(IntPtr device, IntPtr buttons, IntPtr context) } break; case 1024: - mustRefresh = SetTab(LcdTab.Events); + mustRefresh = SetTab(LcdTab.Missions); break; case 2048: mustRefresh = true; @@ -1384,6 +1385,20 @@ public void RefreshDevicePage(bool mustRender = true) } break; + case LcdTab.Galnet: + + if (_currentCard[(int)CurrentTab] < 0) + { + _currentCard[(int)CurrentTab] = 0; + } + else + if (_currentCard[(int)CurrentTab] > (Galnet.GalnetList?.Count ?? 1) - 1) + { + _currentCard[(int)CurrentTab] = (Galnet.GalnetList?.Count ?? 1) - 1; + } + + break; + } if (mustRender) @@ -1672,19 +1687,29 @@ public void RefreshDevicePage(bool mustRender = true) break; - case LcdTab.Missions: + case LcdTab.Galnet: + + var currentCard = _currentCard[(int)CurrentTab]; + + if (Galnet.GalnetList?.Count <= currentCard -1) + { + currentCard = _currentCard[(int) CurrentTab] = 0; + } str = - Engine.Razor.Run("missions.cshtml", null, new + Engine.Razor.Run("galnet.cshtml", null, new { CurrentTab = CurrentTab, CurrentPage = _currentPage, + CurrentCard = currentCard, - MissionList = Missions.MissionList + Galnet = Galnet.GalnetList.Skip(currentCard).FirstOrDefault().Value + }); break; + case LcdTab.POI: lock (App.RefreshJsonLock) @@ -1931,6 +1956,19 @@ public void RefreshDevicePage(bool mustRender = true) break; + case LcdTab.Missions: + + str = + Engine.Razor.Run("missions.cshtml", null, new + { + CurrentTab = CurrentTab, + CurrentPage = _currentPage, + + MissionList = Missions.MissionList + }); + + break; +/* case LcdTab.Events: var eventlist = ""; @@ -1949,7 +1987,7 @@ public void RefreshDevicePage(bool mustRender = true) }); break; - +*/ } @@ -2013,12 +2051,39 @@ public void RefreshDevicePage(bool mustRender = true) { if (mustRender) { + var currentCard = _currentCard[(int) CurrentTab]; + + var galnetDate = "???"; + var galnetCaption = "Galnet"; + + var galNetCount = Galnet.GalnetList?.Count ?? 0; + + if (CurrentTab == LcdTab.Galnet && galNetCount > currentCard) + { + galnetDate = Galnet.GalnetList.Skip(currentCard).FirstOrDefault().Value + .FirstOrDefault()?.Date; + } + + if (currentCard > 0) + { + galnetCaption = "◀ " + galnetCaption; + } + + galnetCaption += " : " + galnetDate; + + if (currentCard < galNetCount -1) + { + galnetCaption += " ▶"; + } + var cardcaptionstr = Engine.Razor.Run("cardcaption.cshtml", null, new { CurrentTab = CurrentTab, CurrentPage = _currentPage, - CurrentCard = _currentCard[(int)CurrentTab] + CurrentCard = currentCard, + + GalnetCaption = galnetCaption }); _cardcaptionHtmlImage = HtmlRender.RenderToImage(cardcaptionstr, diff --git a/Elite/Galnet.cs b/Elite/Galnet.cs new file mode 100644 index 0000000..2407047 --- /dev/null +++ b/Elite/Galnet.cs @@ -0,0 +1,113 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net; +using Newtonsoft.Json; +// ReSharper disable IdentifierTypo + +namespace Elite +{ + public class GalnetData + { + [JsonProperty("title")] + public string Title { get; set; } + + [JsonProperty("body")] + public string Body { get; set; } + + [JsonProperty("nid")] + public string Nid { get; set; } + + [JsonProperty("date")] + public string Date { get; set; } + + + [JsonProperty("imageList")] + public List ImageList { get; set; } + + + [JsonProperty("slug")] + public string Slug { get; set; } + + } + + public static class Galnet + { + public static Dictionary>GalnetList = new Dictionary>(); + + public static Dictionary> GetGalnet(string path) + { + try + { + path = Path.Combine(App.ExePath, path); + + if (File.Exists(path)) + { + return JsonConvert.DeserializeObject>(File.ReadAllText(path)) + .GroupBy(x => x.Date) + .ToDictionary(x => x.Key, x => x.ToList()) + .Take(10).ToDictionary(kvp => kvp.Key, kvp => kvp.Value); + } + } + catch (Exception ex) + { + App.Log.Error(ex); + } + + return new Dictionary>(); + + } + + public static void GetGalnetImages(Dictionary> GalnetList) + { + try + { + var directory = Path.Combine(App.ExePath, "templates/images/galnet"); + + foreach (var l in GalnetList) + { + foreach (var n in l.Value) + { + for (var i = 0; i < n.ImageList.Count; i++) + { + if (!string.IsNullOrEmpty(n.ImageList[i])) + { + var imageName = n.ImageList[i] + ".png"; + + var imgPath = Path.Combine(directory, imageName); + + if (!File.Exists(imgPath)) + { + try + { + using (var client = new WebClient()) + { + client.Headers[HttpRequestHeader.AcceptEncoding] = "gzip"; + var data = client.DownloadData("https://hosting.zaonce.net/elite-dangerous/galnet/" + imageName); + + File.WriteAllBytes(imgPath, data); + } + } + catch + { + App.Log.Error("galnet image not found " + imageName); + + n.ImageList[i] = null; + } + } + } + } + } + } + } + catch (Exception ex) + { + App.Log.Error(ex); + } + + } + + + } +} diff --git a/Elite/Properties/AssemblyInfo.cs b/Elite/Properties/AssemblyInfo.cs index bcf1867..5d8a9cf 100644 --- a/Elite/Properties/AssemblyInfo.cs +++ b/Elite/Properties/AssemblyInfo.cs @@ -31,7 +31,7 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.4.9.0")] -[assembly: AssemblyFileVersion("1.4.9.0")] +[assembly: AssemblyVersion("1.5.0.0")] +[assembly: AssemblyFileVersion("1.5.0.0")] [assembly: log4net.Config.XmlConfigurator(Watch = true)] \ No newline at end of file diff --git a/Elite/Templates/cardcaption.cshtml b/Elite/Templates/cardcaption.cshtml index daa8c91..3bb994e 100644 --- a/Elite/Templates/cardcaption.cshtml +++ b/Elite/Templates/cardcaption.cshtml @@ -22,10 +22,14 @@ {
Missions
} - else if (Model.CurrentTab == LcdTab.Events) + else if (Model.CurrentTab == LcdTab.Galnet) { -
Events
+
@Html.Raw(Model.GalnetCaption)
} + @*else if (Model.CurrentTab == LcdTab.Events) + { +
Events
+ }*@ else if (Model.CurrentTab == LcdTab.Ship) { if (Model.CurrentCard == 0) diff --git a/Elite/Templates/galnet.cshtml b/Elite/Templates/galnet.cshtml new file mode 100644 index 0000000..e12d59e --- /dev/null +++ b/Elite/Templates/galnet.cshtml @@ -0,0 +1,41 @@ +@using System +@using System.Collections.Generic +@using Elite +@using System.Linq +@using System.Security.Cryptography.X509Certificates +@{ + Layout = "layout.cshtml"; +} + +
+ +
 
+ + @if (Model.Galnet != null) + { + foreach (var m in Model.Galnet) + { +
@m.Title
+ + if (m.ImageList != null) + { + foreach (var im in m.ImageList) + { + if (!string.IsNullOrEmpty(im)) + { +
+ } + } + } +
@Html.Raw(m.Body)
+ + if (!((List) Model.Galnet).Last().Equals((GalnetData) m)) + { +
+
 
+ } + + } + } + +
\ No newline at end of file diff --git a/Elite/Templates/images/galnet/NewsImageDeathOfEmperor.png b/Elite/Templates/images/galnet/NewsImageDeathOfEmperor.png new file mode 100644 index 0000000..60aa967 Binary files /dev/null and b/Elite/Templates/images/galnet/NewsImageDeathOfEmperor.png differ diff --git a/Elite/Templates/menu.cshtml b/Elite/Templates/menu.cshtml index c7217a6..70398d1 100644 --- a/Elite/Templates/menu.cshtml +++ b/Elite/Templates/menu.cshtml @@ -15,7 +15,7 @@
TARGET
-
MISSIONS
+
GALNET
@@ -59,7 +59,7 @@ -
EVENTS
+
MISSIONS
diff --git a/Elite/Templates/styles.css b/Elite/Templates/styles.css index e4322d9..5edc2ee 100644 --- a/Elite/Templates/styles.css +++ b/Elite/Templates/styles.css @@ -140,4 +140,16 @@ ul { .smallfont { font-size: 11px; +} + +.galnetbody { + margin-right: 10px; +} + +.galnetbody br { + margin-bottom: 10px; +} + +.galnettitle { + margin-bottom: 20px; } \ No newline at end of file diff --git a/Elite/packages.config b/Elite/packages.config index 3704a52..512075a 100644 --- a/Elite/packages.config +++ b/Elite/packages.config @@ -1,12 +1,12 @@  - + - + diff --git a/ImportData/GalnetData.cs b/ImportData/GalnetData.cs new file mode 100644 index 0000000..6efdc8a --- /dev/null +++ b/ImportData/GalnetData.cs @@ -0,0 +1,31 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace ImportData +{ + public class GalnetData + { + [JsonProperty("title")] + public string Title { get; set; } + + [JsonProperty("body")] + public string Body { get; set; } + + [JsonProperty("nid")] + public string Nid { get; set; } + + [JsonProperty("date")] + public string Date { get; set; } + + [JsonProperty("image")] + public string Image { get; set; } + + [JsonProperty("imageList")] + public List ImageList { get; set; } + + + [JsonProperty("slug")] + public string Slug { get; set; } + + } +} diff --git a/ImportData/ImportData.csproj b/ImportData/ImportData.csproj index 2e44969..fc7255d 100644 --- a/ImportData/ImportData.csproj +++ b/ImportData/ImportData.csproj @@ -48,8 +48,8 @@ ..\packages\HtmlAgilityPack.1.11.24\lib\Net45\HtmlAgilityPack.dll - - ..\packages\log4net.2.0.10\lib\net45\log4net.dll + + ..\packages\log4net.2.0.11\lib\net45\log4net.dll ..\packages\Newtonsoft.Json.12.0.3\lib\net45\Newtonsoft.Json.dll @@ -70,6 +70,7 @@ + diff --git a/ImportData/Program.cs b/ImportData/Program.cs index 3760219..ca95640 100644 --- a/ImportData/Program.cs +++ b/ImportData/Program.cs @@ -315,6 +315,97 @@ private static void DownloadHotspotSystems(string path, string url, string mater } + private static void GalnetSerialize(List systems, string fullPath) + { + new FileInfo(fullPath).Directory?.Create(); + + var serializer = new JsonSerializer + { + NullValueHandling = NullValueHandling.Ignore + }; + + using (var sw = new StreamWriter(fullPath)) + using (var writer = new JsonTextWriter(sw)) + { + serializer.Serialize(writer, systems); + } + } + + private static bool RemoteFileExists(string url) + { + try + { + //Creating the HttpWebRequest + HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest; + //Setting the Request method HEAD, you can also use GET too. + request.Method = "HEAD"; + //Getting the Web Response. + HttpWebResponse response = request.GetResponse() as HttpWebResponse; + //Returns TRUE if the Status code == 200 + response.Close(); + return (response.StatusCode == HttpStatusCode.OK); + } + catch + { + //Any exception will returns false. + return false; + } + } + + private static void DownloadGalnet(string path, string url) + { + try + { + path = Path.Combine(GetExePath(), path); + + DeleteExpiredFile(path, 720); + + if (!File.Exists(path)) + { + Console.WriteLine("looking up galnet"); + + using (var client = new WebClient()) + { + var data = client.DownloadString(url); + + var galnetJson = JsonConvert.DeserializeObject>(data)?.Take(100).ToList(); + + if (galnetJson?.Any() == true) + { + galnetJson.ForEach(x => + { + x.ImageList = new List(); + + if (!string.IsNullOrEmpty(x.Image)) + { + foreach (var i in x.Image.TrimStart(',').Split(',').ToList()) + { + if (!string.IsNullOrEmpty(i)) + { + if (RemoteFileExists("https://hosting.zaonce.net/elite-dangerous/galnet/" + i + ".png")) + { + x.ImageList.Add(i); + } + } + } + } + + x.Image = null; + + }); + + GalnetSerialize(galnetJson, path); + } + } + } + } + catch (Exception ex) + { + Log.Error(ex); + } + } + + private class HotspotStationData { public string System { get; set; } @@ -895,6 +986,8 @@ static void Main(string[] args) DownloadHotspotSystems(@"Data\painitesystems.json", "http://edtools.cc/miner?a=r&n=", "Painite"); DownloadHotspotSystems(@"Data\ltdsystems.json", "http://edtools.cc/miner?a=r&n=", "LTD"); + DownloadGalnet(@"Data\galnet.json", "https://elitedangerous-website-backend-production.elitedangerous.com/api/galnet?_format=json"); + } catch (Exception ex) diff --git a/ImportData/packages.config b/ImportData/packages.config index 54b79d3..fa9a0f7 100644 --- a/ImportData/packages.config +++ b/ImportData/packages.config @@ -3,6 +3,6 @@ - + \ No newline at end of file diff --git a/README.md b/README.md index 99880b5..eaed614 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ Use the right rotary encoder to scroll vertically on all tabs. Use the left rotary encoder to show another card on various tabs or zoom into the galaxy map. -Use S1 to display the menu. +Press the S1 button to display the menu. You can also control ONE Flight Instrument Panel with a HOTAS 4-way hat switch with pushbutton. @@ -48,13 +48,13 @@ Otherwise these values are ignored. You can then use a tool like [OVR Toolkit](https://store.steampowered.com/app/1068820/OVR_Toolkit/) to display this window in VR. -The 'Engineer' tab is integrated with the material shopping list of the [EDengineer](https://github.com/msarilar/EDEngineer) application. +The 'Engineer' tab is integrated with the material shopping list of the [EDEngineer](https://github.com/msarilar/EDEngineer) application. -The local api must be active in EDengineer and listening on port 44405 +The local api must be active in EDEngineer and listening on port 44405 -This is optional, you don't have to have edengineer running. +**This is optional, EDEngineer doesn't have to be installed or running.** -You can automatically open the 'Target' tab on ONE Flight Instrument Panel, when a ship is targeted (ShipTargeted event). +You can automatically open the 'Target' tab on ONE Flight Instrument Panel, when a ship is targeted. (ShipTargeted event). You can automatically open the 'Navigation' tab on ONE Flight Instrument Panel, when a ship enters a system, approaches a station or a planet. (ApproachBody, ApproachSettlement, DockingRequested, DockingGranted, Docked, CarrierJump, FSDJump, SupercruiseExit events) @@ -94,6 +94,7 @@ Configure the serial number of the Flight Instrument Panel, that needs these fea ![Screenshot 21](https://i.imgur.com/zGm6qOR.png) ![Screenshot 22](https://i.imgur.com/ncHyT8X.png) ![Screenshot 23](https://i.imgur.com/1ngN8cF.png) +![Screenshot 24](https://i.imgur.com/4gUny6G.png) Works with these 64 bit Logitech Flight Instrument Panel Drivers (currently not with older saitek drivers) :