Skip to content

Commit

Permalink
Release 1.14.0
Browse files Browse the repository at this point in the history
Release 1.14.0
  • Loading branch information
Yelo420 authored Dec 21, 2024
2 parents 6702eb9 + 0e18fee commit 9834c0b
Show file tree
Hide file tree
Showing 32 changed files with 1,136 additions and 113 deletions.
21 changes: 18 additions & 3 deletions .github/workflows/deployment-develop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ jobs:
deploy:
permissions: write-all
runs-on: windows-latest
outputs:
version: ${{ steps.release.outputs.version }}

steps:
- name: Checkout repository
id: checkout
Expand All @@ -16,8 +19,20 @@ jobs:
id: setup
uses: actions/[email protected]
with:
dotnet-version: '6.x'
dotnet-version: '8.x'

- name: Build .NET Solution
- name: Build .NET solution
id: build
run: dotnet build gamevault.sln --configuration Release
run: |
dotnet build gamevault.sln --configuration Release
7z a GameVault.zip gamevault/bin
- name: Upload binaries to release
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: GameVault.zip
asset_name: GameVault.zip
tag: unstable
overwrite: true
prerelease: true
2 changes: 1 addition & 1 deletion .github/workflows/deployment-master.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
id: setup
uses: actions/[email protected]
with:
dotnet-version: '6.x'
dotnet-version: '8.x'

- name: Build .NET solution
id: build
Expand Down
17 changes: 17 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,22 @@
# GameVault App Changelog

## 1.14.0
Recommended Gamevault Server Version: `v13.1.2`
### Changes

- Sync the currently played game with the discord Presence API (+)
- Sync installed Gamevault games with Steam shortcuts (+)
- The popup window now also closes when you have uninstalled a setup game
- Enhanced offline handling
- Added a new Christmas theme (+).
- Bug fix: Added increasing tick rate to download retry timer to avoid continuous spam
- Bug fix: Media slider video was sometimes rendered on top of a popup
- Bug fix: Crash on Media Slider navigation
- Bug fix: Crash on create shortcut after installation
- Bug fix: Prevent the message copy button from taking focus away from the current control
- Bug fix: Animated profile pictures were still displayed when switching to a profile without a set profile picture
- Bug fix: Improved Gif decoder

## 1.13.1
Recommended Gamevault Server Version: `v13.1.0`
### Changes
Expand Down
5 changes: 4 additions & 1 deletion gamevault/App.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ protected override void OnStartup(StartupEventArgs e)
base.OnStartup(e);
AnalyticsHelper.Instance.InitHeartBeat();
AnalyticsHelper.Instance.RegisterGlobalEvents();
AnalyticsHelper.Instance.SendCustomEvent("APP_INITIALIZED", AnalyticsHelper.Instance.GetSysInfo());
AnalyticsHelper.Instance.SendCustomEvent(CustomAnalyticsEventKeys.APP_INITIALIZED, AnalyticsHelper.Instance.GetSysInfo());
}

private async void Application_Startup(object sender, StartupEventArgs e)
Expand All @@ -85,6 +85,9 @@ private async void Application_Startup(object sender, StartupEventArgs e)
#endif
await LoginManager.Instance.StartupLogin();
await LoginManager.Instance.PhalcodeLogin(true);

AnalyticsHelper.Instance.SendCustomEvent(CustomAnalyticsEventKeys.USER_SETTINGS, AnalyticsHelper.Instance.PrepareSettingsForAnalytics());

m_gameTimeTracker = new GameTimeTracker();
await m_gameTimeTracker.Start();

Expand Down
2 changes: 1 addition & 1 deletion gamevault/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
)]
[assembly: AssemblyVersion("1.13.1.0")]
[assembly: AssemblyVersion("1.14.0.0")]
[assembly: AssemblyCopyright("© Phalcode™. All Rights Reserved.")]
#if DEBUG
[assembly: XmlnsDefinition("debug-mode", "Namespace")]
Expand Down
32 changes: 28 additions & 4 deletions gamevault/Helper/AnalyticsHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
using System.IO;
using System.Linq;
using System.Management;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Reflection;
Expand All @@ -30,6 +31,13 @@

