Skip to content

Commit

Permalink
fix #12
Browse files Browse the repository at this point in the history
Support installation of game state integration configuration from
  • Loading branch information
pjmagee committed Oct 14, 2024
1 parent 99ffd8b commit a5f4da9
Show file tree
Hide file tree
Showing 11 changed files with 221 additions and 28 deletions.
2 changes: 1 addition & 1 deletion dagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@
}
],
"source": "dagger",
"engineVersion": "v0.13.3"
"engineVersion": "v0.13.5"
}
1 change: 1 addition & 0 deletions src/Dota2Helper.Desktop/Dota2Helper.Desktop.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,6 @@
<None Update="appsettings.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<Content Include="gamestate_integration_timers.cfg" CopyToOutputDirectory="Always" />
</ItemGroup>
</Project>
17 changes: 17 additions & 0 deletions src/Dota2Helper.Desktop/gamestate_integration_timers.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
"Dota 2 Integration Configuration"
{
"uri" "http://localhost:4001/"
"timeout" "5.0"
"buffer" "0.1"
"throttle" "0.1"
"heartbeat" "1.0"
"data"
{
"provider" "0"
"map" "1"
"player" "0"
"hero" "0"
"abilities" "0"
"items" "0"
}
}
1 change: 1 addition & 0 deletions src/Dota2Helper/App.axaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ private static IHost CreateHost()
builder.Services.AddSingleton<FakeDotaListener>();
builder.Services.AddSingleton<DotaListener>();
builder.Services.AddSingleton<IListenerStrategy, DynamicListenerStrategy>();
builder.Services.AddSingleton<SteamLibraryService>();

