mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/PCK-Studio.git
synced 2026-05-22 18:35:30 +00:00
364 lines
14 KiB
C#
364 lines
14 KiB
C#
/* Copyright (c) 2023-present miku-666
|
|
* This software is provided 'as-is', without any express or implied
|
|
* warranty. In no event will the authors be held liable for any damages
|
|
* arising from the use of this software.
|
|
*
|
|
* Permission is granted to anyone to use this software for any purpose,
|
|
* including commercial applications, and to alter it and redistribute it
|
|
* freely, subject to the following restrictions:
|
|
*
|
|
* 1.The origin of this software must not be misrepresented; you must not
|
|
* claim that you wrote the original software. If you use this software
|
|
* in a product, an acknowledgment in the product documentation would be
|
|
* appreciated but is not required.
|
|
* 2. Altered source versions must be plainly marked as such, and must not be
|
|
* misrepresented as being the original software.
|
|
* 3. This notice may not be removed or altered from any source distribution.
|
|
**/
|
|
using System;
|
|
using System.IO;
|
|
using System.Xml;
|
|
using System.Linq;
|
|
using System.Diagnostics;
|
|
using System.Windows.Forms;
|
|
using PckStudio.Core.Misc;
|
|
using PckStudio.Properties;
|
|
using PckStudio.Core.Extensions;
|
|
|
|
namespace PckStudio.Forms.Features
|
|
{
|
|
/// <summary>
|
|
/// Wishlist:
|
|
/// - add the ability to save the currently open pck file to the desired folder destination.
|
|
/// (even if the pck file has not yet be saved to disk)
|
|
/// </summary>
|
|
public partial class CemuPanel : UserControl
|
|
{
|
|
private const string TitleId_EUR = "101d7500";
|
|
private const string TitleId_USA = "101d9d00";
|
|
private const string TitleId_JPN = "101dbe00";
|
|
|
|
public CemuPanel()
|
|
{
|
|
InitializeComponent();
|
|
var imgList = new ImageList();
|
|
imgList.ColorDepth = ColorDepth.Depth32Bit;
|
|
imgList.ImageSize = new System.Drawing.Size(28, 28);
|
|
imgList.Images.Add(Resources.SKIN_ICON);
|
|
imgList.Images.Add(Resources.TEXTURE_ICON);
|
|
DLCTreeView.ImageList = imgList;
|
|
if (!TryApplyPermanentCemuConfig() &&
|
|
MessageBox.Show(this, "Failed to get Cemu perma settings\nDo you want to open your local settings.xml file?",
|
|
"Cemu mlc path not found",
|
|
MessageBoxButtons.YesNo,
|
|
MessageBoxIcon.Warning) == DialogResult.Yes
|
|
)
|
|
{
|
|
|
|
OpenFileDialog fileDialog = new OpenFileDialog()
|
|
{
|
|
Filter = "Cemu Settings|settings.xml",
|
|
};
|
|
|
|
if (fileDialog.ShowDialog(this) == DialogResult.OK)
|
|
{
|
|
TryApplyCemuConfig(fileDialog.FileName);
|
|
}
|
|
}
|
|
}
|
|
|
|
private bool TryApplyCemuConfig(string settingsPath)
|
|
{
|
|
string cemuPath = Path.Combine(Path.GetDirectoryName(settingsPath), "Cemu.exe");
|
|
if (File.Exists(settingsPath) && File.Exists(cemuPath))
|
|
{
|
|
try
|
|
{
|
|
var xml = new XmlDocument();
|
|
xml.Load(settingsPath);
|
|
GameDirectoryTextBox.Text = xml.SelectSingleNode("content").SelectSingleNode("mlc_path").InnerText;
|
|
GameDirectoryTextBox.Enabled = false;
|
|
BrowseDirectoryBtn.Enabled = false;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Debug.WriteLine(ex, category: $"{nameof(CemuPanel)}:{nameof(TryApplyCemuConfig)}");
|
|
return false;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private bool TryApplyPermanentCemuConfig()
|
|
{
|
|
string path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Cemu");
|
|
string filepath = Path.Combine(path, "perm_setting.xml");
|
|
if (Directory.Exists(path) && File.Exists(filepath))
|
|
{
|
|
try
|
|
{
|
|
var xml = new XmlDocument();
|
|
using (var reader = new StreamReader(filepath))
|
|
{
|
|
reader.ReadLine();
|
|
xml.Load(reader);
|
|
}
|
|
XmlNode configNode = xml.SelectSingleNode("config");
|
|
XmlNode mlcpathNode = configNode.SelectSingleNode("MlcPath");
|
|
GameDirectoryTextBox.Text = mlcpathNode.InnerText;
|
|
GameDirectoryTextBox.Enabled = false;
|
|
BrowseDirectoryBtn.Enabled = false;
|
|
return true;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Debug.WriteLine(ex, category: $"{nameof(CemuPanel)}:{nameof(TryApplyPermanentCemuConfig)}");
|
|
return false;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private string GetSelectedRegionTitleId()
|
|
{
|
|
if (radioButtonEur.Checked)
|
|
{
|
|
return TitleId_EUR;
|
|
}
|
|
if (radioButtonUs.Checked)
|
|
{
|
|
return TitleId_USA;
|
|
}
|
|
if (radioButtonJap.Checked)
|
|
{
|
|
return TitleId_JPN;
|
|
}
|
|
throw new Exception("how did you get here ?");
|
|
}
|
|
|
|
private string GetGameContentPath(string region)
|
|
{
|
|
return $"{GameDirectoryTextBox.Text}/usr/title/0005000e/{region}/content";
|
|
}
|
|
|
|
private string GetGameContentPath()
|
|
{
|
|
string region = GetSelectedRegionTitleId();
|
|
return GetGameContentPath(region);
|
|
}
|
|
|
|
private string GetContentSubDirectory(params string[] subpaths)
|
|
{
|
|
return Path.Combine(GetGameContentPath(), Path.Combine(subpaths));
|
|
}
|
|
|
|
private void BrowseDirectoryBtn_Click(object sender, EventArgs e)
|
|
{
|
|
OpenFolderDialog openFolderDialog = new OpenFolderDialog
|
|
{
|
|
Title = "Select Cemu mlc01 Directory"
|
|
};
|
|
if (openFolderDialog.ShowDialog(Handle) == true && Directory.Exists(openFolderDialog.ResultPath))
|
|
{
|
|
GameDirectoryTextBox.Text = openFolderDialog.ResultPath;
|
|
}
|
|
}
|
|
|
|
private class DLCDirectoryInfo
|
|
{
|
|
private readonly bool _hasTexturePack;
|
|
private readonly string _basePckPath;
|
|
private readonly string _texturePackPath;
|
|
|
|
public bool HasTexturePack => _hasTexturePack;
|
|
public string PackPath => _basePckPath;
|
|
public string TexturePackPath => _texturePackPath;
|
|
|
|
public DLCDirectoryInfo(DirectoryInfo directory)
|
|
{
|
|
_basePckPath = directory.GetFiles().FirstOrDefault(f => f.Name.EndsWith(".pck")).FullName;
|
|
_ = _basePckPath ?? throw new NullReferenceException($"Could not find any '.pck' inside {directory.Name}");
|
|
if (TryGetDataDirectory(directory, out DirectoryInfo dataDir))
|
|
{
|
|
FileInfo tpFileInfo = dataDir.GetFiles().FirstOrDefault(f => !f.Name.Equals("audio.pck") && f.Name.EndsWith(".pck"));
|
|
_hasTexturePack = tpFileInfo is not null;
|
|
_texturePackPath = _hasTexturePack ? tpFileInfo.FullName : string.Empty;
|
|
}
|
|
}
|
|
|
|
public DLCDirectoryInfo(string path)
|
|
: this(new DirectoryInfo(path))
|
|
{
|
|
}
|
|
|
|
private bool TryGetDataDirectory(DirectoryInfo directory, out DirectoryInfo dataDirectory)
|
|
{
|
|
DirectoryInfo[] dirs = directory.GetDirectories("Data", SearchOption.TopDirectoryOnly);
|
|
dataDirectory = dirs.Length != 0 ? dirs[0] : null;
|
|
return dirs.Length != 0;
|
|
}
|
|
}
|
|
|
|
private void ListDLCs()
|
|
{
|
|
DLCTreeView.Nodes.Clear();
|
|
if (!IsValidInstallDirectory())
|
|
{
|
|
MessageBox.Show(this, "Please select a valid Game Directory!", "Invalid Directory Specified",
|
|
MessageBoxButtons.OK, MessageBoxIcon.Error);
|
|
return;
|
|
}
|
|
|
|
if (!IsValidGameDirectory())
|
|
{
|
|
MessageBox.Show(this, $"Could not find '{GetGameContentPath()}'!", "Not Found",
|
|
MessageBoxButtons.OK, MessageBoxIcon.Error);
|
|
return;
|
|
}
|
|
|
|
string dirPath = GetContentSubDirectory("WiiU", "DLC");
|
|
DirectoryInfo dlcDirectory = new DirectoryInfo(dirPath);
|
|
|
|
if (!dlcDirectory.Exists)
|
|
{
|
|
MessageBox.Show(this, $"'{dirPath}' does not exist!", "Not Found",
|
|
MessageBoxButtons.OK, MessageBoxIcon.Error);
|
|
return;
|
|
}
|
|
|
|
foreach (DirectoryInfo directoryInfo in dlcDirectory.GetDirectories())
|
|
{
|
|
if (directoryInfo.GetFileSystemInfos().Length != 0)
|
|
{
|
|
DLCDirectoryInfo dlcDirectoryInfo = new DLCDirectoryInfo(directoryInfo);
|
|
TreeNode node = DLCTreeView.Nodes.Add(directoryInfo.Name);
|
|
node.ImageIndex = dlcDirectoryInfo.HasTexturePack ? 1 : 0;
|
|
node.Tag = dlcDirectoryInfo;
|
|
}
|
|
}
|
|
}
|
|
|
|
private bool IsValidInstallDirectory()
|
|
{
|
|
return !string.IsNullOrWhiteSpace(GameDirectoryTextBox.Text) && Directory.Exists(GameDirectoryTextBox.Text);
|
|
}
|
|
|
|
private void radioButton_Click(object sender, EventArgs e)
|
|
{
|
|
ListDLCs();
|
|
}
|
|
|
|
private bool IsValidGameDirectory()
|
|
{
|
|
return IsValidInstallDirectory() && Directory.Exists(GetGameContentPath());
|
|
}
|
|
|
|
private void openSkinPackToolStripMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
if (DLCTreeView.SelectedNode?.Tag is DLCDirectoryInfo dlcDir)
|
|
{
|
|
Program.MainInstance.LoadPckFromFile(dlcDir.PackPath);
|
|
}
|
|
}
|
|
|
|
private void openTexturePackToolStripMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
if (DLCTreeView.SelectedNode?.Tag is DLCDirectoryInfo dlcDir && dlcDir.HasTexturePack)
|
|
{
|
|
Program.MainInstance.LoadPckFromFile(dlcDir.TexturePackPath);
|
|
}
|
|
}
|
|
|
|
private void DLCTreeView_AfterSelect(object sender, TreeViewEventArgs e)
|
|
{
|
|
openTexturePackToolStripMenuItem.Visible = e.Node.Tag is DLCDirectoryInfo dlcDir && dlcDir.HasTexturePack;
|
|
}
|
|
|
|
private void addCustomPckToolStripMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
TextPrompt prompt = new TextPrompt();
|
|
prompt.OKButtonText = "OK";
|
|
prompt.LabelText = "Folder:";
|
|
|
|
if (prompt.ShowDialog(this) != DialogResult.OK)
|
|
return;
|
|
|
|
if (prompt.NewText.ContainsAny(Path.GetInvalidPathChars()))
|
|
{
|
|
MessageBox.Show(this, "Invalid Folder name entered!", "Invalid Folder Name", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
|
return;
|
|
}
|
|
|
|
string directoryPath = GetContentSubDirectory("WiiU", "DLC", prompt.NewText);
|
|
|
|
if (Directory.Exists(directoryPath))
|
|
{
|
|
MessageBox.Show(this, "A Folder with the same name already exists!", "Folder Name taken", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
|
return;
|
|
}
|
|
Directory.CreateDirectory(directoryPath);
|
|
|
|
using OpenFileDialog fileDialog = new OpenFileDialog
|
|
{
|
|
Filter = "PCK (Minecraft Console Package)|*.pck"
|
|
};
|
|
if (fileDialog.ShowDialog(this) == DialogResult.OK)
|
|
{
|
|
File.Copy(fileDialog.FileName, Path.Combine(directoryPath, fileDialog.SafeFileName));
|
|
}
|
|
}
|
|
|
|
private void removePckToolStripMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
string pckName = DLCTreeView.SelectedNode.Text;
|
|
DialogResult result = MessageBox.Show(this, $"Are you sure you want to permanently delete '{pckName}'?", "Hold up!", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);
|
|
if (result == DialogResult.Yes)
|
|
{
|
|
string directoryPath = GetContentSubDirectory("WiiU", "DLC", pckName);
|
|
Directory.Delete(directoryPath, recursive: true);
|
|
DLCTreeView.SelectedNode.Remove();
|
|
}
|
|
}
|
|
|
|
private void DLCTreeView_NodeMouseDoubleClick(object sender, TreeNodeMouseClickEventArgs e)
|
|
{
|
|
openSkinPackToolStripMenuItem_Click(sender, e);
|
|
}
|
|
|
|
private void GameDirectoryTextBox_TextChanged(object sender, EventArgs e)
|
|
{
|
|
if (IsValidInstallDirectory())
|
|
{
|
|
radioButtonEur.Enabled = Directory.Exists(GetGameContentPath(TitleId_EUR));
|
|
radioButtonUs.Enabled = Directory.Exists(GetGameContentPath(TitleId_USA));
|
|
radioButtonJap.Enabled = Directory.Exists(GetGameContentPath(TitleId_JPN));
|
|
}
|
|
ListDLCs();
|
|
}
|
|
|
|
private void DLCTreeView_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
|
|
{
|
|
if (e.KeyCode == Keys.Enter && DLCTreeView.SelectedNode is not null)
|
|
{
|
|
openSkinPackToolStripMenuItem_Click(sender, EventArgs.Empty);
|
|
}
|
|
base.OnPreviewKeyDown(e);
|
|
}
|
|
|
|
private void DLCTreeView_KeyPress(object sender, KeyPressEventArgs e)
|
|
{
|
|
e.Handled = true;
|
|
}
|
|
|
|
private void openToolStripMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
Process.Start(GetContentSubDirectory("WiiU", "DLC"));
|
|
}
|
|
|
|
private void copyToolStripMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
Clipboard.SetText(GameDirectoryTextBox.Text);
|
|
}
|
|
}
|
|
}
|