Skip to content

Commit

Permalink
Merge pull request #36 from derail-valley-modding/b99
Browse files Browse the repository at this point in the history
Detail texture handling, packager fixes, inventory icons
  • Loading branch information
katycat5e authored Jan 23, 2025
2 parents 6d9471b + 4c2c006 commit 8c12193
Show file tree
Hide file tree
Showing 27 changed files with 1,409 additions and 134 deletions.
Binary file added Resources/can_dropped.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Resources/can_icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Resources/can_icon.xcf
Binary file not shown.
15 changes: 15 additions & 0 deletions SMShared/Json/SkinConfigJson.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,20 @@ namespace SMShared.Json
public class SkinConfigJson : ResourceConfigJson
{
public string[] ResourceNames;
public BaseTheme BaseTheme = BaseTheme.DVRT;
}

[Flags]
public enum BaseTheme
{
DVRT = 0,
Pristine = 1,
Demonstrator = 2,
Relic = 4,

DVRT_NoDetails = 32,
Pristine_NoDetails = Pristine | DVRT_NoDetails,
Demonstrator_NoDetails = Demonstrator | DVRT_NoDetails,
Relic_NoDetails = Relic | DVRT_NoDetails,
}
}
1 change: 1 addition & 0 deletions SMShared/Json/ThemeConfigJson.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ public class ThemeConfigItem
{
public string Name;
public bool HideFromStores;
public bool PreventRandomSpawning;

public string LabelTextureFile;
public string LabelBaseColor;
Expand Down
6 changes: 5 additions & 1 deletion SkinConfigurator/AssemblyInfo.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using SMShared;
using System.Reflection;
using System.Runtime.Versioning;
using System.Windows;

[assembly: ThemeInfo(
Expand All @@ -13,6 +14,9 @@

[assembly: AssemblyTitle("SkinConfigurator")]
[assembly: AssemblyProduct("SkinConfigurator")]
[assembly: AssemblyCompany("Derail Valley Modding")]

[assembly: AssemblyVersion(Constants.MOD_VERSION)]
[assembly: AssemblyFileVersion(Constants.MOD_VERSION)]
[assembly: AssemblyFileVersion(Constants.MOD_VERSION)]

[assembly: SupportedOSPlatform("windows")]
38 changes: 27 additions & 11 deletions SkinConfigurator/MainWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:local="clr-namespace:SkinConfigurator"
xmlns:model="clr-namespace:SkinConfigurator.ViewModels"
xmlns:json="clr-namespace:SMShared.Json"
mc:Ignorable="d"
Title="Skin Packager" Height="600" Width="1000"
d:DataContext="{d:DesignInstance {x:Type model:MainWindowViewModel}}">
Expand All @@ -15,17 +16,26 @@
<x:Type TypeName="model:PackComponentType"/>
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
<ObjectDataProvider x:Key="defaultThemeTypes" ObjectType="{x:Type sys:Enum}" MethodName="GetValues">
<ObjectDataProvider.MethodParameters>
<x:Type TypeName="json:BaseTheme"/>
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
</Window.Resources>

<DockPanel LastChildFill="True" Background="{x:Static SystemColors.ControlBrush}" >
<Menu DockPanel.Dock="Top">
<MenuItem Header="File">
<MenuItem x:Name="CreatePackButton" Header="New Project" Click="CreatePackButton_Click" ToolTip="Clear all fields and start anew"/>
<MenuItem x:Name="ImportPackButton" Header="Open Folder..." Click="ImportPackButton_Click" ToolTip="Import multiple skins from a folder"/>
<MenuItem x:Name="ImportZipButton" Header="Open Zip..." Click="ImportZipButton_Click" ToolTip="Import skins from a zipped skin pack"/>
<MenuItem Header="_File">
<MenuItem x:Name="CreatePackButton" Header="_New Project" Click="CreatePackButton_Click" ToolTip="Clear all fields and start anew"/>
<MenuItem x:Name="ImportPackButton" Header="_Open Folder..." Click="ImportPackButton_Click" ToolTip="Import multiple skins from a folder"/>
<MenuItem x:Name="ImportZipButton" Header="Open _Zip..." Click="ImportZipButton_Click" ToolTip="Import skins from a zipped skin pack"/>

<local:RecentFileList x:Name="RecentFileSelector" MenuClick="RecentFileSelector_MenuClick"/>

<MenuItem x:Name="ExitButton" Header="E_xit" Click="ExitButton_Click"/>
</MenuItem>

<MenuItem x:Name="SettingsButton" Header="Settings..." Click="SettingsButton_Click"/>
<MenuItem x:Name="SettingsButton" Header="_Settings..." Click="SettingsButton_Click"/>
</Menu>

<Grid Margin="5">
Expand Down Expand Up @@ -173,6 +183,7 @@
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>

Expand All @@ -194,15 +205,19 @@
<Button x:Name="SelectCarTypeButton" Content=" Defaults... " Click="SelectCarTypeButton_Click" Grid.Column="2"/>
</Grid>

<Label Content="Resources" Grid.Row="3" Grid.Column="0" Visibility="{Binding SelectedSkin.HasResources, Converter={StaticResource boolToCollapseConverter}}"/>
<local:ResourceSelector x:Name="MyResourceSelector" Grid.Row="3" Grid.Column="2"
<Label Content="Base Theme" Grid.Row="3" Grid.Column="0" Visibility="{Binding SelectedSkin.HasResources, Converter={StaticResource boolToCollapseConverter}}"/>
<ComboBox Grid.Row="3" Grid.Column="1" IsEditable="False" ItemsSource="{Binding Source={StaticResource defaultThemeTypes}}" SelectedItem="{Binding SelectedSkin.BaseTheme}"
Visibility="{Binding SelectedSkin.HasResources, Converter={StaticResource boolToCollapseConverter}}"/>

<Label Content="Resources" Grid.Row="4" Grid.Column="0" Visibility="{Binding SelectedSkin.HasResources, Converter={StaticResource boolToCollapseConverter}}"/>
<local:ResourceSelector x:Name="MyResourceSelector" Grid.Row="4" Grid.Column="2"
Visibility="{Binding SelectedSkin.HasResources, Converter={StaticResource boolToCollapseConverter}}"
SkinPack="{Binding SkinPack}" Skin="{Binding SelectedSkin}"
ToolTip="Select common files to be used by this skin"/>

<!-- Skin Items -->
<Label Content="Skin Files:" Grid.Row="4" Grid.Column="0" Margin="0,7,0,0"/>
<UniformGrid Columns="3" Grid.Row="4" Grid.Column="1" Margin="0,7,0,0">
<Label Content="Skin Files:" Grid.Row="5" Grid.Column="0" Margin="0,7,0,0"/>
<UniformGrid Columns="3" Grid.Row="5" Grid.Column="1" Margin="0,7,0,0">
<Button x:Name="AddFileButton" Content="Add..." Click="AddFileButton_Click"/>
<Button x:Name="ReplaceFileButton" Content="Replace..." Click="ReplaceFileButton_Click"
IsEnabled="{Binding SelectedSkinFile, Converter={StaticResource nullBoolConverter}, FallbackValue=False}"/>
Expand All @@ -212,7 +227,7 @@

<ListView x:Name="SkinFileList" DockPanel.Dock="Bottom" ItemsSource="{Binding SelectedSkin.Items}" d:ItemsSource="{d:SampleData}"
SelectedItem="{Binding SelectedSkinFile}" FocusManager.IsFocusScope="True" AllowDrop="True"
Grid.Row="5" Grid.ColumnSpan="2">
Grid.Row="6" Grid.ColumnSpan="2">
<ListView.Resources>
<ContextMenu x:Key="SkinFileContextMenu">
<MenuItem Header="Replace..." Click="ReplaceFileButton_Click"/>
Expand All @@ -235,7 +250,8 @@
<Image Width="64px" Height="64px" Source="{Binding Preview}"/>
<UniformGrid Rows="2" Grid.Column="1">
<local:SpecialCombo IsEditable="True" Text="{Binding FileName, UpdateSourceTrigger=LostFocus}"
ItemsSource="{Binding Path=DataContext.DefaultTextureNames, RelativeSource={RelativeSource AncestorType=ListView}, Mode=OneWay}"/>
ItemsSource="{Binding Path=DataContext.DefaultTextureNames, RelativeSource={RelativeSource AncestorType=ListView}, Mode=OneWay}"
ScrollViewer.VerticalScrollBarVisibility="Visible" ScrollViewer.CanContentScroll="True"/>
<Button Grid.Row="1" Content="Upgrade Filename" Click="UpgradeFileNameButton_Click"
Visibility="{Binding CanUpgradeFileName, Mode=OneWay, Converter={StaticResource boolToCollapseConverter}}"
Background="PaleGoldenrod"/>
Expand Down
75 changes: 67 additions & 8 deletions SkinConfigurator/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
using System.Text.Json;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Media;

Expand Down Expand Up @@ -48,16 +49,16 @@ public MainWindow()
#endif
}

IEnumerable<string> GetNames(string folder)
private static IEnumerable<string> GetNames(string folder)
{
string[] ext = { ".png", ".jpeg", ".jpg" };
return Directory.GetFiles(folder)
return Directory.EnumerateFiles(folder, "*", SearchOption.AllDirectories)
.Where(s => ext.Contains(Path.GetExtension(s)))
.Select(s => Path.GetFileName(s))
.OrderBy(s => s);
}

Dictionary<string, string[]> GetCarTex(string baseFolder)
private static Dictionary<string, string[]> GetCarTex(string baseFolder)
{
var result = new Dictionary<string, string[]>();
foreach (string subDir in Directory.EnumerateDirectories(baseFolder))
Expand Down Expand Up @@ -90,12 +91,26 @@ private void ImportPackButton_Click(object sender, RoutedEventArgs e)
if (!Directory.Exists(folderDialog.SelectedPath))
{
MessageBox.Show(this, "Selected path is not a valid directory", "Invalid Path", MessageBoxButton.OK, MessageBoxImage.Error);
RecentFileSelector.RemoveFile(folderDialog.SelectedPath);
return;
}

using (new WaitCursor())
DoFolderImport(folderDialog.SelectedPath);
}
}

private void DoFolderImport(string path)
{
using (new WaitCursor())
{
var imported = PackImporter.ImportFromFolder(path);

if (imported is not null)
{
Model.SkinPack = PackImporter.ImportFromFolder(folderDialog.SelectedPath);
Model.SkinPack = imported;
MyResourceSelector.RefreshAvailableItems();

RecentFileSelector.InsertFile(path);
}
}
}
Expand All @@ -117,17 +132,49 @@ private void ImportZipButton_Click(object sender, RoutedEventArgs e)
if (!File.Exists(dialog.FileName))
{
MessageBox.Show(this, "Selected path is not a valid Zip Archive", "Invalid Path", MessageBoxButton.OK, MessageBoxImage.Error);
RecentFileSelector.RemoveFile(dialog.FileName);
return;
}

using (new WaitCursor())
DoZipImport(dialog.FileName);
}
}

