Skip to content

Commit 5389edd

Browse files
committed
Add automatic handling of mdf2 parameters based on mmtr data
1 parent bd00a3f commit 5389edd

File tree

7 files changed

+244
-35
lines changed

7 files changed

+244
-35
lines changed

ContentEditor.App/BackgroundTasks/BackgroundTaskService.cs

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,22 @@ public sealed class BackgroundTaskService : IDisposable
2323

2424
public int PendingTasks => waitingTasks.Count + (workers.Count - freeWorkers.Count);
2525
public int ActiveWorkerCount => workers.Count - freeWorkers.Count;
26-
public IEnumerable<string> CurrentJobs {
26+
public IEnumerable<(string status, float progress)> CurrentJobs {
2727
get {
28-
var list = new List<string>();
28+
var list = new List<(string, float)>();
2929
for (int i = 0; i < workers.Count; ++i) {
3030
var worker = workers[i];
31-
if (worker.CurrentTask != null) {
32-
var task = worker.CurrentTask?.Status ?? "Finalizing";
33-
list.Add(task + " | " + worker.ToString());
31+
var task = worker.CurrentTask;
32+
if (task != null) {
33+
var status = task.Status ?? "Finalizing";
34+
var pct = task.Progress;
35+
if (pct > 1) {
36+
list.Add(($"{status} | {Math.Round(pct * 10) / 10} | {worker}", pct));
37+
} else if (pct >= 0) {
38+
list.Add(($"{status} | {Math.Round(pct * 100)}% | {worker}", pct));
39+
} else {
40+
list.Add(($"{status} | {worker}", -1));
41+
}
3442
}
3543
}
3644
return list;
@@ -110,6 +118,8 @@ public void Dispose()
110118
}
111119
}
112120

121+
public bool HasPendingTask<T>() => workers.Any(w => w.CurrentTask is T) || waitingTasks.Any(t => t is T);
122+
113123
private class BackgroundTaskWorker : BackgroundWorker, IDisposable
114124
{
115125
private CancellationTokenSource tokenSource = new();
@@ -191,6 +201,7 @@ public interface IBackgroundTask
191201
{
192202
bool IsCancelled { get; internal set; }
193203
string? Status { get; }
204+
float Progress => -1;
194205

195206
void Execute(CancellationToken token = default);
196207
}
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
using System.Diagnostics;
2+
using System.Text.Json;
3+
using ContentPatcher;
4+
using ReeLib;
5+
6+
namespace ContentEditor.BackgroundTasks;
7+
8+
public class MaterialParamCacheTask : IBackgroundTask
9+
{
10+
public static string GetCachePath(GameIdentifier game) => Path.Combine(AppConfig.Instance.CacheFilepath.Get() ?? Path.Combine(AppConfig.AppDataPath, "cache"), game.name, "materials.json");
11+
12+
public string Status { get; private set; }
13+
public bool IsCancelled { get; set; }
14+
public Workspace Workspace { get; }
15+
16+
private int filesProcessed = 0;
17+
private int totalFiles = 0;
18+
19+
public float Progress => totalFiles <= 0 ? -1 : (float)filesProcessed / totalFiles;
20+
21+
public MaterialParamCacheTask(Workspace workspace)
22+
{
23+
Status = "Starting";
24+
Workspace = workspace;
25+
}
26+
27+
public override string ToString() => $"Caching material parameter data";
28+
29+
public unsafe void Execute(CancellationToken token = default)
30+
{
31+
totalFiles = Workspace.ListFile?.FilterAllFiles(".*\\.mdf2\\..*").Length ?? 1;
32+
filesProcessed = 0;
33+
var dict = new Dictionary<string, MmtrTemplate>();
34+
foreach (var (path, stream) in Workspace.GetFilesWithExtension("mdf2", token)) {
35+
filesProcessed++;
36+
var mdf = new MdfFile(new FileHandler(stream, path));
37+
if (!mdf.Read()) continue;
38+
foreach (var mat in mdf.Materials) {
39+
if (string.IsNullOrEmpty(mat.Header.mmtrPath)) continue;
40+
41+
if (!dict.TryGetValue(mat.Header.mmtrPath, out var template)) {
42+
dict[mat.Header.mmtrPath] = template = new MmtrTemplate();
43+
foreach (var p in mat.Parameters) {
44+
template.Parameters.Add(new MmtrTemplateParameter(p.paramName, p.componentCount));
45+
}
46+
foreach (var t in mat.Textures) {
47+
template.TextureNames.Add(t.texType);
48+
}
49+
} else {
50+
Debug.Assert(template.Parameters.Select(p => p.Name).Intersect(mat.Parameters.Select(p => p.paramName)).Count() == template.Parameters.Count);
51+
Debug.Assert(template.TextureNames.Intersect(mat.Textures.Select(p => p.texType)).Count() == template.TextureNames.Count);
52+
}
53+
54+
foreach (var t in mat.Textures) {
55+
if (t.texPath?.Contains("/null", StringComparison.InvariantCultureIgnoreCase) == true) {
56+
template.TextureDefaults.TryAdd(t.texType, t.texPath);
57+
}
58+
}
59+
}
60+
}
61+
62+
var outputFilepath = GetCachePath(Workspace.Config.Game);
63+
var db = new MmtrTemplateDB() {
64+
Templates = dict,
65+
GameDataHash = AppUtils.GetGameVersionHash(Workspace.Config)
66+
};
67+
var outputDir = Path.GetDirectoryName(outputFilepath);
68+
if (string.IsNullOrEmpty(outputDir)) {
69+
Logger.Error("Failed to determine cache output path");
70+
return;
71+
}
72+
73+
try {
74+
Directory.CreateDirectory(outputDir);
75+
using var fs = File.Create(outputFilepath);
76+
JsonSerializer.Serialize(fs, db);
77+
Logger.Info("Stored material parameter cache in " + outputFilepath);
78+
} catch (Exception e) {
79+
Logger.Error("Failed to save material parameter cache in path " + outputFilepath + ":\n" + e.Message);
80+
}
81+
}
82+
}
83+
84+
public class MmtrTemplateDB
85+
{
86+
public string GameDataHash { get; set; } = "";
87+
public Dictionary<string, MmtrTemplate> Templates { get; set; } = new();
88+
}
89+
90+
public class MmtrTemplate
91+
{
92+
public List<MmtrTemplateParameter> Parameters { get; set; } = new();
93+
public List<string> TextureNames { get; set; } = new();
94+
public Dictionary<string, string> TextureDefaults { get; set; } = new();
95+
}
96+
97+
public record MmtrTemplateParameter(string Name, int Components);
98+

ContentEditor.App/Configuration/AppConfig.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ public static class Keys
4444
public const string UsePakCompactFilePaths = "use_pak_compact_file_paths";
4545
public const string PakDisplayMode = "pak_display_mode";
4646
public const string ThumbnailCacheFilepath = "thumbnail_cache_path";
47+
public const string CacheFilepath = "cache_path";
4748
public const string WindowRect = "window_rect";
4849

4950
public const string RenderAxis = "render_axis";
@@ -142,6 +143,7 @@ public void Set(T? value) => SetAndSave(value, (v) => {
142143
public readonly ClassSettingWrapper<string> BlenderPath = new ClassSettingWrapper<string>(Keys.BlenderPath, _lock);
143144
public readonly ClassSettingWrapper<string> RemoteDataSource = new ClassSettingWrapper<string>(Keys.RemoteDataSource, _lock);
144145
public readonly ClassSettingWrapper<string> GameConfigBaseFilepath = new ClassSettingWrapper<string>(Keys.GameConfigBaseFilepath, _lock);
146+
public readonly ClassSettingWrapper<string> CacheFilepath = new ClassSettingWrapper<string>(Keys.CacheFilepath, _lock, () => Path.Combine(AppDataPath, "cache"));
145147
public readonly ClassSettingWrapper<string> ThumbnailCacheFilepath = new ClassSettingWrapper<string>(Keys.ThumbnailCacheFilepath, _lock, () => Path.Combine(AppDataPath, "thumbs"));
146148
public readonly ClassSettingWrapper<string> Theme = new ClassSettingWrapper<string>(Keys.Theme, _lock, () => "default");
147149
public readonly SettingWrapper<int> UnpackMaxThreads = new SettingWrapper<int>(Keys.UnpackMaxThreads, _lock, 4);
@@ -297,6 +299,7 @@ public static void SaveConfigToIni()
297299
(Keys.UnpackMaxThreads, instance.UnpackMaxThreads.value.ToString(), null),
298300
(Keys.RemoteDataSource, instance.RemoteDataSource.value?.ToString() ?? "", null),
299301
(Keys.GameConfigBaseFilepath, instance.GameConfigBaseFilepath.value?.ToString() ?? "", null),
302+
(Keys.CacheFilepath, instance.CacheFilepath.value?.ToString() ?? "", null),
300303
(Keys.ThumbnailCacheFilepath, instance.ThumbnailCacheFilepath.value?.ToString() ?? "", null),
301304
(Keys.Theme, instance.Theme.value?.ToString() ?? "", null),
302305
(Keys.BackgroundColor, instance.BackgroundColor.value.ToString(), null),
@@ -405,6 +408,9 @@ private void LoadConfigs(IEnumerable<(string key, string value, string? group)>
405408
case Keys.ThumbnailCacheFilepath:
406409
ThumbnailCacheFilepath.value = ReadString(value);
407410
break;
411+
case Keys.CacheFilepath:
412+
CacheFilepath.value = ReadString(value);
413+
break;
408414
case Keys.Theme:
409415
Theme.value = string.IsNullOrEmpty(value) ? "default" : value;
410416
break;

ContentEditor.App/Imgui/App/FileTesterWindow.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,7 @@ private static IEnumerable<ContentWorkspace> GetWorkspaces(ContentWorkspace curr
471471

472472
foreach (var other in AppConfig.Instance.ConfiguredGames) {
473473
if (other == current.Game) continue;
474+
// if (other == "re7") continue;
474475

475476
var env = WorkspaceManager.Instance.GetWorkspace(other);
476477
ContentWorkspace? cw = null;

ContentEditor.App/Imgui/App/OverlaysWindow.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,9 +82,9 @@ public void OnIMGUI()
8282
ImGui.Text("Pending background tasks: " + runningTasks);
8383

8484
var jobSize = new Vector2(ImGui.GetWindowWidth() - ImGui.GetStyle().WindowPadding.X * 2, 30);
85-
foreach (var job in bg.CurrentJobs) {
85+
foreach (var (job, progress) in bg.CurrentJobs) {
8686
ImGui.Separator();
87-
ImGui.ProgressBar(-1 * (float)ImGui.GetTime(), jobSize);
87+
ImGui.ProgressBar(progress >= 0 && progress <= 1 ? progress : -1 * (float)ImGui.GetTime(), jobSize);
8888
ImGui.TextWrapped(job);
8989
}
9090
}

0 commit comments

Comments
 (0)