diff --git a/AutumnLauncher.CLI/AutumnLauncher.CLI.csproj b/AutumnLauncher.CLI/AutumnLauncher.CLI.csproj new file mode 100644 index 0000000..d9fd9b6 --- /dev/null +++ b/AutumnLauncher.CLI/AutumnLauncher.CLI.csproj @@ -0,0 +1,18 @@ + + + + Exe + net7.0 + enable + enable + + + + + + + + + + + diff --git a/AutumnLauncher.CLI/Options.cs b/AutumnLauncher.CLI/Options.cs new file mode 100644 index 0000000..218fe3d --- /dev/null +++ b/AutumnLauncher.CLI/Options.cs @@ -0,0 +1,73 @@ +using CommandLine; + +namespace AutumnLauncher.CLI; + +// Command-line options for the --run argument +[Verb("run", HelpText = "Run a game.")] +public class RunOptions +{ + [Option('i', "id", Required = true, HelpText = "Game ID.")] + public int Id { get; set; } +} + +// Command-line options for the --remove argument +[Verb("remove", HelpText = "Remove a game.")] +public class RemoveOptions +{ + [Option('i', "id", Required = true, HelpText = "Game ID.")] + public int Id { get; set; } +} + +// Command-line options for the --list argument +[Verb("list", HelpText = "List all games.")] +public class ListOptions +{ +} + +// Command-line options for the --add argument +[Verb("add", HelpText = "Add a game.")] +public class AddOptions +{ + [Option('n', "name", Required = true, HelpText = "Game name.")] + public string? Name { get; set; } + + [Option('d', "developer", Required = true, HelpText = "Game developer.")] + public string? Developer { get; set; } + + [Option('r', "date", Required = true, HelpText = "Release date.")] + public string? Date { get; set; } + + [Option('g', "genre", Required = true, HelpText = "Game genre.")] + public string? Genre { get; set; } + + [Option('t', "type", Required = true, HelpText = "Game type.")] + public string? Type { get; set; } + + [Option('p', "path", Required = true, HelpText = "Game path.")] + public string? Path { get; set; } +} + +[Verb("edit", HelpText = "Add a game.")] +public class EditOptions +{ + [Option('i', "id", Required = true, HelpText = "Game id.")] + public int Id { get; set; } + + [Option('n', "name", Required = false, HelpText = "Game name.")] + public string? Name { get; set; } + + [Option('d', "developer", Required = false, HelpText = "Game developer.")] + public string? Developer { get; set; } + + [Option('r', "date", Required = false, HelpText = "Release date.")] + public string? Date { get; set; } + + [Option('g', "genre", Required = false, HelpText = "Game genre.")] + public string? Genre { get; set; } + + [Option('t', "type", Required = false, HelpText = "Game type.")] + public string? Type { get; set; } + + [Option('p', "path", Required = false, HelpText = "Game path.")] + public string? Path { get; set; } +} \ No newline at end of file diff --git a/AutumnLauncher.CLI/Program.cs b/AutumnLauncher.CLI/Program.cs new file mode 100644 index 0000000..a13da4c --- /dev/null +++ b/AutumnLauncher.CLI/Program.cs @@ -0,0 +1,53 @@ +using CommandLine; + +namespace AutumnLauncher.CLI; + +public static class Program +{ + public static void Main(string[] args) + { + // create directory and database if not already created + Directory.CreateDirectory(Configuration.DataDir); + Directory.CreateDirectory(Configuration.ConfigDir); + SqliteData.CreateDatabase(); + + Parser.Default.ParseArguments(args) + .WithParsed(RunAdd) + .WithParsed(RunList) + .WithParsed(RunRemove) + .WithParsed(RunRun) + .WithParsed(RunEdit); + //.WithNotParsed(HandleParseError); + } + + private static void RunAdd(AddOptions options) + { + ControlActions.Add(options.Name, options.Developer, options.Date, options.Genre, options.Type, options.Path); + } + + private static void RunList(ListOptions options) + { + ControlActions.List(); + } + + private static void RunRemove(RemoveOptions options) + { + ControlActions.Remove(options.Id); + } + + private static void RunRun(RunOptions options) + { + ControlActions.Run(options.Id); + } + + private static void RunEdit(EditOptions options) + { + ControlActions.Edit(options.Id, options.Name, options.Developer, options.Date, options.Genre, options.Type, options.Path); + } + + // private static void HandleParseError(IEnumerable errors) + // { + // // Handle command-line argument parsing errors + // foreach (var error in errors) Console.WriteLine(error.ToString()); + // } +} \ No newline at end of file diff --git a/AutumnLauncher.Core/AutumnLauncher.Core.csproj b/AutumnLauncher.Core/AutumnLauncher.Core.csproj new file mode 100644 index 0000000..e4da202 --- /dev/null +++ b/AutumnLauncher.Core/AutumnLauncher.Core.csproj @@ -0,0 +1,11 @@ + + + net7.0 + enable + enable + AutumnLauncher + + + + + diff --git a/AutumnLauncher.Core/Configuration.cs b/AutumnLauncher.Core/Configuration.cs new file mode 100644 index 0000000..d1b0e4b --- /dev/null +++ b/AutumnLauncher.Core/Configuration.cs @@ -0,0 +1,25 @@ +using System.Runtime.InteropServices; + +namespace AutumnLauncher; + +public static class Configuration +{ + public static string DataDir { get; set; } = Path.Combine(Environment.GetFolderPath( + Environment.SpecialFolder.LocalApplicationData, + Environment.SpecialFolderOption.Create), "AutumnLauncher"); + + public static string ConfigDir { get; set; } = Path.Combine(Environment.GetFolderPath( + Environment.SpecialFolder.ApplicationData, + Environment.SpecialFolderOption.Create), "AutumnLauncher"); + + public static LauncherPlatform Platform { get; set; } = GetPlatform(); + + private static LauncherPlatform GetPlatform() + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) return LauncherPlatform.Windows; + + if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) return LauncherPlatform.Linux; + + return LauncherPlatform.Unsupported; + } +} \ No newline at end of file diff --git a/AutumnLauncher.Core/ControlActions.cs b/AutumnLauncher.Core/ControlActions.cs new file mode 100644 index 0000000..a94052c --- /dev/null +++ b/AutumnLauncher.Core/ControlActions.cs @@ -0,0 +1,55 @@ +using System.Diagnostics; + +namespace AutumnLauncher; + +public static class ControlActions +{ + public static void Run(int num) + { + try + { + var game = SqliteData.GetGameById(num); + + Process.Start(game.GamePath ?? throw new InvalidOperationException()); + } + catch (Exception ex) + { + Console.WriteLine($"Error running game: {ex.Message}"); + } + } + + public static void List() + { + var games = SqliteData.GetAllGames(); + + foreach (var game in games) + { + Console.WriteLine(game + "\n"); + } + } + + public static void Add(string? gameName, string? developer, string? date, string? genre, string? type, string? path) + { + SqliteData.AddGame(gameName, developer, date, genre, type, path); + } + + public static void Remove(int num) + { + SqliteData.RemoveGame(num); + } + + public static void Edit(int num, string? gameName = null, string? developer = null, string? date = null, + string? genre = null, string? type = null, string? path = null) + { + var game = SqliteData.GetGameById(num); + + if (!string.IsNullOrWhiteSpace(gameName)) game.GameName = gameName; + if (!string.IsNullOrWhiteSpace(developer)) game.GameDeveloper = developer; + if (!string.IsNullOrWhiteSpace(date)) game.GameReleaseDate = date; + if (!string.IsNullOrWhiteSpace(genre)) game.GameGenre = genre; + if (!string.IsNullOrWhiteSpace(type)) game.GameType = type; + if (!string.IsNullOrWhiteSpace(path)) game.GamePath = path; + SqliteData.EditGame(game.GameId, game.GameName, game.GameDeveloper, game.GameReleaseDate, game.GameGenre, + game.GameType, game.GamePath); + } +} \ No newline at end of file diff --git a/AutumnLauncher.Core/Game.cs b/AutumnLauncher.Core/Game.cs new file mode 100644 index 0000000..ae841ef --- /dev/null +++ b/AutumnLauncher.Core/Game.cs @@ -0,0 +1,19 @@ +namespace AutumnLauncher; + +public class Game +{ + public int GameId { get; set; } + public string? GameName { get; set; } + public string? GameDeveloper { get; set; } + public string? GameReleaseDate { get; set; } + public string? GameGenre { get; set; } + public string? GameType { get; set; } + public string? GamePath { get; set; } + + public override string ToString() + { + return "Game ID: " + GameId + "\nGame Name: " + GameName + "\nGame Developer: " + GameDeveloper + + "\nGame Release Date: " + GameReleaseDate + "\nGame Genre: " + GameGenre + + "\nGame Type: " + GameType + "\nGame Path: " + GamePath; + } +} \ No newline at end of file diff --git a/AutumnLauncher.Core/LauncherPlatform.cs b/AutumnLauncher.Core/LauncherPlatform.cs new file mode 100644 index 0000000..70aaa8a --- /dev/null +++ b/AutumnLauncher.Core/LauncherPlatform.cs @@ -0,0 +1,8 @@ +namespace AutumnLauncher; + +public enum LauncherPlatform +{ + Unsupported, + Windows, + Linux +} \ No newline at end of file diff --git a/AutumnLauncher.Core/Sqlite.cs b/AutumnLauncher.Core/Sqlite.cs new file mode 100644 index 0000000..7146224 --- /dev/null +++ b/AutumnLauncher.Core/Sqlite.cs @@ -0,0 +1,159 @@ +using System.Data.SQLite; + +namespace AutumnLauncher; + +public static class SqliteData +{ + private static readonly string DataPath = Configuration.DataDir; + + public static void CreateDatabase() + { + if (File.Exists(Path.Combine(Configuration.DataDir, "GameDB.sqlite"))) return; + Console.WriteLine("Creating Database..."); + // Create a new SQLite database file + SQLiteConnection.CreateFile($"{DataPath}/GameDB.sqlite"); + + // Connect to the database + using var connection = new SQLiteConnection($"Data Source={DataPath}/GameDB.sqlite"); + //var connection = new SQLiteConnection($"Data Source={DataPath}/GameDB.sqlite;Version=3;"); + connection.Open(); + + // Create a Games table + const string createTableSql = "CREATE TABLE Games (GameID INTEGER PRIMARY KEY, GameName TEXT, Developer TEXT, ReleaseDate DATE, Genre TEXT, Type TEXT, FilePath TEXT)"; + var createTableCmd = new SQLiteCommand(createTableSql, connection); + createTableCmd.ExecuteNonQuery(); + + // Close the database connection + connection.Close(); + } + + public static void AddGame(string? gameName, string? developer, string? date, string? genre, string? type, + string? path) // method for adding sample data + { + using var connection = new SQLiteConnection($"Data Source={DataPath}/GameDB.sqlite"); + connection.Open(); + + // var command = connection.CreateCommand(); + + // Insert game data + const string insertSql = "INSERT INTO Games (GameName, Developer, ReleaseDate, Genre, Type, FilePath) VALUES (@GameName, @Developer, @ReleaseDate, @Genre, @Type, @FilePath)"; + var insertGame = new SQLiteCommand(insertSql, connection); + insertGame.Parameters.AddWithValue("@GameName", gameName); + insertGame.Parameters.AddWithValue("@Developer", developer); + insertGame.Parameters.AddWithValue("@ReleaseDate", date); + insertGame.Parameters.AddWithValue("@Genre", genre); + insertGame.Parameters.AddWithValue("@Type", type); + insertGame.Parameters.AddWithValue("@FilePath", path); + insertGame.ExecuteNonQuery(); + connection.Close(); + } + + public static void EditGame(int id, string? gameName, string? developer, string? date, string? genre, string? type, + string? path) // has to replace all at once + { + using var connection = new SQLiteConnection($"Data Source={DataPath}/GameDB.sqlite"); + connection.Open(); + + const string editSql = "UPDATE Games SET GameName = @GameName, Developer = @Developer, ReleaseDate = @GameDate, " + + "Genre = @GameGenre, Type = @GameType, FilePath = @GamePath WHERE GameID = @Id"; + var editGame = new SQLiteCommand(editSql, connection); + editGame.Parameters.AddWithValue("@Id", id); + editGame.Parameters.AddWithValue("@GameName", gameName); + editGame.Parameters.AddWithValue("@Developer", developer); + editGame.Parameters.AddWithValue("@GameDate", date); + editGame.Parameters.AddWithValue("@GameGenre", genre); + editGame.Parameters.AddWithValue("@GameType", type); + editGame.Parameters.AddWithValue("@GamePath", path); + editGame.ExecuteNonQuery(); + connection.Close(); + } + + public static void RemoveGame(int? gameId) + { + using var connection = new SQLiteConnection($"Data Source={DataPath}/GameDB.sqlite"); + connection.Open(); + + // var command = connection.CreateCommand(); + + // remove game data + const string insertSql = "DELETE FROM Games where GameID = @GameID"; + var removeGame = new SQLiteCommand(insertSql, connection); + removeGame.Parameters.AddWithValue("@GameID", gameId); + removeGame.ExecuteNonQuery(); + connection.Close(); + } + + public static List GetAllGames() + { + var games = new List(); + + using var connection = new SQLiteConnection($"Data Source={DataPath}/GameDB.sqlite"); + connection.Open(); + + var command = connection.CreateCommand(); + command.CommandText = @"SELECT * FROM Games"; + + using var reader = command.ExecuteReader(); + while (reader.Read()) + { + var game = new Game + { + GameId = reader.GetInt32(0), + GameName = reader.GetString(1), + GameDeveloper = reader.GetString(2), + GameReleaseDate = reader.GetString(3), + GameGenre = reader.GetString(4), + GameType = reader.GetString(5), + GamePath = reader.GetString(6) + }; + + games.Add(game); + } + + return games; + } + + // public static int NumOfGames() + // { + // using (var connection = new SQLiteConnection($"Data Source={DataPath}/GameDB.sqlite")) + // { + // connection.Open(); + // + // var command = connection.CreateCommand(); + // command.CommandText = @"SELECT COUNT(*) from Games"; + // + // using (var reader = command.ExecuteReader()) + // { + // while (reader.Read()) + // { + // return reader.GetInt32(0); + // } + // } + // } + // return 0; + // } + + public static Game GetGameById(int gameId) + { + using var connection = new SQLiteConnection($"Data Source={DataPath}/GameDB.sqlite"); + connection.Open(); + + var command = connection.CreateCommand(); + command.CommandText = @"SELECT * FROM Games WHERE GameID = @gameID LIMIT 1"; + command.Parameters.AddWithValue("@gameID", gameId); + using var reader = command.ExecuteReader(); + if (reader.Read()) + return new Game + { + GameId = reader.GetInt32(0), + GameName = reader.GetString(1), + GameDeveloper = reader.GetString(2), + GameReleaseDate = reader.GetString(3), + GameGenre = reader.GetString(4), + GameType = reader.GetString(5), + GamePath = reader.GetString(6) + }; + // Handle the case where no game was found with the specified ID + throw new Exception($"No game found with ID {gameId}"); + } +} \ No newline at end of file diff --git a/AutumnLauncher.Core/Startup.cs b/AutumnLauncher.Core/Startup.cs new file mode 100644 index 0000000..ab4300c --- /dev/null +++ b/AutumnLauncher.Core/Startup.cs @@ -0,0 +1,11 @@ +namespace AutumnLauncher; + +public class Startup +{ + public void AppStart() + { + Directory.CreateDirectory(Configuration.DataDir); + Directory.CreateDirectory(Configuration.ConfigDir); + SqliteData.CreateDatabase(); + } +} \ No newline at end of file diff --git a/AutumnLauncher/App.axaml b/AutumnLauncher.UI/App.axaml similarity index 83% rename from AutumnLauncher/App.axaml rename to AutumnLauncher.UI/App.axaml index 3bdb216..42265cc 100644 --- a/AutumnLauncher/App.axaml +++ b/AutumnLauncher.UI/App.axaml @@ -1,7 +1,7 @@ diff --git a/AutumnLauncher/App.axaml.cs b/AutumnLauncher.UI/App.axaml.cs similarity index 85% rename from AutumnLauncher/App.axaml.cs rename to AutumnLauncher.UI/App.axaml.cs index 29f9636..b8dea0a 100644 --- a/AutumnLauncher/App.axaml.cs +++ b/AutumnLauncher.UI/App.axaml.cs @@ -1,10 +1,10 @@ using Avalonia; using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Markup.Xaml; -using AutumnLauncher.ViewModels; -using AutumnLauncher.Views; +using AutumnLauncher.UI.ViewModels; +using AutumnLauncher.UI.Views; -namespace AutumnLauncher; +namespace AutumnLauncher.UI; public partial class App : Application { diff --git a/AutumnLauncher/Assets/avalonia-logo.ico b/AutumnLauncher.UI/Assets/avalonia-logo.ico similarity index 100% rename from AutumnLauncher/Assets/avalonia-logo.ico rename to AutumnLauncher.UI/Assets/avalonia-logo.ico diff --git a/AutumnLauncher/AutumnLauncher.csproj b/AutumnLauncher.UI/AutumnLauncher.UI.csproj similarity index 100% rename from AutumnLauncher/AutumnLauncher.csproj rename to AutumnLauncher.UI/AutumnLauncher.UI.csproj diff --git a/AutumnLauncher/Program.cs b/AutumnLauncher.UI/Program.cs similarity index 95% rename from AutumnLauncher/Program.cs rename to AutumnLauncher.UI/Program.cs index dae8d7c..e48eaef 100644 --- a/AutumnLauncher/Program.cs +++ b/AutumnLauncher.UI/Program.cs @@ -2,7 +2,7 @@ using Avalonia.ReactiveUI; using System; -namespace AutumnLauncher; +namespace AutumnLauncher.UI; class Program { diff --git a/AutumnLauncher/ViewLocator.cs b/AutumnLauncher.UI/ViewLocator.cs similarity index 89% rename from AutumnLauncher/ViewLocator.cs rename to AutumnLauncher.UI/ViewLocator.cs index 2985eb7..9893b12 100644 --- a/AutumnLauncher/ViewLocator.cs +++ b/AutumnLauncher.UI/ViewLocator.cs @@ -1,9 +1,9 @@ using System; using Avalonia.Controls; using Avalonia.Controls.Templates; -using AutumnLauncher.ViewModels; +using AutumnLauncher.UI.ViewModels; -namespace AutumnLauncher; +namespace AutumnLauncher.UI; public class ViewLocator : IDataTemplate { diff --git a/AutumnLauncher/ViewModels/MainWindowViewModel.cs b/AutumnLauncher.UI/ViewModels/MainWindowViewModel.cs similarity index 71% rename from AutumnLauncher/ViewModels/MainWindowViewModel.cs rename to AutumnLauncher.UI/ViewModels/MainWindowViewModel.cs index 2592d1c..64f9827 100644 --- a/AutumnLauncher/ViewModels/MainWindowViewModel.cs +++ b/AutumnLauncher.UI/ViewModels/MainWindowViewModel.cs @@ -1,4 +1,4 @@ -namespace AutumnLauncher.ViewModels; +namespace AutumnLauncher.UI.ViewModels; public class MainWindowViewModel : ViewModelBase { diff --git a/AutumnLauncher/ViewModels/ViewModelBase.cs b/AutumnLauncher.UI/ViewModels/ViewModelBase.cs similarity index 63% rename from AutumnLauncher/ViewModels/ViewModelBase.cs rename to AutumnLauncher.UI/ViewModels/ViewModelBase.cs index d5a1041..af061f0 100644 --- a/AutumnLauncher/ViewModels/ViewModelBase.cs +++ b/AutumnLauncher.UI/ViewModels/ViewModelBase.cs @@ -1,6 +1,6 @@ using ReactiveUI; -namespace AutumnLauncher.ViewModels; +namespace AutumnLauncher.UI.ViewModels; public class ViewModelBase : ReactiveObject { diff --git a/AutumnLauncher/Views/MainWindow.axaml b/AutumnLauncher.UI/Views/MainWindow.axaml similarity index 84% rename from AutumnLauncher/Views/MainWindow.axaml rename to AutumnLauncher.UI/Views/MainWindow.axaml index 1bf7f82..b354ff5 100644 --- a/AutumnLauncher/Views/MainWindow.axaml +++ b/AutumnLauncher.UI/Views/MainWindow.axaml @@ -1,13 +1,13 @@ + Title="AutumnLauncher.UI"> - + diff --git a/AutumnLauncher.sln b/AutumnLauncher.sln index 09cfbc8..cda3a33 100644 --- a/AutumnLauncher.sln +++ b/AutumnLauncher.sln @@ -1,6 +1,10 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AutumnLauncher", "AutumnLauncher\AutumnLauncher.csproj", "{9A7C9986-943E-48C6-B0F3-96A0BBA925D1}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AutumnLauncher.CLI", "AutumnLauncher.CLI\AutumnLauncher.CLI.csproj", "{848D68E5-10A6-4CF4-8B6F-4F3095B3468A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AutumnLauncher.Core", "AutumnLauncher.Core\AutumnLauncher.Core.csproj", "{E9919AFD-C95F-4F13-A8FB-62387D56E237}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AutumnLauncher.UI", "AutumnLauncher.UI\AutumnLauncher.UI.csproj", "{F9F1C18F-D201-4C43-99DE-D2881F8CA06A}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -8,9 +12,17 @@ Global Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {9A7C9986-943E-48C6-B0F3-96A0BBA925D1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {9A7C9986-943E-48C6-B0F3-96A0BBA925D1}.Debug|Any CPU.Build.0 = Debug|Any CPU - {9A7C9986-943E-48C6-B0F3-96A0BBA925D1}.Release|Any CPU.ActiveCfg = Release|Any CPU - {9A7C9986-943E-48C6-B0F3-96A0BBA925D1}.Release|Any CPU.Build.0 = Release|Any CPU + {848D68E5-10A6-4CF4-8B6F-4F3095B3468A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {848D68E5-10A6-4CF4-8B6F-4F3095B3468A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {848D68E5-10A6-4CF4-8B6F-4F3095B3468A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {848D68E5-10A6-4CF4-8B6F-4F3095B3468A}.Release|Any CPU.Build.0 = Release|Any CPU + {E9919AFD-C95F-4F13-A8FB-62387D56E237}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E9919AFD-C95F-4F13-A8FB-62387D56E237}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E9919AFD-C95F-4F13-A8FB-62387D56E237}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E9919AFD-C95F-4F13-A8FB-62387D56E237}.Release|Any CPU.Build.0 = Release|Any CPU + {F9F1C18F-D201-4C43-99DE-D2881F8CA06A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F9F1C18F-D201-4C43-99DE-D2881F8CA06A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F9F1C18F-D201-4C43-99DE-D2881F8CA06A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F9F1C18F-D201-4C43-99DE-D2881F8CA06A}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal