160 lines
No EOL
5.7 KiB
C#
160 lines
No EOL
5.7 KiB
C#
using LANCommander.Launcher.Data;
|
|
using LANCommander.Launcher.Data.Models;
|
|
using LANCommander.Launcher.Models;
|
|
using LANCommander.SDK;
|
|
using LANCommander.SDK.Extensions;
|
|
using LANCommander.SDK.Helpers;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using Microsoft.Extensions.Logging;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using System.Diagnostics;
|
|
using LANCommander.SDK.Services;
|
|
|
|
namespace LANCommander.Launcher.Services
|
|
{
|
|
public class GameService(
|
|
DatabaseContext dbContext,
|
|
ILogger<GameService> logger,
|
|
AuthenticationService authenticationService,
|
|
PlaySessionService playSessionService,
|
|
ProfileClient profileClient,
|
|
GameClient gameClient,
|
|
ToolService toolService,
|
|
ToolClient toolClient,
|
|
IConnectionClient connectionClient,
|
|
IServiceProvider serviceProvider) : BaseDatabaseService<Game>(dbContext, logger)
|
|
{
|
|
public Dictionary<Guid, Process> RunningProcesses = new Dictionary<Guid, Process>();
|
|
|
|
public async Task<Dictionary<Guid, DateTime>> GetImportedOnMapAsync(IEnumerable<Guid> ids)
|
|
{
|
|
var idSet = ids.ToHashSet();
|
|
|
|
return await Context.Set<Game>()
|
|
.Where(g => idSet.Contains(g.Id))
|
|
.Select(g => new { g.Id, g.ImportedOn })
|
|
.ToDictionaryAsync(g => g.Id, g => g.ImportedOn);
|
|
}
|
|
|
|
public delegate Task OnUninstallCompleteHandler(Game game);
|
|
public event OnUninstallCompleteHandler OnUninstallComplete;
|
|
|
|
public delegate Task OnUninstallHandler(Game game);
|
|
public event OnUninstallHandler OnUninstall;
|
|
|
|
public async Task UninstallAsync(Game game)
|
|
{
|
|
using (var operation = Logger.BeginOperation("Uninstalling game {GameTitle} ({GameId})", game.Title, game.Id))
|
|
{
|
|
try
|
|
{
|
|
OnUninstall?.Invoke(game);
|
|
|
|
var installService = serviceProvider.GetService<InstallService>();
|
|
installService?.ClearCompleted(game.Id);
|
|
|
|
await gameClient.UninstallAsync(game.InstallDirectory, game.Id);
|
|
|
|
if (game.BaseGameId.HasValue)
|
|
{
|
|
var libraryService = serviceProvider.GetService<LibraryService>();
|
|
var isInstalled = await libraryService!.IsInstalledAsync(game.BaseGameId.Value);
|
|
|
|
if (!isInstalled)
|
|
{
|
|
var baseGame = await GetAsync(game.BaseGameId.Value);
|
|
|
|
await gameClient.UninstallAsync(game.InstallDirectory, baseGame?.Id ?? game.BaseGameId.Value);
|
|
|
|
ClearGameState(baseGame!, skipAddons: true);
|
|
}
|
|
}
|
|
|
|
// Uninstall any tools that were installed for this game. Tools are installed
|
|
// into the game's own directory and tracked per game, so uninstalling this
|
|
// game only removes its copy and leaves the tool intact for other games that
|
|
// share it. This must run before ClearGameState clears the install directory.
|
|
var installedTools = await toolService.GetInstalledToolsForGameAsync(game.Id);
|
|
|
|
foreach (var gameTool in installedTools)
|
|
{
|
|
try
|
|
{
|
|
await toolClient.UninstallAsync(game.InstallDirectory, gameTool.ToolId);
|
|
|
|
await toolService.SetToolUninstalledAsync(game.Id, gameTool.ToolId);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Logger?.LogError(ex, "Could not uninstall tool {ToolId} from game {GameId}", gameTool.ToolId, game.Id);
|
|
}
|
|
}
|
|
|
|
ClearGameState(game);
|
|
await UpdateAsync(game);
|
|
|
|
OnUninstallComplete?.Invoke(game);
|
|
|
|
operation.Complete();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Logger?.LogError(ex, "Game {GameTitle} ({GameId}) could not be uninstalled", game.Title, game.Id);
|
|
}
|
|
}
|
|
}
|
|
|
|
public async Task Run(Game game, SDK.Models.Manifest.Action action)
|
|
{
|
|
Guid userId;
|
|
|
|
if (connectionClient.IsConnected())
|
|
{
|
|
var profile = await profileClient.GetAsync();
|
|
|
|
userId = profile.Id;
|
|
}
|
|
else
|
|
{
|
|
userId = authenticationService.GetUserId();
|
|
}
|
|
|
|
try
|
|
{
|
|
var latestSession = await playSessionService.GetLatestSession(game.Id, userId);
|
|
|
|
await playSessionService.StartSession(game.Id, userId);
|
|
|
|
await gameClient.RunAsync(game.InstallDirectory, game.Id, action, latestSession?.End);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Logger?.LogError(ex, "Game failed to run");
|
|
throw;
|
|
}
|
|
finally
|
|
{
|
|
await playSessionService.EndSession(game.Id, userId);
|
|
}
|
|
}
|
|
|
|
protected void ClearGameState(Game game, bool skipAddons = false)
|
|
{
|
|
if (game == null)
|
|
return;
|
|
|
|
game.InstallDirectory = null;
|
|
game.Installed = false;
|
|
game.InstalledOn = null;
|
|
game.InstalledVersion = null;
|
|
|
|
if (!skipAddons)
|
|
{
|
|
foreach (var addon in (game.DependentGames ?? []))
|
|
{
|
|
ClearGameState(addon);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} |