From 91731e1a42ffe21fe9af67a2893596640d190d3b Mon Sep 17 00:00:00 2001
From: AsY!um- <377468+AsYlum-@users.noreply.github.com>
Date: Fri, 24 Apr 2026 17:02:36 +0200
Subject: [PATCH 1/6] Replace from folder for Items and Land tiles. #102
---
.../ReplaceFromFolderResultForm.Designer.cs | 86 +++++++++++++
.../Forms/ReplaceFromFolderResultForm.cs | 24 ++++
.../Forms/ReplaceFromFolderResultForm.resx | 120 ++++++++++++++++++
.../UserControls/ItemsControl.Designer.cs | 13 +-
.../UserControls/ItemsControl.cs | 91 +++++++++++++
.../UserControls/LandTilesControl.Designer.cs | 13 +-
.../UserControls/LandTilesControl.cs | 97 ++++++++++++++
7 files changed, 440 insertions(+), 4 deletions(-)
create mode 100644 UoFiddler.Controls/Forms/ReplaceFromFolderResultForm.Designer.cs
create mode 100644 UoFiddler.Controls/Forms/ReplaceFromFolderResultForm.cs
create mode 100644 UoFiddler.Controls/Forms/ReplaceFromFolderResultForm.resx
diff --git a/UoFiddler.Controls/Forms/ReplaceFromFolderResultForm.Designer.cs b/UoFiddler.Controls/Forms/ReplaceFromFolderResultForm.Designer.cs
new file mode 100644
index 00000000..42b91c5e
--- /dev/null
+++ b/UoFiddler.Controls/Forms/ReplaceFromFolderResultForm.Designer.cs
@@ -0,0 +1,86 @@
+namespace UoFiddler.Controls.Forms
+{
+ partial class ReplaceFromFolderResultForm
+ {
+ private System.ComponentModel.IContainer components = null;
+
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ private void InitializeComponent()
+ {
+ reportTextBox = new System.Windows.Forms.TextBox();
+ buttonPanel = new System.Windows.Forms.Panel();
+ closeButton = new System.Windows.Forms.Button();
+ buttonPanel.SuspendLayout();
+ SuspendLayout();
+ //
+ // reportTextBox
+ //
+ reportTextBox.BackColor = System.Drawing.SystemColors.Window;
+ reportTextBox.Dock = System.Windows.Forms.DockStyle.Fill;
+ reportTextBox.Font = new System.Drawing.Font("Consolas", 9F);
+ reportTextBox.Location = new System.Drawing.Point(8, 8);
+ reportTextBox.Multiline = true;
+ reportTextBox.Name = "reportTextBox";
+ reportTextBox.ReadOnly = true;
+ reportTextBox.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
+ reportTextBox.Size = new System.Drawing.Size(368, 210);
+ reportTextBox.TabIndex = 1;
+ //
+ // buttonPanel
+ //
+ buttonPanel.Controls.Add(closeButton);
+ buttonPanel.Dock = System.Windows.Forms.DockStyle.Bottom;
+ buttonPanel.Location = new System.Drawing.Point(8, 218);
+ buttonPanel.Name = "buttonPanel";
+ buttonPanel.Padding = new System.Windows.Forms.Padding(0, 4, 8, 4);
+ buttonPanel.Size = new System.Drawing.Size(368, 43);
+ buttonPanel.TabIndex = 0;
+ //
+ // closeButton
+ //
+ closeButton.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right;
+ closeButton.DialogResult = System.Windows.Forms.DialogResult.Cancel;
+ closeButton.Location = new System.Drawing.Point(267, 7);
+ closeButton.Name = "closeButton";
+ closeButton.Size = new System.Drawing.Size(90, 28);
+ closeButton.TabIndex = 2;
+ closeButton.Text = "Close";
+ closeButton.UseVisualStyleBackColor = true;
+ //
+ // ReplaceFromFolderResultForm
+ //
+ AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
+ AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
+ ClientSize = new System.Drawing.Size(384, 261);
+ Controls.Add(reportTextBox);
+ Controls.Add(buttonPanel);
+ MaximizeBox = false;
+ MinimizeBox = false;
+ MinimumSize = new System.Drawing.Size(400, 300);
+ Name = "ReplaceFromFolderResultForm";
+ Padding = new System.Windows.Forms.Padding(8, 8, 8, 0);
+ ShowInTaskbar = false;
+ StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
+ Text = "Replace from Folder";
+ buttonPanel.ResumeLayout(false);
+ ResumeLayout(false);
+ PerformLayout();
+ }
+
+ #endregion
+
+ private System.Windows.Forms.TextBox reportTextBox;
+ private System.Windows.Forms.Panel buttonPanel;
+ private System.Windows.Forms.Button closeButton;
+ }
+}
diff --git a/UoFiddler.Controls/Forms/ReplaceFromFolderResultForm.cs b/UoFiddler.Controls/Forms/ReplaceFromFolderResultForm.cs
new file mode 100644
index 00000000..efbfda68
--- /dev/null
+++ b/UoFiddler.Controls/Forms/ReplaceFromFolderResultForm.cs
@@ -0,0 +1,24 @@
+/***************************************************************************
+ *
+ * $Author: Turley
+ *
+ * "THE BEER-WARE LICENSE"
+ * As long as you retain this notice you can do whatever you want with
+ * this stuff. If we meet some day, and you think this stuff is worth it,
+ * you can buy me a beer in return.
+ *
+ ***************************************************************************/
+
+using System.Windows.Forms;
+
+namespace UoFiddler.Controls.Forms
+{
+ public sealed partial class ReplaceFromFolderResultForm : Form
+ {
+ public ReplaceFromFolderResultForm(string report)
+ {
+ InitializeComponent();
+ reportTextBox.Text = report;
+ }
+ }
+}
diff --git a/UoFiddler.Controls/Forms/ReplaceFromFolderResultForm.resx b/UoFiddler.Controls/Forms/ReplaceFromFolderResultForm.resx
new file mode 100644
index 00000000..4edf53f8
--- /dev/null
+++ b/UoFiddler.Controls/Forms/ReplaceFromFolderResultForm.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/UoFiddler.Controls/UserControls/ItemsControl.Designer.cs b/UoFiddler.Controls/UserControls/ItemsControl.Designer.cs
index 04605df6..4773dcfc 100644
--- a/UoFiddler.Controls/UserControls/ItemsControl.Designer.cs
+++ b/UoFiddler.Controls/UserControls/ItemsControl.Designer.cs
@@ -69,6 +69,7 @@ private void InitializeComponent()
replaceToolStripMenuItem = new ToolStripMenuItem();
replaceStartingFromToolStripMenuItem = new ToolStripMenuItem();
ReplaceStartingFromText = new ToolStripTextBox();
+ replaceFromFolderToolStripMenuItem = new ToolStripMenuItem();
insertAtToolStripMenuItem = new ToolStripMenuItem();
InsertText = new ToolStripTextBox();
removeToolStripMenuItem = new ToolStripMenuItem();
@@ -217,7 +218,7 @@ private void InitializeComponent()
//
// TileViewContextMenuStrip
//
- TileViewContextMenuStrip.Items.AddRange(new ToolStripItem[] { showFreeSlotsToolStripMenuItem, findNextFreeSlotToolStripMenuItem, ChangeBackgroundColorToolStripMenuItem, toolStripSeparator3, extractToolStripMenuItem, toolStripSeparator7, selectInTileDataTabToolStripMenuItem, selectInRadarColorTabToolStripMenuItem, selectInGumpsTabMaleToolStripMenuItem, selectInGumpsTabFemaleToolStripMenuItem, toolStripSeparator2, replaceToolStripMenuItem, replaceStartingFromToolStripMenuItem, insertAtToolStripMenuItem, removeToolStripMenuItem, toolStripSeparator1, saveToolStripMenuItem });
+ TileViewContextMenuStrip.Items.AddRange(new ToolStripItem[] { showFreeSlotsToolStripMenuItem, findNextFreeSlotToolStripMenuItem, ChangeBackgroundColorToolStripMenuItem, toolStripSeparator3, extractToolStripMenuItem, toolStripSeparator7, selectInTileDataTabToolStripMenuItem, selectInRadarColorTabToolStripMenuItem, selectInGumpsTabMaleToolStripMenuItem, selectInGumpsTabFemaleToolStripMenuItem, toolStripSeparator2, replaceToolStripMenuItem, replaceStartingFromToolStripMenuItem, replaceFromFolderToolStripMenuItem, insertAtToolStripMenuItem, removeToolStripMenuItem, toolStripSeparator1, saveToolStripMenuItem });
TileViewContextMenuStrip.Name = "contextMenuStrip1";
TileViewContextMenuStrip.Size = new System.Drawing.Size(213, 314);
TileViewContextMenuStrip.Opening += TileViewContextMenuStrip_Opening;
@@ -343,7 +344,14 @@ private void InitializeComponent()
ReplaceStartingFromText.Name = "ReplaceStartingFromText";
ReplaceStartingFromText.Size = new System.Drawing.Size(100, 23);
ReplaceStartingFromText.KeyDown += ReplaceStartingFromText_KeyDown;
- //
+ //
+ // replaceFromFolderToolStripMenuItem
+ //
+ replaceFromFolderToolStripMenuItem.Name = "replaceFromFolderToolStripMenuItem";
+ replaceFromFolderToolStripMenuItem.Size = new System.Drawing.Size(212, 22);
+ replaceFromFolderToolStripMenuItem.Text = "Replace from Folder...";
+ replaceFromFolderToolStripMenuItem.Click += OnClickReplaceFromFolder;
+ //
// insertAtToolStripMenuItem
//
insertAtToolStripMenuItem.DropDownItems.AddRange(new ToolStripItem[] { InsertText });
@@ -635,6 +643,7 @@ private void InitializeComponent()
private ToolStripMenuItem selectInGumpsTabFemaleToolStripMenuItem;
private ToolStripMenuItem replaceStartingFromToolStripMenuItem;
private ToolStripTextBox ReplaceStartingFromText;
+ private ToolStripMenuItem replaceFromFolderToolStripMenuItem;
private ToolStripLabel toolStripLabel1;
private ToolStripTextBox searchByIdToolStripTextBox;
private ToolStripLabel toolStripLabel2;
diff --git a/UoFiddler.Controls/UserControls/ItemsControl.cs b/UoFiddler.Controls/UserControls/ItemsControl.cs
index 4abd0840..eeb55c51 100644
--- a/UoFiddler.Controls/UserControls/ItemsControl.cs
+++ b/UoFiddler.Controls/UserControls/ItemsControl.cs
@@ -16,6 +16,7 @@
using System.Drawing.Imaging;
using System.IO;
using System.Text;
+using System.Text.RegularExpressions;
using System.Windows.Forms;
using Ultima;
using UoFiddler.Controls.Classes;
@@ -37,6 +38,8 @@ public ItemsControl()
DetailTextBox.AddBasicContextMenu();
}
+ private static readonly Regex _hexIndexRegex = new(@"0[xX][0-9a-fA-F]+", RegexOptions.Compiled);
+
private List _itemList = new List();
private bool _showFreeSlots;
@@ -1187,6 +1190,94 @@ private static bool IsIndexValid(int index)
return index >= 0 && index <= Art.GetMaxItemId();
}
+ private void OnClickReplaceFromFolder(object sender, EventArgs e)
+ {
+ using FolderBrowserDialog dialog = new FolderBrowserDialog();
+ dialog.Description = "Select folder containing images to replace";
+
+ if (dialog.ShowDialog() != DialogResult.OK)
+ {
+ return;
+ }
+
+ string[] allFiles = Directory.GetFiles(dialog.SelectedPath);
+ var replacedLines = new List();
+ var skippedLines = new List();
+
+ foreach (string file in allFiles)
+ {
+ string ext = Path.GetExtension(file).ToLowerInvariant();
+ if (ext != ".bmp" && ext != ".jpg" && ext != ".jpeg" && ext != ".png" && ext != ".tif" && ext != ".tiff")
+ {
+ continue;
+ }
+
+ string name = Path.GetFileName(file);
+ Match match = _hexIndexRegex.Match(Path.GetFileNameWithoutExtension(file));
+ if (!match.Success)
+ {
+ skippedLines.Add($" {name} (no hex ID in filename)");
+ continue;
+ }
+
+ int index;
+ try
+ {
+ index = Convert.ToInt32(match.Value, 16);
+ }
+ catch
+ {
+ skippedLines.Add($" {name} (invalid hex value)");
+ continue;
+ }
+
+ if (!IsIndexValid(index))
+ {
+ skippedLines.Add($" {name} (index 0x{index:X} out of range)");
+ continue;
+ }
+
+ try
+ {
+ AddSingleItem(file, index);
+ replacedLines.Add($" 0x{index:X4} {name}");
+ }
+ catch
+ {
+ skippedLines.Add($" {name} (failed to load image)");
+ }
+ }
+
+ ItemsTileView.VirtualListSize = _itemList.Count;
+ ItemsTileView.Invalidate();
+
+ var sb = new StringBuilder();
+ sb.AppendLine($"Replaced: {replacedLines.Count} Skipped: {skippedLines.Count}");
+
+ if (replacedLines.Count > 0)
+ {
+ sb.AppendLine();
+ sb.AppendLine($"Replaced ({replacedLines.Count}):");
+ foreach (string line in replacedLines)
+ {
+ sb.AppendLine(line);
+ }
+ }
+
+ if (skippedLines.Count > 0)
+ {
+ sb.AppendLine();
+ sb.AppendLine($"Skipped ({skippedLines.Count}):");
+ foreach (string line in skippedLines)
+ {
+ sb.AppendLine(line);
+ }
+ }
+
+ using var resultForm = new ReplaceFromFolderResultForm(sb.ToString());
+ resultForm.ShowDialog(this);
+ }
+
private void SearchByIdToolStripTextBox_KeyUp(object sender, KeyEventArgs e)
{
if (!Utils.ConvertStringToInt(searchByIdToolStripTextBox.Text, out int indexValue))
diff --git a/UoFiddler.Controls/UserControls/LandTilesControl.Designer.cs b/UoFiddler.Controls/UserControls/LandTilesControl.Designer.cs
index 67a01c4c..00fb1d78 100644
--- a/UoFiddler.Controls/UserControls/LandTilesControl.Designer.cs
+++ b/UoFiddler.Controls/UserControls/LandTilesControl.Designer.cs
@@ -62,6 +62,7 @@ private void InitializeComponent()
replaceToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
replaceStartingFromToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
ReplaceStartingFromTb = new System.Windows.Forms.ToolStripTextBox();
+ replaceFromFolderToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
insertAtToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
InsertText = new System.Windows.Forms.ToolStripTextBox();
removeToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
@@ -97,7 +98,7 @@ private void InitializeComponent()
//
// LandTilesContextMenuStrip
//
- LandTilesContextMenuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { showFreeSlotsToolStripMenuItem, findNextFreeSlotToolStripMenuItem, changeBackgroundColorToolStripMenuItem, toolStripSeparator6, exportImageToolStripMenuItem, toolStripSeparator3, selectInTileDataTabToolStripMenuItem, selectInRadarColorTabToolStripMenuItem, selectInTexturesTabToolStripMenuItem, toolStripSeparator2, replaceToolStripMenuItem, replaceStartingFromToolStripMenuItem, insertAtToolStripMenuItem, removeToolStripMenuItem, toolStripSeparator1, saveToolStripMenuItem });
+ LandTilesContextMenuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { showFreeSlotsToolStripMenuItem, findNextFreeSlotToolStripMenuItem, changeBackgroundColorToolStripMenuItem, toolStripSeparator6, exportImageToolStripMenuItem, toolStripSeparator3, selectInTileDataTabToolStripMenuItem, selectInRadarColorTabToolStripMenuItem, selectInTexturesTabToolStripMenuItem, toolStripSeparator2, replaceToolStripMenuItem, replaceStartingFromToolStripMenuItem, replaceFromFolderToolStripMenuItem, insertAtToolStripMenuItem, removeToolStripMenuItem, toolStripSeparator1, saveToolStripMenuItem });
LandTilesContextMenuStrip.Name = "contextMenuStrip1";
LandTilesContextMenuStrip.Size = new System.Drawing.Size(201, 270);
LandTilesContextMenuStrip.Opening += LandTilesContextMenuStrip_Opening;
@@ -214,7 +215,14 @@ private void InitializeComponent()
ReplaceStartingFromTb.Name = "ReplaceStartingFromTb";
ReplaceStartingFromTb.Size = new System.Drawing.Size(100, 23);
ReplaceStartingFromTb.KeyDown += ReplaceStartingFromTb_KeyDown;
- //
+ //
+ // replaceFromFolderToolStripMenuItem
+ //
+ replaceFromFolderToolStripMenuItem.Name = "replaceFromFolderToolStripMenuItem";
+ replaceFromFolderToolStripMenuItem.Size = new System.Drawing.Size(200, 22);
+ replaceFromFolderToolStripMenuItem.Text = "Replace from Folder...";
+ replaceFromFolderToolStripMenuItem.Click += OnClickReplaceFromFolder;
+ //
// insertAtToolStripMenuItem
//
insertAtToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { InsertText });
@@ -476,6 +484,7 @@ private void InitializeComponent()
private System.Windows.Forms.ToolStripSeparator toolStripSeparator4;
private System.Windows.Forms.ToolStripMenuItem replaceStartingFromToolStripMenuItem;
private System.Windows.Forms.ToolStripTextBox ReplaceStartingFromTb;
+ private System.Windows.Forms.ToolStripMenuItem replaceFromFolderToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem showFreeSlotsToolStripMenuItem;
private System.Windows.Forms.ToolStripSeparator toolStripSeparator6;
private System.Windows.Forms.StatusStrip StatusStrip;
diff --git a/UoFiddler.Controls/UserControls/LandTilesControl.cs b/UoFiddler.Controls/UserControls/LandTilesControl.cs
index 9616c60d..f3d51754 100644
--- a/UoFiddler.Controls/UserControls/LandTilesControl.cs
+++ b/UoFiddler.Controls/UserControls/LandTilesControl.cs
@@ -14,6 +14,8 @@
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
+using System.Text;
+using System.Text.RegularExpressions;
using System.Windows.Forms;
using Ultima;
using UoFiddler.Controls.Classes;
@@ -35,6 +37,8 @@ public LandTilesControl()
public bool IsLoaded { get; private set; }
+ private static readonly Regex _hexIndexRegex = new(@"0[xX][0-9a-fA-F]+", RegexOptions.Compiled);
+
private const int _landTileMax = 0x4000;
private static LandTilesControl _refMarker;
@@ -801,6 +805,99 @@ private static bool IsIndexValid(int index)
return index < 0x4000;
}
+ private void OnClickReplaceFromFolder(object sender, EventArgs e)
+ {
+ using FolderBrowserDialog dialog = new FolderBrowserDialog();
+ dialog.Description = "Select folder containing images to replace";
+
+ if (dialog.ShowDialog() != DialogResult.OK)
+ {
+ return;
+ }
+
+ string[] allFiles = Directory.GetFiles(dialog.SelectedPath);
+ var replacedLines = new List();
+ var skippedLines = new List();
+
+ foreach (string file in allFiles)
+ {
+ string ext = Path.GetExtension(file).ToLowerInvariant();
+ if (ext != ".bmp" && ext != ".jpg" && ext != ".jpeg" && ext != ".png" && ext != ".tif" && ext != ".tiff")
+ {
+ continue;
+ }
+
+ string name = Path.GetFileName(file);
+ Match match = _hexIndexRegex.Match(Path.GetFileNameWithoutExtension(file));
+ if (!match.Success)
+ {
+ skippedLines.Add($" {name} (no hex ID in filename)");
+ continue;
+ }
+
+ int index;
+ try
+ {
+ index = Convert.ToInt32(match.Value, 16);
+ }
+ catch
+ {
+ skippedLines.Add($" {name} (invalid hex value)");
+ continue;
+ }
+
+ if (!IsIndexValid(index))
+ {
+ skippedLines.Add($" {name} (index 0x{index:X} out of range)");
+ continue;
+ }
+
+ try
+ {
+ AddSingleLandTile(file, index);
+ replacedLines.Add($" 0x{index:X4} {name}");
+ }
+ catch
+ {
+ skippedLines.Add($" {name} (failed to load image)");
+ }
+ }
+
+ LandTilesTileView.VirtualListSize = _tileList.Count;
+ LandTilesTileView.Invalidate();
+
+ if (replacedLines.Count > 0)
+ {
+ Options.ChangedUltimaClass["Art"] = true;
+ }
+
+ var sb = new StringBuilder();
+ sb.AppendLine($"Replaced: {replacedLines.Count} Skipped: {skippedLines.Count}");
+
+ if (replacedLines.Count > 0)
+ {
+ sb.AppendLine();
+ sb.AppendLine($"Replaced ({replacedLines.Count}):");
+ foreach (string line in replacedLines)
+ {
+ sb.AppendLine(line);
+ }
+ }
+
+ if (skippedLines.Count > 0)
+ {
+ sb.AppendLine();
+ sb.AppendLine($"Skipped ({skippedLines.Count}):");
+ foreach (string line in skippedLines)
+ {
+ sb.AppendLine(line);
+ }
+ }
+
+ using var resultForm = new ReplaceFromFolderResultForm(sb.ToString());
+ resultForm.ShowDialog(this);
+ }
+
///
/// Adds a single land tile.
///
From 9e42fc2ddc478f7a728de5f62c31b76ab682a9ec Mon Sep 17 00:00:00 2001
From: AsY!um- <377468+AsYlum-@users.noreply.github.com>
Date: Fri, 24 Apr 2026 18:10:10 +0200
Subject: [PATCH 2/6] Map copy/replace uop support. #105
---
UoFiddler.Controls/Forms/MapReplaceForm.cs | 64 +++++++---------------
1 file changed, 20 insertions(+), 44 deletions(-)
diff --git a/UoFiddler.Controls/Forms/MapReplaceForm.cs b/UoFiddler.Controls/Forms/MapReplaceForm.cs
index 98b62b84..abe2f51a 100644
--- a/UoFiddler.Controls/Forms/MapReplaceForm.cs
+++ b/UoFiddler.Controls/Forms/MapReplaceForm.cs
@@ -157,32 +157,27 @@ private void OnClickCopy(object sender, EventArgs e)
if (checkBoxMap.Checked)
{
- string copyMap = Path.Combine(path, $"map{replaceMap.Id}.mul");
- if (!File.Exists(copyMap))
+ string copyMapMul = Path.Combine(path, $"map{replaceMap.Id}.mul");
+ string copyMapUop = Path.Combine(path, $"map{replaceMap.Id}LegacyMUL.uop");
+ if (!File.Exists(copyMapMul) && !File.Exists(copyMapUop))
{
MessageBox.Show("Map file not found!", "Map Replace", MessageBoxButtons.OK, MessageBoxIcon.Error,
MessageBoxDefaultButton.Button1);
return;
}
- FileStream mMapCopy = new FileStream(copyMap, FileMode.Open, FileAccess.Read, FileShare.Read);
- BinaryReader mMapReaderCopy = new BinaryReader(mMapCopy);
- string mapPath = Files.GetFilePath($"map{_workingMap.FileIndex}.mul");
-
- BinaryReader mMapReader;
-
- if (mapPath != null)
- {
- FileStream mMap = new FileStream(mapPath, FileMode.Open, FileAccess.Read, FileShare.Read);
- mMapReader = new BinaryReader(mMap);
- }
- else
+ string workingMapMul = Files.GetFilePath($"map{_workingMap.FileIndex}.mul");
+ string workingMapUop = Files.GetFilePath($"map{_workingMap.FileIndex}LegacyMUL.uop");
+ if (workingMapMul == null && workingMapUop == null)
{
MessageBox.Show("Map file not found!", "Map Replace", MessageBoxButtons.OK, MessageBoxIcon.Error,
MessageBoxDefaultButton.Button1);
return;
}
+ var copyTileMatrix = new TileMatrix(replaceMap.Id, replaceMap.Id, replaceMap.Width, replaceMap.Height, path);
+ var workTileMatrix = new TileMatrix(_workingMap.FileIndex, _workingMap.FileIndex, _workingMap.Width, _workingMap.Height, null);
+
string mul = Path.Combine(Options.OutputPath, $"map{_workingMap.FileIndex}.mul");
using (FileStream fsMul = new FileStream(mul, FileMode.Create, FileAccess.Write, FileShare.Write))
{
@@ -192,35 +187,16 @@ private void OnClickCopy(object sender, EventArgs e)
{
for (int y = 0; y < blockY; ++y)
{
- if (tox <= x && x <= tox2 && toy <= y && y <= toy2)
- {
- mMapReaderCopy.BaseStream.Seek((((x - tox + x1) * blockYReplace) + (y - toy) + y1) * 196, SeekOrigin.Begin);
- int header = mMapReaderCopy.ReadInt32();
- binMul.Write(header);
- }
- else
- {
- mMapReader.BaseStream.Seek(((x * blockY) + y) * 196, SeekOrigin.Begin);
- int header = mMapReader.ReadInt32();
- binMul.Write(header);
- }
- for (int i = 0; i < 64; ++i)
- {
- ushort tileId;
- sbyte z;
-
- if (tox <= x && x <= tox2 && toy <= y && y <= toy2)
- {
- tileId = mMapReaderCopy.ReadUInt16();
- z = mMapReaderCopy.ReadSByte();
- }
- else
- {
- tileId = mMapReader.ReadUInt16();
- z = mMapReader.ReadSByte();
- }
+ bool inRegion = tox <= x && x <= tox2 && toy <= y && y <= toy2;
+ Tile[] tiles = inRegion
+ ? copyTileMatrix.GetLandBlock(x - tox + x1, y - toy + y1, false)
+ : workTileMatrix.GetLandBlock(x, y, false);
- tileId = Art.GetLegalItemId(tileId);
+ binMul.Write(0); // 4-byte block header
+ foreach (Tile tile in tiles)
+ {
+ ushort tileId = Art.GetLegalItemId(tile.Id);
+ sbyte z = tile.Z;
if (z < -128)
{
@@ -241,8 +217,8 @@ private void OnClickCopy(object sender, EventArgs e)
}
}
- mMapReader.Close();
- mMapReaderCopy.Close();
+ copyTileMatrix.CloseStreams();
+ workTileMatrix.CloseStreams();
}
if (checkBoxStatics.Checked)
From edd5b839c4d5d9cbb683da593456daade5b09f66 Mon Sep 17 00:00:00 2001
From: AsY!um- <377468+AsYlum-@users.noreply.github.com>
Date: Fri, 24 Apr 2026 18:33:32 +0200
Subject: [PATCH 3/6] More updates with file save dialog.
---
UoFiddler.Controls/Forms/MapDiffInsertForm.cs | 2 +-
.../UserControls/AnimationListControl.cs | 7 ++-
.../UserControls/FontsControl.cs | 3 +-
.../UserControls/GumpControl.cs | 3 +-
.../UserControls/HuesControl.cs | 5 +-
.../UserControls/ItemsControl.cs | 3 +-
.../UserControls/LandTilesControl.cs | 3 +-
.../UserControls/LightControl.cs | 12 ++---
UoFiddler.Controls/UserControls/MapControl.cs | 11 ++--
.../UserControls/MultiMapControl.cs | 3 +-
.../UserControls/MultisControl.cs | 53 ++++++++-----------
.../UserControls/RadarColorControl.cs | 4 +-
.../UserControls/SoundsControl.cs | 3 +-
.../UserControls/SpeechControl.cs | 3 +-
.../UserControls/CompareGumpControl.cs | 9 ++--
.../UserControls/CompareItemControl.cs | 8 +--
.../UserControls/CompareLandControl.cs | 8 +--
.../UserControls/CompareTextureControl.cs | 7 ++-
.../Forms/MassImportForm.cs | 6 +--
.../UserControls/MultiEditorControl.cs | 4 +-
20 files changed, 70 insertions(+), 87 deletions(-)
diff --git a/UoFiddler.Controls/Forms/MapDiffInsertForm.cs b/UoFiddler.Controls/Forms/MapDiffInsertForm.cs
index 6624aa4e..a48d98ed 100644
--- a/UoFiddler.Controls/Forms/MapDiffInsertForm.cs
+++ b/UoFiddler.Controls/Forms/MapDiffInsertForm.cs
@@ -487,7 +487,7 @@ private void OnClickCopy(object sender, EventArgs e)
mStaticsReader.Close();
}
- MessageBox.Show($"Files saved to {Options.OutputPath}", "Saved", MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1);
+ FileSavedDialog.Show(FindForm(), Options.OutputPath, "Files saved successfully.");
}
}
}
diff --git a/UoFiddler.Controls/UserControls/AnimationListControl.cs b/UoFiddler.Controls/UserControls/AnimationListControl.cs
index 0c51f304..04f77848 100644
--- a/UoFiddler.Controls/UserControls/AnimationListControl.cs
+++ b/UoFiddler.Controls/UserControls/AnimationListControl.cs
@@ -944,8 +944,7 @@ private void ExportAnimationFrames(ImageFormat imageFormat)
}
}
- MessageBox.Show($"{what} saved to '{fileName}-X.{fileExtension}'", "Saved", MessageBoxButtons.OK,
- MessageBoxIcon.Information, MessageBoxDefaultButton.Button1);
+ FileSavedDialog.Show(FindForm(), Options.OutputPath, $"Files with following format {fileName}-X.{fileExtension} saved successfully.");
}
private void OnClickExportFrameBmp(object sender, EventArgs e)
@@ -1007,8 +1006,8 @@ private void ExportAnimatedGif(bool looping)
var outputFile = Path.Combine(Options.OutputPath, $"{(_displayType == 1 ? "Equipment" : "Mob")} {_currentSelect}.gif");
MainPictureBox.Frames.ToGif(outputFile, looping: looping, delay: 150, showFrameBounds: MainPictureBox.ShowFrameBounds);
- MessageBox.Show($"InGame Anim saved to {outputFile}", "Saved", MessageBoxButtons.OK,
- MessageBoxIcon.Information, MessageBoxDefaultButton.Button1);
+
+ FileSavedDialog.Show(FindForm(), outputFile, "InGame Anim saved successfully.");
}
private void OnClickExtractAnimGifLooping(object sender, EventArgs e)
diff --git a/UoFiddler.Controls/UserControls/FontsControl.cs b/UoFiddler.Controls/UserControls/FontsControl.cs
index 7c3abaaa..28b34867 100644
--- a/UoFiddler.Controls/UserControls/FontsControl.cs
+++ b/UoFiddler.Controls/UserControls/FontsControl.cs
@@ -226,8 +226,7 @@ private void OnClickExport(object sender, EventArgs e)
bmp.Save(fileName, ImageFormat.Tiff);
}
- MessageBox.Show($"Character saved to {fileName}", "Saved", MessageBoxButtons.OK, MessageBoxIcon.Information,
- MessageBoxDefaultButton.Button1);
+ FileSavedDialog.Show(FindForm(), fileName, "Character saved successfully.");
}
private static int AsciiFontOffset => 32;
diff --git a/UoFiddler.Controls/UserControls/GumpControl.cs b/UoFiddler.Controls/UserControls/GumpControl.cs
index 22c1e4f5..04ffa04b 100644
--- a/UoFiddler.Controls/UserControls/GumpControl.cs
+++ b/UoFiddler.Controls/UserControls/GumpControl.cs
@@ -807,8 +807,7 @@ private void ExportAllGumps(ImageFormat imageFormat)
Cursor.Current = Cursors.Default;
- MessageBox.Show($"All Gumps saved to {dialog.SelectedPath}", "Saved", MessageBoxButtons.OK,
- MessageBoxIcon.Information, MessageBoxDefaultButton.Button1);
+ FileSavedDialog.Show(FindForm(), dialog.SelectedPath, "All Gumps saved successfully.");
}
}
diff --git a/UoFiddler.Controls/UserControls/HuesControl.cs b/UoFiddler.Controls/UserControls/HuesControl.cs
index b4648374..b4e02d4a 100644
--- a/UoFiddler.Controls/UserControls/HuesControl.cs
+++ b/UoFiddler.Controls/UserControls/HuesControl.cs
@@ -20,6 +20,7 @@
using UoFiddler.Controls.Classes;
using UoFiddler.Controls.Forms;
using UoFiddler.Controls.Helpers;
+using static System.Windows.Forms.VisualStyles.VisualStyleElement.Window;
namespace UoFiddler.Controls.UserControls
{
@@ -272,7 +273,7 @@ private void OnExport(object sender, EventArgs e)
string path = Options.OutputPath;
string fileName = Path.Combine(path, $"Hue {_selected}.txt");
Hues.List[_selected].Export(fileName);
- MessageBox.Show($"Hue saved to {fileName}", "Saved", MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1);
+ FileSavedDialog.Show(FindForm(), fileName, "Hue saved successfully.");
}
private void OnImport(object sender, EventArgs e)
@@ -396,7 +397,7 @@ private void ExportAllHueNamesListToolStripMenuItem_Click(object sender, EventAr
Hues.ExportHueList(fileName);
- MessageBox.Show($"Hue names list saved to {fileName}", "Saved", MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1);
+ FileSavedDialog.Show(FindForm(), fileName, "Hue names list saved successfully.");
}
private void IndexOffsetButton_CheckedChanged(object sender, EventArgs e)
diff --git a/UoFiddler.Controls/UserControls/ItemsControl.cs b/UoFiddler.Controls/UserControls/ItemsControl.cs
index eeb55c51..4a345a0d 100644
--- a/UoFiddler.Controls/UserControls/ItemsControl.cs
+++ b/UoFiddler.Controls/UserControls/ItemsControl.cs
@@ -836,8 +836,7 @@ private void ExportAllItemImages(ImageFormat imageFormat)
Cursor.Current = Cursors.Default;
- MessageBox.Show($"All items saved to {dialog.SelectedPath}", "Saved", MessageBoxButtons.OK,
- MessageBoxIcon.Information, MessageBoxDefaultButton.Button1);
+ FileSavedDialog.Show(FindForm(), dialog.SelectedPath, "All items saved successfully.");
}
}
diff --git a/UoFiddler.Controls/UserControls/LandTilesControl.cs b/UoFiddler.Controls/UserControls/LandTilesControl.cs
index f3d51754..a170fdc9 100644
--- a/UoFiddler.Controls/UserControls/LandTilesControl.cs
+++ b/UoFiddler.Controls/UserControls/LandTilesControl.cs
@@ -665,8 +665,7 @@ private void ExportAllLandTiles(ImageFormat imageFormat)
Cursor.Current = Cursors.Default;
- MessageBox.Show($"All land tiles saved to {dialog.SelectedPath}", "Saved", MessageBoxButtons.OK,
- MessageBoxIcon.Information, MessageBoxDefaultButton.Button1);
+ FileSavedDialog.Show(FindForm(), dialog.SelectedPath, "All land tiles saved successfully.");
}
}
diff --git a/UoFiddler.Controls/UserControls/LightControl.cs b/UoFiddler.Controls/UserControls/LightControl.cs
index 9ee277ce..5a975066 100644
--- a/UoFiddler.Controls/UserControls/LightControl.cs
+++ b/UoFiddler.Controls/UserControls/LightControl.cs
@@ -18,6 +18,7 @@
using UoFiddler.Controls.Classes;
using UoFiddler.Controls.Forms;
using UoFiddler.Controls.Helpers;
+using static System.Windows.Forms.VisualStyles.VisualStyleElement.Window;
namespace UoFiddler.Controls.UserControls
{
@@ -348,9 +349,8 @@ private void OnClickExportBmp(object sender, EventArgs e)
string path = Options.OutputPath;
int i = (int)treeViewLights.SelectedNode.Tag;
string fileName = Path.Combine(path, $"Light {i}.bmp");
- Ultima.Light.GetLight(i).Save(fileName, ImageFormat.Bmp);
- MessageBox.Show($"Light saved to {fileName}", "Saved", MessageBoxButtons.OK, MessageBoxIcon.Information,
- MessageBoxDefaultButton.Button1);
+ Light.GetLight(i).Save(fileName, ImageFormat.Bmp);
+ FileSavedDialog.Show(FindForm(), fileName, "Light saved successfully.");
}
private void OnClickExportTiff(object sender, EventArgs e)
@@ -364,8 +364,7 @@ private void OnClickExportTiff(object sender, EventArgs e)
int i = (int)treeViewLights.SelectedNode.Tag;
string fileName = Path.Combine(path, $"Light {i}.tiff");
Ultima.Light.GetLight(i).Save(fileName, ImageFormat.Tiff);
- MessageBox.Show($"Light saved to {fileName}", "Saved", MessageBoxButtons.OK, MessageBoxIcon.Information,
- MessageBoxDefaultButton.Button1);
+ FileSavedDialog.Show(FindForm(), fileName, "Light saved successfully.");
}
private void OnClickExportJpg(object sender, EventArgs e)
@@ -379,8 +378,7 @@ private void OnClickExportJpg(object sender, EventArgs e)
int i = (int)treeViewLights.SelectedNode.Tag;
string fileName = Path.Combine(path, $"Light {i}.jpg");
Ultima.Light.GetLight(i).Save(fileName, ImageFormat.Jpeg);
- MessageBox.Show($"Light saved to {fileName}", "Saved", MessageBoxButtons.OK, MessageBoxIcon.Information,
- MessageBoxDefaultButton.Button1);
+ FileSavedDialog.Show(FindForm(), fileName, "Light saved successfully.");
}
private void IgPreviewClicked(object sender, EventArgs e)
diff --git a/UoFiddler.Controls/UserControls/MapControl.cs b/UoFiddler.Controls/UserControls/MapControl.cs
index 88ad56c2..c7709611 100644
--- a/UoFiddler.Controls/UserControls/MapControl.cs
+++ b/UoFiddler.Controls/UserControls/MapControl.cs
@@ -854,8 +854,7 @@ private void ExtractMapImage(ImageFormat imageFormat)
Cursor.Current = Cursors.Default;
}
- MessageBox.Show($"Map saved to {fileName}", "Saved", MessageBoxButtons.OK, MessageBoxIcon.Information,
- MessageBoxDefaultButton.Button1);
+ FileSavedDialog.Show(FindForm(), fileName, "Map saved successfully.");
}
private MapMarkerForm _mapMarkerForm;
@@ -1108,7 +1107,8 @@ private void OnClickDefragStatics(object sender, EventArgs e)
Map.DefragStatics(Options.OutputPath,
CurrentMap, CurrentMap.Width, CurrentMap.Height, false);
Cursor.Current = Cursors.Default;
- MessageBox.Show($"Statics saved to {Options.OutputPath}", "Saved", MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1);
+
+ FileSavedDialog.Show(FindForm(), Options.OutputPath, "Statics saved successfully.");
}
private void OnClickDefragRemoveStatics(object sender, EventArgs e)
@@ -1117,7 +1117,7 @@ private void OnClickDefragRemoveStatics(object sender, EventArgs e)
Map.DefragStatics(Options.OutputPath,
CurrentMap, CurrentMap.Width, CurrentMap.Height, true);
Cursor.Current = Cursors.Default;
- MessageBox.Show($"Statics saved to {Options.OutputPath}", "Saved", MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1);
+ FileSavedDialog.Show(FindForm(), Options.OutputPath, "Statics saved successfully.");
}
private void OnResizeMap(object sender, EventArgs e)
@@ -1158,8 +1158,7 @@ private void OnClickReportInvalidMapIDs(object sender, EventArgs e)
Cursor.Current = Cursors.WaitCursor;
CurrentMap.ReportInvalidMapIDs(Options.OutputPath);
Cursor.Current = Cursors.Default;
- MessageBox.Show($"Report saved to {Options.OutputPath}", "Saved", MessageBoxButtons.OK,
- MessageBoxIcon.Information, MessageBoxDefaultButton.Button1);
+ FileSavedDialog.Show(FindForm(), Options.OutputPath, "Report saved successfully.");
}
private MapReplaceForm _showForm;
diff --git a/UoFiddler.Controls/UserControls/MultiMapControl.cs b/UoFiddler.Controls/UserControls/MultiMapControl.cs
index bb3141d4..02a377ec 100644
--- a/UoFiddler.Controls/UserControls/MultiMapControl.cs
+++ b/UoFiddler.Controls/UserControls/MultiMapControl.cs
@@ -222,8 +222,7 @@ private void ExportMultiMapImage(ImageFormat imageFormat)
pictureBox.Image.Save(fileName, imageFormat);
- MessageBox.Show($"{CheckedToString()} saved to {fileName}", "Export", MessageBoxButtons.OK,
- MessageBoxIcon.Information, MessageBoxDefaultButton.Button1);
+ FileSavedDialog.Show(FindForm(), fileName, $"{CheckedToString()} saved successfully.");
}
private string CheckedToString()
diff --git a/UoFiddler.Controls/UserControls/MultisControl.cs b/UoFiddler.Controls/UserControls/MultisControl.cs
index 2d4f81fc..ac3394ab 100644
--- a/UoFiddler.Controls/UserControls/MultisControl.cs
+++ b/UoFiddler.Controls/UserControls/MultisControl.cs
@@ -20,6 +20,7 @@
using UoFiddler.Controls.Classes;
using UoFiddler.Controls.Forms;
using UoFiddler.Controls.Helpers;
+using static System.Windows.Forms.VisualStyles.VisualStyleElement.Window;
namespace UoFiddler.Controls.UserControls
{
@@ -673,8 +674,7 @@ private void ExportAllMultis(ImageFormat imageFormat, Color backgroundColor)
}
}
- MessageBox.Show($"All Multis saved to {dialog.SelectedPath}", "Saved", MessageBoxButtons.OK,
- MessageBoxIcon.Information, MessageBoxDefaultButton.Button1);
+ FileSavedDialog.Show(FindForm(), dialog.SelectedPath, "All Multis saved successfully.");
}
}
@@ -706,8 +706,8 @@ private void OnClick_SaveAllText(object sender, EventArgs e)
string fileName = Path.Combine(dialog.SelectedPath, $"Multi 0x{index:X4}.txt");
multi.ExportToTextFile(fileName);
}
- MessageBox.Show($"All Multis saved to {dialog.SelectedPath}", "Saved", MessageBoxButtons.OK,
- MessageBoxIcon.Information, MessageBoxDefaultButton.Button1);
+
+ FileSavedDialog.Show(FindForm(), dialog.SelectedPath, "All Multis saved successfully.");
}
}
@@ -739,8 +739,8 @@ private void OnClick_SaveAllUOA(object sender, EventArgs e)
string fileName = Path.Combine(dialog.SelectedPath, $"Multi 0x{index:X4}.uoa");
multi.ExportToUOAFile(fileName);
}
- MessageBox.Show($"All Multis saved to {dialog.SelectedPath}", "Saved", MessageBoxButtons.OK,
- MessageBoxIcon.Information, MessageBoxDefaultButton.Button1);
+
+ FileSavedDialog.Show(FindForm(), dialog.SelectedPath, "All Multis saved successfully.");
}
}
@@ -772,8 +772,8 @@ private void OnClick_SaveAllWSC(object sender, EventArgs e)
string fileName = Path.Combine(dialog.SelectedPath, $"Multi 0x{index:X4}.wsc");
multi.ExportToWscFile(fileName);
}
- MessageBox.Show($"All Multis saved to {dialog.SelectedPath}", "Saved", MessageBoxButtons.OK,
- MessageBoxIcon.Information, MessageBoxDefaultButton.Button1);
+
+ FileSavedDialog.Show(FindForm(), dialog.SelectedPath, "All Multis saved successfully.");
}
}
@@ -805,8 +805,8 @@ private void OnClick_SaveAllCSV(object sender, EventArgs e)
string fileName = Path.Combine(dialog.SelectedPath, $"{index:D4}.csv");
multi.ExportToCsvFile(fileName);
}
- MessageBox.Show($"All Multis saved to {dialog.SelectedPath}", "Saved", MessageBoxButtons.OK,
- MessageBoxIcon.Information, MessageBoxDefaultButton.Button1);
+
+ FileSavedDialog.Show(FindForm(), dialog.SelectedPath, "All Multis saved successfully.");
}
}
@@ -838,8 +838,8 @@ private void OnClick_SaveAllUox3(object sender, EventArgs e)
string fileName = Path.Combine(dialog.SelectedPath, $"Multi 0x{index:X4}.uox3");
multi.ExportToUox3File(fileName);
}
- MessageBox.Show($"All Multis saved to {dialog.SelectedPath}", "Saved", MessageBoxButtons.OK,
- MessageBoxIcon.Information, MessageBoxDefaultButton.Button1);
+
+ FileSavedDialog.Show(FindForm(), dialog.SelectedPath, "All Multis saved successfully.");
}
}
@@ -861,8 +861,7 @@ private void OnExportCsvFile(object sender, EventArgs e)
string path = Options.OutputPath;
string fileName = Path.Combine(path, $"{id:D4}.csv");
multi.ExportToCsvFile(fileName);
- MessageBox.Show($"Multi saved to {fileName}", "Saved", MessageBoxButtons.OK, MessageBoxIcon.Information,
- MessageBoxDefaultButton.Button1);
+ FileSavedDialog.Show(FindForm(), fileName, "Multi saved successfully.");
}
private void OnExportUox3File(object sender, EventArgs e)
@@ -883,8 +882,7 @@ private void OnExportUox3File(object sender, EventArgs e)
string path = Options.OutputPath;
string fileName = Path.Combine(path, $"Multi 0x{id:X4}.uox3");
multi.ExportToUox3File(fileName);
- MessageBox.Show($"Multi saved to {fileName}", "Saved", MessageBoxButtons.OK, MessageBoxIcon.Information,
- MessageBoxDefaultButton.Button1);
+ FileSavedDialog.Show(FindForm(), fileName, "Multi saved successfully.");
}
private void ChangeBackgroundColorToolStripMenuItem_Click(object sender, EventArgs e)
@@ -1365,8 +1363,7 @@ private void ExportAllUopMultis(ImageFormat imageFormat, Color backgroundColor)
}
}
- MessageBox.Show($"All UOP Multis saved to {dialog.SelectedPath}", "Saved", MessageBoxButtons.OK,
- MessageBoxIcon.Information, MessageBoxDefaultButton.Button1);
+ FileSavedDialog.Show(FindForm(), dialog.SelectedPath, "All UOP Multis saved successfully.");
}
private void OnUopClick_SaveAllText(object sender, EventArgs e)
@@ -1392,8 +1389,7 @@ private void OnUopClick_SaveAllText(object sender, EventArgs e)
multi.ExportToTextFile(Path.Combine(dialog.SelectedPath, $"UopMulti 0x{index:X4}.txt"));
}
- MessageBox.Show($"All UOP Multis saved to {dialog.SelectedPath}", "Saved", MessageBoxButtons.OK,
- MessageBoxIcon.Information, MessageBoxDefaultButton.Button1);
+ FileSavedDialog.Show(FindForm(), dialog.SelectedPath, "All UOP Multis saved successfully.");
}
private void OnUopClick_SaveAllUOA(object sender, EventArgs e)
@@ -1419,8 +1415,7 @@ private void OnUopClick_SaveAllUOA(object sender, EventArgs e)
multi.ExportToUOAFile(Path.Combine(dialog.SelectedPath, $"UopMulti 0x{index:X4}.uoa"));
}
- MessageBox.Show($"All UOP Multis saved to {dialog.SelectedPath}", "Saved", MessageBoxButtons.OK,
- MessageBoxIcon.Information, MessageBoxDefaultButton.Button1);
+ FileSavedDialog.Show(FindForm(), dialog.SelectedPath, "All UOP Multis saved successfully.");
}
private void OnUopClick_SaveAllWSC(object sender, EventArgs e)
@@ -1446,8 +1441,7 @@ private void OnUopClick_SaveAllWSC(object sender, EventArgs e)
multi.ExportToWscFile(Path.Combine(dialog.SelectedPath, $"UopMulti 0x{index:X4}.wsc"));
}
- MessageBox.Show($"All UOP Multis saved to {dialog.SelectedPath}", "Saved", MessageBoxButtons.OK,
- MessageBoxIcon.Information, MessageBoxDefaultButton.Button1);
+ FileSavedDialog.Show(FindForm(), dialog.SelectedPath, "All UOP Multis saved successfully.");
}
private void OnUopClick_SaveAllCSV(object sender, EventArgs e)
@@ -1473,8 +1467,7 @@ private void OnUopClick_SaveAllCSV(object sender, EventArgs e)
multi.ExportToCsvFile(Path.Combine(dialog.SelectedPath, $"{index:D4}_uop.csv"));
}
- MessageBox.Show($"All UOP Multis saved to {dialog.SelectedPath}", "Saved", MessageBoxButtons.OK,
- MessageBoxIcon.Information, MessageBoxDefaultButton.Button1);
+ FileSavedDialog.Show(FindForm(), dialog.SelectedPath, "All UOP Multis saved successfully.");
}
private void OnClick_SaveAllToXML(object sender, EventArgs e)
@@ -1545,20 +1538,20 @@ private void OnClick_SaveAllToXML(object sender, EventArgs e)
groupWriter.WriteEndDocument();
}
- MessageBox.Show($"All Multis saved to {fileName}", "Saved", MessageBoxButtons.OK,
- MessageBoxIcon.Information, MessageBoxDefaultButton.Button1);
+ FileSavedDialog.Show(FindForm(), fileName, "All Multis saved successfully.");
}
private sealed class MouseWheelFilter : IMessageFilter
{
- private const int WmMouseWheel = 0x020A;
+ private const int _wmMouseWheel = 0x020A;
+
private readonly MultisControl _owner;
public MouseWheelFilter(MultisControl owner) => _owner = owner;
public bool PreFilterMessage(ref Message m)
{
- if (m.Msg != WmMouseWheel)
+ if (m.Msg != _wmMouseWheel)
{
return false;
}
diff --git a/UoFiddler.Controls/UserControls/RadarColorControl.cs b/UoFiddler.Controls/UserControls/RadarColorControl.cs
index dc33bbdd..6ce5b68d 100644
--- a/UoFiddler.Controls/UserControls/RadarColorControl.cs
+++ b/UoFiddler.Controls/UserControls/RadarColorControl.cs
@@ -831,8 +831,8 @@ private void OnClickExport(object sender, EventArgs e)
string path = Options.OutputPath;
string fileName = Path.Combine(path, "RadarColor.csv");
RadarCol.ExportToCSV(fileName);
- MessageBox.Show($"RadarColor saved to {fileName}", "Saved", MessageBoxButtons.OK,
- MessageBoxIcon.Information, MessageBoxDefaultButton.Button1);
+
+ FileSavedDialog.Show(FindForm(), fileName, "RadarColor saved successfully.");
}
private void OnClickMeanColorAll(object sender, EventArgs e)
diff --git a/UoFiddler.Controls/UserControls/SoundsControl.cs b/UoFiddler.Controls/UserControls/SoundsControl.cs
index 81dfafd5..90b1da31 100644
--- a/UoFiddler.Controls/UserControls/SoundsControl.cs
+++ b/UoFiddler.Controls/UserControls/SoundsControl.cs
@@ -474,8 +474,7 @@ private void OnClickExportSoundListCsv(object sender, EventArgs e)
Sounds.SaveSoundListToCsv(fileName, _soundIdOffset);
- MessageBox.Show($"SoundList saved to {fileName}", "Saved", MessageBoxButtons.OK, MessageBoxIcon.Information,
- MessageBoxDefaultButton.Button1);
+ FileSavedDialog.Show(FindForm(), fileName, "SoundList saved successfully.");
}
public bool SearchId(int id)
diff --git a/UoFiddler.Controls/UserControls/SpeechControl.cs b/UoFiddler.Controls/UserControls/SpeechControl.cs
index 07a2c58f..f25b67bf 100644
--- a/UoFiddler.Controls/UserControls/SpeechControl.cs
+++ b/UoFiddler.Controls/UserControls/SpeechControl.cs
@@ -352,8 +352,7 @@ private void OnClickExport(object sender, EventArgs e)
SpeechList.ExportToCsv(fileName);
- MessageBox.Show($"Speech saved to {fileName}", "Saved", MessageBoxButtons.OK, MessageBoxIcon.Information,
- MessageBoxDefaultButton.Button1);
+ FileSavedDialog.Show(FindForm(), fileName, "Speech saved successfully.");
}
private void OnClickImport(object sender, EventArgs e)
diff --git a/UoFiddler.Plugin.Compare/UserControls/CompareGumpControl.cs b/UoFiddler.Plugin.Compare/UserControls/CompareGumpControl.cs
index ec66eeac..7708e66b 100644
--- a/UoFiddler.Plugin.Compare/UserControls/CompareGumpControl.cs
+++ b/UoFiddler.Plugin.Compare/UserControls/CompareGumpControl.cs
@@ -18,6 +18,7 @@
using System.Windows.Forms;
using Ultima;
using UoFiddler.Controls.Classes;
+using UoFiddler.Controls.Forms;
using UoFiddler.Controls.UserControls.TileView;
using UoFiddler.Plugin.Compare.Classes;
@@ -326,8 +327,8 @@ private void Export_Bmp(object sender, EventArgs e)
string path = Options.OutputPath;
string fileName = Path.Combine(path, $"Gump(Sec) 0x{i:X}.bmp");
SecondGump.GetGump(i).Save(fileName, ImageFormat.Bmp);
- MessageBox.Show($"Gump saved to {fileName}", "Saved",
- MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1);
+
+ FileSavedDialog.Show(FindForm(), fileName, "Gump saved successfully.");
}
private void Export_Tiff(object sender, EventArgs e)
@@ -347,8 +348,8 @@ private void Export_Tiff(object sender, EventArgs e)
string path = Options.OutputPath;
string fileName = Path.Combine(path, $"Gump(Sec) 0x{i:X}.tiff");
SecondGump.GetGump(i).Save(fileName, ImageFormat.Tiff);
- MessageBox.Show($"Gump saved to {fileName}", "Saved",
- MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1);
+
+ FileSavedDialog.Show(FindForm(), fileName, "Gump saved successfully.");
}
private void OnClickCopy(object sender, EventArgs e)
diff --git a/UoFiddler.Plugin.Compare/UserControls/CompareItemControl.cs b/UoFiddler.Plugin.Compare/UserControls/CompareItemControl.cs
index 2a002612..45bdc16f 100644
--- a/UoFiddler.Plugin.Compare/UserControls/CompareItemControl.cs
+++ b/UoFiddler.Plugin.Compare/UserControls/CompareItemControl.cs
@@ -18,6 +18,7 @@
using System.Windows.Forms;
using Ultima;
using UoFiddler.Controls.Classes;
+using UoFiddler.Controls.Forms;
using UoFiddler.Controls.UserControls.TileView;
using UoFiddler.Plugin.Compare.Classes;
@@ -298,8 +299,8 @@ private void ExportAsBmp(object sender, EventArgs e)
string fileName = Path.Combine(Options.OutputPath, $"Item(Sec) 0x{i:X}.bmp");
SecondArt.GetStatic(i).Save(fileName, ImageFormat.Bmp);
- MessageBox.Show($"Item saved to {fileName}", "Saved",
- MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1);
+
+ FileSavedDialog.Show(FindForm(), fileName, "Item saved successfully.");
}
private void ExportAsTiff(object sender, EventArgs e)
@@ -318,8 +319,7 @@ private void ExportAsTiff(object sender, EventArgs e)
string fileName = Path.Combine(Options.OutputPath, $"Item(Sec) 0x{i:X}.tiff");
SecondArt.GetStatic(i).Save(fileName, ImageFormat.Tiff);
- MessageBox.Show($"Item saved to {fileName}", "Saved",
- MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1);
+ FileSavedDialog.Show(FindForm(), fileName, "Item saved successfully.");
}
private void OnClickCopy(object sender, EventArgs e)
diff --git a/UoFiddler.Plugin.Compare/UserControls/CompareLandControl.cs b/UoFiddler.Plugin.Compare/UserControls/CompareLandControl.cs
index 961172d1..f3cd8c73 100644
--- a/UoFiddler.Plugin.Compare/UserControls/CompareLandControl.cs
+++ b/UoFiddler.Plugin.Compare/UserControls/CompareLandControl.cs
@@ -18,6 +18,7 @@
using System.Windows.Forms;
using Ultima;
using UoFiddler.Controls.Classes;
+using UoFiddler.Controls.Forms;
using UoFiddler.Controls.UserControls.TileView;
using UoFiddler.Plugin.Compare.Classes;
@@ -263,8 +264,8 @@ private void ExportAsBmp(object sender, EventArgs e)
string fileName = Path.Combine(Options.OutputPath, $"Landtile(Sec) 0x{i:X}.bmp");
SecondArt.GetLand(i).Save(fileName, ImageFormat.Bmp);
- MessageBox.Show($"Landtile saved to {fileName}", "Saved",
- MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1);
+
+ FileSavedDialog.Show(FindForm(), fileName, "Landtile saved successfully.");
}
private void ExportAsTiff(object sender, EventArgs e)
@@ -283,8 +284,7 @@ private void ExportAsTiff(object sender, EventArgs e)
string fileName = Path.Combine(Options.OutputPath, $"Landtile(Sec) 0x{i:X}.tiff");
SecondArt.GetLand(i).Save(fileName, ImageFormat.Tiff);
- MessageBox.Show($"Landtile saved to {fileName}", "Saved",
- MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1);
+ FileSavedDialog.Show(FindForm(), fileName, "Landtile saved successfully.");
}
private void BrowseOnClick(object sender, EventArgs e)
diff --git a/UoFiddler.Plugin.Compare/UserControls/CompareTextureControl.cs b/UoFiddler.Plugin.Compare/UserControls/CompareTextureControl.cs
index fcf70b5b..922493fb 100644
--- a/UoFiddler.Plugin.Compare/UserControls/CompareTextureControl.cs
+++ b/UoFiddler.Plugin.Compare/UserControls/CompareTextureControl.cs
@@ -18,6 +18,7 @@
using System.Windows.Forms;
using Ultima;
using UoFiddler.Controls.Classes;
+using UoFiddler.Controls.Forms;
using UoFiddler.Controls.UserControls.TileView;
using UoFiddler.Plugin.Compare.Classes;
@@ -252,8 +253,7 @@ private void ExportAsBmp(object sender, EventArgs e)
string fileName = Path.Combine(Options.OutputPath, $"Texture(Sec) 0x{i:X}.bmp");
SecondTexture.GetTexture(i).Save(fileName, ImageFormat.Bmp);
- MessageBox.Show($"Texture saved to {fileName}", "Saved",
- MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1);
+ FileSavedDialog.Show(FindForm(), fileName, "Texture saved successfully.");
}
private void ExportAsTiff(object sender, EventArgs e)
@@ -272,8 +272,7 @@ private void ExportAsTiff(object sender, EventArgs e)
string fileName = Path.Combine(Options.OutputPath, $"Texture(Sec) 0x{i:X}.tiff");
SecondTexture.GetTexture(i).Save(fileName, ImageFormat.Tiff);
- MessageBox.Show($"Texture saved to {fileName}", "Saved",
- MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1);
+ FileSavedDialog.Show(FindForm(), fileName, "Texture saved successfully.");
}
private void BrowseOnClick(object sender, EventArgs e)
diff --git a/UoFiddler.Plugin.MassImport/Forms/MassImportForm.cs b/UoFiddler.Plugin.MassImport/Forms/MassImportForm.cs
index 1e573761..16f7dfb2 100644
--- a/UoFiddler.Plugin.MassImport/Forms/MassImportForm.cs
+++ b/UoFiddler.Plugin.MassImport/Forms/MassImportForm.cs
@@ -16,6 +16,7 @@
using System.Windows.Forms;
using System.Xml;
using UoFiddler.Controls.Classes;
+using UoFiddler.Controls.Forms;
using UoFiddler.Plugin.MassImport.Imports;
namespace UoFiddler.Plugin.MassImport.Forms
@@ -121,8 +122,8 @@ private void DefaultXMLOnClick(object sender, EventArgs e)
dom.AppendChild(sr);
dom.Save(fileName);
- MessageBox.Show($"Default xml saved to {fileName}", "Saved", MessageBoxButtons.OK,
- MessageBoxIcon.Information, MessageBoxDefaultButton.Button1);
+
+ FileSavedDialog.Show(FindForm(), fileName, "Default xml saved successfully.");
}
private readonly List _importList;
@@ -254,7 +255,6 @@ private void LoadXMLOnClick(object sender, EventArgs e)
{
button3.Enabled = true;
}
-
}
private void StartOnClick(object sender, EventArgs e)
diff --git a/UoFiddler.Plugin.MultiEditor/UserControls/MultiEditorControl.cs b/UoFiddler.Plugin.MultiEditor/UserControls/MultiEditorControl.cs
index d9b17111..0c37556a 100644
--- a/UoFiddler.Plugin.MultiEditor/UserControls/MultiEditorControl.cs
+++ b/UoFiddler.Plugin.MultiEditor/UserControls/MultiEditorControl.cs
@@ -18,6 +18,7 @@
using System.Xml;
using Ultima;
using UoFiddler.Controls.Classes;
+using UoFiddler.Controls.Forms;
using UoFiddler.Plugin.MultiEditor.Classes;
using UoFiddler.Plugin.MultiEditor.Forms;
@@ -265,8 +266,7 @@ private void DoExport(Multis.ImportType type)
break;
}
- MessageBox.Show($"Multi design saved to {fileName}", "Saved", MessageBoxButtons.OK,
- MessageBoxIcon.Information, MessageBoxDefaultButton.Button1);
+ FileSavedDialog.Show(FindForm(), fileName, "Multi design saved successfully.");
}
private void BTN_Export_TXT_OnClick(object sender, EventArgs e)
From e4392277b216b9e033e099cf95507f716c3f0616 Mon Sep 17 00:00:00 2001
From: AsY!um- <377468+AsYlum-@users.noreply.github.com>
Date: Fri, 24 Apr 2026 18:55:30 +0200
Subject: [PATCH 4/6] Remeber selected file type for `Add frame` in
AnimationEditForm. #82
---
UoFiddler.Controls/Forms/AnimationEditForm.cs | 3 +++
1 file changed, 3 insertions(+)
diff --git a/UoFiddler.Controls/Forms/AnimationEditForm.cs b/UoFiddler.Controls/Forms/AnimationEditForm.cs
index f2fc4994..22b2e650 100644
--- a/UoFiddler.Controls/Forms/AnimationEditForm.cs
+++ b/UoFiddler.Controls/Forms/AnimationEditForm.cs
@@ -34,6 +34,7 @@ public partial class AnimationEditForm : Form
private bool _showOnlyValid;
private static bool _drawEmpty;
private static bool _drawFull;
+ private static int _lastAddFilterIndex = 1;
private static readonly Color _whiteConvert = Color.FromArgb(255, 255, 255, 255);
private static readonly Pen _blackUnDrawTransparent = new Pen(Color.FromArgb(0, 0, 0, 0), 1);
@@ -846,9 +847,11 @@ private void OnClickAdd(object sender, EventArgs e)
dialog.Title = "Choose image file to add";
dialog.CheckFileExists = true;
dialog.Filter = "Gif files (*.gif;)|*.gif; |Bitmap files (*.bmp;)|*.bmp; |Tiff files (*.tif;*.tiff)|*.tif;*.tiff; |Png files (*.png;)|*.png; |Jpeg files (*.jpeg;*.jpg;)|*.jpeg;*.jpg;";
+ dialog.FilterIndex = _lastAddFilterIndex;
if (dialog.ShowDialog() == DialogResult.OK)
{
+ _lastAddFilterIndex = dialog.FilterIndex;
FramesListView.BeginUpdate();
try
{
From 3e6159655902b6ab7f6de5ec7638990f489421f2 Mon Sep 17 00:00:00 2001
From: AsY!um- <377468+AsYlum-@users.noreply.github.com>
Date: Fri, 24 Apr 2026 22:46:45 +0200
Subject: [PATCH 5/6] UopPacker improvements - MultiCollection.uop save and UI
updates.
---
.../Classes/LegacyMulFileConverter.cs | 126 +++++++-
.../UserControls/UopPackerControl.Designer.cs | 290 ++++++++++--------
.../UserControls/UopPackerControl.cs | 275 +++++++++++++----
3 files changed, 501 insertions(+), 190 deletions(-)
diff --git a/UoFiddler.Plugin.UopPacker/Classes/LegacyMulFileConverter.cs b/UoFiddler.Plugin.UopPacker/Classes/LegacyMulFileConverter.cs
index 91e6aad8..21e437e2 100644
--- a/UoFiddler.Plugin.UopPacker/Classes/LegacyMulFileConverter.cs
+++ b/UoFiddler.Plugin.UopPacker/Classes/LegacyMulFileConverter.cs
@@ -47,10 +47,16 @@ private static BinaryWriter OpenOutput(string path)
: new BinaryWriter(new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None));
}
+ // Identifier for "build/multicollection/housing.bin" inside MultiCollection.uop.
+ private const ulong _housingBinIdentifier = 0x126D1E99DDEDEE0A;
+
+ // Sentinel Id used to mark a synthetic entry that should be written from housing.bin.
+ private const int _housingBinSentinelId = -1;
+
//
// MUL -> UOP
//
- public static void ToUop(string inFile, string inFileIdx, string outFile, FileType type, int typeIndex, CompressionFlag compressionFlag = CompressionFlag.None)
+ public static void ToUop(string inFile, string inFileIdx, string outFile, FileType type, int typeIndex, CompressionFlag compressionFlag = CompressionFlag.None, string housingBinFile = "")
{
// Same for all UOP files
const long firstTable = 0x200;
@@ -121,6 +127,17 @@ public static void ToUop(string inFile, string inFileIdx, string outFile, FileTy
}
}
+ if (type == FileType.MultiCollection && !string.IsNullOrWhiteSpace(housingBinFile) && File.Exists(housingBinFile))
+ {
+ idxEntries.Add(new IdxEntry
+ {
+ Id = _housingBinSentinelId,
+ Offset = 0,
+ Size = 0,
+ Extra = 0
+ });
+ }
+
// File header
writer.Write(0x50594D); // MYP
writer.Write(type == FileType.GumpartLegacyMul ? 4 : 5); // version
@@ -163,8 +180,17 @@ public static void ToUop(string inFile, string inFileIdx, string outFile, FileTy
for (int j = idxStart; j < idxEnd; ++j, ++tableIdx)
{
- reader.BaseStream.Seek(idxEntries[j].Offset, SeekOrigin.Begin);
- byte[] data = reader.ReadBytes(idxEntries[j].Size);
+ byte[] data;
+
+ if (type == FileType.MultiCollection && idxEntries[j].Id == _housingBinSentinelId)
+ {
+ data = File.ReadAllBytes(housingBinFile);
+ }
+ else
+ {
+ reader.BaseStream.Seek(idxEntries[j].Offset, SeekOrigin.Begin);
+ data = reader.ReadBytes(idxEntries[j].Size);
+ }
tableEntries[tableIdx].Offset = writer.BaseStream.Position;
tableEntries[tableIdx].DecompressedSize = data.Length;
@@ -177,12 +203,37 @@ public static void ToUop(string inFile, string inFileIdx, string outFile, FileTy
{
tableEntries[tableIdx].Identifier = HashLittle2(string.Format(hashFormat[1], idxEntries[j].Id));
}
+ else if (type == FileType.MultiCollection && idxEntries[j].Id == _housingBinSentinelId)
+ {
+ tableEntries[tableIdx].Identifier = _housingBinIdentifier;
+ }
else
{
tableEntries[tableIdx].Identifier = HashLittle2(string.Format(hashFormat[0], idxEntries[j].Id));
}
- if (type == FileType.GumpartLegacyMul)
+ if (type == FileType.MultiCollection && idxEntries[j].Id != _housingBinSentinelId)
+ {
+ byte[] multiData = BuildMultiUopEntryFromMul(data, idxEntries[j].Id);
+
+ tableEntries[tableIdx].DecompressedSize = multiData.Length;
+ tableEntries[tableIdx].Size = multiData.Length;
+
+ if (compressionFlag >= CompressionFlag.Zlib)
+ {
+ var result = UopUtils.Compress(multiData);
+ if (!result.success)
+ {
+ return;
+ }
+ multiData = result.compressedData;
+ tableEntries[tableIdx].Size = multiData.Length;
+ }
+
+ tableEntries[tableIdx].Hash = HashAdler32(multiData);
+ writer.Write(multiData);
+ }
+ else if (type == FileType.GumpartLegacyMul)
{
byte[] gumpArtData = new byte[data.Length + 8];
using (MemoryStream ms = new MemoryStream(gumpArtData))
@@ -231,6 +282,26 @@ public static void ToUop(string inFile, string inFileIdx, string outFile, FileTy
tableEntries[tableIdx].Hash = HashAdler32(gumpArtData);
writer.Write(gumpArtData);
}
+ else if (type == FileType.MultiCollection && idxEntries[j].Id == _housingBinSentinelId)
+ {
+ byte[] binData = data;
+ tableEntries[tableIdx].DecompressedSize = binData.Length;
+ tableEntries[tableIdx].Size = binData.Length;
+
+ if (compressionFlag >= CompressionFlag.Zlib)
+ {
+ var result = UopUtils.Compress(binData);
+ if (!result.success)
+ {
+ return;
+ }
+ binData = result.compressedData;
+ tableEntries[tableIdx].Size = binData.Length;
+ }
+
+ tableEntries[tableIdx].Hash = HashAdler32(binData);
+ writer.Write(binData);
+ }
else
{
tableEntries[tableIdx].Size = data.Length;
@@ -311,7 +382,7 @@ public void FromUop(string inFile, string outFile, string outFileIdx, FileType t
{
if (reader.ReadInt32() != 0x50594D) // MYP
{
- throw new ArgumentException("inFile is not a UOP file.");
+ throw new ArgumentException("Input file is not a UOP file.");
}
Stream stream = reader.BaseStream;
@@ -582,7 +653,7 @@ private static string[] GetHashFormat(FileType type, int typeIndex, out int maxI
}
case FileType.MultiCollection:
{
- maxId = 0x2200; // seems like this is reasonable limit for multis
+ maxId = 0x2710; // newer clients add multis past 0x2200 (e.g. 9000); keep generous for future entries
return ["build/multicollection/{0:000000}.bin", string.Empty];
}
default:
@@ -704,5 +775,48 @@ private static void WriteMultiUopEntryToMul(BinaryWriter mulWriter, byte[] chunk
mulWriter.Write(0);
}
}
+
+ // MUL row layout: [itemId:2][x:2][y:2][z:2][flag:4][extra:4] = 16 bytes
+ // UOP component: [itemId:2][x:2][y:2][z:2][flag:2][clilocsCount:4] = 14 bytes
+ private static byte[] BuildMultiUopEntryFromMul(byte[] mulData, int multiId)
+ {
+ const int mulRowSize = 16;
+ const int uopComponentSize = 14;
+
+ int componentCount = mulData.Length / mulRowSize;
+ byte[] result = new byte[8 + componentCount * uopComponentSize];
+
+ Span dst = result.AsSpan();
+ BinaryPrimitives.WriteUInt32LittleEndian(dst, (uint)multiId);
+ BinaryPrimitives.WriteUInt32LittleEndian(dst[4..], (uint)componentCount);
+ dst = dst[8..];
+
+ ReadOnlySpan src = mulData.AsSpan();
+
+ for (int i = 0; i < componentCount; i++)
+ {
+ ushort itemId = BinaryPrimitives.ReadUInt16LittleEndian(src);
+ short x = BinaryPrimitives.ReadInt16LittleEndian(src[2..]);
+ short y = BinaryPrimitives.ReadInt16LittleEndian(src[4..]);
+ short z = BinaryPrimitives.ReadInt16LittleEndian(src[6..]);
+ int mulFlag = BinaryPrimitives.ReadInt32LittleEndian(src[8..]);
+ // extra int32 at src[12..16] is discarded
+
+ // Inverse of WriteMultiUopEntryToMul: mul==1 -> visible (uop flag 0), otherwise invisible (uop flag 1).
+ ushort uopFlag = (ushort)(mulFlag == 1 ? 0 : 1);
+
+ BinaryPrimitives.WriteUInt16LittleEndian(dst, itemId);
+ BinaryPrimitives.WriteInt16LittleEndian(dst[2..], x);
+ BinaryPrimitives.WriteInt16LittleEndian(dst[4..], y);
+ BinaryPrimitives.WriteInt16LittleEndian(dst[6..], z);
+ BinaryPrimitives.WriteUInt16LittleEndian(dst[8..], uopFlag);
+ BinaryPrimitives.WriteUInt32LittleEndian(dst[10..], 0u); // clilocsCount
+
+ src = src[mulRowSize..];
+ dst = dst[uopComponentSize..];
+ }
+
+ return result;
+ }
}
}
diff --git a/UoFiddler.Plugin.UopPacker/UserControls/UopPackerControl.Designer.cs b/UoFiddler.Plugin.UopPacker/UserControls/UopPackerControl.Designer.cs
index ab82e360..806c13f1 100644
--- a/UoFiddler.Plugin.UopPacker/UserControls/UopPackerControl.Designer.cs
+++ b/UoFiddler.Plugin.UopPacker/UserControls/UopPackerControl.Designer.cs
@@ -46,15 +46,19 @@ private void InitializeComponent()
label3 = new System.Windows.Forms.Label();
inmulbtn = new System.Windows.Forms.Button();
inidxbtn = new System.Windows.Forms.Button();
+ inhousingbin = new System.Windows.Forms.TextBox();
+ inhousingbinbtn = new System.Windows.Forms.Button();
+ labelHousingBin = new System.Windows.Forms.Label();
multouop = new System.Windows.Forms.Button();
FileDialog = new System.Windows.Forms.OpenFileDialog();
- outuop = new System.Windows.Forms.TextBox();
+ outuopfolder = new System.Windows.Forms.TextBox();
+ outputUopFileLabel = new System.Windows.Forms.Label();
label7 = new System.Windows.Forms.Label();
multype = new System.Windows.Forms.ComboBox();
label4 = new System.Windows.Forms.Label();
label5 = new System.Windows.Forms.Label();
mulMapIndex = new System.Windows.Forms.NumericUpDown();
- outuopbtn = new System.Windows.Forms.Button();
+ outuopfolderbtn = new System.Windows.Forms.Button();
inuopbtn = new System.Windows.Forms.Button();
uopMapIndex = new System.Windows.Forms.NumericUpDown();
label6 = new System.Windows.Forms.Label();
@@ -63,11 +67,9 @@ private void InitializeComponent()
inuop = new System.Windows.Forms.TextBox();
label9 = new System.Windows.Forms.Label();
uoptomul = new System.Windows.Forms.Button();
- outidxbtn = new System.Windows.Forms.Button();
- outmulbtn = new System.Windows.Forms.Button();
- outidx = new System.Windows.Forms.TextBox();
- label10 = new System.Windows.Forms.Label();
- outmul = new System.Windows.Forms.TextBox();
+ outfolderbtn = new System.Windows.Forms.Button();
+ outputFilesLabel = new System.Windows.Forms.Label();
+ outfolder = new System.Windows.Forms.TextBox();
label11 = new System.Windows.Forms.Label();
label12 = new System.Windows.Forms.Label();
OperationTypeTabControl = new System.Windows.Forms.TabControl();
@@ -115,7 +117,7 @@ private void InitializeComponent()
// label2
//
label2.AutoSize = true;
- label2.Location = new System.Drawing.Point(35, 42);
+ label2.Location = new System.Drawing.Point(47, 72);
label2.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
label2.Name = "label2";
label2.Size = new System.Drawing.Size(63, 15);
@@ -125,25 +127,25 @@ private void InitializeComponent()
// inmul
//
inmul.BackColor = System.Drawing.Color.White;
- inmul.Location = new System.Drawing.Point(118, 38);
+ inmul.Location = new System.Drawing.Point(118, 68);
inmul.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
inmul.Name = "inmul";
inmul.Size = new System.Drawing.Size(241, 23);
- inmul.TabIndex = 2;
+ inmul.TabIndex = 1;
//
// inidx
//
inidx.BackColor = System.Drawing.Color.White;
- inidx.Location = new System.Drawing.Point(118, 68);
+ inidx.Location = new System.Drawing.Point(118, 98);
inidx.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
inidx.Name = "inidx";
inidx.Size = new System.Drawing.Size(241, 23);
- inidx.TabIndex = 4;
+ inidx.TabIndex = 3;
//
// label3
//
label3.AutoSize = true;
- label3.Location = new System.Drawing.Point(35, 72);
+ label3.Location = new System.Drawing.Point(54, 102);
label3.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
label3.Name = "label3";
label3.Size = new System.Drawing.Size(56, 15);
@@ -152,33 +154,63 @@ private void InitializeComponent()
//
// inmulbtn
//
- inmulbtn.Location = new System.Drawing.Point(366, 38);
+ inmulbtn.Location = new System.Drawing.Point(366, 68);
inmulbtn.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
inmulbtn.Name = "inmulbtn";
inmulbtn.Size = new System.Drawing.Size(31, 23);
- inmulbtn.TabIndex = 5;
+ inmulbtn.TabIndex = 2;
inmulbtn.Text = "...";
inmulbtn.UseVisualStyleBackColor = true;
inmulbtn.Click += InputMulSelect;
//
// inidxbtn
//
- inidxbtn.Location = new System.Drawing.Point(366, 68);
+ inidxbtn.Location = new System.Drawing.Point(366, 98);
inidxbtn.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
inidxbtn.Name = "inidxbtn";
inidxbtn.Size = new System.Drawing.Size(31, 23);
- inidxbtn.TabIndex = 6;
+ inidxbtn.TabIndex = 4;
inidxbtn.Text = "...";
inidxbtn.UseVisualStyleBackColor = true;
inidxbtn.Click += InputIdxSelect;
//
+ // inhousingbin
+ //
+ inhousingbin.BackColor = System.Drawing.Color.White;
+ inhousingbin.Location = new System.Drawing.Point(118, 128);
+ inhousingbin.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
+ inhousingbin.Name = "inhousingbin";
+ inhousingbin.Size = new System.Drawing.Size(241, 23);
+ inhousingbin.TabIndex = 5;
+ //
+ // inhousingbinbtn
+ //
+ inhousingbinbtn.Location = new System.Drawing.Point(366, 128);
+ inhousingbinbtn.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
+ inhousingbinbtn.Name = "inhousingbinbtn";
+ inhousingbinbtn.Size = new System.Drawing.Size(31, 23);
+ inhousingbinbtn.TabIndex = 6;
+ inhousingbinbtn.Text = "...";
+ inhousingbinbtn.UseVisualStyleBackColor = true;
+ inhousingbinbtn.Click += InputHousingBinSelect;
+ //
+ // labelHousingBin
+ //
+ labelHousingBin.AutoSize = true;
+ labelHousingBin.Location = new System.Drawing.Point(9, 132);
+ labelHousingBin.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
+ labelHousingBin.Name = "labelHousingBin";
+ labelHousingBin.Size = new System.Drawing.Size(101, 15);
+ labelHousingBin.TabIndex = 43;
+ labelHousingBin.Text = "Input housing.bin";
+ //
// multouop
//
multouop.Location = new System.Drawing.Point(405, 38);
multouop.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
multouop.Name = "multouop";
- multouop.Size = new System.Drawing.Size(102, 150);
- multouop.TabIndex = 7;
+ multouop.Size = new System.Drawing.Size(102, 173);
+ multouop.TabIndex = 11;
multouop.Text = "Convert";
multouop.UseVisualStyleBackColor = true;
multouop.Click += ToUop;
@@ -186,41 +218,51 @@ private void InitializeComponent()
// FileDialog
//
FileDialog.CheckFileExists = false;
- FileDialog.Filter = "MUL|*.mul|UOP|*.uop|IDX|*.idx";
+ FileDialog.Filter = "MUL|*.mul|UOP|*.uop|IDX|*.idx|BIN|*.bin";
+ //
+ // outuopfolder
//
- // outuop
+ outuopfolder.BackColor = System.Drawing.Color.White;
+ outuopfolder.Location = new System.Drawing.Point(118, 188);
+ outuopfolder.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
+ outuopfolder.Name = "outuopfolder";
+ outuopfolder.Size = new System.Drawing.Size(241, 23);
+ outuopfolder.TabIndex = 9;
//
- outuop.BackColor = System.Drawing.Color.White;
- outuop.Location = new System.Drawing.Point(118, 165);
- outuop.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
- outuop.Name = "outuop";
- outuop.Size = new System.Drawing.Size(241, 23);
- outuop.TabIndex = 17;
+ // outputUopFileLabel
+ //
+ outputUopFileLabel.AutoSize = true;
+ outputUopFileLabel.ForeColor = System.Drawing.SystemColors.GrayText;
+ outputUopFileLabel.Location = new System.Drawing.Point(118, 215);
+ outputUopFileLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
+ outputUopFileLabel.Name = "outputUopFileLabel";
+ outputUopFileLabel.Size = new System.Drawing.Size(0, 15);
+ outputUopFileLabel.TabIndex = 45;
//
// label7
//
label7.AutoSize = true;
- label7.Location = new System.Drawing.Point(35, 168);
+ label7.Location = new System.Drawing.Point(31, 192);
label7.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
label7.Name = "label7";
- label7.Size = new System.Drawing.Size(72, 15);
+ label7.Size = new System.Drawing.Size(79, 15);
label7.TabIndex = 16;
- label7.Text = "Output UOP";
+ label7.Text = "Output folder";
//
// multype
//
multype.BackColor = System.Drawing.Color.White;
- multype.Location = new System.Drawing.Point(118, 99);
+ multype.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
+ multype.Location = new System.Drawing.Point(118, 38);
multype.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
multype.Name = "multype";
multype.Size = new System.Drawing.Size(241, 23);
- multype.TabIndex = 19;
- multype.Text = "File Type";
+ multype.TabIndex = 0;
//
// label4
//
label4.AutoSize = true;
- label4.Location = new System.Drawing.Point(35, 103);
+ label4.Location = new System.Drawing.Point(49, 41);
label4.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
label4.Name = "label4";
label4.Size = new System.Drawing.Size(61, 15);
@@ -230,7 +272,7 @@ private void InitializeComponent()
// label5
//
label5.AutoSize = true;
- label5.Location = new System.Drawing.Point(35, 137);
+ label5.Location = new System.Drawing.Point(54, 161);
label5.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
label5.Name = "label5";
label5.Size = new System.Drawing.Size(56, 15);
@@ -240,32 +282,32 @@ private void InitializeComponent()
// mulMapIndex
//
mulMapIndex.BackColor = System.Drawing.Color.White;
- mulMapIndex.Location = new System.Drawing.Point(118, 135);
+ mulMapIndex.Location = new System.Drawing.Point(118, 158);
mulMapIndex.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
mulMapIndex.Maximum = new decimal(new int[] { 5, 0, 0, 0 });
mulMapIndex.Name = "mulMapIndex";
mulMapIndex.ReadOnly = true;
mulMapIndex.Size = new System.Drawing.Size(42, 23);
- mulMapIndex.TabIndex = 22;
+ mulMapIndex.TabIndex = 7;
//
- // outuopbtn
+ // outuopfolderbtn
//
- outuopbtn.Location = new System.Drawing.Point(366, 165);
- outuopbtn.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
- outuopbtn.Name = "outuopbtn";
- outuopbtn.Size = new System.Drawing.Size(31, 23);
- outuopbtn.TabIndex = 23;
- outuopbtn.Text = "...";
- outuopbtn.UseVisualStyleBackColor = true;
- outuopbtn.Click += OutputUopSelect;
+ outuopfolderbtn.Location = new System.Drawing.Point(366, 188);
+ outuopfolderbtn.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
+ outuopfolderbtn.Name = "outuopfolderbtn";
+ outuopfolderbtn.Size = new System.Drawing.Size(31, 23);
+ outuopfolderbtn.TabIndex = 10;
+ outuopfolderbtn.Text = "...";
+ outuopfolderbtn.UseVisualStyleBackColor = true;
+ outuopfolderbtn.Click += OutputUopFolderSelect;
//
// inuopbtn
//
- inuopbtn.Location = new System.Drawing.Point(366, 365);
+ inuopbtn.Location = new System.Drawing.Point(367, 326);
inuopbtn.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
inuopbtn.Name = "inuopbtn";
inuopbtn.Size = new System.Drawing.Size(31, 23);
- inuopbtn.TabIndex = 39;
+ inuopbtn.TabIndex = 14;
inuopbtn.Text = "...";
inuopbtn.UseVisualStyleBackColor = true;
inuopbtn.Click += InputUopSelect;
@@ -273,18 +315,18 @@ private void InitializeComponent()
// uopMapIndex
//
uopMapIndex.BackColor = System.Drawing.Color.White;
- uopMapIndex.Location = new System.Drawing.Point(118, 335);
+ uopMapIndex.Location = new System.Drawing.Point(118, 297);
uopMapIndex.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
uopMapIndex.Maximum = new decimal(new int[] { 5, 0, 0, 0 });
uopMapIndex.Name = "uopMapIndex";
uopMapIndex.ReadOnly = true;
uopMapIndex.Size = new System.Drawing.Size(42, 23);
- uopMapIndex.TabIndex = 38;
+ uopMapIndex.TabIndex = 17;
//
// label6
//
label6.AutoSize = true;
- label6.Location = new System.Drawing.Point(35, 337);
+ label6.Location = new System.Drawing.Point(54, 299);
label6.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
label6.Name = "label6";
label6.Size = new System.Drawing.Size(56, 15);
@@ -294,7 +336,7 @@ private void InitializeComponent()
// label8
//
label8.AutoSize = true;
- label8.Location = new System.Drawing.Point(35, 302);
+ label8.Location = new System.Drawing.Point(49, 271);
label8.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
label8.Name = "label8";
label8.Size = new System.Drawing.Size(61, 15);
@@ -304,27 +346,27 @@ private void InitializeComponent()
// uoptype
//
uoptype.BackColor = System.Drawing.Color.White;
+ uoptype.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
uoptype.FormattingEnabled = true;
- uoptype.Location = new System.Drawing.Point(118, 299);
+ uoptype.Location = new System.Drawing.Point(118, 268);
uoptype.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
uoptype.Name = "uoptype";
uoptype.Size = new System.Drawing.Size(241, 23);
- uoptype.TabIndex = 35;
- uoptype.Text = "File Type";
+ uoptype.TabIndex = 12;
//
// inuop
//
inuop.BackColor = System.Drawing.Color.White;
- inuop.Location = new System.Drawing.Point(118, 365);
+ inuop.Location = new System.Drawing.Point(118, 326);
inuop.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
inuop.Name = "inuop";
inuop.Size = new System.Drawing.Size(241, 23);
- inuop.TabIndex = 33;
+ inuop.TabIndex = 13;
//
// label9
//
label9.AutoSize = true;
- label9.Location = new System.Drawing.Point(35, 368);
+ label9.Location = new System.Drawing.Point(48, 329);
label9.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
label9.Name = "label9";
label9.Size = new System.Drawing.Size(62, 15);
@@ -333,79 +375,59 @@ private void InitializeComponent()
//
// uoptomul
//
- uoptomul.Location = new System.Drawing.Point(405, 238);
+ uoptomul.Location = new System.Drawing.Point(406, 268);
uoptomul.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
uoptomul.Name = "uoptomul";
- uoptomul.Size = new System.Drawing.Size(102, 150);
- uoptomul.TabIndex = 31;
+ uoptomul.Size = new System.Drawing.Size(102, 110);
+ uoptomul.TabIndex = 18;
uoptomul.Text = "Convert";
uoptomul.UseVisualStyleBackColor = true;
uoptomul.Click += ToMul;
//
- // outidxbtn
- //
- outidxbtn.Location = new System.Drawing.Point(366, 268);
- outidxbtn.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
- outidxbtn.Name = "outidxbtn";
- outidxbtn.Size = new System.Drawing.Size(31, 23);
- outidxbtn.TabIndex = 30;
- outidxbtn.Text = "...";
- outidxbtn.UseVisualStyleBackColor = true;
- outidxbtn.Click += OutputIdxSelect;
- //
- // outmulbtn
- //
- outmulbtn.Location = new System.Drawing.Point(366, 238);
- outmulbtn.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
- outmulbtn.Name = "outmulbtn";
- outmulbtn.Size = new System.Drawing.Size(31, 23);
- outmulbtn.TabIndex = 29;
- outmulbtn.Text = "...";
- outmulbtn.UseVisualStyleBackColor = true;
- outmulbtn.Click += OutMulSelect;
- //
- // outidx
- //
- outidx.BackColor = System.Drawing.Color.White;
- outidx.Location = new System.Drawing.Point(118, 268);
- outidx.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
- outidx.Name = "outidx";
- outidx.Size = new System.Drawing.Size(241, 23);
- outidx.TabIndex = 28;
- //
- // label10
- //
- label10.AutoSize = true;
- label10.Location = new System.Drawing.Point(35, 271);
- label10.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
- label10.Name = "label10";
- label10.Size = new System.Drawing.Size(66, 15);
- label10.TabIndex = 27;
- label10.Text = "Output IDX";
- //
- // outmul
- //
- outmul.BackColor = System.Drawing.Color.White;
- outmul.Location = new System.Drawing.Point(118, 238);
- outmul.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
- outmul.Name = "outmul";
- outmul.Size = new System.Drawing.Size(241, 23);
- outmul.TabIndex = 26;
+ // outfolderbtn
+ //
+ outfolderbtn.Location = new System.Drawing.Point(367, 355);
+ outfolderbtn.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
+ outfolderbtn.Name = "outfolderbtn";
+ outfolderbtn.Size = new System.Drawing.Size(31, 23);
+ outfolderbtn.TabIndex = 16;
+ outfolderbtn.Text = "...";
+ outfolderbtn.UseVisualStyleBackColor = true;
+ outfolderbtn.Click += OutFolderSelect;
+ //
+ // outputFilesLabel
+ //
+ outputFilesLabel.AutoSize = true;
+ outputFilesLabel.ForeColor = System.Drawing.SystemColors.GrayText;
+ outputFilesLabel.Location = new System.Drawing.Point(118, 357);
+ outputFilesLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
+ outputFilesLabel.Name = "outputFilesLabel";
+ outputFilesLabel.Size = new System.Drawing.Size(0, 15);
+ outputFilesLabel.TabIndex = 44;
+ //
+ // outfolder
+ //
+ outfolder.BackColor = System.Drawing.Color.White;
+ outfolder.Location = new System.Drawing.Point(118, 355);
+ outfolder.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
+ outfolder.Name = "outfolder";
+ outfolder.Size = new System.Drawing.Size(241, 23);
+ outfolder.TabIndex = 15;
//
// label11
//
label11.AutoSize = true;
- label11.Location = new System.Drawing.Point(35, 241);
+ label11.Location = new System.Drawing.Point(31, 358);
label11.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
label11.Name = "label11";
- label11.Size = new System.Drawing.Size(73, 15);
+ label11.Size = new System.Drawing.Size(79, 15);
label11.TabIndex = 25;
- label11.Text = "Output MUL";
+ label11.Text = "Output folder";
//
// label12
//
label12.AutoSize = true;
- label12.Location = new System.Drawing.Point(7, 203);
+ label12.Location = new System.Drawing.Point(7, 233);
label12.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
label12.Name = "label12";
label12.Size = new System.Drawing.Size(147, 15);
@@ -444,10 +466,10 @@ private void InitializeComponent()
//
// StartFolderButton
//
- StartFolderButton.Location = new System.Drawing.Point(10, 96);
+ StartFolderButton.Location = new System.Drawing.Point(56, 96);
StartFolderButton.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
StartFolderButton.Name = "StartFolderButton";
- StartFolderButton.Size = new System.Drawing.Size(326, 27);
+ StartFolderButton.Size = new System.Drawing.Size(279, 27);
StartFolderButton.TabIndex = 12;
StartFolderButton.Text = "Start";
StartFolderButton.UseVisualStyleBackColor = true;
@@ -538,6 +560,9 @@ private void InitializeComponent()
ExtractSingleFileTabPage.Controls.Add(label1);
ExtractSingleFileTabPage.Controls.Add(label2);
ExtractSingleFileTabPage.Controls.Add(inmul);
+ ExtractSingleFileTabPage.Controls.Add(inhousingbin);
+ ExtractSingleFileTabPage.Controls.Add(inhousingbinbtn);
+ ExtractSingleFileTabPage.Controls.Add(labelHousingBin);
ExtractSingleFileTabPage.Controls.Add(inuopbtn);
ExtractSingleFileTabPage.Controls.Add(label3);
ExtractSingleFileTabPage.Controls.Add(uopMapIndex);
@@ -551,20 +576,19 @@ private void InitializeComponent()
ExtractSingleFileTabPage.Controls.Add(inuop);
ExtractSingleFileTabPage.Controls.Add(label7);
ExtractSingleFileTabPage.Controls.Add(label9);
- ExtractSingleFileTabPage.Controls.Add(outuop);
+ ExtractSingleFileTabPage.Controls.Add(outuopfolder);
+ ExtractSingleFileTabPage.Controls.Add(outputUopFileLabel);
ExtractSingleFileTabPage.Controls.Add(uoptomul);
ExtractSingleFileTabPage.Controls.Add(multype);
- ExtractSingleFileTabPage.Controls.Add(outidxbtn);
ExtractSingleFileTabPage.Controls.Add(label4);
- ExtractSingleFileTabPage.Controls.Add(outmulbtn);
+ ExtractSingleFileTabPage.Controls.Add(outfolderbtn);
ExtractSingleFileTabPage.Controls.Add(label5);
- ExtractSingleFileTabPage.Controls.Add(outidx);
ExtractSingleFileTabPage.Controls.Add(mulMapIndex);
- ExtractSingleFileTabPage.Controls.Add(label10);
- ExtractSingleFileTabPage.Controls.Add(outuopbtn);
- ExtractSingleFileTabPage.Controls.Add(outmul);
+ ExtractSingleFileTabPage.Controls.Add(outuopfolderbtn);
+ ExtractSingleFileTabPage.Controls.Add(outfolder);
ExtractSingleFileTabPage.Controls.Add(label12);
ExtractSingleFileTabPage.Controls.Add(label11);
+ ExtractSingleFileTabPage.Controls.Add(outputFilesLabel);
ExtractSingleFileTabPage.Location = new System.Drawing.Point(4, 24);
ExtractSingleFileTabPage.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
ExtractSingleFileTabPage.Name = "ExtractSingleFileTabPage";
@@ -578,11 +602,11 @@ private void InitializeComponent()
//
compressionBox.BackColor = System.Drawing.Color.White;
compressionBox.Items.AddRange(new object[] { "None", "Zlib", "Mythic" });
- compressionBox.Location = new System.Drawing.Point(168, 134);
+ compressionBox.Location = new System.Drawing.Point(168, 158);
compressionBox.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
compressionBox.Name = "compressionBox";
compressionBox.Size = new System.Drawing.Size(191, 23);
- compressionBox.TabIndex = 40;
+ compressionBox.TabIndex = 8;
compressionBox.Text = "None";
//
// MainStatusStrip
@@ -678,7 +702,6 @@ private void InitializeComponent()
private System.Windows.Forms.TextBox inuop;
private System.Windows.Forms.Button inuopbtn;
private System.Windows.Forms.Label label1;
- private System.Windows.Forms.Label label10;
private System.Windows.Forms.Label label11;
private System.Windows.Forms.Label label12;
private System.Windows.Forms.Label label13;
@@ -693,12 +716,11 @@ private void InitializeComponent()
private System.Windows.Forms.NumericUpDown mulMapIndex;
private System.Windows.Forms.Button multouop;
private System.Windows.Forms.ComboBox multype;
- private System.Windows.Forms.TextBox outidx;
- private System.Windows.Forms.Button outidxbtn;
- private System.Windows.Forms.TextBox outmul;
- private System.Windows.Forms.Button outmulbtn;
- private System.Windows.Forms.TextBox outuop;
- private System.Windows.Forms.Button outuopbtn;
+ private System.Windows.Forms.TextBox outfolder;
+ private System.Windows.Forms.Button outfolderbtn;
+ private System.Windows.Forms.TextBox outuopfolder;
+ private System.Windows.Forms.Label outputUopFileLabel;
+ private System.Windows.Forms.Button outuopfolderbtn;
private System.Windows.Forms.RadioButton pack;
private System.Windows.Forms.OpenFileDialog FileDialog;
private System.Windows.Forms.FolderBrowserDialog FolderDialog;
@@ -718,5 +740,9 @@ private void InitializeComponent()
private System.Windows.Forms.ComboBox uoptype;
private System.Windows.Forms.ToolStripStatusLabel VersionLabel;
private System.Windows.Forms.ComboBox compressionBox;
+ private System.Windows.Forms.TextBox inhousingbin;
+ private System.Windows.Forms.Button inhousingbinbtn;
+ private System.Windows.Forms.Label labelHousingBin;
+ private System.Windows.Forms.Label outputFilesLabel;
}
}
diff --git a/UoFiddler.Plugin.UopPacker/UserControls/UopPackerControl.cs b/UoFiddler.Plugin.UopPacker/UserControls/UopPackerControl.cs
index 9b52c913..14b697f9 100644
--- a/UoFiddler.Plugin.UopPacker/UserControls/UopPackerControl.cs
+++ b/UoFiddler.Plugin.UopPacker/UserControls/UopPackerControl.cs
@@ -11,9 +11,11 @@
using System;
using System.IO;
-using System.Linq;
using System.Windows.Forms;
+using Serilog;
using Ultima;
+using UoFiddler.Controls.Classes;
+using UoFiddler.Controls.Forms;
using UoFiddler.Plugin.UopPacker.Classes;
namespace UoFiddler.Plugin.UopPacker.UserControls
@@ -30,14 +32,98 @@ private UopPackerControl()
var fileTypes = Enum.GetNames(typeof(FileType));
- uoptype.DataSource = fileTypes;
- multype.DataSource = fileTypes.SkipLast(1).ToArray(); // remove multi collection from ToUOP() conversion (not supported yet)
+ multype.SelectedIndexChanged += OnMulTypeChanged;
+ uoptype.SelectedIndexChanged += OnUopTypeChanged;
+ mulMapIndex.ValueChanged += OnMulTypeChanged;
+ uopMapIndex.ValueChanged += OnUopTypeChanged;
+
+ uoptype.DataSource = new System.Collections.Generic.List(fileTypes);
+ multype.DataSource = new System.Collections.Generic.List(fileTypes);
mulMapIndex.ReadOnly = uopMapIndex.ReadOnly = true;
+ // Single output folder for both directions; individual filenames are derived from the selected FileType.
+ outfolder.PlaceholderText = "folder where .mul/.idx will be written";
+ outuopfolder.PlaceholderText = "folder where .uop will be written";
+
+ RefreshMulTypeUi();
+ RefreshUopTypeUi();
+
Dock = DockStyle.Fill;
}
+ private static (string mul, string idx, string uop) GetConventionalNames(FileType type, int mapIndex)
+ {
+ return type switch
+ {
+ FileType.ArtLegacyMul => ("art.mul", "artidx.mul", "artLegacyMUL.uop"),
+ FileType.GumpartLegacyMul => ("gumpart.mul", "gumpidx.mul", "gumpartLegacyMUL.uop"),
+ FileType.MapLegacyMul => ($"map{mapIndex}.mul", null, $"map{mapIndex}LegacyMUL.uop"),
+ FileType.SoundLegacyMul => ("sound.mul", "soundidx.mul", "soundLegacyMUL.uop"),
+ FileType.MultiCollection => ("multi.mul", "multi.idx", "MultiCollection.uop"),
+ _ => ("", "", "")
+ };
+ }
+
+ private void OnMulTypeChanged(object sender, EventArgs e) => RefreshMulTypeUi();
+
+ private void OnUopTypeChanged(object sender, EventArgs e) => RefreshUopTypeUi();
+
+ private void RefreshMulTypeUi()
+ {
+ if (multype == null || !Enum.TryParse(multype.SelectedValue?.ToString() ?? string.Empty, out FileType type))
+ {
+ return;
+ }
+
+ bool isMap = type == FileType.MapLegacyMul;
+ bool isMulti = type == FileType.MultiCollection;
+
+ inidx.Enabled = inidxbtn.Enabled = !isMap;
+ mulMapIndex.Enabled = isMap;
+
+ inhousingbin.Visible = inhousingbinbtn.Visible = labelHousingBin.Visible = isMulti;
+
+ // Previously-picked paths belong to the old type; clear them so the user can't accidentally
+ // run a conversion against the wrong file.
+ inmul.Text = string.Empty;
+ inidx.Text = string.Empty;
+ inhousingbin.Text = string.Empty;
+
+ var (mulName, idxName, uopName) = GetConventionalNames(type, (int)mulMapIndex.Value);
+ inmul.PlaceholderText = mulName;
+ inidx.PlaceholderText = idxName ?? string.Empty;
+ inhousingbin.PlaceholderText = "housing.bin";
+
+ outputUopFileLabel.Text = string.IsNullOrEmpty(uopName) ? string.Empty : "Will create: " + uopName;
+ }
+
+ private void RefreshUopTypeUi()
+ {
+ if (uoptype == null || !Enum.TryParse(uoptype.SelectedValue?.ToString() ?? string.Empty, out FileType type))
+ {
+ return;
+ }
+
+ bool isMap = type == FileType.MapLegacyMul;
+ bool isMulti = type == FileType.MultiCollection;
+
+ uopMapIndex.Enabled = isMap;
+
+ inuop.Text = string.Empty;
+
+ var (mulName, idxName, uopName) = GetConventionalNames(type, (int)uopMapIndex.Value);
+ inuop.PlaceholderText = uopName;
+
+ // Preview what will be written under the output folder.
+ string preview = idxName != null ? $"{mulName}, {idxName}" : mulName;
+ if (isMulti)
+ {
+ preview += ", housing.bin";
+ }
+ outputFilesLabel.Text = "Will create: " + preview;
+ }
+
public UopPackerControl(string version) : this()
{
VersionLabel.Text = version;
@@ -63,13 +149,11 @@ private void InputIdxSelect(object sender, EventArgs e)
}
}
- private void OutputUopSelect(object sender, EventArgs e)
+ private void OutputUopFolderSelect(object sender, EventArgs e)
{
- FileDialog.FilterIndex = 2;
-
- if (FileDialog.ShowDialog() == DialogResult.OK)
+ if (FolderDialog.ShowDialog() == DialogResult.OK)
{
- outuop.Text = FileDialog.FileName;
+ outuopfolder.Text = FolderDialog.SelectedPath;
}
}
@@ -88,71 +172,107 @@ private void ToUop(object sender, EventArgs e)
return;
}
- if (inidx.Text.Length == 0)
+ if (!File.Exists(inmul.Text))
{
- MessageBox.Show("You must specify the input idx");
+ MessageBox.Show("The input mul does not exist");
return;
}
- if (outuop.Text.Length == 0)
+ if (inidx.Text.Length == 0 && fileType != FileType.MapLegacyMul)
{
- MessageBox.Show("You must specify the output uop");
+ MessageBox.Show("You must specify the input idx");
return;
}
- if (!File.Exists(inmul.Text))
+ if (fileType != FileType.MapLegacyMul && !File.Exists(inidx.Text))
{
- MessageBox.Show("The input mul does not exists");
+ MessageBox.Show("The input idx does not exist");
return;
}
- if (!File.Exists(inidx.Text))
+ if (outuopfolder.Text.Length == 0)
{
- MessageBox.Show("The input idx does not exists");
+ MessageBox.Show("You must specify the output folder");
return;
}
- if (File.Exists(outuop.Text))
+ if (!Directory.Exists(outuopfolder.Text))
{
- MessageBox.Show("Output file already exists");
+ MessageBox.Show("The output folder does not exist");
return;
}
+
+ string housingBin = string.Empty;
+ if (fileType == FileType.MultiCollection)
+ {
+ housingBin = inhousingbin.Text;
+ if (!string.IsNullOrWhiteSpace(housingBin) && !File.Exists(housingBin))
+ {
+ MessageBox.Show("The input housing.bin does not exist");
+ return;
+ }
+ }
+
+ var (_, _, uopName) = GetConventionalNames(fileType, (int)mulMapIndex.Value);
+ string outUopPath = Path.Combine(outuopfolder.Text, uopName);
+
+ if (File.Exists(outUopPath))
+ {
+ var prompt = MessageBox.Show(
+ $"{uopName} already exists in the output folder and will be overwritten.\n\nProceed?",
+ "Overwrite existing file",
+ MessageBoxButtons.YesNo,
+ MessageBoxIcon.Warning);
+ if (prompt != DialogResult.Yes)
+ {
+ return;
+ }
+ // ToUop opens output with FileMode.Create, which overwrites.
+ }
+
CompressionFlag selectedCompressionMethod = Enum.Parse(compressionBox.SelectedItem.ToString());
+
+ bool succeeded = false;
try
{
multouop.Text = "Converting...";
multouop.Enabled = false;
- LegacyMulFileConverter.ToUop(inmul.Text, inidx.Text, outuop.Text, fileType, (int)mulMapIndex.Value, selectedCompressionMethod);
+ LegacyMulFileConverter.ToUop(inmul.Text, inidx.Text, outUopPath, fileType, (int)mulMapIndex.Value, selectedCompressionMethod, housingBin);
+ succeeded = true;
}
- catch
+ catch (Exception ex)
{
- MessageBox.Show("An error occurred");
+ LogConverterError(ex, nameof(ToUop), inmul.Text, outUopPath, fileType);
+ MessageBox.Show($"An error occurred.\r\n{ex.Message}");
}
finally
{
multouop.Text = "Convert";
multouop.Enabled = true;
}
+
+ if (succeeded)
+ {
+ FileSavedDialog.Show(FindForm(), outUopPath, "UOP file saved successfully.", "Conversion complete");
+ }
}
- private void OutMulSelect(object sender, EventArgs e)
+ private void InputHousingBinSelect(object sender, EventArgs e)
{
- FileDialog.FilterIndex = 1;
+ FileDialog.FilterIndex = 4;
if (FileDialog.ShowDialog() == DialogResult.OK)
{
- outmul.Text = FileDialog.FileName;
+ inhousingbin.Text = FileDialog.FileName;
}
}
- private void OutputIdxSelect(object sender, EventArgs e)
+ private void OutFolderSelect(object sender, EventArgs e)
{
- FileDialog.FilterIndex = 3;
-
- if (FileDialog.ShowDialog() == DialogResult.OK)
+ if (FolderDialog.ShowDialog() == DialogResult.OK)
{
- outidx.Text = FileDialog.FileName;
+ outfolder.Text = FolderDialog.SelectedPath;
}
}
@@ -175,58 +295,88 @@ private void ToMul(object sender, EventArgs e)
return;
}
- if (outmul.Text.Length == 0)
+ if (inuop.Text.Length == 0)
{
- MessageBox.Show("You must specify the output mul");
+ MessageBox.Show("You must specify the input uop");
return;
}
- if (outidx.Text.Length == 0 && fileType != FileType.MapLegacyMul)
+ if (!File.Exists(inuop.Text))
{
- MessageBox.Show("You must specify the output idx");
+ MessageBox.Show("The input file does not exist");
return;
}
- if (inuop.Text.Length == 0)
+ if (outfolder.Text.Length == 0)
{
- MessageBox.Show("You must specify the input uop");
+ MessageBox.Show("You must specify the output folder");
return;
}
- if (!File.Exists(inuop.Text))
+ if (!Directory.Exists(outfolder.Text))
{
- MessageBox.Show("The input file does not exists");
+ MessageBox.Show("The output folder does not exist");
return;
}
- if (File.Exists(outmul.Text))
- {
- MessageBox.Show("Output mul file already exists");
- return;
- }
+ int mapIdx = (int)uopMapIndex.Value;
+ var (mulName, idxName, _) = GetConventionalNames(fileType, mapIdx);
- if (File.Exists(outidx.Text) && fileType != FileType.MapLegacyMul)
+ string outMulPath = Path.Combine(outfolder.Text, mulName);
+ string outIdxPath = idxName != null ? Path.Combine(outfolder.Text, idxName) : null;
+ string housingBinPath = fileType == FileType.MultiCollection
+ ? Path.Combine(outfolder.Text, "housing.bin")
+ : string.Empty;
+
+ var conflicts = new System.Collections.Generic.List();
+ if (File.Exists(outMulPath)) conflicts.Add(mulName);
+ if (outIdxPath != null && File.Exists(outIdxPath)) conflicts.Add(idxName);
+ if (!string.IsNullOrEmpty(housingBinPath) && File.Exists(housingBinPath)) conflicts.Add("housing.bin");
+
+ if (conflicts.Count > 0)
{
- MessageBox.Show("Output index file already exists");
- return;
+ var prompt = MessageBox.Show(
+ $"These files already exist in the output folder and will be overwritten:\n\n {string.Join("\n ", conflicts)}\n\nProceed?",
+ "Overwrite existing files",
+ MessageBoxButtons.YesNo,
+ MessageBoxIcon.Warning);
+ if (prompt != DialogResult.Yes)
+ {
+ return;
+ }
+ // FromUop opens outputs with FileMode.Create, which overwrites.
}
+ bool succeeded = false;
try
{
uoptomul.Text = "Converting...";
uoptomul.Enabled = false;
- _conv.FromUop(inuop.Text, outmul.Text, outidx.Text, fileType, (int)uopMapIndex.Value);
+ _conv.FromUop(inuop.Text, outMulPath, outIdxPath, fileType, mapIdx, housingBinPath);
+ succeeded = true;
}
- catch
+ catch (Exception ex)
{
- MessageBox.Show("An error occurred");
+ LogConverterError(ex, nameof(ToMul), inuop.Text, outMulPath, fileType);
+ MessageBox.Show($"An error occurred.\r\n{ex.Message}");
}
finally
{
uoptomul.Text = "Convert";
uoptomul.Enabled = true;
}
+
+ if (succeeded)
+ {
+ var written = new System.Collections.Generic.List { Path.GetFileName(outMulPath) };
+ if (!string.IsNullOrEmpty(outIdxPath)) written.Add(Path.GetFileName(outIdxPath));
+ if (!string.IsNullOrEmpty(housingBinPath)) written.Add(Path.GetFileName(housingBinPath));
+
+ FileSavedDialog.Show(FindForm(), outfolder.Text,
+ $"Saved: {string.Join(", ", written)}",
+ "Conversion complete");
+ }
}
private void SelectFolder_Click(object sender, EventArgs e)
@@ -281,11 +431,12 @@ private void Extract(string inFile, string outFile, string outIdx, FileType type
}
catch (Exception e)
{
+ LogConverterError(e, nameof(Extract), inFile, outFile, type);
MessageBox.Show($"An error occurred while performing the action.\r\n{e.Message}");
}
}
- private void Pack(string inFile, string inIdx, string outFile, FileType type, int typeIndex)
+ private void Pack(string inFile, string inIdx, string outFile, FileType type, int typeIndex, string housingBinFile = "")
{
try
{
@@ -308,19 +459,34 @@ private void Pack(string inFile, string inIdx, string outFile, FileType type, in
}
inIdx = FixPath(inIdx);
+
+ if (!string.IsNullOrWhiteSpace(housingBinFile))
+ {
+ housingBinFile = FixPath(housingBinFile);
+ }
+
++_total;
CompressionFlag selectedCompressionMethod = Enum.Parse(compressionBox.SelectedItem.ToString());
- LegacyMulFileConverter.ToUop(inFile, inIdx, outFile, type, typeIndex, selectedCompressionMethod);
+ LegacyMulFileConverter.ToUop(inFile, inIdx, outFile, type, typeIndex, selectedCompressionMethod, housingBinFile ?? string.Empty);
++_success;
}
catch (Exception e)
{
+ LogConverterError(e, nameof(Pack), inFile, outFile, type);
MessageBox.Show($"An error occurred while performing the action.\r\n{e.Message}");
}
}
+ private static void LogConverterError(Exception ex, string operation, string input, string output, FileType type)
+ {
+ ILogger logger = Options.Logger;
+
+ logger?.Error(ex, "UopPacker {Operation} failed (type={FileType}, input={Input}, output={Output})",
+ operation, type, input, output);
+ }
+
private string FixPath(string file)
{
return (file == null) ? null : Path.Combine(inputfolder.Text, file);
@@ -351,7 +517,9 @@ private void StartFolderButtonClick(object sender, EventArgs e)
Extract(map + "xLegacyMUL.uop", map + "x.mul", null, FileType.MapLegacyMul, i);
}
- statustext.Text = $"Done ({_success}/{_total} files extracted)";
+ string extractMessage = $"Done ({_success}/{_total} files extracted)";
+ statustext.Text = extractMessage;
+ FileSavedDialog.Show(FindForm(), inputfolder.Text, extractMessage, "Extraction complete");
}
else if (pack.Checked)
{
@@ -360,6 +528,7 @@ private void StartFolderButtonClick(object sender, EventArgs e)
Pack("art.mul", "artidx.mul", "artLegacyMUL.uop", FileType.ArtLegacyMul, 0);
Pack("gumpart.mul", "gumpidx.mul", "gumpartLegacyMUL.uop", FileType.GumpartLegacyMul, 0);
Pack("sound.mul", "soundidx.mul", "soundLegacyMUL.uop", FileType.SoundLegacyMul, 0);
+ Pack("multi-unpacked.mul", "multi-unpacked.idx", "MultiCollection.uop", FileType.MultiCollection, 0, "housing.bin");
for (int i = 0; i <= 5; ++i)
{
@@ -369,7 +538,9 @@ private void StartFolderButtonClick(object sender, EventArgs e)
Pack(map + "x.mul", null, map + "xLegacyMUL.uop", FileType.MapLegacyMul, i);
}
- statustext.Text = $"Done ({_success}/{_total} files packed)";
+ string packMessage = $"Done ({_success}/{_total} files packed)";
+ statustext.Text = packMessage;
+ FileSavedDialog.Show(FindForm(), inputfolder.Text, packMessage, "Pack complete");
}
else
{
From c0c29855d141ff92e6ce412080795366b5aa23ae Mon Sep 17 00:00:00 2001
From: AsY!um- <377468+AsYlum-@users.noreply.github.com>
Date: Sun, 26 Apr 2026 21:41:35 +0200
Subject: [PATCH 6/6] Update change log and version.
---
UoFiddler/Forms/AboutBoxForm.resx | 9 ++++++++-
UoFiddler/UoFiddler.csproj | 6 +++---
2 files changed, 11 insertions(+), 4 deletions(-)
diff --git a/UoFiddler/Forms/AboutBoxForm.resx b/UoFiddler/Forms/AboutBoxForm.resx
index 15b32ccd..47a0bc6e 100644
--- a/UoFiddler/Forms/AboutBoxForm.resx
+++ b/UoFiddler/Forms/AboutBoxForm.resx
@@ -118,7 +118,14 @@
System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
- Version 4.19.0
+ Version 4.19.1
+- UopPacker: added save support for MultiCollection.uop (including housing.bin) and refreshed the plugin UI.
+- Map copy/replace dialog now supports UOP map files. #105
+- Added "Replace from folder" bulk action for Items and Land Tiles tabs. #102
+- More controls now use the unified File Saved dialog (with Open Folder shortcut) when saving.
+- Animation editor remembers the selected file filter when adding new frames. #82
+
+Version 4.19.0
- Added support for previewing contents of animations in anim6.mul and AnimationFrame1-6.uop (no export or edit option for uop yet).
- Fixed possible crash and slowdown during tiledata CSV import from newer client to older client.
- More preview boxes now support change background color and use background color set in Options.
diff --git a/UoFiddler/UoFiddler.csproj b/UoFiddler/UoFiddler.csproj
index ce5756bd..9ac78ff6 100644
--- a/UoFiddler/UoFiddler.csproj
+++ b/UoFiddler/UoFiddler.csproj
@@ -9,9 +9,9 @@
UoFiddler
UoFiddler
Copyright © 2026
- 4.19.0
- 4.19.0
- 4.19.0
+ 4.19.1
+ 4.19.1
+ 4.19.1
true