namespace gamevault.Helper
{
internal static class CustomAnalyticsEventKeys
{
internal static string APP_INITIALIZED => "APP_INITIALIZED";
internal static string EASTER_EGG => "EASTER_EGG";
internal static string SERVER_USER_COUNT => "SERVER_USER_COUNT";
internal static string USER_SETTINGS => "USER_SETTINGS";
}
internal class AnalyticsHelper
{
#region Singleton
Expand Down Expand Up @@ -167,8 +175,7 @@ private async Task SendHeartBeat(string url)
try
{
var jsonContent = new StringContent(JsonSerializer.Serialize(new AnalyticsData()), Encoding.UTF8, "application/json");
await client.PostAsync(url, jsonContent);
//string responseBody = await response.Content.ReadAsStringAsync();
await client.PostAsync(url, jsonContent);
}
catch (Exception e) { }

Expand Down Expand Up @@ -196,7 +203,7 @@ public void SendErrorLog(Exception ex)
{
try
{
var jsonContent = new StringContent(JsonSerializer.Serialize(new AnalyticsData() { ExceptionType = ex.GetType().ToString(), ExceptionMessage = $"Message:{ex.Message} | InnerException:{ex.InnerException?.Message} | StackTrace:{ex.StackTrace?.Substring(0, Math.Min(2000, ex.StackTrace.Length))} | Is Windows Package: {(App.IsWindowsPackage == true ? "True" : "False")}", Timezone = timeZone, Language = language }), Encoding.UTF8, "application/json");
var jsonContent = new StringContent(JsonSerializer.Serialize(new AnalyticsData() { ExceptionType = ex.GetType().ToString(), ExceptionMessage = $"Message:{ex.Message} | InnerException:{ex.InnerException?.Message} | StackTrace:{ex.StackTrace?.Substring(0, Math.Min(2000, ex.StackTrace.Length))} | Is Windows Package: {(App.IsWindowsPackage == true ? "True" : "False")} | Version: {SettingsViewModel.Instance.Version}", Timezone = timeZone, Language = language }), Encoding.UTF8, "application/json");
await client.PostAsync(AnalyticsTargets.ER, jsonContent);
}
catch (Exception ex) { }
Expand All @@ -210,7 +217,8 @@ public void SendCustomEvent(string eventName, object meta)
try
{
var jsonContent = new StringContent(JsonSerializer.Serialize(new AnalyticsData() { Event = eventName, Metadata = meta, Timezone = timeZone, Language = language }), Encoding.UTF8, "application/json");
await client.PostAsync(AnalyticsTargets.CU, jsonContent);
HttpResponseMessage res =
await client.PostAsync(AnalyticsTargets.CU, jsonContent);
}
catch { }
});
Expand Down Expand Up @@ -273,6 +281,22 @@ public object GetSysInfo()
return new { app_version = SettingsViewModel.Instance.Version, hardware_os = $"The system information could not be loaded due to an {ex.GetType().Name}" };
}
}
public Dictionary<string, string> PrepareSettingsForAnalytics()
{
try
{
var propertiesToExclude = new[] { "Instance", "UserName", "RootPath", "ServerUrl", "License", "RegistrationUser", "SendAnonymousAnalytics", "IgnoreList", "Themes" };
var trimmedObject = SettingsViewModel.Instance.GetType()
.GetProperties()
.Where(prop => !propertiesToExclude.Contains(prop.Name))
.ToDictionary(prop => prop.Name, prop => prop.GetValue(SettingsViewModel.Instance).ToString());

trimmedObject.Add("HasLicence", (SettingsViewModel.Instance.License?.IsActive() == true).ToString());
return trimmedObject;
}
catch { }
return null;
}
private bool IsWineRunning()
{
// Search for WINLOGON process
Expand Down
60 changes: 55 additions & 5 deletions gamevault/Helper/CacheHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ internal static async Task CreateOfflineCacheAsync(Game game)
catch { }
}

