Files
PS-Classics-fPKG-Builder/Linux/makePSClassicsfPKG/MainWindow.axaml.cs
T
SvenGDK 651e3ae792 Linux build
- Add Linux build
2024-09-08 16:25:24 +02:00

2083 lines
100 KiB
C#

using Avalonia.Controls;
using Avalonia.Interactivity;
using LibOrbisPkg.SFO;
using MsBox.Avalonia;
using MsBox.Avalonia.Enums;
using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.CompilerServices;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace makePSClassicsfPKG
{
#pragma warning disable CS0618 // Type or member is obsolete (but working as intended).
public partial class MainWindow : Window
{
public string homePath = "";
public string wineDriveC = "";
public string PS4ToolsPath = "";
public MainWindow()
{
InitializeComponent();
Opened += MainWindow_Opened;
}
private async void MainWindow_Opened(object? sender, EventArgs e)
{
// Set paths
homePath = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
wineDriveC = homePath + "/.wine/drive_c";
PS4ToolsPath = wineDriveC + "/PS4";
Console.WriteLine(Directory.GetCurrentDirectory());
// Prevent working in the wrong directory
if (!Directory.Exists(Directory.GetCurrentDirectory() + "/Tools/PS4"))
{
Directory.SetCurrentDirectory("/usr/lib/makePSClassicsfPKG");
Console.WriteLine(Directory.GetCurrentDirectory());
}
await CheckWinePrefixAndSetup();
}
#region PS1
private string CurrentPS1GameID = "";
private async void BrowsePS1IconButton_Click(object sender, RoutedEventArgs e)
{
if (VisualRoot is not Window window)
return;
var newOpenFileDialog = new OpenFileDialog() { Title = "Select a PNG icon file", AllowMultiple = false, Filters = [new FileDialogFilter() { Name = "PNG files", Extensions = { "png" } }] };
var selectedFile = await newOpenFileDialog.ShowAsync(window);
if (selectedFile is null || selectedFile.Length == 0)
return;
if (selectedFile[0] is not null)
{
SelectedPS1IconTextBox.Text = selectedFile[0];
}
}
private async void BrowsePS1StartupImageButton_Click(object sender, RoutedEventArgs e)
{
if (VisualRoot is not Window window)
return;
var newOpenFileDialog = new OpenFileDialog() { Title = "Select a PNG background file", AllowMultiple = false, Filters = [new FileDialogFilter() { Name = "PNG files", Extensions = { "png" } }] };
var selectedFile = await newOpenFileDialog.ShowAsync(window);
if (selectedFile is null || selectedFile.Length == 0)
return;
if (selectedFile[0] is not null)
{
SelectedPS1BGTextBox.Text = selectedFile[0];
}
}
private async void BrowsePS1TXTConfigButton_Click(object sender, RoutedEventArgs e)
{
if (VisualRoot is not Window window)
return;
var newOpenFileDialog = new OpenFileDialog() { Title = "Select a TXT file", AllowMultiple = false, Filters = [new FileDialogFilter() { Name = "TXT files", Extensions = { "txt" } }] };
var selectedFile = await newOpenFileDialog.ShowAsync(window);
if (selectedFile is null || selectedFile.Length == 0)
return;
if (selectedFile[0] is not null)
{
SelectedPS1TXTConfigTextBox.Text = selectedFile[0];
}
}
private async void BrowsePS1LUAConfigButton_Click(object sender, RoutedEventArgs e)
{
if (VisualRoot is not Window window)
return;
var newOpenFileDialog = new OpenFileDialog() { Title = "Select a LUA file", AllowMultiple = false, Filters = [new FileDialogFilter() { Name = "LUA files", Extensions = { "lua" } }] };
var selectedFile = await newOpenFileDialog.ShowAsync(window);
if (selectedFile is null || selectedFile.Length == 0)
return;
if (selectedFile[0] is not null)
{
SelectedPS1LUAConfigTextBox.Text = selectedFile[0];
}
}
private async void BrowsePS1Disc1Button_Click(object sender, RoutedEventArgs e)
{
if (VisualRoot is not Window window)
return;
var newOpenFileDialog = new OpenFileDialog() { Title = "", AllowMultiple = false, Filters = [new FileDialogFilter() { Name = "BIN files", Extensions = { "bin" } }] };
var selectedFile = await newOpenFileDialog.ShowAsync(window);
if (selectedFile is null || selectedFile.Length == 0)
return;
if (selectedFile[0] is not null)
{
ReadPS1BIN(selectedFile[0]);
}
else
{
var box = MessageBoxManager.GetMessageBoxStandard("PS Classics fPKG Builder", "Aborted", ButtonEnum.Ok);
await box.ShowWindowDialogAsync(window);
}
}
private async void BrowsePS1Disc2Button_Click(object sender, RoutedEventArgs e)
{
if (VisualRoot is not Window window)
return;
var newOpenFileDialog = new OpenFileDialog() { Title = "", AllowMultiple = false, Filters = [new FileDialogFilter() { Name = "BIN files", Extensions = { "bin" } }] };
var selectedFile = await newOpenFileDialog.ShowAsync(window);
if (selectedFile is null || selectedFile.Length == 0)
return;
if (selectedFile[0] is not null)
{
PS1SelectedDisc2TextBox.Text = selectedFile[0];
}
}
private async void BrowsePS1Disc3Button_Click(object sender, RoutedEventArgs e)
{
if (VisualRoot is not Window window)
return;
var newOpenFileDialog = new OpenFileDialog() { Title = "", AllowMultiple = false, Filters = [new FileDialogFilter() { Name = "BIN files", Extensions = { "bin" } }] };
var selectedFile = await newOpenFileDialog.ShowAsync(window);
if (selectedFile is null || selectedFile.Length == 0)
return;
if (selectedFile[0] is not null)
{
PS1SelectedDisc3TextBox.Text = selectedFile[0];
}
}
private async void BrowsePS1Disc4Button_Click(object sender, RoutedEventArgs e)
{
if (VisualRoot is not Window window)
return;
var newOpenFileDialog = new OpenFileDialog() { Title = "", AllowMultiple = false, Filters = [new FileDialogFilter() { Name = "BIN files", Extensions = { "bin" } }] };
var selectedFile = await newOpenFileDialog.ShowAsync(window);
if (selectedFile is null || selectedFile.Length == 0)
return;
if (selectedFile[0] is not null)
{
PS1SelectedDisc4TextBox.Text = selectedFile[0];
}
}
private async void BuildPS1fPKGButton_Click(object sender, RoutedEventArgs e)
{
if (VisualRoot is not Window window)
return;
// Checks before fPKG creation
if (string.IsNullOrEmpty(PS1SelectedDisc1TextBox.Text))
{
var ErrorMessageBox = MessageBoxManager.GetMessageBoxStandard("Cannot create fPKG", "No disc 1 specified, fPKG creation will be aborted.", ButtonEnum.Ok);
await ErrorMessageBox.ShowWindowDialogAsync(window);
return;
}
if (string.IsNullOrEmpty(PS1TitleTextBox.Text))
{
var ErrorMessageBox = MessageBoxManager.GetMessageBoxStandard("Cannot create fPKG", "No game title specified, fPKG creation will be aborted.", ButtonEnum.Ok);
await ErrorMessageBox.ShowWindowDialogAsync(window);
return;
}
if (string.IsNullOrEmpty(PS1NPTitleTextBox.Text))
{
var ErrorMessageBox = MessageBoxManager.GetMessageBoxStandard("Cannot create fPKG", "No NP title specified, fPKG creation will be aborted.", ButtonEnum.Ok);
await ErrorMessageBox.ShowWindowDialogAsync(window);
return;
}
if (PS1NPTitleTextBox.Text.Length != 9)
{
var ErrorMessageBox = MessageBoxManager.GetMessageBoxStandard("Cannot create fPKG", "'NP Title' length mismatching, only 9 characters are allowed, fPKG creation will be aborted.", ButtonEnum.Ok);
await ErrorMessageBox.ShowWindowDialogAsync(window);
return;
}
// Select output folder
var newOpenFolderDialog = new OpenFolderDialog() { Title = "Please select an output folder" };
var selectedFolder = await newOpenFolderDialog.ShowAsync(window);
// Continue if selection is not empty
if (!string.IsNullOrWhiteSpace(selectedFolder))
{
string PKGOutputFolder = selectedFolder;
string CacheDirectory = wineDriveC + @"/Cache";
string GameCacheDirectory = wineDriveC + @"/Cache/PS1fPKG";
// Remove previous fPKG creation & re-create the PS1fPKG cache folder
if (Directory.Exists(GameCacheDirectory))
{
Directory.Delete(GameCacheDirectory, true);
}
if (File.Exists(Directory.GetCurrentDirectory() + @"/Cache/PS1fPKG.gp4"))
{
File.Delete(Directory.GetCurrentDirectory() + @"/Cache/PS1fPKG.gp4");
}
Directory.CreateDirectory(GameCacheDirectory);
// Copy the PS1 emulator to the cache directory
CopyFilesRecursively(Directory.GetCurrentDirectory() + @"/Tools/PS4/emus/ps1hd", GameCacheDirectory);
// Copy the selected icon and background to the cache directory
if (!Directory.Exists(GameCacheDirectory + @"/sce_sys"))
{
Directory.CreateDirectory(GameCacheDirectory + @"/sce_sys");
}
if (!string.IsNullOrEmpty(SelectedPS1IconTextBox.Text))
{
File.Copy(SelectedPS1IconTextBox.Text, GameCacheDirectory + @"/sce_sys/icon0.png", true);
}
if (!string.IsNullOrEmpty(SelectedPS1BGTextBox.Text))
{
File.Copy(SelectedPS1BGTextBox.Text, GameCacheDirectory + @"/sce_sys/pic0.png", true);
}
// PS1 Emulator configuration
string Disc1CueFile = "";
using (var ConfigWriter = new StreamWriter(GameCacheDirectory + @"/config-title.txt", false))
{
ConfigWriter.WriteLine("--ps4-trophies=0");
ConfigWriter.WriteLine("--ps5-uds=0");
ConfigWriter.WriteLine("--trophies=0");
// Setup discs
Disc1CueFile = PS1SelectedDisc1TextBox.Text.Replace(".bin", ".cue");
ConfigWriter.WriteLine("--image=\"data/disc1.bin\"");
string Disc1BINFileName = Path.GetFileName(PS1SelectedDisc1TextBox.Text);
string Disc1CUEFileName = Path.GetFileName(Disc1CueFile);
// Copy disc 1 to the wine 'fPKG' folder
if (File.Exists(PS1SelectedDisc1TextBox.Text) && !File.Exists(wineDriveC + "/fPKG/" + Disc1BINFileName))
{
File.Copy(PS1SelectedDisc1TextBox.Text, wineDriveC + "/fPKG/" + Disc1BINFileName, true);
File.Copy(Disc1CueFile, wineDriveC + "/fPKG/" + Disc1CUEFileName, true);
}
// Copy other discs (if not empty) to the wine 'fPKG' folder
if (!string.IsNullOrEmpty(PS1SelectedDisc2TextBox.Text))
{
string Disc2CueFile = PS1SelectedDisc2TextBox.Text.Replace(".bin", ".cue");
ConfigWriter.WriteLine("--image=\"data/disc2.bin\"");
string Disc2BINFileName = Path.GetFileName(PS1SelectedDisc2TextBox.Text);
string Disc2CUEFileName = Path.GetFileName(Disc2CueFile);
if (File.Exists(PS1SelectedDisc2TextBox.Text) && !File.Exists(wineDriveC + "/fPKG/" + Disc2BINFileName))
{
File.Copy(PS1SelectedDisc2TextBox.Text, wineDriveC + "/fPKG/" + Disc2BINFileName, true);
File.Copy(Disc2CueFile, wineDriveC + "/fPKG/" + Disc2CUEFileName, true);
}
}
if (!string.IsNullOrEmpty(PS1SelectedDisc3TextBox.Text))
{
string Disc3CueFile = PS1SelectedDisc3TextBox.Text.Replace(".bin", ".cue");
ConfigWriter.WriteLine("--image=\"data/disc3.bin\"");
string Disc3BINFileName = Path.GetFileName(PS1SelectedDisc3TextBox.Text);
string Disc3CUEFileName = Path.GetFileName(Disc3CueFile);
if (File.Exists(PS1SelectedDisc3TextBox.Text) && !File.Exists(wineDriveC + "/fPKG/" + Disc3BINFileName))
{
File.Copy(PS1SelectedDisc3TextBox.Text, wineDriveC + "/fPKG/" + Disc3BINFileName, true);
File.Copy(Disc3CueFile, wineDriveC + "/fPKG/" + Disc3CUEFileName, true);
}
}
if (!string.IsNullOrEmpty(PS1SelectedDisc4TextBox.Text))
{
string Disc4CueFile = PS1SelectedDisc4TextBox.Text.Replace(".bin", ".cue");
ConfigWriter.WriteLine("--image=\"data/disc4.bin\"");
string Disc4BINFileName = Path.GetFileName(PS1SelectedDisc4TextBox.Text);
string Disc4CUEFileName = Path.GetFileName(Disc4CueFile);
if (File.Exists(PS1SelectedDisc4TextBox.Text) && !File.Exists(wineDriveC + "/fPKG/" + Disc4BINFileName))
{
File.Copy(PS1SelectedDisc4TextBox.Text, wineDriveC + "/fPKG/" + Disc4BINFileName, true);
File.Copy(Disc4CueFile, wineDriveC + "/fPKG/" + Disc4CUEFileName, true);
}
}
// Check for libcrypt protection
string FormattedGameID = "";
if (string.IsNullOrEmpty(CurrentPS1GameID))
{
FormattedGameID = PS1NPTitleTextBox.Text.Insert(4, "_").Insert(8, ".");
}
else
{
FormattedGameID = CurrentPS1GameID.Replace("-", "_").Insert(8, ".");
}
string ProtectionValue = PS1Game.IsGameProtected(FormattedGameID);
if (!string.IsNullOrEmpty(ProtectionValue))
{
ConfigWriter.WriteLine("--libcrypt=" + ProtectionValue);
}
// Check for LUA config
if (!string.IsNullOrEmpty(SelectedPS1LUAConfigTextBox.Text))
{
ConfigWriter.WriteLine("--ps1-title-id=" + PS1NPTitleTextBox.Text);
File.Copy(SelectedPS1LUAConfigTextBox.Text, GameCacheDirectory + @"/scripts/" + PS1NPTitleTextBox.Text + ".lua", true);
}
// Graphics & other configs
if (PS1UpscalingComboBox.SelectedItem is ComboBoxItem PS1UpscalingValue && PS1UpscalingValue.Content != null)
{
ConfigWriter.WriteLine("--scale=" + PS1UpscalingValue.Content.ToString());
}
if (PS1SkipBootlogoCheckBox.IsChecked == true)
{
ConfigWriter.WriteLine("--bios-hide-sce-osd=1");
}
if (PS1GunconCheckBox.IsChecked == true)
{
ConfigWriter.WriteLine("--guncon");
}
if (PS1Force60HzCheckBox.IsChecked == true)
{
ConfigWriter.WriteLine("--gpu-scanout-fps-override=60");
}
if (PS1EmulateAnalogSticksCheckBox.IsChecked == true)
{
ConfigWriter.WriteLine("--sim-analog-pad=0x2020");
}
// Check for TXT config
if (!string.IsNullOrEmpty(SelectedPS1TXTConfigTextBox.Text))
{
ConfigWriter.WriteLine("#User imported config");
ConfigWriter.WriteLine(File.ReadAllText(SelectedPS1TXTConfigTextBox.Text));
}
}
// Create a new PARAM.SFO file
var NewPS4ParamSFO = new ParamSfo();
NewPS4ParamSFO.SetValue("APP_TYPE", SfoEntryType.Integer, "1", 4);
NewPS4ParamSFO.SetValue("APP_VER", SfoEntryType.Utf8, "01.00", 8);
NewPS4ParamSFO.SetValue("ATTRIBUTE", SfoEntryType.Integer, "0", 4);
NewPS4ParamSFO.SetValue("CATEGORY", SfoEntryType.Utf8, "gd", 4);
NewPS4ParamSFO.SetValue("CONTENT_ID", SfoEntryType.Utf8, "UP9000-" + PS1NPTitleTextBox.Text + "_00-" + PS1NPTitleTextBox.Text + "PS1FPKG", 48);
NewPS4ParamSFO.SetValue("DOWNLOAD_DATA_SIZE", SfoEntryType.Integer, "0", 4);
NewPS4ParamSFO.SetValue("FORMAT", SfoEntryType.Utf8, "obs", 4);
NewPS4ParamSFO.SetValue("PARENTAL_LEVEL", SfoEntryType.Integer, "5", 4);
NewPS4ParamSFO.SetValue("SYSTEM_VER", SfoEntryType.Integer, "0", 4);
NewPS4ParamSFO.SetValue("TITLE", SfoEntryType.Utf8, PS1TitleTextBox.Text, 128);
NewPS4ParamSFO.SetValue("TITLE_ID", SfoEntryType.Utf8, PS1NPTitleTextBox.Text, 12);
NewPS4ParamSFO.SetValue("VERSION", SfoEntryType.Utf8, "01.00", 8);
File.WriteAllBytes(GameCacheDirectory + @"/sce_sys/param.sfo", NewPS4ParamSFO.Serialize());
// Create Disc TOC file
var GameBinFileInfo = new FileInfo(PS1SelectedDisc1TextBox.Text);
string CUE2TOCCMD = "\"" + Directory.GetCurrentDirectory() + @"/Tools/cue2toc" + "\" \"" + Disc1CueFile + "\" --size " + GameBinFileInfo.Length.ToString();
var EscapedArgs = CUE2TOCCMD.Replace("\"", "\\\"");
var CUE2TOCProcess = new Process();
CUE2TOCProcess.StartInfo.FileName = "/bin/bash";
CUE2TOCProcess.StartInfo.Arguments = $"-c \"{EscapedArgs}\"";
CUE2TOCProcess.StartInfo.WorkingDirectory = Path.GetDirectoryName(Disc1CueFile);
CUE2TOCProcess.StartInfo.UseShellExecute = false;
CUE2TOCProcess.StartInfo.CreateNoWindow = true;
CUE2TOCProcess.Start();
CUE2TOCProcess.WaitForExit();
// Move Disc TOC file
if (!Directory.Exists(GameCacheDirectory + @"/data"))
{
Directory.CreateDirectory(GameCacheDirectory + @"/data");
}
File.Move(Path.GetDirectoryName(PS1SelectedDisc1TextBox.Text) + @"/" + Path.GetFileNameWithoutExtension(PS1SelectedDisc1TextBox.Text) + ".TOC", GameCacheDirectory + @"/data/disc1.toc");
// Generate a GP4 project
string GenGP4CCMD = "wine \"c:\\PS4\\gengp4_patch.exe\" \"c:\\Cache\\PS1fPKG\"";
EscapedArgs = GenGP4CCMD.Replace("\"", "\\\"");
var NewProcess = new Process();
NewProcess.StartInfo.FileName = "/bin/bash";
NewProcess.StartInfo.Arguments = $"-c \"{EscapedArgs}\"";
NewProcess.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
NewProcess.StartInfo.CreateNoWindow = true;
NewProcess.Start();
NewProcess.WaitForExit();
// Modify the GP4 project and add disc info
var BaseFileNameWithExt = Path.GetFileName(PS1SelectedDisc1TextBox.Text);
var BaseFileName = BaseFileNameWithExt.Replace(".bin", "");
string Disc1CUEFilePath = "C:\\fPKG\\" + BaseFileName + ".cue";
string Disc1BINFilePath = "C:\\fPKG\\" + BaseFileName + ".bin";
string XMLDisc1CuePath = $"\n <file targ_path=\"data/disc1.cue\" orig_path=\"{Disc1CUEFilePath}\" pfs_compression=\"enable\"/>";
string XMLDisc1BinPath = $"\n <file targ_path=\"data/disc1.bin\" orig_path=\"{Disc1BINFilePath}\" pfs_compression=\"enable\"/>";
var fileContents = File.ReadAllText(CacheDirectory + "/PS1fPKG.gp4");
fileContents = fileContents.Replace("<?xml version=\"1.1\"", "<?xml version=\"1.0\"");
fileContents = fileContents.Replace("<scenarios default_id=\"1\">", "<scenarios default_id=\"0\">");
fileContents = fileContents.Replace("</files>", $"{XMLDisc1CuePath}{XMLDisc1BinPath}\n</files>");
File.WriteAllText(CacheDirectory + "/PS1fPKG.gp4", fileContents);
if (!string.IsNullOrEmpty(PS1SelectedDisc2TextBox.Text))
{
BaseFileNameWithExt = Path.GetFileName(PS1SelectedDisc2TextBox.Text);
BaseFileName = BaseFileNameWithExt.Replace(".bin", "");
string Disc2CUEFilePath = "C:\\fPKG\\" + BaseFileName + ".cue";
string Disc2BINFilePath = "C:\\fPKG\\" + BaseFileName + ".bin";
string XMLDisc2CuePath = $"\n <file targ_path=\"data/disc2.cue\" orig_path=\"{Disc2CUEFilePath}\" pfs_compression=\"enable\"/>";
string XMLDisc2BinPath = $"\n <file targ_path=\"data/disc2.bin\" orig_path=\"{Disc2BINFilePath}\" pfs_compression=\"enable\"/>";
fileContents = File.ReadAllText(CacheDirectory + "/PS1fPKG.gp4");
fileContents = fileContents.Replace("</files>", $"{XMLDisc2CuePath}{XMLDisc2BinPath}\n</files>");
File.WriteAllText(CacheDirectory + "/PS1fPKG.gp4", fileContents);
}
if (!string.IsNullOrEmpty(PS1SelectedDisc3TextBox.Text))
{
BaseFileNameWithExt = Path.GetFileName(PS1SelectedDisc3TextBox.Text);
BaseFileName = BaseFileNameWithExt.Replace(".bin", "");
string Disc3CUEFilePath = "C:\\fPKG\\" + BaseFileName + ".cue";
string Disc3BINFilePath = "C:\\fPKG\\" + BaseFileName + ".bin";
string XMLDisc3CuePath = $"\n <file targ_path=\"data/disc3.cue\" orig_path=\"{Disc3CUEFilePath}\" pfs_compression=\"enable\"/>";
string XMLDisc3BinPath = $"\n <file targ_path=\"data/disc3.bin\" orig_path=\"{Disc3BINFilePath}\" pfs_compression=\"enable\"/>";
fileContents = File.ReadAllText(CacheDirectory + "/PS1fPKG.gp4");
fileContents = fileContents.Replace("</files>", $"{XMLDisc3CuePath}{XMLDisc3BinPath}\n</files>");
File.WriteAllText(CacheDirectory + "/PS1fPKG.gp4", fileContents);
}
if (!string.IsNullOrEmpty(PS1SelectedDisc4TextBox.Text))
{
BaseFileNameWithExt = Path.GetFileName(PS1SelectedDisc4TextBox.Text);
BaseFileName = BaseFileNameWithExt.Replace(".bin", "");
string Disc4CUEFilePath = "C:\\fPKG\\" + BaseFileName + ".cue";
string Disc4BINFilePath = "C:\\fPKG\\" + BaseFileName + ".bin";
string XMLDisc4CuePath = $"\n <file targ_path=\"data/disc4.cue\" orig_path=\"{Disc4CUEFilePath}\" pfs_compression=\"enable\"/>";
string XMLDisc4BinPath = $"\n <file targ_path=\"data/disc4.bin\" orig_path=\"{Disc4BINFilePath}\" pfs_compression=\"enable\"/>";
fileContents = File.ReadAllText(CacheDirectory + "/PS1fPKG.gp4");
fileContents = fileContents.Replace("</files>", $"{XMLDisc4CuePath}{XMLDisc4BinPath}\n</files>");
File.WriteAllText(CacheDirectory + "/PS1fPKG.gp4", fileContents);
}
var DebugMessageBox = MessageBoxManager.GetMessageBoxStandard("PS fPKG Classics Builder", "All files ready!\r\nfPKG can be build.", ButtonEnum.Ok);
await DebugMessageBox.ShowWindowDialogAsync(window);
// Create the fPKG
string PUBCMD = "wine \"c:\\PS4\\orbis-pub-cmd-3.38.exe\" img_create --oformat pkg --skip_digest --no_progress_bar \"c:\\Cache\\PS1fPKG.gp4\" \"c:\\fPKG\"";
EscapedArgs = PUBCMD.Replace("\"", "\\\"");
string PKGBuilderProcessOutput;
var PKGBuilderProcess = new Process();
PKGBuilderProcess.StartInfo.FileName = "/bin/bash";
PKGBuilderProcess.StartInfo.Arguments = $"-c \"{EscapedArgs}\"";
PKGBuilderProcess.StartInfo.UseShellExecute = false;
PKGBuilderProcess.StartInfo.RedirectStandardOutput = true;
PKGBuilderProcess.StartInfo.CreateNoWindow = true;
PKGBuilderProcess.Start();
PKGBuilderProcess.WaitForExit();
// Read the process output
using (var NewStreamReader = PKGBuilderProcess.StandardOutput)
{
PKGBuilderProcessOutput = NewStreamReader.ReadToEnd();
}
if (PKGBuilderProcessOutput.Contains("Create image Process finished with warning"))
{
string PKGFileName = "UP9000-" + PS1NPTitleTextBox.Text + "_00-" + PS1NPTitleTextBox.Text + "PS1FPKG-A0100-V0100.pkg";
string PKGFilePath = wineDriveC + "/fPKG/" + PKGFileName;
if (File.Exists(PKGFilePath))
{
try
{
File.Move(PKGFilePath, PKGOutputFolder + "/" + PKGFileName);
}
catch (Exception error)
{
Console.WriteLine(error);
}
}
var PKGBuildMessageBox = MessageBoxManager.GetMessageBoxStandard("DEBUG", "fPKG created with success!", ButtonEnum.Ok);
await PKGBuildMessageBox.ShowWindowDialogAsync(window);
}
else
{
var PKGBuildMessageBox = MessageBoxManager.GetMessageBoxStandard("DEBUG", "Error creating fPKG", ButtonEnum.Ok);
await PKGBuildMessageBox.ShowWindowDialogAsync(window);
}
}
else { return; }
}
public void ReadPS1BIN(string GameBIN)
{
string GameID = "";
string GameTitle = "";
using var Bash = new Process();
var StringsCMD = $"strings \"{GameBIN}\" | fgrep BOOT";
var EscapedArgs = StringsCMD.Replace("\"", "\\\"");
Bash.StartInfo.FileName = "/bin/bash";
Bash.StartInfo.Arguments = $"-c \"{EscapedArgs}\"";
Bash.StartInfo.RedirectStandardOutput = true;
Bash.StartInfo.RedirectStandardError = true;
Bash.StartInfo.UseShellExecute = false;
Bash.StartInfo.CreateNoWindow = false;
Bash.Start();
Bash.WaitForExit();
var OutputReader = Bash.StandardOutput;
string[] ProcessOutput = OutputReader.ReadToEnd().Split(["\r\n"], StringSplitOptions.RemoveEmptyEntries);
if (ProcessOutput.Length > 0)
{
foreach (var OutputLine in ProcessOutput)
{
if (OutputLine.Contains("BOOT =") | OutputLine.Contains("BOOT="))
{
GameID = OutputLine.Replace(@"BOOT = cdrom:\", "").Replace(@"BOOT=cdrom:\", "").Replace("BOOT = cdrom:", "").Replace(";1", "").Replace("_", "-").Replace(".", "").Replace(@"MGS\", "").Trim();
GameID = GameID.ToUpper().Trim();
// Try to get a game title from the master list
if (GameID.Length == 10)
{
GameTitle = PS1Game.GetPS1GameTitleFromDatabaseList(GameID);
}
break;
}
}
}
if (!string.IsNullOrEmpty(GameID))
{
CurrentPS1GameID = GameID.Trim();
PS1NPTitleTextBox.Text = GameID.Replace("-", "").Trim();
PS1SelectedDisc1TextBox.Text = GameBIN;
}
if (!string.IsNullOrEmpty(GameTitle))
{
PS1TitleTextBox.Text = GameTitle;
}
}
#endregion
#region PS2
private string CurrentPS2GameID = "";
private string CurrentPS2GameCRC = "";
private async void BrowsePS2Disc1Button_Click(object sender, RoutedEventArgs e)
{
if (VisualRoot is not Window window)
return;
var newOpenFileDialog = new OpenFileDialog() { Title = "Select a PS2 ISO file.", AllowMultiple = false, Filters = [new FileDialogFilter() { Name = "ISO files", Extensions = { "iso" } }] };
var selectedFile = await newOpenFileDialog.ShowAsync(window);
if (selectedFile is null || selectedFile.Length == 0)
return;
if (selectedFile[0] is not null)
{
string PS2GameID = PS2Game.GetPS2GameID(selectedFile[0]);
Console.WriteLine(PS2GameID);
string ExtractedPS2GameELFPath = GetELFfromISO(selectedFile[0], PS2GameID);
CurrentPS2GameID = PS2GameID;
string PS2GameCRC = GetGameCRC(ExtractedPS2GameELFPath);
PS2GameCRC = CRCRegex().Replace(PS2GameCRC, "");
CurrentPS2GameCRC = PS2GameCRC;
if (!string.IsNullOrEmpty(PS2GameID) && !string.IsNullOrEmpty(PS2GameCRC))
{
// Check for existing TXT config in DB
if (IsConfigAvailable(PS2GameID, Directory.GetCurrentDirectory() + @"/Tools/PS4/ps2-configs/configs_txt.dat"))
{
PS2AddTXTConfigFromDatabaseCheckBox.IsChecked = true;
PS2AddTXTConfigFromDatabaseCheckBox.IsVisible = true;
}
else
{
PS2AddTXTConfigFromDatabaseCheckBox.IsChecked = false;
PS2AddTXTConfigFromDatabaseCheckBox.IsVisible = false;
}
// Check for existing LUA config in DB
if (IsConfigAvailable(PS2GameID, Directory.GetCurrentDirectory() + @"/Tools/PS4/ps2-configs/configs_lua.dat"))
{
PS2AddLUAConfigFromDatabaseCheckBox.IsChecked = true;
PS2AddLUAConfigFromDatabaseCheckBox.IsVisible = true;
}
else
{
PS2AddLUAConfigFromDatabaseCheckBox.IsChecked = false;
PS2AddLUAConfigFromDatabaseCheckBox.IsVisible = false;
}
// Check for existing PS3 config in DB
if (IsConfigAvailable(PS2GameID + ".CONFIG", Directory.GetCurrentDirectory() + @"/Tools/PS4/ps2-configs/configs_ps3.dat"))
{
PS2AddPS3ConfigFromDatabaseCheckBox.IsChecked = true;
PS2AddPS3ConfigFromDatabaseCheckBox.IsVisible = true;
}
else
{
PS2AddPS3ConfigFromDatabaseCheckBox.IsChecked = false;
PS2AddPS3ConfigFromDatabaseCheckBox.IsVisible = false;
}
// Check for existing Widescreen patch in DB
if (IsConfigAvailable(PS2GameCRC + ".lua", Directory.GetCurrentDirectory() + @"/Tools/PS4/ps2-configs/widescreen.dat"))
{
PS2UseWidescreenPatchCheckBox.IsChecked = true;
PS2UseWidescreenPatchCheckBox.IsEnabled = true;
}
else
{
PS2UseWidescreenPatchCheckBox.IsEnabled = false;
}
PS2TitleTextBox.Text = PS2Game.GetPS2GameTitleFromDatabaseList(PS2GameID.Replace(".", "").Replace("_", "-").Trim());
PS2NPTitleTextBox.Text = PS2GameID.Replace(".", "").Replace("_", "").Trim();
SelectedDisc1TextBox.Text = selectedFile[0];
}
else
{
var NoGameIDMessage = MessageBoxManager.GetMessageBoxStandard("PS Classics fPKG Builder", "Could not find the PS2 game ID within the ISO file.\r\nDo you want to use this file anyway ?", ButtonEnum.YesNo);
if (NoGameIDMessage.ShowWindowDialogAsync(window).Result == ButtonResult.Yes)
{
SelectedDisc1TextBox.Text = selectedFile[0];
}
}
}
else
{
var box = MessageBoxManager.GetMessageBoxStandard("PS Classics fPKG Builder", "Aborted", ButtonEnum.Ok);
await box.ShowWindowDialogAsync(window);
}
}
private async void BrowsePS2Disc2Button_Click(object sender, RoutedEventArgs e)
{
if (VisualRoot is not Window window)
return;
var newOpenFileDialog = new OpenFileDialog() { Title = "", AllowMultiple = false, Filters = [new FileDialogFilter() { Name = "ISO files", Extensions = { "iso" } }] };
var selectedFile = await newOpenFileDialog.ShowAsync(window);
if (selectedFile is null || selectedFile.Length == 0)
return;
if (selectedFile[0] is not null)
{
SelectedDisc2TextBox.Text = selectedFile[0];
}
}
private async void BrowsePS2Disc3Button_Click(object sender, RoutedEventArgs e)
{
if (VisualRoot is not Window window)
return;
var newOpenFileDialog = new OpenFileDialog() { Title = "", AllowMultiple = false, Filters = [new FileDialogFilter() { Name = "ISO files", Extensions = { "iso" } }] };
var selectedFile = await newOpenFileDialog.ShowAsync(window);
if (selectedFile is null || selectedFile.Length == 0)
return;
if (selectedFile[0] is not null)
{
SelectedDisc3TextBox.Text = selectedFile[0];
}
}
private async void BrowsePS2Disc4Button_Click(object sender, RoutedEventArgs e)
{
if (VisualRoot is not Window window)
return;
var newOpenFileDialog = new OpenFileDialog() { Title = "", AllowMultiple = false, Filters = [new FileDialogFilter() { Name = "ISO files", Extensions = { "iso" } }] };
var selectedFile = await newOpenFileDialog.ShowAsync(window);
if (selectedFile is null || selectedFile.Length == 0)
return;
if (selectedFile[0] is not null)
{
SelectedDisc4TextBox.Text = selectedFile[0];
}
}
private async void BrowsePS2Disc5Button_Click(object sender, RoutedEventArgs e)
{
if (VisualRoot is not Window window)
return;
var newOpenFileDialog = new OpenFileDialog() { Title = "", AllowMultiple = false, Filters = [new FileDialogFilter() { Name = "ISO files", Extensions = { "iso" } }] };
var selectedFile = await newOpenFileDialog.ShowAsync(window);
if (selectedFile is null || selectedFile.Length == 0)
return;
if (selectedFile[0] is not null)
{
SelectedDisc5TextBox.Text = selectedFile[0];
}
}
private async void BrowsePS2TXTConfigButton_Click(object sender, RoutedEventArgs e)
{
if (VisualRoot is not Window window)
return;
var newOpenFileDialog = new OpenFileDialog() { Title = "", AllowMultiple = false, Filters = [new FileDialogFilter() { Name = "TXT files", Extensions = { "txt" } }] };
var selectedFile = await newOpenFileDialog.ShowAsync(window);
if (selectedFile is null || selectedFile.Length == 0)
return;
if (selectedFile[0] is not null)
{
SelectedDisc5TextBox.Text = selectedFile[0];
}
}
private async void BrowsePS2LUAConfigButton_Click(object sender, RoutedEventArgs e)
{
if (VisualRoot is not Window window)
return;
var newOpenFileDialog = new OpenFileDialog() { Title = "", AllowMultiple = false, Filters = [new FileDialogFilter() { Name = "LUA files", Extensions = { "lua" } }] };
var selectedFile = await newOpenFileDialog.ShowAsync(window);
if (selectedFile is null || selectedFile.Length == 0)
return;
if (selectedFile[0] is not null)
{
SelectedDisc5TextBox.Text = selectedFile[0];
}
}
private async void BrowsePS2MCButton_Click(object sender, RoutedEventArgs e)
{
if (VisualRoot is not Window window)
return;
var newOpenFileDialog = new OpenFileDialog() { Title = "", AllowMultiple = false, Filters = [new FileDialogFilter() { Name = "BIN files", Extensions = { "bin" } }] };
var selectedFile = await newOpenFileDialog.ShowAsync(window);
if (selectedFile is null || selectedFile.Length == 0)
return;
if (selectedFile[0] is not null)
{
SelectedDisc5TextBox.Text = selectedFile[0];
}
}
private async void BrowsePS2IconButton_Click(object sender, RoutedEventArgs e)
{
if (VisualRoot is not Window window)
return;
var newOpenFileDialog = new OpenFileDialog() { Title = "Select a PNG icon file", AllowMultiple = false, Filters = [new FileDialogFilter() { Name = "PNG files", Extensions = { "png" } }] };
var selectedFile = await newOpenFileDialog.ShowAsync(window);
if (selectedFile is null || selectedFile.Length == 0)
return;
if (selectedFile[0] is not null)
{
SelectedIconTextBox.Text = selectedFile[0];
}
}
private async void BrowsePS2StartupImageButton_Click(object sender, RoutedEventArgs e)
{
if (VisualRoot is not Window window)
return;
var newOpenFileDialog = new OpenFileDialog() { Title = "Select a PNG background file", AllowMultiple = false, Filters = [new FileDialogFilter() { Name = "PNG files", Extensions = { "png" } }] };
var selectedFile = await newOpenFileDialog.ShowAsync(window);
if (selectedFile is null || selectedFile.Length == 0)
return;
if (selectedFile[0] is not null)
{
SelectedStartupImageTextBox.Text = selectedFile[0];
}
}
private async void BuildPS2fPKGButton_Click(object sender, RoutedEventArgs e)
{
if (VisualRoot is not Window window)
return;
// Checks before fPKG creation
if (string.IsNullOrEmpty(SelectedDisc1TextBox.Text))
{
var ErrorMessageBox = MessageBoxManager.GetMessageBoxStandard("Cannot create fPKG", "No disc 1 specified, fPKG creation will be aborted.", ButtonEnum.Ok);
await ErrorMessageBox.ShowWindowDialogAsync(window);
return;
}
if (string.IsNullOrEmpty(PS2TitleTextBox.Text))
{
var ErrorMessageBox = MessageBoxManager.GetMessageBoxStandard("Cannot create fPKG", "No game title specified, fPKG creation will be aborted.", ButtonEnum.Ok);
await ErrorMessageBox.ShowWindowDialogAsync(window);
return;
}
if (string.IsNullOrEmpty(PS2NPTitleTextBox.Text))
{
var ErrorMessageBox = MessageBoxManager.GetMessageBoxStandard("Cannot create fPKG", "No NP title specified, fPKG creation will be aborted.", ButtonEnum.Ok);
await ErrorMessageBox.ShowWindowDialogAsync(window);
return;
}
if (PS2NPTitleTextBox.Text.Length != 9)
{
var ErrorMessageBox = MessageBoxManager.GetMessageBoxStandard("Cannot create fPKG", "'NP Title' length mismatching, only 9 characters are allowed, fPKG creation will be aborted.", ButtonEnum.Ok);
await ErrorMessageBox.ShowWindowDialogAsync(window);
return;
}
// Get disc count
int DiscCount = 0;
if (!string.IsNullOrEmpty(SelectedDisc1TextBox.Text))
{
DiscCount += 1;
}
if (!string.IsNullOrEmpty(SelectedDisc2TextBox.Text))
{
DiscCount += 1;
}
if (!string.IsNullOrEmpty(SelectedDisc3TextBox.Text))
{
DiscCount += 1;
}
if (!string.IsNullOrEmpty(SelectedDisc4TextBox.Text))
{
DiscCount += 1;
}
if (!string.IsNullOrEmpty(SelectedDisc5TextBox.Text))
{
DiscCount += 1;
}
// Select output folder
var newOpenFolderDialog = new OpenFolderDialog() { Title = "Please select an output folder" };
var selectedFolder = await newOpenFolderDialog.ShowAsync(window);
if (selectedFolder != null)
{
string SelectedPS2Emulator = "";
if (PS2EmulatorComboBox.SelectedItem is ComboBoxItem SelectedPS2EmulatorComboBoxItem)
{
if (SelectedPS2EmulatorComboBoxItem.Content != null)
{
SelectedPS2Emulator = SelectedPS2EmulatorComboBoxItem.Content.ToString() ?? "";
}
}
string FullPS2GameID = CurrentPS2GameID.Replace(".", "").Replace("_", "-").Trim();
string PKGOutputFolder = selectedFolder;
string CacheDirectory = wineDriveC + @"/Cache";
string GameCacheDirectory = wineDriveC + @"/Cache/PS2fPKG";
// Remove previous fPKG creation & re-create the PS1fPKG cache folder
if (Directory.Exists(GameCacheDirectory))
{
Directory.Delete(GameCacheDirectory, true);
}
if (File.Exists(Directory.GetCurrentDirectory() + @"/Cache/PS2fPKG.gp4"))
{
File.Delete(Directory.GetCurrentDirectory() + @"/Cache/PS2fPKG.gp4");
}
Directory.CreateDirectory(GameCacheDirectory);
// Copy the PS2 emulator to the cache directory
CopyFilesRecursively(Directory.GetCurrentDirectory() + @"/Tools/PS4/emus/" + SelectedPS2Emulator, GameCacheDirectory);
// Copy the selected icon and background to the cache directory
if (!Directory.Exists(GameCacheDirectory + @"/sce_sys"))
{
Directory.CreateDirectory(GameCacheDirectory + @"/sce_sys");
}
if (!string.IsNullOrEmpty(SelectedPS1IconTextBox.Text))
{
var IconBytes = File.ReadAllBytes(SelectedPS1IconTextBox.Text);
var ConvertedIcon = Utils.ConvertTo24bppPNG(IconBytes, 512, 512);
ConvertedIcon.Save(GameCacheDirectory + @"/sce_sys/icon0.png");
//File.Copy(SelectedPS1IconTextBox.Text, GameCacheDirectory + @"/sce_sys/icon0.png", true);
}
if (!string.IsNullOrEmpty(SelectedPS1BGTextBox.Text))
{
var BGBytes = File.ReadAllBytes(SelectedPS1BGTextBox.Text);
var ConvertedBG = Utils.ConvertTo24bppPNG(BGBytes, 1920, 1080);
ConvertedBG.Save(GameCacheDirectory + @"/sce_sys/pic0.png");
//File.Copy(SelectedPS1BGTextBox.Text, GameCacheDirectory + @"/sce_sys/pic0.png", true);
}
// Create a new PARAM.SFO file
var NewPS4ParamSFO = new ParamSfo();
NewPS4ParamSFO.SetValue("APP_TYPE", SfoEntryType.Integer, "1", 4);
NewPS4ParamSFO.SetValue("APP_VER", SfoEntryType.Utf8, "01.00", 8);
NewPS4ParamSFO.SetValue("ATTRIBUTE", SfoEntryType.Integer, "0", 4);
NewPS4ParamSFO.SetValue("CATEGORY", SfoEntryType.Utf8, "gd", 4);
NewPS4ParamSFO.SetValue("CONTENT_ID", SfoEntryType.Utf8, "UP9000-" + PS2NPTitleTextBox.Text + "_00-" + CurrentPS2GameID.Replace(".", "").Replace("_", "").Trim() + "0000001", 48);
NewPS4ParamSFO.SetValue("DOWNLOAD_DATA_SIZE", SfoEntryType.Integer, "0", 4);
NewPS4ParamSFO.SetValue("FORMAT", SfoEntryType.Utf8, "obs", 4);
NewPS4ParamSFO.SetValue("PARENTAL_LEVEL", SfoEntryType.Integer, "5", 4);
NewPS4ParamSFO.SetValue("REMOTE_PLAY_KEY_ASSIGN", SfoEntryType.Integer, "0", 4);
NewPS4ParamSFO.SetValue("SYSTEM_VER", SfoEntryType.Integer, "0", 4);
NewPS4ParamSFO.SetValue("TITLE", SfoEntryType.Utf8, PS2TitleTextBox.Text, 128);
NewPS4ParamSFO.SetValue("TITLE_ID", SfoEntryType.Utf8, PS2NPTitleTextBox.Text, 12);
NewPS4ParamSFO.SetValue("VERSION", SfoEntryType.Utf8, "01.00", 8);
File.WriteAllBytes(GameCacheDirectory + @"/sce_sys/param.sfo", NewPS4ParamSFO.Serialize());
// Create a new PS2 emulator configuration file
string UprenderValue = "";
if (PS2EmulatorComboBox.SelectedItem is ComboBoxItem UprenderComboBoxItem)
{
if (UprenderComboBoxItem.Content != null)
{
UprenderValue = UprenderComboBoxItem.Content.ToString() ?? "";
}
}
string UpscalingValue = "";
if (PS2EmulatorComboBox.SelectedItem is ComboBoxItem UpscalingComboBoxItem)
{
if (UpscalingComboBoxItem.Content != null)
{
UprenderValue = UpscalingComboBoxItem.Content.ToString() ?? "";
}
}
string DisplayModeValue = "";
if (PS2EmulatorComboBox.SelectedItem is ComboBoxItem DisplayModeComboBoxItem)
{
if (DisplayModeComboBoxItem.Content != null)
{
UprenderValue = DisplayModeComboBoxItem.Content.ToString() ?? "";
}
}
string[] NewPS2EmulatorConfig = [ "--path-vmc=\"/tmp/vmc\"\r\n--config-local-lua=\"\"\r\n--ps2-title-id=",
FullPS2GameID, "\r\n--max-disc-num=",
DiscCount.ToString(),
"\r\n--gs-uprender=",
UprenderValue.ToLower(),
"\r\n--gs-upscale=",
UpscalingValue.ToLower(),
"\r\n--host-audio=1\r\n--rom=\"PS20220WD20050620.crack\"\r\n--verbose-cdvd-reads=0\r\n--host-display-mode=",
DisplayModeValue.ToLower() ];
string NewPS2EmulatorConfigContent = string.Concat(NewPS2EmulatorConfig);
// Reset on disc change config
if (PS2RestartEmulatorOnDiscChangeCheckBox.IsChecked == false)
{
NewPS2EmulatorConfigContent += "\r\n#Disable emu reset on disc change\r\n--switch-disc-reset=0";
}
// Multitap config
if (PS2MultitapComboBox.SelectedIndex == 1)
{
NewPS2EmulatorConfigContent += "\r\n#Enable Multitap\r\n--mtap1=always";
}
else if (PS2MultitapComboBox.SelectedIndex == 2)
{
NewPS2EmulatorConfigContent += "\r\n#Enable Multitap\r\n--mtap2=always";
}
else if (PS2MultitapComboBox.SelectedIndex == 3)
{
NewPS2EmulatorConfigContent += "\r\n#Enable Multitap\r\n--mtap1=always\r\n--mtap2=always";
}
// Check for PS3 config file
if (PS2AddPS3ConfigFromDatabaseCheckBox.IsChecked == true)
{
if (File.Exists(Directory.GetCurrentDirectory() + @"/Tools/PS4/ps2-configs/ps3/" + CurrentPS2GameID + ".CONFIG"))
{
NewPS2EmulatorConfigContent += "\r\n--lopnor-config=1";
// Create patches directory
if (!Directory.Exists(GameCacheDirectory + @"/patches/" + FullPS2GameID))
{
Directory.CreateDirectory(GameCacheDirectory + @"/patches/" + FullPS2GameID);
}
File.Copy(Directory.GetCurrentDirectory() + @"/Tools/PS4/ps2-configs/ps3/" + CurrentPS2GameID + ".CONFIG", GameCacheDirectory + @"/patches/" + FullPS2GameID + @"/" + FullPS2GameID + "_lopnor.cfgbin", true);
}
else if (IsConfigAvailable(CurrentPS2GameID + ".CONFIG", Directory.GetCurrentDirectory() + @"/Tools/PS4/ps2-configs/configs_ps3.dat"))
{
if (!Directory.Exists(GameCacheDirectory + @"/patches/" + FullPS2GameID))
{
Directory.CreateDirectory(GameCacheDirectory + @"/patches/" + FullPS2GameID);
}
ExtractFileFromISO(Directory.GetCurrentDirectory() + @"/Tools/PS4/ps2-configs/configs_ps3.dat", CurrentPS2GameID + ".CONFIG", GameCacheDirectory + @"/patches/" + FullPS2GameID + @"/" + FullPS2GameID + "_lopnor.cfgbin");
}
}
// Widescreen Patch cnofig
if (PS2UseWidescreenPatchCheckBox.IsChecked == true)
{
string WidescreenPatch = "";
if (File.Exists(Directory.GetCurrentDirectory() + @"/Tools/PS4/ps2-configs/widescreen/" + CurrentPS2GameCRC + ".lua"))
{
WidescreenPatch = File.ReadAllText(Directory.GetCurrentDirectory() + @"/Tools/PS4/ps2-configs/widescreen/" + CurrentPS2GameCRC + ".lua");
}
else if (IsConfigAvailable(CurrentPS2GameCRC + ".lua", Directory.GetCurrentDirectory() + @"/Tools/PS4/ps2-configs/widescreen.dat"))
{
WidescreenPatch = GetPNACHFromDAT(Directory.GetCurrentDirectory() + @"/Tools/PS4/ps2-configs/widescreen.dat", CurrentPS2GameCRC + ".lua");
}
if (!string.IsNullOrEmpty(WidescreenPatch))
{
NewPS2EmulatorConfigContent += "\r\n--path-trophydata=\"/app0/trophy_data\"";
if (!Directory.Exists(GameCacheDirectory + @"/trophy_data/"))
{
Directory.CreateDirectory(GameCacheDirectory + @"/trophy_data/");
}
File.WriteAllText(GameCacheDirectory + @"/trophy_data/" + FullPS2GameID + "_trophies.lua", WidescreenPatch);
}
}
// Copy lua_include to cache directory
CopyFilesRecursively(Directory.GetCurrentDirectory() + @"/Tools/PS4/lua_include", GameCacheDirectory + @"/lua_include");
// Check for LUA config
if (!string.IsNullOrEmpty(SelectedPS2LUAConfigTextBox.Text))
{
NewPS2EmulatorConfigContent += "\r\n--path-patches=\"/app0/patches";
// Create patches directory if it doesn't exist yet
if (!Directory.Exists(GameCacheDirectory + @"/patches/" + FullPS2GameID))
{
Directory.CreateDirectory(GameCacheDirectory + @"/patches/" + FullPS2GameID);
}
File.Copy(SelectedPS2LUAConfigTextBox.Text, GameCacheDirectory + @"/patches/" + FullPS2GameID + "_config.lua", true);
}
else if (PS2AddLUAConfigFromDatabaseCheckBox.IsChecked == true)
{
if (IsConfigAvailable(CurrentPS2GameID, Directory.GetCurrentDirectory() + @"/Tools/PS4/ps2-configs/configs_lua.dat"))
{
NewPS2EmulatorConfigContent += "\r\n--path-patches=\"/app0/patches";
if (!Directory.Exists(GameCacheDirectory + @"/patches/" + FullPS2GameID))
{
Directory.CreateDirectory(GameCacheDirectory + @"/patches/" + FullPS2GameID);
}
ExtractFileFromISO(Directory.GetCurrentDirectory() + @"/Tools/PS4/ps2-configs/configs_lua.dat", CurrentPS2GameID, GameCacheDirectory + @"/patches/" + FullPS2GameID + "_config.lua");
}
}
// Emulator fixes
string PS2EmulatorFixes = "";
if (PS2ImproveSpeedCheckBox.IsChecked == true)
{
PS2EmulatorFixes += "\r\n#Improve Speed\r\n-vu0-opt-flags=1\r\n--vu1-opt-flags=1\r\n--cop2-opt-flags=1\r\n--vu0-const-prop=0\r\n--vu1-const-prop=0\r\n--vu1-jr-cache-policy=newprog\r\n--vu1-jalr-cache-policy=newprog\r\n--vu0-jr-cache-policy=newprog\r\n--vu0-jalr-cache-policy=newprog";
}
if (PS2FixGraphicsCheckBox.IsChecked == true)
{
PS2EmulatorFixes += "\r\n#Fix Graphics\r\n--fpu-no-clamping=0\r\n--fpu-clamp-results=1\r\n--vu0-no-clamping=0\r\n--vu0-clamp-results=1\r\n--vu1-no-clamping=0\r\n--vu1-clamp-results=1\r\n--cop2-no-clamping=0\r\n--cop2-clamp-results=1";
}
if (PS2DisableMTVUCheckBox.IsChecked == true)
{
PS2EmulatorFixes += "\r\n#Disable MTVU\r\n--vu1=jit-sync";
}
if (PS2DisableInstantVIF1TransferCheckBox.IsChecked == true)
{
PS2EmulatorFixes += "\r\n#Disable Instant VIF1 Transfer\r\n--vif1-instant-xfer=0";
}
// Check for TXT config
if (!string.IsNullOrEmpty(SelectedPS2TXTConfigTextBox.Text))
{
string[] ModifiedPS2EmulatorConfigContent = [NewPS2EmulatorConfigContent, "\r\n", PS2EmulatorFixes, "\r\n#User Config\r\n", File.ReadAllText(SelectedPS2TXTConfigTextBox.Text)];
NewPS2EmulatorConfigContent = string.Concat(ModifiedPS2EmulatorConfigContent);
}
else if (PS2AddTXTConfigFromDatabaseCheckBox.IsChecked == true)
{
if (IsConfigAvailable(CurrentPS2GameID, Directory.GetCurrentDirectory() + @"/Tools/PS4/ps2-configs/configs_txt.dat"))
{
NewPS2EmulatorConfigContent = NewPS2EmulatorConfigContent + "\r\n#" + CurrentPS2GameID + "\r\n" + GetPNACHFromDAT(Directory.GetCurrentDirectory() + @"/Tools/PS4/ps2-configs/configs_txt.dat", CurrentPS2GameID);
}
}
else
{
// Append only PS2EmulatorFixes
NewPS2EmulatorConfigContent = NewPS2EmulatorConfigContent + "\r\n" + PS2EmulatorFixes;
}
// Write config-emu-ps4.txt
if (File.Exists(GameCacheDirectory + @"/config-emu-ps4.txt"))
{
File.Delete(GameCacheDirectory + @"/config-emu-ps4.txt");
}
File.WriteAllText(GameCacheDirectory + @"/config-emu-ps4.txt", NewPS2EmulatorConfigContent);
if (!Directory.Exists(GameCacheDirectory + @"/feature_data/"))
{
Directory.CreateDirectory(GameCacheDirectory + @"/feature_data/");
}
if (!Directory.Exists(GameCacheDirectory + @"/feature_data/" + FullPS2GameID))
{
Directory.CreateDirectory(GameCacheDirectory + @"/feature_data/" + FullPS2GameID);
}
// Check for PS2 Memory Card file
if (!string.IsNullOrEmpty(SelectedPS2MemoryCardTextBox.Text))
{
File.Copy(SelectedPS2MemoryCardTextBox.Text, GameCacheDirectory + @"/feature_data/" + FullPS2GameID + @"/custom.card", true);
}
if (!Directory.Exists(GameCacheDirectory + @"/image"))
{
Directory.CreateDirectory(GameCacheDirectory + @"/image");
}
// Generate a GP4 project
string GenGP4CCMD = "wine \"c:\\PS4\\gengp4_patch.exe\" \"c:\\Cache\\PS2fPKG\"";
var EscapedArgs = GenGP4CCMD.Replace("\"", "\\\"");
var NewProcess = new Process();
NewProcess.StartInfo.FileName = "/bin/bash";
NewProcess.StartInfo.Arguments = $"-c \"{EscapedArgs}\"";
NewProcess.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
NewProcess.StartInfo.CreateNoWindow = true;
NewProcess.Start();
NewProcess.WaitForExit();
// Modify the GP4 project and add disc info
File.WriteAllText(CacheDirectory + "/PS2fPKG.gp4", File.ReadAllText(CacheDirectory + "/PS2fPKG.gp4").Replace("<?xml version=\"1.1\"", "<?xml version=\"1.0\""));
File.WriteAllText(CacheDirectory + "/PS2fPKG.gp4", File.ReadAllText(CacheDirectory + "/PS2fPKG.gp4").Replace("<scenarios default_id=\"1\">", "<scenarios default_id=\"0\">"));
// Copy selected discs to the inner fPKG folder (if not exists) and add to GP4 project file
string FullDiscInfo = "";
string Disc1FileNameWithExtension = Path.GetFileName(SelectedDisc1TextBox.Text);
string Disc1FileNameWithoutExtension = Path.GetFileNameWithoutExtension(Disc1FileNameWithExtension);
string Disc1ISOFilePath = "C:\\fPKG\\" + Disc1FileNameWithoutExtension + ".iso";
string[] Disc1Info = [FullDiscInfo, $"\n <file targ_path=\"image/disc01.iso\" orig_path=\"{Disc1ISOFilePath}\" pfs_compression=\"enable\"/>"];
FullDiscInfo = string.Join("", Disc1Info);
if (!File.Exists(wineDriveC + "/fPKG/" + Disc1FileNameWithExtension))
{
File.Copy(SelectedDisc1TextBox.Text, wineDriveC + "/fPKG/" + Disc1FileNameWithExtension);
}
if (!string.IsNullOrEmpty(SelectedDisc2TextBox.Text))
{
string Disc2FileNameWithExtension = Path.GetFileName(SelectedDisc2TextBox.Text);
string Disc2FileNameWithoutExtension = Path.GetFileNameWithoutExtension(Disc2FileNameWithExtension);
string Disc2ISOFilePath = "C:\\fPKG\\" + Disc2FileNameWithoutExtension + ".iso";
string[] Disc2Info = [FullDiscInfo, $"\n <file targ_path=\"image/disc02.iso\" orig_path=\"{Disc2ISOFilePath}\" pfs_compression=\"enable\"/>"];
FullDiscInfo = string.Join("", Disc2Info);
if (!File.Exists(wineDriveC + "/fPKG/" + Disc2FileNameWithExtension))
{
File.Copy(SelectedDisc2TextBox.Text, wineDriveC + "/fPKG/" + Disc2FileNameWithExtension);
}
}
if (!string.IsNullOrEmpty(SelectedDisc3TextBox.Text))
{
string Disc3FileNameWithExtension = Path.GetFileName(SelectedDisc3TextBox.Text);
string Disc3FileNameWithoutExtension = Path.GetFileNameWithoutExtension(Disc3FileNameWithExtension);
string Disc3ISOFilePath = "C:\\fPKG\\" + Disc3FileNameWithoutExtension + ".iso";
string[] Disc3Info = [FullDiscInfo, $"\n <file targ_path=\"image/disc03.iso\" orig_path=\"{Disc3ISOFilePath}\" pfs_compression=\"enable\"/>"];
FullDiscInfo = string.Join("", Disc3Info);
if (!File.Exists(wineDriveC + "/fPKG/" + Disc3FileNameWithExtension))
{
File.Copy(SelectedDisc3TextBox.Text, wineDriveC + "/fPKG/" + Disc3FileNameWithExtension);
}
}
if (!string.IsNullOrEmpty(SelectedDisc4TextBox.Text))
{
string Disc4FileNameWithExtension = Path.GetFileName(SelectedDisc4TextBox.Text);
string Disc4FileNameWithoutExtension = Path.GetFileNameWithoutExtension(Disc4FileNameWithExtension);
string Disc4ISOFilePath = "C:\\fPKG\\" + Disc4FileNameWithoutExtension + ".iso";
string[] Disc4Info = [FullDiscInfo, $"\n <file targ_path=\"image/disc04.iso\" orig_path=\"{Disc4ISOFilePath}\" pfs_compression=\"enable\"/>"];
FullDiscInfo = string.Join("", Disc4Info);
if (!File.Exists(wineDriveC + "/fPKG/" + Disc4FileNameWithExtension))
{
File.Copy(SelectedDisc4TextBox.Text, wineDriveC + "/fPKG/" + Disc4FileNameWithExtension);
}
}
if (!string.IsNullOrEmpty(SelectedDisc5TextBox.Text))
{
string Disc5FileNameWithExtension = Path.GetFileName(SelectedDisc5TextBox.Text);
string Disc5FileNameWithoutExtension = Path.GetFileNameWithoutExtension(Disc5FileNameWithExtension);
string Disc5ISOFilePath = "C:\\fPKG\\" + Disc5FileNameWithoutExtension + ".iso";
string[] Disc5Info = [FullDiscInfo, $"\n <file targ_path=\"image/disc05.iso\" orig_path=\"{Disc5ISOFilePath}\" pfs_compression=\"enable\"/>"];
FullDiscInfo = string.Join("", Disc5Info);
if (!File.Exists(wineDriveC + "/fPKG/" + Disc5FileNameWithExtension))
{
File.Copy(SelectedDisc5TextBox.Text, wineDriveC + "/fPKG/" + Disc5FileNameWithExtension);
}
}
File.WriteAllText(CacheDirectory + "/PS2fPKG.gp4", File.ReadAllText(CacheDirectory + "/PS2fPKG.gp4").Replace("</files>", $"{FullDiscInfo}\n</files>"));
var DebugMessageBox = MessageBoxManager.GetMessageBoxStandard("PS fPKG Classics Builder", "All files ready! \r\n fPKG can be build.", ButtonEnum.Ok);
await DebugMessageBox.ShowWindowDialogAsync(window);
// Create the fPKG
string PUBCMD = "wine \"c:\\PS4\\orbis-pub-cmd-3.38.exe\" img_create --oformat pkg --skip_digest --no_progress_bar \"c:\\Cache\\PS2fPKG.gp4\" \"c:\\fPKG\"";
EscapedArgs = PUBCMD.Replace("\"", "\\\"");
string PKGBuilderProcessOutput;
var PKGBuilderProcess = new Process();
PKGBuilderProcess.StartInfo.FileName = "/bin/bash";
PKGBuilderProcess.StartInfo.Arguments = $"-c \"{EscapedArgs}\"";
PKGBuilderProcess.StartInfo.UseShellExecute = false;
PKGBuilderProcess.StartInfo.RedirectStandardOutput = true;
PKGBuilderProcess.StartInfo.CreateNoWindow = true;
PKGBuilderProcess.Start();
PKGBuilderProcess.WaitForExit();
// Read the process output
using (var NewStreamReader = PKGBuilderProcess.StandardOutput)
{
PKGBuilderProcessOutput = NewStreamReader.ReadToEnd();
}
if (PKGBuilderProcessOutput.Contains("Create image Process finished with warning"))
{
string PKGFileName = "UP9000-" + PS2NPTitleTextBox.Text + "_00-" + CurrentPS2GameID.Replace(".", "").Replace("_", "").Trim() + "0000001" + "-A0100-V0100.pkg";
string PKGFilePath = wineDriveC + "/fPKG/" + PKGFileName;
if (File.Exists(PKGFilePath))
{
try
{
File.Move(PKGFilePath, PKGOutputFolder + "/" + PKGFileName);
}
catch (Exception error)
{
Console.WriteLine(error);
}
}
var PKGBuildMessageBox = MessageBoxManager.GetMessageBoxStandard("DEBUG", "fPKG created with success!", ButtonEnum.Ok);
await PKGBuildMessageBox.ShowWindowDialogAsync(window);
}
else
{
DebugMessageBox = MessageBoxManager.GetMessageBoxStandard("DEBUG", "Error creating fPKG", ButtonEnum.Ok);
await DebugMessageBox.ShowWindowDialogAsync(window);
}
}
else { return; }
}
private static bool IsConfigAvailable(string GameID, string ConfigDatabaseFile)
{
bool Exists;
try
{
using var NewFileStream = new FileStream(ConfigDatabaseFile, FileMode.Open, FileAccess.Read);
var NewUdfReader = new DiscUtils.Udf.UdfReader(NewFileStream, 2048);
try
{
NewUdfReader.OpenFile(GameID, FileMode.Open);
Exists = true;
}
catch (Exception)
{
Exists = false;
}
}
catch (Exception)
{
Exists = false;
}
return Exists;
}
private static string GetELFfromISO(string GameISOFile, string GameELFName)
{
string ExtractedELFPath = "";
string CacheDir = Directory.GetCurrentDirectory() + @"/Cache";
if (!Directory.Exists(CacheDir))
{
Directory.CreateDirectory(CacheDir);
}
try
{
using var NewFileStream = new FileStream(GameISOFile, FileMode.Open, FileAccess.Read);
var NewCDReader = new DiscUtils.Iso9660.CDReader(NewFileStream, true);
try
{
var ELFExtractionFileStream = new FileStream(CacheDir + @"/" + GameELFName, FileMode.Create);
NewCDReader.OpenFile(GameELFName, FileMode.Open).CopyTo(ELFExtractionFileStream);
ExtractedELFPath = CacheDir + @"/" + GameELFName;
}
catch (Exception)
{
ExtractedELFPath = "";
}
}
catch (Exception)
{
return ExtractedELFPath;
}
return ExtractedELFPath;
}
private static string GetGameCRC(string PS2GamePath)
{
// Get ELF crc
string CRCCCMD = "\"" + Directory.GetCurrentDirectory() + @"/Tools/crc" + "\" \"" + PS2GamePath + "\"";
var EscapedArgs = CRCCCMD.Replace("\"", "\\\"");
var CRCProcess = new Process();
CRCProcess.StartInfo.FileName = "/bin/bash";
CRCProcess.StartInfo.Arguments = $"-c \"{EscapedArgs}\"";
CRCProcess.StartInfo.UseShellExecute = false;
CRCProcess.StartInfo.CreateNoWindow = true;
CRCProcess.StartInfo.RedirectStandardOutput = true;
CRCProcess.Start();
CRCProcess.WaitForExit();
using var NewStreamReader = CRCProcess.StandardOutput;
return NewStreamReader.ReadToEnd().Replace("crc:", "").Trim();
}
private static string ExtractFileFromISO(string GameISOFile, string FileToExtract, string FileDestinationPath)
{
string ReturnedFileDestinationPath;
try
{
using var NewFileStream = new FileStream(GameISOFile, FileMode.Open, FileAccess.Read);
var NewUdfReader = new DiscUtils.Udf.UdfReader(NewFileStream, 2048);
try
{
var NewFileStream2 = new FileStream(FileDestinationPath, FileMode.Create);
NewUdfReader.OpenFile(FileToExtract, FileMode.Open).CopyTo(NewFileStream2);
NewFileStream2.Close();
ReturnedFileDestinationPath = FileDestinationPath;
}
catch (Exception)
{
ReturnedFileDestinationPath = "";
}
}
catch (Exception)
{
ReturnedFileDestinationPath = "";
}
return ReturnedFileDestinationPath;
}
private static string GetPNACHFromDAT(string DATFile, string FileToExtract)
{
string PNACHString;
try
{
using var NewFileStream = new FileStream(DATFile, FileMode.Open, FileAccess.Read);
var NewUdfReader = new DiscUtils.Udf.UdfReader(NewFileStream, 2048);
try
{
PNACHString = new StreamReader(NewUdfReader.OpenFile(FileToExtract, FileMode.Open)).ReadToEnd();
}
catch (Exception)
{
PNACHString = "";
}
}
catch (Exception)
{
PNACHString = "";
}
return PNACHString;
}
#endregion
#region PSP
private async void BrowsePSPIconButton_Click(object sender, RoutedEventArgs e)
{
if (VisualRoot is not Window window)
return;
var newOpenFileDialog = new OpenFileDialog() { Title = "Select a PNG icon file", AllowMultiple = false, Filters = [new FileDialogFilter() { Name = "PNG files", Extensions = { "png" } }] };
var selectedFile = await newOpenFileDialog.ShowAsync(window);
if (selectedFile is null || selectedFile.Length == 0)
return;
if (selectedFile[0] is not null)
{
SelectedPSPIconTextBox.Text = selectedFile[0];
}
}
private async void BrowsePSPBGButton_Click(object sender, RoutedEventArgs e)
{
if (VisualRoot is not Window window)
return;
var newOpenFileDialog = new OpenFileDialog() { Title = "Select a PNG background file", AllowMultiple = false, Filters = [new FileDialogFilter() { Name = "PNG files", Extensions = { "png" } }] };
var selectedFile = await newOpenFileDialog.ShowAsync(window);
if (selectedFile is null || selectedFile.Length == 0)
return;
if (selectedFile[0] is not null)
{
SelectedPSPBGImageTextBox.Text = selectedFile[0];
}
}
private async void BrowsePSPDiscButton_Click(object sender, RoutedEventArgs e)
{
if (VisualRoot is not Window window)
return;
var newOpenFileDialog = new OpenFileDialog() { Title = "Select a PSP ISO file.", AllowMultiple = false, Filters = [new FileDialogFilter() { Name = "ISO files", Extensions = { "iso" } }] };
var selectedFile = await newOpenFileDialog.ShowAsync(window);
if (selectedFile is null || selectedFile.Length == 0)
return;
if (selectedFile[0] is not null)
{
if (FileExistInISO(selectedFile[0], @"\PSP_GAME\PARAM.SFO"))
{
string CacheDir = Directory.GetCurrentDirectory() + @"/Cache";
string ExtractedUMDDataPath = ExtractFileFromPSPISO(selectedFile[0], "UMD_DATA.BIN", CacheDir + @"/temp_umd_data.bin");
if (!string.IsNullOrEmpty(ExtractedUMDDataPath))
{
PSPNPTitleTextBox.Text = System.Text.Encoding.ASCII.GetString(ReadUMDData(CacheDir + @"/temp_umd_data.bin", 0L, 10)).Replace("-", "");
PSPTitleTextBox.Text = PSPTitleRegex1().Replace(Path.GetFileNameWithoutExtension(selectedFile[0]), "");
PSPTitleTextBox.Text = PSPTitleRegex2().Replace(PSPTitleTextBox.Text, "");
}
SelectedPSPDiscTextBox.Text = selectedFile[0];
}
else
{
var NoValidFileMessage = MessageBoxManager.GetMessageBoxStandard("PS fPKG Classics Builder", "Could not find any PSP game information within the ISO file.\r\nDo you want to use this file anyway ?", ButtonEnum.YesNo);
var NoValidFileMessageValue = await NoValidFileMessage.ShowWindowDialogAsync(window);
if (NoValidFileMessageValue == ButtonResult.Yes)
{
SelectedPSPDiscTextBox.Text = selectedFile[0];
}
}
}
}
private async void BrowsePSPConfigButton_Click(object sender, RoutedEventArgs e)
{
if (VisualRoot is not Window window)
return;
var newOpenFileDialog = new OpenFileDialog() { Title = "", AllowMultiple = false, Filters = [new FileDialogFilter() { Name = "TXT files", Extensions = { "txt" } }] };
var selectedFile = await newOpenFileDialog.ShowAsync(window);
if (selectedFile is null || selectedFile.Length == 0)
return;
if (selectedFile[0] is not null)
{
SelectedDisc5TextBox.Text = selectedFile[0];
}
}
private async void BuildPSPfPKGButton_Click(object sender, RoutedEventArgs e)
{
if (VisualRoot is not Window window)
return;
// Checks before fPKG creation
if (string.IsNullOrEmpty(SelectedPSPDiscTextBox.Text))
{
var ErrorMessageBox = MessageBoxManager.GetMessageBoxStandard("Cannot create fPKG", "No disc specified, fPKG creation will be aborted.", ButtonEnum.Ok);
await ErrorMessageBox.ShowWindowDialogAsync(window);
return;
}
if (string.IsNullOrEmpty(PSPTitleTextBox.Text))
{
var ErrorMessageBox = MessageBoxManager.GetMessageBoxStandard("Cannot create fPKG", "No game title specified, fPKG creation will be aborted.", ButtonEnum.Ok);
await ErrorMessageBox.ShowWindowDialogAsync(window);
return;
}
if (string.IsNullOrEmpty(PSPNPTitleTextBox.Text))
{
var ErrorMessageBox = MessageBoxManager.GetMessageBoxStandard("Cannot create fPKG", "No NP title specified, fPKG creation will be aborted.", ButtonEnum.Ok);
await ErrorMessageBox.ShowWindowDialogAsync(window);
return;
}
if (PSPNPTitleTextBox.Text.Length != 9)
{
var ErrorMessageBox = MessageBoxManager.GetMessageBoxStandard("Cannot create fPKG", "'NP Title' length mismatching, only 9 characters are allowed, fPKG creation will be aborted.", ButtonEnum.Ok);
await ErrorMessageBox.ShowWindowDialogAsync(window);
return;
}
// Select output folder
var newOpenFolderDialog = new OpenFolderDialog() { Title = "Please select an output folder" };
var selectedFolder = await newOpenFolderDialog.ShowAsync(window);
string SelectedISOFile = SelectedPSPDiscTextBox.Text;
// Continue if selection is not empty
if (!string.IsNullOrWhiteSpace(selectedFolder))
{
string PKGOutputFolder = selectedFolder;
string CacheDirectory = wineDriveC + @"/Cache";
string GameCacheDirectory = wineDriveC + @"/Cache/PSPfPKG";
// Remove previous fPKG creation & re-create the PS1fPKG cache folder
if (Directory.Exists(GameCacheDirectory))
{
Directory.Delete(GameCacheDirectory, true);
}
if (File.Exists(Directory.GetCurrentDirectory() + @"/Cache/PSPfPKG.gp4"))
{
File.Delete(Directory.GetCurrentDirectory() + @"/Cache/PSPfPKG.gp4");
}
Directory.CreateDirectory(GameCacheDirectory);
// Copy the PSP emulator to the cache directory
CopyFilesRecursively(Directory.GetCurrentDirectory() + @"/Tools/PS4/emus/psphd", GameCacheDirectory);
// Copy the selected icon and background to the cache directory
if (!Directory.Exists(GameCacheDirectory + @"/sce_sys"))
{
Directory.CreateDirectory(GameCacheDirectory + @"/sce_sys");
}
if (!string.IsNullOrEmpty(SelectedPSPIconTextBox.Text))
{
File.Copy(SelectedPSPIconTextBox.Text, GameCacheDirectory + @"/sce_sys/icon0.png", true);
}
if (!string.IsNullOrEmpty(SelectedPSPBGImageTextBox.Text))
{
File.Copy(SelectedPSPBGImageTextBox.Text, GameCacheDirectory + @"/sce_sys/pic0.png", true);
}
// Get PSP EBOOT
if (!File.Exists(ExtractFileFromPSPISO(SelectedISOFile, @"\PSP_GAME\SYSDIR\EBOOT.BIN", CacheDirectory + @"/temp_eboot.bin")))
{
File.Copy(SelectedISOFile, GameCacheDirectory + @"/data/USER_L0.IMG", true);
var NoValidFileMessage = MessageBoxManager.GetMessageBoxStandard("PS fPKG Classics Builder", "Cannot read the EBOOT.BIN file from the ISO.\r\nWarning: This game may not work!", ButtonEnum.Ok);
await NoValidFileMessage.ShowWindowDialogAsync(window);
}
else
{
string PSPDecryptCMD = "\"" + Directory.GetCurrentDirectory() + @"/Tools/pspdecrypt" + "\"" + " \"" + CacheDirectory + @"/temp_eboot.bin" + "\"";
var EscapedArgs = PSPDecryptCMD.Replace("\"", "\\\"");
var PSPDecryptProcess = new Process();
PSPDecryptProcess.StartInfo.FileName = "/bin/bash";
PSPDecryptProcess.StartInfo.Arguments = $"-c \"{EscapedArgs}\"";
PSPDecryptProcess.StartInfo.CreateNoWindow = true;
PSPDecryptProcess.Start();
PSPDecryptProcess.WaitForExit();
if (!Directory.Exists(GameCacheDirectory + @"/data"))
{
Directory.CreateDirectory(GameCacheDirectory + @"/data");
}
File.Copy(SelectedISOFile, GameCacheDirectory + @"/data/USER_L0.IMG", true);
var NewFileInfo = new FileInfo(CacheDirectory + @"/temp_eboot.bin");
long FileLength = NewFileInfo.Length;
if (FileLength > 512320L)
{
FileLength = 512320L;
}
byte[] TempEBOOTByteArray = ReadUMDData(CacheDirectory + @"/temp_eboot.bin", 0L, (int)FileLength);
var OffsetValue = RuntimeHelpers.GetObjectValue(FindOffset(GameCacheDirectory + @"/data/USER_L0.IMG", TempEBOOTByteArray));
byte[] DecTempEBOOTByteArray = ReadUMDData(CacheDirectory + @"/temp_eboot.bin.dec", 0L, (int)NewFileInfo.Length);
WriteData(GameCacheDirectory + @"/data/USER_L0.IMG", Convert.ToInt64(OffsetValue), BitConverter.ToString(DecTempEBOOTByteArray));
}
// Remove temp files
if (File.Exists(CacheDirectory + @"/temp_eboot.bin"))
{
File.Delete(CacheDirectory + @"/temp_eboot.bin");
}
if (File.Exists(CacheDirectory + @"/temp_eboot.bin.dec"))
{
File.Delete(CacheDirectory + @"/temp_eboot.bin.dec");
}
// Copy the selected icon and background to the cache directory
if (!Directory.Exists(GameCacheDirectory + @"/sce_sys"))
{
Directory.CreateDirectory(GameCacheDirectory + @"/sce_sys");
}
if (!string.IsNullOrEmpty(SelectedPSPIconTextBox.Text))
{
var IconBytes = File.ReadAllBytes(SelectedPSPIconTextBox.Text);
var ConvertedIcon = Utils.ConvertTo24bppPNG(IconBytes, 512, 512);
ConvertedIcon.Save(GameCacheDirectory + @"/sce_sys/icon0.png");
//File.Copy(SelectedPSPIconTextBox.Text, GameCacheDirectory + @"/sce_sys/icon0.png", true);
}
if (!string.IsNullOrEmpty(SelectedPSPBGImageTextBox.Text))
{
var BGBytes = File.ReadAllBytes(SelectedPSPBGImageTextBox.Text);
var ConvertedBG = Utils.ConvertTo24bppPNG(BGBytes, 1920, 1080);
ConvertedBG.Save(GameCacheDirectory + @"/sce_sys/pic0.png");
//File.Copy(SelectedPSPBGImageTextBox.Text, GameCacheDirectory + @"/sce_sys/pic0.png", true);
}
// PSP Emulator configuration
string EmulatorConfig = string.Concat("--ps4-trophies=0\r\n--ps5-uds=0\r\n--trophies=0\r\n--image=\"data/USER_L0.IMG\"\r\n--antialias=SSAA4x\r\n--multisaves=true\r\n--notrophies=true\r\n\r\n");
if (File.Exists(GameCacheDirectory + "/config-title.txt"))
{
File.Delete(GameCacheDirectory + "/config-title.txt");
}
File.WriteAllText(GameCacheDirectory + "/config-title.txt", EmulatorConfig);
if (!string.IsNullOrEmpty(SelectedPSPConfigTextBox.Text))
{
File.AppendAllText(GameCacheDirectory + "/config-title.txt", File.ReadAllText(SelectedPSPConfigTextBox.Text));
}
// Create a new PARAM.SFO file
var NewPS4ParamSFO = new ParamSfo();
NewPS4ParamSFO.SetValue("APP_TYPE", SfoEntryType.Integer, "1", 4);
NewPS4ParamSFO.SetValue("APP_VER", SfoEntryType.Utf8, "01.00", 8);
NewPS4ParamSFO.SetValue("ATTRIBUTE", SfoEntryType.Integer, "0", 4);
NewPS4ParamSFO.SetValue("CATEGORY", SfoEntryType.Utf8, "gd", 4);
NewPS4ParamSFO.SetValue("CONTENT_ID", SfoEntryType.Utf8, "UP9000-" + PSPNPTitleTextBox.Text + "_00-" + PSPNPTitleTextBox.Text + "PSPFPKG", 48);
NewPS4ParamSFO.SetValue("DOWNLOAD_DATA_SIZE", SfoEntryType.Integer, "0", 4);
NewPS4ParamSFO.SetValue("FORMAT", SfoEntryType.Utf8, "obs", 4);
NewPS4ParamSFO.SetValue("PARENTAL_LEVEL", SfoEntryType.Integer, "5", 4);
NewPS4ParamSFO.SetValue("SYSTEM_VER", SfoEntryType.Integer, "0", 4);
NewPS4ParamSFO.SetValue("TITLE", SfoEntryType.Utf8, PSPTitleTextBox.Text, 128);
NewPS4ParamSFO.SetValue("TITLE_ID", SfoEntryType.Utf8, PSPNPTitleTextBox.Text, 12);
NewPS4ParamSFO.SetValue("VERSION", SfoEntryType.Utf8, "01.00", 8);
File.WriteAllBytes(GameCacheDirectory + @"/sce_sys/param.sfo", NewPS4ParamSFO.Serialize());
// Generate a GP4 project
string GenGP4CCMD = "wine \"c:\\PS4\\gengp4_patch.exe\" \"c:\\Cache\\PSPfPKG\"";
var EscapedArgs2 = GenGP4CCMD.Replace("\"", "\\\"");
var NewProcess = new Process();
NewProcess.StartInfo.FileName = "/bin/bash";
NewProcess.StartInfo.Arguments = $"-c \"{EscapedArgs2}\"";
NewProcess.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
NewProcess.StartInfo.CreateNoWindow = true;
NewProcess.Start();
NewProcess.WaitForExit();
// Modify the GP4 project
File.WriteAllText(CacheDirectory + "/PSPfPKG.gp4", File.ReadAllText(CacheDirectory + "/PSPfPKG.gp4").Replace("<?xml version=\"1.1\"", "<?xml version=\"1.0\""));
File.WriteAllText(CacheDirectory + "/PSPfPKG.gp4", File.ReadAllText(CacheDirectory + "/PSPfPKG.gp4").Replace("<scenarios default_id=\"1\">", "<scenarios default_id=\"0\">"));
var DebugMessageBox = MessageBoxManager.GetMessageBoxStandard("PS fPKG Classics Builder", "All files ready! \r\n fPKG can be build.", ButtonEnum.Ok);
await DebugMessageBox.ShowWindowDialogAsync(window);
// Create the fPKG
string PUBCMD = "wine \"c:\\PS4\\orbis-pub-cmd-3.38.exe\" img_create --oformat pkg --skip_digest --no_progress_bar \"c:\\Cache\\PSPfPKG.gp4\" \"c:\\fPKG\"";
EscapedArgs2 = PUBCMD.Replace("\"", "\\\"");
string PKGBuilderProcessOutput;
var PKGBuilderProcess = new Process();
PKGBuilderProcess.StartInfo.FileName = "/bin/bash";
PKGBuilderProcess.StartInfo.Arguments = $"-c \"{EscapedArgs2}\"";
PKGBuilderProcess.StartInfo.UseShellExecute = false;
PKGBuilderProcess.StartInfo.RedirectStandardOutput = true;
PKGBuilderProcess.StartInfo.CreateNoWindow = true;
PKGBuilderProcess.Start();
PKGBuilderProcess.WaitForExit();
// Read the process output
using (var NewStreamReader = PKGBuilderProcess.StandardOutput)
{
PKGBuilderProcessOutput = NewStreamReader.ReadToEnd();
}
if (PKGBuilderProcessOutput.Contains("Create image Process finished with warning"))
{
string PKGFileName = "UP9000-" + PSPNPTitleTextBox.Text + "_00-" + PSPNPTitleTextBox.Text + "PSPFPKG-A0100-V0100.pkg";
string PKGFilePath = wineDriveC + "/fPKG/" + PKGFileName;
if (File.Exists(PKGFilePath))
{
try
{
File.Move(PKGFilePath, PKGOutputFolder + "/" + PKGFileName);
}
catch (Exception error)
{
Console.WriteLine(error);
}
}
var PKGBuildMessageBox = MessageBoxManager.GetMessageBoxStandard("DEBUG", "fPKG created with success!", ButtonEnum.Ok);
await PKGBuildMessageBox.ShowWindowDialogAsync(window);
}
else
{
DebugMessageBox = MessageBoxManager.GetMessageBoxStandard("DEBUG", "Error creating fPKG", ButtonEnum.Ok);
await DebugMessageBox.ShowWindowDialogAsync(window);
}
}
}
public static bool FileExistInISO(string GameISOPath, string FileToSearch)
{
bool Exists = false;
try
{
using var NewFileStream = new FileStream(GameISOPath, FileMode.Open, FileAccess.Read);
var NewIso9660CDReader = new DiscUtils.Iso9660.CDReader(NewFileStream, true);
try
{
NewIso9660CDReader.OpenFile(FileToSearch, FileMode.Open);
Exists = true;
}
catch (Exception)
{
Exists = false;
}
}
catch (Exception)
{
Exists = false;
}
return Exists;
}
public static string ExtractFileFromPSPISO(string path, string fileName, string DestinationPath)
{
string OutputDestination = "";
string DesinationDirectoryName = Path.GetDirectoryName(DestinationPath) ?? "";
if (!string.IsNullOrEmpty(DestinationPath) && !Directory.Exists(DesinationDirectoryName))
{
Directory.CreateDirectory(DesinationDirectoryName);
}
try
{
using var NewFileStream = new FileStream(path, FileMode.Open, FileAccess.Read);
var NewIso9660CDReader = new DiscUtils.Iso9660.CDReader(NewFileStream, true);
try
{
var NewSparseStream = NewIso9660CDReader.OpenFile(fileName, FileMode.Open);
var OutputFileStream = new FileStream(DestinationPath, FileMode.Create);
NewSparseStream.CopyTo(OutputFileStream);
OutputFileStream.Close();
OutputDestination = DestinationPath;
}
catch (Exception)
{
OutputDestination = "";
}
}
catch (Exception)
{
OutputDestination = "";
}
return OutputDestination;
}
public static byte[] ReadUMDData(string DataFile, long Offset, int Lenght)
{
var NewByte = new byte[(Lenght - 1 + 1)];
using (var NewBinaryReader = new BinaryReader(File.Open(DataFile, FileMode.Open)))
{
long BaseStreamLenght = NewBinaryReader.BaseStream.Length;
int Num = 0;
NewBinaryReader.BaseStream.Seek(Offset, SeekOrigin.Begin);
while (Offset < BaseStreamLenght & Num < Lenght)
{
NewByte[Num] = NewBinaryReader.ReadByte();
Offset += 1L;
Num += 1;
}
}
return NewByte;
}
public static object FindOffset(string FileName, byte[] Query)
{
object ReturnLenght;
using (var NewBinaryReader = new BinaryReader(File.Open(FileName, FileMode.Open)))
{
double BaseStreamLength = NewBinaryReader.BaseStream.Length;
if (Query.Length <= BaseStreamLength)
{
byte[] NewByteArray = NewBinaryReader.ReadBytes(Query.Length);
bool Flag = false;
int NewQueryLenght = Query.Length - 1;
int WhileInt = 0;
while (WhileInt <= NewQueryLenght)
{
if (NewByteArray[WhileInt] == Query[WhileInt])
{
Flag = true;
WhileInt += 1;
}
else
{
Flag = false;
break;
}
}
if (!Flag)
{
double NewBaseStreamLength = BaseStreamLength - 1d;
double QueryLenght = Query.Length;
while (QueryLenght <= NewBaseStreamLength)
{
Array.Copy(NewByteArray, 1, NewByteArray, 0, NewByteArray.Length - 1);
NewByteArray[^1] = NewBinaryReader.ReadByte();
int length3 = Query.Length - 1;
int num3 = 0;
while (num3 <= length3)
{
if (NewByteArray[num3] == Query[num3])
{
Flag = true;
num3 += 1;
}
else
{
Flag = false;
break;
}
}
if (!Flag)
{
QueryLenght += 1d;
}
else
{
ReturnLenght = QueryLenght - (Query.Length - 1);
return ReturnLenght;
}
}
}
else
{
ReturnLenght = 0;
return ReturnLenght;
}
}
}
ReturnLenght = -1;
return ReturnLenght;
}
public static void WriteData(string FileToWrite, long Offset, string DataToWrite)
{
var NewFileStream = new FileStream(FileToWrite, FileMode.Open, FileAccess.Write, FileShare.Write);
string[] NewStringArray = DataToWrite.Split(['-']);
NewFileStream.Seek(Offset, SeekOrigin.Begin);
int DoInt = 0;
do
{
string str = NewStringArray[DoInt];
NewFileStream.WriteByte(Convert.ToByte(Convert.ToInt32(str, 16)));
DoInt += 1;
}
while (DoInt < NewStringArray.Length);
NewFileStream.Close();
}
#endregion
public async Task CheckWinePrefixAndSetup()
{
// Check if a wine prefix exists
if (!Directory.Exists(wineDriveC))
{
if (VisualRoot is not Window window)
return;
var WineNotInstalledMessage = MessageBoxManager.GetMessageBoxStandard("Wine installation not complete", "A wine prefix will be created, please close the Wine Configuration Tool when the initialization finished.", ButtonEnum.Ok);
await WineNotInstalledMessage.ShowWindowDialogAsync(window);
// Check if winetricks is updated if previously installed
using var BashProcess = new Process();
var WineCFG = "winecfg";
BashProcess.StartInfo.FileName = "/bin/bash";
BashProcess.StartInfo.Arguments = $"-c \"{WineCFG}\"";
BashProcess.StartInfo.RedirectStandardOutput = true;
BashProcess.StartInfo.RedirectStandardError = true;
BashProcess.StartInfo.UseShellExecute = false;
BashProcess.StartInfo.CreateNoWindow = false;
BashProcess.Start();
BashProcess.WaitForExit();
}
// Check if wine prefix is 64bit
if (!Directory.Exists(wineDriveC + "/windows/syswow64"))
{
if (VisualRoot is not Window window)
return;
var Wine64NotInstalledMessage = MessageBoxManager.GetMessageBoxStandard("Wine prefix mismatch", "Current wine prefix is 32bit only, please change to 64bit mode before continuing.", ButtonEnum.Ok);
await Wine64NotInstalledMessage.ShowWindowDialogAsync(window);
return;
}
// Check if PS4 tools exist in current wine prefix
if (!Directory.Exists(wineDriveC + "/PS4"))
{
// Copy PS4 tools to the wine C:\ drive
CopyFilesRecursively(Directory.GetCurrentDirectory() + @"/Tools/PS4", PS4ToolsPath);
}
// Create fPKG output folder if not exists in current wine prefix
if (!Directory.Exists(wineDriveC + "/fPKG"))
{
Directory.CreateDirectory(wineDriveC + "/fPKG");
}
// Check if winetricks is updated if previously installed
using var Bash = new Process();
var WinetricksCMD = $"winetricks -V";
Bash.StartInfo.FileName = "/bin/bash";
Bash.StartInfo.Arguments = $"-c \"{WinetricksCMD}\"";
Bash.StartInfo.RedirectStandardOutput = true;
Bash.StartInfo.RedirectStandardError = true;
Bash.StartInfo.UseShellExecute = false;
Bash.StartInfo.CreateNoWindow = false;
Bash.Start();
Bash.WaitForExit();
var UpdateRequired = false;
var OutputReader = Bash.StandardOutput;
string[] ProcessOutput = OutputReader.ReadToEnd().Split(["\r\n"], StringSplitOptions.RemoveEmptyEntries);
if (ProcessOutput.Length > 0)
{
foreach (var OutputLine in ProcessOutput)
{
if (OutputLine.Contains("sha256sum:"))
{
var currentWinetricksVersion = OutputLine.Split(["-"], StringSplitOptions.None)[0].Trim();
var buildYear = currentWinetricksVersion.Remove(4, 4);
Console.WriteLine(currentWinetricksVersion);
Console.WriteLine(buildYear);
if (int.TryParse(buildYear, out int x))
{
if (x < 2024)
{
UpdateRequired = true;
Console.WriteLine("Update required");
}
}
break;
}
}
}
if (UpdateRequired == true)
{
if (VisualRoot is not Window window)
return;
var WineNotInstalledMessage = MessageBoxManager.GetMessageBoxStandard("Winetricks Update Required", "Winetricks will be updated, please close the terminal window when the installation finished.", ButtonEnum.Ok);
await WineNotInstalledMessage.ShowWindowDialogAsync(window);
// Update winetricks
string WinetricksUpdateCMD = "gnome-terminal sudo winetricks --self-update";
var WinetricksProcess = new Process();
WinetricksProcess.StartInfo.FileName = "/bin/bash";
WinetricksProcess.StartInfo.Arguments = $"-c \"{WinetricksUpdateCMD}\"";
WinetricksProcess.StartInfo.UseShellExecute = false;
WinetricksProcess.StartInfo.CreateNoWindow = false;
WinetricksProcess.Start();
WinetricksProcess.WaitForExit();
}
// Setup required vcrun2008 in current wine prefix (skips if already installed)
string WinetricksInstallCMD = "winetricks vcrun2008";
var Winetricks = new Process();
Winetricks.StartInfo.FileName = "/bin/bash";
Winetricks.StartInfo.Arguments = $"-c \"{WinetricksInstallCMD}\"";
Winetricks.StartInfo.UseShellExecute = false;
Winetricks.StartInfo.RedirectStandardOutput = true;
Winetricks.StartInfo.CreateNoWindow = true;
Winetricks.Start();
Winetricks.WaitForExit();
}
private static void CopyFilesRecursively(string sourcePath, string targetPath)
{
foreach (string dirPath in Directory.GetDirectories(sourcePath, "*", SearchOption.AllDirectories))
{
Directory.CreateDirectory(dirPath.Replace(sourcePath, targetPath));
}
foreach (string newPath in Directory.GetFiles(sourcePath, "*.*", SearchOption.AllDirectories))
{
File.Copy(newPath, newPath.Replace(sourcePath, targetPath), true);
}
}
#region RegexStuff
[GeneratedRegex("[^a-zA-Z0-9]")]
private static partial Regex CRCRegex();
[GeneratedRegex(@"\((.*?)\)")]
private static partial Regex PSPTitleRegex1();
[GeneratedRegex(" {2,}")]
private static partial Regex PSPTitleRegex2();
#endregion
}
#pragma warning restore CS0618 // Type or member is obsolete
}