Compare commits
33 commits
experiment
...
master
Author | SHA1 | Date | |
---|---|---|---|
4cfe64067d | |||
4f786226bd | |||
75fdd45938 | |||
b69cac606a | |||
0479843d47 | |||
dc89d32164 | |||
7f01a92677 | |||
ee23983551 | |||
c1c4f89622 | |||
c08316e222 | |||
e562d4a0ad | |||
d32c17dc1c | |||
ecc4728e5e | |||
951f93b1b3 | |||
a9bfb5c706 | |||
bc0ac93f3f | |||
1eaf8c2580 | |||
4eb2d47adf | |||
312afabfdc | |||
86da04442c | |||
1ae4690d0d | |||
2f3effc087 | |||
55adc6c2a9 | |||
8d7a45ce5c | |||
cc2eee27c2 | |||
492d3c71f2 | |||
d6671ad2f8 | |||
af4e7848ae | |||
8965f2c5cc | |||
3c18a4b942 | |||
7b3e52595e | |||
d7479b9fec | |||
1f4d68461f |
|
@ -18,6 +18,22 @@ jobs:
|
|||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Extract FileVersion from .csproj
|
||||
id: get_version
|
||||
run: |
|
||||
version=$(grep -oPm1 "(?<=<FileVersion>)[^<]+" PS2_Manager/PS2_Manager.csproj)
|
||||
echo "PS2Manager version: $version"
|
||||
echo "version=$version" >> $GITHUB_OUTPUT
|
||||
|
||||
|
||||
- name: Check if release tag already exists
|
||||
run: |
|
||||
tag="v${{ steps.get_version.outputs.version }}"
|
||||
if git ls-remote --tags origin | grep -q "refs/tags/$tag"; then
|
||||
echo "Release tag $tag already exists. Cancelling workflow."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Build the project (Linux x64)
|
||||
run: |
|
||||
dotnet publish ./PS2_Manager/PS2_Manager.csproj \
|
||||
|
@ -38,6 +54,27 @@ jobs:
|
|||
-o ./output_win
|
||||
|
||||
|
||||
- name: Download appimagetool
|
||||
run: |
|
||||
curl -L -o appimagetool-x86_64.AppImage https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-x86_64.AppImage
|
||||
chmod +x appimagetool-x86_64.AppImage
|
||||
|
||||
- name: Build AppImage
|
||||
run: |
|
||||
mkdir -p PS2_Manager.AppDir/usr/bin
|
||||
cp -r ./output_linux/* PS2_Manager.AppDir/usr/bin/
|
||||
|
||||
cp PS2_Manager/Assets/AppRun PS2_Manager.AppDir/
|
||||
cp PS2_Manager/Assets/ps2manager.desktop PS2_Manager.AppDir/
|
||||
cp PS2_Manager/Assets/ps2manager.png PS2_Manager.AppDir/
|
||||
|
||||
chmod +x PS2_Manager.AppDir/AppRun
|
||||
|
||||
./appimagetool-x86_64.AppImage PS2_Manager.AppDir
|
||||
|
||||
mkdir -p release
|
||||
mv PS2_Manager-x86_64.AppImage release/PS2Manager_Linux_x64.AppImage
|
||||
|
||||
- name: Pack Releases into Zips
|
||||
run: |
|
||||
mkdir -p ./release
|
||||
|
@ -46,21 +83,12 @@ jobs:
|
|||
rm -rf ./output_linux ./output_win
|
||||
|
||||
|
||||
|
||||
- name: Generate tag name based on current date and time
|
||||
id: generate_tag
|
||||
run: |
|
||||
# Get current date and time, format as 'YYYY-MM-DD-HHMMSS'
|
||||
current_date=$(date +"%Y-%m-%d-%H%M%S")
|
||||
echo "Generated tag name: $current_date"
|
||||
echo "::set-output name=tag_name::$current_date"
|
||||
|
||||
|
||||
- name: Create Git tag
|
||||
run: |
|
||||
git tag ${{ steps.generate_tag.outputs.tag_name }}
|
||||
git push origin ${{ steps.generate_tag.outputs.tag_name }}
|
||||
|
||||
git config user.name "WeeXnes"
|
||||
git config user.email "somtrigi@gmail.com"
|
||||
git tag v${{ steps.get_version.outputs.version }}
|
||||
git push origin v${{ steps.get_version.outputs.version }}
|
||||
|
||||
- name: Upload to Forgejo
|
||||
uses: actions/forgejo-release@v2.6.0
|
||||
|
@ -69,6 +97,6 @@ jobs:
|
|||
url: https://git.weexnes.dev/
|
||||
repo: WeeXnes/ps2_manager
|
||||
token: ${{ secrets.RELEASE_TOKEN }}
|
||||
tag: ${{ steps.generate_tag.outputs.tag_name }}
|
||||
tag: v${{ steps.get_version.outputs.version }}
|
||||
release-dir: release
|
||||
release-notes: "Automated release from CI"
|
||||
release-notes: "Automated release for version ${{ steps.get_version.outputs.version }}"
|
Before Width: | Height: | Size: 149 KiB After Width: | Height: | Size: 137 KiB |
Before Width: | Height: | Size: 160 KiB After Width: | Height: | Size: 149 KiB |
Before Width: | Height: | Size: 79 KiB After Width: | Height: | Size: 75 KiB |
Before Width: | Height: | Size: 223 KiB After Width: | Height: | Size: 256 KiB |
|
@ -3,32 +3,19 @@
|
|||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
Height="349"
|
||||
Height="389"
|
||||
Width="598"
|
||||
CanResize="False"
|
||||
x:Class="PS2_Manager.AddGameWindow"
|
||||
Title="Install Game"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
Loaded="Control_OnLoaded"
|
||||
Background="#201c29"
|
||||
SystemDecorations="None">
|
||||
<Grid RowDefinitions="20, *">
|
||||
<Grid Grid.Row="0">
|
||||
<Border Background="#35313d"
|
||||
PointerPressed="WindowDrag">
|
||||
<Grid ColumnDefinitions="*, 20">
|
||||
<TextBlock Name="WindowTitle" FontSize="12" Text="Install Game" Padding="8,0,0,0" VerticalAlignment="Center"/>
|
||||
<Border Grid.Column="1" Background="#4b4753" PointerPressed="WindowClose">
|
||||
<TextBlock FontSize="12" Text="×" HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Border>
|
||||
</Grid>
|
||||
Background="#201c29">
|
||||
<Grid Grid.Row="1" ColumnDefinitions="Auto,Auto,*" Margin="20">
|
||||
<!-- PS2 Cover -->
|
||||
<Border Width="205" Height="292" Background="Black" CornerRadius="5" HorizontalAlignment="Left"
|
||||
PointerPressed="CoverImage_OnPointerPressed">
|
||||
<Image Name="CoverImage" Source="Images/missing.png" Stretch="UniformToFill"/>
|
||||
<Image Name="CoverImage" Source="Assets/missing.png" Stretch="UniformToFill"/>
|
||||
</Border>
|
||||
|
||||
<!-- Spacer -->
|
||||
|
@ -52,6 +39,10 @@
|
|||
<TextBlock Text="ISO Path"/>
|
||||
<TextBox Name="IsoPathBox" IsEnabled="False"/>
|
||||
|
||||
<TextBlock Text="Installation Method"/>
|
||||
<ComboBox Name="InstallationMethodBox" Margin="5,0" HorizontalAlignment="Stretch" SelectionChanged="InstallationMethodBox_OnSelectionChanged">
|
||||
</ComboBox>
|
||||
|
||||
<Button Name="InstallButton" Content="Install Game" HorizontalAlignment="Center"
|
||||
Background="#aa4de8"
|
||||
Foreground="Black"
|
||||
|
@ -60,6 +51,4 @@
|
|||
</StackPanel>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
</Window>
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
|
@ -22,6 +23,9 @@ public partial class AddGameWindow : Window
|
|||
{
|
||||
this.newGame = new Game(filePath);
|
||||
InitializeComponent();
|
||||
InstallationMethodBox.Items.Add("Move");
|
||||
InstallationMethodBox.Items.Add("Copy");
|
||||
InstallationMethodBox.SelectedItem = settings.preferred_installation_method.GetValue<string>() ?? "Move";
|
||||
}
|
||||
|
||||
private void RefreshPreview()
|
||||
|
@ -57,6 +61,7 @@ public partial class AddGameWindow : Window
|
|||
{
|
||||
InstallButton.IsEnabled = false;
|
||||
GameNameBox.IsEnabled = false;
|
||||
InstallationMethodBox.IsEnabled = false;
|
||||
InstallButton.Content = "Installing...";
|
||||
newGame.Install();
|
||||
newGame.InstallProgress.ValueChanged += () =>
|
||||
|
@ -100,4 +105,9 @@ public partial class AddGameWindow : Window
|
|||
Console.Error("OpenFilePicker was called but Canceled or no Files selected");
|
||||
}
|
||||
}
|
||||
|
||||
private void InstallationMethodBox_OnSelectionChanged(object? sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
settings.preferred_installation_method.SetValue(InstallationMethodBox.SelectionBoxItem?.ToString());
|
||||
}
|
||||
}
|
|
@ -51,7 +51,6 @@ public partial class App : Application
|
|||
|
||||
setupWindow.Closed += (_, _) =>
|
||||
{
|
||||
// Replace MainWindow after setup finishes
|
||||
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
||||
{
|
||||
var mainWindow = new MainWindow();
|
||||
|
|
4
PS2_Manager/Assets/AppRun
Normal file
|
@ -0,0 +1,4 @@
|
|||
#!/bin/bash
|
||||
HERE="$(dirname "$(readlink -f "$0")")"
|
||||
exec "$HERE/usr/bin/PS2_Manager" "$@"
|
||||
|
BIN
PS2_Manager/Assets/bin.png
Normal file
After Width: | Height: | Size: 208 KiB |
BIN
PS2_Manager/Assets/cd.png
Normal file
After Width: | Height: | Size: 585 KiB |
BIN
PS2_Manager/Assets/dvd.png
Normal file
After Width: | Height: | Size: 700 KiB |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
6
PS2_Manager/Assets/ps2manager.desktop
Normal file
|
@ -0,0 +1,6 @@
|
|||
[Desktop Entry]
|
||||
Type=Application
|
||||
Name=PS2 Manager
|
||||
Exec=PS2_Manager
|
||||
Icon=ps2manager
|
||||
Categories=Utility;
|
BIN
PS2_Manager/Assets/ps2manager.png
Normal file
After Width: | Height: | Size: 62 KiB |
BIN
PS2_Manager/Assets/vmc.png
Normal file
After Width: | Height: | Size: 517 KiB |
33
PS2_Manager/ConvertGameWindow.axaml
Normal file
|
@ -0,0 +1,33 @@
|
|||
<Window xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="PS2_Manager.ConvertGameWindow"
|
||||
Title="Convert BIN to ISO"
|
||||
Height="260"
|
||||
Width="398"
|
||||
CanResize="False"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
Background="#201c29"
|
||||
Loaded="Control_OnLoaded"
|
||||
Closing="Window_OnClosing">
|
||||
<Grid RowDefinitions="80, *, 80">
|
||||
<TextBlock Name="Label_1" HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||
<Border Grid.Row="1" CornerRadius="10" Background="#35313d" Margin="10, 0">
|
||||
<Grid ColumnDefinitions="100,*,100">
|
||||
<Border Grid.Column="0" Background="#201c29" Margin="10" CornerRadius="7">
|
||||
<Image Margin="10" RenderOptions.BitmapInterpolationMode="HighQuality" Source="Assets/bin.png"/>
|
||||
</Border>
|
||||
|
||||
<TextBlock Grid.Column="1" FontSize="25" Text="→" HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||
|
||||
<Border Grid.Column="2" Background="#201c29" Margin="10" CornerRadius="7">
|
||||
<Image Margin="10" RenderOptions.BitmapInterpolationMode="HighQuality" Source="Assets/cd.png"/>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Border>
|
||||
<Button Click="ConvertButton_OnClick" Name="ConvertButton" Grid.Row="2" Content="Convert" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="10,0"/>
|
||||
|
||||
</Grid>
|
||||
</Window>
|
69
PS2_Manager/ConvertGameWindow.axaml.cs
Normal file
|
@ -0,0 +1,69 @@
|
|||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Avalonia.Threading;
|
||||
using PS2_Manager.Core.IO.DiscImage;
|
||||
using PS2_Manager.Core.IO.DiscImage.Type;
|
||||
|
||||
namespace PS2_Manager;
|
||||
|
||||
public partial class ConvertGameWindow : Window
|
||||
{
|
||||
public bool PreventClose { get; set; } = false;
|
||||
public string binPath { get; set; }
|
||||
public string isoPath { get; set; }
|
||||
public BackgroundWorker Worker { get; set; }
|
||||
public ConvertGameWindow(string path)
|
||||
{
|
||||
this.binPath = path;
|
||||
this.isoPath = Path.ChangeExtension(path, ".iso");
|
||||
InitializeComponent();
|
||||
Worker = new BackgroundWorker();
|
||||
Worker.RunWorkerCompleted += WorkerOnRunWorkerCompleted;
|
||||
Worker.DoWork += WorkerOnDoWork;
|
||||
}
|
||||
|
||||
private void WorkerOnDoWork(object? sender, DoWorkEventArgs e)
|
||||
{
|
||||
Console.Info("Worker has started");
|
||||
Iso9660Conv conv = new Iso9660Conv();
|
||||
conv.DiscImage = new BinType(this.binPath);
|
||||
conv.Convert(this.isoPath);
|
||||
}
|
||||
|
||||
private void WorkerOnRunWorkerCompleted(object? sender, RunWorkerCompletedEventArgs e)
|
||||
{
|
||||
Console.Info("File Converted");
|
||||
OpenInstallWindow();
|
||||
}
|
||||
|
||||
public void OpenInstallWindow()
|
||||
{
|
||||
Console.Success("Converted Successfully");
|
||||
this.PreventClose = false;
|
||||
new AddGameWindow(this.isoPath).Show();
|
||||
this.Close();
|
||||
}
|
||||
|
||||
private void Control_OnLoaded(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
this.Label_1.Text = Path.GetFileName(this.binPath) + " needs to be converted into a ISO file";
|
||||
}
|
||||
|
||||
private void Window_OnClosing(object? sender, WindowClosingEventArgs e)
|
||||
{
|
||||
if(this.PreventClose)
|
||||
e.Cancel = true;
|
||||
}
|
||||
|
||||
private void ConvertButton_OnClick(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
this.PreventClose = true;
|
||||
ConvertButton.Content = "Converting...";
|
||||
Console.Warning("Converting " + this.binPath + " to ISO");
|
||||
Worker.RunWorkerAsync();
|
||||
}
|
||||
}
|
23
PS2_Manager/Core/Artwork.cs
Normal file
|
@ -0,0 +1,23 @@
|
|||
using System;
|
||||
|
||||
namespace PS2_Manager.Core;
|
||||
|
||||
public static class Artwork
|
||||
{
|
||||
public enum Type
|
||||
{
|
||||
Front,
|
||||
Back,
|
||||
Disc
|
||||
}
|
||||
|
||||
public static Type NextType(Type _type)
|
||||
{
|
||||
return (Type)(((int)_type + 1) % Enum.GetValues(typeof(Type)).Length);
|
||||
}
|
||||
|
||||
public static Type PrevType(Type _type)
|
||||
{
|
||||
return (Type)(((int)_type - 1 + Enum.GetValues(typeof(Type)).Length) % Enum.GetValues(typeof(Type)).Length);
|
||||
}
|
||||
}
|
118
PS2_Manager/Core/Config.cs
Normal file
|
@ -0,0 +1,118 @@
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace PS2_Manager.Core;
|
||||
|
||||
|
||||
public class Config
|
||||
{
|
||||
private string path { get; set; }
|
||||
public string MemoryCard1 { get; set; }
|
||||
public string MemoryCard2 { get; set; }
|
||||
public bool Mode1 { get; set; }
|
||||
public bool Mode2 { get; set; }
|
||||
public bool Mode3 { get; set; }
|
||||
public bool Mode4 { get; set; }
|
||||
public bool Mode5 { get; set; }
|
||||
public bool Mode6 { get; set; }
|
||||
|
||||
public Config(string path)
|
||||
{
|
||||
this.path = path;
|
||||
this.ParseConfig(path);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"VMCs: {MemoryCard1} - {MemoryCard2}\n" +
|
||||
$"Mode 1: {Mode1}\n" +
|
||||
$"Mode 2: {Mode2}\n" +
|
||||
$"Mode 3: {Mode3}\n" +
|
||||
$"Mode 4: {Mode4}\n" +
|
||||
$"Mode 5: {Mode5}\n" +
|
||||
$"Mode 6: {Mode6}\n";
|
||||
}
|
||||
|
||||
private void FromCompatibility(int value)
|
||||
{
|
||||
Mode1 = (value & (1 << 0)) != 0;
|
||||
Mode2 = (value & (1 << 1)) != 0;
|
||||
Mode3 = (value & (1 << 2)) != 0;
|
||||
Mode4 = (value & (1 << 3)) != 0;
|
||||
Mode5 = (value & (1 << 4)) != 0;
|
||||
Mode6 = (value & (1 << 5)) != 0;
|
||||
}
|
||||
|
||||
private int ToCompatibility()
|
||||
{
|
||||
int value = 0;
|
||||
if (Mode1) value |= (1 << 0);
|
||||
if (Mode2) value |= (1 << 1);
|
||||
if (Mode3) value |= (1 << 2);
|
||||
if (Mode4) value |= (1 << 3);
|
||||
if (Mode5) value |= (1 << 4);
|
||||
if (Mode6) value |= (1 << 5);
|
||||
return value;
|
||||
}
|
||||
public void SaveConfig()
|
||||
{
|
||||
var lines = new List<string>();
|
||||
|
||||
if (!string.IsNullOrEmpty(MemoryCard1))
|
||||
lines.Add($"$VMC_0={MemoryCard1}");
|
||||
|
||||
if (!string.IsNullOrEmpty(MemoryCard2))
|
||||
lines.Add($"$VMC_1={MemoryCard2}");
|
||||
|
||||
lines.Add($"$Compatibility={ToCompatibility()}");
|
||||
|
||||
lines.Add($"$ConfigSource=1");
|
||||
|
||||
File.WriteAllLines(path, lines);
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void ParseConfig(string path)
|
||||
{
|
||||
if (!File.Exists(path))
|
||||
return;
|
||||
|
||||
var lines = File.ReadAllLines(path);
|
||||
|
||||
foreach (var rawLine in lines)
|
||||
{
|
||||
var line = rawLine.Trim();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(line) || line.StartsWith("#") || line.StartsWith("//"))
|
||||
continue;
|
||||
|
||||
var parts = line.Split('=', 2);
|
||||
if (parts.Length != 2)
|
||||
continue;
|
||||
|
||||
var key = parts[0].Trim();
|
||||
var value = parts[1].Trim();
|
||||
|
||||
switch (key)
|
||||
{
|
||||
case "$Compatibility":
|
||||
if (int.TryParse(value, out int compat))
|
||||
this.FromCompatibility(compat);
|
||||
break;
|
||||
|
||||
case "$VMC_0":
|
||||
this.MemoryCard1 = value;
|
||||
break;
|
||||
|
||||
case "$VMC_1":
|
||||
this.MemoryCard2 = value;
|
||||
break;
|
||||
|
||||
case "$ConfigSource":
|
||||
// Optional: You can store/use this if needed
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -21,7 +21,7 @@ public static class ConfigUtils
|
|||
return;
|
||||
config.SetValue(getStrType(_type), getStrName(_type), _value.ToString());
|
||||
}
|
||||
public static T GetValue<T>(this Enum _type)
|
||||
public static T? GetValue<T>(this Enum _type)
|
||||
{
|
||||
if (!checkIfInitialized())
|
||||
return default(T);
|
||||
|
|
35
PS2_Manager/Core/DiscType.cs
Normal file
|
@ -0,0 +1,35 @@
|
|||
using System;
|
||||
using Avalonia;
|
||||
using Avalonia.Media.Imaging;
|
||||
using Avalonia.Platform;
|
||||
|
||||
namespace PS2_Manager.Core;
|
||||
|
||||
|
||||
public class DiscIcon
|
||||
{
|
||||
public bool ShowDVD { get; set; }
|
||||
public bool ShowCD { get; set; }
|
||||
public DiscType type { get; set; }
|
||||
|
||||
public DiscIcon(DiscType _type)
|
||||
{
|
||||
this.type = _type;
|
||||
if (type == DiscType.CD)
|
||||
{
|
||||
this.ShowCD = true;
|
||||
this.ShowDVD = false;
|
||||
}else if (type == DiscType.DVD)
|
||||
{
|
||||
this.ShowCD = false;
|
||||
this.ShowDVD = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public enum DiscType
|
||||
{
|
||||
DVD,
|
||||
CD
|
||||
}
|
|
@ -12,6 +12,7 @@ using Avalonia.Threading;
|
|||
using Microsoft.VisualBasic.CompilerServices;
|
||||
using Nocksoft.IO.ConfigFiles;
|
||||
|
||||
|
||||
namespace PS2_Manager.Core;
|
||||
|
||||
public class Game
|
||||
|
@ -22,6 +23,8 @@ public class Game
|
|||
public Bitmap? ArtworkFront { get; set; }
|
||||
public Bitmap? ArtworkBack { get; set; }
|
||||
public Bitmap? ArtworkDVD { get; set; }
|
||||
public Config? Config { get; set; }
|
||||
public DiscIcon Icon { get; set; }
|
||||
public EventHandler? InstallationFinished { get; set; }
|
||||
public UpdateVar<double> InstallProgress { get; private set; }
|
||||
|
||||
|
@ -29,6 +32,16 @@ public class Game
|
|||
{
|
||||
this.GamePath = isoPath;
|
||||
this.GameID = ISO.GetSerial(isoPath);
|
||||
FileInfo fileInfo = new FileInfo(isoPath);
|
||||
if (fileInfo.Length < 1_000_000_000)
|
||||
{
|
||||
this.Icon = new DiscIcon(DiscType.CD);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.Icon = new DiscIcon(DiscType.DVD);
|
||||
}
|
||||
this.Config = new Config(this.GetConfigPath());
|
||||
if (!installed)
|
||||
{
|
||||
this.Name = this.GetGameTitle();
|
||||
|
@ -45,6 +58,8 @@ public class Game
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void ChangeName(string newName)
|
||||
{
|
||||
Console.Info("Changing name of " + this.Name + " to " + newName);
|
||||
|
@ -104,6 +119,9 @@ public class Game
|
|||
{
|
||||
this.InstallProgress = new UpdateVar<double>();
|
||||
await this.CopyIsoWithProgressAsync();
|
||||
string installationMethod = settings.preferred_installation_method.GetValue<string>() ?? "Move";
|
||||
if(installationMethod == "Move")
|
||||
this.Uninstall();
|
||||
}
|
||||
|
||||
private Bitmap DownloadCover(Artwork.Type type)
|
||||
|
@ -152,11 +170,14 @@ public class Game
|
|||
public async Task CopyIsoWithProgressAsync()
|
||||
{
|
||||
Console.Info("Copying ISO file for " + this + "...");
|
||||
string targetDirectory = settings.library_path.GetValue<string>();
|
||||
Util.CheckDir(Path.Combine(targetDirectory, "DVD"));
|
||||
string targetDirectory = "";
|
||||
if (this.Icon.type == DiscType.DVD)
|
||||
targetDirectory = Path.Combine(settings.library_path.GetValue<string>(), "DVD");
|
||||
if (this.Icon.type == DiscType.CD)
|
||||
targetDirectory = Path.Combine(settings.library_path.GetValue<string>(), "CD");
|
||||
|
||||
string newFileName = $"{this.GameID}.{this.Name}.iso";
|
||||
string destPath = Path.Combine(Path.Combine(targetDirectory, "DVD"), newFileName);
|
||||
string destPath = Path.Combine(targetDirectory, newFileName);
|
||||
|
||||
const int bufferSize = 1024 * 1024;
|
||||
byte[] buffer = new byte[bufferSize];
|
||||
|
@ -185,10 +206,6 @@ public class Game
|
|||
MainWindow.RefreshGamesListTrigger?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public Bitmap? LoadCover(Artwork.Type artworkType)
|
||||
{
|
||||
Console.Info("Loading " + artworkType + " Artwork for " + this.GameID);
|
||||
|
@ -249,115 +266,32 @@ public class Game
|
|||
{
|
||||
return this.Name + " -> " + this.GameID;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class GameConfig
|
||||
{
|
||||
public string MemoryCard1 { get; set; }
|
||||
public string MemoryCard2 { get; set; }
|
||||
public bool Mode1 { get; set; }
|
||||
public bool Mode2 { get; set; }
|
||||
public bool Mode3 { get; set; }
|
||||
public bool Mode4 { get; set; }
|
||||
public bool Mode5 { get; set; }
|
||||
public bool Mode6 { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
private string GetConfigPath()
|
||||
{
|
||||
return $"VMCs: {MemoryCard1} - {MemoryCard2}\n" +
|
||||
$"Mode 1: {Mode1}\n" +
|
||||
$"Mode 2: {Mode2}\n" +
|
||||
$"Mode 3: {Mode3}\n" +
|
||||
$"Mode 4: {Mode4}\n" +
|
||||
$"Mode 5: {Mode5}\n" +
|
||||
$"Mode 6: {Mode6}\n";
|
||||
return Path.Combine(Path.Combine(settings.library_path.GetValue<string>(), "CFG"), this.GameID + ".cfg");
|
||||
}
|
||||
|
||||
private void FromCompatibility(int value)
|
||||
private string GetArtworkPath(Artwork.Type artworkType)
|
||||
{
|
||||
Mode1 = (value & (1 << 0)) != 0;
|
||||
Mode2 = (value & (1 << 1)) != 0;
|
||||
Mode3 = (value & (1 << 2)) != 0;
|
||||
Mode4 = (value & (1 << 3)) != 0;
|
||||
Mode5 = (value & (1 << 4)) != 0;
|
||||
Mode6 = (value & (1 << 5)) != 0;
|
||||
}
|
||||
|
||||
private int ToCompatibility()
|
||||
{
|
||||
int value = 0;
|
||||
if (Mode1) value |= (1 << 0);
|
||||
if (Mode2) value |= (1 << 1);
|
||||
if (Mode3) value |= (1 << 2);
|
||||
if (Mode4) value |= (1 << 3);
|
||||
if (Mode5) value |= (1 << 4);
|
||||
if (Mode6) value |= (1 << 5);
|
||||
return value;
|
||||
}
|
||||
|
||||
public void ParseConfig(string path)
|
||||
{
|
||||
if (!File.Exists(path))
|
||||
throw new FileNotFoundException("Config file not found.", path);
|
||||
|
||||
var lines = File.ReadAllLines(path);
|
||||
|
||||
foreach (var rawLine in lines)
|
||||
string targetDirectory = settings.library_path.GetValue<string>();
|
||||
string modifier = "";
|
||||
switch (artworkType)
|
||||
{
|
||||
var line = rawLine.Trim();
|
||||
|
||||
// Skip empty or comment lines
|
||||
if (string.IsNullOrWhiteSpace(line) || line.StartsWith("#") || line.StartsWith("//"))
|
||||
continue;
|
||||
|
||||
var parts = line.Split('=', 2);
|
||||
if (parts.Length != 2)
|
||||
continue;
|
||||
|
||||
var key = parts[0].Trim();
|
||||
var value = parts[1].Trim();
|
||||
|
||||
switch (key)
|
||||
{
|
||||
case "$Compatibility":
|
||||
if (int.TryParse(value, out int compat))
|
||||
this.FromCompatibility(compat);
|
||||
break;
|
||||
|
||||
case "$VMC_0":
|
||||
this.MemoryCard1 = value;
|
||||
break;
|
||||
|
||||
case "$VMC_1":
|
||||
this.MemoryCard2 = value;
|
||||
break;
|
||||
|
||||
case "$ConfigSource":
|
||||
// Optional: You can store/use this if needed
|
||||
break;
|
||||
}
|
||||
case Artwork.Type.Front:
|
||||
modifier = "_COV.png";
|
||||
break;
|
||||
case Artwork.Type.Back:
|
||||
modifier = "_COV2.png";
|
||||
break;
|
||||
case Artwork.Type.Disc:
|
||||
modifier = "_ICO.png";
|
||||
break;
|
||||
}
|
||||
return Path.Combine(Path.Combine(targetDirectory, "ART"), this.GameID + modifier);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class Artwork
|
||||
{
|
||||
public enum Type
|
||||
{
|
||||
Front,
|
||||
Back,
|
||||
Disc
|
||||
}
|
||||
|
||||
public static Type NextType(Type _type)
|
||||
{
|
||||
return (Type)(((int)_type + 1) % Enum.GetValues(typeof(Type)).Length);
|
||||
}
|
||||
|
||||
public static Type PrevType(Type _type)
|
||||
{
|
||||
return (Type)(((int)_type - 1 + Enum.GetValues(typeof(Type)).Length) % Enum.GetValues(typeof(Type)).Length);
|
||||
}
|
||||
}
|
|
@ -4,6 +4,7 @@ using System.Threading.Tasks;
|
|||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Platform.Storage;
|
||||
using Microsoft.VisualBasic.CompilerServices;
|
||||
|
||||
namespace PS2_Manager.Core;
|
||||
|
||||
|
@ -23,7 +24,7 @@ public static class Globals
|
|||
{
|
||||
public static FilePickerFileType PS2Game { get; } = new("PS2 Game")
|
||||
{
|
||||
Patterns = new[] { "*.iso" }
|
||||
Patterns = new[] { "*.iso", "*.bin" }
|
||||
};
|
||||
public static FilePickerFileType PS2Cover { get; } = new("PS2 Cover")
|
||||
{
|
||||
|
@ -34,7 +35,8 @@ public static class Globals
|
|||
|
||||
public enum settings
|
||||
{
|
||||
library_path
|
||||
library_path,
|
||||
preferred_installation_method
|
||||
}
|
||||
|
||||
public class UpdateVar<T>
|
||||
|
|
310
PS2_Manager/Core/IsoConverter.cs
Normal file
|
@ -0,0 +1,310 @@
|
|||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
#nullable disable
|
||||
namespace PS2_Manager.Core.IO.DiscImage.Type
|
||||
{
|
||||
public class BinType : IDiscImage
|
||||
{
|
||||
private SectorStructure _sector;
|
||||
private string _imagePath;
|
||||
|
||||
public string ImagePath => this._imagePath;
|
||||
|
||||
public BinType(string imagePath)
|
||||
{
|
||||
this._imagePath = imagePath;
|
||||
this._sector = new SectorStructure();
|
||||
}
|
||||
|
||||
public long FirstDumpSector() => 0;
|
||||
|
||||
public SectorStructure GetSectorStucture()
|
||||
{
|
||||
this._sector = new SectorStructure();
|
||||
FileStream input = (FileStream) null;
|
||||
BinaryReader binaryReader = (BinaryReader) null;
|
||||
try
|
||||
{
|
||||
input = new FileStream(this._imagePath, FileMode.Open, FileAccess.Read, FileShare.Read);
|
||||
binaryReader = new BinaryReader((Stream) input);
|
||||
byte[] numArray = new byte[16];
|
||||
binaryReader.Read(numArray, 0, numArray.Length);
|
||||
if (BytesHelper.CompareBytesArray(BytesHelper.CopyRange(numArray, 0, Iso9660Conv.SYNC_HEADER.Length), Iso9660Conv.SYNC_HEADER))
|
||||
{
|
||||
switch (numArray[15])
|
||||
{
|
||||
case 1:
|
||||
this._sector.sectorLength = 2352;
|
||||
this._sector.userDataOffset = 16;
|
||||
break;
|
||||
case 2:
|
||||
this._sector.sectorLength = 2352;
|
||||
this._sector.userDataOffset = 24;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this._sector.sectorLength = 2336;
|
||||
this._sector.userDataOffset = 8;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
}
|
||||
finally
|
||||
{
|
||||
binaryReader?.Close();
|
||||
if (input != null)
|
||||
{
|
||||
input.Close();
|
||||
input.Dispose();
|
||||
}
|
||||
}
|
||||
return this._sector;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
namespace PS2_Manager.Core.IO.DiscImage
|
||||
{
|
||||
public interface IDiscImage
|
||||
{
|
||||
string ImagePath { get; }
|
||||
|
||||
long FirstDumpSector();
|
||||
|
||||
SectorStructure GetSectorStucture();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
namespace PS2_Manager.Core.IO.DiscImage
|
||||
{
|
||||
public struct SectorStructure(int length, int dataOffset)
|
||||
{
|
||||
public int sectorLength = length;
|
||||
public int userDataOffset = dataOffset;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#nullable disable
|
||||
namespace PS2_Manager.Core.IO.DiscImage
|
||||
{
|
||||
public class Iso9660Conv
|
||||
{
|
||||
private const int ISO_SECTOR_SIZE = 2048;
|
||||
private const int BUFFER_LENGTH_FACTOR = 64;
|
||||
private const uint FAT32_DISK_LIMIT = 4294967295;
|
||||
private SectorStructure _sectorStruct;
|
||||
private long _startFirstSector;
|
||||
private IDiscImage _discImage;
|
||||
private FileStream _fsSrc = (FileStream) null;
|
||||
private FileStream _fsDst = (FileStream) null;
|
||||
private BinaryReader _brSrc = (BinaryReader) null;
|
||||
private BinaryWriter _wrDst = (BinaryWriter) null;
|
||||
internal static byte[] SYNC_HEADER = new byte[12]
|
||||
{
|
||||
(byte) 0,
|
||||
byte.MaxValue,
|
||||
byte.MaxValue,
|
||||
byte.MaxValue,
|
||||
byte.MaxValue,
|
||||
byte.MaxValue,
|
||||
byte.MaxValue,
|
||||
byte.MaxValue,
|
||||
byte.MaxValue,
|
||||
byte.MaxValue,
|
||||
byte.MaxValue,
|
||||
(byte) 0
|
||||
};
|
||||
|
||||
public event EventHandler<Iso9660CreatorEventArgs> Progression;
|
||||
|
||||
public event EventHandler Terminate;
|
||||
|
||||
public IDiscImage DiscImage
|
||||
{
|
||||
get => this._discImage;
|
||||
set
|
||||
{
|
||||
this._discImage = value;
|
||||
this.SetDiscImage();
|
||||
}
|
||||
}
|
||||
|
||||
public Iso9660Conv()
|
||||
{
|
||||
}
|
||||
|
||||
public Iso9660Conv(IDiscImage converter)
|
||||
{
|
||||
this._discImage = converter;
|
||||
this.SetDiscImage();
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
if (this._brSrc != null)
|
||||
this._brSrc.Close();
|
||||
if (this._wrDst != null)
|
||||
this._wrDst.Close();
|
||||
if (this._fsSrc != null)
|
||||
{
|
||||
this._fsSrc.Close();
|
||||
this._fsSrc.Dispose();
|
||||
}
|
||||
if (this._fsDst == null)
|
||||
return;
|
||||
this._fsDst.Close();
|
||||
this._fsDst.Dispose();
|
||||
}
|
||||
|
||||
public void Convert(IDiscImage discImage, string isoDestination)
|
||||
{
|
||||
this._discImage = discImage != null ? discImage : throw new ArgumentNullException(nameof (discImage), "The IDiscImage interface is null.");
|
||||
this.SetDiscImage();
|
||||
this.Convert(isoDestination);
|
||||
}
|
||||
|
||||
public void Convert(string isoDestination)
|
||||
{
|
||||
if (this._discImage == null)
|
||||
throw new ArgumentNullException("The IDiscImage interface is null. You can specified an instance from DiscImage propertie.");
|
||||
if (isoDestination == string.Empty)
|
||||
throw new ArgumentNullException("output", "The output file path must not be null.");
|
||||
if (this._sectorStruct.sectorLength == 0)
|
||||
throw new IOException("The source image file format is unknown.");
|
||||
if (!File.Exists(this._discImage.ImagePath))
|
||||
throw new FileNotFoundException("The souce image file does not exists.");
|
||||
DriveInfo driveInfo = new DriveInfo(Path.GetPathRoot(isoDestination));
|
||||
long num1 = new FileInfo(this._discImage.ImagePath).Length / (long) this._sectorStruct.sectorLength * 2048L - this._startFirstSector;
|
||||
if (driveInfo.DriveFormat.Equals("FAT32") && num1 > (long) uint.MaxValue)
|
||||
throw new IOException("Not enough space on FAT32 destination drive.");
|
||||
if (driveInfo.TotalSize < num1)
|
||||
throw new IOException("Not enough space on the destination drive.");
|
||||
try
|
||||
{
|
||||
this._fsSrc = new FileStream(this._discImage.ImagePath, FileMode.Open, FileAccess.Read, FileShare.Read);
|
||||
this._brSrc = new BinaryReader((Stream) this._fsSrc);
|
||||
this._fsDst = new FileStream(isoDestination, FileMode.Create, FileAccess.Write, FileShare.None);
|
||||
this._wrDst = new BinaryWriter((Stream) this._fsDst);
|
||||
this._brSrc.BaseStream.Seek(this._startFirstSector, SeekOrigin.Begin);
|
||||
byte[] numArray = new byte[this._sectorStruct.sectorLength * 64];
|
||||
int num2;
|
||||
do
|
||||
{
|
||||
num2 = this._brSrc.Read(numArray, 0, numArray.Length);
|
||||
if (num2 == this._sectorStruct.sectorLength * 64)
|
||||
this._wrDst.Write(this.CleanUserDataBuffer(numArray, 131072U));
|
||||
else if (num2 > 0)
|
||||
{
|
||||
uint uint32 = System.Convert.ToUInt32(num2 / this._sectorStruct.sectorLength * 2048);
|
||||
this._wrDst.Write(this.CleanUserDataBuffer(numArray, uint32));
|
||||
}
|
||||
if (this.Progression != null)
|
||||
this.Progression((object) null, new Iso9660CreatorEventArgs(this._wrDst.BaseStream.Position, this._brSrc.BaseStream.Length));
|
||||
}
|
||||
while (num2 > 0 && this._wrDst.BaseStream.Position != num1);
|
||||
if (this.Terminate == null)
|
||||
return;
|
||||
this.Terminate((object) null, EventArgs.Empty);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new Exception(ex.Message, ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.Close();
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] CleanUserDataBuffer(byte[] source, uint dataSize)
|
||||
{
|
||||
byte[] dst = new byte[(int) dataSize];
|
||||
int num = 0;
|
||||
for (int index = 0; (long) index < (long) dataSize; index += 2048)
|
||||
{
|
||||
if ((long) dataSize - (long) index >= 2048L)
|
||||
{
|
||||
Buffer.BlockCopy((Array) source, num * this._sectorStruct.sectorLength + this._sectorStruct.userDataOffset, (Array) dst, num * 2048, 2048);
|
||||
++num;
|
||||
}
|
||||
else
|
||||
Buffer.BlockCopy((Array) source, this._sectorStruct.sectorLength * num + this._sectorStruct.userDataOffset, (Array) dst, num * 2048, (int) ((long) dataSize - (long) index));
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
private void SetDiscImage()
|
||||
{
|
||||
this._sectorStruct = this._discImage.GetSectorStucture();
|
||||
this._startFirstSector = this._discImage.FirstDumpSector();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#nullable disable
|
||||
namespace PS2_Manager.Core
|
||||
{
|
||||
internal static class BytesHelper
|
||||
{
|
||||
public static bool CompareBytesArray(byte[] a, byte[] b)
|
||||
{
|
||||
if (a == null || b == null || a.Length != b.Length)
|
||||
return false;
|
||||
for (int index = 0; index < a.Length; ++index)
|
||||
{
|
||||
if ((int) a[index] != (int) b[index])
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static byte[] CopyRange(byte[] source, int srcOffset, int length)
|
||||
{
|
||||
byte[] dst = new byte[length];
|
||||
if (source.Length < length)
|
||||
return (byte[]) null;
|
||||
Buffer.BlockCopy((Array) source, srcOffset, (Array) dst, 0, dst.Length);
|
||||
return dst;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#nullable disable
|
||||
namespace PS2_Manager.Core.IO.DiscImage
|
||||
{
|
||||
public class Iso9660CreatorEventArgs : EventArgs
|
||||
{
|
||||
private long _bytesWritted;
|
||||
private long _discLength;
|
||||
|
||||
public long DiscLength => this._discLength;
|
||||
|
||||
public long BytesWritted => this._bytesWritted;
|
||||
|
||||
public Iso9660CreatorEventArgs()
|
||||
{
|
||||
}
|
||||
|
||||
public Iso9660CreatorEventArgs(long writted, long discLength)
|
||||
{
|
||||
this._bytesWritted = writted;
|
||||
this._discLength = discLength;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -31,8 +31,16 @@ public static class Util
|
|||
|
||||
public static void CheckDir(string path)
|
||||
{
|
||||
if(!Directory.Exists(path))
|
||||
//Console.Info("Checking directory: " + path);
|
||||
if (!Directory.Exists(path))
|
||||
{
|
||||
Console.Error("Directory " + path + " wasn't found, creating now.");
|
||||
Directory.CreateDirectory(path);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.Success("Directory was found: " + path);
|
||||
}
|
||||
}
|
||||
public static string FormatFileSize(long bytes)
|
||||
{
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d"
|
||||
x:Class="PS2_Manager.GameInfo">
|
||||
|
||||
</UserControl>
|
|
@ -1,29 +0,0 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Avalonia.Media;
|
||||
using Avalonia.Media.Imaging;
|
||||
using Avalonia.Platform.Storage;
|
||||
using PS2_Manager.Core;
|
||||
|
||||
namespace PS2_Manager;
|
||||
|
||||
public partial class GameInfo : UserControl
|
||||
{
|
||||
public Game game { get; set; }
|
||||
public GameInfo(Game _game)
|
||||
{
|
||||
InitializeComponent();
|
||||
this.game = _game;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -10,7 +10,7 @@
|
|||
Width="990"
|
||||
Height="520"
|
||||
MinHeight="490"
|
||||
MinWidth="600"
|
||||
MinWidth="875"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
Loaded="Control_OnLoaded"
|
||||
Foreground="White">
|
||||
|
@ -25,11 +25,16 @@
|
|||
<Border Background="Transparent" Padding="10">
|
||||
<Border.ContextMenu>
|
||||
<ContextMenu>
|
||||
<MenuItem Header="Add New Game" Click="OpenFileButton_Clicked"/>
|
||||
<MenuItem Header="Remove Game" Click="DeleteButton"/>
|
||||
<MenuItem Header="Show Details"/>
|
||||
</ContextMenu>
|
||||
</Border.ContextMenu>
|
||||
<TextBlock Foreground="White" Text="{Binding Name}"/>
|
||||
<Grid ColumnDefinitions="30, 5,*">
|
||||
<Image IsVisible="{Binding Icon.ShowDVD}" Grid.Column="0" RenderOptions.BitmapInterpolationMode="HighQuality" Source="Assets/dvd.png"/>
|
||||
<Image IsVisible="{Binding Icon.ShowCD}" Grid.Column="0" RenderOptions.BitmapInterpolationMode="HighQuality" Source="Assets/cd.png"/>
|
||||
<TextBlock Grid.Column="2" Foreground="White" Text="{Binding Name}" VerticalAlignment="Center"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
|
@ -64,7 +69,8 @@
|
|||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Center"
|
||||
Spacing="10">
|
||||
<TextBlock Text="Welcome to the PS2 Games Manager"
|
||||
<TextBlock Text=""
|
||||
Name="WelcomeTextTop"
|
||||
HorizontalAlignment="Center"
|
||||
TextAlignment="Center"
|
||||
FontSize="18"
|
||||
|
@ -92,7 +98,31 @@
|
|||
<StackPanel Orientation="Vertical" Margin="10">
|
||||
<TextBlock Foreground="White" Text="Display Name:" HorizontalAlignment="Center" Padding="0,10"/>
|
||||
<TextBox Foreground="White" Name="NameTextBox_Edit"/>
|
||||
<Separator/>
|
||||
<Separator Margin="0,10"/>
|
||||
<Grid Grid.ColumnDefinitions="*,120,*,120,*">
|
||||
<Border Grid.Column="1" Background="#35313d" Padding="0,5" CornerRadius="5">
|
||||
<StackPanel>
|
||||
<Image RenderOptions.BitmapInterpolationMode="HighQuality" Source="Assets/vmc.png"/>
|
||||
<ComboBox Name="VMC_1" Margin="5,0" HorizontalAlignment="Stretch" SelectionChanged="VMC_1_OnSelectionChanged"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
<Border Grid.Column="3" Background="#35313d" Padding="0,5" CornerRadius="5">
|
||||
<StackPanel>
|
||||
<Image RenderOptions.BitmapInterpolationMode="HighQuality" Source="Assets/vmc.png"/>
|
||||
<ComboBox Name="VMC_2" Margin="5,0" HorizontalAlignment="Stretch" SelectionChanged="VMC_2_OnSelectionChanged"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
<Separator Margin="0,10"/>
|
||||
<Grid Grid.RowDefinitions="*,*,*" Grid.ColumnDefinitions="*,120,*,120,*">
|
||||
<ToggleSwitch Name="toggle_mode1" Content="Mode 1" Grid.Row="0" Grid.Column="1" IsCheckedChanged="Toggle_mode_OnIsCheckedChanged"/>
|
||||
<ToggleSwitch Name="toggle_mode2" Content="Mode 2" Grid.Row="1" Grid.Column="1" IsCheckedChanged="Toggle_mode_OnIsCheckedChanged"/>
|
||||
<ToggleSwitch Name="toggle_mode3" Content="Mode 3" Grid.Row="2" Grid.Column="1" IsCheckedChanged="Toggle_mode_OnIsCheckedChanged"/>
|
||||
<ToggleSwitch Name="toggle_mode4" Content="Mode 4" Grid.Row="0" Grid.Column="3" IsCheckedChanged="Toggle_mode_OnIsCheckedChanged"/>
|
||||
<ToggleSwitch Name="toggle_mode5" Content="Mode 5" Grid.Row="1" Grid.Column="3" IsCheckedChanged="Toggle_mode_OnIsCheckedChanged"/>
|
||||
<ToggleSwitch Name="toggle_mode6" Content="Mode 6" Grid.Row="2" Grid.Column="3" IsCheckedChanged="Toggle_mode_OnIsCheckedChanged"/>
|
||||
</Grid>
|
||||
<Separator Margin="0,10"/>
|
||||
<Button Foreground="White" Content="Calculate Checksums" Click="ChecksumButtonOnClick" HorizontalAlignment="Stretch"></Button>
|
||||
<Border Background="#35313d" CornerRadius="5" Padding="10" Margin="0,5" IsVisible="False" Name="ChecksumArea">
|
||||
<StackPanel>
|
||||
|
@ -127,7 +157,7 @@
|
|||
<Border Grid.Column="1" Width="205" Height="292" Background="Transparent" CornerRadius="5" HorizontalAlignment="Center" VerticalAlignment="Center"
|
||||
PointerPressed="CoverImage_OnPointerPressed" Name="CoverContainer">
|
||||
<Grid>
|
||||
<Image Name="CoverImage" Source="Images/missing.png" Stretch="UniformToFill"/>
|
||||
<Image Name="CoverImage" Source="Assets/missing.png" Stretch="UniformToFill"/>
|
||||
<TextBlock Name="CoverTextHint" HorizontalAlignment="Center" VerticalAlignment="Center" IsVisible="False"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
|
|
@ -4,6 +4,7 @@ using System.ComponentModel;
|
|||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Interactivity;
|
||||
|
@ -11,6 +12,7 @@ using Avalonia.Media;
|
|||
using Avalonia.Media.Imaging;
|
||||
using Avalonia.Platform.Storage;
|
||||
using Avalonia.Threading;
|
||||
using DiscUtils;
|
||||
using PS2_Manager.Core;
|
||||
|
||||
namespace PS2_Manager;
|
||||
|
@ -22,6 +24,7 @@ public partial class MainWindow : Window
|
|||
public UpdateVar<Artwork.Type> ArtworkType { get; set; } = new UpdateVar<Artwork.Type>();
|
||||
public UpdateVar<string> MD5Hash { get; set; } = new UpdateVar<string>();
|
||||
public UpdateVar<string> SHA1Hash { get; set; } = new UpdateVar<string>();
|
||||
|
||||
public MainWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
@ -88,21 +91,16 @@ public partial class MainWindow : Window
|
|||
{
|
||||
ChecksumArea.IsVisible = false;
|
||||
NameTextBox_Edit.Text = selectedGame.Name;
|
||||
VMC_1.SelectedItem = selectedGame.Config?.MemoryCard1;
|
||||
VMC_2.SelectedItem = selectedGame.Config?.MemoryCard2;
|
||||
toggle_mode1.IsChecked = selectedGame.Config?.Mode1;
|
||||
toggle_mode2.IsChecked = selectedGame.Config?.Mode2;
|
||||
toggle_mode3.IsChecked = selectedGame.Config?.Mode3;
|
||||
toggle_mode4.IsChecked = selectedGame.Config?.Mode4;
|
||||
toggle_mode5.IsChecked = selectedGame.Config?.Mode5;
|
||||
toggle_mode6.IsChecked = selectedGame.Config?.Mode6;
|
||||
}
|
||||
}
|
||||
private void WindowDrag(object? sender, PointerPressedEventArgs e)
|
||||
{
|
||||
if (e.GetCurrentPoint(this).Properties.IsLeftButtonPressed)
|
||||
{
|
||||
BeginMoveDrag(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void WindowClose(object? sender, PointerPressedEventArgs e)
|
||||
{
|
||||
Console.Success("Window closing");
|
||||
this.Close();
|
||||
}
|
||||
|
||||
private async void OpenFileButton_Clicked(object sender, RoutedEventArgs args)
|
||||
{
|
||||
|
@ -121,7 +119,16 @@ public partial class MainWindow : Window
|
|||
if (files.Count >= 1)
|
||||
{
|
||||
Console.Info("AddGameWindow was called for " + files[0].Path.LocalPath);
|
||||
new AddGameWindow(files[0].Path.LocalPath).Show();
|
||||
string ext = Path.GetExtension(files[0].Path.LocalPath);
|
||||
if (ext == ".bin")
|
||||
{
|
||||
new ConvertGameWindow(files[0].Path.LocalPath).Show();
|
||||
}
|
||||
else if (ext == ".iso")
|
||||
{
|
||||
new AddGameWindow(files[0].Path.LocalPath).Show();
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -131,6 +138,26 @@ public partial class MainWindow : Window
|
|||
|
||||
private async void Control_OnLoaded(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
string welcomeText = "";
|
||||
try
|
||||
{
|
||||
welcomeText = FileVersionInfo
|
||||
.GetVersionInfo(Assembly.GetExecutingAssembly().Location)
|
||||
.FileVersion ?? "Unknown";
|
||||
welcomeText = "Welcome to the PS2 Games Manager v" + welcomeText;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
welcomeText = "Welcome to the PS2 Games Manager";
|
||||
}
|
||||
|
||||
WelcomeTextTop.Text = welcomeText;
|
||||
Util.CheckDir(settings.library_path.GetValue<string>());
|
||||
Util.CheckDir(Path.Combine(settings.library_path.GetValue<string>(), "DVD"));
|
||||
Util.CheckDir(Path.Combine(settings.library_path.GetValue<string>(), "CD"));
|
||||
Util.CheckDir(Path.Combine(settings.library_path.GetValue<string>(), "CFG"));
|
||||
Util.CheckDir(Path.Combine(settings.library_path.GetValue<string>(), "ART"));
|
||||
Util.CheckDir(Path.Combine(settings.library_path.GetValue<string>(), "VMC"));
|
||||
FetchGamesFromLibrary();
|
||||
}
|
||||
|
||||
|
@ -139,17 +166,53 @@ public partial class MainWindow : Window
|
|||
SwitchView(true);
|
||||
Console.Info("Fetching games from library...");
|
||||
List<Game> Games = new List<Game>();
|
||||
Util.CheckDir(Path.Combine(settings.library_path.GetValue<string>(), "DVD"));
|
||||
string[] files = Directory.GetFiles(Path.Combine(settings.library_path.GetValue<string>(), "DVD"));
|
||||
foreach (var file in files)
|
||||
string[] filesDVDDir = Directory.GetFiles(Path.Combine(settings.library_path.GetValue<string>(), "DVD"));
|
||||
foreach (var file in filesDVDDir)
|
||||
{
|
||||
Game newGame =
|
||||
new Game(file, true);
|
||||
Games.Add(newGame);
|
||||
Console.Success("Successfully fetched " + newGame);
|
||||
if (Path.GetExtension(file).ToLower() == ".iso")
|
||||
{
|
||||
Game newGame =
|
||||
new Game(file, true);
|
||||
Games.Add(newGame);
|
||||
Console.Success("Successfully fetched " + newGame);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Skipped non-ISO file: " + file);
|
||||
}
|
||||
}
|
||||
string[] filesCDDir = Directory.GetFiles(Path.Combine(settings.library_path.GetValue<string>(), "CD"));
|
||||
foreach (var file in filesCDDir)
|
||||
{
|
||||
if (Path.GetExtension(file).ToLower() == ".iso")
|
||||
{
|
||||
Game newGame =
|
||||
new Game(file, true);
|
||||
Games.Add(newGame);
|
||||
Console.Success("Successfully fetched " + newGame);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Skipped non-ISO file: " + file);
|
||||
}
|
||||
}
|
||||
Games = Games.OrderBy(game => game.Name).ToList();
|
||||
GamesList.ItemsSource = Games;
|
||||
FetchVMCs();
|
||||
}
|
||||
|
||||
private void FetchVMCs()
|
||||
{
|
||||
List<string> VMCs = new List<string>();
|
||||
string[] files = Directory.GetFiles(Path.Combine(settings.library_path.GetValue<string>(), "VMC"));
|
||||
VMCs.Add("");
|
||||
foreach (var file in files)
|
||||
{
|
||||
string fileName = Path.GetFileNameWithoutExtension(file);
|
||||
VMCs.Add(fileName);
|
||||
}
|
||||
VMC_1.ItemsSource = VMCs;
|
||||
VMC_2.ItemsSource = VMCs;
|
||||
}
|
||||
|
||||
|
||||
|
@ -340,4 +403,70 @@ public partial class MainWindow : Window
|
|||
{
|
||||
this.ArtworkType.Value = Artwork.PrevType(this.ArtworkType.Value);
|
||||
}
|
||||
|
||||
private void VMC_1_OnSelectionChanged(object? sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
|
||||
if (GamesList.SelectedItem is Game selectedGame)
|
||||
{
|
||||
if (VMC_1.SelectedItem is string selectedVMC)
|
||||
{
|
||||
Console.Warning("Setting " + selectedVMC + " as VMC1 for " + selectedGame.GameID);
|
||||
selectedGame.Config.MemoryCard1 = selectedVMC;
|
||||
selectedGame.Config.SaveConfig();
|
||||
}
|
||||
}
|
||||
}
|
||||
private void VMC_2_OnSelectionChanged(object? sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
|
||||
if (GamesList.SelectedItem is Game selectedGame)
|
||||
{
|
||||
if (VMC_2.SelectedItem is string selectedVMC)
|
||||
{
|
||||
Console.Warning("Setting " + selectedVMC + " as VMC2 for " + selectedGame.GameID);
|
||||
selectedGame.Config.MemoryCard2 = selectedVMC;
|
||||
selectedGame.Config.SaveConfig();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Toggle_mode_OnIsCheckedChanged(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (GamesList.SelectedItem is Game selectedGame)
|
||||
{
|
||||
if (sender is ToggleSwitch toggle)
|
||||
{
|
||||
switch (toggle.Name)
|
||||
{
|
||||
case "toggle_mode1":
|
||||
selectedGame.Config.Mode1 = toggle_mode1.IsChecked.Value;
|
||||
Console.Warning("Toggled Mode 1 for " + selectedGame.GameID + " to " + selectedGame.Config.Mode1);
|
||||
break;
|
||||
case "toggle_mode2":
|
||||
selectedGame.Config.Mode2 = toggle_mode2.IsChecked.Value;
|
||||
Console.Warning("Toggled Mode 2 for " + selectedGame.GameID + " to " + selectedGame.Config.Mode2);
|
||||
break;
|
||||
case "toggle_mode3":
|
||||
selectedGame.Config.Mode3 = toggle_mode3.IsChecked.Value;
|
||||
Console.Warning("Toggled Mode 3 for " + selectedGame.GameID + " to " + selectedGame.Config.Mode3);
|
||||
break;
|
||||
case "toggle_mode4":
|
||||
selectedGame.Config.Mode4 = toggle_mode4.IsChecked.Value;
|
||||
Console.Warning("Toggled Mode 4 for " + selectedGame.GameID + " to " + selectedGame.Config.Mode4);
|
||||
break;
|
||||
case "toggle_mode5":
|
||||
selectedGame.Config.Mode5 = toggle_mode5.IsChecked.Value;
|
||||
Console.Warning("Toggled Mode 5 for " + selectedGame.GameID + " to " + selectedGame.Config.Mode5);
|
||||
break;
|
||||
case "toggle_mode6":
|
||||
selectedGame.Config.Mode6 = toggle_mode6.IsChecked.Value;
|
||||
Console.Warning("Toggled Mode 6 for " + selectedGame.GameID + " to " + selectedGame.Config.Mode6);
|
||||
break;
|
||||
}
|
||||
}
|
||||
selectedGame.Config.SaveConfig();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -3,9 +3,12 @@
|
|||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ApplicationIcon>icon.ico</ApplicationIcon>
|
||||
<BuiltInComInteropSupport>true</BuiltInComInteropSupport>
|
||||
<ApplicationManifest>app.manifest</ApplicationManifest>
|
||||
<AvaloniaUseCompiledBindingsByDefault>true</AvaloniaUseCompiledBindingsByDefault>
|
||||
<AssemblyVersion>1.0</AssemblyVersion>
|
||||
<FileVersion>1.4</FileVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -23,6 +26,14 @@
|
|||
|
||||
<ItemGroup>
|
||||
<None Remove="Images\missing.png" />
|
||||
<AvaloniaResource Include="Images\missing.png" />
|
||||
<AvaloniaResource Include="Assets\missing.png" />
|
||||
<None Remove="Images\vmc.png" />
|
||||
<AvaloniaResource Include="Assets\vmc.png" />
|
||||
<None Remove="Images\cd.png" />
|
||||
<AvaloniaResource Include="Assets\cd.png" />
|
||||
<None Remove="Images\dvd.png" />
|
||||
<AvaloniaResource Include="Assets\dvd.png" />
|
||||
<None Remove="Assets\bin.png" />
|
||||
<AvaloniaResource Include="Assets\bin.png" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
|
@ -5,29 +5,19 @@
|
|||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="PS2_Manager.Setup"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
SystemDecorations="None"
|
||||
Title="Setup"
|
||||
Title="Setup PS2 Manager"
|
||||
Height="349"
|
||||
Width="598"
|
||||
CanResize="False"
|
||||
Background="#201c29"
|
||||
Closing="Window_OnClosing">
|
||||
<Grid RowDefinitions="20, *">
|
||||
<Grid Grid.Row="0">
|
||||
<Border Background="#35313d"
|
||||
PointerPressed="WindowDrag">
|
||||
<Grid ColumnDefinitions="*, 20">
|
||||
<TextBlock Name="WindowTitle" FontSize="12" Text="Setup PS2 Manager" Padding="8,0,0,0" VerticalAlignment="Center"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
</Grid>
|
||||
<Grid Grid.Row="1" Margin="20">
|
||||
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
|
||||
<TextBlock Name="InfoText1" Text="Welcome to PS2 Manager" HorizontalAlignment="Center"/>
|
||||
<Separator/>
|
||||
<TextBlock Name="InfoText2" Text="First of all please select the path to your PS2 Game Library" HorizontalAlignment="Center"/>
|
||||
<Button Name="OpenLibraryButton" Content="Select Folder" HorizontalAlignment="Center" Margin="0,10"
|
||||
Click="OpenLibraryButton_OnClick"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
<Grid Margin="20">
|
||||
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
|
||||
<TextBlock Name="InfoText1" Text="Welcome to PS2 Manager" HorizontalAlignment="Center"/>
|
||||
<Separator/>
|
||||
<TextBlock Name="InfoText2" Text="First of all please select the path to your PS2 Game Library" HorizontalAlignment="Center"/>
|
||||
<Button Name="OpenLibraryButton" Content="Select Folder" HorizontalAlignment="Center" Margin="0,10"
|
||||
Click="OpenLibraryButton_OnClick"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Window>
|
||||
|
|
|
@ -43,29 +43,30 @@ public partial class Setup : Window
|
|||
{
|
||||
Console.Info("Open Library Button Clicked");
|
||||
settings.library_path.SetValue("");
|
||||
while (String.IsNullOrEmpty(settings.library_path.GetValue<string>()))
|
||||
var topLevel = TopLevel.GetTopLevel(this);
|
||||
var path = await topLevel.StorageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions
|
||||
{
|
||||
var topLevel = TopLevel.GetTopLevel(this);
|
||||
var path = await topLevel.StorageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions
|
||||
Title = "Open Game Library",
|
||||
AllowMultiple = false
|
||||
});
|
||||
try
|
||||
{
|
||||
if (!String.IsNullOrEmpty(path[0].Path.LocalPath))
|
||||
{
|
||||
Title = "Open Game Library",
|
||||
AllowMultiple = false
|
||||
});
|
||||
try
|
||||
{
|
||||
if (!String.IsNullOrEmpty(path[0].Path.LocalPath))
|
||||
settings.library_path.SetValue(path[0].Path.LocalPath);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex.Message);
|
||||
settings.library_path.SetValue(path[0].Path.LocalPath);
|
||||
FinishSetup();
|
||||
}
|
||||
|
||||
}
|
||||
FinishSetup();
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex.Message);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void Window_OnClosing(object? sender, WindowClosingEventArgs e)
|
||||
{
|
||||
if(!this.SetupFinished) e.Cancel = true;
|
||||
if(!this.SetupFinished) Environment.Exit(0);
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d"
|
||||
x:Class="PS2_Manager.Welcome">
|
||||
<StackPanel >
|
||||
|
||||
</StackPanel>
|
||||
</UserControl>
|
|
@ -1,16 +0,0 @@
|
|||
using System.Diagnostics;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.Markup.Xaml;
|
||||
|
||||
namespace PS2_Manager;
|
||||
|
||||
public partial class Welcome : UserControl
|
||||
{
|
||||
public Welcome()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
}
|
BIN
PS2_Manager/icon.ico
Normal file
After Width: | Height: | Size: 220 KiB |
11
README.md
|
@ -1,6 +1,5 @@
|
|||
# PS2 Game Manager for OPL
|
||||
|
||||
ARTWORK API IS NOT PUBLIC YET.
|
||||
|
||||
## Overview
|
||||
|
||||
|
@ -9,6 +8,10 @@ PS2 Game Manager for OPL is a modern, open-source alternative to OPL Manager des
|
|||
### Key Features:
|
||||
- **Modern and Intuitive Interface**: A redesigned UI focused on ease of use, making managing PS2 games a smooth and enjoyable experience.
|
||||
- **Open-Source**: PS2 Game Manager for OPL is completely open-source and free to use. Contributions are welcome, and the community plays a key role in its development.
|
||||
- **CD/DVD Support**: PS2-Manager supports DVDs in ISO format and CDs in BIN/CUE format with its included BIN to ISO converter
|
||||
- **Virtual Memory Cards Support**: Configure and manage virtual memory cards to store your game saves. (VMC's need to be created via OPL right now tho)
|
||||
- **Mode Toggles**
|
||||
|
||||
|
||||
## Screenshots
|
||||
|
||||
|
@ -41,6 +44,11 @@ PS2 Game Manager for OPL was built with **modern design principles** in mind. We
|
|||
- **Responsive Design**: The program adapts well to different screen sizes and resolutions, providing an optimal experience regardless of your device.
|
||||
- **Optimized Performance**: With faster loading times and smooth transitions, the program ensures a seamless experience even with large game libraries.
|
||||
|
||||
## Disclaimer
|
||||
|
||||
This project does **NOT** support piracy in any form. Please ensure that all game images you use are legally obtained. We encourage users to only use game images that they have personally dumped from their own legally owned discs. The developers of this tool do not condone or support the use of illegally obtained game images.
|
||||
|
||||
|
||||
## Open Source
|
||||
|
||||
This project is **open-source**, and contributions are highly encouraged! If you're passionate about improving the PS2 gaming experience or if you have suggestions or improvements, feel free to contribute to the project.
|
||||
|
@ -48,3 +56,4 @@ This project is **open-source**, and contributions are highly encouraged! If you
|
|||
|
||||
We welcome **issues**, **pull requests**, and **feature suggestions** from the community. Help us make this tool even better for PS2 gamers!
|
||||
|
||||
|
||||
|
|