internal static async Task HandleImageCacheAsync(int identifier, int imageId, string cachePath, ImageCache cacheType, System.Windows.Controls.Image img)
internal static async Task LoadImageCacheToUIAsync(int identifier, int imageId, string cachePath, ImageCache cacheType, System.Windows.Controls.Image img)
{
string cacheFile = $"{cachePath}/{identifier}.{imageId}";
try
Expand Down Expand Up @@ -108,9 +108,49 @@ internal static async Task HandleImageCacheAsync(int identifier, int imageId, st
}
}
catch { }
img.BeginAnimation(System.Windows.Controls.Image.SourceProperty, null);//Make sure all animations are removed, so a non animated image can be set to the source
img.Source = GetReplacementImage(cacheType);
}
}
internal static async Task EnsureImageCacheForGame(Game game)
{
try
{
if (LoginManager.Instance.IsLoggedIn())
{
if (TaskQueue.Instance.IsAlreadyInProcess(game.Metadata.Background.ID))
{
await TaskQueue.Instance.WaitForProcessToFinish(game.Metadata.Background.ID);
}
if (TaskQueue.Instance.IsAlreadyInProcess(game.Metadata.Cover.ID))
{
await TaskQueue.Instance.WaitForProcessToFinish(game.Metadata.Cover.ID);
}

string backGroundCacheFile = $"{AppFilePath.ImageCache}/gbg/{game.ID}.{game.Metadata.Background.ID}";
string boxArtCacheFile = $"{AppFilePath.ImageCache}/gbox/{game.ID}.{game.Metadata.Cover.ID}";
if (!Directory.Exists($"{AppFilePath.ImageCache}/gbg"))
{
Directory.CreateDirectory($"{AppFilePath.ImageCache}/gbg");
}
if (!Directory.Exists($"{AppFilePath.ImageCache}/gbox"))
{
Directory.CreateDirectory($"{AppFilePath.ImageCache}/gbox");
}

if (!File.Exists(backGroundCacheFile))
{
//Not in que because its not loading images for the UI
await WebHelper.DownloadImageFromUrlAsync($"{SettingsViewModel.Instance.ServerUrl}/api/media/{game.Metadata.Background.ID}", backGroundCacheFile);
}
if (!File.Exists(boxArtCacheFile))
{
await WebHelper.DownloadImageFromUrlAsync($"{SettingsViewModel.Instance.ServerUrl}/api/media/{game.Metadata.Cover.ID}", boxArtCacheFile);
}
}
}
catch { }
}
internal static BitmapImage GetReplacementImage(ImageCache cacheType)
{
switch (cacheType)
Expand Down Expand Up @@ -148,13 +188,13 @@ await Task.Run(() =>
{
if (GifHelper.IsGif(file))
{
int maxGifHeightWidth = 400;
uint maxGifHeightWidth = 400;
GifHelper.OptimizeGIF(file, maxGifHeightWidth);
image.Refresh();
continue;
}
}
ResizeImage(file, Convert.ToInt32(maxHeight));
ResizeImage(file, Convert.ToUInt32(maxHeight));
image.Refresh();
}
else
Expand All @@ -181,7 +221,17 @@ internal static async Task<string> CreateHashAsync(string input)
return hash;
}
}
private static void ResizeImage(string path, int maxHeight)
internal static Dictionary<string, string> GetImageCacheForGame(Game game)
{
Dictionary<string, string> imageCache = new Dictionary<string, string>();
string cachePath = AppFilePath.ImageCache;
var boxArt = Directory.GetFiles(Path.Combine(cachePath, "gbox").Replace("/", "\\"), $"{game.ID}.*").FirstOrDefault();
var background = Directory.GetFiles(Path.Combine(cachePath, "gbg").Replace("/", "\\"), $"{game.ID}.*").FirstOrDefault();
imageCache.Add("gbox", boxArt);
imageCache.Add("gbg", background);
return imageCache;
}
private static void ResizeImage(string path, uint maxHeight)
{
using (var imageMagick = new MagickImage(path))
{
Expand All @@ -195,7 +245,7 @@ private static void ResizeImage(string path, int maxHeight)
}
else if (imageMagick.Height > SystemParameters.FullPrimaryScreenHeight)
{
var size = new MagickGeometry((int)SystemParameters.FullPrimaryScreenWidth, (int)SystemParameters.FullPrimaryScreenHeight);
var size = new MagickGeometry((uint)SystemParameters.FullPrimaryScreenWidth, (uint)SystemParameters.FullPrimaryScreenHeight);
size.IgnoreAspectRatio = false;
imageMagick.Resize(size);
imageMagick.Write(path);
Expand Down
60 changes: 40 additions & 20 deletions gamevault/Helper/GameTimeTracker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public class GameTimeTracker
private Timer? m_Timer { get; set; }
public async Task Start()
{
await SendOfflineProcess();
await SendOfflineProgess();
await SettingsViewModel.Instance.InitIgnoreList();

m_Timer = new Timer();
Expand All @@ -28,9 +28,9 @@ public async Task Start()
}
private void TimerCallback(object sender, ElapsedEventArgs e)
{
Task.Run(() =>
{
string installationPath = Path.Combine(SettingsViewModel.Instance.RootPath, "GameVault\\Installations");
Task.Run(async () =>
{
string installationPath = Path.Combine(SettingsViewModel.Instance.RootPath, "GameVault\\Installations");

if (!Directory.Exists(installationPath))
return;
Expand Down Expand Up @@ -85,41 +85,61 @@ private void TimerCallback(object sender, ElapsedEventArgs e)
}
}
}
if (true == LoginManager.Instance.IsLoggedIn())
if (LoginManager.Instance.IsLoggedIn())
{
try
{
if(AnyOfflineProgressToSend())
{
await SendOfflineProgess();
}
foreach (int gameid in gamesToCountUp)
{
WebHelper.Put(@$"{SettingsViewModel.Instance.ServerUrl}/api/progresses/user/{LoginManager.Instance.GetCurrentUser().ID}/game/{gameid}/increment", string.Empty);
}
DiscordHelper.Instance.SyncGameWithDiscordPresence(gamesToCountUp, foundGames);
}
catch (Exception ex)
{
LoginManager.Instance.SwitchToOfflineMode();
SaveToOfflineProgress(gamesToCountUp);
}
}
else
{
foreach (int gameid in gamesToCountUp)
{
try
{
string timeString = Preferences.Get(gameid.ToString(), AppFilePath.OfflineProgress, true);
int result = int.TryParse(timeString, out result) ? result : 0;
result++;
Preferences.Set(gameid.ToString(), result, AppFilePath.OfflineProgress, true);
}
catch { }
}
SaveToOfflineProgress(gamesToCountUp);
}
});
}
private async Task SendOfflineProcess()
private bool AnyOfflineProgressToSend()
{
try
{
return new FileInfo(AppFilePath.OfflineProgress).Length > 0;
}
catch
{
return false;
}
}
private void SaveToOfflineProgress(List<int> progress)
{
foreach (int gameid in progress)
{
try
{
string timeString = Preferences.Get(gameid.ToString(), AppFilePath.OfflineProgress, true);
int result = int.TryParse(timeString, out result) ? result : 0;
result++;
Preferences.Set(gameid.ToString(), result, AppFilePath.OfflineProgress, true);
}
catch { }
}
}
private async Task SendOfflineProgess()
{
await Task.Run(() =>
{
if (true == LoginManager.Instance.IsLoggedIn())
if (LoginManager.Instance.IsLoggedIn())
{
foreach (string key in GetAllOfflineCacheKeys())
{
Expand Down Expand Up @@ -165,7 +185,7 @@ private string[] GetAllOfflineCacheKeys()
return keys.ToArray();
}
return new string[0];
}
}
private bool ContainsValueFromIgnoreList(string value)
{
return SettingsViewModel.Instance.IgnoreList.Any(x => x.Contains(value, StringComparison.OrdinalIgnoreCase));
Expand Down
Loading

0 comments on commit 9834c0b

Please sign in to comment.