builder.Logging.ClearProviders();
builder.Logging.AddDebug();
Expand Down
4 changes: 2 additions & 2 deletions src/Dota2Helper/Core/Gsi/GameState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ public class GameState
{
[JsonIgnore]
// ReSharper disable once InconsistentNaming
private const string DOTA_GAMERULES_STATE_PRE_GAME = nameof(DOTA_GAMERULES_STATE_PRE_GAME);
const string DOTA_GAMERULES_STATE_PRE_GAME = nameof(DOTA_GAMERULES_STATE_PRE_GAME);

[JsonIgnore]
// ReSharper disable once InconsistentNaming
private const string DOTA_GAMERULES_STATE_GAME_IN_PROGRESS = nameof(DOTA_GAMERULES_STATE_GAME_IN_PROGRESS);
const string DOTA_GAMERULES_STATE_GAME_IN_PROGRESS = nameof(DOTA_GAMERULES_STATE_GAME_IN_PROGRESS);

[JsonPropertyName("map")]
public Map? Map { get; set; }
Expand Down
7 changes: 3 additions & 4 deletions src/Dota2Helper/Core/Gsi/GameStateHolder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,9 @@ namespace Dota2Helper.Core.Gsi;

public class GameStateHolder
{

private static readonly object Lock = new();

private GameState? _state;
static readonly object Lock = new();

GameState? _state;

public GameState? State
{
Expand Down
127 changes: 127 additions & 0 deletions src/Dota2Helper/Core/Gsi/SteamLibraryService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
using System;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text.RegularExpressions;
using Microsoft.Extensions.Logging;
using Microsoft.Win32;

namespace Dota2Helper.Core.Gsi;

public partial class SteamLibraryService(ILogger<SteamLibraryService> logger)
{
const string ConfigFile = "gamestate_integration_timers.cfg";

string? FindGameStateIntegrationPath()
{
var dota2FolderPath = FindDota2InstallationPath();

if (dota2FolderPath == null) return null;

var gameStateIntegrationPath = Path.Combine(dota2FolderPath, "game", "dota", "cfg", "gamestate_integration");
return Directory.Exists(gameStateIntegrationPath) ? gameStateIntegrationPath : null;
}

public bool IsIntegrationInstalled()
{
var gameStateIntegrationPath = FindGameStateIntegrationPath();

if (gameStateIntegrationPath == null) return false;

var configFileFullPath = Path.Combine(gameStateIntegrationPath, ConfigFile);
return File.Exists(configFileFullPath);
}

string? FindDota2InstallationPath()
{
var libraryFoldersPath = GetLibraryFoldersPath();

if (string.IsNullOrEmpty(libraryFoldersPath) || !File.Exists(libraryFoldersPath))
{
logger.LogError("libraryfolders.vdf not found");
return null;
}

var steamInstallPath = GetSteamInstallationPath();

if (string.IsNullOrEmpty(steamInstallPath))
{
logger.LogError("Steam installation path not found");
return null;
}

var steamLibraryPaths = GetSteamLibraryPaths(libraryFoldersPath);

foreach (var steamLibraryPath in steamLibraryPaths)
{
var dota2FolderPath = Path.Combine(steamLibraryPath, "steamapps", "common", "dota 2 beta");

if (Directory.Exists(dota2FolderPath)) return dota2FolderPath;
}

return null;
}

string? GetSteamInstallationPath() => RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? GetWindowsInstall() :
RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? GetMacInstall() : null;

string? GetLibraryFoldersPath()
{
var steamInstallPath = GetSteamInstallationPath();
return steamInstallPath == null ? null : Path.Combine(steamInstallPath, "steamapps", "libraryfolders.vdf");
}

[SupportedOSPlatform("windows")]
string? GetWindowsInstall()
{
const string steamRegistryKey = @"HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Valve\Steam";
const string steamRegistryValue = "InstallPath";

try
{
var installPath = Registry.GetValue(steamRegistryKey, steamRegistryValue, null);

if (installPath != null) return installPath.ToString();
}
catch (Exception ex)
{
logger.LogError(ex, "Failed to read Steam installation path from registry");
}

return null;
}

[SupportedOSPlatform("macos")]
string? GetMacInstall() => Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "Library", "Application Support", "Steam");

string[] GetSteamLibraryPaths(string libraryFoldersVdfPath)
{
var pathRegex = LibraryLocations();
var fileContent = File.ReadAllText(libraryFoldersVdfPath);
var matches = pathRegex.Matches(fileContent);
var libraryPaths = matches.Select(m => m.Groups[1].Value.Replace("\\\\", "\\")).ToList();
return libraryPaths.Where(Directory.Exists).ToArray();
}

public void InstallIntegration()
{
var gameStateIntegrationPath = FindGameStateIntegrationPath();

if (gameStateIntegrationPath == null)
{
logger.LogError("gamestate_integration folder not found");
return;
}

var configFileFullPath = Path.Combine(gameStateIntegrationPath, ConfigFile);
var configFileSourcePath = Path.Combine(Directory.GetCurrentDirectory(), ConfigFile);

if (File.Exists(configFileFullPath)) File.Delete(configFileFullPath);

File.Copy(configFileSourcePath, configFileFullPath);
}

[GeneratedRegex(@"\s*\""path\""\s*\""(.+?)\""", RegexOptions.Compiled)]
private static partial Regex LibraryLocations();
}
2 changes: 1 addition & 1 deletion src/Dota2Helper/Dota2Helper.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
</PropertyGroup>

<ItemGroup>
<AvaloniaResource Include="Assets\**" />
<AvaloniaResource Include="Assets\**" CopyToOutputDirectory="Always" />
</ItemGroup>

<ItemGroup>
Expand Down
16 changes: 13 additions & 3 deletions src/Dota2Helper/ViewModels/SettingsViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using Avalonia.Styling;
using Dota2Helper.Core.Audio;
using Dota2Helper.Core.Configuration;
using Dota2Helper.Core.Gsi;
using Dota2Helper.Core.Timers;
using DynamicData.Binding;
using ReactiveUI;
Expand All @@ -15,10 +16,10 @@ namespace Dota2Helper.ViewModels;

public class SettingsViewModel : ViewModelBase
{
static readonly object WriterLock = new();

readonly static object WriterLock = new();


readonly SteamLibraryService _steamLibraryService;
readonly AudioPlayer _audioPlayer;

public DotaTimers Timers { get; }
Expand All @@ -34,8 +35,9 @@ public double Volume
get => _audioPlayer.Volume;
}

public SettingsViewModel(AudioPlayer audioPlayer, DotaTimers timers)
public SettingsViewModel(SteamLibraryService steamLibraryService, AudioPlayer audioPlayer, DotaTimers timers)
{
_steamLibraryService = steamLibraryService;
_audioPlayer = audioPlayer;
Timers = timers;

Expand All @@ -60,6 +62,14 @@ public SettingsViewModel(AudioPlayer audioPlayer, DotaTimers timers)
nameof(DotaTimer.Reminder)
];

public void Install()
{
_steamLibraryService.InstallIntegration();
this.RaisePropertyChanged(nameof(IsIntegrated));
}

public bool IsIntegrated => _steamLibraryService.IsIntegrationInstalled();

public void ToggleTheme()
{
var toggle = Application.Current!.RequestedThemeVariant switch
Expand Down
1 change: 0 additions & 1 deletion src/Dota2Helper/ViewModels/WindowExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ internal static void HideMinimizeAndMaximizeButtons(this Window window)

SetWindowLong(hwnd, GWL_STYLE, (currentStyle & ~WS_MAXIMIZEBOX & ~WS_MINIMIZEBOX));
SetWindowLong(hwnd, GWL_EXSTYLE, (currentExStyle | WS_EX_DLGMODALFRAME));

SetWindowPos(hwnd, IntPtr.Zero, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_FRAMECHANGED);
}
}
Expand Down
Loading

0 comments on commit a5f4da9

Please sign in to comment.