diff --git a/Documentation/smithbox.txt b/Documentation/smithbox.txt
index 7c411e00..eb3f4a27 100644
--- a/Documentation/smithbox.txt
+++ b/Documentation/smithbox.txt
@@ -46,9 +46,6 @@ Map Editor:
- FIX: duping assets to new map and then pressing X to bring to camera results in incorrect placement
- FIX: misc texture loads during map load can hang, causing the load window to never disppear. (e.g. Leyndell)
-Text Editor:
- - ADD: context menu in text input: add color (Text) that wraps selected text with the html tag (include detection/removal of tag when selecting existing one too)
-
Material Editor
- ADD: Implement Material/MATBIN editor
@@ -99,6 +96,11 @@ Model Editor:
- FIX: account for scale when displaying dummies/bones
+Text Editor:
+ - ADD: context menu in text input: add color (Text) that wraps selected text with the html tag (include detection/removal of tag when selecting existing one too)
+ - FIX: issue with exporting modified/unique on container level
+ - FIX: crash on multi-select in FMG list
+
#--------------------------------------
# Notes
#--------------------------------------
diff --git a/src/StudioCore/Editors/TextEditor/Data/FmgExporter.cs b/src/StudioCore/Editors/TextEditor/Data/FmgExporter.cs
index c04c969e..6c93043d 100644
--- a/src/StudioCore/Editors/TextEditor/Data/FmgExporter.cs
+++ b/src/StudioCore/Editors/TextEditor/Data/FmgExporter.cs
@@ -385,6 +385,10 @@ private static void ProcessFmg(TextFmgWrapper wrapper, StoredFmgContainer stored
storedFmg.BigEndian = wrapper.File.BigEndian;
storedFmg.Entries = new List();
+ // We have to call this so the diff cache updates for each wrapper,
+ // without changing the user selection
+ Smithbox.EditorHandler.TextEditor.DifferenceManager.TrackFmgDifferences(wrapper.ID);
+
// Build FMG entries
foreach (var entry in wrapper.File.Entries)
{
diff --git a/src/StudioCore/Editors/TextEditor/Data/FmgImporter.cs b/src/StudioCore/Editors/TextEditor/Data/FmgImporter.cs
index ef8968f7..f067d6ed 100644
--- a/src/StudioCore/Editors/TextEditor/Data/FmgImporter.cs
+++ b/src/StudioCore/Editors/TextEditor/Data/FmgImporter.cs
@@ -6,6 +6,7 @@
using StudioCore.Editors.TextEditor.Actions;
using StudioCore.Editors.TextEditor.Enums;
using StudioCore.Interface;
+using StudioCore.Platform;
using StudioCore.Resource.Locators;
using System;
using System.Collections.Generic;
@@ -116,6 +117,13 @@ public static void DisplayImportList(ImportType importType)
if(ImGui.BeginMenu("Append"))
{
+ if (ImGui.Selectable($"From external file"))
+ {
+ PromptExternalTextImport(ImportBehavior.Append);
+ }
+
+ ImGui.Separator();
+
if (ImportSources.Count > 0)
{
foreach (var (key, entry) in ImportSources)
@@ -137,6 +145,13 @@ public static void DisplayImportList(ImportType importType)
if (ImGui.BeginMenu("Replace"))
{
+ if (ImGui.Selectable($"From external file"))
+ {
+ PromptExternalTextImport(ImportBehavior.Replace);
+ }
+
+ ImGui.Separator();
+
if (ImportSources.Count > 0)
{
foreach (var (key, entry) in ImportSources)
@@ -161,6 +176,11 @@ public static void DisplayImportList(ImportType importType)
private static void ImportText(StoredFmgContainer containerWrapper, ImportBehavior importBehavior)
{
+ if(containerWrapper.FmgWrappers == null)
+ {
+ return;
+ }
+
ImportActions = new List();
var editor = Smithbox.EditorHandler.TextEditor;
@@ -249,5 +269,50 @@ private static void LoadWrappers()
}
}
}
+
+ private static StoredFmgContainer GenerateStoredFmgContainer(string path)
+ {
+ var filename = Path.GetFileName(path);
+ var wrapper = new StoredFmgContainer();
+
+ if (File.Exists(path))
+ {
+ using (var stream = File.OpenRead(path))
+ {
+ try
+ {
+ wrapper = JsonSerializer.Deserialize(stream, StoredContainerWrapperSerializationContext.Default.StoredFmgContainer);
+ }
+ catch(Exception e)
+ {
+ TaskLogs.AddLog($"Failed to read JSON file for Text Import: {e.Message}");
+ }
+
+ return wrapper;
+ }
+ }
+
+ return wrapper;
+ }
+
+ private static void PromptExternalTextImport(ImportBehavior type)
+ {
+ if (PlatformUtils.Instance.OpenFileDialog("Select stored text JSON", ["json"], out var path))
+ {
+ if (!File.Exists(path))
+ {
+ DialogResult message = PlatformUtils.Instance.MessageBox(
+ "Selected file is invalid.", "Error",
+ MessageBoxButtons.OK);
+ return;
+ }
+
+ var generatedStoredFmgContainer = GenerateStoredFmgContainer(path);
+ if (generatedStoredFmgContainer != null)
+ {
+ ImportText(generatedStoredFmgContainer, type);
+ }
+ }
+ }
}
diff --git a/src/StudioCore/Editors/TextEditor/Framework/TextDifferenceManager.cs b/src/StudioCore/Editors/TextEditor/Framework/TextDifferenceManager.cs
index 3533bdb2..379de6a3 100644
--- a/src/StudioCore/Editors/TextEditor/Framework/TextDifferenceManager.cs
+++ b/src/StudioCore/Editors/TextEditor/Framework/TextDifferenceManager.cs
@@ -37,7 +37,7 @@ public TextDifferenceManager(TextEditorScreen screen)
///
/// Generate difference truth for currently selected FMG
///
- public void TrackFmgDifferences()
+ public void TrackFmgDifferences(int setFmgId = -1)
{
CacheFilled = false;
AdditionCache = new();
@@ -55,10 +55,19 @@ public void TrackFmgDifferences()
var containerCategory = Selection.SelectedContainerWrapper.ContainerDisplayCategory;
var containerSubCategory = Selection.SelectedContainerWrapper.ContainerDisplaySubCategory;
var containerName = Selection.SelectedContainerWrapper.Filename;
+
+ // Fmg ID for comparison is selected FMG
var fmgID = Selection.SelectedFmgWrapper.ID;
+ // Set the ID to passed instead of selected if called from the FmgExporter
+ if(setFmgId != -1)
+ {
+ fmgID = setFmgId;
+ }
+
if (TextBank.VanillaBankLoaded)
{
+ // Get vanilla container and entries
var vanillaContainer = TextBank.VanillaFmgBank
.Where(e => e.Value.ContainerDisplayCategory == containerCategory)
.Where(e => e.Value.Filename == containerName)
@@ -92,7 +101,25 @@ public void TrackFmgDifferences()
}
}
- foreach(var entry in Selection.SelectedFmgWrapper.File.Entries)
+ // Get primary container and enetries
+ var primaryContainer = TextBank.FmgBank
+ .Where(e => e.Value.ContainerDisplayCategory == containerCategory)
+ .Where(e => e.Value.Filename == containerName)
+ .FirstOrDefault();
+
+ if (Smithbox.ProjectType is ProjectType.DS2 or ProjectType.DS2S)
+ {
+ primaryContainer = TextBank.FmgBank
+ .Where(e => e.Value.ContainerDisplayCategory == containerCategory)
+ .Where(e => e.Value.ContainerDisplaySubCategory == containerSubCategory)
+ .Where(e => e.Value.Filename == containerName)
+ .FirstOrDefault();
+ }
+
+ var primaryFmg = primaryContainer.Value.FmgWrappers
+ .Where(e => e.ID == fmgID).FirstOrDefault();
+
+ foreach (var entry in primaryFmg.File.Entries)
{
string entryId = $"{entry.ID}";