private void DoZipImport(string path)
{
using (new WaitCursor())
{
var imported = PackImporter.ImportFromArchive(path);

if (imported is not null)
{
Model.SkinPack = PackImporter.ImportFromArchive(dialog.FileName);
Model.SkinPack = imported;
MyResourceSelector.RefreshAvailableItems();

RecentFileSelector.InsertFile(path);
}
}
}

private void RecentFileSelector_MenuClick(object sender, RecentFileList.MenuClickEventArgs e)
{
var pathAttr = File.GetAttributes(e.Filepath);

if (pathAttr.HasFlag(FileAttributes.Directory))
{
DoFolderImport(e.Filepath);
}
else
{
DoZipImport(e.Filepath);
}
}

private void ExitButton_Click(object sender, RoutedEventArgs e)
{
Application.Current.Shutdown();
}

#endregion

#region Skins Menu
Expand Down Expand Up @@ -438,8 +485,9 @@ protected override void OnPreviewMouseLeftButtonDown(MouseButtonEventArgs e)
protected override void OnPreviewMouseMove(MouseEventArgs e)
{
base.OnPreviewMouseMove(e);
if (e.LeftButton == MouseButtonState.Pressed && (e.OriginalSource is FrameworkElement source) && (source.DataContext is SkinFileModel file))
if (e.LeftButton == MouseButtonState.Pressed && (e.OriginalSource is FrameworkElement source) && !IsChildOf<ScrollBar>(source) && (source.DataContext is SkinFileModel file))
{
Trace.WriteLine(source.GetType());
var newPos = e.GetPosition(null);

if (Math.Abs(newPos.X - _mouseStartPoint.X) > SystemParameters.MinimumHorizontalDragDistance ||
Expand Down Expand Up @@ -501,6 +549,17 @@ private static bool IsChildOf(DependencyObject? child, DependencyObject parent)
return false;
}

private static bool IsChildOf<TParent>(DependencyObject? child)
{
while (child != null)
{
if (child is TParent) return true;

child = VisualTreeHelper.GetParent(child);
}
return false;
}

#endregion

#region Theme Config
Expand Down
48 changes: 36 additions & 12 deletions SkinConfigurator/PackImporter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,29 @@
using System.Linq;
using System.Text.Json;
using System.Text.RegularExpressions;
using System.Windows;

namespace SkinConfigurator
{
internal static class PackImporter
{
public static SkinPackModel ImportFromFolder(string path)
public static SkinPackModel? ImportFromFolder(string path)
{
if (Directory.EnumerateFiles(path, "Info.json", SearchOption.AllDirectories).Any())
try
{
return ImportSimulatorProject(path);
if (Directory.EnumerateFiles(path, "Info.json", SearchOption.AllDirectories).Any())
{
return ImportSimulatorProject(path);
}
else
{
return ImportGenericFolder(path);
}
}
else
catch (Exception ex)
{
return ImportGenericFolder(path);
MessageBox.Show("Failed to import skins from the folder:\n" + ex.Message);
return null;
}
}

Expand Down Expand Up @@ -157,15 +166,23 @@ private static IEnumerable<string> EnumerateSkinFolders(string path)

#endregion

public static SkinPackModel ImportFromArchive(string archivePath)
public static SkinPackModel? ImportFromArchive(string archivePath)
{
using var stream = File.OpenRead(archivePath);
using var archive = new ZipArchive(stream, ZipArchiveMode.Read);
try
{
using var stream = File.OpenRead(archivePath);
using var archive = new ZipArchive(stream, ZipArchiveMode.Read);

string tempFolder = ExtractArchiveToTemp(archive, Path.GetFileNameWithoutExtension(archivePath));
var pack = ImportFromFolder(tempFolder);
Directory.Delete(tempFolder, true);
return pack;
string tempFolder = ExtractArchiveToTemp(archive, Path.GetFileNameWithoutExtension(archivePath));
var pack = ImportFromFolder(tempFolder);
Directory.Delete(tempFolder, true);
return pack;
}
catch (Exception ex)
{
MessageBox.Show("Failed to import the zipped skin pack:\n" + ex.Message);
return null;
}
}

private static string ExtractArchiveToTemp(ZipArchive archive, string archiveName)
Expand All @@ -182,4 +199,11 @@ private static string ExtractArchiveToTemp(ZipArchive archive, string archiveNam
return destFolder;
}
}

public class SkinImportException : Exception
{
public SkinImportException(string message) : base(message) { }

public SkinImportException(string message, Exception inner) : base(message, inner) { }
}
}
Loading

0 comments on commit 8c12193

Please sign in to comment.