mirror of
https://github.com/kwsch/pkNX.git
synced 2026-08-25 11:54:26 -05:00
Temp (don't push)
This commit is contained in:
@@ -15,6 +15,9 @@ public PhysicalFileSystem(string physicalRoot)
|
||||
if (!physicalRoot.EndsWith(Path.DirectorySeparatorChar))
|
||||
physicalRoot += Path.DirectorySeparatorChar;
|
||||
PhysicalRoot = physicalRoot;
|
||||
|
||||
if (!Directory.Exists(PhysicalRoot))
|
||||
throw new ArgumentException("The specified path does not exist.", nameof(physicalRoot));
|
||||
}
|
||||
|
||||
public string GetPhysicalPath(FileSystemPath path)
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.Contracts;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace pkNX.Containers.VFS;
|
||||
|
||||
@@ -59,7 +60,7 @@ private FileSystemPath(string path)
|
||||
return Parse(path);
|
||||
}
|
||||
|
||||
public static implicit operator string(FileSystemPath path)
|
||||
public static explicit operator string(FileSystemPath path)
|
||||
{
|
||||
return path.ToString();
|
||||
}
|
||||
@@ -80,6 +81,21 @@ public static FileSystemPath Parse(string s)
|
||||
return new(s);
|
||||
}
|
||||
|
||||
public static FileSystemPath operator +(FileSystemPath path, string strPathToAppend)
|
||||
{
|
||||
return path.AppendPath(strPathToAppend);
|
||||
}
|
||||
|
||||
public static FileSystemPath operator +(FileSystemPath path, FileSystemPath pathToAppend)
|
||||
{
|
||||
return path.AppendPath(pathToAppend);
|
||||
}
|
||||
|
||||
public static string operator +(string path, FileSystemPath pathToAppend)
|
||||
{
|
||||
return path + (string)pathToAppend;
|
||||
}
|
||||
|
||||
[Pure]
|
||||
public FileSystemPath AppendPath(string strPath)
|
||||
{
|
||||
@@ -159,9 +175,29 @@ public string GetExtension()
|
||||
{
|
||||
if (!IsFile)
|
||||
throw new ArgumentException("The specified FileSystemPath is not a file.");
|
||||
string name = EntityName;
|
||||
int extensionIndex = name.LastIndexOf('.');
|
||||
return extensionIndex <= 0 ? string.Empty : name[extensionIndex..];
|
||||
|
||||
int lastPeriod = EntityName.LastIndexOf('.');
|
||||
return EntityName[(lastPeriod + 1)..];
|
||||
}
|
||||
|
||||
[Pure]
|
||||
public string GetFileNameWithoutExtension()
|
||||
{
|
||||
if (!IsFile)
|
||||
throw new ArgumentException("The specified FileSystemPath is not a file.");
|
||||
|
||||
int lastPeriod = EntityName.LastIndexOf('.');
|
||||
return EntityName[..lastPeriod];
|
||||
}
|
||||
|
||||
[Pure]
|
||||
public (string, string) GetFileNameAndExtension()
|
||||
{
|
||||
if (!IsFile)
|
||||
throw new ArgumentException("The specified FileSystemPath is not a file.");
|
||||
|
||||
int lastPeriod = EntityName.LastIndexOf('.');
|
||||
return (EntityName[..lastPeriod], EntityName[(lastPeriod + 1)..]);
|
||||
}
|
||||
|
||||
[Pure]
|
||||
@@ -169,6 +205,7 @@ public FileSystemPath ChangeExtension(string extension)
|
||||
{
|
||||
if (!IsFile)
|
||||
throw new ArgumentException("The specified FileSystemPath is not a file.");
|
||||
|
||||
string name = EntityName;
|
||||
int extensionIndex = name.LastIndexOf('.');
|
||||
if (extensionIndex < 0)
|
||||
|
||||
@@ -8,6 +8,8 @@ namespace pkNX.Containers.VFS;
|
||||
public string Name => Path.EntityName;
|
||||
public VirtualDirectory ParentDirectory => Create(FileSystem, Path.ParentPath);
|
||||
|
||||
public override string ToString() => Path.ToString();
|
||||
|
||||
public void CopyTo(VirtualDirectory destination)
|
||||
{
|
||||
FileSystem.Copy(Path, destination.FileSystem, destination.Path.AppendDirectory(Name));
|
||||
|
||||
@@ -8,23 +8,11 @@ namespace pkNX.Containers.VFS;
|
||||
public string Name => Path.EntityName;
|
||||
public VirtualDirectory ParentDirectory => VirtualDirectory.Create(FileSystem, Path.ParentPath);
|
||||
|
||||
public (string, string) GetFileNameAndExtension()
|
||||
{
|
||||
int lastPeriod = Name.LastIndexOf('.');
|
||||
return (Name[..lastPeriod], Name[(lastPeriod + 1)..]);
|
||||
}
|
||||
public override string ToString() => Path.ToString();
|
||||
|
||||
public string GetFileNameWithoutExtension()
|
||||
{
|
||||
int lastPeriod = Name.LastIndexOf('.');
|
||||
return Name[..lastPeriod];
|
||||
}
|
||||
|
||||
public string GetExtension()
|
||||
{
|
||||
int lastPeriod = Name.LastIndexOf('.');
|
||||
return Name[(lastPeriod + 1)..];
|
||||
}
|
||||
public (string, string) GetFileNameAndExtension() => Path.GetFileNameAndExtension();
|
||||
public string GetFileNameWithoutExtension() => Path.GetFileNameWithoutExtension();
|
||||
public string GetExtension() => Path.GetExtension();
|
||||
|
||||
public Stream Open(FileMode mode = FileMode.Open, FileAccess access = FileAccess.Read)
|
||||
{
|
||||
|
||||
@@ -1,53 +1,56 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace pkNX.Containers.VFS;
|
||||
|
||||
public record MountPoint
|
||||
public record MountPoint : IComparable<MountPoint>
|
||||
{
|
||||
public FileSystemPath MountPath { get; }
|
||||
public IFileSystem FileSystem { get; }
|
||||
|
||||
public FileSystemPath AddMountPoint(FileSystemPath path)
|
||||
{
|
||||
return MountPath.AppendPath(path);
|
||||
}
|
||||
|
||||
public FileSystemPath RemoveMountPoint(FileSystemPath path)
|
||||
{
|
||||
return path.IsRoot ? path : path.MakeRelativeTo(MountPath);
|
||||
}
|
||||
|
||||
public MountPoint(FileSystemPath mountPath, IFileSystem fileSystem)
|
||||
{
|
||||
MountPath = mountPath;
|
||||
FileSystem = fileSystem.AsRelativeFileSystem(RemoveMountPoint, AddMountPoint);
|
||||
FileSystem = fileSystem.AsRelativeFileSystem(
|
||||
path => path.IsRoot ? path : path.MakeRelativeTo(MountPath),
|
||||
path => MountPath.AppendPath(path)
|
||||
);
|
||||
}
|
||||
|
||||
public int CompareTo(MountPoint? other)
|
||||
{
|
||||
if (other == null)
|
||||
return 1;
|
||||
|
||||
return MountPath.CompareTo(other.MountPath);
|
||||
}
|
||||
}
|
||||
|
||||
public class VirtualFileSystem : IFileSystem
|
||||
{
|
||||
public static VirtualFileSystem Current { get; private set; } = null!;
|
||||
public bool IsReadOnly => _mounts.All(x => x.FileSystem.IsReadOnly);
|
||||
|
||||
public SortedSet<MountPoint> Mounts { get; }
|
||||
public bool IsReadOnly => Mounts.All(x => x.FileSystem.IsReadOnly);
|
||||
private readonly SortedSet<MountPoint> _mounts;
|
||||
|
||||
public VirtualFileSystem(IEnumerable<MountPoint> mounts)
|
||||
public VirtualFileSystem(IEnumerable<MountPoint> mounts) :
|
||||
this(mounts.ToArray())
|
||||
{
|
||||
Mounts = new SortedSet<MountPoint>(mounts);
|
||||
}
|
||||
|
||||
public VirtualFileSystem(params MountPoint[] mounts)
|
||||
{
|
||||
_mounts = new(mounts);
|
||||
Current = this;
|
||||
}
|
||||
|
||||
public VirtualFileSystem(params MountPoint[] mounts) :
|
||||
this(mounts.AsEnumerable())
|
||||
{ }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
foreach (var fs in Mounts.Select(x => x.FileSystem))
|
||||
foreach (var fs in _mounts.Select(x => x.FileSystem))
|
||||
fs.Dispose();
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
@@ -55,7 +58,22 @@ public void Dispose()
|
||||
|
||||
protected MountPoint GetMountPoint(FileSystemPath path)
|
||||
{
|
||||
return Mounts.First(mount => mount.MountPath == path || mount.MountPath.IsParentOf(path));
|
||||
return _mounts.First(mount => mount.MountPath == path || mount.MountPath.IsParentOf(path));
|
||||
}
|
||||
|
||||
public bool IsMounted(FileSystemPath mountPath)
|
||||
{
|
||||
return _mounts.Any(mount => mount.MountPath == mountPath || mount.MountPath.IsParentOf(mountPath));
|
||||
}
|
||||
|
||||
public void Mount(MountPoint mountPoint)
|
||||
{
|
||||
_mounts.Add(mountPoint);
|
||||
}
|
||||
|
||||
public void UnMount(MountPoint mountPoint)
|
||||
{
|
||||
_mounts.Remove(mountPoint);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
|
||||
@@ -11,9 +11,16 @@ namespace pkNX.Game;
|
||||
|
||||
public static class GamePath
|
||||
{
|
||||
public static readonly GameVersion[] SupportedGames = { GameVersion.SW, GameVersion.SH, GameVersion.PLA, GameVersion.SL, GameVersion.VL };
|
||||
|
||||
private static GameVersion CurrentGame { get; set; }
|
||||
private static int CurrentLanguage { get; set; }
|
||||
|
||||
public static void InitializeWorkspace()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public static void Initialize(GameVersion game, int language)
|
||||
{
|
||||
CurrentGame = game;
|
||||
@@ -30,6 +37,11 @@ public static FileSystemPath GetDirectoryPath(GameFile file, int language)
|
||||
return GetDirectoryPath(file, CurrentGame, language);
|
||||
}
|
||||
|
||||
public static FileSystemPath GetDirectoryPath(GameFile file, GameVersion game)
|
||||
{
|
||||
return GetDirectoryPath(file, game, CurrentLanguage);
|
||||
}
|
||||
|
||||
public static FileSystemPath GetDirectoryPath(GameFile file, GameVersion game, int language)
|
||||
{
|
||||
if (file is GameFile.GameText or GameFile.StoryText)
|
||||
@@ -38,8 +50,12 @@ public static FileSystemPath GetDirectoryPath(GameFile file, GameVersion game, i
|
||||
return game switch
|
||||
{
|
||||
GameVersion.GG => GetDirectoryPath_GG(file),
|
||||
GameVersion.SW => GetDirectoryPath_SWSH(file),
|
||||
GameVersion.SH => GetDirectoryPath_SWSH(file),
|
||||
GameVersion.SWSH => GetDirectoryPath_SWSH(file),
|
||||
GameVersion.PLA => GetDirectoryPath_PLA(file),
|
||||
GameVersion.SL => GetDirectoryPath_SV(file),
|
||||
GameVersion.VL => GetDirectoryPath_SV(file),
|
||||
GameVersion.SV => GetDirectoryPath_SV(file),
|
||||
|
||||
_ => throw new NotSupportedException($"The selected game ({game}) is currently not mapped")
|
||||
@@ -89,6 +105,8 @@ private static FileSystemPath GetDirectoryPath_SWSH(GameFile file)
|
||||
GameFile.StoryText8 => "/romfs/bin/message/Simp_Chinese/script/",
|
||||
GameFile.StoryText9 => "/romfs/bin/message/Trad_Chinese/script/",
|
||||
|
||||
GameFile.PokemonArchiveFolder => "/romfs/bin/archive/pokemon/",
|
||||
|
||||
_ => throw new NotSupportedException($"The selected file ({file}) is currently not mapped")
|
||||
};
|
||||
|
||||
|
||||
@@ -21,8 +21,6 @@ public class GameManagerPLA : GameManager
|
||||
/// </summary>
|
||||
public GameData8a Data { get; protected set; } = null!;
|
||||
|
||||
public VirtualFileSystem VFS { get; private set; } = null!;
|
||||
|
||||
protected override void SetMitm()
|
||||
{
|
||||
var basePath = Path.GetDirectoryName(ROM.RomFS);
|
||||
@@ -32,12 +30,6 @@ protected override void SetMitm()
|
||||
var tid = ROM.ExeFS != null ? TitleID : "arceus";
|
||||
var redirect = Path.Combine(basePath, tid);
|
||||
FileMitm.SetRedirect(basePath, redirect);
|
||||
|
||||
var cleanRomFS = new PhysicalFileSystem(basePath + "/romfs/").AsReadOnlyFileSystem();
|
||||
var moddedRomFS = new PhysicalFileSystem(redirect + "/romfs/");
|
||||
|
||||
var layeredFS = new LayeredFileSystem(moddedRomFS, cleanRomFS);
|
||||
VFS = new VirtualFileSystem(new MountPoint("/romfs/", layeredFS));
|
||||
}
|
||||
|
||||
public override void Initialize()
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.Contracts;
|
||||
using System.Linq;
|
||||
|
||||
namespace pkNX.Structures;
|
||||
@@ -199,16 +200,16 @@ internal static T[] ConcatAll<T>(T[] arr1, T[] arr2, ReadOnlySpan<T> arr3)
|
||||
|
||||
public static class ArrayUtilsExt
|
||||
{
|
||||
public static TSource[] Append<TSource>(this TSource[] first, TSource second, params TSource[] third)
|
||||
[Pure]
|
||||
public static TSource[] Concat<TSource>(this TSource[] src, params TSource[] toAdd)
|
||||
{
|
||||
return ArrayUtil.ConcatAll(first, new[] { second }, third);
|
||||
return ArrayUtil.ConcatAll(src, toAdd);
|
||||
}
|
||||
|
||||
public static TSource[] Remove<TSource>(this TSource[] first, TSource toRemove)
|
||||
[Pure]
|
||||
public static TSource[] Remove<TSource>(this TSource[] src, params TSource[] toRemove)
|
||||
{
|
||||
var list = first.ToList();
|
||||
list.Remove(toRemove);
|
||||
return list.ToArray();
|
||||
return src.Except(toRemove).ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
using pkNX.Containers.VFS;
|
||||
|
||||
namespace pkNX.Structures;
|
||||
|
||||
/// <summary>
|
||||
@@ -512,3 +514,39 @@ public enum GameVersion
|
||||
Stadium2,
|
||||
#endregion
|
||||
}
|
||||
|
||||
|
||||
public static class GameVersionExt
|
||||
{
|
||||
public static string GetTitleID(this GameVersion game) => game switch
|
||||
{
|
||||
GameVersion.PLA => "01001F5010DFA000",
|
||||
GameVersion.SW => "0100ABF008968000",
|
||||
GameVersion.SH => "01008DB008C2C000",
|
||||
GameVersion.SL => "0100A3D008C5C000",
|
||||
GameVersion.VL => "01008F6008C5E000",
|
||||
_ => throw new System.NotImplementedException(),
|
||||
};
|
||||
|
||||
public static string GetTitleName(this GameVersion game) => game switch
|
||||
{
|
||||
GameVersion.PLA => "Pokémon Legends Arceus",
|
||||
GameVersion.SW => "Pokémon Sword",
|
||||
GameVersion.SH => "Pokémon Shield",
|
||||
GameVersion.SL => "Pokémon Scarlet",
|
||||
GameVersion.VL => "Pokémon Violet",
|
||||
_ => throw new System.NotImplementedException(),
|
||||
};
|
||||
|
||||
public static string ToLowerString(this GameVersion game) => game.ToString().ToLowerInvariant();
|
||||
public static FileSystemPath ToMountPath(this GameVersion game) => $"/{game.ToString().ToLowerInvariant()}/";
|
||||
}
|
||||
|
||||
public static class VFSExt
|
||||
{
|
||||
public static bool IsGameLoaded(this VirtualFileSystem vfs, GameVersion game)
|
||||
{
|
||||
var gamePath = game.ToMountPath() + "romfs/";
|
||||
return vfs.IsMounted(gamePath);
|
||||
}
|
||||
}
|
||||
|
||||
32
pkNX.WinForms/Controls/Arceus/ItemDrop.xaml
Normal file
32
pkNX.WinForms/Controls/Arceus/ItemDrop.xaml
Normal file
@@ -0,0 +1,32 @@
|
||||
<UserControl x:Class="pkNX.WinForms.Controls.ItemDrop"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:pkNX.WinForms"
|
||||
mc:Ignorable="d"
|
||||
d:DesignWidth="343">
|
||||
<GroupBox Header="Field Drops:" Margin="3">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="38"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Label Grid.Column="0" Grid.Row="0" Content="Regular Item:" HorizontalAlignment="Right"/>
|
||||
<Label Grid.Column="0" Grid.Row="1" Content="Rare Item:" HorizontalAlignment="Right"/>
|
||||
<ComboBox Grid.Column="1" Grid.Row="0" Margin="3" ItemsSource="{Binding Source={x:Static local:UIStaticSources.ItemsList}}" />
|
||||
<ComboBox Grid.Column="1" Grid.Row="1" Margin="3" ItemsSource="{Binding Source={x:Static local:UIStaticSources.ItemsList}}" />
|
||||
<local:NumericTextBox Grid.Column="2" Grid.Row="0" Margin="3" Value="50" MaxValue="100"/>
|
||||
<local:NumericTextBox Grid.Column="2" Grid.Row="1" Margin="3" Value="50" MaxValue="100"/>
|
||||
<Label Grid.Column="3" Grid.Row="0" Content="%"/>
|
||||
<Label Grid.Column="3" Grid.Row="1" Content="%"/>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
</UserControl>
|
||||
28
pkNX.WinForms/Controls/Arceus/ItemDrop.xaml.cs
Normal file
28
pkNX.WinForms/Controls/Arceus/ItemDrop.xaml.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace pkNX.WinForms.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for ItemDrop.xaml
|
||||
/// </summary>
|
||||
public partial class ItemDrop : UserControl
|
||||
{
|
||||
public ItemDrop()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@
|
||||
mc:Ignorable="d"
|
||||
x:Name="Root"
|
||||
d:Background="{StaticResource DockWindow.Background}"
|
||||
d:DesignHeight="74" d:DesignWidth="692">
|
||||
d:DesignWidth="692">
|
||||
<UserControl.Resources>
|
||||
<local:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter" />
|
||||
</UserControl.Resources>
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Windows;
|
||||
using static System.Windows.Forms.VisualStyles.VisualStyleElement;
|
||||
|
||||
namespace pkNX.WinForms;
|
||||
|
||||
|
||||
15
pkNX.WinForms/Controls/LabeledControl.cs
Normal file
15
pkNX.WinForms/Controls/LabeledControl.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace pkNX.WinForms;
|
||||
|
||||
public class LabeledControl : ContentControl
|
||||
{
|
||||
public static readonly DependencyProperty LabelProperty = DependencyProperty.Register(nameof(Label), typeof(string), typeof(LabeledControl), new PropertyMetadata("Label:"));
|
||||
public string Label
|
||||
{
|
||||
get { return (string)GetValue(LabelProperty); }
|
||||
set { SetValue(LabelProperty, value); }
|
||||
}
|
||||
}
|
||||
19
pkNX.WinForms/Controls/PathSelector.xaml
Normal file
19
pkNX.WinForms/Controls/PathSelector.xaml
Normal file
@@ -0,0 +1,19 @@
|
||||
<UserControl x:Class="pkNX.WinForms.PathSelector"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:pkNX.WinForms"
|
||||
x:Name="Root"
|
||||
mc:Ignorable="d" d:DesignWidth="500">
|
||||
<Grid Height="27">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBox Grid.Column="0" Text="{Binding Path, ElementName=Root}" Margin="3" IsReadOnly="{Binding IsPathReadOnly, ElementName=Root}" TextChanged="TextBox_TextChanged" />
|
||||
<Button Grid.Column="1" Margin="3" Padding="3" Width="32" Click="B_PathSelect_Click">
|
||||
<local:IconImage Icon="FolderOpen" IconFont="Solid" Height="14" />
|
||||
</Button>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
68
pkNX.WinForms/Controls/PathSelector.xaml.cs
Normal file
68
pkNX.WinForms/Controls/PathSelector.xaml.cs
Normal file
@@ -0,0 +1,68 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace pkNX.WinForms
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for PathSelector.xaml
|
||||
/// </summary>
|
||||
public partial class PathSelector : UserControl
|
||||
{
|
||||
public static readonly DependencyProperty PathProperty = DependencyProperty.Register(nameof(Path), typeof(string), typeof(PathSelector), new FrameworkPropertyMetadata(string.Empty, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
|
||||
public static readonly DependencyProperty IsPathReadOnlyProperty = DependencyProperty.Register(nameof(IsPathReadOnly), typeof(bool), typeof(PathSelector), new PropertyMetadata(false));
|
||||
public static readonly DependencyProperty FolderSelectDescriptionProperty = DependencyProperty.Register(nameof(FolderSelectDescription), typeof(string), typeof(PathSelector), new PropertyMetadata(null));
|
||||
|
||||
public string Path
|
||||
{
|
||||
get { return (string)GetValue(PathProperty); }
|
||||
set { SetValue(PathProperty, value); }
|
||||
}
|
||||
|
||||
public bool IsPathReadOnly
|
||||
{
|
||||
get { return (bool)GetValue(IsPathReadOnlyProperty); }
|
||||
set { SetValue(IsPathReadOnlyProperty, value); }
|
||||
}
|
||||
|
||||
public string FolderSelectDescription
|
||||
{
|
||||
get { return (string)GetValue(FolderSelectDescriptionProperty); }
|
||||
set { SetValue(FolderSelectDescriptionProperty, value); }
|
||||
}
|
||||
|
||||
public event TextChangedEventHandler? PathChanged;
|
||||
|
||||
public PathSelector()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void B_PathSelect_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
using System.Windows.Forms.FolderBrowserDialog fbd = new();
|
||||
fbd.Description = FolderSelectDescription;
|
||||
fbd.UseDescriptionForTitle = true;
|
||||
fbd.ShowNewFolderButton = false;
|
||||
|
||||
if (fbd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
|
||||
Path = fbd.SelectedPath;
|
||||
}
|
||||
|
||||
private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
|
||||
{
|
||||
PathChanged?.Invoke(sender, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -749,8 +749,8 @@ public void EditPokedexRankTable()
|
||||
[EditorCallable()]
|
||||
public void ModelConverter()
|
||||
{
|
||||
using var form = new ModelConverter(ROM);
|
||||
form.ShowDialog();
|
||||
var form = new ModelEditor();
|
||||
form.Show();
|
||||
}
|
||||
|
||||
[EditorCallable()]
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Intrinsics.Arm;
|
||||
using System.Windows.Controls;
|
||||
using pkNX.Containers.VFS;
|
||||
using pkNX.Game;
|
||||
using pkNX.Structures;
|
||||
|
||||
@@ -16,6 +18,7 @@ public abstract class EditorBase
|
||||
public GameVersion Game => ROM.Game;
|
||||
public int Language { get => ROM.Language; set => ROM.Language = value; }
|
||||
public string? Location { get; private set; }
|
||||
public VirtualFileSystem VFS { get; private set; } = null!;
|
||||
|
||||
private const string prefix = "Edit";
|
||||
private readonly MethodInfo[] editorMethods;
|
||||
@@ -36,11 +39,55 @@ protected EditorBase()
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
SetupVFS();
|
||||
GamePath.Initialize(ROM.Game, ROM.Language);
|
||||
ROM.Initialize();
|
||||
UIStaticSources.SetupForGame(ROM);
|
||||
}
|
||||
|
||||
public void SetupVFS()
|
||||
{
|
||||
var settings = ProgramSettings.LoadSettings();
|
||||
|
||||
var mounts = new List<MountPoint>();
|
||||
|
||||
foreach (var game in settings.GameConfigs)
|
||||
{
|
||||
if (!game.IsValid)
|
||||
continue;
|
||||
|
||||
// Map romfs to the game mount path (e.g. /pla/romfs/game/files/)
|
||||
string exportPath = Path.Combine(game.ExportPath, "romfs");
|
||||
if (!Directory.Exists(exportPath))
|
||||
Directory.CreateDirectory(exportPath);
|
||||
|
||||
if (!Directory.Exists(game.RomFSPath))
|
||||
throw new DirectoryNotFoundException($"The specified romfs path for {game.Game} does not exist.");
|
||||
|
||||
var cleanRomFS = new PhysicalFileSystem(game.RomFSPath).AsReadOnlyFileSystem();
|
||||
var moddedRomFS = new PhysicalFileSystem(exportPath);
|
||||
var layeredRomFS = new LayeredFileSystem(moddedRomFS, cleanRomFS);
|
||||
|
||||
mounts.Add(new MountPoint($"/{game.Game.ToLowerString()}/romfs/", layeredRomFS));
|
||||
// Map romfs (without game title) only to the currently selected game
|
||||
if (game.Game == settings.GameOverride)
|
||||
mounts.Add(new MountPoint("/romfs/", layeredRomFS));
|
||||
|
||||
if (!Directory.Exists(game.ExeFSPath))
|
||||
continue;
|
||||
|
||||
// Currently we don't support modding exefs, so just map the (read-only) clean exefs
|
||||
var cleanExeFS = new PhysicalFileSystem(game.ExeFSPath).AsReadOnlyFileSystem();
|
||||
mounts.Add(new MountPoint($"/{game.Game.ToLowerString()}/exefs/", cleanExeFS));
|
||||
|
||||
// Map exefs (without game title) only to the currently selected game
|
||||
if (game.Game == settings.GameOverride)
|
||||
mounts.Add(new MountPoint("/exefs/", cleanExeFS));
|
||||
}
|
||||
|
||||
VFS = new VirtualFileSystem(mounts);
|
||||
}
|
||||
|
||||
public int CountControlsForCategory(EditorCategory category) => editorAttributes.Count(a => a.Category == category);
|
||||
|
||||
public IEnumerable<EditorButtonData> GetControls(EditorCategory category = EditorCategory.None, bool displayAdvanced = false)
|
||||
|
||||
@@ -1,18 +1,141 @@
|
||||
using pkNX.Structures;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace pkNX.WinForms;
|
||||
|
||||
public class GameConfig : INotifyPropertyChanged
|
||||
{
|
||||
private string? _workspacePath;
|
||||
|
||||
public GameVersion Game { get; init; } = GameVersion.Invalid;
|
||||
public string? WorkspacePath
|
||||
{
|
||||
get => _workspacePath;
|
||||
set
|
||||
{
|
||||
_workspacePath = value;
|
||||
OnPropertyChanged();
|
||||
OnPropertyChanged(nameof(RomFSPath));
|
||||
OnPropertyChanged(nameof(ExeFSPath));
|
||||
OnPropertyChanged(nameof(ExportPath));
|
||||
}
|
||||
}
|
||||
public string? RomFSPathOverride { get; set; }
|
||||
public string? ExeFSPathOverride { get; set; }
|
||||
public string? ExportPathOverride { get; set; }
|
||||
|
||||
public string GameTitle => Game.GetTitleName();
|
||||
public bool IsValid => Game != GameVersion.Invalid && !string.IsNullOrWhiteSpace(WorkspacePath);
|
||||
public bool OverrideDefaultPaths { get; set; }
|
||||
|
||||
private string GetOverridePathOrDefault(string? overridePath, string defaultFolder)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(WorkspacePath))
|
||||
return string.Empty;
|
||||
|
||||
if (OverrideDefaultPaths && !string.IsNullOrWhiteSpace(overridePath))
|
||||
return overridePath;
|
||||
|
||||
return Path.Combine(WorkspacePath, defaultFolder);
|
||||
}
|
||||
|
||||
public string RomFSPath
|
||||
{
|
||||
get => GetOverridePathOrDefault(RomFSPathOverride, "romfs");
|
||||
set => RomFSPathOverride = value;
|
||||
}
|
||||
public string ExeFSPath
|
||||
{
|
||||
get => GetOverridePathOrDefault(ExeFSPathOverride, "exefs");
|
||||
set => ExeFSPathOverride = value;
|
||||
}
|
||||
public string ExportPath
|
||||
{
|
||||
get => GetOverridePathOrDefault(ExportPathOverride, Game.GetTitleID());
|
||||
set => ExportPathOverride = value;
|
||||
}
|
||||
|
||||
public event PropertyChangedEventHandler? PropertyChanged;
|
||||
|
||||
protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null)
|
||||
{
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
}
|
||||
|
||||
public class ProgramSettings
|
||||
{
|
||||
public static readonly string ProgramSettingsPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "settings.json");
|
||||
public static ProgramSettings LoadSettings() => SettingsSerializer.GetSettings<ProgramSettings>(ProgramSettingsPath).Result;
|
||||
public static ProgramSettings LoadSettings()
|
||||
{
|
||||
var settings = SettingsSerializer.GetSettings<ProgramSettings>(ProgramSettingsPath).Result;
|
||||
settings.UpdateForSupportedGames();
|
||||
return settings;
|
||||
}
|
||||
|
||||
public static async Task SaveSettings(ProgramSettings settings) => await SettingsSerializer.SaveSettings(settings, ProgramSettingsPath);
|
||||
|
||||
public int Language { get; set; } = 2;
|
||||
public bool DisplayAdvanced { get; set; } = false;
|
||||
|
||||
public string GamePath { get; set; } = string.Empty;
|
||||
public GameVersion GameOverride { get; set; } = GameVersion.Any;
|
||||
public bool DisplayAdvanced { get; set; } = false;
|
||||
|
||||
public GameConfig[] GameConfigs { get; set; } = Array.Empty<GameConfig>();
|
||||
|
||||
public void UpdateForSupportedGames()
|
||||
{
|
||||
// Add all missing supported games to the config
|
||||
if (GameConfigs.Length >= Game.GamePath.SupportedGames.Length)
|
||||
return;
|
||||
|
||||
var missing = Game.GamePath.SupportedGames.Except(GameConfigs.Select(x => x.Game));
|
||||
GameConfigs = GameConfigs
|
||||
.Concat(missing.Select(x => new GameConfig { Game = x }))
|
||||
.OrderBy(x => x.Game)
|
||||
.ToArray();
|
||||
|
||||
GameConfigs.First(x => x.Game == GameOverride).WorkspacePath = GamePath;
|
||||
}
|
||||
}
|
||||
|
||||
public static class SettingsSerializer
|
||||
{
|
||||
public static async Task<T> GetSettings<T>(string path, CancellationToken token = default) where T : new()
|
||||
{
|
||||
if (!File.Exists(path))
|
||||
return new T();
|
||||
|
||||
try
|
||||
{
|
||||
var data = await File.ReadAllTextAsync(path, token).ConfigureAwait(false);
|
||||
return System.Text.Json.JsonSerializer.Deserialize<T>(data) ?? new T();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine($"Unable to load settings from {path}: {ex.Message}");
|
||||
return new T();
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task SaveSettings<T>(T settings, string path, CancellationToken token = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
var json = System.Text.Json.JsonSerializer.Serialize(settings);
|
||||
await File.WriteAllTextAsync(path, json, token).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine(ex.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace pkNX.WinForms;
|
||||
|
||||
public static class SettingsSerializer
|
||||
{
|
||||
public static async Task<T> GetSettings<T>(string path, CancellationToken token = default) where T : new()
|
||||
{
|
||||
if (!File.Exists(path))
|
||||
return new T();
|
||||
|
||||
try
|
||||
{
|
||||
var data = await File.ReadAllTextAsync(path, token).ConfigureAwait(false);
|
||||
return System.Text.Json.JsonSerializer.Deserialize<T>(data) ?? new T();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine($"Unable to load settings from {path}: {ex.Message}");
|
||||
return new T();
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task SaveSettings<T>(T settings, string path, CancellationToken token = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
var json = System.Text.Json.JsonSerializer.Serialize(settings);
|
||||
await File.WriteAllTextAsync(path, json, token).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine(ex.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -199,6 +199,26 @@
|
||||
<Geometry x:Key="ExpanderToggleButtonArrow">M5,-0 L9,5 1,5 z</Geometry>
|
||||
|
||||
<Geometry x:Key="SliderThumb.Horizontal.Default">M0 26 L0 6 Q0 0 3 0 Q6 0 6 6 L6 26 Q6 32 3 32 Q0 32 0 26 z</Geometry>
|
||||
|
||||
<!-- local:LabeledControl -->
|
||||
<Style TargetType="{x:Type local:LabeledControl}">
|
||||
<Setter Property="Label" Value="Label: "/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type local:LabeledControl}">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" SharedSizeGroup="LabelGroup"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Label Grid.Column="0" Content="{TemplateBinding Label}" HorizontalAlignment="Right" />
|
||||
<ContentControl Grid.Column="1" Content="{TemplateBinding Content}"/>
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<!--FontStyle-->
|
||||
<Style TargetType="{x:Type local:IconImage}">
|
||||
<Setter Property="ToolTipService.InitialShowDelay" Value="{StaticResource ToolTipInitialShowDelay}"/>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<Window x:Class="pkNX.WinForms.MainWindow"
|
||||
<Window x:Class="pkNX.WinForms.MainWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
@@ -45,6 +45,7 @@
|
||||
</MenuItem>
|
||||
</MenuItem>
|
||||
<MenuItem Header="Options">
|
||||
<MenuItem Header="Edit Workspace Settings..." Click="Menu_EditWorkspaceSettings_Click"/>
|
||||
<MenuItem Header="Language">
|
||||
<MenuItem.Icon>
|
||||
<local:IconImage Icon="Language" IconFont="Solid" />
|
||||
|
||||
@@ -347,7 +347,7 @@ private void Menu_SetRNGSeed_Click(object sender, EventArgs e)
|
||||
|
||||
private void OpenCommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
|
||||
{
|
||||
using FolderBrowserDialog fbd = new();
|
||||
using System.Windows.Forms.FolderBrowserDialog fbd = new();
|
||||
fbd.Description = "Select a folder containing the game files.";
|
||||
fbd.UseDescriptionForTitle = true;
|
||||
fbd.ShowNewFolderButton = false;
|
||||
@@ -386,4 +386,11 @@ private async void Menu_DisplayAdvanced_Click(object sender, RoutedEventArgs e)
|
||||
// Force reload of editor buttons
|
||||
LoadEditorButtons();
|
||||
}
|
||||
|
||||
private void Menu_EditWorkspaceSettings_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var form = new Settings();
|
||||
form.ShowDialog();
|
||||
Editor.SetupVFS();
|
||||
}
|
||||
}
|
||||
|
||||
55
pkNX.WinForms/UI/ModelEditor.xaml
Normal file
55
pkNX.WinForms/UI/ModelEditor.xaml
Normal file
@@ -0,0 +1,55 @@
|
||||
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
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"
|
||||
xmlns:local="clr-namespace:pkNX.WinForms"
|
||||
xmlns:forms="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"
|
||||
xmlns:System="clr-namespace:System;assembly=System.Runtime" x:Class="pkNX.WinForms.ModelEditor"
|
||||
Background="{StaticResource Window.Background}"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
x:Name="Root"
|
||||
mc:Ignorable="d"
|
||||
Title="ModelEditor" MinWidth="420" MinHeight="250" Width="560" Height="720">
|
||||
<Window.Resources>
|
||||
<local:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter"/>
|
||||
</Window.Resources>
|
||||
<Grid Margin="3">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid Grid.Row="0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<local:LabeledControl Label="Convert Mode:">
|
||||
<CheckBox x:Name="CHK_ConvertMode" Margin="3" VerticalAlignment="Center" IsChecked="True"/>
|
||||
</local:LabeledControl>
|
||||
<local:LabeledControl Grid.Column="1" Label="Output Format:" Visibility="{Binding IsChecked, Converter={StaticResource BoolToVisibilityConverter}, ElementName=CHK_ConvertMode}">
|
||||
<ComboBox MinWidth="108" Margin="3" Visibility="{Binding IsChecked, Converter={StaticResource BoolToVisibilityConverter}, ElementName=CHK_ConvertMode}"/>
|
||||
</local:LabeledControl>
|
||||
|
||||
<Button Grid.Column="2" Click="B_Convert_Click" Margin="3" Width="80" Content="Convert" />
|
||||
</Grid>
|
||||
|
||||
<Grid Grid.Row="1">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<local:LabeledControl Label="Source:">
|
||||
<ComboBox x:Name="CB_GameSource" MinWidth="168" Margin="3" DisplayMemberPath="GameTitle" SelectionChanged="CB_GameSource_SelectionChanged"/>
|
||||
</local:LabeledControl>
|
||||
<local:LabeledControl Grid.Column="1" Label="Species:">
|
||||
<ComboBox x:Name="CB_Species" Margin="3" DisplayMemberPath="Name" SelectionChanged="CB_Species_SelectionChanged"/>
|
||||
</local:LabeledControl>
|
||||
</Grid>
|
||||
<WindowsFormsHost Grid.Row="2" Margin="3">
|
||||
<forms:PropertyGrid x:Name="PG_Model" HelpVisible="False" ToolbarVisible="False"/>
|
||||
</WindowsFormsHost>
|
||||
</Grid>
|
||||
</Window>
|
||||
83
pkNX.WinForms/UI/ModelEditor.xaml.cs
Normal file
83
pkNX.WinForms/UI/ModelEditor.xaml.cs
Normal file
@@ -0,0 +1,83 @@
|
||||
using pkNX.Containers.VFS;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Shapes;
|
||||
using pkNX.Game;
|
||||
using pkNX.Structures;
|
||||
using pkNX.Containers;
|
||||
|
||||
namespace pkNX.WinForms;
|
||||
|
||||
/// <summary>
|
||||
/// Interaction logic for ModelEditor.xaml
|
||||
/// </summary>
|
||||
public partial class ModelEditor : Window
|
||||
{
|
||||
public ModelEditor()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
VirtualFileSystem vfs = VirtualFileSystem.Current;
|
||||
|
||||
var settings = ProgramSettings.LoadSettings();
|
||||
var loadedGames = settings.GameConfigs
|
||||
.Where(x => x.IsValid && vfs.IsGameLoaded(x.Game))
|
||||
.ToList();
|
||||
|
||||
CB_GameSource.ItemsSource = loadedGames;
|
||||
CB_GameSource.SelectedIndex = loadedGames.FindIndex(x => x.Game == settings.GameOverride);
|
||||
}
|
||||
|
||||
private void B_Convert_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private void CB_GameSource_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
if (CB_GameSource.SelectedItem is not GameConfig config)
|
||||
return;
|
||||
|
||||
VirtualFileSystem vfs = VirtualFileSystem.Current;
|
||||
FileSystemPath pokemonModelDir = config.Game.ToMountPath() + GamePath.GetDirectoryPath(GameFile.PokemonArchiveFolder, config.Game);
|
||||
|
||||
var f = vfs.GetFilesInDirectory(pokemonModelDir);
|
||||
CB_Species.ItemsSource = vfs.GetFiles(pokemonModelDir, path => path.EntityName != "pokeconfig.gfpak");
|
||||
|
||||
}
|
||||
|
||||
private void CB_Species_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
var file = (VirtualFile)CB_Species.SelectedItem;
|
||||
|
||||
switch (((GameConfig)CB_GameSource.SelectedItem).Game)
|
||||
{
|
||||
case GameVersion.SW:
|
||||
case GameVersion.SH:
|
||||
case GameVersion.SWSH:
|
||||
break;
|
||||
case GameVersion.PLA:
|
||||
LoadFile_PLA(file);
|
||||
break;
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadFile_PLA(VirtualFile file)
|
||||
{
|
||||
using var reader = new BinaryReader(file.OpenRead());
|
||||
PG_Model.SelectedObject = new GFPack(reader);
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@
|
||||
xmlns:local="clr-namespace:pkNX.WinForms"
|
||||
xmlns:forms="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"
|
||||
xmlns:arceus="clr-namespace:pkNX.Structures.FlatBuffers.Arceus;assembly=pkNX.Structures.FlatBuffers.Arceus"
|
||||
xmlns:controls="clr-namespace:pkNX.WinForms.Controls"
|
||||
mc:Ignorable="d"
|
||||
x:Name="PkmEditor"
|
||||
Background="{StaticResource Window.Background}"
|
||||
@@ -151,8 +152,8 @@
|
||||
<Label Grid.Column="0" Grid.Row="5" Content="EXP Group:" HorizontalContentAlignment="Right"/>
|
||||
<ComboBox Grid.Column="1" Grid.Row="5" x:Name="CB_EXPGroup" Margin="3" Grid.ColumnSpan="2" ItemsSource="{Binding Source={x:Static local:UIStaticSources.EXPGroups}}"/>
|
||||
|
||||
<Label Grid.Column="0" Grid.Row="6" Content="Form Name:" HorizontalContentAlignment="Right" Visibility="Hidden"/>
|
||||
<TextBox Grid.Column="1" Grid.ColumnSpan="2" Grid.Row="6" x:Name="TB_FormName" Margin="3" IsReadOnly="True" Visibility="Hidden"/>
|
||||
<Label Grid.Column="0" Grid.Row="6" Content="Form Name:" HorizontalContentAlignment="Right" />
|
||||
<TextBox Grid.Column="1" Grid.ColumnSpan="2" Grid.Row="6" x:Name="TB_FormName" Margin="3" IsReadOnly="True" />
|
||||
</Grid>
|
||||
|
||||
<!-- Status -->
|
||||
@@ -242,7 +243,7 @@
|
||||
<!-- Tabs -->
|
||||
<TabControl x:Name="tabControl1" Grid.Row="2" Margin="3">
|
||||
<!-- Personal Tab -->
|
||||
<!-- TODO: The personal tab should contain data that is shared between games and the Details section at the top should contain all game specific data -->
|
||||
<!-- TODO: Sort out the properties better between the personal tab and the details section at the top. The section at the top should contain all the info you'd want to see/edit when other tabs are open -->
|
||||
<TabItem Header="Personal" >
|
||||
<Grid Margin="3">
|
||||
<Grid.RowDefinitions>
|
||||
@@ -519,7 +520,7 @@
|
||||
|
||||
<!-- Level Up -->
|
||||
<GroupBox Grid.Column="0" Header="Level Up Learnset:">
|
||||
<DataGrid x:Name="DG_LevelUp" AutoGenerateColumns="False">
|
||||
<DataGrid x:Name="DG_LevelUp" AutoGenerateColumns="False" UseLayoutRounding="True">
|
||||
<DataGrid.Columns>
|
||||
<DataGridTextColumn Header="Level" MinWidth="32" Binding="{Binding Level}"/>
|
||||
<DataGridTextColumn Header="Mastery Level" MinWidth="32" Binding="{Binding LevelMaster}"/>
|
||||
@@ -598,8 +599,34 @@
|
||||
|
||||
</TabItem>
|
||||
|
||||
<!-- Drops Tab -->
|
||||
<TabItem Header="Drops">
|
||||
<Grid Margin="3">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<controls:ItemDrop/>
|
||||
<controls:ItemDrop Grid.Column="1"/>
|
||||
</Grid>
|
||||
|
||||
<DataGrid x:Name="DG_Drops" Grid.Row="1" Margin="0,22,0,0"/>
|
||||
</Grid>
|
||||
</TabItem>
|
||||
|
||||
<!-- Enhancements Tab -->
|
||||
<TabItem Header="Enhancements" Visibility="Hidden">
|
||||
<TabItem Header="Randomizer" Visibility="Hidden">
|
||||
|
||||
<TabControl>
|
||||
<!-- Enhancement sections -->
|
||||
|
||||
@@ -31,14 +31,6 @@ public partial class PokemonEditor
|
||||
|
||||
public static readonly DependencyProperty SelectedSpeciesProperty = DependencyProperty.Register(nameof(SelectedSpecies), typeof(ushort), typeof(PokemonEditor), new PropertyMetadata((ushort)0, OnSelectedSpeciesChanged));
|
||||
|
||||
private static void OnSelectedSpeciesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var self = (PokemonEditor)d;
|
||||
if (self.Loaded)
|
||||
self.SaveCurrent();
|
||||
self.LoadSelectedSpecies();
|
||||
}
|
||||
|
||||
private readonly bool Loaded;
|
||||
private readonly GameData8a Data;
|
||||
|
||||
@@ -83,7 +75,7 @@ private void LoadSelectedSpecies()
|
||||
var pt = Data.PersonalData;
|
||||
var index = pt.GetFormIndex(SelectedSpecies, SelectedForm);
|
||||
|
||||
//TB_FormName.Text = UIStaticSources.FormsList[index];
|
||||
TB_FormName.Text = UIStaticSources.FormsList[index];
|
||||
|
||||
LoadPersonal((IPersonalInfoPLA)Data.PersonalData[index]);
|
||||
LoadMisc(Editor.PokeMisc.Root.GetEntry(SelectedSpecies, SelectedForm));
|
||||
@@ -294,6 +286,8 @@ private void LoadMisc(PokeMisc pokeMisc8a)
|
||||
|
||||
pokeMisc8a.DropTable = Editor.FieldDropTables.Table.FirstOrDefault(drops => drops.Hash == pokeMisc8a.DropTableRef);
|
||||
pokeMisc8a.AlphaDropTable = Editor.FieldDropTables.Table.FirstOrDefault(drops => drops.Hash == pokeMisc8a.AlphaDropTableRef);
|
||||
|
||||
DG_Drops.ItemsSource = Editor.FieldDropTables.Table;
|
||||
}
|
||||
|
||||
private void LoadDexResearch(PokedexResearchTask[] pokedexResearchTask)
|
||||
@@ -430,6 +424,14 @@ private void AutoFillEvolutions()
|
||||
}
|
||||
}
|
||||
|
||||
private static void OnSelectedSpeciesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var self = (PokemonEditor)d;
|
||||
if (self.Loaded)
|
||||
self.SaveCurrent();
|
||||
self.LoadSelectedSpecies();
|
||||
}
|
||||
|
||||
private void B_DumpTable_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var pt = Editor.Personal;
|
||||
|
||||
55
pkNX.WinForms/UI/Settings.xaml
Normal file
55
pkNX.WinForms/UI/Settings.xaml
Normal file
@@ -0,0 +1,55 @@
|
||||
<Window x:Class="pkNX.WinForms.Settings"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
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"
|
||||
xmlns:local="clr-namespace:pkNX.WinForms"
|
||||
mc:Ignorable="d"
|
||||
x:Name="Root"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
Background="{StaticResource Window.Background}"
|
||||
Title="Settings" Height="450" Width="800" Closing="Window_Closing">
|
||||
<Window.Resources>
|
||||
<ResourceDictionary>
|
||||
<local:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter"/>
|
||||
</ResourceDictionary>
|
||||
</Window.Resources>
|
||||
<Grid>
|
||||
<ScrollViewer VerticalScrollBarVisibility="Auto">
|
||||
<GroupBox Header="Game File Paths">
|
||||
<ItemsControl ItemsSource="{Binding Config.GameConfigs, ElementName=Root}" d:ItemsSource="{d:SampleData ItemCount=3}" >
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<StackPanel Margin="3"/>
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate DataType="local:GameConfig">
|
||||
<Expander Header="{Binding GameTitle}" Grid.IsSharedSizeScope="True" IsExpanded="{Binding IsValid, Mode=OneTime}">
|
||||
<StackPanel Margin="14 3 3 3">
|
||||
<local:LabeledControl Label="Workspace Path:">
|
||||
<local:PathSelector Path="{Binding WorkspacePath}"/>
|
||||
</local:LabeledControl>
|
||||
<local:LabeledControl Label="Override Paths:">
|
||||
<CheckBox x:Name="CHK_Split" VerticalAlignment="Center" Margin="3" IsChecked="{Binding OverrideDefaultPaths}"/>
|
||||
</local:LabeledControl>
|
||||
<StackPanel Visibility="{Binding IsChecked, ElementName=CHK_Split, Converter={StaticResource BoolToVisibilityConverter}}">
|
||||
<local:LabeledControl Label="RomFS:">
|
||||
<local:PathSelector Path="{Binding RomFSPath }" IsEnabled="{Binding IsChecked, ElementName=CHK_Split}"/>
|
||||
</local:LabeledControl>
|
||||
<local:LabeledControl Label="ExeFS:">
|
||||
<local:PathSelector Path="{Binding ExeFSPath}" IsEnabled="{Binding IsChecked, ElementName=CHK_Split}"/>
|
||||
</local:LabeledControl>
|
||||
<local:LabeledControl Label="Mod Export:">
|
||||
<local:PathSelector Path="{Binding ExportPath}" IsEnabled="{Binding IsChecked, ElementName=CHK_Split}"/>
|
||||
</local:LabeledControl>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Expander>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</GroupBox>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
</Window>
|
||||
35
pkNX.WinForms/UI/Settings.xaml.cs
Normal file
35
pkNX.WinForms/UI/Settings.xaml.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
using pkNX.Structures;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using pkNX.Game;
|
||||
|
||||
namespace pkNX.WinForms;
|
||||
|
||||
public class SettingsModel
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interaction logic for Settings.xaml
|
||||
/// </summary>
|
||||
public partial class Settings
|
||||
{
|
||||
public ProgramSettings Config { get; set; }
|
||||
|
||||
public Settings()
|
||||
{
|
||||
Config = ProgramSettings.LoadSettings();
|
||||
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private async void Window_Closing(object sender, CancelEventArgs e)
|
||||
{
|
||||
// TODO: Verify workspace paths for each game
|
||||
|
||||
await ProgramSettings.SaveSettings(Config);
|
||||
}
|
||||
}
|
||||
@@ -409,7 +409,6 @@ private void BatchExport()
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
var result = WinFormsUtil.Prompt(MessageBoxButton.YesNo, "Would you like to unescape newline characters?");
|
||||
bool newline = result == MessageBoxResult.Yes;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user