diff --git a/src/StudioCore/AssetBrowser/AssetBrowserScreen.cs b/src/StudioCore/AssetBrowser/AssetBrowserScreen.cs index 3eab16ef5..3ffebff17 100644 --- a/src/StudioCore/AssetBrowser/AssetBrowserScreen.cs +++ b/src/StudioCore/AssetBrowser/AssetBrowserScreen.cs @@ -3,11 +3,11 @@ using StudioCore.Banks; using StudioCore.Banks.AliasBank; using StudioCore.Editor; -using StudioCore.Gui; -using StudioCore.Interface; +using StudioCore.Renderer.Gui; +using StudioCore.Editor; using StudioCore.MsbEditor; using StudioCore.Platform; -using StudioCore.Scene; +using StudioCore.Renderer.Scene; using StudioCore.Utilities; using System; using System.Collections.Generic; @@ -15,9 +15,8 @@ using System.Numerics; using System.Threading; using static Andre.Native.ImGuiBindings; -using Action = StudioCore.MsbEditor.Action; -using ActionManager = StudioCore.MsbEditor.ActionManager; -using CompoundAction = StudioCore.MsbEditor.CompoundAction; +using ActionManager = StudioCore.Editor.ActionManager; +using CompoundAction = StudioCore.Editor.CompoundAction; namespace StudioCore.Editors.AssetBrowser; public enum AssetBrowserSource @@ -157,7 +156,7 @@ public void OnProjectChanged() } } - List mapList = Locator.AssetLocator.GetFullMapList(); + List mapList = Locator.ActiveProject.MSBBank.GetFullMapList(); foreach (var mapId in mapList) { @@ -218,7 +217,7 @@ public void OnGui() if (ImGui.Begin($@"Asset Browser: Category##{SourceType}AssetBrowser_CategoryList")) { ImGui.Separator(); - ImguiUtils.WrappedText("Categories:"); + Editor.EditorDecorations.WrappedText("Categories:"); ImGui.Separator(); DisplayCategoryList(); @@ -235,7 +234,7 @@ public void OnGui() DisplayTopSection(); ImGui.Separator(); - ImguiUtils.WrappedText("Assets:"); + Editor.EditorDecorations.WrappedText("Assets:"); ImGui.Separator(); DisplayBrowserList(AssetCategoryType.Character, _characterNameCache, chrReferenceDict); @@ -255,7 +254,7 @@ public void OnGui() ImGui.Indent(10.0f); ImGui.Separator(); - ImguiUtils.WrappedText("Actions:"); + Editor.EditorDecorations.WrappedText("Actions:"); ImGui.Separator(); if (SourceType == AssetBrowserSource.MapEditor) @@ -283,7 +282,7 @@ private void DisplayTopSection() { ImGui.Separator(); ImGui.InputText($"Search", ref _searchInput, 255); - ImguiUtils.ShowHoverTooltip("Separate terms are split via the + character."); + Editor.EditorDecorations.ShowHoverTooltip("Separate terms are split via the + character."); } private void DisplayCategoryList() @@ -327,7 +326,7 @@ private void DisplayCategoryList() if (CFG.Current.AssetBrowser_ShowAliasesInBrowser) { var labelName = AliasUtils.GetMapNameAlias(mapId); - AliasUtils.DisplayAlias(labelName); + EditorDecorations.DisplayAlias(labelName); } } } @@ -393,14 +392,14 @@ private void DisplayBrowserList(AssetCategoryType assetType, List nameCa if (CFG.Current.AssetBrowser_ShowAliasesInBrowser) { var aliasName = referenceDict[lowerName].name; - AliasUtils.DisplayAlias(aliasName); + EditorDecorations.DisplayAlias(aliasName); } // Tags if (CFG.Current.AssetBrowser_ShowTagsInBrowser) { var tagString = string.Join(" ", referenceDict[lowerName].tags); - AliasUtils.DisplayTagAlias(tagString); + EditorDecorations.DisplayTagAlias(tagString); } } } @@ -462,14 +461,14 @@ private void DisplayBrowserList_MapPiece(AssetCategoryType assetType, Dictionary if (CFG.Current.AssetBrowser_ShowAliasesInBrowser) { var aliasName = referenceDict[lowerName].name; - AliasUtils.DisplayAlias(aliasName); + EditorDecorations.DisplayAlias(aliasName); } // Tags if (CFG.Current.AssetBrowser_ShowTagsInBrowser) { var tagString = string.Join(" ", referenceDict[lowerName].tags); - AliasUtils.DisplayTagAlias(tagString); + EditorDecorations.DisplayTagAlias(tagString); } } } @@ -483,41 +482,41 @@ private void DisplayActions_MapEditor() if (_selectedName == null || _selectedName == "") return; - ImguiUtils.WrappedText("Apply the selected asset attributes to your current object selection."); - ImguiUtils.WrappedText(""); + Editor.EditorDecorations.WrappedText("Apply the selected asset attributes to your current object selection."); + Editor.EditorDecorations.WrappedText(""); ImGui.Checkbox("Update Name of Selected Object", ref CFG.Current.AssetBrowser_UpdateName); - ImguiUtils.ShowHoverTooltip("Update the Name property of the selected entity when it is changed to a selected asset."); + Editor.EditorDecorations.ShowHoverTooltip("Update the Name property of the selected entity when it is changed to a selected asset."); if (Locator.AssetLocator.Type is GameType.EldenRing or GameType.ArmoredCoreVI) { ImGui.Checkbox("Update Instance ID of Selected Object", ref CFG.Current.AssetBrowser_UpdateInstanceID); - ImguiUtils.ShowHoverTooltip("Update the Name property of the selected entity when it is changed to a selected asset."); - ImguiUtils.WrappedText(""); + Editor.EditorDecorations.ShowHoverTooltip("Update the Name property of the selected entity when it is changed to a selected asset."); + Editor.EditorDecorations.WrappedText(""); } if (ImGui.Button("Apply##action_Asset_Apply", new Vector2(200, 32))) { ApplyMapAssetSelection(); } - ImguiUtils.WrappedText(""); + Editor.EditorDecorations.WrappedText(""); ImGui.Separator(); - ImguiUtils.WrappedText("Alias:"); + Editor.EditorDecorations.WrappedText("Alias:"); ImGui.Separator(); - ImguiUtils.WrappedText("Update the stored name and tag list for the selected asset here."); - ImguiUtils.WrappedText(""); + Editor.EditorDecorations.WrappedText("Update the stored name and tag list for the selected asset here."); + Editor.EditorDecorations.WrappedText(""); - ImguiUtils.WrappedText("Name:"); + Editor.EditorDecorations.WrappedText("Name:"); ImGui.InputText($"##Name", ref _refUpdateName, 255); - ImguiUtils.ShowHoverTooltip("Alias name given to this asset."); - ImguiUtils.WrappedText(""); + Editor.EditorDecorations.ShowHoverTooltip("Alias name given to this asset."); + Editor.EditorDecorations.WrappedText(""); - ImguiUtils.WrappedText("Tags:"); + Editor.EditorDecorations.WrappedText("Tags:"); ImGui.InputText($"##Tags", ref _refUpdateTags, 255); - ImguiUtils.ShowHoverTooltip("Tags associated with this asset. Tags are separated with the , character."); - ImguiUtils.WrappedText(""); + Editor.EditorDecorations.ShowHoverTooltip("Tags associated with this asset. Tags are separated with the , character."); + Editor.EditorDecorations.WrappedText(""); if (ImGui.Button("Update##action_AssetAlias_Update", new Vector2(200, 32))) { @@ -535,31 +534,31 @@ private void DisplayActions_ModelEditor() if (_selectedName == null || _selectedName == "") return; - ImguiUtils.WrappedText("Load the selected asset."); - ImguiUtils.WrappedText(""); + Editor.EditorDecorations.WrappedText("Load the selected asset."); + Editor.EditorDecorations.WrappedText(""); if (ImGui.Button("Load##action_Asset_Load", new Vector2(200, 32))) { LoadModelAssetSelection(); } - ImguiUtils.WrappedText(""); + Editor.EditorDecorations.WrappedText(""); ImGui.Separator(); - ImguiUtils.WrappedText("Alias:"); + Editor.EditorDecorations.WrappedText("Alias:"); ImGui.Separator(); - ImguiUtils.WrappedText("Update the stored name and tag list for the selected asset here."); - ImguiUtils.WrappedText(""); + Editor.EditorDecorations.WrappedText("Update the stored name and tag list for the selected asset here."); + Editor.EditorDecorations.WrappedText(""); - ImguiUtils.WrappedText("Name:"); + Editor.EditorDecorations.WrappedText("Name:"); ImGui.InputText($"##Name", ref _refUpdateName, 255); - ImguiUtils.ShowHoverTooltip("Alias name given to this asset."); - ImguiUtils.WrappedText(""); + Editor.EditorDecorations.ShowHoverTooltip("Alias name given to this asset."); + Editor.EditorDecorations.WrappedText(""); - ImguiUtils.WrappedText("Tags:"); + Editor.EditorDecorations.WrappedText("Tags:"); ImGui.InputText($"##Tags", ref _refUpdateTags, 255); - ImguiUtils.ShowHoverTooltip("Tags associated with this asset. Tags are separated with the , character."); - ImguiUtils.WrappedText(""); + Editor.EditorDecorations.ShowHoverTooltip("Tags associated with this asset. Tags are separated with the , character."); + Editor.EditorDecorations.WrappedText(""); if (ImGui.Button("Update##action_AssetAlias_Update", new Vector2(200, 32))) { @@ -657,7 +656,7 @@ public void LoadModelAssetSelection() public void SetObjectModelForSelection(string modelName, AssetCategoryType assetType, string assetMapId) { - var actlist = new List(); + var actlist = new List(); var selected = _selection.GetFilteredSelection(); diff --git a/src/StudioCore/AssetLocator.cs b/src/StudioCore/AssetLocator.cs index 88e20c28b..447ba0e26 100644 --- a/src/StudioCore/AssetLocator.cs +++ b/src/StudioCore/AssetLocator.cs @@ -96,15 +96,6 @@ public class AssetLocator public bool CreateRecoveryProject() => Locator.ActiveProject.CreateRecoveryProject() != null; - /// - /// Gets the full list of maps in the game (excluding chalice dungeons). Basically if there's an msb for it, - /// it will be in this list. - /// - /// - public List GetFullMapList() => Locator.ActiveProject.AssetLocator.GetFullMapList(); - - public AssetDescription GetMapMSB(string mapid, bool writemode = false) => Locator.ActiveProject.AssetLocator.GetMapMSB(mapid, writemode); - public List GetMapBTLs(string mapid, bool writemode = false) => Locator.ActiveProject.AssetLocator.GetMapBTLs(mapid, writemode); public AssetDescription GetMapNVA(string mapid, bool writemode = false) => Locator.ActiveProject.AssetLocator.GetMapNVA(mapid, writemode); diff --git a/src/StudioCore/Res/TAE.Template.BB.xml b/src/StudioCore/Assets/Res/TAE.Template.BB.xml similarity index 100% rename from src/StudioCore/Res/TAE.Template.BB.xml rename to src/StudioCore/Assets/Res/TAE.Template.BB.xml diff --git a/src/StudioCore/Res/TAE.Template.DS1.OBJ.xml b/src/StudioCore/Assets/Res/TAE.Template.DS1.OBJ.xml similarity index 100% rename from src/StudioCore/Res/TAE.Template.DS1.OBJ.xml rename to src/StudioCore/Assets/Res/TAE.Template.DS1.OBJ.xml diff --git a/src/StudioCore/Res/TAE.Template.DS1.xml b/src/StudioCore/Assets/Res/TAE.Template.DS1.xml similarity index 100% rename from src/StudioCore/Res/TAE.Template.DS1.xml rename to src/StudioCore/Assets/Res/TAE.Template.DS1.xml diff --git a/src/StudioCore/Res/TAE.Template.DS3.OBJ.xml b/src/StudioCore/Assets/Res/TAE.Template.DS3.OBJ.xml similarity index 100% rename from src/StudioCore/Res/TAE.Template.DS3.OBJ.xml rename to src/StudioCore/Assets/Res/TAE.Template.DS3.OBJ.xml diff --git a/src/StudioCore/Res/TAE.Template.DS3.xml b/src/StudioCore/Assets/Res/TAE.Template.DS3.xml similarity index 100% rename from src/StudioCore/Res/TAE.Template.DS3.xml rename to src/StudioCore/Assets/Res/TAE.Template.DS3.xml diff --git a/src/StudioCore/Res/TAE.Template.SDT.OBJ.xml b/src/StudioCore/Assets/Res/TAE.Template.SDT.OBJ.xml similarity index 100% rename from src/StudioCore/Res/TAE.Template.SDT.OBJ.xml rename to src/StudioCore/Assets/Res/TAE.Template.SDT.OBJ.xml diff --git a/src/StudioCore/Res/TAE.Template.SDT.xml b/src/StudioCore/Assets/Res/TAE.Template.SDT.xml similarity index 100% rename from src/StudioCore/Res/TAE.Template.SDT.xml rename to src/StudioCore/Assets/Res/TAE.Template.SDT.xml diff --git a/src/StudioCore/Interface/AliasUtils.cs b/src/StudioCore/Banks/AliasBank/AliasUtils.cs similarity index 93% rename from src/StudioCore/Interface/AliasUtils.cs rename to src/StudioCore/Banks/AliasBank/AliasUtils.cs index 01906485d..0bf97c36d 100644 --- a/src/StudioCore/Interface/AliasUtils.cs +++ b/src/StudioCore/Banks/AliasBank/AliasUtils.cs @@ -14,30 +14,9 @@ using System.Threading.Tasks; using static Andre.Native.ImGuiBindings; -namespace StudioCore.Interface; +namespace StudioCore.Banks.AliasBank; public static class AliasUtils { - public static void DisplayAlias(string aliasName) - { - if (aliasName != "") - { - ImGui.SameLine(); - ImGui.PushTextWrapPos(0); - ImGui.TextColored(new Vector4(1.0f, 1.0f, 0.0f, 1.0f), @$"{aliasName}"); - ImGui.PopTextWrapPos(); - } - } - public static void DisplayTagAlias(string aliasName) - { - if (aliasName != "") - { - ImGui.SameLine(); - ImGui.PushTextWrapPos(0); - ImGui.TextColored(new Vector4(0.0f, 1.0f, 0.0f, 1.0f), @$"[{aliasName}]"); - ImGui.PopTextWrapPos(); - } - } - public static string GetTagListString(List refTagList) { var tagListStr = ""; diff --git a/src/StudioCore/CFG.cs b/src/StudioCore/CFG.cs index 820cd00a6..c0d40a46d 100644 --- a/src/StudioCore/CFG.cs +++ b/src/StudioCore/CFG.cs @@ -1,5 +1,5 @@ using StudioCore.Platform; -using StudioCore.Scene; +using StudioCore.Renderer.Scene; using System; using System.Collections.Generic; using System.Drawing; @@ -17,7 +17,7 @@ internal partial class CfgSerializerContext : JsonSerializerContext { } -public class CFG +public partial class CFG { public const string FolderName = "DSMapStudio"; public const string Config_FileName = "DSMapStudio_Config.json"; @@ -28,9 +28,6 @@ public class CFG private static readonly object _lock_SaveLoadCFG = new(); - //private string _Param_Export_Array_Delimiter = "|"; - private string _Param_Export_Delimiter = ","; - // JsonExtensionData stores info in config file not present in class in order to retain settings between versions. #pragma warning disable IDE0051 [JsonExtensionData] public IDictionary AdditionalData; @@ -65,140 +62,8 @@ public class CFG public bool MapAliases_ShowTagsInBrowser = true; public bool MapAliases_ShowAliasAddition = false; - // Settings: Map Editor - public bool Viewport_Enable_Selection_Outline = false; - - public bool MapEditor_MapObjectList_ShowMapNames = true; - public bool MapEditor_MapObjectList_ShowCharacterNames = true; - public bool MapEditor_MapObjectList_ShowAssetNames = true; - public bool MapEditor_MapObjectList_ShowMapPieceNames = true; - public bool MapEditor_MapObjectList_ShowPlayerCharacterNames = true; - public bool MapEditor_MapObjectList_ShowSystemCharacterNames = true; - public bool MapEditor_MapObjectList_ShowTreasureNames = true; - - public bool EnableFrustrumCulling = false; - public bool Map_AlwaysListLoadedMaps = true; - public bool EnableEldenRingAutoMapOffset = true; - - public bool Map_EnableViewportGrid = false; - public int Map_ViewportGridType = 0; - public Vector3 GFX_Viewport_Grid_Color = Utils.GetDecimalColor(Color.Red); - public int Map_ViewportGrid_TotalSize = 1000; - public int Map_ViewportGrid_IncrementSize = 10; - - public float Map_ViewportGrid_Offset = 0; - - public float Map_ViewportGrid_ShortcutIncrement = 1; - - public float Map_MoveSelectionToCamera_Radius = 3.0f; - public float GFX_Camera_FOV { get; set; } = 60.0f; - public float GFX_Camera_MoveSpeed_Slow { get; set; } = 1.0f; - public float GFX_Camera_MoveSpeed_Normal { get; set; } = 20.0f; - public float GFX_Camera_MoveSpeed_Fast { get; set; } = 200.0f; - public float GFX_Camera_Sensitivity { get; set; } = 0.0160f; - public float GFX_RenderDistance_Max { get; set; } = 50000.0f; - public float Map_ArbitraryRotation_X_Shift { get; set; } = 90.0f; - public float Map_ArbitraryRotation_Y_Shift { get; set; } = 90.0f; - - public float GFX_Framerate_Limit_Unfocused = 20.0f; - public float GFX_Framerate_Limit = 60.0f; - public uint GFX_Limit_Buffer_Flver_Bone = 65536; - public uint GFX_Limit_Buffer_Indirect_Draw = 50000; - public int GFX_Limit_Renderables = 50000; - - public float GFX_Wireframe_Color_Variance = 0.11f; - - public Vector3 GFX_Renderable_Box_BaseColor = Utils.GetDecimalColor(Color.Blue); - public Vector3 GFX_Renderable_Box_HighlightColor = Utils.GetDecimalColor(Color.DarkViolet); - - public Vector3 GFX_Renderable_Cylinder_BaseColor = Utils.GetDecimalColor(Color.Blue); - public Vector3 GFX_Renderable_Cylinder_HighlightColor = Utils.GetDecimalColor(Color.DarkViolet); - - public Vector3 GFX_Renderable_Sphere_BaseColor = Utils.GetDecimalColor(Color.Blue); - public Vector3 GFX_Renderable_Sphere_HighlightColor = Utils.GetDecimalColor(Color.DarkViolet); - - public Vector3 GFX_Renderable_Point_BaseColor = Utils.GetDecimalColor(Color.Yellow); - public Vector3 GFX_Renderable_Point_HighlightColor = Utils.GetDecimalColor(Color.DarkViolet); - - public Vector3 GFX_Renderable_DummyPoly_BaseColor = Utils.GetDecimalColor(Color.Yellow); - public Vector3 GFX_Renderable_DummyPoly_HighlightColor = Utils.GetDecimalColor(Color.DarkViolet); - - public Vector3 GFX_Renderable_BonePoint_BaseColor = Utils.GetDecimalColor(Color.Blue); - public Vector3 GFX_Renderable_BonePoint_HighlightColor = Utils.GetDecimalColor(Color.DarkViolet); - - public Vector3 GFX_Renderable_ModelMarker_Chr_BaseColor = Utils.GetDecimalColor(Color.Firebrick); - public Vector3 GFX_Renderable_ModelMarker_Chr_HighlightColor = Utils.GetDecimalColor(Color.Tomato); - - public Vector3 GFX_Renderable_ModelMarker_Object_BaseColor = Utils.GetDecimalColor(Color.MediumVioletRed); - public Vector3 GFX_Renderable_ModelMarker_Object_HighlightColor = Utils.GetDecimalColor(Color.DeepPink); - - public Vector3 GFX_Renderable_ModelMarker_Player_BaseColor = Utils.GetDecimalColor(Color.DarkOliveGreen); - public Vector3 GFX_Renderable_ModelMarker_Player_HighlightColor = Utils.GetDecimalColor(Color.OliveDrab); - - public Vector3 GFX_Renderable_ModelMarker_Other_BaseColor = Utils.GetDecimalColor(Color.Wheat); - public Vector3 GFX_Renderable_ModelMarker_Other_HighlightColor = Utils.GetDecimalColor(Color.AntiqueWhite); - - public Vector3 GFX_Renderable_PointLight_BaseColor = Utils.GetDecimalColor(Color.YellowGreen); - public Vector3 GFX_Renderable_PointLight_HighlightColor = Utils.GetDecimalColor(Color.Yellow); - - public Vector3 GFX_Renderable_SpotLight_BaseColor = Utils.GetDecimalColor(Color.Goldenrod); - public Vector3 GFX_Renderable_SpotLight_HighlightColor = Utils.GetDecimalColor(Color.Violet); - - public Vector3 GFX_Renderable_DirectionalLight_BaseColor = Utils.GetDecimalColor(Color.Cyan); - public Vector3 GFX_Renderable_DirectionalLight_HighlightColor = Utils.GetDecimalColor(Color.AliceBlue); - - public Vector3 GFX_Gizmo_X_BaseColor = new(0.952f, 0.211f, 0.325f); - public Vector3 GFX_Gizmo_X_HighlightColor = new(1.0f, 0.4f, 0.513f); - - public Vector3 GFX_Gizmo_Y_BaseColor = new(0.525f, 0.784f, 0.082f); - public Vector3 GFX_Gizmo_Y_HighlightColor = new(0.713f, 0.972f, 0.270f); - - public Vector3 GFX_Gizmo_Z_BaseColor = new(0.219f, 0.564f, 0.929f); - public Vector3 GFX_Gizmo_Z_HighlightColor = new(0.407f, 0.690f, 1.0f); - public RenderFilter LastSceneFilter { get; set; } = RenderFilter.All ^ RenderFilter.Light; - - public RenderFilterPreset SceneFilter_Preset_01 { get; set; } = new("Map", - RenderFilter.MapPiece | RenderFilter.Object | RenderFilter.Character | RenderFilter.Region); - - public RenderFilterPreset SceneFilter_Preset_02 { get; set; } = new("Collision", - RenderFilter.Collision | RenderFilter.Object | RenderFilter.Character | RenderFilter.Region); - - public RenderFilterPreset SceneFilter_Preset_03 { get; set; } = new("Collision & Navmesh", - RenderFilter.Collision | RenderFilter.Navmesh | RenderFilter.Object | RenderFilter.Character | - RenderFilter.Region); - - public RenderFilterPreset SceneFilter_Preset_04 { get; set; } = new("Lighting (Map)", - RenderFilter.MapPiece | RenderFilter.Object | RenderFilter.Character | RenderFilter.Light); - - public RenderFilterPreset SceneFilter_Preset_05 { get; set; } = new("Lighting (Collision)", - RenderFilter.Collision | RenderFilter.Object | RenderFilter.Character | RenderFilter.Light); - - public RenderFilterPreset SceneFilter_Preset_06 { get; set; } = new("All", RenderFilter.All); - // Settings: Model Editor - // Settings: Param Editor - public bool Param_AdvancedMassedit = false; - public bool Param_AllowFieldReorder = true; - public bool Param_AlphabeticalParams = true; - public bool Param_DisableLineWrapping = false; - public bool Param_DisableRowGrouping = false; - public bool Param_HideEnums = false; - public bool Param_HideReferenceRows = false; - public bool Param_MakeMetaNamesPrimary = true; - public bool Param_PasteAfterSelection = false; - public bool Param_PasteThenSelect = true; - public bool Param_ShowFieldOffsets = false; - public bool Param_ShowHotkeysInContextMenu = true; - public bool Param_ShowSecondaryNames = true; - public bool Param_ShowVanillaParams = true; - public bool UI_CompactParams = false; - - // Settings: Text Editor - public bool FMG_NoFmgPatching = false; - public bool FMG_NoGroupedFmgEntries = false; - public bool FMG_ShowOriginalNames = false; - // CFG public static CFG Current { get; private set; } public static CFG Default { get; } = new(); @@ -214,26 +79,6 @@ public class CFG public int GFX_Display_X { get; set; } = 0; public int GFX_Display_Y { get; set; } = 23; - public string Param_Export_Delimiter - { - get - { - if (_Param_Export_Delimiter.Length == 0) - { - _Param_Export_Delimiter = Default.Param_Export_Delimiter; - } - else if (_Param_Export_Delimiter == "|") - { - _Param_Export_Delimiter = - Default - .Param_Export_Delimiter; // Temporary measure to prevent conflicts with byte array delimiters. Will be removed later. - } - - return _Param_Export_Delimiter; - } - set => _Param_Export_Delimiter = value; - } - public static string GetConfigFilePath() { return $@"{GetConfigFolderPath()}\{Config_FileName}"; @@ -428,21 +273,4 @@ public bool IsSameProjectLocation(RecentProject otherProject) return false; } } - - public class RenderFilterPreset - { - [JsonConstructor] - public RenderFilterPreset() - { - } - - public RenderFilterPreset(string name, RenderFilter filters) - { - Name = name; - Filters = filters; - } - - public string Name { get; set; } - public RenderFilter Filters { get; set; } - } } diff --git a/src/StudioCore/DataBank.cs b/src/StudioCore/DataBank.cs new file mode 100644 index 000000000..f11d9adeb --- /dev/null +++ b/src/StudioCore/DataBank.cs @@ -0,0 +1,19 @@ +namespace StudioCore; + +/// +/// Class that stores a collection of game data sourced from a single project +/// +public abstract class DataBank : StudioResource +{ + public Project Project; + + public DataBank(Project project, string nameForUI) : base(project.Settings.GameType, nameForUI) + { + Project = project; + } + public override string GetTaskName() + { + return $@"Resource - Loading {nameForUI} ({Project.Settings.ProjectName})"; + } + public abstract void Save(); +} diff --git a/src/StudioCore/DebugPrimitives/VertexPositionColorNormal.cs b/src/StudioCore/DebugPrimitives/VertexPositionColorNormal.cs deleted file mode 100644 index 5f8563f54..000000000 --- a/src/StudioCore/DebugPrimitives/VertexPositionColorNormal.cs +++ /dev/null @@ -1,2 +0,0 @@ -namespace StudioCore.DebugPrimitives; - diff --git a/src/StudioCore/Editor/Action.cs b/src/StudioCore/Editor/Action.cs index 466095945..536e38b18 100644 --- a/src/StudioCore/Editor/Action.cs +++ b/src/StudioCore/Editor/Action.cs @@ -140,222 +140,6 @@ private class PropertyChange public PropertyInfo Property; } } - -public class AddParamsAction : EditorAction -{ - private readonly bool appOnly; - private readonly List Clonables = new(); - private readonly List Clones = new(); - private readonly int InsertIndex; - private readonly Param Param; - private readonly List Removed = new(); - private readonly List RemovedIndex = new(); - private readonly bool replParams; - private string ParamString; - - public AddParamsAction(Param param, string pstring, List rows, bool appendOnly, bool replaceParams, - int index = -1) - { - Param = param; - Clonables.AddRange(rows); - ParamString = pstring; - appOnly = appendOnly; - replParams = replaceParams; - InsertIndex = index; - } - - public override ActionEvent Execute() - { - foreach (Param.Row row in Clonables) - { - var newrow = new Param.Row(row); - if (InsertIndex > -1) - { - newrow.Name = row.Name != null ? row.Name + "_1" : ""; - Param.InsertRow(InsertIndex, newrow); - } - else - { - if (Param[row.ID] != null) - { - if (replParams) - { - Param.Row existing = Param[row.ID]; - RemovedIndex.Add(Param.IndexOfRow(existing)); - Removed.Add(existing); - Param.RemoveRow(existing); - } - else - { - newrow.Name = row.Name != null ? row.Name + "_1" : ""; - var newID = row.ID + 1; - while (Param[newID] != null) - { - newID++; - } - - newrow.ID = newID; - Param.InsertRow(Param.IndexOfRow(Param[newID - 1]) + 1, newrow); - } - } - - if (Param[row.ID] == null) - { - newrow.Name = row.Name != null ? row.Name : ""; - if (appOnly) - { - Param.AddRow(newrow); - } - else - { - var index = 0; - foreach (Param.Row r in Param.Rows) - { - if (r.ID > newrow.ID) - { - break; - } - - index++; - } - - Param.InsertRow(index, newrow); - } - } - } - - Clones.Add(newrow); - } - - // Refresh diff cache - TaskManager.Run(new TaskManager.LiveTask("Param - Check Differences", - TaskManager.RequeueType.Repeat, true, - TaskLogs.LogPriority.Low, - () => ParamBank.RefreshAllParamDiffCaches(false))); - return ActionEvent.NoEvent; - } - - public override ActionEvent Undo() - { - for (var i = 0; i < Clones.Count(); i++) - { - Param.RemoveRow(Clones[i]); - } - - for (var i = Removed.Count() - 1; i >= 0; i--) - { - Param.InsertRow(RemovedIndex[i], Removed[i]); - } - - Clones.Clear(); - RemovedIndex.Clear(); - Removed.Clear(); - return ActionEvent.NoEvent; - } - - public List GetResultantRows() - { - return Clones; - } -} - -public class DeleteParamsAction : EditorAction -{ - private readonly List Deletables = new(); - private readonly Param Param; - private readonly List RemoveIndices = new(); - private readonly bool SetSelection = false; - - public DeleteParamsAction(Param param, List rows) - { - Param = param; - Deletables.AddRange(rows); - } - - public override ActionEvent Execute() - { - foreach (Param.Row row in Deletables) - { - RemoveIndices.Add(Param.IndexOfRow(row)); - Param.RemoveRowAt(RemoveIndices.Last()); - } - - if (SetSelection) - { - } - - return ActionEvent.NoEvent; - } - - public override ActionEvent Undo() - { - for (var i = Deletables.Count() - 1; i >= 0; i--) - { - Param.InsertRow(RemoveIndices[i], Deletables[i]); - } - - if (SetSelection) - { - } - - // Refresh diff cache - TaskManager.Run(new TaskManager.LiveTask("Param - Check Differences", - TaskManager.RequeueType.Repeat, true, - TaskLogs.LogPriority.Low, - () => ParamBank.RefreshAllParamDiffCaches(false))); - return ActionEvent.NoEvent; - } -} - -public class DuplicateFMGEntryAction : EditorAction -{ - private readonly FMGEntryGroup EntryGroup; - private FMGEntryGroup NewEntryGroup; - - public DuplicateFMGEntryAction(FMGEntryGroup entryGroup) - { - EntryGroup = entryGroup; - } - - public override ActionEvent Execute() - { - NewEntryGroup = EntryGroup.DuplicateFMGEntries(); - NewEntryGroup.SetNextUnusedID(); - return ActionEvent.NoEvent; - } - - public override ActionEvent Undo() - { - NewEntryGroup.DeleteEntries(); - return ActionEvent.NoEvent; - } -} - -public class DeleteFMGEntryAction : EditorAction -{ - private FMGEntryGroup BackupEntryGroup = new(); - private FMGEntryGroup EntryGroup; - - public DeleteFMGEntryAction(FMGEntryGroup entryGroup) - { - EntryGroup = entryGroup; - } - - public override ActionEvent Execute() - { - BackupEntryGroup = EntryGroup.CloneEntryGroup(); - EntryGroup.DeleteEntries(); - return ActionEvent.NoEvent; - } - - public override ActionEvent Undo() - { - EntryGroup = BackupEntryGroup; - EntryGroup.ImplementEntryGroup(); - return ActionEvent.NoEvent; - } -} - public class CompoundAction : EditorAction { private readonly List Actions; diff --git a/src/StudioCore/Editor/EditorDecorations.cs b/src/StudioCore/Editor/EditorDecorations.cs index 5c8c06dd1..9ff8a4093 100644 --- a/src/StudioCore/Editor/EditorDecorations.cs +++ b/src/StudioCore/Editor/EditorDecorations.cs @@ -4,6 +4,7 @@ using SoulsFormats; using StudioCore.ParamEditor; using StudioCore.TextEditor; +using StudioCore.Utilities; using System; using System.Collections.Generic; using System.Diagnostics; @@ -28,6 +29,23 @@ public static bool HelpIcon(string id, ref string hint, bool canEdit) return UIHints.AddImGuiHintButton(id, ref hint, canEdit, true); //presently a hack, move code here } + // A second one with brackets and hover instead + public static void ShowHelpMarker(string desc) + { + if (CFG.Current.ShowUITooltips) + { + ImGui.TextDisabled("(?)"); + if (ImGui.IsItemHovered(0)) + { + ImGui.BeginTooltip(); + ImGui.PushTextWrapPos(450.0f); + ImGui.TextUnformatted(desc); + ImGui.PopTextWrapPos(); + ImGui.EndTooltip(); + } + ImGui.SameLine(); + } + } public static void ParamRefText(List paramRefs, Param.Row context) { @@ -924,5 +942,136 @@ public static void ImGui_DisplayPropertyInfo(Type propType, string fieldName, st } ImGui.Separator(); + } + public static unsafe void ShowMenuIcon(string iconStr) + { + ImGui.PushStyleVarVec2(ImGuiStyleVar.ItemSpacing, new Vector2(0, ImGui.GetStyle()->ItemSpacing.Y)); + ImGui.TextUnformatted(iconStr); + ImGui.PopStyleVar(1); + ImGui.SameLine(); + } + + public static unsafe void ShowActiveStatus(bool isActive) + { + if (isActive) + { + ImGui.SameLine(); + ImGui.PushStyleVarVec2(ImGuiStyleVar.ItemSpacing, new Vector2(0, ImGui.GetStyle()->ItemSpacing.Y)); + ImGui.TextUnformatted($"{ForkAwesome.CheckSquare}"); + ImGui.PopStyleVar(1); + } + else + { + ImGui.SameLine(); + ImGui.PushStyleVarVec2(ImGuiStyleVar.ItemSpacing, new Vector2(0, ImGui.GetStyle()->ItemSpacing.Y)); + ImGui.TextUnformatted($"{ForkAwesome.Square}"); + ImGui.PopStyleVar(1); + } + } + + public static void ShowHelpButton(string title, string desc, string id) + { + if (ImGui.Button($"{title}")) + ImGui.OpenPopup($"##{id}HelpPopup"); + + if (ImGui.BeginPopup($"##{id}HelpPopup")) + { + ImGui.Text($"{desc}"); + ImGui.EndPopup(); + } + } + + public static void ShowButtonTooltip(string desc) + { + if (CFG.Current.ShowUITooltips) + { + if (ImGui.IsItemHovered(0)) + { + ImGui.BeginTooltip(); + ImGui.PushTextWrapPos(450.0f); + ImGui.TextUnformatted(desc); + ImGui.PopTextWrapPos(); + ImGui.EndTooltip(); + } + } + } + + public static void ShowHoverTooltip(string desc) + { + if (CFG.Current.ShowUITooltips) + { + if (ImGui.IsItemHovered(0)) + { + ImGui.BeginTooltip(); + ImGui.PushTextWrapPos(450.0f); + ImGui.TextUnformatted(desc); + ImGui.PopTextWrapPos(); + ImGui.EndTooltip(); + } + } } + + public static void ShowWideHoverTooltip(string desc) + { + if (CFG.Current.ShowUITooltips) + { + if (ImGui.IsItemHovered(0)) + { + ImGui.BeginTooltip(); + ImGui.PushTextWrapPos(800.0f); + ImGui.TextUnformatted(desc); + ImGui.PopTextWrapPos(); + ImGui.EndTooltip(); + } + } + } + + public static string GetKeybindHint(string hint) + { + if (hint == "") + return "None"; + else + return hint; + } + + public static void WrappedText(string text) + { + var size = ImGui.GetWindowSize(); + + ImGui.PushTextWrapPos(size.X); + ImGui.TextUnformatted(text); + ImGui.PopTextWrapPos(); + } + + public static void WrappedTextColored(Vector4 color, string text) + { + var size = ImGui.GetWindowSize(); + + ImGui.PushTextWrapPos(size.X); + ImGui.PushStyleColorVec4(ImGuiCol.Text, color); + ImGui.TextUnformatted(text); + ImGui.PopStyleColor(1); + ImGui.PopTextWrapPos(); + } + public static void DisplayAlias(string aliasName) + { + if (aliasName != "") + { + ImGui.SameLine(); + ImGui.PushTextWrapPos(0); + ImGui.TextColored(new Vector4(1.0f, 1.0f, 0.0f, 1.0f), @$"{aliasName}"); + ImGui.PopTextWrapPos(); + } + } + public static void DisplayTagAlias(string aliasName) + { + if (aliasName != "") + { + ImGui.SameLine(); + ImGui.PushTextWrapPos(0); + ImGui.TextColored(new Vector4(0.0f, 1.0f, 0.0f, 1.0f), @$"[{aliasName}]"); + ImGui.PopTextWrapPos(); + } + } + } diff --git a/src/StudioCore/Editor/EditorScreen.cs b/src/StudioCore/Editor/EditorScreen.cs index 8c1d277e0..96014d534 100644 --- a/src/StudioCore/Editor/EditorScreen.cs +++ b/src/StudioCore/Editor/EditorScreen.cs @@ -1,4 +1,7 @@ -using Veldrid; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using Veldrid; using Veldrid.Sdl2; namespace StudioCore.Editor; @@ -81,4 +84,17 @@ public void EditorResized(Sdl2Window window, GraphicsDevice device) public void Draw(GraphicsDevice device, CommandList cl) { } + + public bool IsEnabled(Project project) + { + return StudioResource.AreResourcesLoaded(GetDependencies(project)); + } + public void Load(Project project) + { + StudioResource.Load(project, GetDependencies(project)); + } + + protected abstract IEnumerable GetDependencies(Project project); + + public abstract void SettingsMenu(); } diff --git a/src/StudioCore/Interface/HelpWindow.cs b/src/StudioCore/Editor/HelpWindow.cs similarity index 95% rename from src/StudioCore/Interface/HelpWindow.cs rename to src/StudioCore/Editor/HelpWindow.cs index 0f2e01103..e28f346d3 100644 --- a/src/StudioCore/Interface/HelpWindow.cs +++ b/src/StudioCore/Editor/HelpWindow.cs @@ -8,7 +8,7 @@ using System.Text.RegularExpressions; using static Andre.Native.ImGuiBindings; -namespace StudioCore.Interface; +namespace StudioCore.Editor; public class HelpWindow { @@ -300,9 +300,9 @@ private void DisplayHelpSection(List entries, string name, string tab // No selection if (entry == null) { - ImguiUtils.WrappedText($"No {descName} selected"); + EditorDecorations.WrappedText($"No {descName} selected"); ImGui.Separator(); - ImguiUtils.WrappedText(""); + EditorDecorations.WrappedText(""); } // Selection else @@ -341,11 +341,11 @@ private void ProcessText(HelpEntry entry, string textLine) if (entry.HeaderColor != null) { Vector4 color = new Vector4(entry.HeaderColor[0], entry.HeaderColor[1], entry.HeaderColor[2], entry.HeaderColor[3]); - ImguiUtils.WrappedTextColored(color, outputLine); + EditorDecorations.WrappedTextColored(color, outputLine); } else { - ImguiUtils.WrappedText(outputLine); + EditorDecorations.WrappedText(outputLine); } ImGui.Separator(); @@ -364,17 +364,17 @@ private void ProcessText(HelpEntry entry, string textLine) if (entry.HighlightColor != null) { Vector4 color = new Vector4(entry.HighlightColor[0], entry.HighlightColor[1], entry.HighlightColor[2], entry.HighlightColor[3]); - ImguiUtils.WrappedTextColored(color, highlightText); + EditorDecorations.WrappedTextColored(color, highlightText); var offset = highlightText.Length * 8.0f; ImGui.SameLine(offset, 0); - ImguiUtils.WrappedText(otherText); + EditorDecorations.WrappedText(otherText); } else { - ImguiUtils.WrappedText(highlightText); + EditorDecorations.WrappedText(highlightText); ImGui.SameLine(); - ImguiUtils.WrappedText(otherText); + EditorDecorations.WrappedText(otherText); } } } @@ -399,7 +399,7 @@ private void ProcessText(HelpEntry entry, string textLine) // Default else { - ImguiUtils.WrappedText(textLine); + EditorDecorations.WrappedText(textLine); } } } diff --git a/src/StudioCore/Editor/ProjectSettings.cs b/src/StudioCore/Editor/ProjectSettings.cs index 495fe6974..f88adb78c 100644 --- a/src/StudioCore/Editor/ProjectSettings.cs +++ b/src/StudioCore/Editor/ProjectSettings.cs @@ -79,6 +79,15 @@ public static ProjectSettings Deserialize(string path) } } + internal ProjectSettings CopyForGameDir() + { + ProjectSettings newProj = new(); + newProj.ProjectName = "Vanilla"; + newProj.GameRoot = GameRoot; + newProj.GameType = GameType; + newProj.UseLooseParams = false; + return newProj; + } internal ProjectSettings CopyAndAssumeFromModDir(string moddir) { ProjectSettings newProj = new(); diff --git a/src/StudioCore/Editor/TaskManager.cs b/src/StudioCore/Editor/TaskManager.cs index f75663504..718377f84 100644 --- a/src/StudioCore/Editor/TaskManager.cs +++ b/src/StudioCore/Editor/TaskManager.cs @@ -31,9 +31,9 @@ public enum RequeueType /// public static int ActiveTaskNum { get; private set; } - public static void Run(LiveTask liveTask) + public static LiveTask Run(LiveTask liveTask) { - liveTask.Run(); + return liveTask.Run(); } public static void RunPassiveTask(LiveTask liveTask) @@ -138,7 +138,7 @@ public LiveTask(string taskId, RequeueType requeueType, bool silentFail, TaskLog public Task Task { get; private set; } - public void Run() + public LiveTask Run() { if (_liveTasks.TryGetValue(TaskId, out LiveTask oldLiveTask)) { @@ -149,11 +149,11 @@ public void Run() else if (oldLiveTask.RequeueBehavior == RequeueType.Repeat) { oldLiveTask.HasScheduledRequeue = true; - return; + return oldLiveTask; } else { - return; + return oldLiveTask; } } @@ -166,6 +166,7 @@ public void Run() CreateTask(); Task.Start(); + return this; } private void CreateTask() diff --git a/src/StudioCore/Editor/CacheBank.cs b/src/StudioCore/Editor/UICache.cs similarity index 100% rename from src/StudioCore/Editor/CacheBank.cs rename to src/StudioCore/Editor/UICache.cs diff --git a/src/StudioCore/ColorSpaceHandling.cs b/src/StudioCore/Graphics/ColorSpaceHandling.cs similarity index 94% rename from src/StudioCore/ColorSpaceHandling.cs rename to src/StudioCore/Graphics/ColorSpaceHandling.cs index 5bf9c4f80..87a196538 100644 --- a/src/StudioCore/ColorSpaceHandling.cs +++ b/src/StudioCore/Graphics/ColorSpaceHandling.cs @@ -1,4 +1,4 @@ -namespace StudioCore; +namespace StudioCore.Graphics; /// /// Identifies the kind of color space handling that an uses. diff --git a/src/StudioCore/Graphics/VulkanGraphicsContext.cs b/src/StudioCore/Graphics/VulkanGraphicsContext.cs index 93b698864..6c75eef4b 100644 --- a/src/StudioCore/Graphics/VulkanGraphicsContext.cs +++ b/src/StudioCore/Graphics/VulkanGraphicsContext.cs @@ -1,5 +1,5 @@ using StudioCore.Editor; -using StudioCore.Scene; +using StudioCore.Renderer.Scene; using System.Collections.Generic; using System.Diagnostics; using Veldrid; @@ -62,7 +62,7 @@ public void Initialize() _window.Resized += () => _windowResized = true; _window.Moved += p => _windowMoved = true; - Renderer.Initialize(_gd); + Renderer.Scene.Renderer.Initialize(_gd); ResourceFactory factory = _gd.ResourceFactory; _imGuiRenderer = new VulkanImGuiRenderer(_gd, _gd.SwapchainFramebuffer.OutputDescription, @@ -115,12 +115,12 @@ public void Draw(List editors, EditorScreen focusedEditor) mainWindowCommandList.SetFullViewport(0); focusedEditor.Draw(_gd, mainWindowCommandList); - Fence fence = Renderer.Frame(mainWindowCommandList, false); + Fence fence = Renderer.Scene.Renderer.Frame(mainWindowCommandList, false); mainWindowCommandList.SetFullViewport(0); mainWindowCommandList.SetFullScissorRects(); _imGuiRenderer.Render(_gd, mainWindowCommandList); _gd.SubmitCommands(mainWindowCommandList, fence); - Renderer.SubmitPostDrawCommandLists(); + Renderer.Scene.Renderer.SubmitPostDrawCommandLists(); _gd.SwapBuffers(); } diff --git a/src/StudioCore/Graphics/VulkanImGuiRenderer.cs b/src/StudioCore/Graphics/VulkanImGuiRenderer.cs index c758e023f..af7f94f30 100644 --- a/src/StudioCore/Graphics/VulkanImGuiRenderer.cs +++ b/src/StudioCore/Graphics/VulkanImGuiRenderer.cs @@ -1,6 +1,6 @@ using Silk.NET.SDL; using static Andre.Native.ImGuiBindings; -using StudioCore.Scene; +using StudioCore.Renderer.Scene; using System; using System.Collections.Generic; using System.IO; @@ -8,7 +8,7 @@ using System.Reflection; using Veldrid; using Vortice.Vulkan; -using Renderer = StudioCore.Scene.Renderer; +using Renderer = StudioCore.Renderer.Scene.Renderer; using Texture = Veldrid.Texture; using Andre.Native; @@ -91,7 +91,7 @@ public VulkanImGuiRenderer(GraphicsDevice gd, OutputDescription outputDescriptio _windowWidth = width; _windowHeight = height; - _fontTexture = Renderer.GlobalTexturePool.AllocateTextureDescriptor(); + _fontTexture = Renderer.Scene.Renderer.GlobalTexturePool.AllocateTextureDescriptor(); var context = ImGui.CreateContext(null); ImGui.SetCurrentContext(context); @@ -237,7 +237,7 @@ public void CreateDeviceResources(GraphicsDevice gd, OutputDescription outputDes new SpecializationConstant(0, gd.IsClipSpaceYInverted), new SpecializationConstant(1, _colorSpaceHandling == ColorSpaceHandling.Legacy) }), - new[] { _layout, Renderer.GlobalTexturePool.GetLayout() }, + new[] { _layout, Renderer.Scene.Renderer.GlobalTexturePool.GetLayout() }, outputDescription); _pipeline = factory.CreateGraphicsPipeline(ref pd); _pipeline.Name = "ImGuiPipeline"; @@ -764,7 +764,7 @@ private void RenderImDrawData(ImDrawData *draw_data, GraphicsDevice gd, CommandL cl.SetGraphicsResourceSet(1, GetImageResourceSet(pcmd.TextureId)); } }*/ - Renderer.GlobalTexturePool.BindTexturePool(cl, 1); + Renderer.Scene.Renderer.GlobalTexturePool.BindTexturePool(cl, 1); cl.SetScissorRect( 0, diff --git a/src/StudioCore/NewAnimSkeleton.cs b/src/StudioCore/Havok/NewAnimSkeleton.cs similarity index 99% rename from src/StudioCore/NewAnimSkeleton.cs rename to src/StudioCore/Havok/NewAnimSkeleton.cs index 4e7d79747..f3783bae4 100644 --- a/src/StudioCore/NewAnimSkeleton.cs +++ b/src/StudioCore/Havok/NewAnimSkeleton.cs @@ -1,10 +1,10 @@ using SoulsFormats; -using StudioCore.DebugPrimitives; +using StudioCore.Renderer.DebugPrimitives; using System; using System.Collections.Generic; using System.Numerics; -namespace StudioCore; +namespace StudioCore.Havok; public class NewAnimSkeleton { diff --git a/src/StudioCore/NewBlendableTransform.cs b/src/StudioCore/Havok/NewBlendableTransform.cs similarity index 98% rename from src/StudioCore/NewBlendableTransform.cs rename to src/StudioCore/Havok/NewBlendableTransform.cs index c16300c09..191bcb6cc 100644 --- a/src/StudioCore/NewBlendableTransform.cs +++ b/src/StudioCore/Havok/NewBlendableTransform.cs @@ -1,6 +1,6 @@ using System.Numerics; -namespace StudioCore; +namespace StudioCore.Havok; public struct NewBlendableTransform { diff --git a/src/StudioCore/NewHavokAnimation.cs b/src/StudioCore/Havok/NewHavokAnimation.cs similarity index 99% rename from src/StudioCore/NewHavokAnimation.cs rename to src/StudioCore/Havok/NewHavokAnimation.cs index bcf32bf18..0dd915010 100644 --- a/src/StudioCore/NewHavokAnimation.cs +++ b/src/StudioCore/Havok/NewHavokAnimation.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.Numerics; -namespace StudioCore; +namespace StudioCore.Havok; public abstract class NewHavokAnimation { diff --git a/src/StudioCore/NewHavokAnimation_SplineCompressed.cs b/src/StudioCore/Havok/NewHavokAnimation_SplineCompressed.cs similarity index 99% rename from src/StudioCore/NewHavokAnimation_SplineCompressed.cs rename to src/StudioCore/Havok/NewHavokAnimation_SplineCompressed.cs index dcfe0d98c..15e21bcae 100644 --- a/src/StudioCore/NewHavokAnimation_SplineCompressed.cs +++ b/src/StudioCore/Havok/NewHavokAnimation_SplineCompressed.cs @@ -4,7 +4,7 @@ using System.Collections.Generic; using System.Numerics; -namespace StudioCore; +namespace StudioCore.Havok; public class NewHavokAnimation_SplineCompressed : NewHavokAnimation { diff --git a/src/StudioCore/Interface/ImguiUtils.cs b/src/StudioCore/Interface/ImguiUtils.cs deleted file mode 100644 index bf2265992..000000000 --- a/src/StudioCore/Interface/ImguiUtils.cs +++ /dev/null @@ -1,139 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Numerics; -using System.Text; -using System.Threading.Tasks; -using static Andre.Native.ImGuiBindings; - -namespace StudioCore.Interface; -public static class ImguiUtils -{ - public static unsafe void ShowMenuIcon(string iconStr) - { - ImGui.PushStyleVarVec2(ImGuiStyleVar.ItemSpacing, new Vector2(0, ImGui.GetStyle()->ItemSpacing.Y)); - ImGui.TextUnformatted(iconStr); - ImGui.PopStyleVar(1); - ImGui.SameLine(); - } - - public static unsafe void ShowActiveStatus(bool isActive) - { - if (isActive) - { - ImGui.SameLine(); - ImGui.PushStyleVarVec2(ImGuiStyleVar.ItemSpacing, new Vector2(0, ImGui.GetStyle()->ItemSpacing.Y)); - ImGui.TextUnformatted($"{ForkAwesome.CheckSquare}"); - ImGui.PopStyleVar(1); - } - else - { - ImGui.SameLine(); - ImGui.PushStyleVarVec2(ImGuiStyleVar.ItemSpacing, new Vector2(0, ImGui.GetStyle()->ItemSpacing.Y)); - ImGui.TextUnformatted($"{ForkAwesome.Square}"); - ImGui.PopStyleVar(1); - } - } - - public static void ShowHelpButton(string title, string desc, string id) - { - if (ImGui.Button($"{title}")) - ImGui.OpenPopup($"##{id}HelpPopup"); - - if (ImGui.BeginPopup($"##{id}HelpPopup")) - { - ImGui.Text($"{desc}"); - ImGui.EndPopup(); - } - } - - public static void ShowHelpMarker(string desc) - { - if (CFG.Current.ShowUITooltips) - { - ImGui.SameLine(); - ImGui.TextDisabled("(?)"); - if (ImGui.IsItemHovered(0)) - { - ImGui.BeginTooltip(); - ImGui.PushTextWrapPos(450.0f); - ImGui.TextUnformatted(desc); - ImGui.PopTextWrapPos(); - ImGui.EndTooltip(); - } - } - } - - public static void ShowButtonTooltip(string desc) - { - if (CFG.Current.ShowUITooltips) - { - if (ImGui.IsItemHovered(0)) - { - ImGui.BeginTooltip(); - ImGui.PushTextWrapPos(450.0f); - ImGui.TextUnformatted(desc); - ImGui.PopTextWrapPos(); - ImGui.EndTooltip(); - } - } - } - - public static void ShowHoverTooltip(string desc) - { - if (CFG.Current.ShowUITooltips) - { - if (ImGui.IsItemHovered(0)) - { - ImGui.BeginTooltip(); - ImGui.PushTextWrapPos(450.0f); - ImGui.TextUnformatted(desc); - ImGui.PopTextWrapPos(); - ImGui.EndTooltip(); - } - } - } - - public static void ShowWideHoverTooltip(string desc) - { - if (CFG.Current.ShowUITooltips) - { - if (ImGui.IsItemHovered(0)) - { - ImGui.BeginTooltip(); - ImGui.PushTextWrapPos(800.0f); - ImGui.TextUnformatted(desc); - ImGui.PopTextWrapPos(); - ImGui.EndTooltip(); - } - } - } - - public static string GetKeybindHint(string hint) - { - if (hint == "") - return "None"; - else - return hint; - } - - public static void WrappedText(string text) - { - var size = ImGui.GetWindowSize(); - - ImGui.PushTextWrapPos(size.X); - ImGui.TextUnformatted(text); - ImGui.PopTextWrapPos(); - } - - public static void WrappedTextColored(Vector4 color, string text) - { - var size = ImGui.GetWindowSize(); - - ImGui.PushTextWrapPos(size.X); - ImGui.PushStyleColorVec4(ImGuiCol.Text, color); - ImGui.TextUnformatted(text); - ImGui.PopStyleColor(1); - ImGui.PopTextWrapPos(); - } -} diff --git a/src/StudioCore/MapStudioNew.cs b/src/StudioCore/MapStudioNew.cs index b3c86e976..bff436c39 100644 --- a/src/StudioCore/MapStudioNew.cs +++ b/src/StudioCore/MapStudioNew.cs @@ -12,7 +12,7 @@ using StudioCore.MsbEditor; using StudioCore.ParamEditor; using StudioCore.Platform; -using StudioCore.Resource; +using StudioCore.Renderer.Resource; using StudioCore.Tests; using StudioCore.TextEditor; using System; @@ -25,9 +25,9 @@ using System.Runtime.InteropServices; using Veldrid; using Veldrid.Sdl2; -using StudioCore.Interface; +using StudioCore.Editor; using StudioCore.Utilities; -using Renderer = StudioCore.Scene.Renderer; +using Renderer = StudioCore.Renderer.Scene.Renderer; using Thread = System.Threading.Thread; using Version = System.Version; @@ -384,7 +384,7 @@ public void Run() else { // Flush the background queues - Renderer.Frame(null, true); + Renderer.Scene.Renderer.Frame(null, true); } } @@ -413,13 +413,12 @@ private void ChangeProjectSettings(ProjectSettings newsettings, string moddir, N ModelAliasBank.Bank.ReloadAliasBank(); MapAliasBank.Bank.ReloadAliasBank(); - ParamBank.ReloadParams(newsettings, options); MtdBank.ReloadMtds(); - FMGBank.ReloadFMGs(); foreach (EditorScreen editor in _editors) { editor.OnProjectChanged(_projectSettings); + editor.Load(Locator.ActiveProject); } @@ -1033,7 +1032,7 @@ private unsafe void Update(float deltaseconds) ImGui.EndMainMenuBar(); } - _settingsMenu.Display(); + _settingsMenu.Display(_editors); HelpWindow.Display(); ImGui.PopStyleVar(1); @@ -1339,7 +1338,10 @@ private unsafe void Update(float deltaseconds) { ImGui.PopStyleColor(1); ImGui.PopStyleVar(1); - editor.OnGUI(commands); + if (editor.IsEnabled(Locator.ActiveProject)) + editor.OnGUI(commands); + else + ImGui.Text("Resources required for editor not loaded."); ImGui.End(); _focusedEditor = editor; editor.Update(deltaseconds); diff --git a/src/StudioCore/MsbEditor/ModelEditorScreen.cs b/src/StudioCore/ModelEditor/ModelEditorScreen.cs similarity index 96% rename from src/StudioCore/MsbEditor/ModelEditorScreen.cs rename to src/StudioCore/ModelEditor/ModelEditorScreen.cs index 0b0ee6cdc..d4453de74 100644 --- a/src/StudioCore/MsbEditor/ModelEditorScreen.cs +++ b/src/StudioCore/ModelEditor/ModelEditorScreen.cs @@ -1,8 +1,8 @@ using static Andre.Native.ImGuiBindings; using StudioCore.Editor; -using StudioCore.Gui; -using StudioCore.Resource; -using StudioCore.Scene; +using StudioCore.Renderer.Gui; +using StudioCore.Renderer.Resource; +using StudioCore.Renderer.Scene; using System; using System.Collections.Generic; using System.Numerics; @@ -10,7 +10,7 @@ using Veldrid; using Veldrid.Sdl2; using Veldrid.Utilities; -using Viewport = StudioCore.Gui.Viewport; +using Viewport = StudioCore.Renderer.Gui.Viewport; using StudioCore.Editors.AssetBrowser; namespace StudioCore.MsbEditor; @@ -361,4 +361,17 @@ public void LoadModel(string modelid, ModelEditorModelType modelType, string map ResourceManager.AddResourceListener(asset.AssetVirtualPath, this, AccessLevel.AccessFull); } + + IEnumerable EditorScreen.GetDependencies(Project project) + { + return []; + } + + public void SettingsMenu() + { + if (ImGui.CollapsingHeader("General", ImGuiTreeNodeFlags.DefaultOpen)) + { + //Nothing here + } + } } diff --git a/src/StudioCore/MsbEditor/ModelEditorTypes.cs b/src/StudioCore/ModelEditor/ModelEditorTypes.cs similarity index 100% rename from src/StudioCore/MsbEditor/ModelEditorTypes.cs rename to src/StudioCore/ModelEditor/ModelEditorTypes.cs diff --git a/src/StudioCore/MsbEditor/ActionManager.cs b/src/StudioCore/MsbEditor/ActionManager.cs deleted file mode 100644 index 8c1e45a6d..000000000 --- a/src/StudioCore/MsbEditor/ActionManager.cs +++ /dev/null @@ -1,109 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; - -namespace StudioCore.MsbEditor; - -[Flags] -public enum ActionEvent -{ - NoEvent = 0, - - // An object was added or removed from a scene - ObjectAddedRemoved = 1 -} - -/// -/// Interface for objects that may react to events caused by actions that -/// happen. Useful for invalidating caches that various editors may have. -/// -public interface IActionEventHandler -{ - public void OnActionEvent(ActionEvent evt); -} - -/// -/// Manages undo and redo for an editor context -/// -public class ActionManager -{ - private readonly List _eventHandlers = new(); - private readonly Stack RedoStack = new(); - - private readonly Stack UndoStack = new(); - - public void AddEventHandler(IActionEventHandler handler) - { - _eventHandlers.Add(handler); - } - - private void NotifyHandlers(ActionEvent evt) - { - if (evt == ActionEvent.NoEvent) - { - return; - } - - foreach (IActionEventHandler handler in _eventHandlers) - { - handler.OnActionEvent(evt); - } - } - - public void ExecuteAction(Action a) - { - NotifyHandlers(a.Execute()); - UndoStack.Push(a); - RedoStack.Clear(); - } - - public Action PeekUndoAction() - { - if (UndoStack.Count() == 0) - { - return null; - } - - return UndoStack.Peek(); - } - - public void UndoAction() - { - if (UndoStack.Count() == 0) - { - return; - } - - Action a = UndoStack.Pop(); - NotifyHandlers(a.Undo()); - RedoStack.Push(a); - } - - public void RedoAction() - { - if (RedoStack.Count() == 0) - { - return; - } - - Action a = RedoStack.Pop(); - NotifyHandlers(a.Execute()); - UndoStack.Push(a); - } - - public bool CanUndo() - { - return UndoStack.Count() > 0; - } - - public bool CanRedo() - { - return RedoStack.Count() > 0; - } - - public void Clear() - { - UndoStack.Clear(); - RedoStack.Clear(); - } -} diff --git a/src/StudioCore/MsbEditor/AssetPrefab.cs b/src/StudioCore/MsbEditor/AssetPrefab.cs index c67c69d1c..6b2c58a2c 100644 --- a/src/StudioCore/MsbEditor/AssetPrefab.cs +++ b/src/StudioCore/MsbEditor/AssetPrefab.cs @@ -7,7 +7,7 @@ using System.Numerics; using System.Xml.Serialization; using SoulsFormats; -using StudioCore.Scene; +using StudioCore.Renderer.Scene; using System.Diagnostics; using Andre.Formats; using StudioCore.Editor; diff --git a/src/StudioCore/MsbEditor/CreateMapModal.cs b/src/StudioCore/MsbEditor/CreateMapModal.cs index 91e1c9b16..40d638754 100644 --- a/src/StudioCore/MsbEditor/CreateMapModal.cs +++ b/src/StudioCore/MsbEditor/CreateMapModal.cs @@ -3,7 +3,7 @@ using System.Numerics; using System.Text.RegularExpressions; -namespace StudioCore.Scene; +namespace StudioCore.Renderer.Scene; internal class CreateMapModal : IModal { diff --git a/src/StudioCore/MsbEditor/DisplayGroupsEditor.cs b/src/StudioCore/MsbEditor/DisplayGroupsEditor.cs index b219ae8b5..6b0b68813 100644 --- a/src/StudioCore/MsbEditor/DisplayGroupsEditor.cs +++ b/src/StudioCore/MsbEditor/DisplayGroupsEditor.cs @@ -1,5 +1,6 @@ using static Andre.Native.ImGuiBindings; -using StudioCore.Scene; +using StudioCore.Editor; +using StudioCore.Renderer.Scene; using System.Collections.Generic; using System.Linq; using System.Numerics; diff --git a/src/StudioCore/MsbEditor/Entity.cs b/src/StudioCore/MsbEditor/Entity.cs index f26ab9a83..aafa906ed 100644 --- a/src/StudioCore/MsbEditor/Entity.cs +++ b/src/StudioCore/MsbEditor/Entity.cs @@ -1,7 +1,8 @@ using Andre.Formats; using Microsoft.Extensions.Logging; using SoulsFormats; -using StudioCore.Scene; +using StudioCore.Editor; +using StudioCore.Renderer.Scene; using StudioCore.Utilities; using System; using System.Collections.Generic; @@ -743,11 +744,11 @@ public void ClearTemporaryTransform(bool updaterender = true) } } - public Action GetUpdateTransformAction(Transform newt) + public EditorAction GetUpdateTransformAction(Transform newt) { if (WrappedObject is Param.Row || WrappedObject is MergedParamRow) { - List actions = new(); + List actions = new(); var roty = (newt.EulerRotation.Y * Utils.Rad2Deg) - 180.0f; actions.Add(GetPropertyChangeAction("PositionX", newt.Position.X)); actions.Add(GetPropertyChangeAction("PositionY", newt.Position.Y)); @@ -802,9 +803,9 @@ public Action GetUpdateTransformAction(Transform newt) } } - public Action ChangeObjectProperty(string propTarget, string propValue) + public EditorAction ChangeObjectProperty(string propTarget, string propValue) { - var actions = new List(); + var actions = new List(); actions.Add(GetPropertyChangeAction(propTarget, propValue)); var act = new CompoundAction(actions); act.SetPostExecutionAction((undo) => diff --git a/src/StudioCore/MsbEditor/Gizmos.cs b/src/StudioCore/MsbEditor/Gizmos.cs index c9ad42ba8..8190081a0 100644 --- a/src/StudioCore/MsbEditor/Gizmos.cs +++ b/src/StudioCore/MsbEditor/Gizmos.cs @@ -1,6 +1,8 @@ using static Andre.Native.ImGuiBindings; -using StudioCore.DebugPrimitives; -using StudioCore.Scene; +using StudioCore.Renderer.DebugPrimitives; +using StudioCore.Editor; +using StudioCore.Renderer.Scene; +using StudioCore.Utilities; using System; using System.Collections.Generic; using System.Drawing; @@ -302,7 +304,7 @@ public void Update(Ray ray, bool canCaptureMouse) if (!InputTracker.GetMouseButton(MouseButton.Left)) { IsTransforming = false; - List actlist = new(); + List actlist = new(); foreach (Entity sel in _selection.GetFilteredSelection(o => o.HasTransform)) { sel.ClearTemporaryTransform(false); diff --git a/src/StudioCore/MsbEditor/MSBBank.cs b/src/StudioCore/MsbEditor/MSBBank.cs new file mode 100644 index 000000000..3825e0c54 --- /dev/null +++ b/src/StudioCore/MsbEditor/MSBBank.cs @@ -0,0 +1,191 @@ +using Silk.NET.OpenGL; +using SoulsFormats; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text.RegularExpressions; + +namespace StudioCore.ParamEditor; + +/// +/// Utilities for dealing with global paramdefs for a game +/// +public class MSBBank : DataBank +{ + + /// + /// List of msb names + /// + private List _msbIDs = null; + + /// + /// Mapping from msb path|name -> IMsb. + /// + private Dictionary _msbs = new(); + + public MSBBank(Project project) : base(project, "MSBs") + { + + } + + protected override void Load() + { + //move this functionality to msbbank + _msbIDs = LoadFullMapList(); + } + + public override void Save() + { + //move this functionality to msbbank - requires editing IMsb rather than Map! Current editor is a big liar! + } + + protected override IEnumerable GetDependencies(Project project) + { + return []; + } + + public IMsb GetMsb(string mapId) + { + if (_msbs.TryGetValue(mapId, out IMsb msb)) + { + return msb; + } + + AssetDescription ad = GetMapMSB(mapId); + if (ad.AssetPath == null) + { + return null; + } + string path = ad.AssetPath; + + if (Project.Type == GameType.DarkSoulsIII) + { + msb = MSB3.Read(path); + } + else if (Project.Type == GameType.Sekiro) + { + msb = MSBS.Read(path); + } + else if (Project.Type == GameType.EldenRing) + { + msb = MSBE.Read(path); + } + else if (Project.Type == GameType.ArmoredCoreVI) + { + msb = MSB_AC6.Read(path); + } + else if (Project.Type == GameType.DarkSoulsIISOTFS) + { + msb = MSB2.Read(path); + } + else if (Project.Type == GameType.Bloodborne) + { + msb = MSBB.Read(path); + } + else if (Project.Type == GameType.DemonsSouls) + { + msb = MSBD.Read(path); + } + else + { + msb = MSB1.Read(path); + } + _msbs[mapId] = msb; + return msb; + } + + + /// + /// Gets the full list of maps in the game (excluding chalice dungeons). Basically if there's an msb for it, + /// it will be in this list. + /// + /// + public List GetFullMapList() + { + if (_msbIDs == null) + _msbIDs = LoadFullMapList(); + return _msbIDs; + } + private List LoadFullMapList() + { + HashSet mapSet = new(); + + // DS2 has its own structure for msbs, where they are all inside individual folders + if (Project.Type == GameType.DarkSoulsIISOTFS) + { + foreach (var map in Project.AssetLocator.GetAllAssets(@"map", [@"*.msb"], true, true)) + { + mapSet.Add(Path.GetFileNameWithoutExtension(map)); + } + } + else + { + foreach (var msb in Project.AssetLocator.GetAllAssets(@"map\MapStudio\", [@"*.msb", @"*.msb.dcx"])) + { + mapSet.Add(ProjectAssetLocator.GetFileNameWithoutExtensions(msb)); + } + } + Regex mapRegex = new(@"^m\d{2}_\d{2}_\d{2}_\d{2}$"); + List mapList = mapSet.Where(x => mapRegex.IsMatch(x)).ToList(); + mapList.Sort(); + return mapList; + } + public AssetDescription GetMapMSB(string mapid, bool writemode = false) + { + AssetDescription ad = new(); + ad.AssetPath = null; + if (mapid.Length != 12) + { + return ad; + } + + string preferredPath; + string backupPath; + // SOFTS + if (Project.Type == GameType.DarkSoulsIISOTFS) + { + preferredPath = $@"map\{mapid}\{mapid}.msb"; + backupPath = $@"map\{mapid}\{mapid}.msb"; + } + // BB chalice maps + else if (Project.Type == GameType.Bloodborne && mapid.StartsWith("m29")) + { + preferredPath = $@"\map\MapStudio\{mapid.Substring(0, 9)}_00\{mapid}.msb.dcx"; + backupPath = $@"\map\MapStudio\{mapid.Substring(0, 9)}_00\{mapid}.msb"; + } + // DeS, DS1, DS1R + else if (Project.Type == GameType.DarkSoulsPTDE || Project.Type == GameType.DarkSoulsRemastered || + Project.Type == GameType.DemonsSouls) + { + preferredPath = $@"\map\MapStudio\{mapid}.msb"; + backupPath = $@"\map\MapStudio\{mapid}.msb.dcx"; + } + // BB, DS3, ER, SSDT + else if (Project.Type == GameType.Bloodborne || Project.Type == GameType.DarkSoulsIII || Project.Type == GameType.EldenRing || + Project.Type == GameType.Sekiro) + { + preferredPath = $@"\map\MapStudio\{mapid}.msb.dcx"; + backupPath = $@"\map\MapStudio\{mapid}.msb"; + } + else + { + preferredPath = $@"\map\MapStudio\{mapid}.msb.dcx"; + backupPath = $@"\map\MapStudio\{mapid}.msb"; + } + + + + if (writemode) + { + ad.AssetPath = $@"{Project.AssetLocator.RootDirectory}\{preferredPath}"; + } + else + { + ad.AssetPath = Project.AssetLocator.GetAssetPathFromOptions([preferredPath, backupPath]).Item2; + } + + ad.AssetName = mapid; + return ad; + } +} diff --git a/src/StudioCore/MsbEditor/Map.cs b/src/StudioCore/MsbEditor/Map.cs new file mode 100644 index 000000000..1b4e58429 --- /dev/null +++ b/src/StudioCore/MsbEditor/Map.cs @@ -0,0 +1,896 @@ +using Andre.Formats; +using SoulsFormats; +using StudioCore.Platform; +using StudioCore.Renderer.Scene; +using StudioCore.Utilities; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Numerics; +using System.Xml.Serialization; + +namespace StudioCore.MsbEditor; + +public class Map : ObjectContainer +{ + // This keeps all models that exist when loading a map, so that saves + // can be byte perfect + private readonly Dictionary LoadedModels = new(); + + public Map(Universe u, string mapid) + { + Name = mapid; + Universe = u; + var t = new TransformNode(mapid); + RootObject = new MapEntity(this, t, MapEntity.MapEntityType.MapRoot); + MapOffsetNode = new MapEntity(this, new TransformNode(mapid)); + RootObject.AddChild(MapOffsetNode); + } + + public List GParams { get; } + + /// + /// The map offset used to transform BTL lights, DS2 Generators, and Navmesh. + /// Only DS2, Bloodborne, DS3, and Sekiro define map offsets. + /// + public Transform MapOffset + { + get => MapOffsetNode.GetLocalTransform(); + set + { + var node = (TransformNode)MapOffsetNode.WrappedObject; + node.Position = value.Position; + var x = Utils.RadiansToDeg(value.EulerRotation.X); + var y = Utils.RadiansToDeg(value.EulerRotation.Y); + var z = Utils.RadiansToDeg(value.EulerRotation.Z); + node.Rotation = new Vector3(x, y, z); + } + } + + public Entity MapOffsetNode { get; set; } + + public void LoadMSB(IMsb msb) + { + foreach (IMsbModel m in msb.Models.GetEntries()) + { + LoadedModels.Add(m.Name, m); + } + + foreach (IMsbPart p in msb.Parts.GetEntries()) + { + var n = new MapEntity(this, p, MapEntity.MapEntityType.Part); + Objects.Add(n); + RootObject.AddChild(n); + } + + foreach (IMsbRegion p in msb.Regions.GetEntries()) + { + var n = new MapEntity(this, p, MapEntity.MapEntityType.Region); + Objects.Add(n); + RootObject.AddChild(n); + } + + foreach (IMsbEvent p in msb.Events.GetEntries()) + { + var n = new MapEntity(this, p, MapEntity.MapEntityType.Event); + if (p is MSB2.Event.MapOffset mo1) + { + var t = Transform.Default; + t.Position = mo1.Translation; + MapOffset = t; + } + else if (p is MSBB.Event.MapOffset mo2) + { + var t = Transform.Default; + t.Position = mo2.Position; + t.EulerRotation = new Vector3(0f, Utils.DegToRadians(mo2.RotationY), 0f); + MapOffset = t; + } + else if (p is MSB3.Event.MapOffset mo3) + { + var t = Transform.Default; + t.Position = mo3.Position; + t.EulerRotation = new Vector3(0f, Utils.DegToRadians(mo3.RotationY), 0f); + MapOffset = t; + } + else if (p is MSBS.Event.MapOffset mo4) + { + var t = Transform.Default; + t.Position = mo4.Position; + t.EulerRotation = new Vector3(0f, Utils.DegToRadians(mo4.RotationY), 0f); + MapOffset = t; + } + + Objects.Add(n); + RootObject.AddChild(n); + } + + foreach (Entity m in Objects) + { + m.BuildReferenceMap(); + } + + // Add map-level references after all others + RootObject.BuildReferenceMap(); + } + + public void LoadBTL(AssetDescription ad, BTL btl) + { + var btlParent = new MapEntity(this, ad, MapEntity.MapEntityType.Editor); + MapOffsetNode.AddChild(btlParent); + foreach (BTL.Light l in btl.Lights) + { + var n = new MapEntity(this, l, MapEntity.MapEntityType.Light); + Objects.Add(n); + btlParent.AddChild(n); + } + + BTLParents.Add(btlParent); + } + + private void AddModelDeS(IMsb m, MSBD.Model model, string name) + { + if (LoadedModels[name] != null) + { + m.Models.Add(LoadedModels[name]); + return; + } + + model.Name = name; + if (model is MSBD.Model.MapPiece) + { + model.SibPath = $@"N:\DemonsSoul\data\Model\map\{Name}\sib\{name}.sib"; + } + else if (model is MSBD.Model.Object) + { + model.SibPath = $@"N:\DemonsSoul\data\Model\obj\{name}\sib\{name}.sib"; + } + else if (model is MSBD.Model.Enemy) + { + model.SibPath = $@"N:\DemonsSoul\data\Model\chr\{name}\sib\{name}.sib"; + } + else if (model is MSBD.Model.Collision) + { + model.SibPath = $@"N:\DemonsSoul\data\Model\map\{Name}\hkxwin\{name}.hkxwin"; + } + else if (model is MSBD.Model.Navmesh) + { + model.SibPath = $@"N:\DemonsSoul\data\Model\map\{Name}\navimesh\{name}.SIB"; + } + + m.Models.Add(model); + } + + private void AddModelDS1(IMsb m, MSB1.Model model, string name) + { + if (LoadedModels[name] != null) + { + m.Models.Add(LoadedModels[name]); + return; + } + + model.Name = name; + if (model is MSB1.Model.MapPiece) + { + model.SibPath = $@"N:\FRPG\data\Model\map\{Name}\sib\{name}.sib"; + } + else if (model is MSB1.Model.Object) + { + model.SibPath = $@"N:\FRPG\data\Model\obj\{name}\sib\{name}.sib"; + } + else if (model is MSB1.Model.Enemy) + { + model.SibPath = $@"N:\FRPG\data\Model\chr\{name}\sib\{name}.sib"; + } + else if (model is MSB1.Model.Collision) + { + model.SibPath = $@"N:\FRPG\data\Model\map\{Name}\hkxwin\{name}.hkxwin"; + } + else if (model is MSB1.Model.Navmesh) + { + model.SibPath = $@"N:\FRPG\data\Model\map\{Name}\navimesh\{name}.sib"; + } + + m.Models.Add(model); + } + + private void AddModelDS2(IMsb m, MSB2.Model model, string name) + { + if (LoadedModels[name] != null) + { + m.Models.Add(LoadedModels[name]); + return; + } + + model.Name = name; + m.Models.Add(model); + } + + private void AddModelBB(IMsb m, MSBB.Model model, string name) + { + if (LoadedModels[name] != null) + { + m.Models.Add(LoadedModels[name]); + return; + } + + var a = $@"A{Name.Substring(1, 2)}"; + model.Name = name; + if (model is MSBB.Model.MapPiece) + { + model.SibPath = $@"N:\SPRJ\data\Model\map\{Name}\sib\{name}{a}.sib"; + } + else if (model is MSBB.Model.Object) + { + model.SibPath = $@"N:\SPRJ\data\Model\obj\{name.Substring(0, 3)}\{name}\sib\{name}.sib"; + } + else if (model is MSBB.Model.Enemy) + { + // Not techincally required but doing so means that unedited bloodborne maps + // will write identical to the original byte for byte + if (name == "c0000") + { + model.SibPath = $@"N:\SPRJ\data\Model\chr\{name}\sib\{name}.SIB"; + } + else + { + model.SibPath = $@"N:\SPRJ\data\Model\chr\{name}\sib\{name}.sib"; + } + } + else if (model is MSBB.Model.Collision) + { + model.SibPath = $@"N:\SPRJ\data\Model\map\{Name}\hkt\{name}{a}.hkt"; + } + else if (model is MSBB.Model.Navmesh) + { + model.SibPath = $@"N:\SPRJ\data\Model\map\{Name}\navimesh\{name}{a}.sib"; + } + else if (model is MSBB.Model.Other) + { + model.SibPath = @""; + } + + m.Models.Add(model); + } + + private void AddModelDS3(IMsb m, MSB3.Model model, string name) + { + if (LoadedModels[name] != null) + { + m.Models.Add(LoadedModels[name]); + return; + } + + model.Name = name; + if (model is MSB3.Model.MapPiece) + { + model.SibPath = $@"N:\FDP\data\Model\map\{Name}\sib\{name}.sib"; + } + else if (model is MSB3.Model.Object) + { + model.SibPath = $@"N:\FDP\data\Model\obj\{name}\sib\{name}.sib"; + } + else if (model is MSB3.Model.Enemy) + { + model.SibPath = $@"N:\FDP\data\Model\chr\{name}\sib\{name}.sib"; + } + else if (model is MSB3.Model.Collision) + { + model.SibPath = $@"N:\FDP\data\Model\map\{Name}\hkt\{name}.hkt"; + } + else if (model is MSB3.Model.Other) + { + model.SibPath = @""; + } + + m.Models.Add(model); + } + + private void AddModelSekiro(IMsb m, MSBS.Model model, string name) + { + if (LoadedModels[name] != null) + { + m.Models.Add(LoadedModels[name]); + return; + } + + model.Name = name; + if (model is MSBS.Model.MapPiece) + { + model.SibPath = $@"N:\FDP\data\Model\map\{Name}\sib\{name}.sib"; + } + else if (model is MSBS.Model.Object) + { + model.SibPath = $@"N:\FDP\data\Model\obj\{name}\sib\{name}.sib"; + } + else if (model is MSBS.Model.Enemy) + { + model.SibPath = $@"N:\FDP\data\Model\chr\{name}\sib\{name}.sib"; + } + else if (model is MSBS.Model.Collision) + { + model.SibPath = $@"N:\FDP\data\Model\map\{Name}\hkt\{name}.hkt"; + } + else if (model is MSBS.Model.Player) + { + model.SibPath = @""; + } + + m.Models.Add(model); + } + + private void AddModelER(IMsb m, MSBE.Model model, string name) + { + if (LoadedModels[name] != null) + { + m.Models.Add(LoadedModels[name]); + return; + } + + model.Name = name; + if (model is MSBE.Model.MapPiece) + { + model.SibPath = $@"N:\GR\data\Model\map\{Name}\sib\{name}.sib"; + } + else if (model is MSBE.Model.Asset) + { + model.SibPath = $@"N:\GR\data\Asset\Environment\geometry\{name.Substring(0, 6)}\{name}\sib\{name}.sib"; + } + else if (model is MSBE.Model.Enemy) + { + model.SibPath = $@"N:\GR\data\Model\chr\{name}\sib\{name}.sib"; + } + else if (model is MSBE.Model.Collision) + { + model.SibPath = $@"N:\GR\data\Model\map\{Name}\hkt\{name}.hkt"; + } + else if (model is MSBE.Model.Player) + { + model.SibPath = $@"N:\GR\data\Model\chr\{name}\sib\{name}.sib"; + } + + m.Models.Add(model); + } + + private void AddModelAC6(IMsb m, MSB_AC6.Model model, string name) + { + if (LoadedModels[name] != null) + { + m.Models.Add(LoadedModels[name]); + return; + } + + model.Name = name; + if (model is MSB_AC6.Model.MapPiece) + { + model.SourcePath = $@"N:\FNR\data\Model\map\{Name}\sib\{name}.sib"; + } + else if (model is MSB_AC6.Model.Asset) + { + model.SourcePath = $@"N:\FNR\data\Asset\Environment\geometry\{name.Substring(0, 6)}\{name}\sib\{name}.sib"; + } + else if (model is MSB_AC6.Model.Enemy) + { + model.SourcePath = $@"N:\FNR\data\Model\chr\{name}\sib\{name}.sib"; + } + else if (model is MSB_AC6.Model.Collision) + { + model.SourcePath = $@"N:\FNR\data\Model\map\{Name}\hkt\{name}.hkt"; + } + else if (model is MSB_AC6.Model.Player) + { + model.SourcePath = $@"N:\FNR\data\Model\chr\{name}\sib\{name}.sib"; + } + + m.Models.Add(model); + } + + private void AddModel(IMsb m, string name) where T : IMsbModel, new() + { + var model = new T(); + model.Name = name; + m.Models.Add(model); + } + + private void AddModelsDeS(IMsb msb) + { + foreach (KeyValuePair mk in LoadedModels.OrderBy(q => q.Key)) + { + var m = mk.Key; + if (m.StartsWith("m")) + { + AddModelDeS(msb, new MSBD.Model.MapPiece(), m); + } + + if (m.StartsWith("h")) + { + AddModelDeS(msb, new MSBD.Model.Collision(), m); + } + + if (m.StartsWith("o")) + { + AddModelDeS(msb, new MSBD.Model.Object(), m); + } + + if (m.StartsWith("c")) + { + AddModelDeS(msb, new MSBD.Model.Enemy(), m); + } + + if (m.StartsWith("n")) + { + AddModelDeS(msb, new MSBD.Model.Navmesh(), m); + } + } + } + + private void AddModelsDS1(IMsb msb) + { + foreach (KeyValuePair mk in LoadedModels.OrderBy(q => q.Key)) + { + var m = mk.Key; + if (m.StartsWith("m")) + { + AddModelDS1(msb, new MSB1.Model.MapPiece(), m); + } + + if (m.StartsWith("h")) + { + AddModelDS1(msb, new MSB1.Model.Collision(), m); + } + + if (m.StartsWith("o")) + { + AddModelDS1(msb, new MSB1.Model.Object(), m); + } + + if (m.StartsWith("c")) + { + AddModelDS1(msb, new MSB1.Model.Enemy(), m); + } + + if (m.StartsWith("n")) + { + AddModelDS1(msb, new MSB1.Model.Navmesh(), m); + } + } + } + + private void AddModelsDS2(IMsb msb) + { + foreach (KeyValuePair mk in LoadedModels.OrderBy(q => q.Key)) + { + var m = mk.Key; + if (m.StartsWith("m")) + { + AddModelDS2(msb, new MSB2.Model.MapPiece(), m); + } + + if (m.StartsWith("h")) + { + AddModelDS2(msb, new MSB2.Model.Collision(), m); + } + + if (m.StartsWith("o")) + { + AddModelDS2(msb, new MSB2.Model.Object(), m); + } + + if (m.StartsWith("n")) + { + AddModelDS2(msb, new MSB2.Model.Navmesh(), m); + } + } + } + + private void AddModelsBB(IMsb msb) + { + foreach (KeyValuePair mk in LoadedModels.OrderBy(q => q.Key)) + { + var m = mk.Key; + if (m.StartsWith("m")) + { + AddModelBB(msb, new MSBB.Model.MapPiece { Name = m }, m); + } + + if (m.StartsWith("h")) + { + AddModelBB(msb, new MSBB.Model.Collision { Name = m }, m); + } + + if (m.StartsWith("o")) + { + AddModelBB(msb, new MSBB.Model.Object { Name = m }, m); + } + + if (m.StartsWith("c")) + { + AddModelBB(msb, new MSBB.Model.Enemy { Name = m }, m); + } + + if (m.StartsWith("n")) + { + AddModelBB(msb, new MSBB.Model.Navmesh { Name = m }, m); + } + } + } + + private void AddModelsDS3(IMsb msb) + { + foreach (KeyValuePair mk in LoadedModels.OrderBy(q => q.Key)) + { + var m = mk.Key; + if (m.StartsWith("m")) + { + AddModelDS3(msb, new MSB3.Model.MapPiece { Name = m }, m); + } + + if (m.StartsWith("h")) + { + AddModelDS3(msb, new MSB3.Model.Collision { Name = m }, m); + } + + if (m.StartsWith("o")) + { + AddModelDS3(msb, new MSB3.Model.Object { Name = m }, m); + } + + if (m.StartsWith("c")) + { + AddModelDS3(msb, new MSB3.Model.Enemy { Name = m }, m); + } + } + } + + private void AddModelsSekiro(IMsb msb) + { + foreach (KeyValuePair mk in LoadedModels.OrderBy(q => q.Key)) + { + var m = mk.Key; + if (m.StartsWith("m")) + { + AddModelSekiro(msb, new MSBS.Model.MapPiece { Name = m }, m); + } + + if (m.StartsWith("h")) + { + AddModelSekiro(msb, new MSBS.Model.Collision { Name = m }, m); + } + + if (m.StartsWith("o")) + { + AddModelSekiro(msb, new MSBS.Model.Object { Name = m }, m); + } + + if (m.StartsWith("c")) + { + AddModelSekiro(msb, new MSBS.Model.Enemy { Name = m }, m); + } + } + } + + private void AddModelsER(IMsb msb) + { + foreach (KeyValuePair mk in LoadedModels.OrderBy(q => q.Key)) + { + var m = mk.Key; + if (m.ToLower().StartsWith("m")) + { + AddModelER(msb, new MSBE.Model.MapPiece { Name = m }, m); + continue; + } + + if (m.ToLower().StartsWith("h")) + { + AddModelER(msb, new MSBE.Model.Collision { Name = m }, m); + continue; + } + + if (m.ToLower().StartsWith("aeg")) + { + AddModelER(msb, new MSBE.Model.Asset { Name = m }, m); + continue; + } + + if (m.ToLower().StartsWith("c")) + { + AddModelER(msb, new MSBE.Model.Enemy { Name = m }, m); + continue; + } + } + } + + private void AddModelsAC6(IMsb msb) + { + foreach (KeyValuePair mk in LoadedModels.OrderBy(q => q.Key)) + { + var m = mk.Key; + if (m.ToLower().StartsWith("m")) + { + AddModelAC6(msb, new MSB_AC6.Model.MapPiece { Name = m }, m); + continue; + } + + if (m.ToLower().StartsWith("h")) + { + AddModelAC6(msb, new MSB_AC6.Model.Collision { Name = m }, m); + continue; + } + + if (m.ToLower().StartsWith("aeg")) + { + AddModelAC6(msb, new MSB_AC6.Model.Asset { Name = m }, m); + continue; + } + + if (m.ToLower().StartsWith("c")) + { + AddModelAC6(msb, new MSB_AC6.Model.Enemy { Name = m }, m); + continue; + } + } + } + + public void SerializeToMSB(IMsb msb, GameType game) + { + foreach (Entity m in Objects) + { + if (m.WrappedObject != null && m.WrappedObject is IMsbPart p) + { + msb.Parts.Add(p); + if (p.ModelName != null && !LoadedModels.ContainsKey(p.ModelName)) + { + LoadedModels.Add(p.ModelName, null); + } + } + else if (m.WrappedObject != null && m.WrappedObject is IMsbRegion r) + { + msb.Regions.Add(r); + } + else if (m.WrappedObject != null && m.WrappedObject is IMsbEvent e) + { + msb.Events.Add(e); + } + } + + if (game == GameType.DemonsSouls) + { + AddModelsDeS(msb); + } + else if (game == GameType.DarkSoulsPTDE || game == GameType.DarkSoulsRemastered) + { + AddModelsDS1(msb); + } + else if (game == GameType.DarkSoulsIISOTFS) + { + AddModelsDS2(msb); + } + else if (game == GameType.Bloodborne) + { + AddModelsBB(msb); + } + else if (game == GameType.DarkSoulsIII) + { + AddModelsDS3(msb); + } + else if (game == GameType.Sekiro) + { + AddModelsSekiro(msb); + } + else if (game == GameType.EldenRing) + { + AddModelsER(msb); + } + else if (game == GameType.ArmoredCoreVI) + { + AddModelsAC6(msb); + } + } + + /// + /// Gets all BTL.Light with matching ParentBtlNames. + /// + public List SerializeBtlLights(string btlName) + { + List lights = new(); + foreach (Entity p in BTLParents) + { + var ad = (AssetDescription)p.WrappedObject; + if (ad.AssetName == btlName) + { + foreach (Entity e in p.Children) + { + if (e.WrappedObject != null && e.WrappedObject is BTL.Light light) + { + lights.Add(light); + } + else + { + throw new Exception($"WrappedObject \"{e.WrappedObject}\" is not a BTL Light."); + } + } + } + } + + return lights; + } + + public void SerializeToXML(XmlSerializer serializer, TextWriter writer, GameType game) + { + serializer.Serialize(writer, this); + } + + public bool SerializeDS2Generators(Param locations, Param generators) + { + HashSet ids = new(); + foreach (Entity o in Objects) + { + if (o is MapEntity m && m.Type == MapEntity.MapEntityType.DS2Generator && + m.WrappedObject is MergedParamRow mp) + { + if (!ids.Contains(mp.ID)) + { + ids.Add(mp.ID); + } + else + { + PlatformUtils.Instance.MessageBox( + $@"{mp.Name} has an ID that's already used. Please change it to something unique and save again.", + "", MessageBoxButtons.OK, MessageBoxIcon.Error); + return false; + } + + Param.Row loc = mp.GetRow("generator-loc"); + if (loc != null) + { + // Set param positions + var newloc = new Param.Row(loc, locations); + newloc.GetCellHandleOrThrow("PositionX").SetValue( + (float)loc.GetCellHandleOrThrow("PositionX").Value); + newloc.GetCellHandleOrThrow("PositionY").SetValue( + (float)loc.GetCellHandleOrThrow("PositionY").Value); + newloc.GetCellHandleOrThrow("PositionZ").SetValue( + (float)loc.GetCellHandleOrThrow("PositionZ").Value); + locations.AddRow(newloc); + } + + Param.Row gen = mp.GetRow("generator"); + if (gen != null) + { + generators.AddRow(new Param.Row(gen, generators)); + } + } + } + + return true; + } + + public bool SerializeDS2Regist(Param regist) + { + HashSet ids = new(); + foreach (Entity o in Objects) + { + if (o is MapEntity m && m.Type == MapEntity.MapEntityType.DS2GeneratorRegist && + m.WrappedObject is Param.Row mp) + { + if (!ids.Contains(mp.ID)) + { + ids.Add(mp.ID); + } + else + { + PlatformUtils.Instance.MessageBox( + $@"{mp.Name} has an ID that's already used. Please change it to something unique and save again.", + "", MessageBoxButtons.OK, MessageBoxIcon.Error); + return false; + } + + regist.AddRow(new Param.Row(mp, regist)); + } + } + + return true; + } + + public bool SerializeDS2Events(Param evs) + { + HashSet ids = new(); + foreach (Entity o in Objects) + { + if (o is MapEntity m && m.Type == MapEntity.MapEntityType.DS2Event && m.WrappedObject is Param.Row mp) + { + if (!ids.Contains(mp.ID)) + { + ids.Add(mp.ID); + } + else + { + PlatformUtils.Instance.MessageBox( + $@"{mp.Name} has an ID that's already used. Please change it to something unique and save again.", + "", MessageBoxButtons.OK, MessageBoxIcon.Error); + return false; + } + + var newloc = new Param.Row(mp, evs); + evs.AddRow(newloc); + } + } + + return true; + } + + public bool SerializeDS2EventLocations(Param locs) + { + HashSet ids = new(); + foreach (Entity o in Objects) + { + if (o is MapEntity m && m.Type == MapEntity.MapEntityType.DS2EventLocation && + m.WrappedObject is Param.Row mp) + { + if (!ids.Contains(mp.ID)) + { + ids.Add(mp.ID); + } + else + { + PlatformUtils.Instance.MessageBox( + $@"{mp.Name} has an ID that's already used. Please change it to something unique and save again.", + "", MessageBoxButtons.OK, MessageBoxIcon.Error); + return false; + } + + // Set param location positions + var newloc = new Param.Row(mp, locs); + newloc.GetCellHandleOrThrow("PositionX").SetValue( + (float)mp.GetCellHandleOrThrow("PositionX").Value); + newloc.GetCellHandleOrThrow("PositionY").SetValue( + (float)mp.GetCellHandleOrThrow("PositionY").Value); + newloc.GetCellHandleOrThrow("PositionZ").SetValue( + (float)mp.GetCellHandleOrThrow("PositionZ").Value); + locs.AddRow(newloc); + } + } + + return true; + } + + public bool SerializeDS2ObjInstances(Param objs) + { + HashSet ids = new(); + foreach (Entity o in Objects) + { + if (o is MapEntity m && m.Type == MapEntity.MapEntityType.DS2ObjectInstance && + m.WrappedObject is Param.Row mp) + { + if (!ids.Contains(mp.ID)) + { + ids.Add(mp.ID); + } + else + { + PlatformUtils.Instance.MessageBox( + $@"{mp.Name} has an ID that's already used. Please change it to something unique and save again.", + "", MessageBoxButtons.OK, MessageBoxIcon.Error); + return false; + } + + var newobj = new Param.Row(mp, objs); + objs.AddRow(newobj); + } + } + + return true; + } + + public MapSerializationEntity SerializeHierarchy() + { + Dictionary idmap = new(); + for (var i = 0; i < Objects.Count; i++) + { + idmap.Add(Objects[i], i); + } + + return ((MapEntity)RootObject).Serialize(idmap); + } +} diff --git a/src/StudioCore/MsbEditor/MapCFG.cs b/src/StudioCore/MsbEditor/MapCFG.cs new file mode 100644 index 000000000..9ae0b747f --- /dev/null +++ b/src/StudioCore/MsbEditor/MapCFG.cs @@ -0,0 +1,140 @@ +using StudioCore.Platform; +using StudioCore.Renderer.Scene; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.IO; +using System.Numerics; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace StudioCore; + +public partial class CFG +{ + public bool Viewport_Enable_Selection_Outline = false; + + public bool MapEditor_MapObjectList_ShowMapNames = true; + public bool MapEditor_MapObjectList_ShowCharacterNames = true; + public bool MapEditor_MapObjectList_ShowAssetNames = true; + public bool MapEditor_MapObjectList_ShowMapPieceNames = true; + public bool MapEditor_MapObjectList_ShowPlayerCharacterNames = true; + public bool MapEditor_MapObjectList_ShowSystemCharacterNames = true; + public bool MapEditor_MapObjectList_ShowTreasureNames = true; + + public bool EnableFrustrumCulling = false; + public bool Map_AlwaysListLoadedMaps = true; + public bool EnableEldenRingAutoMapOffset = true; + + public bool Map_EnableViewportGrid = false; + public int Map_ViewportGridType = 0; + public Vector3 GFX_Viewport_Grid_Color = Utils.GetDecimalColor(Color.Red); + public int Map_ViewportGrid_TotalSize = 1000; + public int Map_ViewportGrid_IncrementSize = 10; + + public float Map_ViewportGrid_Offset = 0; + + public float Map_ViewportGrid_ShortcutIncrement = 1; + + public float Map_MoveSelectionToCamera_Radius = 3.0f; + public float GFX_Camera_FOV { get; set; } = 60.0f; + public float GFX_Camera_MoveSpeed_Slow { get; set; } = 1.0f; + public float GFX_Camera_MoveSpeed_Normal { get; set; } = 20.0f; + public float GFX_Camera_MoveSpeed_Fast { get; set; } = 200.0f; + public float GFX_Camera_Sensitivity { get; set; } = 0.0160f; + public float GFX_RenderDistance_Max { get; set; } = 50000.0f; + public float Map_ArbitraryRotation_X_Shift { get; set; } = 90.0f; + public float Map_ArbitraryRotation_Y_Shift { get; set; } = 90.0f; + + public float GFX_Framerate_Limit_Unfocused = 20.0f; + public float GFX_Framerate_Limit = 60.0f; + public uint GFX_Limit_Buffer_Flver_Bone = 65536; + public uint GFX_Limit_Buffer_Indirect_Draw = 50000; + public int GFX_Limit_Renderables = 50000; + + public float GFX_Wireframe_Color_Variance = 0.11f; + + public Vector3 GFX_Renderable_Box_BaseColor = Utils.GetDecimalColor(Color.Blue); + public Vector3 GFX_Renderable_Box_HighlightColor = Utils.GetDecimalColor(Color.DarkViolet); + + public Vector3 GFX_Renderable_Cylinder_BaseColor = Utils.GetDecimalColor(Color.Blue); + public Vector3 GFX_Renderable_Cylinder_HighlightColor = Utils.GetDecimalColor(Color.DarkViolet); + + public Vector3 GFX_Renderable_Sphere_BaseColor = Utils.GetDecimalColor(Color.Blue); + public Vector3 GFX_Renderable_Sphere_HighlightColor = Utils.GetDecimalColor(Color.DarkViolet); + + public Vector3 GFX_Renderable_Point_BaseColor = Utils.GetDecimalColor(Color.Yellow); + public Vector3 GFX_Renderable_Point_HighlightColor = Utils.GetDecimalColor(Color.DarkViolet); + + public Vector3 GFX_Renderable_DummyPoly_BaseColor = Utils.GetDecimalColor(Color.Yellow); + public Vector3 GFX_Renderable_DummyPoly_HighlightColor = Utils.GetDecimalColor(Color.DarkViolet); + + public Vector3 GFX_Renderable_BonePoint_BaseColor = Utils.GetDecimalColor(Color.Blue); + public Vector3 GFX_Renderable_BonePoint_HighlightColor = Utils.GetDecimalColor(Color.DarkViolet); + + public Vector3 GFX_Renderable_ModelMarker_Chr_BaseColor = Utils.GetDecimalColor(Color.Firebrick); + public Vector3 GFX_Renderable_ModelMarker_Chr_HighlightColor = Utils.GetDecimalColor(Color.Tomato); + + public Vector3 GFX_Renderable_ModelMarker_Object_BaseColor = Utils.GetDecimalColor(Color.MediumVioletRed); + public Vector3 GFX_Renderable_ModelMarker_Object_HighlightColor = Utils.GetDecimalColor(Color.DeepPink); + + public Vector3 GFX_Renderable_ModelMarker_Player_BaseColor = Utils.GetDecimalColor(Color.DarkOliveGreen); + public Vector3 GFX_Renderable_ModelMarker_Player_HighlightColor = Utils.GetDecimalColor(Color.OliveDrab); + + public Vector3 GFX_Renderable_ModelMarker_Other_BaseColor = Utils.GetDecimalColor(Color.Wheat); + public Vector3 GFX_Renderable_ModelMarker_Other_HighlightColor = Utils.GetDecimalColor(Color.AntiqueWhite); + + public Vector3 GFX_Renderable_PointLight_BaseColor = Utils.GetDecimalColor(Color.YellowGreen); + public Vector3 GFX_Renderable_PointLight_HighlightColor = Utils.GetDecimalColor(Color.Yellow); + + public Vector3 GFX_Renderable_SpotLight_BaseColor = Utils.GetDecimalColor(Color.Goldenrod); + public Vector3 GFX_Renderable_SpotLight_HighlightColor = Utils.GetDecimalColor(Color.Violet); + + public Vector3 GFX_Renderable_DirectionalLight_BaseColor = Utils.GetDecimalColor(Color.Cyan); + public Vector3 GFX_Renderable_DirectionalLight_HighlightColor = Utils.GetDecimalColor(Color.AliceBlue); + + public Vector3 GFX_Gizmo_X_BaseColor = new(0.952f, 0.211f, 0.325f); + public Vector3 GFX_Gizmo_X_HighlightColor = new(1.0f, 0.4f, 0.513f); + + public Vector3 GFX_Gizmo_Y_BaseColor = new(0.525f, 0.784f, 0.082f); + public Vector3 GFX_Gizmo_Y_HighlightColor = new(0.713f, 0.972f, 0.270f); + + public Vector3 GFX_Gizmo_Z_BaseColor = new(0.219f, 0.564f, 0.929f); + public Vector3 GFX_Gizmo_Z_HighlightColor = new(0.407f, 0.690f, 1.0f); + public RenderFilter LastSceneFilter { get; set; } = RenderFilter.All ^ RenderFilter.Light; + + public RenderFilterPreset SceneFilter_Preset_01 { get; set; } = new("Map", + RenderFilter.MapPiece | RenderFilter.Object | RenderFilter.Character | RenderFilter.Region); + + public RenderFilterPreset SceneFilter_Preset_02 { get; set; } = new("Collision", + RenderFilter.Collision | RenderFilter.Object | RenderFilter.Character | RenderFilter.Region); + + public RenderFilterPreset SceneFilter_Preset_03 { get; set; } = new("Collision & Navmesh", + RenderFilter.Collision | RenderFilter.Navmesh | RenderFilter.Object | RenderFilter.Character | + RenderFilter.Region); + + public RenderFilterPreset SceneFilter_Preset_04 { get; set; } = new("Lighting (Map)", + RenderFilter.MapPiece | RenderFilter.Object | RenderFilter.Character | RenderFilter.Light); + + public RenderFilterPreset SceneFilter_Preset_05 { get; set; } = new("Lighting (Collision)", + RenderFilter.Collision | RenderFilter.Object | RenderFilter.Character | RenderFilter.Light); + + public RenderFilterPreset SceneFilter_Preset_06 { get; set; } = new("All", RenderFilter.All); + + public class RenderFilterPreset + { + [JsonConstructor] + public RenderFilterPreset() + { + } + + public RenderFilterPreset(string name, RenderFilter filters) + { + Name = name; + Filters = filters; + } + + public string Name { get; set; } + public RenderFilter Filters { get; set; } + } +} diff --git a/src/StudioCore/MsbEditor/Action.cs b/src/StudioCore/MsbEditor/MsbAction.cs similarity index 79% rename from src/StudioCore/MsbEditor/Action.cs rename to src/StudioCore/MsbEditor/MsbAction.cs index ae29097bc..0bdc8f43a 100644 --- a/src/StudioCore/MsbEditor/Action.cs +++ b/src/StudioCore/MsbEditor/MsbAction.cs @@ -1,6 +1,7 @@ using Microsoft.Extensions.Logging; using SoulsFormats; -using StudioCore.Scene; +using StudioCore.Editor; +using StudioCore.Renderer.Scene; using StudioCore.Utilities; using System; using System.Collections.Generic; @@ -10,143 +11,10 @@ namespace StudioCore.MsbEditor; -/// -/// An action that can be performed by the user in the editor that represents -/// a single atomic editor action that affects the state of the map. Each action -/// should have enough information to apply the action AND undo the action, as -/// these actions get pushed to a stack for undo/redo -/// -public abstract class Action -{ - public abstract ActionEvent Execute(); - public abstract ActionEvent Undo(); -} - -public class PropertiesChangedAction : Action -{ - private readonly object ChangedObject; - private readonly List Changes = new(); - private Action PostExecutionAction; - - public PropertiesChangedAction(object changed) - { - ChangedObject = changed; - } - - public PropertiesChangedAction(PropertyInfo prop, object changed, object newval) - { - ChangedObject = changed; - var change = new PropertyChange(); - change.Property = prop; - change.OldValue = prop.GetValue(ChangedObject); - change.NewValue = newval; - change.ArrayIndex = -1; - Changes.Add(change); - } - - public PropertiesChangedAction(PropertyInfo prop, int index, object changed, object newval) - { - ChangedObject = changed; - var change = new PropertyChange(); - change.Property = prop; - if (index != -1 && prop.PropertyType.IsArray) - { - var a = (Array)change.Property.GetValue(ChangedObject); - change.OldValue = a.GetValue(index); - } - else - { - change.OldValue = prop.GetValue(ChangedObject); - } - - change.NewValue = newval; - change.ArrayIndex = index; - Changes.Add(change); - } - - public void AddPropertyChange(PropertyInfo prop, object newval, int index = -1) - { - var change = new PropertyChange(); - change.Property = prop; - if (index != -1 && prop.PropertyType.IsArray) - { - var a = (Array)change.Property.GetValue(ChangedObject); - change.OldValue = a.GetValue(index); - } - else - { - change.OldValue = prop.GetValue(ChangedObject); - } - - change.NewValue = newval; - change.ArrayIndex = index; - Changes.Add(change); - } - - public void SetPostExecutionAction(Action action) - { - PostExecutionAction = action; - } - - public override ActionEvent Execute() - { - foreach (PropertyChange change in Changes) - { - if (change.Property.PropertyType.IsArray && change.ArrayIndex != -1) - { - var a = (Array)change.Property.GetValue(ChangedObject); - a.SetValue(change.NewValue, change.ArrayIndex); - } - else - { - change.Property.SetValue(ChangedObject, change.NewValue); - } - } - - if (PostExecutionAction != null) - { - PostExecutionAction.Invoke(false); - } - - return ActionEvent.NoEvent; - } - - public override ActionEvent Undo() - { - foreach (PropertyChange change in Changes) - { - if (change.Property.PropertyType.IsArray && change.ArrayIndex != -1) - { - var a = (Array)change.Property.GetValue(ChangedObject); - a.SetValue(change.OldValue, change.ArrayIndex); - } - else - { - change.Property.SetValue(ChangedObject, change.OldValue); - } - } - - if (PostExecutionAction != null) - { - PostExecutionAction.Invoke(true); - } - - return ActionEvent.NoEvent; - } - - private class PropertyChange - { - public int ArrayIndex; - public object NewValue; - public object OldValue; - public PropertyInfo Property; - } -} - /// /// Copies values from one array to another without affecting references. /// -public class ArrayPropertyCopyAction : Action +public class ArrayPropertyCopyAction : EditorAction { private readonly List Changes = new(); private Action PostExecutionAction; @@ -222,7 +90,7 @@ private class PropertyChange } } -public class MultipleEntityPropertyChangeAction : Action +public class MultipleEntityPropertyChangeAction : EditorAction { private readonly HashSet ChangedEnts = new(); private readonly List Changes = new(); @@ -322,7 +190,7 @@ private class PropertyChange } } -public class CloneMapObjectsAction : Action +public class CloneMapObjectsAction : EditorAction { private static readonly Regex TrailIDRegex = new(@"_(?\d+)$"); private readonly List Clonables = new(); @@ -546,7 +414,7 @@ public override ActionEvent Undo() } } -public class AddMapObjectsAction : Action +public class AddMapObjectsAction : EditorAction { private static Regex TrailIDRegex = new(@"_(?\d+)$"); private readonly List Added = new(); @@ -635,81 +503,7 @@ public override ActionEvent Undo() } } -/// -/// Deprecated -/// -[Obsolete] -public class AddParamsAction : Action -{ - private readonly List Clonables = new(); - private readonly List Clones = new(); - private readonly PARAM Param; - private readonly bool SetSelection; - private string ParamString; - - public AddParamsAction(PARAM param, string pstring, List rows, bool setsel) - { - Param = param; - Clonables.AddRange(rows); - ParamString = pstring; - SetSelection = setsel; - } - - public override ActionEvent Execute() - { - foreach (PARAM.Row row in Clonables) - { - var newrow = new PARAM.Row(row); - if (Param[row.ID] == null) - { - newrow.Name = row.Name != null ? row.Name : ""; - var index = 0; - foreach (PARAM.Row r in Param.Rows) - { - if (r.ID > newrow.ID) - { - break; - } - - index++; - } - - Param.Rows.Insert(index, newrow); - } - else - { - newrow.Name = row.Name != null ? row.Name + "_1" : ""; - Param.Rows.Insert(Param.Rows.IndexOf(Param[row.ID]) + 1, newrow); - } - - Clones.Add(newrow); - } - - if (SetSelection) - { - // EditorCommandQueue.AddCommand($@"param/select/{ParamString}/{Clones[0].ID}"); - } - - return ActionEvent.NoEvent; - } - - public override ActionEvent Undo() - { - for (var i = 0; i < Clones.Count(); i++) - { - Param.Rows.Remove(Clones[i]); - } - - Clones.Clear(); - if (SetSelection) - { - } - - return ActionEvent.NoEvent; - } -} - -public class DeleteMapObjectsAction : Action +public class DeleteMapObjectsAction : EditorAction { private readonly List Deletables = new(); private readonly List RemoveIndices = new(); @@ -807,54 +601,7 @@ public override ActionEvent Undo() } } -/// -/// Deprecated -/// -[Obsolete] -public class DeleteParamsAction : Action -{ - private readonly List Deletables = new(); - private readonly PARAM Param; - private readonly List RemoveIndices = new(); - private readonly bool SetSelection = false; - - public DeleteParamsAction(PARAM param, List rows) - { - Param = param; - Deletables.AddRange(rows); - } - - public override ActionEvent Execute() - { - foreach (PARAM.Row row in Deletables) - { - RemoveIndices.Add(Param.Rows.IndexOf(row)); - Param.Rows.RemoveAt(RemoveIndices.Last()); - } - - if (SetSelection) - { - } - - return ActionEvent.NoEvent; - } - - public override ActionEvent Undo() - { - for (var i = 0; i < Deletables.Count(); i++) - { - Param.Rows.Insert(RemoveIndices[i], Deletables[i]); - } - - if (SetSelection) - { - } - - return ActionEvent.NoEvent; - } -} - -public class ReorderContainerObjectsAction : Action +public class ReorderContainerObjectsAction : EditorAction { private readonly List Containers = new(); private readonly bool SetSelection; @@ -992,7 +739,7 @@ public override ActionEvent Undo() } } -public class ChangeEntityHierarchyAction : Action +public class ChangeEntityHierarchyAction : EditorAction { private readonly bool SetSelection; private readonly List SourceObjects = new(); @@ -1133,7 +880,7 @@ public override ActionEvent Undo() } } -public class ChangeMapObjectType : Action +public class ChangeMapObjectType : EditorAction { private readonly List Entities = new(); private readonly List MapObjectChanges = new(); @@ -1245,58 +992,3 @@ public override ActionEvent Undo() private record MapObjectChange(object OldObject, object NewObject, MapEntity Entity); } - -public class CompoundAction : Action -{ - private readonly List Actions; - - private Action PostExecutionAction; - - public CompoundAction(List actions) - { - Actions = actions; - } - - public void SetPostExecutionAction(Action action) - { - PostExecutionAction = action; - } - - public override ActionEvent Execute() - { - var evt = ActionEvent.NoEvent; - foreach (Action act in Actions) - { - if (act != null) - { - evt |= act.Execute(); - } - } - - if (PostExecutionAction != null) - { - PostExecutionAction.Invoke(false); - } - - return evt; - } - - public override ActionEvent Undo() - { - var evt = ActionEvent.NoEvent; - foreach (Action act in Actions) - { - if (act != null) - { - evt |= act.Undo(); - } - } - - if (PostExecutionAction != null) - { - PostExecutionAction.Invoke(true); - } - - return evt; - } -} diff --git a/src/StudioCore/MsbEditor/MsbEditorScreen.cs b/src/StudioCore/MsbEditor/MsbEditorScreen.cs index d9d6f6150..5d5ed9bf1 100644 --- a/src/StudioCore/MsbEditor/MsbEditorScreen.cs +++ b/src/StudioCore/MsbEditor/MsbEditorScreen.cs @@ -2,10 +2,10 @@ using Microsoft.Extensions.Logging; using SoulsFormats; using StudioCore.Editor; -using StudioCore.Gui; +using StudioCore.Renderer.Gui; using StudioCore.Platform; -using StudioCore.Resource; -using StudioCore.Scene; +using StudioCore.Renderer.Resource; +using StudioCore.Renderer.Scene; using StudioCore.Utilities; using System; using System.Collections.Generic; @@ -15,7 +15,7 @@ using Veldrid; using Veldrid.Sdl2; using Veldrid.Utilities; -using Viewport = StudioCore.Gui.Viewport; +using Viewport = StudioCore.Renderer.Gui.Viewport; using Microsoft.AspNetCore.Mvc.ModelBinding; using StudioCore.Editors.AssetBrowser; @@ -1382,7 +1382,7 @@ private void GotoSelection() public void SetObjectModelForSelection(string modelName, string assetType, string assetMapId) { - var actlist = new List(); + var actlist = new List(); var selected = _selection.GetFilteredSelection(); @@ -1620,7 +1620,7 @@ public string PadNameString(int value) /// private void ResetRotationSelection() { - List actlist = new(); + List actlist = new(); HashSet selected = _selection.GetFilteredSelection(o => o.HasTransform); foreach (Entity s in selected) @@ -1648,7 +1648,7 @@ private void ResetRotationSelection() /// private void ArbitraryRotation_Selection(Vector3 axis, bool pivot) { - List actlist = new(); + List actlist = new(); HashSet sels = _selection.GetFilteredSelection(o => o.HasTransform); // Get the center position of the selections @@ -1709,7 +1709,7 @@ private void ArbitraryRotation_Selection(Vector3 axis, bool pivot) /// private void MoveSelectionToCamera() { - List actlist = new(); + List actlist = new(); HashSet sels = _selection.GetFilteredSelection(o => o.HasTransform); Vector3 camDir = Vector3.Transform(Vector3.UnitZ, Viewport.WorldView.CameraTransform.RotationMatrix); @@ -2109,4 +2109,400 @@ private void GenerateMCGMCP(Dictionary orderedMaps) ImGui.EndCombo(); } } + + IEnumerable EditorScreen.GetDependencies(Project project) + { + if (project.Type == GameType.DarkSoulsIISOTFS) + return [project.ParamBank, project.MSBBank]; + return [project.MSBBank]; + } + + public void SettingsMenu() + { + if (ImGui.CollapsingHeader("General", ImGuiTreeNodeFlags.DefaultOpen)) + { + EditorDecorations.ShowHelpMarker("Viewport FPS when window is focused."); + ImGui.DragFloat("Frame Limit", ref CFG.Current.GFX_Framerate_Limit, 1.0f, 5.0f, 300.0f); + + EditorDecorations.ShowHelpMarker("Viewport FPS when window is not focused."); + ImGui.DragFloat("Frame Limit (Unfocused)", ref CFG.Current.GFX_Framerate_Limit_Unfocused, 1.0f, 1.0f, 60.0f); + + EditorDecorations.ShowHelpMarker("Enabling this option will allow DSMS to render the textures of models within the viewport.\n\nNote, this feature is in an alpha state."); + ImGui.Checkbox("Enable texturing", ref CFG.Current.EnableTexturing); + + EditorDecorations.ShowHelpMarker("This option will cause loaded maps to always be visible within the map list, ignoring the search filter."); + ImGui.Checkbox("Exclude loaded maps from search filter", ref CFG.Current.Map_AlwaysListLoadedMaps); + + if (Locator.ActiveProject.Type is GameType.EldenRing) + { + if (CFG.Current.ShowUITooltips) + { + EditorDecorations.ShowHelpMarker(""); + ImGui.SameLine(); + } + ImGui.Checkbox("Enable Elden Ring auto map offset", ref CFG.Current.EnableEldenRingAutoMapOffset); + } + } + + // Scene View + // Scene View + if (ImGui.CollapsingHeader("Map Object List")) + { + ImGui.Checkbox("Display map names", ref CFG.Current.MapEditor_MapObjectList_ShowMapNames); + Editor.EditorDecorations.ShowHoverTooltip("Map names will be displayed within the scene view list."); + + ImGui.Checkbox("Display character names", ref CFG.Current.MapEditor_MapObjectList_ShowCharacterNames); + Editor.EditorDecorations.ShowHoverTooltip("Characters names will be displayed within the scene view list."); + + ImGui.Checkbox("Display asset names", ref CFG.Current.MapEditor_MapObjectList_ShowAssetNames); + Editor.EditorDecorations.ShowHoverTooltip("Asset/object names will be displayed within the scene view list."); + + ImGui.Checkbox("Display map piece names", ref CFG.Current.MapEditor_MapObjectList_ShowMapPieceNames); + Editor.EditorDecorations.ShowHoverTooltip("Map piece names will be displayed within the scene view list."); + + ImGui.Checkbox("Display treasure names", ref CFG.Current.MapEditor_MapObjectList_ShowTreasureNames); + Editor.EditorDecorations.ShowHoverTooltip("Treasure itemlot names will be displayed within the scene view list."); + } + + if (ImGui.CollapsingHeader("Selection")) + { + var arbitrary_rotation_x = CFG.Current.Map_ArbitraryRotation_X_Shift; + var arbitrary_rotation_y = CFG.Current.Map_ArbitraryRotation_Y_Shift; + var camera_radius_offset = CFG.Current.Map_MoveSelectionToCamera_Radius; + + ImGui.Checkbox("Enable selection outline", ref CFG.Current.Viewport_Enable_Selection_Outline); + Editor.EditorDecorations.ShowHoverTooltip("Enable the selection outline around map entities."); + + EditorDecorations.ShowHelpMarker("Set the angle increment amount used by Arbitary Rotation in the X-axis."); + if (ImGui.InputFloat("Rotation increment degrees: Roll", ref arbitrary_rotation_x)) + { + CFG.Current.Map_ArbitraryRotation_X_Shift = Math.Clamp(arbitrary_rotation_x, -180.0f, 180.0f); + } + + EditorDecorations.ShowHelpMarker("Set the angle increment amount used by Arbitary Rotation in the Y-axis."); + if (ImGui.InputFloat("Rotation increment degrees: Yaw", ref arbitrary_rotation_y)) + { + CFG.Current.Map_ArbitraryRotation_Y_Shift = Math.Clamp(arbitrary_rotation_y, -180.0f, 180.0f); + ; + } + + EditorDecorations.ShowHelpMarker("Set the distance at which the current select is offset from the camera when using the Move Selection to Camera action."); + if (ImGui.DragFloat("Move selection to camera (offset distance)", ref camera_radius_offset)) + { + CFG.Current.Map_MoveSelectionToCamera_Radius = camera_radius_offset; + } + } + + if (ImGui.CollapsingHeader("Camera")) + { + EditorDecorations.ShowHelpMarker("Resets all of the values within this section to their default values."); + if (ImGui.Button("Reset##ViewportCamera")) + { + CFG.Current.GFX_Camera_Sensitivity = CFG.Default.GFX_Camera_Sensitivity; + + CFG.Current.GFX_Camera_FOV = CFG.Default.GFX_Camera_FOV; + + CFG.Current.GFX_RenderDistance_Max = CFG.Default.GFX_RenderDistance_Max; + + Viewport.WorldView.CameraMoveSpeed_Slow = CFG.Default.GFX_Camera_MoveSpeed_Slow; + CFG.Current.GFX_Camera_MoveSpeed_Slow = Viewport.WorldView.CameraMoveSpeed_Slow; + + Viewport.WorldView.CameraMoveSpeed_Normal = CFG.Default.GFX_Camera_MoveSpeed_Normal; + CFG.Current.GFX_Camera_MoveSpeed_Normal = Viewport.WorldView.CameraMoveSpeed_Normal; + + Viewport.WorldView.CameraMoveSpeed_Fast = CFG.Default.GFX_Camera_MoveSpeed_Fast; + CFG.Current.GFX_Camera_MoveSpeed_Fast = Viewport.WorldView.CameraMoveSpeed_Fast; + } + + var cam_sensitivity = CFG.Current.GFX_Camera_Sensitivity; + + EditorDecorations.ShowHelpMarker("Mouse sensitivty for turning the camera."); + if (ImGui.SliderFloat("Camera sensitivity", ref cam_sensitivity, 0.0f, 0.1f)) + { + CFG.Current.GFX_Camera_Sensitivity = cam_sensitivity; + } + + var cam_fov = CFG.Current.GFX_Camera_FOV; + + EditorDecorations.ShowHelpMarker("Set the field of view used by the camera within DSMS."); + if (ImGui.SliderFloat("Camera FOV", ref cam_fov, 40.0f, 140.0f)) + { + CFG.Current.GFX_Camera_FOV = cam_fov; + } + + var farClip = CFG.Current.GFX_RenderDistance_Max; + EditorDecorations.ShowHelpMarker("Set the maximum distance at which entities will be rendered within the DSMS viewport."); + if (ImGui.SliderFloat("Map max render distance", ref farClip, 10.0f, 500000.0f)) + { + CFG.Current.GFX_RenderDistance_Max = farClip; + } + + EditorDecorations.ShowHelpMarker("Set the speed at which the camera will move when the Left or Right Shift key is pressed whilst moving."); + if (ImGui.SliderFloat("Map camera speed (slow)", + ref Viewport.WorldView.CameraMoveSpeed_Slow, 0.1f, 999.0f)) + { + CFG.Current.GFX_Camera_MoveSpeed_Slow = Viewport.WorldView.CameraMoveSpeed_Slow; + } + + EditorDecorations.ShowHelpMarker("Set the speed at which the camera will move whilst moving normally."); + if (ImGui.SliderFloat("Map camera speed (normal)", + ref Viewport.WorldView.CameraMoveSpeed_Normal, 0.1f, 999.0f)) + { + CFG.Current.GFX_Camera_MoveSpeed_Normal = Viewport.WorldView.CameraMoveSpeed_Normal; + } + + EditorDecorations.ShowHelpMarker("Set the speed at which the camera will move when the Left or Right Control key is pressed whilst moving."); + if (ImGui.SliderFloat("Map camera speed (fast)", + ref Viewport.WorldView.CameraMoveSpeed_Fast, 0.1f, 999.0f)) + { + CFG.Current.GFX_Camera_MoveSpeed_Fast = Viewport.WorldView.CameraMoveSpeed_Fast; + } + } + + if (ImGui.CollapsingHeader("Limits")) + { + EditorDecorations.ShowHelpMarker("Reset the values within this section to their default values."); + if (ImGui.Button("Reset##MapLimits")) + { + CFG.Current.GFX_Limit_Renderables = CFG.Default.GFX_Limit_Renderables; + CFG.Current.GFX_Limit_Buffer_Indirect_Draw = CFG.Default.GFX_Limit_Buffer_Indirect_Draw; + CFG.Current.GFX_Limit_Buffer_Flver_Bone = CFG.Default.GFX_Limit_Buffer_Flver_Bone; + } + + ImGui.Text("Please restart the program for changes to take effect."); + + ImGui.TextColored(new Vector4(1.0f, 0.0f, 0.0f, 1.0f), + @"Try smaller increments (+25%%) at first, as high values will cause issues."); + + EditorDecorations.ShowHelpMarker("This value constrains the number of renderable entities that are allowed. Exceeding this value will throw an exception."); + if (ImGui.InputInt("Renderables", ref CFG.Current.GFX_Limit_Renderables, 0, 0)) + { + if (CFG.Current.GFX_Limit_Renderables < CFG.Default.GFX_Limit_Renderables) + { + CFG.Current.GFX_Limit_Renderables = CFG.Default.GFX_Limit_Renderables; + } + } + + EditorDecorations.ShowHelpMarker("This value constrains the size of the indirect draw buffer. Exceeding this value will throw an exception."); + Utils.ImGui_InputUint("Indirect Draw buffer", ref CFG.Current.GFX_Limit_Buffer_Indirect_Draw); + + EditorDecorations.ShowHelpMarker("This value constrains the size of the FLVER bone buffer. Exceeding this value will throw an exception."); + Utils.ImGui_InputUint("FLVER Bone buffer", ref CFG.Current.GFX_Limit_Buffer_Flver_Bone); + } + + if (FeatureFlags.ViewportGrid) + { + if (ImGui.CollapsingHeader("Grid")) + { + EditorDecorations.ShowHelpMarker("Enable the viewport grid when in the Map Editor."); + ImGui.Checkbox("Enable viewport grid", ref CFG.Current.Map_EnableViewportGrid); + + EditorDecorations.ShowHelpMarker("The overall maximum size of the grid.\nThe grid will only update upon restarting DSMS after changing this value."); + ImGui.SliderInt("Grid size", ref CFG.Current.Map_ViewportGrid_TotalSize, 100, 1000); + + EditorDecorations.ShowHelpMarker("The increment size of the grid."); + ImGui.SliderInt("Grid increment", ref CFG.Current.Map_ViewportGrid_IncrementSize, 1, 100); + + EditorDecorations.ShowHelpMarker("The height at which the horizontal grid sits."); + ImGui.SliderFloat("Grid height", ref CFG.Current.Map_ViewportGrid_Offset, -1000, 1000); + + EditorDecorations.ShowHelpMarker("The amount to lower or raise the viewport grid height via the shortcuts."); + ImGui.SliderFloat("Grid height increment", ref CFG.Current.Map_ViewportGrid_ShortcutIncrement, 0.1f, 100); + + ImGui.ColorEdit3("Grid color", ref CFG.Current.GFX_Viewport_Grid_Color); + + EditorDecorations.ShowHelpMarker("Resets all of the values within this section to their default values."); + if (ImGui.Button("Reset")) + { + CFG.Current.GFX_Viewport_Grid_Color = Utils.GetDecimalColor(System.Drawing.Color.Red); + CFG.Current.Map_ViewportGrid_TotalSize = 1000; + CFG.Current.Map_ViewportGrid_IncrementSize = 10; + CFG.Current.Map_ViewportGrid_Offset = 0; + } + } + } + + if (ImGui.CollapsingHeader("Wireframes")) + { + EditorDecorations.ShowHelpMarker("Resets all of the values within this section to their default values."); + if (ImGui.Button("Reset")) + { + // Proxies + CFG.Current.GFX_Renderable_Box_BaseColor = Utils.GetDecimalColor(System.Drawing.Color.Blue); + CFG.Current.GFX_Renderable_Box_HighlightColor = Utils.GetDecimalColor(System.Drawing.Color.DarkViolet); + + CFG.Current.GFX_Renderable_Cylinder_BaseColor = Utils.GetDecimalColor(System.Drawing.Color.Blue); + CFG.Current.GFX_Renderable_Cylinder_HighlightColor = Utils.GetDecimalColor(System.Drawing.Color.DarkViolet); + + CFG.Current.GFX_Renderable_Sphere_BaseColor = Utils.GetDecimalColor(System.Drawing.Color.Blue); + CFG.Current.GFX_Renderable_Sphere_HighlightColor = Utils.GetDecimalColor(System.Drawing.Color.DarkViolet); + + CFG.Current.GFX_Renderable_Point_BaseColor = Utils.GetDecimalColor(System.Drawing.Color.Yellow); + CFG.Current.GFX_Renderable_Point_HighlightColor = Utils.GetDecimalColor(System.Drawing.Color.DarkViolet); + + CFG.Current.GFX_Renderable_DummyPoly_BaseColor = Utils.GetDecimalColor(System.Drawing.Color.Yellow); + CFG.Current.GFX_Renderable_DummyPoly_HighlightColor = Utils.GetDecimalColor(System.Drawing.Color.DarkViolet); + + CFG.Current.GFX_Renderable_BonePoint_BaseColor = Utils.GetDecimalColor(System.Drawing.Color.Blue); + CFG.Current.GFX_Renderable_BonePoint_HighlightColor = Utils.GetDecimalColor(System.Drawing.Color.DarkViolet); + + CFG.Current.GFX_Renderable_ModelMarker_Chr_BaseColor = Utils.GetDecimalColor(System.Drawing.Color.Firebrick); + CFG.Current.GFX_Renderable_ModelMarker_Chr_HighlightColor = Utils.GetDecimalColor(System.Drawing.Color.Tomato); + + CFG.Current.GFX_Renderable_ModelMarker_Object_BaseColor = Utils.GetDecimalColor(System.Drawing.Color.MediumVioletRed); + CFG.Current.GFX_Renderable_ModelMarker_Object_HighlightColor = Utils.GetDecimalColor(System.Drawing.Color.DeepPink); + + CFG.Current.GFX_Renderable_ModelMarker_Player_BaseColor = Utils.GetDecimalColor(System.Drawing.Color.DarkOliveGreen); + CFG.Current.GFX_Renderable_ModelMarker_Player_HighlightColor = Utils.GetDecimalColor(System.Drawing.Color.OliveDrab); + + CFG.Current.GFX_Renderable_ModelMarker_Other_BaseColor = Utils.GetDecimalColor(System.Drawing.Color.Wheat); + CFG.Current.GFX_Renderable_ModelMarker_Other_HighlightColor = Utils.GetDecimalColor(System.Drawing.Color.AntiqueWhite); + + CFG.Current.GFX_Renderable_PointLight_BaseColor = Utils.GetDecimalColor(System.Drawing.Color.YellowGreen); + CFG.Current.GFX_Renderable_PointLight_HighlightColor = Utils.GetDecimalColor(System.Drawing.Color.Yellow); + + CFG.Current.GFX_Renderable_SpotLight_BaseColor = Utils.GetDecimalColor(System.Drawing.Color.Goldenrod); + CFG.Current.GFX_Renderable_SpotLight_HighlightColor = Utils.GetDecimalColor(System.Drawing.Color.Violet); + + CFG.Current.GFX_Renderable_DirectionalLight_BaseColor = Utils.GetDecimalColor(System.Drawing.Color.Cyan); + CFG.Current.GFX_Renderable_DirectionalLight_HighlightColor = Utils.GetDecimalColor(System.Drawing.Color.AliceBlue); + + // Gizmos + CFG.Current.GFX_Gizmo_X_BaseColor = new Vector3(0.952f, 0.211f, 0.325f); + CFG.Current.GFX_Gizmo_X_HighlightColor = new Vector3(1.0f, 0.4f, 0.513f); + + CFG.Current.GFX_Gizmo_Y_BaseColor = new Vector3(0.525f, 0.784f, 0.082f); + CFG.Current.GFX_Gizmo_Y_HighlightColor = new Vector3(0.713f, 0.972f, 0.270f); + + CFG.Current.GFX_Gizmo_Z_BaseColor = new Vector3(0.219f, 0.564f, 0.929f); + CFG.Current.GFX_Gizmo_Z_HighlightColor = new Vector3(0.407f, 0.690f, 1.0f); + + // Color Variance + CFG.Current.GFX_Wireframe_Color_Variance = CFG.Default.GFX_Wireframe_Color_Variance; + } + + ImGui.SliderFloat("Wireframe color variance", ref CFG.Current.GFX_Wireframe_Color_Variance, 0.0f, 1.0f); + + // Proxies + ImGui.ColorEdit3("Box region - base color", ref CFG.Current.GFX_Renderable_Box_BaseColor); + ImGui.ColorEdit3("Box region - highlight color", ref CFG.Current.GFX_Renderable_Box_HighlightColor); + + ImGui.ColorEdit3("Cylinder region - base color", ref CFG.Current.GFX_Renderable_Cylinder_BaseColor); + ImGui.ColorEdit3("Cylinder region - highlight color", ref CFG.Current.GFX_Renderable_Cylinder_HighlightColor); + + ImGui.ColorEdit3("Sphere region - base color", ref CFG.Current.GFX_Renderable_Sphere_BaseColor); + ImGui.ColorEdit3("Sphere region - highlight color", ref CFG.Current.GFX_Renderable_Sphere_HighlightColor); + + ImGui.ColorEdit3("Point region - base color", ref CFG.Current.GFX_Renderable_Point_BaseColor); + ImGui.ColorEdit3("Point region - highlight color", ref CFG.Current.GFX_Renderable_Point_HighlightColor); + + ImGui.ColorEdit3("Dummy poly - base color", ref CFG.Current.GFX_Renderable_DummyPoly_BaseColor); + ImGui.ColorEdit3("Dummy poly - highlight color", ref CFG.Current.GFX_Renderable_DummyPoly_HighlightColor); + + ImGui.ColorEdit3("Bone point - base color", ref CFG.Current.GFX_Renderable_BonePoint_BaseColor); + ImGui.ColorEdit3("Bone point - highlight color", ref CFG.Current.GFX_Renderable_BonePoint_HighlightColor); + + ImGui.ColorEdit3("Chr marker - base color", ref CFG.Current.GFX_Renderable_ModelMarker_Chr_BaseColor); + ImGui.ColorEdit3("Chr marker - highlight color", ref CFG.Current.GFX_Renderable_ModelMarker_Chr_HighlightColor); + + ImGui.ColorEdit3("Object marker - base color", ref CFG.Current.GFX_Renderable_ModelMarker_Object_BaseColor); + ImGui.ColorEdit3("Object marker - highlight color", ref CFG.Current.GFX_Renderable_ModelMarker_Object_HighlightColor); + + ImGui.ColorEdit3("Player marker - base color", ref CFG.Current.GFX_Renderable_ModelMarker_Player_BaseColor); + ImGui.ColorEdit3("Player marker - highlight color", ref CFG.Current.GFX_Renderable_ModelMarker_Player_HighlightColor); + + ImGui.ColorEdit3("Other marker - base color", ref CFG.Current.GFX_Renderable_ModelMarker_Other_BaseColor); + ImGui.ColorEdit3("Other marker - highlight color", ref CFG.Current.GFX_Renderable_ModelMarker_Other_HighlightColor); + + ImGui.ColorEdit3("Point light - base color", ref CFG.Current.GFX_Renderable_PointLight_BaseColor); + ImGui.ColorEdit3("Point light - highlight color", ref CFG.Current.GFX_Renderable_PointLight_HighlightColor); + + ImGui.ColorEdit3("Spot light - base color", ref CFG.Current.GFX_Renderable_SpotLight_BaseColor); + ImGui.ColorEdit3("Spot light - highlight color", ref CFG.Current.GFX_Renderable_SpotLight_HighlightColor); + + ImGui.ColorEdit3("Directional light - base color", ref CFG.Current.GFX_Renderable_DirectionalLight_BaseColor); + ImGui.ColorEdit3("Directional light - highlight color", ref CFG.Current.GFX_Renderable_DirectionalLight_HighlightColor); + + // Gizmos + ImGui.ColorEdit3("Gizmo - X Axis - base color", ref CFG.Current.GFX_Gizmo_X_BaseColor); + ImGui.ColorEdit3("Gizmo - X Axis - highlight color", ref CFG.Current.GFX_Gizmo_X_HighlightColor); + + ImGui.ColorEdit3("Gizmo - Y Axis - base color", ref CFG.Current.GFX_Gizmo_Y_BaseColor); + ImGui.ColorEdit3("Gizmo - Y Axis - highlight color", ref CFG.Current.GFX_Gizmo_Y_HighlightColor); + + ImGui.ColorEdit3("Gizmo - Z Axis - base color", ref CFG.Current.GFX_Gizmo_Z_BaseColor); + ImGui.ColorEdit3("Gizmo - Z Axis - highlight color", ref CFG.Current.GFX_Gizmo_Z_HighlightColor); + } + + if (ImGui.CollapsingHeader("Map Object Display Presets")) + { + ImGui.Text("Configure each of the six display presets available."); + + EditorDecorations.ShowHelpMarker("Reset the values within this section to their default values."); + if (ImGui.Button("Reset##DisplayPresets")) + { + CFG.Current.SceneFilter_Preset_01.Name = CFG.Default.SceneFilter_Preset_01.Name; + CFG.Current.SceneFilter_Preset_01.Filters = CFG.Default.SceneFilter_Preset_01.Filters; + CFG.Current.SceneFilter_Preset_02.Name = CFG.Default.SceneFilter_Preset_02.Name; + CFG.Current.SceneFilter_Preset_02.Filters = CFG.Default.SceneFilter_Preset_02.Filters; + CFG.Current.SceneFilter_Preset_03.Name = CFG.Default.SceneFilter_Preset_03.Name; + CFG.Current.SceneFilter_Preset_03.Filters = CFG.Default.SceneFilter_Preset_03.Filters; + CFG.Current.SceneFilter_Preset_04.Name = CFG.Default.SceneFilter_Preset_04.Name; + CFG.Current.SceneFilter_Preset_04.Filters = CFG.Default.SceneFilter_Preset_04.Filters; + CFG.Current.SceneFilter_Preset_05.Name = CFG.Default.SceneFilter_Preset_05.Name; + CFG.Current.SceneFilter_Preset_05.Filters = CFG.Default.SceneFilter_Preset_05.Filters; + CFG.Current.SceneFilter_Preset_06.Name = CFG.Default.SceneFilter_Preset_06.Name; + CFG.Current.SceneFilter_Preset_06.Filters = CFG.Default.SceneFilter_Preset_06.Filters; + } + + SettingsRenderFilterPresetEditor(CFG.Current.SceneFilter_Preset_01); + SettingsRenderFilterPresetEditor(CFG.Current.SceneFilter_Preset_02); + SettingsRenderFilterPresetEditor(CFG.Current.SceneFilter_Preset_03); + SettingsRenderFilterPresetEditor(CFG.Current.SceneFilter_Preset_04); + SettingsRenderFilterPresetEditor(CFG.Current.SceneFilter_Preset_05); + SettingsRenderFilterPresetEditor(CFG.Current.SceneFilter_Preset_06); + } + + ImGui.Unindent(); + } + + private void SettingsRenderFilterPresetEditor(CFG.RenderFilterPreset preset) + { + ImGui.PushID($"{preset.Name}##PresetEdit"); + if (ImGui.CollapsingHeader($"{preset.Name}##Header")) + { + ImGui.Indent(); + var nameInput = preset.Name; + ImGui.InputText("Preset Name", ref nameInput, 32); + if (ImGui.IsItemDeactivatedAfterEdit()) + { + preset.Name = nameInput; + } + + foreach (RenderFilter e in Enum.GetValues(typeof(RenderFilter))) + { + var ticked = false; + if (preset.Filters.HasFlag(e)) + { + ticked = true; + } + + if (ImGui.Checkbox(e.ToString(), ref ticked)) + { + if (ticked) + { + preset.Filters |= e; + } + else + { + preset.Filters &= ~e; + } + } + } + + ImGui.Unindent(); + } + + ImGui.PopID(); + } } diff --git a/src/StudioCore/NavGen.cs b/src/StudioCore/MsbEditor/NavGen.cs similarity index 96% rename from src/StudioCore/NavGen.cs rename to src/StudioCore/MsbEditor/NavGen.cs index ab4b2881b..fb60629d1 100644 --- a/src/StudioCore/NavGen.cs +++ b/src/StudioCore/MsbEditor/NavGen.cs @@ -1,7 +1,7 @@ using System.Numerics; using System.Runtime.InteropServices; -namespace StudioCore; +namespace StudioCore.MsbEditor; /// /// Binding to Navgen recast based navmesh generation library diff --git a/src/StudioCore/MsbEditor/NavRegion.cs b/src/StudioCore/MsbEditor/NavRegion.cs index 58bf6c7ce..245f1275d 100644 --- a/src/StudioCore/MsbEditor/NavRegion.cs +++ b/src/StudioCore/MsbEditor/NavRegion.cs @@ -1,5 +1,5 @@ using SoulsFormats; -using StudioCore.Scene; +using StudioCore.Renderer.Scene; using System; using System.Collections.Generic; using Veldrid.Utilities; diff --git a/src/StudioCore/MsbEditor/NavmeshEditor.cs b/src/StudioCore/MsbEditor/NavmeshEditor.cs index f70485fef..5520f7154 100644 --- a/src/StudioCore/MsbEditor/NavmeshEditor.cs +++ b/src/StudioCore/MsbEditor/NavmeshEditor.cs @@ -2,8 +2,8 @@ using HKX2.Builders; using static Andre.Native.ImGuiBindings; using SoulsFormats; -using StudioCore.Resource; -using StudioCore.Scene; +using StudioCore.Renderer.Resource; +using StudioCore.Renderer.Scene; using System.Collections.Generic; using System.IO; using System.Numerics; diff --git a/src/StudioCore/MsbEditor/ObjectContainer.cs b/src/StudioCore/MsbEditor/ObjectContainer.cs index 927b397e0..4ac1618d0 100644 --- a/src/StudioCore/MsbEditor/ObjectContainer.cs +++ b/src/StudioCore/MsbEditor/ObjectContainer.cs @@ -1,7 +1,7 @@ using Andre.Formats; using SoulsFormats; using StudioCore.Platform; -using StudioCore.Scene; +using StudioCore.Renderer.Scene; using System; using System.Collections.Generic; using System.IO; @@ -15,6 +15,8 @@ namespace StudioCore.MsbEditor; /// High level class that stores a single map (msb) and can serialize/ /// deserialize it. This is the logical portion of the map and does not /// handle tasks like rendering or loading associated assets with it. +/// +/// CURRENTLY ALSO USED TO HOLD A FLVER??? /// public class ObjectContainer { @@ -177,886 +179,3 @@ public void LoadFlver(FLVER2 flver, MeshRenderableProxy proxy) } } } - -public class Map : ObjectContainer -{ - // This keeps all models that exist when loading a map, so that saves - // can be byte perfect - private readonly Dictionary LoadedModels = new(); - - public Map(Universe u, string mapid) - { - Name = mapid; - Universe = u; - var t = new TransformNode(mapid); - RootObject = new MapEntity(this, t, MapEntity.MapEntityType.MapRoot); - MapOffsetNode = new MapEntity(this, new TransformNode(mapid)); - RootObject.AddChild(MapOffsetNode); - } - - public List GParams { get; } - - /// - /// The map offset used to transform BTL lights, DS2 Generators, and Navmesh. - /// Only DS2, Bloodborne, DS3, and Sekiro define map offsets. - /// - public Transform MapOffset - { - get => MapOffsetNode.GetLocalTransform(); - set - { - var node = (TransformNode)MapOffsetNode.WrappedObject; - node.Position = value.Position; - var x = Utils.RadiansToDeg(value.EulerRotation.X); - var y = Utils.RadiansToDeg(value.EulerRotation.Y); - var z = Utils.RadiansToDeg(value.EulerRotation.Z); - node.Rotation = new Vector3(x, y, z); - } - } - - public Entity MapOffsetNode { get; set; } - - public void LoadMSB(IMsb msb) - { - foreach (IMsbModel m in msb.Models.GetEntries()) - { - LoadedModels.Add(m.Name, m); - } - - foreach (IMsbPart p in msb.Parts.GetEntries()) - { - var n = new MapEntity(this, p, MapEntity.MapEntityType.Part); - Objects.Add(n); - RootObject.AddChild(n); - } - - foreach (IMsbRegion p in msb.Regions.GetEntries()) - { - var n = new MapEntity(this, p, MapEntity.MapEntityType.Region); - Objects.Add(n); - RootObject.AddChild(n); - } - - foreach (IMsbEvent p in msb.Events.GetEntries()) - { - var n = new MapEntity(this, p, MapEntity.MapEntityType.Event); - if (p is MSB2.Event.MapOffset mo1) - { - var t = Transform.Default; - t.Position = mo1.Translation; - MapOffset = t; - } - else if (p is MSBB.Event.MapOffset mo2) - { - var t = Transform.Default; - t.Position = mo2.Position; - t.EulerRotation = new Vector3(0f, Utils.DegToRadians(mo2.RotationY), 0f); - MapOffset = t; - } - else if (p is MSB3.Event.MapOffset mo3) - { - var t = Transform.Default; - t.Position = mo3.Position; - t.EulerRotation = new Vector3(0f, Utils.DegToRadians(mo3.RotationY), 0f); - MapOffset = t; - } - else if (p is MSBS.Event.MapOffset mo4) - { - var t = Transform.Default; - t.Position = mo4.Position; - t.EulerRotation = new Vector3(0f, Utils.DegToRadians(mo4.RotationY), 0f); - MapOffset = t; - } - - Objects.Add(n); - RootObject.AddChild(n); - } - - foreach (Entity m in Objects) - { - m.BuildReferenceMap(); - } - - // Add map-level references after all others - RootObject.BuildReferenceMap(); - } - - public void LoadBTL(AssetDescription ad, BTL btl) - { - var btlParent = new MapEntity(this, ad, MapEntity.MapEntityType.Editor); - MapOffsetNode.AddChild(btlParent); - foreach (BTL.Light l in btl.Lights) - { - var n = new MapEntity(this, l, MapEntity.MapEntityType.Light); - Objects.Add(n); - btlParent.AddChild(n); - } - - BTLParents.Add(btlParent); - } - - private void AddModelDeS(IMsb m, MSBD.Model model, string name) - { - if (LoadedModels[name] != null) - { - m.Models.Add(LoadedModels[name]); - return; - } - - model.Name = name; - if (model is MSBD.Model.MapPiece) - { - model.SibPath = $@"N:\DemonsSoul\data\Model\map\{Name}\sib\{name}.sib"; - } - else if (model is MSBD.Model.Object) - { - model.SibPath = $@"N:\DemonsSoul\data\Model\obj\{name}\sib\{name}.sib"; - } - else if (model is MSBD.Model.Enemy) - { - model.SibPath = $@"N:\DemonsSoul\data\Model\chr\{name}\sib\{name}.sib"; - } - else if (model is MSBD.Model.Collision) - { - model.SibPath = $@"N:\DemonsSoul\data\Model\map\{Name}\hkxwin\{name}.hkxwin"; - } - else if (model is MSBD.Model.Navmesh) - { - model.SibPath = $@"N:\DemonsSoul\data\Model\map\{Name}\navimesh\{name}.SIB"; - } - - m.Models.Add(model); - } - - private void AddModelDS1(IMsb m, MSB1.Model model, string name) - { - if (LoadedModels[name] != null) - { - m.Models.Add(LoadedModels[name]); - return; - } - - model.Name = name; - if (model is MSB1.Model.MapPiece) - { - model.SibPath = $@"N:\FRPG\data\Model\map\{Name}\sib\{name}.sib"; - } - else if (model is MSB1.Model.Object) - { - model.SibPath = $@"N:\FRPG\data\Model\obj\{name}\sib\{name}.sib"; - } - else if (model is MSB1.Model.Enemy) - { - model.SibPath = $@"N:\FRPG\data\Model\chr\{name}\sib\{name}.sib"; - } - else if (model is MSB1.Model.Collision) - { - model.SibPath = $@"N:\FRPG\data\Model\map\{Name}\hkxwin\{name}.hkxwin"; - } - else if (model is MSB1.Model.Navmesh) - { - model.SibPath = $@"N:\FRPG\data\Model\map\{Name}\navimesh\{name}.sib"; - } - - m.Models.Add(model); - } - - private void AddModelDS2(IMsb m, MSB2.Model model, string name) - { - if (LoadedModels[name] != null) - { - m.Models.Add(LoadedModels[name]); - return; - } - - model.Name = name; - m.Models.Add(model); - } - - private void AddModelBB(IMsb m, MSBB.Model model, string name) - { - if (LoadedModels[name] != null) - { - m.Models.Add(LoadedModels[name]); - return; - } - - var a = $@"A{Name.Substring(1, 2)}"; - model.Name = name; - if (model is MSBB.Model.MapPiece) - { - model.SibPath = $@"N:\SPRJ\data\Model\map\{Name}\sib\{name}{a}.sib"; - } - else if (model is MSBB.Model.Object) - { - model.SibPath = $@"N:\SPRJ\data\Model\obj\{name.Substring(0, 3)}\{name}\sib\{name}.sib"; - } - else if (model is MSBB.Model.Enemy) - { - // Not techincally required but doing so means that unedited bloodborne maps - // will write identical to the original byte for byte - if (name == "c0000") - { - model.SibPath = $@"N:\SPRJ\data\Model\chr\{name}\sib\{name}.SIB"; - } - else - { - model.SibPath = $@"N:\SPRJ\data\Model\chr\{name}\sib\{name}.sib"; - } - } - else if (model is MSBB.Model.Collision) - { - model.SibPath = $@"N:\SPRJ\data\Model\map\{Name}\hkt\{name}{a}.hkt"; - } - else if (model is MSBB.Model.Navmesh) - { - model.SibPath = $@"N:\SPRJ\data\Model\map\{Name}\navimesh\{name}{a}.sib"; - } - else if (model is MSBB.Model.Other) - { - model.SibPath = @""; - } - - m.Models.Add(model); - } - - private void AddModelDS3(IMsb m, MSB3.Model model, string name) - { - if (LoadedModels[name] != null) - { - m.Models.Add(LoadedModels[name]); - return; - } - - model.Name = name; - if (model is MSB3.Model.MapPiece) - { - model.SibPath = $@"N:\FDP\data\Model\map\{Name}\sib\{name}.sib"; - } - else if (model is MSB3.Model.Object) - { - model.SibPath = $@"N:\FDP\data\Model\obj\{name}\sib\{name}.sib"; - } - else if (model is MSB3.Model.Enemy) - { - model.SibPath = $@"N:\FDP\data\Model\chr\{name}\sib\{name}.sib"; - } - else if (model is MSB3.Model.Collision) - { - model.SibPath = $@"N:\FDP\data\Model\map\{Name}\hkt\{name}.hkt"; - } - else if (model is MSB3.Model.Other) - { - model.SibPath = @""; - } - - m.Models.Add(model); - } - - private void AddModelSekiro(IMsb m, MSBS.Model model, string name) - { - if (LoadedModels[name] != null) - { - m.Models.Add(LoadedModels[name]); - return; - } - - model.Name = name; - if (model is MSBS.Model.MapPiece) - { - model.SibPath = $@"N:\FDP\data\Model\map\{Name}\sib\{name}.sib"; - } - else if (model is MSBS.Model.Object) - { - model.SibPath = $@"N:\FDP\data\Model\obj\{name}\sib\{name}.sib"; - } - else if (model is MSBS.Model.Enemy) - { - model.SibPath = $@"N:\FDP\data\Model\chr\{name}\sib\{name}.sib"; - } - else if (model is MSBS.Model.Collision) - { - model.SibPath = $@"N:\FDP\data\Model\map\{Name}\hkt\{name}.hkt"; - } - else if (model is MSBS.Model.Player) - { - model.SibPath = @""; - } - - m.Models.Add(model); - } - - private void AddModelER(IMsb m, MSBE.Model model, string name) - { - if (LoadedModels[name] != null) - { - m.Models.Add(LoadedModels[name]); - return; - } - - model.Name = name; - if (model is MSBE.Model.MapPiece) - { - model.SibPath = $@"N:\GR\data\Model\map\{Name}\sib\{name}.sib"; - } - else if (model is MSBE.Model.Asset) - { - model.SibPath = $@"N:\GR\data\Asset\Environment\geometry\{name.Substring(0, 6)}\{name}\sib\{name}.sib"; - } - else if (model is MSBE.Model.Enemy) - { - model.SibPath = $@"N:\GR\data\Model\chr\{name}\sib\{name}.sib"; - } - else if (model is MSBE.Model.Collision) - { - model.SibPath = $@"N:\GR\data\Model\map\{Name}\hkt\{name}.hkt"; - } - else if (model is MSBE.Model.Player) - { - model.SibPath = $@"N:\GR\data\Model\chr\{name}\sib\{name}.sib"; - } - - m.Models.Add(model); - } - - private void AddModelAC6(IMsb m, MSB_AC6.Model model, string name) - { - if (LoadedModels[name] != null) - { - m.Models.Add(LoadedModels[name]); - return; - } - - model.Name = name; - if (model is MSB_AC6.Model.MapPiece) - { - model.SourcePath = $@"N:\FNR\data\Model\map\{Name}\sib\{name}.sib"; - } - else if (model is MSB_AC6.Model.Asset) - { - model.SourcePath = $@"N:\FNR\data\Asset\Environment\geometry\{name.Substring(0, 6)}\{name}\sib\{name}.sib"; - } - else if (model is MSB_AC6.Model.Enemy) - { - model.SourcePath = $@"N:\FNR\data\Model\chr\{name}\sib\{name}.sib"; - } - else if (model is MSB_AC6.Model.Collision) - { - model.SourcePath = $@"N:\FNR\data\Model\map\{Name}\hkt\{name}.hkt"; - } - else if (model is MSB_AC6.Model.Player) - { - model.SourcePath = $@"N:\FNR\data\Model\chr\{name}\sib\{name}.sib"; - } - - m.Models.Add(model); - } - - private void AddModel(IMsb m, string name) where T : IMsbModel, new() - { - var model = new T(); - model.Name = name; - m.Models.Add(model); - } - - private void AddModelsDeS(IMsb msb) - { - foreach (KeyValuePair mk in LoadedModels.OrderBy(q => q.Key)) - { - var m = mk.Key; - if (m.StartsWith("m")) - { - AddModelDeS(msb, new MSBD.Model.MapPiece(), m); - } - - if (m.StartsWith("h")) - { - AddModelDeS(msb, new MSBD.Model.Collision(), m); - } - - if (m.StartsWith("o")) - { - AddModelDeS(msb, new MSBD.Model.Object(), m); - } - - if (m.StartsWith("c")) - { - AddModelDeS(msb, new MSBD.Model.Enemy(), m); - } - - if (m.StartsWith("n")) - { - AddModelDeS(msb, new MSBD.Model.Navmesh(), m); - } - } - } - - private void AddModelsDS1(IMsb msb) - { - foreach (KeyValuePair mk in LoadedModels.OrderBy(q => q.Key)) - { - var m = mk.Key; - if (m.StartsWith("m")) - { - AddModelDS1(msb, new MSB1.Model.MapPiece(), m); - } - - if (m.StartsWith("h")) - { - AddModelDS1(msb, new MSB1.Model.Collision(), m); - } - - if (m.StartsWith("o")) - { - AddModelDS1(msb, new MSB1.Model.Object(), m); - } - - if (m.StartsWith("c")) - { - AddModelDS1(msb, new MSB1.Model.Enemy(), m); - } - - if (m.StartsWith("n")) - { - AddModelDS1(msb, new MSB1.Model.Navmesh(), m); - } - } - } - - private void AddModelsDS2(IMsb msb) - { - foreach (KeyValuePair mk in LoadedModels.OrderBy(q => q.Key)) - { - var m = mk.Key; - if (m.StartsWith("m")) - { - AddModelDS2(msb, new MSB2.Model.MapPiece(), m); - } - - if (m.StartsWith("h")) - { - AddModelDS2(msb, new MSB2.Model.Collision(), m); - } - - if (m.StartsWith("o")) - { - AddModelDS2(msb, new MSB2.Model.Object(), m); - } - - if (m.StartsWith("n")) - { - AddModelDS2(msb, new MSB2.Model.Navmesh(), m); - } - } - } - - private void AddModelsBB(IMsb msb) - { - foreach (KeyValuePair mk in LoadedModels.OrderBy(q => q.Key)) - { - var m = mk.Key; - if (m.StartsWith("m")) - { - AddModelBB(msb, new MSBB.Model.MapPiece { Name = m }, m); - } - - if (m.StartsWith("h")) - { - AddModelBB(msb, new MSBB.Model.Collision { Name = m }, m); - } - - if (m.StartsWith("o")) - { - AddModelBB(msb, new MSBB.Model.Object { Name = m }, m); - } - - if (m.StartsWith("c")) - { - AddModelBB(msb, new MSBB.Model.Enemy { Name = m }, m); - } - - if (m.StartsWith("n")) - { - AddModelBB(msb, new MSBB.Model.Navmesh { Name = m }, m); - } - } - } - - private void AddModelsDS3(IMsb msb) - { - foreach (KeyValuePair mk in LoadedModels.OrderBy(q => q.Key)) - { - var m = mk.Key; - if (m.StartsWith("m")) - { - AddModelDS3(msb, new MSB3.Model.MapPiece { Name = m }, m); - } - - if (m.StartsWith("h")) - { - AddModelDS3(msb, new MSB3.Model.Collision { Name = m }, m); - } - - if (m.StartsWith("o")) - { - AddModelDS3(msb, new MSB3.Model.Object { Name = m }, m); - } - - if (m.StartsWith("c")) - { - AddModelDS3(msb, new MSB3.Model.Enemy { Name = m }, m); - } - } - } - - private void AddModelsSekiro(IMsb msb) - { - foreach (KeyValuePair mk in LoadedModels.OrderBy(q => q.Key)) - { - var m = mk.Key; - if (m.StartsWith("m")) - { - AddModelSekiro(msb, new MSBS.Model.MapPiece { Name = m }, m); - } - - if (m.StartsWith("h")) - { - AddModelSekiro(msb, new MSBS.Model.Collision { Name = m }, m); - } - - if (m.StartsWith("o")) - { - AddModelSekiro(msb, new MSBS.Model.Object { Name = m }, m); - } - - if (m.StartsWith("c")) - { - AddModelSekiro(msb, new MSBS.Model.Enemy { Name = m }, m); - } - } - } - - private void AddModelsER(IMsb msb) - { - foreach (KeyValuePair mk in LoadedModels.OrderBy(q => q.Key)) - { - var m = mk.Key; - if (m.ToLower().StartsWith("m")) - { - AddModelER(msb, new MSBE.Model.MapPiece { Name = m }, m); - continue; - } - - if (m.ToLower().StartsWith("h")) - { - AddModelER(msb, new MSBE.Model.Collision { Name = m }, m); - continue; - } - - if (m.ToLower().StartsWith("aeg")) - { - AddModelER(msb, new MSBE.Model.Asset { Name = m }, m); - continue; - } - - if (m.ToLower().StartsWith("c")) - { - AddModelER(msb, new MSBE.Model.Enemy { Name = m }, m); - continue; - } - } - } - - private void AddModelsAC6(IMsb msb) - { - foreach (KeyValuePair mk in LoadedModels.OrderBy(q => q.Key)) - { - var m = mk.Key; - if (m.ToLower().StartsWith("m")) - { - AddModelAC6(msb, new MSB_AC6.Model.MapPiece { Name = m }, m); - continue; - } - - if (m.ToLower().StartsWith("h")) - { - AddModelAC6(msb, new MSB_AC6.Model.Collision { Name = m }, m); - continue; - } - - if (m.ToLower().StartsWith("aeg")) - { - AddModelAC6(msb, new MSB_AC6.Model.Asset { Name = m }, m); - continue; - } - - if (m.ToLower().StartsWith("c")) - { - AddModelAC6(msb, new MSB_AC6.Model.Enemy { Name = m }, m); - continue; - } - } - } - - public void SerializeToMSB(IMsb msb, GameType game) - { - foreach (Entity m in Objects) - { - if (m.WrappedObject != null && m.WrappedObject is IMsbPart p) - { - msb.Parts.Add(p); - if (p.ModelName != null && !LoadedModels.ContainsKey(p.ModelName)) - { - LoadedModels.Add(p.ModelName, null); - } - } - else if (m.WrappedObject != null && m.WrappedObject is IMsbRegion r) - { - msb.Regions.Add(r); - } - else if (m.WrappedObject != null && m.WrappedObject is IMsbEvent e) - { - msb.Events.Add(e); - } - } - - if (game == GameType.DemonsSouls) - { - AddModelsDeS(msb); - } - else if (game == GameType.DarkSoulsPTDE || game == GameType.DarkSoulsRemastered) - { - AddModelsDS1(msb); - } - else if (game == GameType.DarkSoulsIISOTFS) - { - AddModelsDS2(msb); - } - else if (game == GameType.Bloodborne) - { - AddModelsBB(msb); - } - else if (game == GameType.DarkSoulsIII) - { - AddModelsDS3(msb); - } - else if (game == GameType.Sekiro) - { - AddModelsSekiro(msb); - } - else if (game == GameType.EldenRing) - { - AddModelsER(msb); - } - else if (game == GameType.ArmoredCoreVI) - { - AddModelsAC6(msb); - } - } - - /// - /// Gets all BTL.Light with matching ParentBtlNames. - /// - public List SerializeBtlLights(string btlName) - { - List lights = new(); - foreach (Entity p in BTLParents) - { - var ad = (AssetDescription)p.WrappedObject; - if (ad.AssetName == btlName) - { - foreach (Entity e in p.Children) - { - if (e.WrappedObject != null && e.WrappedObject is BTL.Light light) - { - lights.Add(light); - } - else - { - throw new Exception($"WrappedObject \"{e.WrappedObject}\" is not a BTL Light."); - } - } - } - } - - return lights; - } - - public void SerializeToXML(XmlSerializer serializer, TextWriter writer, GameType game) - { - serializer.Serialize(writer, this); - } - - public bool SerializeDS2Generators(Param locations, Param generators) - { - HashSet ids = new(); - foreach (Entity o in Objects) - { - if (o is MapEntity m && m.Type == MapEntity.MapEntityType.DS2Generator && - m.WrappedObject is MergedParamRow mp) - { - if (!ids.Contains(mp.ID)) - { - ids.Add(mp.ID); - } - else - { - PlatformUtils.Instance.MessageBox( - $@"{mp.Name} has an ID that's already used. Please change it to something unique and save again.", - "", MessageBoxButtons.OK, MessageBoxIcon.Error); - return false; - } - - Param.Row loc = mp.GetRow("generator-loc"); - if (loc != null) - { - // Set param positions - var newloc = new Param.Row(loc, locations); - newloc.GetCellHandleOrThrow("PositionX").SetValue( - (float)loc.GetCellHandleOrThrow("PositionX").Value); - newloc.GetCellHandleOrThrow("PositionY").SetValue( - (float)loc.GetCellHandleOrThrow("PositionY").Value); - newloc.GetCellHandleOrThrow("PositionZ").SetValue( - (float)loc.GetCellHandleOrThrow("PositionZ").Value); - locations.AddRow(newloc); - } - - Param.Row gen = mp.GetRow("generator"); - if (gen != null) - { - generators.AddRow(new Param.Row(gen, generators)); - } - } - } - - return true; - } - - public bool SerializeDS2Regist(Param regist) - { - HashSet ids = new(); - foreach (Entity o in Objects) - { - if (o is MapEntity m && m.Type == MapEntity.MapEntityType.DS2GeneratorRegist && - m.WrappedObject is Param.Row mp) - { - if (!ids.Contains(mp.ID)) - { - ids.Add(mp.ID); - } - else - { - PlatformUtils.Instance.MessageBox( - $@"{mp.Name} has an ID that's already used. Please change it to something unique and save again.", - "", MessageBoxButtons.OK, MessageBoxIcon.Error); - return false; - } - - regist.AddRow(new Param.Row(mp, regist)); - } - } - - return true; - } - - public bool SerializeDS2Events(Param evs) - { - HashSet ids = new(); - foreach (Entity o in Objects) - { - if (o is MapEntity m && m.Type == MapEntity.MapEntityType.DS2Event && m.WrappedObject is Param.Row mp) - { - if (!ids.Contains(mp.ID)) - { - ids.Add(mp.ID); - } - else - { - PlatformUtils.Instance.MessageBox( - $@"{mp.Name} has an ID that's already used. Please change it to something unique and save again.", - "", MessageBoxButtons.OK, MessageBoxIcon.Error); - return false; - } - - var newloc = new Param.Row(mp, evs); - evs.AddRow(newloc); - } - } - - return true; - } - - public bool SerializeDS2EventLocations(Param locs) - { - HashSet ids = new(); - foreach (Entity o in Objects) - { - if (o is MapEntity m && m.Type == MapEntity.MapEntityType.DS2EventLocation && - m.WrappedObject is Param.Row mp) - { - if (!ids.Contains(mp.ID)) - { - ids.Add(mp.ID); - } - else - { - PlatformUtils.Instance.MessageBox( - $@"{mp.Name} has an ID that's already used. Please change it to something unique and save again.", - "", MessageBoxButtons.OK, MessageBoxIcon.Error); - return false; - } - - // Set param location positions - var newloc = new Param.Row(mp, locs); - newloc.GetCellHandleOrThrow("PositionX").SetValue( - (float)mp.GetCellHandleOrThrow("PositionX").Value); - newloc.GetCellHandleOrThrow("PositionY").SetValue( - (float)mp.GetCellHandleOrThrow("PositionY").Value); - newloc.GetCellHandleOrThrow("PositionZ").SetValue( - (float)mp.GetCellHandleOrThrow("PositionZ").Value); - locs.AddRow(newloc); - } - } - - return true; - } - - public bool SerializeDS2ObjInstances(Param objs) - { - HashSet ids = new(); - foreach (Entity o in Objects) - { - if (o is MapEntity m && m.Type == MapEntity.MapEntityType.DS2ObjectInstance && - m.WrappedObject is Param.Row mp) - { - if (!ids.Contains(mp.ID)) - { - ids.Add(mp.ID); - } - else - { - PlatformUtils.Instance.MessageBox( - $@"{mp.Name} has an ID that's already used. Please change it to something unique and save again.", - "", MessageBoxButtons.OK, MessageBoxIcon.Error); - return false; - } - - var newobj = new Param.Row(mp, objs); - objs.AddRow(newobj); - } - } - - return true; - } - - public MapSerializationEntity SerializeHierarchy() - { - Dictionary idmap = new(); - for (var i = 0; i < Objects.Count; i++) - { - idmap.Add(Objects[i], i); - } - - return ((MapEntity)RootObject).Serialize(idmap); - } -} diff --git a/src/StudioCore/MsbEditor/ObjectContainerReference.cs b/src/StudioCore/MsbEditor/ObjectContainerReference.cs index 7c43576e9..7d8a9c0bd 100644 --- a/src/StudioCore/MsbEditor/ObjectContainerReference.cs +++ b/src/StudioCore/MsbEditor/ObjectContainerReference.cs @@ -1,4 +1,4 @@ -using StudioCore.Scene; +using StudioCore.Renderer.Scene; namespace StudioCore.MsbEditor; diff --git a/src/StudioCore/MsbEditor/PropertyEditor.cs b/src/StudioCore/MsbEditor/PropertyEditor.cs index f67592dd4..9407d30aa 100644 --- a/src/StudioCore/MsbEditor/PropertyEditor.cs +++ b/src/StudioCore/MsbEditor/PropertyEditor.cs @@ -5,7 +5,8 @@ using StudioCore.Banks; using StudioCore.Editor; using StudioCore.ParamEditor; -using StudioCore.Scene; +using StudioCore.Renderer.Scene; +using StudioCore.Utilities; using System; using System.Collections.Generic; using System.Drawing; @@ -28,7 +29,7 @@ public class PropertyEditor private object _changingObject; private object _changingPropery; - private Action _lastUncommittedAction; + private EditorAction _lastUncommittedAction; public ActionManager ContextActionManager; public PropertyInfo RequestedSearchProperty = null; diff --git a/src/StudioCore/MsbEditor/SceneTree.cs b/src/StudioCore/MsbEditor/SceneTree.cs index 04dae0f4c..2cb805d26 100644 --- a/src/StudioCore/MsbEditor/SceneTree.cs +++ b/src/StudioCore/MsbEditor/SceneTree.cs @@ -2,10 +2,10 @@ using SoulsFormats; using StudioCore.Banks; using StudioCore.Editor; -using StudioCore.Gui; +using StudioCore.Renderer.Gui; using StudioCore.ParamEditor; using StudioCore.Platform; -using StudioCore.Scene; +using StudioCore.Renderer.Scene; using StudioCore.Utilities; using System; using System.Collections.Generic; @@ -14,7 +14,8 @@ using System.Numerics; using System.Runtime.InteropServices; using Veldrid; -using StudioCore.Interface; +using StudioCore.Editor; +using StudioCore.Banks.AliasBank; namespace StudioCore.MsbEditor; @@ -272,7 +273,7 @@ private unsafe void MapObjectSelectable(Entity e, bool visicon, bool hierarchial } var alias = AliasUtils.GetEntityAliasName(e); - AliasUtils.DisplayAlias(alias); + EditorDecorations.DisplayAlias(alias); } if (ImGui.IsItemClicked()) @@ -615,7 +616,7 @@ public unsafe void OnGui() { if (Locator.AssetLocator.Type is GameType.DarkSoulsIISOTFS) { - if (ParamBank.PrimaryBank.IsLoadingParams) + if (ParamBank.PrimaryBank.IsLoading) { ImGui.NewLine(); ImGui.Text(" Please wait for params to finish loading."); @@ -713,7 +714,7 @@ public unsafe void OnGui() if (CFG.Current.MapEditor_MapObjectList_ShowMapNames) { - AliasUtils.DisplayAlias(aliasName); + EditorDecorations.DisplayAlias(aliasName); } ImGui.EndGroup(); diff --git a/src/StudioCore/MsbEditor/Selection.cs b/src/StudioCore/MsbEditor/Selection.cs index 6d351ab52..3e5c1f90e 100644 --- a/src/StudioCore/MsbEditor/Selection.cs +++ b/src/StudioCore/MsbEditor/Selection.cs @@ -1,4 +1,4 @@ -using StudioCore.Scene; +using StudioCore.Renderer.Scene; using System; using System.Collections.Generic; using System.Linq; diff --git a/src/StudioCore/MsbEditor/SpecialMapConnections.cs b/src/StudioCore/MsbEditor/SpecialMapConnections.cs index 117c2865e..12f148eb3 100644 --- a/src/StudioCore/MsbEditor/SpecialMapConnections.cs +++ b/src/StudioCore/MsbEditor/SpecialMapConnections.cs @@ -1,5 +1,6 @@ using Andre.Formats; using StudioCore.ParamEditor; +using StudioCore.Utilities; using System; using System.Collections.Generic; using System.Linq; diff --git a/src/StudioCore/MsbEditor/Universe.cs b/src/StudioCore/MsbEditor/Universe.cs index 23a060c56..70f6bd444 100644 --- a/src/StudioCore/MsbEditor/Universe.cs +++ b/src/StudioCore/MsbEditor/Universe.cs @@ -2,8 +2,9 @@ using Microsoft.Extensions.Logging; using SoulsFormats; using StudioCore.ParamEditor; -using StudioCore.Resource; -using StudioCore.Scene; +using StudioCore.Renderer.Resource; +using StudioCore.Renderer.Scene; +using StudioCore.Utilities; using System; using System.Collections.Generic; using System.IO; @@ -288,7 +289,7 @@ public RenderableProxy GetPatrolLineDrawable(Entity selectable, Entity obj, List return null; } - DebugPrimitives.DbgPrimWireChain line = new(points, looseStartPoints, System.Drawing.Color.Red, endAtStart, random); + Renderer.DebugPrimitives.DbgPrimWireChain line = new(points, looseStartPoints, System.Drawing.Color.Red, endAtStart, random); DebugPrimitiveRenderableProxy mesh = new(_renderScene.OpaqueRenderables, line) { BaseColor = System.Drawing.Color.Red, @@ -615,7 +616,7 @@ public void LoadDS2Generators(string mapid, Map map) public void PopulateMapList() { LoadedObjectContainers.Clear(); - foreach (var m in Locator.AssetLocator.GetFullMapList()) + foreach (var m in Locator.ActiveProject.MSBBank.GetFullMapList()) { LoadedObjectContainers.Add(m, null); } @@ -642,7 +643,7 @@ public bool LoadMap(string mapid, bool selectOnLoad = false) return false; } - AssetDescription ad = Locator.AssetLocator.GetMapMSB(mapid); + AssetDescription ad = Locator.ActiveProject.MSBBank.GetMapMSB(mapid); if (ad.AssetPath == null) { return false; @@ -731,46 +732,9 @@ public async void LoadMapAsync(string mapid, bool selectOnLoad = false) //break; } - AssetDescription ad = Locator.AssetLocator.GetMapMSB(mapid); - if (ad.AssetPath == null) - { + IMsb msb = Locator.ActiveProject.MSBBank.GetMsb(mapid); + if (msb == null) return; - } - - IMsb msb; - if (Locator.AssetLocator.Type == GameType.DarkSoulsIII) - { - msb = MSB3.Read(ad.AssetPath); - } - else if (Locator.AssetLocator.Type == GameType.Sekiro) - { - msb = MSBS.Read(ad.AssetPath); - } - else if (Locator.AssetLocator.Type == GameType.EldenRing) - { - msb = MSBE.Read(ad.AssetPath); - } - else if (Locator.AssetLocator.Type == GameType.ArmoredCoreVI) - { - msb = MSB_AC6.Read(ad.AssetPath); - } - else if (Locator.AssetLocator.Type == GameType.DarkSoulsIISOTFS) - { - msb = MSB2.Read(ad.AssetPath); - } - else if (Locator.AssetLocator.Type == GameType.Bloodborne) - { - msb = MSBB.Read(ad.AssetPath); - } - else if (Locator.AssetLocator.Type == GameType.DemonsSouls) - { - msb = MSBD.Read(ad.AssetPath); - } - else - { - msb = MSB1.Read(ad.AssetPath); - } - map.LoadMSB(msb); var amapid = Locator.AssetLocator.GetAssetMapID(mapid); @@ -1421,8 +1385,8 @@ public void SaveMap(Map map) SaveBTL(map); try { - AssetDescription ad = Locator.AssetLocator.GetMapMSB(map.Name); - AssetDescription adw = Locator.AssetLocator.GetMapMSB(map.Name, true); + AssetDescription ad = Locator.ActiveProject.MSBBank.GetMapMSB(map.Name); + AssetDescription adw = Locator.ActiveProject.MSBBank.GetMapMSB(map.Name, true); IMsb msb; DCX.Type compressionType = GetCompressionType(); if (Locator.AssetLocator.Type == GameType.DarkSoulsIII) diff --git a/src/StudioCore/MsbEditor/ViewGrid.cs b/src/StudioCore/MsbEditor/ViewGrid.cs index ac8c17c20..5953849fc 100644 --- a/src/StudioCore/MsbEditor/ViewGrid.cs +++ b/src/StudioCore/MsbEditor/ViewGrid.cs @@ -1,6 +1,7 @@ using static Andre.Native.ImGuiBindings; -using StudioCore.DebugPrimitives; -using StudioCore.Scene; +using StudioCore.Renderer.DebugPrimitives; +using StudioCore.Renderer.Scene; +using StudioCore.Utilities; using System; using System.Collections.Generic; using System.Drawing; diff --git a/src/StudioCore/ParamEditor/AutoFill.cs b/src/StudioCore/ParamEditor/AutoFill.cs index 35bcfde2e..44e5502b0 100644 --- a/src/StudioCore/ParamEditor/AutoFill.cs +++ b/src/StudioCore/ParamEditor/AutoFill.cs @@ -1,6 +1,7 @@ using Andre.Formats; using static Andre.Native.ImGuiBindings; using StudioCore.Editor; +using StudioCore.Utilities; using System; using System.Collections.Generic; using System.Linq; diff --git a/src/StudioCore/ParamEditor/MassParamEdit.cs b/src/StudioCore/ParamEditor/MassParamEdit.cs index e323b3ce2..2bb1c36ba 100644 --- a/src/StudioCore/ParamEditor/MassParamEdit.cs +++ b/src/StudioCore/ParamEditor/MassParamEdit.cs @@ -895,12 +895,12 @@ private void Setup() "Gives the value of the equivalent cell/field in the specified regulation or parambnd for the currently selected cell/field, row and param.\nWill fail if a row does not have an aux equivilent. Consider using && auxprop ID .*", bankName => { - if (!ParamBank.AuxBanks.ContainsKey(bankName[0])) + if (!ResDirectory.CurrentGame.AuxProjects.ContainsKey(bankName[0])) { throw new Exception($@"Could not locate paramBank {bankName[0]}"); } - ParamBank bank = ParamBank.AuxBanks[bankName[0]]; + ParamBank bank = ResDirectory.CurrentGame.AuxProjects[bankName[0]].ParamBank; return (i, param) => { var paramName = ParamBank.PrimaryBank.GetKeyForParam(param); @@ -929,7 +929,7 @@ private void Setup() }; }; }; - }, () => ParamBank.AuxBanks.Count > 0)); + }, () => ResDirectory.CurrentGame.AuxProjects.Count > 0)); argumentGetters.Add("vanillafield", newGetter(new[] { "field internalName" }, "Gives the value of the specified cell/field in the vanilla regulation or parambnd for the currently selected row and param.\nWill fail if a row does not have a vanilla equivilent. Consider using && !added", field => (i, param) => @@ -963,12 +963,12 @@ private void Setup() "Gives the value of the specified cell/field in the specified regulation or parambnd for the currently selected row and param.\nWill fail if a row does not have an aux equivilent. Consider using && auxprop ID .*", bankAndField => { - if (!ParamBank.AuxBanks.ContainsKey(bankAndField[0])) + if (!ResDirectory.CurrentGame.AuxProjects.ContainsKey(bankAndField[0])) { throw new Exception($@"Could not locate paramBank {bankAndField[0]}"); } - ParamBank bank = ParamBank.AuxBanks[bankAndField[0]]; + ParamBank bank = ResDirectory.CurrentGame.AuxProjects[bankAndField[0]].ParamBank; return (i, param) => { var paramName = ParamBank.PrimaryBank.GetKeyForParam(param); @@ -996,7 +996,7 @@ private void Setup() return (k, c) => v; }; }; - }, () => ParamBank.AuxBanks.Count > 0)); + }, () => ResDirectory.CurrentGame.AuxProjects.Count > 0)); argumentGetters.Add("paramlookup", newGetter(new[] { "param name", "row id", "field name" }, "Returns the specific value specified by the exact param, row and field.", address => { diff --git a/src/StudioCore/ParamEditor/ParamAction.cs b/src/StudioCore/ParamEditor/ParamAction.cs new file mode 100644 index 000000000..df4e37eb1 --- /dev/null +++ b/src/StudioCore/ParamEditor/ParamAction.cs @@ -0,0 +1,175 @@ +using Andre.Formats; +using StudioCore.ParamEditor; +using StudioCore.TextEditor; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; + +namespace StudioCore.Editor; + +public class AddParamsAction : EditorAction +{ + private readonly bool appOnly; + private readonly List Clonables = new(); + private readonly List Clones = new(); + private readonly int InsertIndex; + private readonly Param Param; + private readonly List Removed = new(); + private readonly List RemovedIndex = new(); + private readonly bool replParams; + private string ParamString; + + public AddParamsAction(Param param, string pstring, List rows, bool appendOnly, bool replaceParams, + int index = -1) + { + Param = param; + Clonables.AddRange(rows); + ParamString = pstring; + appOnly = appendOnly; + replParams = replaceParams; + InsertIndex = index; + } + + public override ActionEvent Execute() + { + foreach (Param.Row row in Clonables) + { + var newrow = new Param.Row(row); + if (InsertIndex > -1) + { + newrow.Name = row.Name != null ? row.Name + "_1" : ""; + Param.InsertRow(InsertIndex, newrow); + } + else + { + if (Param[row.ID] != null) + { + if (replParams) + { + Param.Row existing = Param[row.ID]; + RemovedIndex.Add(Param.IndexOfRow(existing)); + Removed.Add(existing); + Param.RemoveRow(existing); + } + else + { + newrow.Name = row.Name != null ? row.Name + "_1" : ""; + var newID = row.ID + 1; + while (Param[newID] != null) + { + newID++; + } + + newrow.ID = newID; + Param.InsertRow(Param.IndexOfRow(Param[newID - 1]) + 1, newrow); + } + } + + if (Param[row.ID] == null) + { + newrow.Name = row.Name != null ? row.Name : ""; + if (appOnly) + { + Param.AddRow(newrow); + } + else + { + var index = 0; + foreach (Param.Row r in Param.Rows) + { + if (r.ID > newrow.ID) + { + break; + } + + index++; + } + + Param.InsertRow(index, newrow); + } + } + } + + Clones.Add(newrow); + } + + // Refresh diff cache + TaskManager.Run(new TaskManager.LiveTask("Param - Check Differences", + TaskManager.RequeueType.Repeat, true, + TaskLogs.LogPriority.Low, + () => ParamDiffBank.RefreshAllParamDiffCaches(false))); + return ActionEvent.NoEvent; + } + + public override ActionEvent Undo() + { + for (var i = 0; i < Clones.Count(); i++) + { + Param.RemoveRow(Clones[i]); + } + + for (var i = Removed.Count() - 1; i >= 0; i--) + { + Param.InsertRow(RemovedIndex[i], Removed[i]); + } + + Clones.Clear(); + RemovedIndex.Clear(); + Removed.Clear(); + return ActionEvent.NoEvent; + } + + public List GetResultantRows() + { + return Clones; + } +} + +public class DeleteParamsAction : EditorAction +{ + private readonly List Deletables = new(); + private readonly Param Param; + private readonly List RemoveIndices = new(); + private readonly bool SetSelection = false; + + public DeleteParamsAction(Param param, List rows) + { + Param = param; + Deletables.AddRange(rows); + } + + public override ActionEvent Execute() + { + foreach (Param.Row row in Deletables) + { + RemoveIndices.Add(Param.IndexOfRow(row)); + Param.RemoveRowAt(RemoveIndices.Last()); + } + + if (SetSelection) + { + } + + return ActionEvent.NoEvent; + } + + public override ActionEvent Undo() + { + for (var i = Deletables.Count() - 1; i >= 0; i--) + { + Param.InsertRow(RemoveIndices[i], Deletables[i]); + } + + if (SetSelection) + { + } + + // Refresh diff cache + TaskManager.Run(new TaskManager.LiveTask("Param - Check Differences", + TaskManager.RequeueType.Repeat, true, + TaskLogs.LogPriority.Low, + () => ParamDiffBank.RefreshAllParamDiffCaches(false))); + return ActionEvent.NoEvent; + } +} diff --git a/src/StudioCore/ParamEditor/ParamBank.cs b/src/StudioCore/ParamEditor/ParamBank.cs index fad809199..7b9463d8e 100644 --- a/src/StudioCore/ParamEditor/ParamBank.cs +++ b/src/StudioCore/ParamEditor/ParamBank.cs @@ -1,6 +1,5 @@ using Andre.Formats; using Microsoft.Extensions.Logging; -using Octokit; using SoulsFormats; using StudioCore.Editor; using StudioCore.Platform; @@ -15,125 +14,31 @@ namespace StudioCore.ParamEditor; /// /// Utilities for dealing with global params for a game /// -public class ParamBank +public partial class ParamBank : DataBank { - public enum ParamUpgradeResult - { - Success = 0, - RowConflictsFound = -1, - OldRegulationNotFound = -2, - OldRegulationVersionMismatch = -3, - OldRegulationMatchesCurrent = -4 - } - - public enum RowGetType - { - AllRows = 0, - ModifiedRows = 1, - SelectedRows = 2 - } - public static ParamBank PrimaryBank => Locator.ActiveProject.ParamBank; public static ParamBank VanillaBank => Locator.ActiveProject.ParentProject.ParamBank; - public static Dictionary AuxBanks = new(); - - /// - /// Mapping from path -> PARAMDEF for cache and and comparison purposes. TODO: check for paramdef comparisons and evaluate if the file/paramdef was actually the same. - /// - private static readonly Dictionary _paramdefsCache = new(); - public static string ClipboardParam = null; public static List ClipboardRows = new(); - /// - /// Mapping from ParamType -> PARAMDEF. - /// - private Dictionary _paramdefs = new(); - - //TODO private this - public Dictionary ParamMetas = new(); - - - /// - /// Mapping from Param filename -> Manual ParamType. - /// This is for params with no usable ParamType at some particular game version. - /// By convention, ParamTypes ending in "_TENTATIVE" do not have official data to reference. - /// - private Dictionary _tentativeParamType; - - /// - /// Map related params. - /// - public static readonly List DS2MapParamlist = new() - { - "demopointlight", - "demospotlight", - "eventlocation", - "eventparam", - "GeneralLocationEventParam", - "generatorparam", - "generatorregistparam", - "generatorlocation", - "generatordbglocation", - "hitgroupparam", - "intrudepointparam", - "mapobjectinstanceparam", - "maptargetdirparam", - "npctalkparam", - "treasureboxparam" - }; - - /// - /// Param name - FMGCategory map - /// - public static readonly List<(string, FmgEntryCategory)> ParamToFmgCategoryList = new() - { - ("EquipParamAccessory", FmgEntryCategory.Rings), - ("EquipParamGoods", FmgEntryCategory.Goods), - ("EquipParamWeapon", FmgEntryCategory.Weapons), - ("EquipParamProtector", FmgEntryCategory.Armor), - ("Magic", FmgEntryCategory.Spells), - ("EquipParamGem", FmgEntryCategory.Gem), - ("SwordArtsParam", FmgEntryCategory.SwordArts), - ("EquipParamGenerator", FmgEntryCategory.Generator), - ("EquipParamFcs", FmgEntryCategory.FCS), - ("EquipParamBooster", FmgEntryCategory.Booster), - ("ArchiveParam", FmgEntryCategory.Archive), - ("MissionParam", FmgEntryCategory.Mission) - }; - - private static readonly HashSet EMPTYSET = new(); - - public Project Project; - private Dictionary _params; private ulong _paramVersion; - private bool _pendingUpgrade; - private Dictionary> _primaryDiffCache; //If param != primaryparam - private Dictionary> _storedStrippedRowNames; - /// /// Dictionary of param file names that were given a tentative ParamType, and the original ParamType it had. /// Used to later restore original ParamType on write (if possible). /// private Dictionary _usedTentativeParamTypes; - private Dictionary> _vanillaDiffCache; //If param != vanillaparam - private Param EnemyParam => _params["EnemyParam"]; - public bool IsDefsLoaded { get; private set; } - public static bool IsMetaLoaded { get; private set; } - public bool IsLoadingParams { get; private set; } - public IReadOnlyDictionary Params { get { - if (IsLoadingParams) + if (IsLoading) { return null; } @@ -143,53 +48,8 @@ public IReadOnlyDictionary Params } public ulong ParamVersion => _paramVersion; - - public IReadOnlyDictionary> VanillaDiffCache - { - get - { - if (IsLoadingParams) - { - return null; - } - - { - if (VanillaBank == this) - { - return null; - } - } - return _vanillaDiffCache; - } - } - - public IReadOnlyDictionary> PrimaryDiffCache - { - get - { - if (IsLoadingParams) - { - return null; - } - - { - if (PrimaryBank == this) - { - return null; - } - } - return _primaryDiffCache; - } - } - - public ParamBank(Project owner) + public ParamBank(Project owner) : base(owner, "Params") { - Project = owner; - } - - public Dictionary GetParamDefs() - { - return _paramdefs; } private static FileNotFoundException CreateParamMissingException(GameType type) @@ -210,91 +70,6 @@ private static FileNotFoundException CreateParamMissingException(GameType type) $"Cannot locate param files for {type}.\nYour game folder may be missing game files, please verify game files through steam to restore them."); } - private List<(string, PARAMDEF)> LoadParamdefs() - { - _paramdefs = new Dictionary(); - _tentativeParamType = new Dictionary(); - var files = Project.AssetLocator.GetAllProjectFiles($@"Paramdex\{AssetUtils.GetGameIDForDir(Locator.ActiveProject.Type)}\Defs", ["*.xml"], true, false); - List<(string, PARAMDEF)> defPairs = new(); - foreach (var f in files) - { - if (!_paramdefsCache.TryGetValue(f, out PARAMDEF pdef)) - { - pdef = PARAMDEF.XmlDeserialize(f, true); - } - _paramdefs.Add(pdef.ParamType, pdef); - defPairs.Add((f, pdef)); - } - - var tentativeMappingPath = Project.AssetLocator.GetProjectFilePath($@"{Project.AssetLocator.GetParamdexDir()}\Defs\TentativeParamType.csv"); - if (File.Exists(tentativeMappingPath)) - { - // No proper CSV library is used currently, and all CSV parsing is in the context of param files. - // If a CSV library is introduced in DSMapStudio, use it here. - foreach (var line in File.ReadAllLines(tentativeMappingPath).Skip(1)) - { - var parts = line.Split(','); - if (parts.Length != 2 || string.IsNullOrWhiteSpace(parts[0]) || string.IsNullOrWhiteSpace(parts[1])) - { - throw new FormatException($"Malformed line in {tentativeMappingPath}: {line}"); - } - - _tentativeParamType[parts[0]] = parts[1]; - } - } - - return defPairs; - } - public void LoadParamMeta(List<(string, PARAMDEF)> defPairs) - { - //This way of tying stuff together still sucks - var mdir = Project.AssetLocator.GetProjectFilePath($@"{Locator.ActiveProject.AssetLocator.GetParamdexDir()}\Meta"); - foreach ((var f, PARAMDEF pdef) in defPairs) - { - var fName = f.Substring(f.LastIndexOf('\\') + 1); - var md = ParamMetaData.XmlDeserialize($@"{mdir}\{fName}", pdef); - ParamMetas.Add(pdef, md); - } - } - - public CompoundAction LoadParamDefaultNames(string param = null, bool onlyAffectEmptyNames = false, bool onlyAffectVanillaNames = false) - { - var files = param == null - ? Project.AssetLocator.GetAllProjectFiles($@"{Project.AssetLocator.GetParamdexDir()}\Names", ["*.txt"], true) - : new[] { Project.AssetLocator.GetProjectFilePath($@"{Project.AssetLocator.GetParamdexDir()}\Names\{param}.txt") }; - List actions = new(); - foreach (var f in files) - { - var fName = Path.GetFileNameWithoutExtension(f); - if (!_params.ContainsKey(fName)) - { - continue; - } - - var names = File.ReadAllText(f); - (var result, CompoundAction action) = - ParamIO.ApplySingleCSV(this, names, fName, "Name", ' ', true, onlyAffectEmptyNames, onlyAffectVanillaNames); - if (action == null) - { - TaskLogs.AddLog($"Could not apply name files for {fName}", - LogLevel.Warning); - } - else - { - actions.Add(action); - } - } - - return new CompoundAction(actions); - } - - public ActionManager TrimNewlineChrsFromNames() - { - (MassEditResult r, ActionManager child) = - MassParamEditRegex.PerformMassEdit(this, "param .*: id .*: name: replace \r:0", null); - return child; - } - private void LoadParamFromBinder(IBinder parambnd, ref Dictionary paramBank, out ulong version, bool checkVersion = false) { @@ -327,9 +102,9 @@ private void LoadParamFromBinder(IBinder parambnd, ref Dictionary p = Param.ReadIgnoreCompression(f.Bytes); if (!string.IsNullOrEmpty(p.ParamType)) { - if (!_paramdefs.ContainsKey(p.ParamType)) + if (!ResDirectory.CurrentGame.ParamDefBank.GetParamDefs().ContainsKey(p.ParamType)) { - if (_tentativeParamType.TryGetValue(paramName, out var newParamType)) + if (ResDirectory.CurrentGame.ParamDefBank.GetTentativeParamTypes().TryGetValue(paramName, out var newParamType)) { _usedTentativeParamTypes.Add(paramName, p.ParamType); p.ParamType = newParamType; @@ -348,7 +123,7 @@ private void LoadParamFromBinder(IBinder parambnd, ref Dictionary } else { - if (_tentativeParamType.TryGetValue(paramName, out var newParamType)) + if (ResDirectory.CurrentGame.ParamDefBank.GetTentativeParamTypes().TryGetValue(paramName, out var newParamType)) { _usedTentativeParamTypes.Add(paramName, p.ParamType); p.ParamType = newParamType; @@ -368,7 +143,7 @@ private void LoadParamFromBinder(IBinder parambnd, ref Dictionary else { p = Param.ReadIgnoreCompression(f.Bytes); - if (!_paramdefs.ContainsKey(p.ParamType ?? "")) + if (!ResDirectory.CurrentGame.ParamDefBank.GetParamDefs().ContainsKey(p.ParamType ?? "")) { TaskLogs.AddLog( $"Couldn't find ParamDef for param {paramName} with ParamType \"{p.ParamType}\".", @@ -391,7 +166,7 @@ private void LoadParamFromBinder(IBinder parambnd, ref Dictionary throw new Exception("Param type is unexpectedly null"); } - PARAMDEF def = _paramdefs[p.ParamType]; + PARAMDEF def = ResDirectory.CurrentGame.ParamDefBank.GetParamDefs()[p.ParamType]; try { p.ApplyParamdef(def, version); @@ -549,7 +324,7 @@ private void LoadParamsDS2FromFile(IEnumerable looseParams, string path, if (loose) { // Loose params: override params already loaded via regulation - PARAMDEF def = _paramdefs[lp.ParamType]; + PARAMDEF def = ResDirectory.CurrentGame.ParamDefBank.GetParamDefs()[lp.ParamType]; lp.ApplyParamdef(def); _params[name] = lp; } @@ -558,7 +333,7 @@ private void LoadParamsDS2FromFile(IEnumerable looseParams, string path, // Non-loose params: do not override params already loaded via regulation if (!_params.ContainsKey(name)) { - PARAMDEF def = _paramdefs[lp.ParamType]; + PARAMDEF def = ResDirectory.CurrentGame.ParamDefBank.GetParamDefs()[lp.ParamType]; lp.ApplyParamdef(def); _params.Add(name, lp); } @@ -711,27 +486,10 @@ private void LoadParamsAC6FromFile(string path, bool encrypted = true) LoadParamFromBinder(bnd, ref _params, out _, false); } } - - private void LoadParams() + protected override void Load() { - - IsDefsLoaded = false; - IsLoadingParams = true; - _params = new Dictionary(); - if (Project.Type != GameType.Undefined) - { - List<(string, PARAMDEF)> defPairs = LoadParamdefs(); - IsDefsLoaded = true; - TaskManager.Run(new TaskManager.LiveTask("Param - Load Meta", - TaskManager.RequeueType.WaitThenRequeue, false, () => - { - LoadParamMeta(defPairs); - IsMetaLoaded = true; - })); - } - if (Project.Type == GameType.DemonsSouls) { LoadParamsDES(); @@ -772,16 +530,14 @@ private void LoadParams() LoadParamsAC6(); } - ClearParamDiffCaches(); - - IsLoadingParams = false; + UICache.ClearCaches(); } + // TODO: Repair on-load actions //Some returns and repetition, but it keeps all threading and loading-flags visible inside this method - public static void ReloadParams(ProjectSettings settings, NewProjectOptions options) + /*public static void ReloadParams(ProjectSettings settings, NewProjectOptions options) { - IsMetaLoaded = false; - + //TODO: subsume with databank system AuxBanks = new Dictionary(); UICache.ClearCaches(); @@ -820,188 +576,15 @@ public static void ReloadParams(ProjectSettings settings, NewProjectOptions opti } UICache.ClearCaches(); })); - } + }*/ public static void LoadAuxBank(string dir, ProjectSettings settings = null) { - // skip the meme and just treat as project Project siblingVirtualProject = new Project(dir, Locator.ActiveProject.ParentProject, settings); - ParamBank newBank = siblingVirtualProject.ParamBank; - - newBank.LoadParams(); - - newBank.RefreshParamDiffCaches(true); - AuxBanks[Path.GetFileName(dir).Replace(' ', '_')] = newBank; - } - - - public void ClearParamDiffCaches() - { - _vanillaDiffCache = new Dictionary>(); - _primaryDiffCache = new Dictionary>(); - foreach (var param in _params.Keys) - { - _vanillaDiffCache.Add(param, new HashSet()); - _primaryDiffCache.Add(param, new HashSet()); - } - } - - public static void RefreshAllParamDiffCaches(bool checkAuxVanillaDiff) - { - PrimaryBank.RefreshParamDiffCaches(true); - foreach (KeyValuePair bank in AuxBanks) - { - bank.Value.RefreshParamDiffCaches(checkAuxVanillaDiff); - } - - UICache.ClearCaches(); - } - - public void RefreshParamDiffCaches(bool checkVanillaDiff) - { - if (this != VanillaBank && checkVanillaDiff) - { - _vanillaDiffCache = GetParamDiff(VanillaBank); - } - - if (this == VanillaBank && PrimaryBank._vanillaDiffCache != null) - { - _primaryDiffCache = PrimaryBank._vanillaDiffCache; - } - else if (this != PrimaryBank) - { - _primaryDiffCache = GetParamDiff(PrimaryBank); - } - - UICache.ClearCaches(); + StudioResource.Load(siblingVirtualProject, [siblingVirtualProject.ParamBank, siblingVirtualProject.ParamDiffBank]); + ResDirectory.CurrentGame.AuxProjects[Path.GetFileName(siblingVirtualProject.AssetLocator.RootDirectory).Replace(' ', '_')] = siblingVirtualProject; } - private Dictionary> GetParamDiff(ParamBank otherBank) - { - if (IsLoadingParams || otherBank == null || otherBank.IsLoadingParams) - { - return null; - } - - Dictionary> newCache = new(); - foreach (var param in _params.Keys) - { - HashSet cache = new(); - newCache.Add(param, cache); - Param p = _params[param]; - if (!otherBank._params.ContainsKey(param)) - { - Console.WriteLine("Missing vanilla param " + param); - continue; - } - - Param.Row[] rows = _params[param].Rows.OrderBy(r => r.ID).ToArray(); - Param.Row[] vrows = otherBank._params[param].Rows.OrderBy(r => r.ID).ToArray(); - - var vanillaIndex = 0; - var lastID = -1; - ReadOnlySpan lastVanillaRows = default; - for (var i = 0; i < rows.Length; i++) - { - var ID = rows[i].ID; - if (ID == lastID) - { - RefreshParamRowDiffCache(rows[i], lastVanillaRows, cache); - } - else - { - lastID = ID; - while (vanillaIndex < vrows.Length && vrows[vanillaIndex].ID < ID) - { - vanillaIndex++; - } - - if (vanillaIndex >= vrows.Length) - { - RefreshParamRowDiffCache(rows[i], Span.Empty, cache); - } - else - { - var count = 0; - while (vanillaIndex + count < vrows.Length && vrows[vanillaIndex + count].ID == ID) - { - count++; - } - - lastVanillaRows = new ReadOnlySpan(vrows, vanillaIndex, count); - RefreshParamRowDiffCache(rows[i], lastVanillaRows, cache); - vanillaIndex += count; - } - } - } - } - - return newCache; - } - - private static void RefreshParamRowDiffCache(Param.Row row, ReadOnlySpan otherBankRows, - HashSet cache) - { - if (IsChanged(row, otherBankRows)) - { - cache.Add(row.ID); - } - else - { - cache.Remove(row.ID); - } - } - - public void RefreshParamRowDiffs(Param.Row row, string param) - { - if (param == null) - { - return; - } - - if (VanillaBank.Params.ContainsKey(param) && VanillaDiffCache != null && - VanillaDiffCache.ContainsKey(param)) - { - Param.Row[] otherBankRows = VanillaBank.Params[param].Rows.Where(cell => cell.ID == row.ID).ToArray(); - RefreshParamRowDiffCache(row, otherBankRows, VanillaDiffCache[param]); - } - - if (this != PrimaryBank) - { - return; - } - - foreach (ParamBank aux in AuxBanks.Values) - { - if (!aux.Params.ContainsKey(param) || aux.PrimaryDiffCache == null || - !aux.PrimaryDiffCache.ContainsKey(param)) - { - continue; // Don't try for now - } - - Param.Row[] otherBankRows = aux.Params[param].Rows.Where(cell => cell.ID == row.ID).ToArray(); - RefreshParamRowDiffCache(row, otherBankRows, aux.PrimaryDiffCache[param]); - } - } - - private static bool IsChanged(Param.Row row, ReadOnlySpan vanillaRows) - { - //List vanils = vanilla.Rows.Where(cell => cell.ID == row.ID).ToList(); - if (vanillaRows.Length == 0) - { - return true; - } - - foreach (Param.Row vrow in vanillaRows) - { - if (row.RowMatches(vrow)) - { - return false; //if we find a matching vanilla row - } - } - - return true; - } private void SaveParamsDS1() { var dir = Project.ParentProject.AssetLocator.RootDirectory; @@ -1481,9 +1064,9 @@ void OverwriteParamsAC6(BND4 paramBnd) _pendingUpgrade = false; } - - public void SaveParams(bool loose = false) + public override void Save() { + bool loose = Project.Settings.UseLooseParams; if (_params == null) { return; @@ -1530,347 +1113,6 @@ public void SaveParams(bool loose = false) } } - private static Param UpgradeParam(Param source, Param oldVanilla, Param newVanilla, HashSet rowConflicts) - { - // Presorting this would make it easier, but we're trying to preserve order as much as possible - // Unfortunately given that rows aren't guaranteed to be sorted and there can be duplicate IDs, - // we try to respect the existing order and IDs as much as possible. - - // In order to assemble the final param, the param needs to know where to sort rows from given the - // following rules: - // 1. If a row with a given ID is unchanged from source to oldVanilla, we source from newVanilla - // 2. If a row with a given ID is deleted from source compared to oldVanilla, we don't take any row - // 3. If a row with a given ID is changed from source compared to oldVanilla, we source from source - // 4. If a row has duplicate IDs, we treat them as if the rows were deduplicated and process them - // in the order they appear. - - // List of rows that are in source but not oldVanilla - Dictionary> addedRows = new(source.Rows.Count); - - // List of rows in oldVanilla that aren't in source - Dictionary> deletedRows = new(source.Rows.Count); - - // List of rows that are in source and oldVanilla, but are modified - Dictionary> modifiedRows = new(source.Rows.Count); - - // List of rows that only had the name changed - Dictionary> renamedRows = new(source.Rows.Count); - - // List of ordered edit operations for each ID - Dictionary> editOperations = new(source.Rows.Count); - - // First off we go through source and everything starts as an added param - foreach (Param.Row row in source.Rows) - { - if (!addedRows.ContainsKey(row.ID)) - { - addedRows.Add(row.ID, new List()); - } - - addedRows[row.ID].Add(row); - } - - // Next we go through oldVanilla to determine if a row is added, deleted, modified, or unmodified - foreach (Param.Row row in oldVanilla.Rows) - { - // First off if the row did not exist in the source, it's deleted - if (!addedRows.ContainsKey(row.ID)) - { - if (!deletedRows.ContainsKey(row.ID)) - { - deletedRows.Add(row.ID, new List()); - } - - deletedRows[row.ID].Add(row); - if (!editOperations.ContainsKey(row.ID)) - { - editOperations.Add(row.ID, new List()); - } - - editOperations[row.ID].Add(EditOperation.Delete); - continue; - } - - // Otherwise the row exists in source. Time to classify it. - List list = addedRows[row.ID]; - - // First we see if we match the first target row. If so we can remove it. - if (row.DataEquals(list[0])) - { - Param.Row modrow = list[0]; - list.RemoveAt(0); - if (list.Count == 0) - { - addedRows.Remove(row.ID); - } - - if (!editOperations.ContainsKey(row.ID)) - { - editOperations.Add(row.ID, new List()); - } - - // See if the name was not updated - if ((modrow.Name == null && row.Name == null) || - (modrow.Name != null && row.Name != null && modrow.Name == row.Name)) - { - editOperations[row.ID].Add(EditOperation.Match); - continue; - } - - // Name was updated - editOperations[row.ID].Add(EditOperation.NameChange); - if (!renamedRows.ContainsKey(row.ID)) - { - renamedRows.Add(row.ID, new List()); - } - - renamedRows[row.ID].Add(modrow); - - continue; - } - - // Otherwise it is modified - if (!modifiedRows.ContainsKey(row.ID)) - { - modifiedRows.Add(row.ID, new List()); - } - - modifiedRows[row.ID].Add(list[0]); - list.RemoveAt(0); - if (list.Count == 0) - { - addedRows.Remove(row.ID); - } - - if (!editOperations.ContainsKey(row.ID)) - { - editOperations.Add(row.ID, new List()); - } - - editOperations[row.ID].Add(EditOperation.Modify); - } - - // Mark all remaining rows as added - foreach (KeyValuePair> entry in addedRows) - { - if (!editOperations.ContainsKey(entry.Key)) - { - editOperations.Add(entry.Key, new List()); - } - - foreach (List k in editOperations.Values) - { - editOperations[entry.Key].Add(EditOperation.Add); - } - } - - if (editOperations.All(kvp => kvp.Value.All(eo => eo == EditOperation.Match))) - { - return oldVanilla; - } - - Param dest = new(newVanilla); - - // Now try to build the destination from the new regulation with the edit operations in mind - var pendingAdds = addedRows.Keys.OrderBy(e => e).ToArray(); - var currPendingAdd = 0; - var lastID = 0; - foreach (Param.Row row in newVanilla.Rows) - { - // See if we have any pending adds we can slot in - while (currPendingAdd < pendingAdds.Length && - pendingAdds[currPendingAdd] >= lastID && - pendingAdds[currPendingAdd] < row.ID) - { - if (!addedRows.ContainsKey(pendingAdds[currPendingAdd])) - { - currPendingAdd++; - continue; - } - - foreach (Param.Row arow in addedRows[pendingAdds[currPendingAdd]]) - { - dest.AddRow(new Param.Row(arow, dest)); - } - - addedRows.Remove(pendingAdds[currPendingAdd]); - editOperations.Remove(pendingAdds[currPendingAdd]); - currPendingAdd++; - } - - lastID = row.ID; - - if (!editOperations.ContainsKey(row.ID)) - { - // No edit operations for this ID, so just add it (likely a new row in the update) - dest.AddRow(new Param.Row(row, dest)); - continue; - } - - // Pop the latest operation we need to do - EditOperation operation = editOperations[row.ID][0]; - editOperations[row.ID].RemoveAt(0); - if (editOperations[row.ID].Count == 0) - { - editOperations.Remove(row.ID); - } - - if (operation == EditOperation.Add) - { - // Getting here means both the mod and the updated regulation added a row. Our current strategy is - // to overwrite the new vanilla row with the modded one and add to the conflict log to give the user - rowConflicts.Add(row.ID); - dest.AddRow(new Param.Row(addedRows[row.ID][0], dest)); - addedRows[row.ID].RemoveAt(0); - if (addedRows[row.ID].Count == 0) - { - addedRows.Remove(row.ID); - } - } - else if (operation == EditOperation.Match) - { - // Match means we inherit updated param - dest.AddRow(new Param.Row(row, dest)); - } - else if (operation == EditOperation.Delete) - { - // deleted means we don't add anything - deletedRows[row.ID].RemoveAt(0); - if (deletedRows[row.ID].Count == 0) - { - deletedRows.Remove(row.ID); - } - } - else if (operation == EditOperation.Modify) - { - // Modified means we use the modded regulation's param - dest.AddRow(new Param.Row(modifiedRows[row.ID][0], dest)); - modifiedRows[row.ID].RemoveAt(0); - if (modifiedRows[row.ID].Count == 0) - { - modifiedRows.Remove(row.ID); - } - } - else if (operation == EditOperation.NameChange) - { - // Inherit name - Param.Row newRow = new(row, dest); - newRow.Name = renamedRows[row.ID][0].Name; - dest.AddRow(newRow); - renamedRows[row.ID].RemoveAt(0); - if (renamedRows[row.ID].Count == 0) - { - renamedRows.Remove(row.ID); - } - } - } - - // Take care of any more pending adds - for (; currPendingAdd < pendingAdds.Length; currPendingAdd++) - { - // If the pending add doesn't exist in the added rows list, it was a conflicting row - if (!addedRows.ContainsKey(pendingAdds[currPendingAdd])) - { - continue; - } - - foreach (Param.Row arow in addedRows[pendingAdds[currPendingAdd]]) - { - dest.AddRow(new Param.Row(arow, dest)); - } - - addedRows.Remove(pendingAdds[currPendingAdd]); - editOperations.Remove(pendingAdds[currPendingAdd]); - } - - return dest; - } - - // Param upgrade. Currently for Elden Ring only. - public ParamUpgradeResult UpgradeRegulation(ParamBank vanillaBank, string oldVanillaParamPath, - Dictionary> conflictingParams) - { - // First we need to load the old regulation - if (!File.Exists(oldVanillaParamPath)) - { - return ParamUpgradeResult.OldRegulationNotFound; - } - - // Backup modded params - string modRegulationPath = $@"{Project.AssetLocator.RootDirectory}\regulation.bin"; - File.Copy(modRegulationPath, $@"{modRegulationPath}.upgrade.bak", true); - - // Load old vanilla regulation - BND4 oldVanillaParamBnd; - if (Project.Type == GameType.EldenRing) - { - oldVanillaParamBnd = SFUtil.DecryptERRegulation(oldVanillaParamPath); - } - else if (Project.Type == GameType.ArmoredCoreVI) - { - oldVanillaParamBnd = SFUtil.DecryptAC6Regulation(oldVanillaParamPath); - } - else - { - throw new NotImplementedException( - $"Param upgrading for game type {Project.Type} is not supported."); - } - - Dictionary oldVanillaParams = new(); - ulong version; - LoadParamFromBinder(oldVanillaParamBnd, ref oldVanillaParams, out version, true); - if (version != ParamVersion) - { - return ParamUpgradeResult.OldRegulationVersionMismatch; - } - - Dictionary updatedParams = new(); - // Now we must diff everything to try and find changed/added rows for each param - var anyUpgrades = false; - foreach (var k in vanillaBank.Params.Keys) - { - // If the param is completely new, just take it - if (!oldVanillaParams.ContainsKey(k) || !Params.ContainsKey(k)) - { - updatedParams.Add(k, vanillaBank.Params[k]); - continue; - } - - // Otherwise try to upgrade - HashSet conflicts = new(); - Param res = UpgradeParam(Params[k], oldVanillaParams[k], vanillaBank.Params[k], conflicts); - if (res != oldVanillaParams[k]) - { - anyUpgrades = true; - } - - updatedParams.Add(k, res); - - if (conflicts.Count > 0) - { - conflictingParams.Add(k, conflicts); - } - } - - if (!anyUpgrades) - { - return ParamUpgradeResult.OldRegulationMatchesCurrent; - } - - var oldVersion = _paramVersion; - - // Set new params - _params = updatedParams; - _paramVersion = VanillaBank.ParamVersion; - _pendingUpgrade = true; - - // Refresh dirty cache - UICache.ClearCaches(); - RefreshAllParamDiffCaches(false); - - return conflictingParams.Count > 0 ? ParamUpgradeResult.RowConflictsFound : ParamUpgradeResult.Success; - } - public string GetChrIDForEnemy(long enemyID) { Param.Row enemy = EnemyParam?[(int)enemyID]; @@ -1913,116 +1155,8 @@ public Param GetParamFromName(string param) return null; } - public HashSet GetVanillaDiffRows(string param) - { - IReadOnlyDictionary> allDiffs = VanillaDiffCache; - if (allDiffs == null || !allDiffs.ContainsKey(param)) - { - return EMPTYSET; - } - - return allDiffs[param]; - } - - public HashSet GetPrimaryDiffRows(string param) - { - IReadOnlyDictionary> allDiffs = PrimaryDiffCache; - if (allDiffs == null || !allDiffs.ContainsKey(param)) - { - return EMPTYSET; - } - - return allDiffs[param]; - } - - /// - /// Loads row names from external files and applies them to params. - /// Uses indicies rather than IDs. - /// - private void LoadExternalRowNames() - { - var failCount = 0; - foreach (KeyValuePair p in _params) - { - var path = Project.AssetLocator.GetStrippedRowNamesPath(p.Key); - if (File.Exists(path)) - { - var names = File.ReadAllLines(path); - if (names.Length != p.Value.Rows.Count) - { - TaskLogs.AddLog($"External row names could not be applied to {p.Key}, row count does not match", - LogLevel.Warning, TaskLogs.LogPriority.Low); - failCount++; - continue; - } - - for (var i = 0; i < names.Length; i++) - { - p.Value.Rows[i].Name = names[i]; - } - } - } - - if (failCount > 0) - { - TaskLogs.AddLog( - $"External row names could not be applied to {failCount} params due to non-matching row counts.", - LogLevel.Warning); - } - } - - /// - /// Strips row names from params, saves them to files, and stores them to be restored after saving params. - /// Should always be used in conjunction with RestoreStrippedRowNames(). - /// - private void StripRowNames() - { - _storedStrippedRowNames = new Dictionary>(); - foreach (KeyValuePair p in _params) - { - _storedStrippedRowNames.TryAdd(p.Key, new List()); - List list = _storedStrippedRowNames[p.Key]; - foreach (Param.Row r in p.Value.Rows) - { - list.Add(r.Name); - r.Name = ""; - } - - var path = Project.AssetLocator.GetStrippedRowNamesPath(p.Key); - Directory.CreateDirectory(Path.GetDirectoryName(path)); - File.WriteAllLines(path, list); - } - } - - /// - /// Restores stripped row names back to all params. - /// Should always be used in conjunction with StripRowNames(). - /// - private void RestoreStrippedRowNames() - { - if (_storedStrippedRowNames == null) - { - throw new InvalidOperationException("No stripped row names have been stored."); - } - - foreach (KeyValuePair p in _params) - { - List storedNames = _storedStrippedRowNames[p.Key]; - for (var i = 0; i < p.Value.Rows.Count; i++) - { - p.Value.Rows[i].Name = storedNames[i]; - } - } - - _storedStrippedRowNames = null; - } - - private enum EditOperation + protected override IEnumerable GetDependencies(Project project) { - Add, - Delete, - Modify, - NameChange, - Match + return [ResDirectory.CurrentGame.ParamDefBank]; } } diff --git a/src/StudioCore/ParamEditor/ParamBankUpgrader.cs b/src/StudioCore/ParamEditor/ParamBankUpgrader.cs new file mode 100644 index 000000000..adcee953c --- /dev/null +++ b/src/StudioCore/ParamEditor/ParamBankUpgrader.cs @@ -0,0 +1,378 @@ +using Andre.Formats; +using Microsoft.Extensions.Logging; +using SoulsFormats; +using StudioCore.Editor; +using StudioCore.Platform; +using StudioCore.TextEditor; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace StudioCore.ParamEditor; + +/// +/// Utilities for dealing with global params for a game +/// +public partial class ParamBank : DataBank +{ + public enum ParamUpgradeResult + { + Success = 0, + RowConflictsFound = -1, + OldRegulationNotFound = -2, + OldRegulationVersionMismatch = -3, + OldRegulationMatchesCurrent = -4 + } + private enum EditOperation + { + Add, + Delete, + Modify, + NameChange, + Match + } + + private bool _pendingUpgrade; + + private static Param UpgradeParam(Param source, Param oldVanilla, Param newVanilla, HashSet rowConflicts) + { + // Presorting this would make it easier, but we're trying to preserve order as much as possible + // Unfortunately given that rows aren't guaranteed to be sorted and there can be duplicate IDs, + // we try to respect the existing order and IDs as much as possible. + + // In order to assemble the final param, the param needs to know where to sort rows from given the + // following rules: + // 1. If a row with a given ID is unchanged from source to oldVanilla, we source from newVanilla + // 2. If a row with a given ID is deleted from source compared to oldVanilla, we don't take any row + // 3. If a row with a given ID is changed from source compared to oldVanilla, we source from source + // 4. If a row has duplicate IDs, we treat them as if the rows were deduplicated and process them + // in the order they appear. + + // List of rows that are in source but not oldVanilla + Dictionary> addedRows = new(source.Rows.Count); + + // List of rows in oldVanilla that aren't in source + Dictionary> deletedRows = new(source.Rows.Count); + + // List of rows that are in source and oldVanilla, but are modified + Dictionary> modifiedRows = new(source.Rows.Count); + + // List of rows that only had the name changed + Dictionary> renamedRows = new(source.Rows.Count); + + // List of ordered edit operations for each ID + Dictionary> editOperations = new(source.Rows.Count); + + // First off we go through source and everything starts as an added param + foreach (Param.Row row in source.Rows) + { + if (!addedRows.ContainsKey(row.ID)) + { + addedRows.Add(row.ID, new List()); + } + + addedRows[row.ID].Add(row); + } + + // Next we go through oldVanilla to determine if a row is added, deleted, modified, or unmodified + foreach (Param.Row row in oldVanilla.Rows) + { + // First off if the row did not exist in the source, it's deleted + if (!addedRows.ContainsKey(row.ID)) + { + if (!deletedRows.ContainsKey(row.ID)) + { + deletedRows.Add(row.ID, new List()); + } + + deletedRows[row.ID].Add(row); + if (!editOperations.ContainsKey(row.ID)) + { + editOperations.Add(row.ID, new List()); + } + + editOperations[row.ID].Add(EditOperation.Delete); + continue; + } + + // Otherwise the row exists in source. Time to classify it. + List list = addedRows[row.ID]; + + // First we see if we match the first target row. If so we can remove it. + if (row.DataEquals(list[0])) + { + Param.Row modrow = list[0]; + list.RemoveAt(0); + if (list.Count == 0) + { + addedRows.Remove(row.ID); + } + + if (!editOperations.ContainsKey(row.ID)) + { + editOperations.Add(row.ID, new List()); + } + + // See if the name was not updated + if ((modrow.Name == null && row.Name == null) || + (modrow.Name != null && row.Name != null && modrow.Name == row.Name)) + { + editOperations[row.ID].Add(EditOperation.Match); + continue; + } + + // Name was updated + editOperations[row.ID].Add(EditOperation.NameChange); + if (!renamedRows.ContainsKey(row.ID)) + { + renamedRows.Add(row.ID, new List()); + } + + renamedRows[row.ID].Add(modrow); + + continue; + } + + // Otherwise it is modified + if (!modifiedRows.ContainsKey(row.ID)) + { + modifiedRows.Add(row.ID, new List()); + } + + modifiedRows[row.ID].Add(list[0]); + list.RemoveAt(0); + if (list.Count == 0) + { + addedRows.Remove(row.ID); + } + + if (!editOperations.ContainsKey(row.ID)) + { + editOperations.Add(row.ID, new List()); + } + + editOperations[row.ID].Add(EditOperation.Modify); + } + + // Mark all remaining rows as added + foreach (KeyValuePair> entry in addedRows) + { + if (!editOperations.ContainsKey(entry.Key)) + { + editOperations.Add(entry.Key, new List()); + } + + foreach (List k in editOperations.Values) + { + editOperations[entry.Key].Add(EditOperation.Add); + } + } + + if (editOperations.All(kvp => kvp.Value.All(eo => eo == EditOperation.Match))) + { + return oldVanilla; + } + + Param dest = new(newVanilla); + + // Now try to build the destination from the new regulation with the edit operations in mind + var pendingAdds = addedRows.Keys.OrderBy(e => e).ToArray(); + var currPendingAdd = 0; + var lastID = 0; + foreach (Param.Row row in newVanilla.Rows) + { + // See if we have any pending adds we can slot in + while (currPendingAdd < pendingAdds.Length && + pendingAdds[currPendingAdd] >= lastID && + pendingAdds[currPendingAdd] < row.ID) + { + if (!addedRows.ContainsKey(pendingAdds[currPendingAdd])) + { + currPendingAdd++; + continue; + } + + foreach (Param.Row arow in addedRows[pendingAdds[currPendingAdd]]) + { + dest.AddRow(new Param.Row(arow, dest)); + } + + addedRows.Remove(pendingAdds[currPendingAdd]); + editOperations.Remove(pendingAdds[currPendingAdd]); + currPendingAdd++; + } + + lastID = row.ID; + + if (!editOperations.ContainsKey(row.ID)) + { + // No edit operations for this ID, so just add it (likely a new row in the update) + dest.AddRow(new Param.Row(row, dest)); + continue; + } + + // Pop the latest operation we need to do + EditOperation operation = editOperations[row.ID][0]; + editOperations[row.ID].RemoveAt(0); + if (editOperations[row.ID].Count == 0) + { + editOperations.Remove(row.ID); + } + + if (operation == EditOperation.Add) + { + // Getting here means both the mod and the updated regulation added a row. Our current strategy is + // to overwrite the new vanilla row with the modded one and add to the conflict log to give the user + rowConflicts.Add(row.ID); + dest.AddRow(new Param.Row(addedRows[row.ID][0], dest)); + addedRows[row.ID].RemoveAt(0); + if (addedRows[row.ID].Count == 0) + { + addedRows.Remove(row.ID); + } + } + else if (operation == EditOperation.Match) + { + // Match means we inherit updated param + dest.AddRow(new Param.Row(row, dest)); + } + else if (operation == EditOperation.Delete) + { + // deleted means we don't add anything + deletedRows[row.ID].RemoveAt(0); + if (deletedRows[row.ID].Count == 0) + { + deletedRows.Remove(row.ID); + } + } + else if (operation == EditOperation.Modify) + { + // Modified means we use the modded regulation's param + dest.AddRow(new Param.Row(modifiedRows[row.ID][0], dest)); + modifiedRows[row.ID].RemoveAt(0); + if (modifiedRows[row.ID].Count == 0) + { + modifiedRows.Remove(row.ID); + } + } + else if (operation == EditOperation.NameChange) + { + // Inherit name + Param.Row newRow = new(row, dest); + newRow.Name = renamedRows[row.ID][0].Name; + dest.AddRow(newRow); + renamedRows[row.ID].RemoveAt(0); + if (renamedRows[row.ID].Count == 0) + { + renamedRows.Remove(row.ID); + } + } + } + + // Take care of any more pending adds + for (; currPendingAdd < pendingAdds.Length; currPendingAdd++) + { + // If the pending add doesn't exist in the added rows list, it was a conflicting row + if (!addedRows.ContainsKey(pendingAdds[currPendingAdd])) + { + continue; + } + + foreach (Param.Row arow in addedRows[pendingAdds[currPendingAdd]]) + { + dest.AddRow(new Param.Row(arow, dest)); + } + + addedRows.Remove(pendingAdds[currPendingAdd]); + editOperations.Remove(pendingAdds[currPendingAdd]); + } + + return dest; + } + + // Param upgrade. Currently for Elden Ring only. + public ParamUpgradeResult UpgradeRegulation(ParamBank vanillaBank, string oldVanillaParamPath, + Dictionary> conflictingParams) + { + // First we need to load the old regulation + if (!File.Exists(oldVanillaParamPath)) + { + return ParamUpgradeResult.OldRegulationNotFound; + } + + // Backup modded params + string modRegulationPath = $@"{Project.AssetLocator.RootDirectory}\regulation.bin"; + File.Copy(modRegulationPath, $@"{modRegulationPath}.upgrade.bak", true); + + // Load old vanilla regulation + BND4 oldVanillaParamBnd; + if (Project.Type == GameType.EldenRing) + { + oldVanillaParamBnd = SFUtil.DecryptERRegulation(oldVanillaParamPath); + } + else if (Project.Type == GameType.ArmoredCoreVI) + { + oldVanillaParamBnd = SFUtil.DecryptAC6Regulation(oldVanillaParamPath); + } + else + { + throw new NotImplementedException( + $"Param upgrading for game type {Project.Type} is not supported."); + } + + Dictionary oldVanillaParams = new(); + ulong version; + LoadParamFromBinder(oldVanillaParamBnd, ref oldVanillaParams, out version, true); + if (version != ParamVersion) + { + return ParamUpgradeResult.OldRegulationVersionMismatch; + } + + Dictionary updatedParams = new(); + // Now we must diff everything to try and find changed/added rows for each param + var anyUpgrades = false; + foreach (var k in vanillaBank.Params.Keys) + { + // If the param is completely new, just take it + if (!oldVanillaParams.ContainsKey(k) || !Params.ContainsKey(k)) + { + updatedParams.Add(k, vanillaBank.Params[k]); + continue; + } + + // Otherwise try to upgrade + HashSet conflicts = new(); + Param res = UpgradeParam(Params[k], oldVanillaParams[k], vanillaBank.Params[k], conflicts); + if (res != oldVanillaParams[k]) + { + anyUpgrades = true; + } + + updatedParams.Add(k, res); + + if (conflicts.Count > 0) + { + conflictingParams.Add(k, conflicts); + } + } + + if (!anyUpgrades) + { + return ParamUpgradeResult.OldRegulationMatchesCurrent; + } + + var oldVersion = _paramVersion; + + // Set new params + _params = updatedParams; + _paramVersion = VanillaBank.ParamVersion; + _pendingUpgrade = true; + + // Refresh dirty cache + UICache.ClearCaches(); + ParamDiffBank.RefreshAllParamDiffCaches(false); + + return conflictingParams.Count > 0 ? ParamUpgradeResult.RowConflictsFound : ParamUpgradeResult.Success; + } +} diff --git a/src/StudioCore/ParamEditor/ParamBankUtilities.cs b/src/StudioCore/ParamEditor/ParamBankUtilities.cs new file mode 100644 index 000000000..112794fdb --- /dev/null +++ b/src/StudioCore/ParamEditor/ParamBankUtilities.cs @@ -0,0 +1,160 @@ +using Andre.Formats; +using Microsoft.Extensions.Logging; +using SoulsFormats; +using StudioCore.Editor; +using StudioCore.Platform; +using StudioCore.TextEditor; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace StudioCore.ParamEditor; + +/// +/// Utilities for dealing with global params for a game +/// +public partial class ParamBank : DataBank +{ + + /// + /// Param name - FMGCategory map + /// + public static readonly List<(string, FmgEntryCategory)> ParamToFmgCategoryList = new() + { + ("EquipParamAccessory", FmgEntryCategory.Rings), + ("EquipParamGoods", FmgEntryCategory.Goods), + ("EquipParamWeapon", FmgEntryCategory.Weapons), + ("EquipParamProtector", FmgEntryCategory.Armor), + ("Magic", FmgEntryCategory.Spells), + ("EquipParamGem", FmgEntryCategory.Gem), + ("SwordArtsParam", FmgEntryCategory.SwordArts), + ("EquipParamGenerator", FmgEntryCategory.Generator), + ("EquipParamFcs", FmgEntryCategory.FCS), + ("EquipParamBooster", FmgEntryCategory.Booster), + ("ArchiveParam", FmgEntryCategory.Archive), + ("MissionParam", FmgEntryCategory.Mission) + }; + + private Dictionary> _storedStrippedRowNames; + + public CompoundAction LoadParamDefaultNames(string param = null, bool onlyAffectEmptyNames = false, bool onlyAffectVanillaNames = false) + { + var files = param == null + ? Project.AssetLocator.GetAllProjectFiles($@"{Project.AssetLocator.GetParamdexDir()}\Names", ["*.txt"], true) + : new[] { Project.AssetLocator.GetProjectFilePath($@"{Project.AssetLocator.GetParamdexDir()}\Names\{param}.txt") }; + List actions = new(); + foreach (var f in files) + { + var fName = Path.GetFileNameWithoutExtension(f); + if (!_params.ContainsKey(fName)) + { + continue; + } + + var names = File.ReadAllText(f); + (var result, CompoundAction action) = + ParamIO.ApplySingleCSV(this, names, fName, "Name", ' ', true, onlyAffectEmptyNames, onlyAffectVanillaNames); + if (action == null) + { + TaskLogs.AddLog($"Could not apply name files for {fName}", + LogLevel.Warning); + } + else + { + actions.Add(action); + } + } + + return new CompoundAction(actions); + } + + public ActionManager TrimNewlineChrsFromNames() + { + (MassEditResult r, ActionManager child) = + MassParamEditRegex.PerformMassEdit(this, "param .*: id .*: name: replace \r:0", null); + return child; + } + + /// + /// Loads row names from external files and applies them to params. + /// Uses indicies rather than IDs. + /// + private void LoadExternalRowNames() + { + var failCount = 0; + foreach (KeyValuePair p in _params) + { + var path = Project.AssetLocator.GetStrippedRowNamesPath(p.Key); + if (File.Exists(path)) + { + var names = File.ReadAllLines(path); + if (names.Length != p.Value.Rows.Count) + { + TaskLogs.AddLog($"External row names could not be applied to {p.Key}, row count does not match", + LogLevel.Warning, TaskLogs.LogPriority.Low); + failCount++; + continue; + } + + for (var i = 0; i < names.Length; i++) + { + p.Value.Rows[i].Name = names[i]; + } + } + } + + if (failCount > 0) + { + TaskLogs.AddLog( + $"External row names could not be applied to {failCount} params due to non-matching row counts.", + LogLevel.Warning); + } + } + + /// + /// Strips row names from params, saves them to files, and stores them to be restored after saving params. + /// Should always be used in conjunction with RestoreStrippedRowNames(). + /// + private void StripRowNames() + { + _storedStrippedRowNames = new Dictionary>(); + foreach (KeyValuePair p in _params) + { + _storedStrippedRowNames.TryAdd(p.Key, new List()); + List list = _storedStrippedRowNames[p.Key]; + foreach (Param.Row r in p.Value.Rows) + { + list.Add(r.Name); + r.Name = ""; + } + + var path = Project.AssetLocator.GetStrippedRowNamesPath(p.Key); + Directory.CreateDirectory(Path.GetDirectoryName(path)); + File.WriteAllLines(path, list); + } + } + + /// + /// Restores stripped row names back to all params. + /// Should always be used in conjunction with StripRowNames(). + /// + private void RestoreStrippedRowNames() + { + if (_storedStrippedRowNames == null) + { + throw new InvalidOperationException("No stripped row names have been stored."); + } + + foreach (KeyValuePair p in _params) + { + List storedNames = _storedStrippedRowNames[p.Key]; + for (var i = 0; i < p.Value.Rows.Count; i++) + { + p.Value.Rows[i].Name = storedNames[i]; + } + } + + _storedStrippedRowNames = null; + } +} diff --git a/src/StudioCore/ParamEditor/ParamCFG.cs b/src/StudioCore/ParamEditor/ParamCFG.cs new file mode 100644 index 000000000..cc6da8c5c --- /dev/null +++ b/src/StudioCore/ParamEditor/ParamCFG.cs @@ -0,0 +1,53 @@ +using StudioCore.Platform; +using StudioCore.Renderer.Scene; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.IO; +using System.Numerics; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace StudioCore; + +public partial class CFG +{ + + //private string _Param_Export_Array_Delimiter = "|"; + private string _Param_Export_Delimiter = ","; + + public bool Param_AdvancedMassedit = false; + public bool Param_AllowFieldReorder = true; + public bool Param_AlphabeticalParams = true; + public bool Param_DisableLineWrapping = false; + public bool Param_DisableRowGrouping = false; + public bool Param_HideEnums = false; + public bool Param_HideReferenceRows = false; + public bool Param_MakeMetaNamesPrimary = true; + public bool Param_PasteAfterSelection = false; + public bool Param_PasteThenSelect = true; + public bool Param_ShowFieldOffsets = false; + public bool Param_ShowHotkeysInContextMenu = true; + public bool Param_ShowSecondaryNames = true; + public bool Param_ShowVanillaParams = true; + public bool UI_CompactParams = false; + + public string Param_Export_Delimiter + { + get + { + if (_Param_Export_Delimiter.Length == 0) + { + _Param_Export_Delimiter = Default.Param_Export_Delimiter; + } + else if (_Param_Export_Delimiter == "|") + { + _Param_Export_Delimiter = + Default.Param_Export_Delimiter; // Temporary measure to prevent conflicts with byte array delimiters. Will be removed later. + } + + return _Param_Export_Delimiter; + } + set => _Param_Export_Delimiter = value; + } +} diff --git a/src/StudioCore/ParamEditor/ParamDefBank.cs b/src/StudioCore/ParamEditor/ParamDefBank.cs new file mode 100644 index 000000000..f36204d36 --- /dev/null +++ b/src/StudioCore/ParamEditor/ParamDefBank.cs @@ -0,0 +1,96 @@ +using SoulsFormats; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace StudioCore.ParamEditor; + +/// +/// Utilities for dealing with global paramdefs for a game +/// +public class ParamDefBank : StudioResource +{ + /// + /// Mapping from path -> PARAMDEF for cache and and comparison purposes. TODO: check for paramdef comparisons and evaluate if the file/paramdef was actually the same. + /// + private static readonly Dictionary _paramdefsCache = new(); + + /// + /// Mapping from ParamType -> PARAMDEF. + /// + private Dictionary _paramdefs = new(); + + private List<(string, PARAMDEF)> _defPairs = new(); + + /// + /// Mapping from Param filename -> Manual ParamType. + /// This is for params with no usable ParamType at some particular game version. + /// By convention, ParamTypes ending in "_TENTATIVE" do not have official data to reference. + /// + private Dictionary _tentativeParamType; + + public ParamDefBank() : base(Locator.ActiveProject.Type, "Paramdefs") + { + } + + public Dictionary GetParamDefs() + { + return _paramdefs; + } + + public List<(string, PARAMDEF)> GetParamDefByFileNames() + { + return _defPairs; + } + + public Dictionary GetTentativeParamTypes() + { + return _tentativeParamType; + } + + private void LoadParamdefs() + { + _paramdefs = new Dictionary(); + _tentativeParamType = new Dictionary(); + var files = Locator.ActiveProject.AssetLocator.GetAllProjectFiles($@"Paramdex\{AssetUtils.GetGameIDForDir(Locator.ActiveProject.Type)}\Defs", ["*.xml"], true, false); + List<(string, PARAMDEF)> defPairs = new(); + foreach (var f in files) + { + if (!_paramdefsCache.TryGetValue(f, out PARAMDEF pdef)) + { + pdef = PARAMDEF.XmlDeserialize(f, true); + } + _paramdefs.Add(pdef.ParamType, pdef); + defPairs.Add((f, pdef)); + } + + var tentativeMappingPath = Locator.ActiveProject.AssetLocator.GetProjectFilePath($@"{Locator.ActiveProject.AssetLocator.GetParamdexDir()}\Defs\TentativeParamType.csv"); + if (File.Exists(tentativeMappingPath)) + { + // No proper CSV library is used currently, and all CSV parsing is in the context of param files. + // If a CSV library is introduced in DSMapStudio, use it here. + foreach (var line in File.ReadAllLines(tentativeMappingPath).Skip(1)) + { + var parts = line.Split(','); + if (parts.Length != 2 || string.IsNullOrWhiteSpace(parts[0]) || string.IsNullOrWhiteSpace(parts[1])) + { + throw new FormatException($"Malformed line in {tentativeMappingPath}: {line}"); + } + + _tentativeParamType[parts[0]] = parts[1]; + } + } + + _defPairs = defPairs; + } + protected override void Load() + { + LoadParamdefs(); + } + + protected override IEnumerable GetDependencies(Project project) + { + return []; + } +} diff --git a/src/StudioCore/ParamEditor/ParamDiffBank.cs b/src/StudioCore/ParamEditor/ParamDiffBank.cs new file mode 100644 index 000000000..2e745c3c6 --- /dev/null +++ b/src/StudioCore/ParamEditor/ParamDiffBank.cs @@ -0,0 +1,266 @@ +using Andre.Formats; +using Microsoft.Extensions.Logging; +using SoulsFormats; +using StudioCore.Editor; +using StudioCore.Platform; +using StudioCore.TextEditor; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace StudioCore.ParamEditor; + +/// +/// Utilities for dealing with global paramdiffs for a game +/// +public class ParamDiffBank : DataBank +{ + + private Dictionary> _primaryDiffCache; //If param != primaryparam + private Dictionary> _vanillaDiffCache; //If param != vanillaparam + + public ParamDiffBank(Project project) : base(project, "ParamDiffs") + { + } + + public IReadOnlyDictionary> VanillaDiffCache + { + get + { + if (IsLoading) + { + return null; + } + + if (Project.ParentProject == null) + { + return null; + } + return _vanillaDiffCache; + } + } + + public IReadOnlyDictionary> PrimaryDiffCache + { + get + { + if (IsLoading) + { + return null; + } + + if (Project == Locator.ActiveProject) + { + return null; + } + return _primaryDiffCache; + } + } + + private void ClearParamDiffCaches() + { + _vanillaDiffCache = new Dictionary>(); + _primaryDiffCache = new Dictionary>(); + foreach (var param in Project.ParamBank.Params?.Keys) + { + _vanillaDiffCache.Add(param, new HashSet()); + _primaryDiffCache.Add(param, new HashSet()); + } + } + + public static void RefreshAllParamDiffCaches(bool checkAuxVanillaDiff) + { + Locator.ActiveProject.ParamDiffBank.RefreshParamDiffCaches(true); + foreach (KeyValuePair aux in ResDirectory.CurrentGame.AuxProjects) + { + aux.Value.ParamDiffBank.RefreshParamDiffCaches(checkAuxVanillaDiff); + } + + UICache.ClearCaches(); + } + + public void RefreshParamDiffCaches(bool checkVanillaDiff) + { + if (Project.ParentProject != null && checkVanillaDiff) + { + _vanillaDiffCache = GetParamDiff(Project.ParentProject.ParamBank); + } + + if (Project.ParentProject == null && Locator.ActiveProject.ParamDiffBank._vanillaDiffCache != null) + { + _primaryDiffCache = Locator.ActiveProject.ParamDiffBank._vanillaDiffCache; + } + else if (Project != Locator.ActiveProject) + { + _primaryDiffCache = GetParamDiff(Locator.ActiveProject.ParamBank); + } + + UICache.ClearCaches(); + } + + private Dictionary> GetParamDiff(ParamBank otherBank) + { + if (otherBank == null || otherBank.IsLoading) + { + return null; + } + + Dictionary> newCache = new(); + foreach (var param in Project.ParamBank.Params.Keys) + { + HashSet cache = new(); + newCache.Add(param, cache); + Param p = Project.ParamBank.Params[param]; + if (!otherBank.Params.ContainsKey(param)) + { + Console.WriteLine("Missing vanilla param " + param); + continue; + } + + Param.Row[] rows = Project.ParamBank.Params[param].Rows.OrderBy(r => r.ID).ToArray(); + Param.Row[] vrows = otherBank.Params[param].Rows.OrderBy(r => r.ID).ToArray(); + + var vanillaIndex = 0; + var lastID = -1; + ReadOnlySpan lastVanillaRows = default; + for (var i = 0; i < rows.Length; i++) + { + var ID = rows[i].ID; + if (ID == lastID) + { + RefreshParamRowDiffCache(rows[i], lastVanillaRows, cache); + } + else + { + lastID = ID; + while (vanillaIndex < vrows.Length && vrows[vanillaIndex].ID < ID) + { + vanillaIndex++; + } + + if (vanillaIndex >= vrows.Length) + { + RefreshParamRowDiffCache(rows[i], Span.Empty, cache); + } + else + { + var count = 0; + while (vanillaIndex + count < vrows.Length && vrows[vanillaIndex + count].ID == ID) + { + count++; + } + + lastVanillaRows = new ReadOnlySpan(vrows, vanillaIndex, count); + RefreshParamRowDiffCache(rows[i], lastVanillaRows, cache); + vanillaIndex += count; + } + } + } + } + + return newCache; + } + + private static void RefreshParamRowDiffCache(Param.Row row, ReadOnlySpan otherBankRows, + HashSet cache) + { + if (IsChanged(row, otherBankRows)) + { + cache.Add(row.ID); + } + else + { + cache.Remove(row.ID); + } + } + + public void RefreshParamRowDiffs(Param.Row row, string param) + { + if (param == null) + { + return; + } + + if (Project.ParentProject.ParamBank.Params.ContainsKey(param) && VanillaDiffCache != null && + VanillaDiffCache.ContainsKey(param)) + { + Param.Row[] otherBankRows = Project.ParentProject.ParamBank.Params[param].Rows.Where(cell => cell.ID == row.ID).ToArray(); + RefreshParamRowDiffCache(row, otherBankRows, VanillaDiffCache[param]); + } + + if (Project != Locator.ActiveProject) + { + return; + } + + foreach (Project aux in ResDirectory.CurrentGame.AuxProjects.Values) + { + if (!aux.ParamBank.Params.ContainsKey(param) || aux.ParamDiffBank.PrimaryDiffCache == null || + !aux.ParamDiffBank.PrimaryDiffCache.ContainsKey(param)) + { + continue; // Don't try for now + } + + Param.Row[] otherBankRows = aux.ParamBank.Params[param].Rows.Where(cell => cell.ID == row.ID).ToArray(); + RefreshParamRowDiffCache(row, otherBankRows, aux.ParamDiffBank.PrimaryDiffCache[param]); + } + } + + private static bool IsChanged(Param.Row row, ReadOnlySpan vanillaRows) + { + //List vanils = vanilla.Rows.Where(cell => cell.ID == row.ID).ToList(); + if (vanillaRows.Length == 0) + { + return true; + } + + foreach (Param.Row vrow in vanillaRows) + { + if (row.RowMatches(vrow)) + { + return false; //if we find a matching vanilla row + } + } + + return true; + } + private static readonly HashSet EMPTYSET = new(); + + public HashSet GetVanillaDiffRows(string param) + { + IReadOnlyDictionary> allDiffs = VanillaDiffCache; + if (allDiffs == null || !allDiffs.ContainsKey(param)) + { + return EMPTYSET; + } + + return allDiffs[param]; + } + + public HashSet GetPrimaryDiffRows(string param) + { + IReadOnlyDictionary> allDiffs = PrimaryDiffCache; + if (allDiffs == null || !allDiffs.ContainsKey(param)) + { + return EMPTYSET; + } + + return allDiffs[param]; + } + + public override void Save() + { + } + + protected override void Load() + { + RefreshParamDiffCaches(true); + UICache.ClearCaches(); + } + + protected override IEnumerable GetDependencies(Project project) + { + return [project.ParamBank, project.ParentProject.ParamBank]; + } +} diff --git a/src/StudioCore/ParamEditor/ParamEditorScreen.cs b/src/StudioCore/ParamEditor/ParamEditorScreen.cs index 5a727b97b..1c2b21165 100644 --- a/src/StudioCore/ParamEditor/ParamEditorScreen.cs +++ b/src/StudioCore/ParamEditor/ParamEditorScreen.cs @@ -226,6 +226,31 @@ public ParamEditorScreen(Sdl2Window window, GraphicsDevice device) public string CommandEndpoint => "param"; public string SaveType => "Params"; + /// + /// Param name - FMGCategory map + /// + public static readonly List<(string, FmgEntryCategory)> ParamToFmgCategoryList = new() + { + ("EquipParamAccessory", FmgEntryCategory.Rings), + ("EquipParamGoods", FmgEntryCategory.Goods), + ("EquipParamWeapon", FmgEntryCategory.Weapons), + ("EquipParamProtector", FmgEntryCategory.Armor), + ("Magic", FmgEntryCategory.Spells), + ("EquipParamGem", FmgEntryCategory.Gem), + ("SwordArtsParam", FmgEntryCategory.SwordArts), + ("EquipParamGenerator", FmgEntryCategory.Generator), + ("EquipParamFcs", FmgEntryCategory.FCS), + ("EquipParamBooster", FmgEntryCategory.Booster), + ("ArchiveParam", FmgEntryCategory.Archive), + ("MissionParam", FmgEntryCategory.Mission) + }; + public enum RowGetType + { + AllRows = 0, + ModifiedRows = 1, + SelectedRows = 2 + } + public void DrawEditorMenu() { // Menu Options @@ -328,20 +353,20 @@ public void DrawEditorMenu() ImGui.Separator(); if (ImGui.BeginMenu("All rows")) { - CsvExportDisplay(ParamBank.RowGetType.AllRows); + CsvExportDisplay(RowGetType.AllRows); ImGui.EndMenu(); } if (ImGui.BeginMenu("Modified rows", - ParamBank.PrimaryBank.GetVanillaDiffRows(_activeView._selection.GetActiveParam()).Any())) + Locator.ActiveProject.ParamDiffBank.GetVanillaDiffRows(_activeView._selection.GetActiveParam()).Any())) { - CsvExportDisplay(ParamBank.RowGetType.ModifiedRows); + CsvExportDisplay(RowGetType.ModifiedRows); ImGui.EndMenu(); } if (ImGui.BeginMenu("Selected rows", _activeView._selection.RowSelectionExists())) { - CsvExportDisplay(ParamBank.RowGetType.SelectedRows); + CsvExportDisplay(RowGetType.SelectedRows); ImGui.EndMenu(); } @@ -416,7 +441,7 @@ public void DrawEditorMenu() TaskManager.Run(new TaskManager.LiveTask("Param - Check Differences", TaskManager.RequeueType.Repeat, true, TaskLogs.LogPriority.Low, - () => ParamBank.RefreshAllParamDiffCaches(false))); + () => ParamDiffBank.RefreshAllParamDiffCaches(false))); } else { @@ -444,7 +469,7 @@ public void DrawEditorMenu() TaskManager.Run(new TaskManager.LiveTask("Param - Check Differences", TaskManager.RequeueType.Repeat, true, TaskLogs.LogPriority.Low, - () => ParamBank.RefreshAllParamDiffCaches(false))); + () => ParamDiffBank.RefreshAllParamDiffCaches(false))); } } @@ -473,7 +498,7 @@ public void DrawEditorMenu() TaskManager.Run(new TaskManager.LiveTask("Param - Check Differences", TaskManager.RequeueType.Repeat, true, TaskLogs.LogPriority.Low, - () => ParamBank.RefreshAllParamDiffCaches(false))); + () => ParamDiffBank.RefreshAllParamDiffCaches(false))); } } } @@ -571,9 +596,9 @@ void ImportRowNames(bool currentParamOnly, string title) ImGui.Separator(); if (ImGui.MenuItem("Check all params for edits", null, false, - !ParamBank.PrimaryBank.IsLoadingParams && !ParamBank.VanillaBank.IsLoadingParams)) + ParamBank.PrimaryBank.IsLoaded && ParamBank.VanillaBank.IsLoaded)) { - ParamBank.RefreshAllParamDiffCaches(true); + ParamDiffBank.RefreshAllParamDiffCaches(true); } ImGui.Separator(); @@ -717,14 +742,14 @@ void ImportRowNames(bool currentParamOnly, string title) } } - if (ImGui.BeginMenu("Clear param comparison...", ParamBank.AuxBanks.Count > 0)) + if (ImGui.BeginMenu("Clear param comparison...", ResDirectory.CurrentGame.AuxProjects.Count > 0)) { - for (var i = 0; i < ParamBank.AuxBanks.Count; i++) + for (var i = 0; i < ResDirectory.CurrentGame.AuxProjects.Count; i++) { - KeyValuePair pb = ParamBank.AuxBanks.ElementAt(i); + KeyValuePair pb = ResDirectory.CurrentGame.AuxProjects.ElementAt(i); if (ImGui.MenuItem(pb.Key)) { - ParamBank.AuxBanks.Remove(pb.Key); + ResDirectory.CurrentGame.AuxProjects.Remove(pb.Key); break; } } @@ -732,9 +757,10 @@ void ImportRowNames(bool currentParamOnly, string title) ImGui.EndMenu(); } - if (ImGui.MenuItem("Clear all param comparisons", null, false, ParamBank.AuxBanks.Count > 0)) + if (ImGui.MenuItem("Clear all param comparisons", null, false, ResDirectory.CurrentGame.AuxProjects.Count > 0)) { - ParamBank.AuxBanks = new Dictionary(); + // TODO look into whether it's sensible for parambank to control auxprojects like this + ResDirectory.CurrentGame.AuxProjects = new Dictionary(); } ImGui.EndMenu(); @@ -859,7 +885,7 @@ public unsafe void OnGUI(string[] initcmd) return; } - if (ParamBank.PrimaryBank.IsLoadingParams) + if (ParamBank.PrimaryBank.IsLoading) { ImGui.Text("Loading Params..."); return; @@ -871,7 +897,7 @@ public unsafe void OnGUI(string[] initcmd) return; } - if (!ParamBank.IsMetaLoaded) + if (!ResDirectory.CurrentGame.ParamMetaBank.IsLoaded) { ImGui.Text("Loading Meta..."); return; @@ -905,7 +931,7 @@ public unsafe void OnGUI(string[] initcmd) if (InputTracker.GetKeyDown(KeyBindings.Current.Param_ExportCSV)) { - EditorCommandQueue.AddCommand($@"param/menu/massEditCSVExport/{ParamBank.RowGetType.AllRows}"); + EditorCommandQueue.AddCommand($@"param/menu/massEditCSVExport/{RowGetType.AllRows}"); } // Parse commands @@ -986,7 +1012,7 @@ public unsafe void OnGUI(string[] initcmd) } else if (initcmd[1] == "massEditCSVExport") { - IReadOnlyList rows = CsvExportGetRows(Enum.Parse(initcmd[2])); + IReadOnlyList rows = CsvExportGetRows(Enum.Parse(initcmd[2])); _currentMEditCSVOutput = ParamIO.GenerateCSV(rows, ParamBank.PrimaryBank.Params[_activeView._selection.GetActiveParam()], CFG.Current.Param_Export_Delimiter[0]); @@ -999,7 +1025,7 @@ public unsafe void OnGUI(string[] initcmd) else if (initcmd[1] == "massEditSingleCSVExport") { _currentMEditSingleCSVField = initcmd[2]; - IReadOnlyList rows = CsvExportGetRows(Enum.Parse(initcmd[3])); + IReadOnlyList rows = CsvExportGetRows(Enum.Parse(initcmd[3])); _currentMEditCSVOutput = ParamIO.GenerateSingleCSV(rows, ParamBank.PrimaryBank.Params[_activeView._selection.GetActiveParam()], _currentMEditSingleCSVField, @@ -1125,7 +1151,7 @@ public void Save() { if (_projectSettings != null) { - ParamBank.PrimaryBank.SaveParams(_projectSettings.UseLooseParams); + ParamBank.PrimaryBank.Save(); TaskLogs.AddLog("Saved params"); } } @@ -1147,7 +1173,7 @@ public void SaveAll() { if (_projectSettings != null) { - ParamBank.PrimaryBank.SaveParams(_projectSettings.UseLooseParams); + ParamBank.PrimaryBank.Save(); TaskLogs.AddLog("Saved params"); } } @@ -1216,12 +1242,12 @@ private void LoadUpgraderData() private void ParamUpgradeDisplay() { - if (Locator.ActiveProject != null && Locator.ActiveProject.ParamBank.IsDefsLoaded + if (Locator.ActiveProject != null && ResDirectory.CurrentGame.ParamDefBank.IsLoaded && ParamBank.PrimaryBank.Params != null && ParamBank.VanillaBank.Params != null && ParamUpgrade_SupportedGames.Contains(Locator.AssetLocator.Type) - && !ParamBank.PrimaryBank.IsLoadingParams - && !ParamBank.VanillaBank.IsLoadingParams + && ParamBank.PrimaryBank.IsLoaded + && ParamBank.VanillaBank.IsLoaded && ParamBank.PrimaryBank.ParamVersion < ParamBank.VanillaBank.ParamVersion) { if (!_paramUpgraderLoaded) @@ -1395,7 +1421,7 @@ public void UpgradeRegulation(ParamBank bank, ParamBank vanillaBank, string oldR } UICache.ClearCaches(); - ParamBank.RefreshAllParamDiffCaches(false); + ParamDiffBank.RefreshAllParamDiffCaches(false); } @@ -1464,7 +1490,7 @@ private void ParamUndo() TaskManager.Run(new TaskManager.LiveTask("Param - Check Differences", TaskManager.RequeueType.Repeat, true, TaskLogs.LogPriority.Low, - () => ParamBank.RefreshAllParamDiffCaches(false))); + () => ParamDiffBank.RefreshAllParamDiffCaches(false))); } private void ParamRedo() @@ -1473,27 +1499,27 @@ private void ParamRedo() TaskManager.Run(new TaskManager.LiveTask("Param - Check Differences", TaskManager.RequeueType.Repeat, true, TaskLogs.LogPriority.Low, - () => ParamBank.RefreshAllParamDiffCaches(false))); + () => ParamDiffBank.RefreshAllParamDiffCaches(false))); } - private IReadOnlyList CsvExportGetRows(ParamBank.RowGetType rowType) + private IReadOnlyList CsvExportGetRows(RowGetType rowType) { IReadOnlyList rows; var activeParam = _activeView._selection.GetActiveParam(); - if (rowType == ParamBank.RowGetType.AllRows) + if (rowType == RowGetType.AllRows) { // All rows rows = ParamBank.PrimaryBank.Params[activeParam].Rows; } - else if (rowType == ParamBank.RowGetType.ModifiedRows) + else if (rowType == RowGetType.ModifiedRows) { // Modified rows - HashSet vanillaDiffCache = ParamBank.PrimaryBank.GetVanillaDiffRows(activeParam); + HashSet vanillaDiffCache = Locator.ActiveProject.ParamDiffBank.GetVanillaDiffRows(activeParam); rows = ParamBank.PrimaryBank.Params[activeParam].Rows.Where(p => vanillaDiffCache.Contains(p.ID)) .ToList(); } - else if (rowType == ParamBank.RowGetType.SelectedRows) + else if (rowType == RowGetType.SelectedRows) { // Selected rows rows = _activeView._selection.GetSelectedRows(); @@ -1509,7 +1535,7 @@ private void ParamRedo() /// /// CSV Export DIsplay /// - private void CsvExportDisplay(ParamBank.RowGetType rowType) + private void CsvExportDisplay(RowGetType rowType) { if (ImGui.BeginMenu("Export to window...")) { @@ -1725,7 +1751,7 @@ public void MassEditPopups() TaskManager.Run(new TaskManager.LiveTask("Param - Check Differences", TaskManager.RequeueType.Repeat, true, TaskLogs.LogPriority.Low, - () => ParamBank.RefreshAllParamDiffCaches(false))); + () => ParamDiffBank.RefreshAllParamDiffCaches(false))); } _mEditRegexResult = r.Information; @@ -1791,7 +1817,7 @@ public void MassEditPopups() TaskManager.Run(new TaskManager.LiveTask("Param - Check Differences", TaskManager.RequeueType.Repeat, true, TaskLogs.LogPriority.Low, - () => ParamBank.RefreshAllParamDiffCaches(false))); + () => ParamDiffBank.RefreshAllParamDiffCaches(false))); } _mEditCSVResult = result; @@ -2092,4 +2118,63 @@ private static string TryReadFile(string path) return null; } } + + IEnumerable EditorScreen.GetDependencies(Project project) + { + return [project.ParamBank, project.ParentProject.ParamBank, project.ParamDiffBank, ResDirectory.CurrentGame.ParamMetaBank]; + } + + public void SettingsMenu() + { + if (ImGui.CollapsingHeader("General", ImGuiTreeNodeFlags.DefaultOpen)) + { + EditorDecorations.ShowHelpMarker("Reduces the line height within the the Param Editor screen."); + ImGui.Checkbox("Use compact param editor", ref CFG.Current.UI_CompactParams); + + EditorDecorations.ShowHelpMarker("Show additional options within the MassEdit context menu."); + ImGui.Checkbox("Show advanced massedit options", ref CFG.Current.Param_AdvancedMassedit); + + EditorDecorations.ShowHelpMarker("Show the shortcut tools in the right-click context menu."); + ImGui.Checkbox("Show shortcut tools in context menus", ref CFG.Current.Param_ShowHotkeysInContextMenu); + } + + if (ImGui.CollapsingHeader("Params")) + { + EditorDecorations.ShowHelpMarker("Sort the Param View list alphabetically."); + if (ImGui.Checkbox("Sort params alphabetically", ref CFG.Current.Param_AlphabeticalParams)) + { + UICache.ClearCaches(); + } + } + + if (ImGui.CollapsingHeader("Rows")) + { + EditorDecorations.ShowHelpMarker("Disable the row names from wrapping within the Row View list."); + ImGui.Checkbox("Disable line wrapping", ref CFG.Current.Param_DisableLineWrapping); + + EditorDecorations.ShowHelpMarker("Disable the grouping of connected rows in certain params, such as ItemLotParam within the Row View list."); + ImGui.Checkbox("Disable row grouping", ref CFG.Current.Param_DisableRowGrouping); + } + + if (ImGui.CollapsingHeader("Fields")) + { + EditorDecorations.ShowHelpMarker("Crowd-sourced names will appear before the canonical name in the Field View list."); + ImGui.Checkbox("Show community field names first", ref CFG.Current.Param_MakeMetaNamesPrimary); + + EditorDecorations.ShowHelpMarker("The crowd-sourced name (or the canonical name if the above option is enabled) will appear after the initial name in the Field View list."); + ImGui.Checkbox("Show secondary field names", ref CFG.Current.Param_ShowSecondaryNames); + + EditorDecorations.ShowHelpMarker("The field offset within the .PARAM file will be show to the left in the Field View List."); + ImGui.Checkbox("Show field data offsets", ref CFG.Current.Param_ShowFieldOffsets); + + EditorDecorations.ShowHelpMarker("Hide the generated param references for fields that link to other params."); + ImGui.Checkbox("Hide field references", ref CFG.Current.Param_HideReferenceRows); + + EditorDecorations.ShowHelpMarker("Hide the crowd-sourced namelist for index-based enum fields."); + ImGui.Checkbox("Hide field enums", ref CFG.Current.Param_HideEnums); + + EditorDecorations.ShowHelpMarker("Allow the field order to be changed by an alternative order as defined within the Paramdex META file."); + ImGui.Checkbox("Allow field reordering", ref CFG.Current.Param_AllowFieldReorder); + } + } } diff --git a/src/StudioCore/ParamEditor/ParamEditorSelectionState.cs b/src/StudioCore/ParamEditor/ParamEditorSelectionState.cs index 63051c364..70dd98757 100644 --- a/src/StudioCore/ParamEditor/ParamEditorSelectionState.cs +++ b/src/StudioCore/ParamEditor/ParamEditorSelectionState.cs @@ -181,9 +181,9 @@ public void SetActiveRow(Param.Row row, bool clearSelection, bool isHistory = fa if (_activeParam != null) { ParamEditorParamSelectionState s = _paramStates[_activeParam]; - if (s.activeRow != null && !ParamBank.VanillaBank.IsLoadingParams) + if (s.activeRow != null && ParamBank.VanillaBank.IsLoaded) { - ParamBank.PrimaryBank.RefreshParamRowDiffs(s.activeRow, _activeParam); + Locator.ActiveProject.ParamDiffBank.RefreshParamRowDiffs(s.activeRow, _activeParam); } if (!isHistory) @@ -194,9 +194,9 @@ public void SetActiveRow(Param.Row row, bool clearSelection, bool isHistory = fa s.activeRow = row; s.selectionRows.Clear(); s.selectionRows.Add(row); - if (s.activeRow != null && !ParamBank.VanillaBank.IsLoadingParams) + if (s.activeRow != null && ParamBank.VanillaBank.IsLoaded) { - ParamBank.PrimaryBank.RefreshParamRowDiffs(s.activeRow, _activeParam); + Locator.ActiveProject.ParamDiffBank.RefreshParamRowDiffs(s.activeRow, _activeParam); } s.selectionCacheDirty = true; diff --git a/src/StudioCore/ParamEditor/ParamEditorView.cs b/src/StudioCore/ParamEditor/ParamEditorView.cs index 41f3d559b..8f5a3fd6b 100644 --- a/src/StudioCore/ParamEditor/ParamEditorView.cs +++ b/src/StudioCore/ParamEditor/ParamEditorView.cs @@ -132,7 +132,7 @@ private void ParamView_ParamList_Pinned(float scale) //ImGui.Text(" Pinned Params"); foreach (var paramKey in pinnedParamKeyList) { - HashSet primary = ParamBank.PrimaryBank.VanillaDiffCache.GetValueOrDefault(paramKey, null); + HashSet primary = Locator.ActiveProject.ParamDiffBank.VanillaDiffCache.GetValueOrDefault(paramKey, null); Param p = ParamBank.PrimaryBank.Params[paramKey]; if (p != null) { @@ -173,6 +173,28 @@ private void ParamView_ParamList_Pinned(float scale) } } + /// + /// Map related params. + /// + public static readonly List DS2MapParamlist = new() + { + "demopointlight", + "demospotlight", + "eventlocation", + "eventparam", + "GeneralLocationEventParam", + "generatorparam", + "generatorregistparam", + "generatorlocation", + "generatordbglocation", + "hitgroupparam", + "intrudepointparam", + "mapobjectinstanceparam", + "maptargetdirparam", + "npctalkparam", + "treasureboxparam" + }; + private void ParamView_ParamList_Main(bool doFocus, float scale, float scrollTo) { List paramKeyList = UICache.GetCached(_paramEditor, _viewIndex, () => @@ -199,11 +221,11 @@ or GameType.DarkSoulsPTDE { if (_mapParamView) { - keyList = keyList.FindAll(p => ParamBank.DS2MapParamlist.Contains(p.Split('_')[0])); + keyList = keyList.FindAll(p => DS2MapParamlist.Contains(p.Split('_')[0])); } else { - keyList = keyList.FindAll(p => !ParamBank.DS2MapParamlist.Contains(p.Split('_')[0])); + keyList = keyList.FindAll(p => !DS2MapParamlist.Contains(p.Split('_')[0])); } } else if (Locator.AssetLocator.Type is GameType.EldenRing) @@ -257,7 +279,7 @@ or GameType.DarkSoulsPTDE foreach (var paramKey in paramKeyList) { - HashSet primary = ParamBank.PrimaryBank.VanillaDiffCache.GetValueOrDefault(paramKey, null); + HashSet primary = Locator.ActiveProject.ParamDiffBank.VanillaDiffCache?.GetValueOrDefault(paramKey, null); Param p = ParamBank.PrimaryBank.Params[paramKey]; if (p != null) { @@ -417,9 +439,9 @@ private void ParamView_RowList(bool doFocus, bool isActiveView, float scrollTo, ParamView_RowList_Header(ref doFocus, isActiveView, ref scrollTo, activeParam); Param para = ParamBank.PrimaryBank.Params[activeParam]; - HashSet vanillaDiffCache = ParamBank.PrimaryBank.GetVanillaDiffRows(activeParam); - List<(HashSet, HashSet)> auxDiffCaches = ParamBank.AuxBanks.Select((bank, i) => - (bank.Value.GetVanillaDiffRows(activeParam), bank.Value.GetPrimaryDiffRows(activeParam))).ToList(); + HashSet vanillaDiffCache = Locator.ActiveProject.ParamDiffBank.GetVanillaDiffRows(activeParam); + List<(HashSet, HashSet)> auxDiffCaches = ResDirectory.CurrentGame.AuxProjects.Select((project, i) => + (project.Value.ParamDiffBank.GetVanillaDiffRows(activeParam), project.Value.ParamDiffBank.GetPrimaryDiffRows(activeParam))).ToList(); Param.Column compareCol = _selection.GetCompareCol(); PropertyInfo compareColProp = typeof(Param.Cell).GetProperty("Value"); @@ -559,8 +581,8 @@ private void ParamView_FieldList(bool isActiveView, string activeParam, Param.Ro ParamBank.PrimaryBank, activeRow, vanillaParam?[activeRow.ID], - ParamBank.AuxBanks.Select((bank, i) => - (bank.Key, bank.Value.Params?.GetValueOrDefault(activeParam)?[activeRow.ID])).ToList(), + ResDirectory.CurrentGame.AuxProjects.Select((project, i) => + (project.Key, project.Value.ParamBank.Params?.GetValueOrDefault(activeParam)?[activeRow.ID])).ToList(), _selection.GetCompareRow(), ref _selection.GetCurrentPropSearchString(), activeParam, @@ -835,9 +857,9 @@ private bool ParamView_RowList_Entry(bool[] selectionCache, int selectionCacheIn ImGui.PushStyleVarVec2(ImGuiStyleVar.FramePadding, new Vector2(0, 0)); ParamEditorCommon.PropertyField(compareCol.ValueType, c.Value, ref newval, false); if (ParamEditorCommon.UpdateProperty(_propEditor.ContextActionManager, c, compareColProp, - c.Value) && !ParamBank.VanillaBank.IsLoadingParams) + c.Value) && ParamBank.VanillaBank.IsLoaded) { - ParamBank.PrimaryBank.RefreshParamRowDiffs(r, activeParam); + Locator.ActiveProject.ParamDiffBank.RefreshParamRowDiffs(r, activeParam); } ImGui.PopStyleVar(1); diff --git a/src/StudioCore/ParamEditor/ParamMeta.cs b/src/StudioCore/ParamEditor/ParamMeta.cs index 363597b4f..cfc4fc332 100644 --- a/src/StudioCore/ParamEditor/ParamMeta.cs +++ b/src/StudioCore/ParamEditor/ParamMeta.cs @@ -213,12 +213,12 @@ private ParamMetaData(XmlDocument xml, string path, PARAMDEF def) public static ParamMetaData Get(PARAMDEF def) { - if (!ParamBank.IsMetaLoaded) + if (!ResDirectory.CurrentGame.ParamMetaBank.IsLoaded) { return null; } - return Locator.ActiveProject.ParamBank.ParamMetas[def]; + return ResDirectory.CurrentGame.ParamMetaBank.ParamMetas[def]; } internal static XmlNode GetXmlNode(XmlDocument xml, XmlNode parent, string child) { @@ -372,7 +372,7 @@ public static void SaveAll() field.Value.Commit(FixName(field.Key.InternalName)); //does not handle shared names } - foreach (ParamMetaData param in Locator.ActiveProject.ParamBank.ParamMetas.Values) + foreach (ParamMetaData param in ResDirectory.CurrentGame.ParamMetaBank.ParamMetas.Values) { param.Commit(); param.Save(); @@ -519,7 +519,7 @@ public FieldMetaData(ParamMetaData parent, XmlNode fieldMeta, PARAMDEF.Field fie public static FieldMetaData Get(PARAMDEF.Field def) { - if (!ParamBank.IsMetaLoaded) + if (!ResDirectory.CurrentGame.ParamMetaBank.IsLoaded) { return null; } diff --git a/src/StudioCore/ParamEditor/ParamMetaBank.cs b/src/StudioCore/ParamEditor/ParamMetaBank.cs new file mode 100644 index 000000000..d28a0741c --- /dev/null +++ b/src/StudioCore/ParamEditor/ParamMetaBank.cs @@ -0,0 +1,36 @@ +using SoulsFormats; +using System.Collections.Generic; + +namespace StudioCore.ParamEditor; + +/// +/// Utilities for dealing with global paramdefs for a game +/// +public class ParamMetaBank : StudioResource +{ + public Dictionary ParamMetas = new(); + + public ParamMetaBank() : base(Locator.ActiveProject.Type, "ParamMetas") + { + } + public void LoadParamMeta() + { + List<(string, PARAMDEF)> defPairs = ResDirectory.CurrentGame.ParamDefBank.GetParamDefByFileNames(); + var mdir = Locator.ActiveProject.AssetLocator.GetProjectFilePath($@"{Locator.ActiveProject.AssetLocator.GetParamdexDir()}\Meta"); + foreach ((var f, PARAMDEF pdef) in defPairs) + { + var fName = f.Substring(f.LastIndexOf('\\') + 1); + var md = ParamMetaData.XmlDeserialize($@"{mdir}\{fName}", pdef); + ParamMetas.Add(pdef, md); + } + } + protected override void Load() + { + LoadParamMeta(); + } + + protected override IEnumerable GetDependencies(Project project) + { + return [ResDirectory.CurrentGame.ParamDefBank]; + } +} diff --git a/src/StudioCore/ParamEditor/ParamReloader.cs b/src/StudioCore/ParamEditor/ParamReloader.cs index 7e3164150..d7d82ecb8 100644 --- a/src/StudioCore/ParamEditor/ParamReloader.cs +++ b/src/StudioCore/ParamEditor/ParamReloader.cs @@ -40,7 +40,7 @@ public static bool GameIsSupported(GameType gameType) public static bool CanReloadMemoryParams(ParamBank bank, ProjectSettings projectSettings) { - if (projectSettings != null && GameIsSupported(projectSettings.GameType) && bank.IsLoadingParams == false) + if (projectSettings != null && GameIsSupported(projectSettings.GameType) && !bank.IsLoading) { return true; } diff --git a/src/StudioCore/ParamEditor/ParamRowEditor.cs b/src/StudioCore/ParamEditor/ParamRowEditor.cs index d666a50b1..6ca5332b0 100644 --- a/src/StudioCore/ParamEditor/ParamRowEditor.cs +++ b/src/StudioCore/ParamEditor/ParamRowEditor.cs @@ -212,7 +212,7 @@ public void PropEditorParamRow(ParamBank bank, Param.Row row, Param.Row vrow, Li List> auxCols = UICache.GetCached(_paramEditor, auxRows, "auxFieldFilter", () => auxRows.Select((r, i) => - cols.Select((c, j) => c.GetAs(ParamBank.AuxBanks[r.Item1].GetParamFromName(activeParam))) + cols.Select((c, j) => c.GetAs(ResDirectory.CurrentGame.AuxProjects[r.Item1].ParamBank.GetParamFromName(activeParam))) .ToList()).ToList()); if (pinnedFields?.Count > 0) @@ -500,9 +500,9 @@ private void PropEditorPropRow(ParamBank bank, object oldval, object compareval, var committed = ParamEditorCommon.UpdateProperty(ContextActionManager, nullableCell != null ? nullableCell : row, proprow, oldval); - if (committed && !ParamBank.VanillaBank.IsLoadingParams) + if (committed && ParamBank.VanillaBank.IsLoaded) { - ParamBank.PrimaryBank.RefreshParamRowDiffs(row, activeParam); + Locator.ActiveProject.ParamDiffBank.RefreshParamRowDiffs(row, activeParam); } ImGui.PopID(); diff --git a/src/StudioCore/ParamEditor/SearchEngine.cs b/src/StudioCore/ParamEditor/SearchEngine.cs index 184a1cde5..0fd5e83ae 100644 --- a/src/StudioCore/ParamEditor/SearchEngine.cs +++ b/src/StudioCore/ParamEditor/SearchEngine.cs @@ -281,7 +281,7 @@ internal class ParamSearchEngine : SearchEngine internal override void Setup() { unpacker = dummy => - ParamBank.AuxBanks.Select((aux, i) => aux.Value.Params.Select((x, i) => (aux.Value, x.Value))) + ResDirectory.CurrentGame.AuxProjects.Select((aux, i) => aux.Value.ParamBank.Params.Select((x, i) => (aux.Value.ParamBank, x.Value))) .Aggregate(bank.Params.Values.Select((x, i) => (bank, x)), (o, n) => o.Concat(n)).ToList(); filterList.Add("modified", newCmd(new string[0], "Selects params where any rows do not match the vanilla version, or where any are added. Ignores row names", @@ -292,7 +292,7 @@ internal override void Setup() return false; } - HashSet cache = bank.GetVanillaDiffRows(bank.GetKeyForParam(param.Item2)); + HashSet cache = bank.Project.ParamDiffBank.GetVanillaDiffRows(bank.GetKeyForParam(param.Item2)); return cache.Count > 0; })))); filterList.Add("param", newCmd(new[] { "param name (regex)" }, @@ -310,7 +310,7 @@ internal override void Setup() "Selects params from the specified regulation or parambnd where the param name matches the given regex", (args, lenient) => { - ParamBank auxBank = ParamBank.AuxBanks[args[0]]; + ParamBank auxBank = ResDirectory.CurrentGame.AuxProjects[args[0]].ParamBank; Regex rx = lenient ? new Regex(args[1], RegexOptions.IgnoreCase) : new Regex($@"^{args[1]}$"); return noContext(param => param.Item1 != auxBank @@ -318,7 +318,7 @@ internal override void Setup() : rx.IsMatch(auxBank.GetKeyForParam(param.Item2) == null ? "" : auxBank.GetKeyForParam(param.Item2))); - }, () => ParamBank.AuxBanks.Count > 0 && CFG.Current.Param_AdvancedMassedit)); + }, () => ResDirectory.CurrentGame.AuxProjects.Count > 0 && CFG.Current.Param_AdvancedMassedit)); defaultFilter = newCmd(new[] { "param name (regex)" }, "Selects all params whose name matches the given regex", (args, lenient) => { @@ -345,7 +345,7 @@ internal override void Setup() "Selects rows which do not match the vanilla version, or are added. Ignores row name", noArgs(context => { var paramName = context.Item1.GetKeyForParam(context.Item2); - HashSet cache = context.Item1.GetVanillaDiffRows(paramName); + HashSet cache = context.Item1.Project.ParamDiffBank.GetVanillaDiffRows(paramName); return row => cache.Contains(row.ID); } ))); @@ -372,27 +372,27 @@ internal override void Setup() return row => true; } - HashSet pCache = ParamBank.PrimaryBank.GetVanillaDiffRows(paramName); - List<(HashSet, HashSet)> auxCaches = ParamBank.AuxBanks.Select(x => - (x.Value.GetPrimaryDiffRows(paramName), x.Value.GetVanillaDiffRows(paramName))).ToList(); + HashSet pCache = Locator.ActiveProject.ParamDiffBank.GetVanillaDiffRows(paramName); + List<(HashSet, HashSet)> auxCaches = ResDirectory.CurrentGame.AuxProjects.Select(x => + (x.Value.ParamDiffBank.GetPrimaryDiffRows(paramName), x.Value.ParamDiffBank.GetVanillaDiffRows(paramName))).ToList(); return row => !pCache.Contains(row.ID) && auxCaches.Where(x => x.Item2.Contains(row.ID) && x.Item1.Contains(row.ID)).Count() == 1; } - ), () => ParamBank.AuxBanks.Count > 0)); + ), () => ResDirectory.CurrentGame.AuxProjects.Count > 0)); filterList.Add("conflicts", newCmd(new string[0], "Selects rows which, among all equivalents in the primary and additional regulations or parambnds, there is more than row 1 which is modified", noArgs(context => { var paramName = context.Item1.GetKeyForParam(context.Item2); - HashSet pCache = ParamBank.PrimaryBank.GetVanillaDiffRows(paramName); - List<(HashSet, HashSet)> auxCaches = ParamBank.AuxBanks.Select(x => - (x.Value.GetPrimaryDiffRows(paramName), x.Value.GetVanillaDiffRows(paramName))).ToList(); + HashSet pCache = Locator.ActiveProject.ParamDiffBank.GetVanillaDiffRows(paramName); + List<(HashSet, HashSet)> auxCaches = ResDirectory.CurrentGame.AuxProjects.Select(x => + (x.Value.ParamDiffBank.GetPrimaryDiffRows(paramName), x.Value.ParamDiffBank.GetVanillaDiffRows(paramName))).ToList(); return row => (pCache.Contains(row.ID) ? 1 : 0) + auxCaches .Where(x => x.Item2.Contains(row.ID) && x.Item1.Contains(row.ID)).Count() > 1; } - ), () => ParamBank.AuxBanks.Count > 0)); + ), () => ResDirectory.CurrentGame.AuxProjects.Count > 0)); filterList.Add("id", newCmd(new[] { "row id (regex)" }, "Selects rows whose ID matches the given regex", (args, lenient) => { @@ -608,15 +608,15 @@ internal override void Setup() { Regex rx = lenient ? new Regex(args[2], RegexOptions.IgnoreCase) : new Regex($@"^{args[2]}$"); var field = args[1]; - ParamBank bank; - if (!ParamBank.AuxBanks.TryGetValue(args[0], out bank)) + Project proj; + if (!ResDirectory.CurrentGame.AuxProjects.TryGetValue(args[0], out proj)) { throw new Exception("Unable to find auxbank " + args[0]); } return param => { - Param vparam = bank.GetParamFromName(param.Item1.GetKeyForParam(param.Item2)); + Param vparam = proj.ParamBank.GetParamFromName(param.Item1.GetKeyForParam(param.Item2)); return row => { Param.Row vrow = vparam[row.ID]; @@ -636,7 +636,7 @@ internal override void Setup() return rx.IsMatch(term); }; }; - }, () => ParamBank.AuxBanks.Count > 0 && CFG.Current.Param_AdvancedMassedit)); + }, () => ResDirectory.CurrentGame.AuxProjects.Count > 0 && CFG.Current.Param_AdvancedMassedit)); filterList.Add("auxproprange", newCmd( new[] { @@ -649,15 +649,15 @@ internal override void Setup() var field = args[0]; var floor = double.Parse(args[1]); var ceil = double.Parse(args[2]); - ParamBank bank; - if (!ParamBank.AuxBanks.TryGetValue(args[0], out bank)) + Project proj; + if (!ResDirectory.CurrentGame.AuxProjects.TryGetValue(args[0], out proj)) { throw new Exception("Unable to find auxbank " + args[0]); } return param => { - Param vparam = bank.GetParamFromName(param.Item1.GetKeyForParam(param.Item2)); + Param vparam = proj.ParamBank.GetParamFromName(param.Item1.GetKeyForParam(param.Item2)); return row => { Param.Row vrow = vparam[row.ID]; @@ -670,7 +670,7 @@ internal override void Setup() return Convert.ToDouble(c.Value.Value) >= floor && Convert.ToDouble(c.Value.Value) <= ceil; }; }; - }, () => ParamBank.AuxBanks.Count > 0 && CFG.Current.Param_AdvancedMassedit)); + }, () => ResDirectory.CurrentGame.AuxProjects.Count > 0 && CFG.Current.Param_AdvancedMassedit)); filterList.Add("semijoin", newCmd( new[] @@ -870,12 +870,12 @@ internal override void Setup() "Selects cells/fields where the equivalent cell in the specified regulation or parambnd has a different value", (args, lenient) => { - if (!ParamBank.AuxBanks.ContainsKey(args[0])) + if (!ResDirectory.CurrentGame.AuxProjects.ContainsKey(args[0])) { throw new Exception("Can't check if cell is modified - parambank not found"); } - ParamBank bank = ParamBank.AuxBanks[args[0]]; + Project proj = ResDirectory.CurrentGame.AuxProjects[args[0]]; return row => { if (row.Item1 == null) @@ -883,7 +883,7 @@ internal override void Setup() throw new Exception("Can't check if cell is modified - not part of a param"); } - Param auxParam = bank.Params?[row.Item1]; + Param auxParam = proj?.ParamBank.Params?[row.Item1]; if (auxParam == null) { throw new Exception("Can't check if cell is modified - no aux param"); @@ -916,7 +916,7 @@ internal override void Setup() return ParamUtils.IsValueDiff(ref valA, ref valB, col.GetColumnType()); }; }; - }, () => ParamBank.AuxBanks.Count > 0)); + }, () => ResDirectory.CurrentGame.AuxProjects.Count > 0)); filterList.Add("sftype", newCmd(new[] { "paramdef type" }, "Selects cells/fields where the field's data type, as enumerated by soulsformats, matches the given regex", (args, lenient) => diff --git a/src/StudioCore/Project.cs b/src/StudioCore/Project.cs index a5660aa9f..1b168f480 100644 --- a/src/StudioCore/Project.cs +++ b/src/StudioCore/Project.cs @@ -21,9 +21,12 @@ public class Project public readonly ProjectAssetLocator AssetLocator; public readonly ParamBank ParamBank; + public readonly ParamDiffBank ParamDiffBank; public readonly FMGBank FMGBank; + public readonly MSBBank MSBBank; + public GameType Type => Settings.GameType; @@ -32,12 +35,14 @@ public class Project /// public Project(ProjectSettings settings) { - Settings = settings; + Settings = settings.CopyForGameDir(); AssetLocator = new(this, settings.GameRoot); ParentProject = null; ParamBank = new(this); + ParamDiffBank = new(this); FMGBank = new(this); + MSBBank = new(this); } /// /// Creates a project based in a folder with no explicit parent project, with a new ParentProject for the game directory. This is for a mod. @@ -49,7 +54,9 @@ public Project(ProjectSettings settings, string moddir) ParentProject = new Project(settings); ParamBank = new(this); + ParamDiffBank = new(this); FMGBank = new(this); + MSBBank = new(this); } /// /// Creates a project based in a folder with an explicit parent project. This is for an addon or fork of a mod. @@ -68,7 +75,9 @@ public Project(string moddir, Project parent, ProjectSettings settings = null) ParentProject = parent; ParamBank = new(this); + ParamDiffBank = new(this); FMGBank = new(this); + MSBBank = new(this); } /// @@ -86,7 +95,9 @@ public Project(Project parent) } ParamBank = parent.ParamBank; + ParamDiffBank = parent.ParamDiffBank; FMGBank = parent.FMGBank; + MSBBank = parent.MSBBank; } public Project CreateRecoveryProject() diff --git a/src/StudioCore/ProjectAssetLocator.cs b/src/StudioCore/ProjectAssetLocator.cs index 97ee2c398..424c4ed2b 100644 --- a/src/StudioCore/ProjectAssetLocator.cs +++ b/src/StudioCore/ProjectAssetLocator.cs @@ -35,7 +35,7 @@ public ProjectAssetLocator(Project owner, string dir) RootDirectory = dir; } - private string GetFileNameWithoutExtensions(string path) + public static string GetFileNameWithoutExtensions(string path) { return Path.GetFileNameWithoutExtension(Path.GetFileNameWithoutExtension(path)); } @@ -204,112 +204,6 @@ public IEnumerable GetAllSubDirs(string relpath, bool distinct = true, b } } - /// - /// Gets the full list of maps in the game (excluding chalice dungeons). Basically if there's an msb for it, - /// it will be in this list. - /// - /// - public List GetFullMapList() - { - - if (MapList != null) - { - return MapList; - } - - try - { - HashSet mapSet = new(); - - // DS2 has its own structure for msbs, where they are all inside individual folders - if (Type == GameType.DarkSoulsIISOTFS) - { - foreach (var map in GetAllAssets(@"map", [@"*.msb"], true, true)) - { - mapSet.Add(Path.GetFileNameWithoutExtension(map)); - } - } - else - { - foreach (var msb in GetAllAssets(@"map\MapStudio\", [@"*.msb", @"*.msb.dcx"])) - { - mapSet.Add(GetFileNameWithoutExtensions(msb)); - } - } - Regex mapRegex = new(@"^m\d{2}_\d{2}_\d{2}_\d{2}$"); - List mapList = mapSet.Where(x => mapRegex.IsMatch(x)).ToList(); - mapList.Sort(); - MapList = mapList; - return MapList; - } - catch (DirectoryNotFoundException e) - { - // Game is likely not UXM unpacked - if (ParentAssetLocator != null) - { - MapList = ParentAssetLocator.GetFullMapList(); - return MapList; - } - return new List(); - } - } - - public AssetDescription GetMapMSB(string mapid, bool writemode = false) - { - AssetDescription ad = new(); - ad.AssetPath = null; - if (mapid.Length != 12) - { - return ad; - } - - string preferredPath; - string backupPath; - // SOFTS - if (Type == GameType.DarkSoulsIISOTFS) - { - preferredPath = $@"map\{mapid}\{mapid}.msb"; - backupPath = $@"map\{mapid}\{mapid}.msb"; - } - // BB chalice maps - else if (Type == GameType.Bloodborne && mapid.StartsWith("m29")) - { - preferredPath = $@"\map\MapStudio\{mapid.Substring(0, 9)}_00\{mapid}.msb.dcx"; - backupPath = $@"\map\MapStudio\{mapid.Substring(0, 9)}_00\{mapid}.msb"; - } - // DeS, DS1, DS1R - else if (Type == GameType.DarkSoulsPTDE || Type == GameType.DarkSoulsRemastered || - Type == GameType.DemonsSouls) - { - preferredPath = $@"\map\MapStudio\{mapid}.msb"; - backupPath = $@"\map\MapStudio\{mapid}.msb.dcx"; - } - // BB, DS3, ER, SSDT - else if (Type == GameType.Bloodborne || Type == GameType.DarkSoulsIII || Type == GameType.EldenRing || - Type == GameType.Sekiro) - { - preferredPath = $@"\map\MapStudio\{mapid}.msb.dcx"; - backupPath = $@"\map\MapStudio\{mapid}.msb"; - } - else - { - preferredPath = $@"\map\MapStudio\{mapid}.msb.dcx"; - backupPath = $@"\map\MapStudio\{mapid}.msb"; - } - - if (writemode) - { - ad.AssetPath = $@"{RootDirectory}\{preferredPath}"; - } - else - { - ad.AssetPath = GetAssetPathFromOptions([preferredPath, backupPath]).Item2; - } - - ad.AssetName = mapid; - return ad; - } - public List GetMapBTLs(string mapid, bool writemode = false) { List adList = new(); diff --git a/src/StudioCore/DDSDeswizzler.cs b/src/StudioCore/Renderer/DDSDeswizzler.cs similarity index 99% rename from src/StudioCore/DDSDeswizzler.cs rename to src/StudioCore/Renderer/DDSDeswizzler.cs index 4032a8007..e0ddaa29a 100644 --- a/src/StudioCore/DDSDeswizzler.cs +++ b/src/StudioCore/Renderer/DDSDeswizzler.cs @@ -1,4 +1,4 @@ -namespace StudioCore; +namespace StudioCore.Renderer; public class DDSDeswizzler { diff --git a/src/StudioCore/DebugPrimitives/DbgPrim.cs b/src/StudioCore/Renderer/DebugPrimitives/DbgPrim.cs similarity index 92% rename from src/StudioCore/DebugPrimitives/DbgPrim.cs rename to src/StudioCore/Renderer/DebugPrimitives/DbgPrim.cs index d7bb55f6a..205a1ae2a 100644 --- a/src/StudioCore/DebugPrimitives/DbgPrim.cs +++ b/src/StudioCore/Renderer/DebugPrimitives/DbgPrim.cs @@ -1,5 +1,5 @@ -using StudioCore.Resource; -using StudioCore.Scene; +using StudioCore.Renderer.Resource; +using StudioCore.Renderer.Scene; using System; using System.Drawing; using System.Numerics; @@ -7,7 +7,7 @@ using Veldrid.Utilities; using Vortice.Vulkan; -namespace StudioCore.DebugPrimitives; +namespace StudioCore.Renderer.DebugPrimitives; public enum DbgPrimCategory { @@ -154,7 +154,7 @@ public void UpdatePerFrameResources(GraphicsDevice device, CommandList cl, Scene GeometryBuffer = null; if (Vertices.Length > 0 && Indices.Length > 0) { - GeometryBuffer = Renderer.GeometryBufferAllocator.Allocate(28 * (uint)Vertices.Length, + GeometryBuffer = Renderer.Scene.Renderer.GeometryBufferAllocator.Allocate(28 * (uint)Vertices.Length, 2 * (uint)Indices.Length, 28, 2, h => { h.FillVBuffer(Vertices); @@ -203,7 +203,7 @@ protected void AddIndex(short index) NeedToRecreateGeomBuffer = true; } - private unsafe void DrawPrimitive(Renderer.IndirectDrawEncoder encoder, SceneRenderPipeline sp) + private unsafe void DrawPrimitive(Renderer.Scene.Renderer.IndirectDrawEncoder encoder, SceneRenderPipeline sp) { if (GeometryBuffer == null || GeometryBuffer.VAllocationSize == 0 || GeometryBuffer.IAllocationSize == 0) { @@ -217,7 +217,7 @@ private unsafe void DrawPrimitive(Renderer.IndirectDrawEncoder encoder, SceneRen return; } - Renderer.IndirectDrawIndexedArgumentsPacked args = new(); + Renderer.Scene.Renderer.IndirectDrawIndexedArgumentsPacked args = new(); args.FirstInstance = WorldBuffer.AllocationStart / (uint)sizeof(InstanceData); args.VertexOffset = (int)(GeometryBuffer.VAllocationStart / 28); args.InstanceCount = 1; @@ -226,7 +226,7 @@ private unsafe void DrawPrimitive(Renderer.IndirectDrawEncoder encoder, SceneRen //encoder.AddDraw(ref args, GeomBuffer.BufferIndex, RenderPipeline, PerObjRS, IndexFormat.UInt16); } - public void Draw(Renderer.IndirectDrawEncoder encoder, SceneRenderPipeline sp, IDbgPrim parentPrim, + public void Draw(Renderer.Scene.Renderer.IndirectDrawEncoder encoder, SceneRenderPipeline sp, IDbgPrim parentPrim, Matrix4x4 world) { DrawPrimitive(encoder, sp); @@ -234,7 +234,7 @@ public void Draw(Renderer.IndirectDrawEncoder encoder, SceneRenderPipeline sp, I protected abstract void DisposeBuffers(); - public void SubmitRenderObjects(Renderer.RenderQueue queue) + public void SubmitRenderObjects(Renderer.Scene.Renderer.RenderQueue queue) { //ulong code = RenderPipeline != null ? (ulong)RenderPipeline.GetHashCode() : 0; //queue.Add(this, RenderKey.Create((int)(code & 0xFFFFFFFF), (uint)BufferIndex)); diff --git a/src/StudioCore/DebugPrimitives/DbgPrimGeometryData.cs b/src/StudioCore/Renderer/DebugPrimitives/DbgPrimGeometryData.cs similarity index 66% rename from src/StudioCore/DebugPrimitives/DbgPrimGeometryData.cs rename to src/StudioCore/Renderer/DebugPrimitives/DbgPrimGeometryData.cs index 5cfacb201..263182e26 100644 --- a/src/StudioCore/DebugPrimitives/DbgPrimGeometryData.cs +++ b/src/StudioCore/Renderer/DebugPrimitives/DbgPrimGeometryData.cs @@ -1,8 +1,8 @@ //using Microsoft.Xna.Framework.Graphics; -using StudioCore.Scene; +using StudioCore.Renderer.Scene; -namespace StudioCore.DebugPrimitives; +namespace StudioCore.Renderer.DebugPrimitives; public class DbgPrimGeometryData { diff --git a/src/StudioCore/DebugPrimitives/DbgPrimGizmo.cs b/src/StudioCore/Renderer/DebugPrimitives/DbgPrimGizmo.cs similarity index 96% rename from src/StudioCore/DebugPrimitives/DbgPrimGizmo.cs rename to src/StudioCore/Renderer/DebugPrimitives/DbgPrimGizmo.cs index 1df052fa3..00c21c6b3 100644 --- a/src/StudioCore/DebugPrimitives/DbgPrimGizmo.cs +++ b/src/StudioCore/Renderer/DebugPrimitives/DbgPrimGizmo.cs @@ -1,4 +1,4 @@ -using StudioCore.Resource; +using StudioCore.Renderer.Resource; using System; using System.Drawing; using System.Numerics; @@ -6,7 +6,7 @@ using Veldrid.Utilities; using Vortice.Vulkan; -namespace StudioCore.DebugPrimitives; +namespace StudioCore.Renderer.DebugPrimitives; public class DbgPrimGizmo : DbgPrim { diff --git a/src/StudioCore/DebugPrimitives/DbgPrimGizmoRotateRing.cs b/src/StudioCore/Renderer/DebugPrimitives/DbgPrimGizmoRotateRing.cs similarity index 97% rename from src/StudioCore/DebugPrimitives/DbgPrimGizmoRotateRing.cs rename to src/StudioCore/Renderer/DebugPrimitives/DbgPrimGizmoRotateRing.cs index 5ee2cd35d..24b710872 100644 --- a/src/StudioCore/DebugPrimitives/DbgPrimGizmoRotateRing.cs +++ b/src/StudioCore/Renderer/DebugPrimitives/DbgPrimGizmoRotateRing.cs @@ -1,5 +1,5 @@ using StudioCore.MsbEditor; -using StudioCore.Scene; +using StudioCore.Renderer.Scene; using System; using System.Collections.Generic; using System.Drawing; @@ -7,7 +7,7 @@ using System.Numerics; using Veldrid.Utilities; -namespace StudioCore.DebugPrimitives; +namespace StudioCore.Renderer.DebugPrimitives; public class DbgPrimGizmoRotateRing : DbgPrimGizmo { @@ -134,7 +134,7 @@ void Ring(Gizmos.Axis axis, Color color) GeometryData = new DbgPrimGeometryData { GeomBuffer = GeometryBuffer }; } - Renderer.AddBackgroundUploadTask((d, cl) => + Renderer.Scene.Renderer.AddBackgroundUploadTask((d, cl) => { UpdatePerFrameResources(d, cl, null); }); diff --git a/src/StudioCore/DebugPrimitives/DbgPrimGizmoTranslateArrow.cs b/src/StudioCore/Renderer/DebugPrimitives/DbgPrimGizmoTranslateArrow.cs similarity index 97% rename from src/StudioCore/DebugPrimitives/DbgPrimGizmoTranslateArrow.cs rename to src/StudioCore/Renderer/DebugPrimitives/DbgPrimGizmoTranslateArrow.cs index ac7042ddc..a0f079fa8 100644 --- a/src/StudioCore/DebugPrimitives/DbgPrimGizmoTranslateArrow.cs +++ b/src/StudioCore/Renderer/DebugPrimitives/DbgPrimGizmoTranslateArrow.cs @@ -1,5 +1,5 @@ using StudioCore.MsbEditor; -using StudioCore.Scene; +using StudioCore.Renderer.Scene; using System; using System.Collections.Generic; using System.Drawing; @@ -7,7 +7,7 @@ using System.Numerics; using Veldrid.Utilities; -namespace StudioCore.DebugPrimitives; +namespace StudioCore.Renderer.DebugPrimitives; public class DbgPrimGizmoTranslateArrow : DbgPrimGizmo { @@ -137,7 +137,7 @@ void Arrow(Gizmos.Axis axis, Color color) GeometryData = new DbgPrimGeometryData { GeomBuffer = GeometryBuffer }; - Renderer.AddBackgroundUploadTask((d, cl) => + Renderer.Scene.Renderer.AddBackgroundUploadTask((d, cl) => { UpdatePerFrameResources(d, cl, null); }); diff --git a/src/StudioCore/DebugPrimitives/DbgPrimGizmoTranslateSquare.cs b/src/StudioCore/Renderer/DebugPrimitives/DbgPrimGizmoTranslateSquare.cs similarity index 95% rename from src/StudioCore/DebugPrimitives/DbgPrimGizmoTranslateSquare.cs rename to src/StudioCore/Renderer/DebugPrimitives/DbgPrimGizmoTranslateSquare.cs index d2c4ef01b..efd41d757 100644 --- a/src/StudioCore/DebugPrimitives/DbgPrimGizmoTranslateSquare.cs +++ b/src/StudioCore/Renderer/DebugPrimitives/DbgPrimGizmoTranslateSquare.cs @@ -1,5 +1,5 @@ using StudioCore.MsbEditor; -using StudioCore.Scene; +using StudioCore.Renderer.Scene; using System; using System.Collections.Generic; using System.Drawing; @@ -7,7 +7,7 @@ using System.Numerics; using Veldrid.Utilities; -namespace StudioCore.DebugPrimitives; +namespace StudioCore.Renderer.DebugPrimitives; public class DbgPrimGizmoTranslateSquare : DbgPrimGizmo { @@ -65,7 +65,7 @@ public DbgPrimGizmoTranslateSquare(Gizmos.Axis axis) GeometryData = new DbgPrimGeometryData { GeomBuffer = GeometryBuffer }; - Renderer.AddBackgroundUploadTask((d, cl) => + Renderer.Scene.Renderer.AddBackgroundUploadTask((d, cl) => { UpdatePerFrameResources(d, cl, null); }); diff --git a/src/StudioCore/DebugPrimitives/DbgPrimSkybox.cs b/src/StudioCore/Renderer/DebugPrimitives/DbgPrimSkybox.cs similarity index 94% rename from src/StudioCore/DebugPrimitives/DbgPrimSkybox.cs rename to src/StudioCore/Renderer/DebugPrimitives/DbgPrimSkybox.cs index a7ae09fe3..2d93c2007 100644 --- a/src/StudioCore/DebugPrimitives/DbgPrimSkybox.cs +++ b/src/StudioCore/Renderer/DebugPrimitives/DbgPrimSkybox.cs @@ -1,5 +1,5 @@ -using StudioCore.Resource; -using StudioCore.Scene; +using StudioCore.Renderer.Resource; +using StudioCore.Renderer.Scene; using System; using System.Drawing; using System.Numerics; @@ -7,7 +7,7 @@ using Veldrid.Utilities; using Vortice.Vulkan; -namespace StudioCore.DebugPrimitives; +namespace StudioCore.Renderer.DebugPrimitives; public class DbgPrimSkybox : DbgPrim { @@ -121,7 +121,7 @@ protected override void DisposeBuffers() //IndexBuffer?.Dispose(); } - public void Render(Renderer.IndirectDrawEncoder encoder, SceneRenderPipeline sp) + public void Render(Renderer.Scene.Renderer.IndirectDrawEncoder encoder, SceneRenderPipeline sp) { throw new NotImplementedException(); } diff --git a/src/StudioCore/DebugPrimitives/DbgPrimSolid.cs b/src/StudioCore/Renderer/DebugPrimitives/DbgPrimSolid.cs similarity index 96% rename from src/StudioCore/DebugPrimitives/DbgPrimSolid.cs rename to src/StudioCore/Renderer/DebugPrimitives/DbgPrimSolid.cs index 6943f623c..ae9df71ad 100644 --- a/src/StudioCore/DebugPrimitives/DbgPrimSolid.cs +++ b/src/StudioCore/Renderer/DebugPrimitives/DbgPrimSolid.cs @@ -1,4 +1,4 @@ -using StudioCore.Resource; +using StudioCore.Renderer.Resource; using System; using System.Drawing; using System.Numerics; @@ -6,7 +6,7 @@ using Veldrid.Utilities; using Vortice.Vulkan; -namespace StudioCore.DebugPrimitives; +namespace StudioCore.Renderer.DebugPrimitives; public class DbgPrimSolid : DbgPrim { diff --git a/src/StudioCore/DebugPrimitives/DbgPrimSolidArrow.cs b/src/StudioCore/Renderer/DebugPrimitives/DbgPrimSolidArrow.cs similarity index 98% rename from src/StudioCore/DebugPrimitives/DbgPrimSolidArrow.cs rename to src/StudioCore/Renderer/DebugPrimitives/DbgPrimSolidArrow.cs index 240356f51..4c576f46f 100644 --- a/src/StudioCore/DebugPrimitives/DbgPrimSolidArrow.cs +++ b/src/StudioCore/Renderer/DebugPrimitives/DbgPrimSolidArrow.cs @@ -2,7 +2,7 @@ using System.Drawing; using System.Numerics; -namespace StudioCore.DebugPrimitives; +namespace StudioCore.Renderer.DebugPrimitives; public class DbgPrimSolidArrow : DbgPrimSolid { diff --git a/src/StudioCore/DebugPrimitives/DbgPrimSolidBone.cs b/src/StudioCore/Renderer/DebugPrimitives/DbgPrimSolidBone.cs similarity index 94% rename from src/StudioCore/DebugPrimitives/DbgPrimSolidBone.cs rename to src/StudioCore/Renderer/DebugPrimitives/DbgPrimSolidBone.cs index eecd05b3d..9b8a007f9 100644 --- a/src/StudioCore/DebugPrimitives/DbgPrimSolidBone.cs +++ b/src/StudioCore/Renderer/DebugPrimitives/DbgPrimSolidBone.cs @@ -1,8 +1,9 @@ -using System; +using StudioCore.Utilities; +using System; using System.Drawing; using System.Numerics; -namespace StudioCore.DebugPrimitives; +namespace StudioCore.Renderer.DebugPrimitives; public class DbgPrimSolidBone : DbgPrimSolid { diff --git a/src/StudioCore/DebugPrimitives/DbgPrimSolidBox.cs b/src/StudioCore/Renderer/DebugPrimitives/DbgPrimSolidBox.cs similarity index 96% rename from src/StudioCore/DebugPrimitives/DbgPrimSolidBox.cs rename to src/StudioCore/Renderer/DebugPrimitives/DbgPrimSolidBox.cs index 57566e692..4b7afbd71 100644 --- a/src/StudioCore/DebugPrimitives/DbgPrimSolidBox.cs +++ b/src/StudioCore/Renderer/DebugPrimitives/DbgPrimSolidBox.cs @@ -1,7 +1,8 @@ -using System.Drawing; +using StudioCore.Utilities; +using System.Drawing; using System.Numerics; -namespace StudioCore.DebugPrimitives; +namespace StudioCore.Renderer.DebugPrimitives; public class DbgPrimSolidBox : DbgPrimSolid { diff --git a/src/StudioCore/DebugPrimitives/DbgPrimWire.cs b/src/StudioCore/Renderer/DebugPrimitives/DbgPrimWire.cs similarity index 96% rename from src/StudioCore/DebugPrimitives/DbgPrimWire.cs rename to src/StudioCore/Renderer/DebugPrimitives/DbgPrimWire.cs index b89956aa0..560e107e2 100644 --- a/src/StudioCore/DebugPrimitives/DbgPrimWire.cs +++ b/src/StudioCore/Renderer/DebugPrimitives/DbgPrimWire.cs @@ -1,11 +1,11 @@ -using StudioCore.Resource; +using StudioCore.Renderer.Resource; using System.Drawing; using System.Numerics; using Veldrid; using Veldrid.Utilities; using Vortice.Vulkan; -namespace StudioCore.DebugPrimitives; +namespace StudioCore.Renderer.DebugPrimitives; public class DbgPrimWire : DbgPrim { diff --git a/src/StudioCore/DebugPrimitives/DbgPrimWireArrow.cs b/src/StudioCore/Renderer/DebugPrimitives/DbgPrimWireArrow.cs similarity index 93% rename from src/StudioCore/DebugPrimitives/DbgPrimWireArrow.cs rename to src/StudioCore/Renderer/DebugPrimitives/DbgPrimWireArrow.cs index 79f32f8aa..cb3d69da9 100644 --- a/src/StudioCore/DebugPrimitives/DbgPrimWireArrow.cs +++ b/src/StudioCore/Renderer/DebugPrimitives/DbgPrimWireArrow.cs @@ -1,9 +1,10 @@ -using StudioCore.Scene; +using StudioCore.Renderer.Scene; +using StudioCore.Utilities; using System; using System.Drawing; using System.Numerics; -namespace StudioCore.DebugPrimitives; +namespace StudioCore.Renderer.DebugPrimitives; public class DbgPrimWireArrow : DbgPrimWire { @@ -69,7 +70,7 @@ Vector3 GetPoint(int segmentIndex, float radius, float depth) //FinalizeBuffers(true); GeometryData = new DbgPrimGeometryData { GeomBuffer = GeometryBuffer }; - Renderer.AddBackgroundUploadTask((d, cl) => + Renderer.Scene.Renderer.AddBackgroundUploadTask((d, cl) => { UpdatePerFrameResources(d, cl, null); }); diff --git a/src/StudioCore/DebugPrimitives/DbgPrimWireBone.cs b/src/StudioCore/Renderer/DebugPrimitives/DbgPrimWireBone.cs similarity index 94% rename from src/StudioCore/DebugPrimitives/DbgPrimWireBone.cs rename to src/StudioCore/Renderer/DebugPrimitives/DbgPrimWireBone.cs index 80464c4da..290a70dbd 100644 --- a/src/StudioCore/DebugPrimitives/DbgPrimWireBone.cs +++ b/src/StudioCore/Renderer/DebugPrimitives/DbgPrimWireBone.cs @@ -1,7 +1,8 @@ -using System.Drawing; +using StudioCore.Utilities; +using System.Drawing; using System.Numerics; -namespace StudioCore.DebugPrimitives; +namespace StudioCore.Renderer.DebugPrimitives; public class DbgPrimWireBone : DbgPrimWire { diff --git a/src/StudioCore/DebugPrimitives/DbgPrimWireBox.cs b/src/StudioCore/Renderer/DebugPrimitives/DbgPrimWireBox.cs similarity index 96% rename from src/StudioCore/DebugPrimitives/DbgPrimWireBox.cs rename to src/StudioCore/Renderer/DebugPrimitives/DbgPrimWireBox.cs index e3592dcde..a0993481d 100644 --- a/src/StudioCore/DebugPrimitives/DbgPrimWireBox.cs +++ b/src/StudioCore/Renderer/DebugPrimitives/DbgPrimWireBox.cs @@ -1,10 +1,11 @@ -using StudioCore.Scene; +using StudioCore.Renderer.Scene; +using StudioCore.Utilities; using System.Collections.Generic; using System.Drawing; using System.Numerics; using Veldrid.Utilities; -namespace StudioCore.DebugPrimitives; +namespace StudioCore.Renderer.DebugPrimitives; public class DbgPrimWireBox : DbgPrimWire { @@ -103,7 +104,7 @@ public DbgPrimWireBox(Transform location, Vector3 localMin, Vector3 localMax, Co GeometryData = new DbgPrimGeometryData { GeomBuffer = GeometryBuffer }; - Renderer.AddBackgroundUploadTask((d, cl) => + Renderer.Scene.Renderer.AddBackgroundUploadTask((d, cl) => { UpdatePerFrameResources(d, cl, null); }); diff --git a/src/StudioCore/DebugPrimitives/DbgPrimWireCapsule.cs b/src/StudioCore/Renderer/DebugPrimitives/DbgPrimWireCapsule.cs similarity index 99% rename from src/StudioCore/DebugPrimitives/DbgPrimWireCapsule.cs rename to src/StudioCore/Renderer/DebugPrimitives/DbgPrimWireCapsule.cs index cea480b99..02ecdca1d 100644 --- a/src/StudioCore/DebugPrimitives/DbgPrimWireCapsule.cs +++ b/src/StudioCore/Renderer/DebugPrimitives/DbgPrimWireCapsule.cs @@ -2,7 +2,7 @@ using System.Drawing; using System.Numerics; -namespace StudioCore.DebugPrimitives; +namespace StudioCore.Renderer.DebugPrimitives; public class DbgPrimWireCapsule : DbgPrimWire { diff --git a/src/StudioCore/DebugPrimitives/DbgPrimWireChain.cs b/src/StudioCore/Renderer/DebugPrimitives/DbgPrimWireChain.cs similarity index 92% rename from src/StudioCore/DebugPrimitives/DbgPrimWireChain.cs rename to src/StudioCore/Renderer/DebugPrimitives/DbgPrimWireChain.cs index b62a06457..81bb067ac 100644 --- a/src/StudioCore/DebugPrimitives/DbgPrimWireChain.cs +++ b/src/StudioCore/Renderer/DebugPrimitives/DbgPrimWireChain.cs @@ -4,10 +4,11 @@ using System.Linq; using System.Numerics; using System.Threading; -using StudioCore.Scene; +using StudioCore.Renderer.Scene; +using StudioCore.Utilities; using Veldrid.Utilities; -namespace StudioCore.DebugPrimitives; +namespace StudioCore.Renderer.DebugPrimitives; public class DbgPrimWireChain : DbgPrimWire { @@ -67,7 +68,7 @@ public DbgPrimWireChain(List points, List looseStartingPoints, GeometryData = new DbgPrimGeometryData { GeomBuffer = GeometryBuffer }; - Renderer.AddBackgroundUploadTask((d, cl) => + Renderer.Scene.Renderer.AddBackgroundUploadTask((d, cl) => { UpdatePerFrameResources(d, cl, null); }); diff --git a/src/StudioCore/DebugPrimitives/DbgPrimWireCylinder.cs b/src/StudioCore/Renderer/DebugPrimitives/DbgPrimWireCylinder.cs similarity index 92% rename from src/StudioCore/DebugPrimitives/DbgPrimWireCylinder.cs rename to src/StudioCore/Renderer/DebugPrimitives/DbgPrimWireCylinder.cs index 98e7c5eaf..42328232a 100644 --- a/src/StudioCore/DebugPrimitives/DbgPrimWireCylinder.cs +++ b/src/StudioCore/Renderer/DebugPrimitives/DbgPrimWireCylinder.cs @@ -1,10 +1,11 @@ -using StudioCore.Scene; +using StudioCore.Renderer.Scene; +using StudioCore.Utilities; using System; using System.Drawing; using System.Numerics; using Veldrid.Utilities; -namespace StudioCore.DebugPrimitives; +namespace StudioCore.Renderer.DebugPrimitives; public class DbgPrimWireCylinder : DbgPrimWire { @@ -48,7 +49,7 @@ public DbgPrimWireCylinder(Transform location, float range, float height, int nu AddLine(new Vector3(x, bottom, z), new Vector3(x, top, z), color); } - Renderer.AddBackgroundUploadTask((d, cl) => + Renderer.Scene.Renderer.AddBackgroundUploadTask((d, cl) => { UpdatePerFrameResources(d, cl, null); }); diff --git a/src/StudioCore/DebugPrimitives/DbgPrimWireGrid.cs b/src/StudioCore/Renderer/DebugPrimitives/DbgPrimWireGrid.cs similarity index 87% rename from src/StudioCore/DebugPrimitives/DbgPrimWireGrid.cs rename to src/StudioCore/Renderer/DebugPrimitives/DbgPrimWireGrid.cs index 2e6943a06..e2d5921e2 100644 --- a/src/StudioCore/DebugPrimitives/DbgPrimWireGrid.cs +++ b/src/StudioCore/Renderer/DebugPrimitives/DbgPrimWireGrid.cs @@ -1,10 +1,10 @@ -using StudioCore.Scene; +using StudioCore.Renderer.Scene; using System; using System.Collections.Generic; using System.Drawing; using System.Numerics; -namespace StudioCore.DebugPrimitives; +namespace StudioCore.Renderer.DebugPrimitives; public class DbgPrimWireGrid : DbgPrimWire { @@ -33,7 +33,7 @@ public DbgPrimWireGrid(Color originColor, Color color, int unitRange, float unit GeometryData = new DbgPrimGeometryData { GeomBuffer = GeometryBuffer }; - Renderer.AddBackgroundUploadTask((d, cl) => + Renderer.Scene.Renderer.AddBackgroundUploadTask((d, cl) => { UpdatePerFrameResources(d, cl, null); }); diff --git a/src/StudioCore/DebugPrimitives/DbgPrimWireRay.cs b/src/StudioCore/Renderer/DebugPrimitives/DbgPrimWireRay.cs similarity index 88% rename from src/StudioCore/DebugPrimitives/DbgPrimWireRay.cs rename to src/StudioCore/Renderer/DebugPrimitives/DbgPrimWireRay.cs index 4493ad78d..4776bed2f 100644 --- a/src/StudioCore/DebugPrimitives/DbgPrimWireRay.cs +++ b/src/StudioCore/Renderer/DebugPrimitives/DbgPrimWireRay.cs @@ -1,7 +1,8 @@ -using System.Drawing; +using StudioCore.Utilities; +using System.Drawing; using System.Numerics; -namespace StudioCore.DebugPrimitives; +namespace StudioCore.Renderer.DebugPrimitives; public class DbgPrimWireRay : DbgPrimWire { diff --git a/src/StudioCore/DebugPrimitives/DbgPrimWireSphere.cs b/src/StudioCore/Renderer/DebugPrimitives/DbgPrimWireSphere.cs similarity index 95% rename from src/StudioCore/DebugPrimitives/DbgPrimWireSphere.cs rename to src/StudioCore/Renderer/DebugPrimitives/DbgPrimWireSphere.cs index de107629c..fc2af1592 100644 --- a/src/StudioCore/DebugPrimitives/DbgPrimWireSphere.cs +++ b/src/StudioCore/Renderer/DebugPrimitives/DbgPrimWireSphere.cs @@ -1,10 +1,11 @@ -using StudioCore.Scene; +using StudioCore.Renderer.Scene; +using StudioCore.Utilities; using System; using System.Drawing; using System.Numerics; using Veldrid.Utilities; -namespace StudioCore.DebugPrimitives; +namespace StudioCore.Renderer.DebugPrimitives; public class DbgPrimWireSphere : DbgPrimWire { @@ -81,7 +82,7 @@ public DbgPrimWireSphere(Transform location, float radius, Color color, int numV } } - Renderer.AddBackgroundUploadTask((d, cl) => + Renderer.Scene.Renderer.AddBackgroundUploadTask((d, cl) => { UpdatePerFrameResources(d, cl, null); }); diff --git a/src/StudioCore/DebugPrimitives/DbgPrimWireSpheroidWithArrow.cs b/src/StudioCore/Renderer/DebugPrimitives/DbgPrimWireSpheroidWithArrow.cs similarity index 96% rename from src/StudioCore/DebugPrimitives/DbgPrimWireSpheroidWithArrow.cs rename to src/StudioCore/Renderer/DebugPrimitives/DbgPrimWireSpheroidWithArrow.cs index 9f5a756a0..cbfe194f3 100644 --- a/src/StudioCore/DebugPrimitives/DbgPrimWireSpheroidWithArrow.cs +++ b/src/StudioCore/Renderer/DebugPrimitives/DbgPrimWireSpheroidWithArrow.cs @@ -1,10 +1,11 @@ -using StudioCore.Scene; +using StudioCore.Renderer.Scene; +using StudioCore.Utilities; using System; using System.Drawing; using System.Numerics; using Veldrid.Utilities; -namespace StudioCore.DebugPrimitives; +namespace StudioCore.Renderer.DebugPrimitives; public class DbgPrimWireSpheroidWithArrow : DbgPrimWire { @@ -149,7 +150,7 @@ Vector3 GetPoint(int segmentIndex, float radius, float depth) { GeomBuffer = GeometryBuffer };*/ - Renderer.AddBackgroundUploadTask((d, cl) => + Renderer.Scene.Renderer.AddBackgroundUploadTask((d, cl) => { UpdatePerFrameResources(d, cl, null); }); diff --git a/src/StudioCore/DebugPrimitives/DbgPrimWireSpotLight.cs b/src/StudioCore/Renderer/DebugPrimitives/DbgPrimWireSpotLight.cs similarity index 96% rename from src/StudioCore/DebugPrimitives/DbgPrimWireSpotLight.cs rename to src/StudioCore/Renderer/DebugPrimitives/DbgPrimWireSpotLight.cs index 2d9192694..00a9ebced 100644 --- a/src/StudioCore/DebugPrimitives/DbgPrimWireSpotLight.cs +++ b/src/StudioCore/Renderer/DebugPrimitives/DbgPrimWireSpotLight.cs @@ -1,10 +1,11 @@ -using StudioCore.Scene; +using StudioCore.Renderer.Scene; +using StudioCore.Utilities; using System; using System.Drawing; using System.Numerics; using Veldrid.Utilities; -namespace StudioCore.DebugPrimitives; +namespace StudioCore.Renderer.DebugPrimitives; public class DbgPrimWireSpotLight : DbgPrimWire { @@ -135,7 +136,7 @@ public DbgPrimWireSpotLight(Transform location, float radius, float angle, Color { GeomBuffer = GeometryBuffer };*/ - Renderer.AddBackgroundUploadTask((d, cl) => + Renderer.Scene.Renderer.AddBackgroundUploadTask((d, cl) => { UpdatePerFrameResources(d, cl, null); }); diff --git a/src/StudioCore/DebugPrimitives/DbgPrimWireWallBox.cs b/src/StudioCore/Renderer/DebugPrimitives/DbgPrimWireWallBox.cs similarity index 96% rename from src/StudioCore/DebugPrimitives/DbgPrimWireWallBox.cs rename to src/StudioCore/Renderer/DebugPrimitives/DbgPrimWireWallBox.cs index eaec32fb5..0dd5cbbea 100644 --- a/src/StudioCore/DebugPrimitives/DbgPrimWireWallBox.cs +++ b/src/StudioCore/Renderer/DebugPrimitives/DbgPrimWireWallBox.cs @@ -1,10 +1,11 @@ -using StudioCore.Scene; +using StudioCore.Renderer.Scene; +using StudioCore.Utilities; using System.Collections.Generic; using System.Drawing; using System.Numerics; using Veldrid.Utilities; -namespace StudioCore.DebugPrimitives; +namespace StudioCore.Renderer.DebugPrimitives; public class DbgPrimWireWallBox : DbgPrimWire { @@ -103,7 +104,7 @@ public DbgPrimWireWallBox(Transform location, Vector3 localMin, Vector3 localMax GeometryData = new DbgPrimGeometryData { GeomBuffer = GeometryBuffer }; - Renderer.AddBackgroundUploadTask((d, cl) => + Renderer.Scene.Renderer.AddBackgroundUploadTask((d, cl) => { UpdatePerFrameResources(d, cl, null); }); diff --git a/src/StudioCore/DebugPrimitives/IDbgPrim.cs b/src/StudioCore/Renderer/DebugPrimitives/IDbgPrim.cs similarity index 90% rename from src/StudioCore/DebugPrimitives/IDbgPrim.cs rename to src/StudioCore/Renderer/DebugPrimitives/IDbgPrim.cs index bd02f7193..08fbf7a6b 100644 --- a/src/StudioCore/DebugPrimitives/IDbgPrim.cs +++ b/src/StudioCore/Renderer/DebugPrimitives/IDbgPrim.cs @@ -1,12 +1,12 @@ -using StudioCore.Resource; -using StudioCore.Scene; +using StudioCore.Renderer.Resource; +using StudioCore.Renderer.Scene; using System; using System.Drawing; using Veldrid; using Veldrid.Utilities; using Vortice.Vulkan; -namespace StudioCore.DebugPrimitives; +namespace StudioCore.Renderer.DebugPrimitives; public interface IDbgPrim : IDisposable { diff --git a/src/StudioCore/Renderer/DebugPrimitives/VertexPositionColorNormal.cs b/src/StudioCore/Renderer/DebugPrimitives/VertexPositionColorNormal.cs new file mode 100644 index 000000000..ad4f28bbb --- /dev/null +++ b/src/StudioCore/Renderer/DebugPrimitives/VertexPositionColorNormal.cs @@ -0,0 +1,2 @@ +namespace StudioCore.Renderer.DebugPrimitives; + diff --git a/src/StudioCore/Gui/GuiView.cs b/src/StudioCore/Renderer/Gui/GuiView.cs similarity index 90% rename from src/StudioCore/Gui/GuiView.cs rename to src/StudioCore/Renderer/Gui/GuiView.cs index 9ccdc860b..5f30aafc9 100644 --- a/src/StudioCore/Gui/GuiView.cs +++ b/src/StudioCore/Renderer/Gui/GuiView.cs @@ -1,6 +1,6 @@ using System.Drawing; -namespace StudioCore.Gui; +namespace StudioCore.Renderer.Gui; /// /// A self contained view that contains a self contained functional GUI diff --git a/src/StudioCore/Gui/IViewport.cs b/src/StudioCore/Renderer/Gui/IViewport.cs similarity index 95% rename from src/StudioCore/Gui/IViewport.cs rename to src/StudioCore/Renderer/Gui/IViewport.cs index 17a649656..be30cdc6c 100644 --- a/src/StudioCore/Gui/IViewport.cs +++ b/src/StudioCore/Renderer/Gui/IViewport.cs @@ -3,7 +3,7 @@ using Veldrid.Sdl2; using Veldrid.Utilities; -namespace StudioCore.Gui; +namespace StudioCore.Renderer.Gui; public interface IViewport { diff --git a/src/StudioCore/Gui/NullViewport.cs b/src/StudioCore/Renderer/Gui/NullViewport.cs similarity index 97% rename from src/StudioCore/Gui/NullViewport.cs rename to src/StudioCore/Renderer/Gui/NullViewport.cs index 230c003cf..6c3ba6980 100644 --- a/src/StudioCore/Gui/NullViewport.cs +++ b/src/StudioCore/Renderer/Gui/NullViewport.cs @@ -1,11 +1,12 @@ using static Andre.Native.ImGuiBindings; +using StudioCore.Editor; using StudioCore.MsbEditor; using System.Numerics; using Veldrid; using Veldrid.Sdl2; using Veldrid.Utilities; -namespace StudioCore.Gui; +namespace StudioCore.Renderer.Gui; /// /// A null viewport that doesn't actually do anything diff --git a/src/StudioCore/Gui/Viewport.cs b/src/StudioCore/Renderer/Gui/Viewport.cs similarity index 96% rename from src/StudioCore/Gui/Viewport.cs rename to src/StudioCore/Renderer/Gui/Viewport.cs index cc0e5ccce..b75c82bb9 100644 --- a/src/StudioCore/Gui/Viewport.cs +++ b/src/StudioCore/Renderer/Gui/Viewport.cs @@ -1,8 +1,10 @@ using static Andre.Native.ImGuiBindings; -using StudioCore.DebugPrimitives; +using StudioCore.Renderer.DebugPrimitives; +using StudioCore.Editor; using StudioCore.MsbEditor; -using StudioCore.Resource; -using StudioCore.Scene; +using StudioCore.Renderer.Resource; +using StudioCore.Renderer.Scene; +using StudioCore.Utilities; using System; using System.Drawing; using System.Numerics; @@ -11,7 +13,7 @@ using Veldrid.Utilities; using Rectangle = Veldrid.Rectangle; -namespace StudioCore.Gui; +namespace StudioCore.Renderer.Gui; /// /// A viewport is a virtual (i.e. render to texture/render target) view of a scene. It can receive input events to @@ -109,7 +111,7 @@ public Viewport(string id, GraphicsDevice device, RenderScene scene, ActionManag _gizmos = new Gizmos(_actionManager, _selection, _renderScene.OverlayRenderables); _clearQuad = new FullScreenQuad(); - Renderer.AddBackgroundUploadTask((gd, cl) => + Renderer.Scene.Renderer.AddBackgroundUploadTask((gd, cl) => { _clearQuad.CreateDeviceObjects(gd, cl); }); @@ -187,9 +189,9 @@ public void OnGui() ImGui.Text($@"Scene Render CPU time: {_viewPipeline.CPURenderTime} ms"); ImGui.Text($@"Visible objects: {_renderScene.RenderObjectCount}"); ImGui.Text( - $@"Vertex Buffers Size: {Renderer.GeometryBufferAllocator.TotalVertexFootprint / 1024 / 1024} MB"); + $@"Vertex Buffers Size: {Renderer.Scene.Renderer.GeometryBufferAllocator.TotalVertexFootprint / 1024 / 1024} MB"); ImGui.Text( - $@"Index Buffers Size: {Renderer.GeometryBufferAllocator.TotalIndexFootprint / 1024 / 1024} MB"); + $@"Index Buffers Size: {Renderer.Scene.Renderer.GeometryBufferAllocator.TotalIndexFootprint / 1024 / 1024} MB"); ImGui.Text($@"FLVER Read Caches: {FlverResource.CacheCount}"); ImGui.Text($@"FLVER Read Caches Size: {FlverResource.CacheFootprint / 1024 / 1024} MB"); //ImGui.Text($@"Selected renderable: { _viewPipeline._pickingEntity }"); diff --git a/src/StudioCore/Resource/FlverResource.cs b/src/StudioCore/Renderer/Resource/FlverResource.cs similarity index 98% rename from src/StudioCore/Resource/FlverResource.cs rename to src/StudioCore/Renderer/Resource/FlverResource.cs index 23994d8b9..351012b84 100644 --- a/src/StudioCore/Resource/FlverResource.cs +++ b/src/StudioCore/Renderer/Resource/FlverResource.cs @@ -2,7 +2,7 @@ using DotNext.IO.MemoryMappedFiles; using SoulsFormats; using StudioCore.MsbEditor; -using StudioCore.Scene; +using StudioCore.Renderer.Scene; using System; using System.Collections.Generic; using System.IO; @@ -15,7 +15,7 @@ using Veldrid.Utilities; using static SoulsFormats.FLVER; -namespace StudioCore.Resource; +namespace StudioCore.Renderer.Resource; public class FlverResource : IResource, IDisposable { @@ -342,7 +342,7 @@ private void ProcessMaterialTexture(FlverMaterial dest, string texType, string m private unsafe void ProcessMaterial(IFlverMaterial mat, FlverMaterial dest, GameType type) { dest.MaterialName = Path.GetFileNameWithoutExtension(mat.MTD); - dest.MaterialBuffer = Renderer.MaterialBufferAllocator.Allocate((uint)sizeof(Material), sizeof(Material)); + dest.MaterialBuffer = Renderer.Scene.Renderer.MaterialBufferAllocator.Allocate((uint)sizeof(Material), sizeof(Material)); dest.MaterialData = new Material(); //FLVER0 stores layouts directly in the material @@ -442,7 +442,7 @@ private unsafe void ProcessMaterial(FlverMaterial dest, GameType type, BinaryRea { var mtd = isUTF ? br.GetUTF16(mat.mtdOffset) : br.GetShiftJIS(mat.mtdOffset); dest.MaterialName = Path.GetFileNameWithoutExtension(mtd); - dest.MaterialBuffer = Renderer.MaterialBufferAllocator.Allocate((uint)sizeof(Material), sizeof(Material)); + dest.MaterialBuffer = Renderer.Scene.Renderer.MaterialBufferAllocator.Allocate((uint)sizeof(Material), sizeof(Material)); dest.MaterialData = new Material(); if (!CFG.Current.EnableTexturing) @@ -1241,7 +1241,7 @@ private unsafe void FillVerticesUV2(FLVER0.Mesh mesh, Span pickingVerts private unsafe void ProcessMesh(FLVER0.Mesh mesh, FlverSubmesh dest) { - ResourceFactory? factory = Renderer.Factory; + ResourceFactory? factory = Renderer.Scene.Renderer.Factory; dest.Material = GPUMaterials[mesh.MaterialIndex]; @@ -1279,7 +1279,7 @@ private unsafe void ProcessMesh(FLVER0.Mesh mesh, FlverSubmesh dest) var indices = mesh.Triangulate(FlverDeS.Header.Version).ToArray(); var indicesTotal = indices.Length; - dest.GeomBuffer = Renderer.GeometryBufferAllocator.Allocate(vbuffersize, + dest.GeomBuffer = Renderer.Scene.Renderer.GeometryBufferAllocator.Allocate(vbuffersize, (uint)indicesTotal * (is32bit ? 4u : 2u), (int)vSize, 4); var meshVertices = dest.GeomBuffer.MapVBuffer(); var meshIndices = dest.GeomBuffer.MapIBuffer(); @@ -1392,7 +1392,7 @@ private unsafe void ProcessMesh(FLVER2.Mesh mesh, FlverSubmesh dest) } var vbuffersize = (uint)mesh.VertexCount * vSize; - dest.GeomBuffer = Renderer.GeometryBufferAllocator.Allocate(vbuffersize, + dest.GeomBuffer = Renderer.Scene.Renderer.GeometryBufferAllocator.Allocate(vbuffersize, (uint)indicesTotal * (is32bit ? 4u : 2u), (int)vSize, 4); var meshVertices = dest.GeomBuffer.MapVBuffer(); var meshIndices = dest.GeomBuffer.MapIBuffer(); @@ -1583,7 +1583,7 @@ private unsafe void ProcessMesh(ref FlverMesh mesh, BinaryReaderEx br, int versi } var vbuffersize = (uint)vertexCount * vSize; - dest.GeomBuffer = Renderer.GeometryBufferAllocator.Allocate(vbuffersize, + dest.GeomBuffer = Renderer.Scene.Renderer.GeometryBufferAllocator.Allocate(vbuffersize, (uint)indicesTotal * (is32bit ? 4u : 2u), (int)vSize, 4); var meshVertices = dest.GeomBuffer.MapVBuffer(); var meshIndices = dest.GeomBuffer.MapIBuffer(); @@ -1819,14 +1819,14 @@ private bool LoadInternal(AccessLevel al, GameType type) if (GPUMeshes.Any(e => e.UseNormalWBoneTransform)) { - StaticBoneBuffer = Renderer.BoneBufferAllocator.Allocate(64 * (uint)Bones.Count, 64); + StaticBoneBuffer = Renderer.Scene.Renderer.BoneBufferAllocator.Allocate(64 * (uint)Bones.Count, 64); var tbones = new Matrix4x4[Bones.Count]; for (var i = 0; i < Bones.Count; i++) { tbones[i] = Utils.GetBoneObjectMatrix(Bones[i], Bones); } - Renderer.AddBackgroundUploadTask((d, cl) => + Renderer.Scene.Renderer.AddBackgroundUploadTask((d, cl) => { StaticBoneBuffer.FillBuffer(cl, tbones); }); @@ -1966,14 +1966,14 @@ private bool LoadInternalFast(BinaryReaderEx br, GameType type) if (GPUMeshes.Any(e => e.UseNormalWBoneTransform)) { - StaticBoneBuffer = Renderer.BoneBufferAllocator.Allocate(64 * (uint)FBones.Count, 64); + StaticBoneBuffer = Renderer.Scene.Renderer.BoneBufferAllocator.Allocate(64 * (uint)FBones.Count, 64); var tbones = new Matrix4x4[FBones.Count]; for (var i = 0; i < FBones.Count; i++) { tbones[i] = GetBoneObjectMatrix(FBones[i], FBones); } - Renderer.AddBackgroundUploadTask((d, cl) => + Renderer.Scene.Renderer.AddBackgroundUploadTask((d, cl) => { StaticBoneBuffer.FillBuffer(cl, tbones); }); @@ -2110,7 +2110,7 @@ public void UpdateMaterial() SetMaterialTexture(TextureType.ShininessTextureResource2, ref MaterialData.shininessTex2, 2); SetMaterialTexture(TextureType.BlendmaskTextureResource, ref MaterialData.blendMaskTex, 0); - Renderer.AddBackgroundUploadTask((d, cl) => + Renderer.Scene.Renderer.AddBackgroundUploadTask((d, cl) => { Tracy.___tracy_c_zone_context ctx = Tracy.TracyCZoneN(1, @"Material upload"); MaterialBuffer.FillBuffer(d, cl, ref MaterialData); diff --git a/src/StudioCore/Resource/HavokCollisionResource.cs b/src/StudioCore/Renderer/Resource/HavokCollisionResource.cs similarity index 98% rename from src/StudioCore/Resource/HavokCollisionResource.cs rename to src/StudioCore/Renderer/Resource/HavokCollisionResource.cs index 68061bd95..a134f41b8 100644 --- a/src/StudioCore/Resource/HavokCollisionResource.cs +++ b/src/StudioCore/Renderer/Resource/HavokCollisionResource.cs @@ -1,6 +1,6 @@ using HKX2; using SoulsFormats; -using StudioCore.Scene; +using StudioCore.Renderer.Scene; using System; using System.Collections.Generic; using System.Linq; @@ -8,7 +8,7 @@ using Veldrid.Utilities; using Vortice.Vulkan; -namespace StudioCore.Resource; +namespace StudioCore.Renderer.Resource; public class HavokCollisionResource : IResource, IDisposable { @@ -115,7 +115,7 @@ private unsafe void ProcessMesh(HKX.HKPStorageExtendedMeshShapeMeshSubpartStorag var buffersize = (uint)dest.IndexCount * 4u; var vbuffersize = (uint)dest.VertexCount * CollisionLayout.SizeInBytes; dest.GeomBuffer = - Renderer.GeometryBufferAllocator.Allocate(vbuffersize, buffersize, (int)CollisionLayout.SizeInBytes, 4); + Renderer.Scene.Renderer.GeometryBufferAllocator.Allocate(vbuffersize, buffersize, (int)CollisionLayout.SizeInBytes, 4); var MeshIndices = new Span(dest.GeomBuffer.MapIBuffer().ToPointer(), dest.IndexCount); var MeshVertices = new Span(dest.GeomBuffer.MapVBuffer().ToPointer(), dest.VertexCount); @@ -331,7 +331,7 @@ private unsafe void ProcessMesh(HKX.FSNPCustomParamCompressedMeshShape mesh, HKX var buffersize = (uint)dest.IndexCount * 4u; var vbuffersize = (uint)dest.VertexCount * CollisionLayout.SizeInBytes; dest.GeomBuffer = - Renderer.GeometryBufferAllocator.Allocate(vbuffersize, buffersize, (int)CollisionLayout.SizeInBytes, 4); + Renderer.Scene.Renderer.GeometryBufferAllocator.Allocate(vbuffersize, buffersize, (int)CollisionLayout.SizeInBytes, 4); var MeshIndices = new Span(dest.GeomBuffer.MapIBuffer().ToPointer(), dest.IndexCount); var MeshVertices = new Span(dest.GeomBuffer.MapVBuffer().ToPointer(), dest.VertexCount); @@ -524,7 +524,7 @@ private unsafe void ProcessMesh(fsnpCustomParamCompressedMeshShape mesh, hknpBod var buffersize = (uint)dest.IndexCount * 4u; var vbuffersize = (uint)dest.VertexCount * CollisionLayout.SizeInBytes; dest.GeomBuffer = - Renderer.GeometryBufferAllocator.Allocate(vbuffersize, buffersize, (int)CollisionLayout.SizeInBytes, 4); + Renderer.Scene.Renderer.GeometryBufferAllocator.Allocate(vbuffersize, buffersize, (int)CollisionLayout.SizeInBytes, 4); var MeshIndices = new Span(dest.GeomBuffer.MapIBuffer().ToPointer(), dest.IndexCount); var MeshVertices = new Span(dest.GeomBuffer.MapVBuffer().ToPointer(), dest.VertexCount); diff --git a/src/StudioCore/Resource/HavokNavmeshResource.cs b/src/StudioCore/Renderer/Resource/HavokNavmeshResource.cs similarity index 97% rename from src/StudioCore/Resource/HavokNavmeshResource.cs rename to src/StudioCore/Renderer/Resource/HavokNavmeshResource.cs index 73918dc16..5ece28c42 100644 --- a/src/StudioCore/Resource/HavokNavmeshResource.cs +++ b/src/StudioCore/Renderer/Resource/HavokNavmeshResource.cs @@ -1,7 +1,7 @@ using DotNext.IO.MemoryMappedFiles; using HKX2; using SoulsFormats; -using StudioCore.Scene; +using StudioCore.Renderer.Scene; using System; using System.Collections.Generic; using System.IO; @@ -11,7 +11,7 @@ using Veldrid; using Veldrid.Utilities; -namespace StudioCore.Resource; +namespace StudioCore.Renderer.Resource; public class HavokNavmeshResource : IResource, IDisposable { @@ -68,7 +68,7 @@ private unsafe void ProcessMesh(hkaiNavMesh mesh) var buffersize = (uint)IndexCount * 4u; var vbuffersize = (uint)VertexCount * NavmeshLayout.SizeInBytes; GeomBuffer = - Renderer.GeometryBufferAllocator.Allocate( + Renderer.Scene.Renderer.GeometryBufferAllocator.Allocate( vbuffersize, buffersize, (int)NavmeshLayout.SizeInBytes, 4); var MeshIndices = new Span(GeomBuffer.MapIBuffer().ToPointer(), IndexCount); var MeshVertices = @@ -76,7 +76,7 @@ private unsafe void ProcessMesh(hkaiNavMesh mesh) PickingVertices = new Vector3[VertexCount]; PickingIndices = new int[IndexCount]; - ResourceFactory factory = Renderer.Factory; + ResourceFactory factory = Renderer.Scene.Renderer.Factory; var idx = 0; @@ -192,7 +192,7 @@ private unsafe void ProcessGraph(hkaiDirectedGraphExplicitCost graph) var lsize = MeshLayoutUtils.GetLayoutVertexSize(MeshLayoutType.LayoutPositionColor); var vbuffersize = (uint)GraphVertexCount * lsize; - CostGraphGeomBuffer = Renderer.GeometryBufferAllocator.Allocate(vbuffersize, buffersize, (int)lsize, 4); + CostGraphGeomBuffer = Renderer.Scene.Renderer.GeometryBufferAllocator.Allocate(vbuffersize, buffersize, (int)lsize, 4); var MeshIndices = new Span(CostGraphGeomBuffer.MapIBuffer().ToPointer(), GraphIndexCount); var MeshVertices = new Span(CostGraphGeomBuffer.MapVBuffer().ToPointer(), GraphVertexCount); diff --git a/src/StudioCore/Resource/IResource.cs b/src/StudioCore/Renderer/Resource/IResource.cs similarity index 82% rename from src/StudioCore/Resource/IResource.cs rename to src/StudioCore/Renderer/Resource/IResource.cs index b7bd1c16d..c1fd7e363 100644 --- a/src/StudioCore/Resource/IResource.cs +++ b/src/StudioCore/Renderer/Resource/IResource.cs @@ -1,6 +1,6 @@ using System; -namespace StudioCore.Resource; +namespace StudioCore.Renderer.Resource; public interface IResource { diff --git a/src/StudioCore/Resource/IResourceEventListener.cs b/src/StudioCore/Renderer/Resource/IResourceEventListener.cs similarity index 88% rename from src/StudioCore/Resource/IResourceEventListener.cs rename to src/StudioCore/Renderer/Resource/IResourceEventListener.cs index 930f9e23f..e3a35620e 100644 --- a/src/StudioCore/Resource/IResourceEventListener.cs +++ b/src/StudioCore/Renderer/Resource/IResourceEventListener.cs @@ -1,4 +1,4 @@ -namespace StudioCore.Resource; +namespace StudioCore.Renderer.Resource; /// /// Implementors of this interface can subscribe to a resource handle to be notified of resource load/unload events diff --git a/src/StudioCore/Resource/MeshLayouts.cs b/src/StudioCore/Renderer/Resource/MeshLayouts.cs similarity index 99% rename from src/StudioCore/Resource/MeshLayouts.cs rename to src/StudioCore/Renderer/Resource/MeshLayouts.cs index b00e3ef0f..791c25210 100644 --- a/src/StudioCore/Resource/MeshLayouts.cs +++ b/src/StudioCore/Renderer/Resource/MeshLayouts.cs @@ -5,7 +5,7 @@ using Veldrid; using Vortice.Vulkan; -namespace StudioCore.Resource; +namespace StudioCore.Renderer.Resource; public enum MeshLayoutType { diff --git a/src/StudioCore/Resource/NVMNavmeshResource.cs b/src/StudioCore/Renderer/Resource/NVMNavmeshResource.cs similarity index 97% rename from src/StudioCore/Resource/NVMNavmeshResource.cs rename to src/StudioCore/Renderer/Resource/NVMNavmeshResource.cs index 873bb3e30..1e23c31e2 100644 --- a/src/StudioCore/Resource/NVMNavmeshResource.cs +++ b/src/StudioCore/Renderer/Resource/NVMNavmeshResource.cs @@ -1,12 +1,12 @@ using SoulsFormats; -using StudioCore.Scene; +using StudioCore.Renderer.Scene; using System; using System.Collections.Generic; using System.Linq; using System.Numerics; using Veldrid.Utilities; -namespace StudioCore.Resource; +namespace StudioCore.Renderer.Resource; public class NVMNavmeshResource : IResource, IDisposable { @@ -44,7 +44,7 @@ private unsafe void ProcessMesh(NVM mesh) var buffersize = (uint)IndexCount * 4u; var vbuffersize = (uint)VertexCount * NavmeshLayout.SizeInBytes; GeomBuffer = - Renderer.GeometryBufferAllocator.Allocate(vbuffersize, buffersize, (int)NavmeshLayout.SizeInBytes, 4); + Renderer.Scene.Renderer.GeometryBufferAllocator.Allocate(vbuffersize, buffersize, (int)NavmeshLayout.SizeInBytes, 4); var MeshIndices = new Span(GeomBuffer.MapIBuffer().ToPointer(), IndexCount); var MeshVertices = new Span(GeomBuffer.MapVBuffer().ToPointer(), VertexCount); diff --git a/src/StudioCore/Resource/ResourceHandle.cs b/src/StudioCore/Renderer/Resource/ResourceHandle.cs similarity index 99% rename from src/StudioCore/Resource/ResourceHandle.cs rename to src/StudioCore/Renderer/Resource/ResourceHandle.cs index b2365f30c..b0523373f 100644 --- a/src/StudioCore/Resource/ResourceHandle.cs +++ b/src/StudioCore/Renderer/Resource/ResourceHandle.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; -namespace StudioCore.Resource; +namespace StudioCore.Renderer.Resource; /// /// Requested access level to a given resource diff --git a/src/StudioCore/Resource/ResourceLoadPipeline.cs b/src/StudioCore/Renderer/Resource/ResourceLoadPipeline.cs similarity index 99% rename from src/StudioCore/Resource/ResourceLoadPipeline.cs rename to src/StudioCore/Renderer/Resource/ResourceLoadPipeline.cs index 097b775a0..ec2240934 100644 --- a/src/StudioCore/Resource/ResourceLoadPipeline.cs +++ b/src/StudioCore/Renderer/Resource/ResourceLoadPipeline.cs @@ -3,7 +3,7 @@ using System.IO; using System.Threading.Tasks.Dataflow; -namespace StudioCore.Resource; +namespace StudioCore.Renderer.Resource; public readonly record struct LoadByteResourceRequest( string VirtualPath, diff --git a/src/StudioCore/Resource/ResourceManager.cs b/src/StudioCore/Renderer/Resource/ResourceManager.cs similarity index 99% rename from src/StudioCore/Resource/ResourceManager.cs rename to src/StudioCore/Renderer/Resource/ResourceManager.cs index 50efba09c..4906802d1 100644 --- a/src/StudioCore/Resource/ResourceManager.cs +++ b/src/StudioCore/Renderer/Resource/ResourceManager.cs @@ -1,7 +1,7 @@ using static Andre.Native.ImGuiBindings; using Microsoft.Extensions.Logging; using SoulsFormats; -using StudioCore.Scene; +using StudioCore.Renderer.Scene; using System; using System.Collections.Concurrent; using System.Collections.Generic; @@ -14,7 +14,7 @@ using System.Threading.Tasks.Dataflow; using System.Threading.Tasks.Schedulers; -namespace StudioCore.Resource; +namespace StudioCore.Renderer.Resource; /// /// Manages resources (mainly GPU) such as textures and models, and can be used to unload and reload them at will. @@ -352,11 +352,11 @@ public static void UpdateTasks() } else { - if (Renderer.GeometryBufferAllocator != null && - Renderer.GeometryBufferAllocator.HasStagingOrPending()) + if (Renderer.Scene.Renderer.GeometryBufferAllocator != null && + Renderer.Scene.Renderer.GeometryBufferAllocator.HasStagingOrPending()) { Tracy.___tracy_c_zone_context ctx = Tracy.TracyCZoneN(1, "Flush Staging buffer"); - Renderer.GeometryBufferAllocator.FlushStaging(true); + Renderer.Scene.Renderer.GeometryBufferAllocator.FlushStaging(true); Tracy.TracyCZoneEnd(ctx); } diff --git a/src/StudioCore/Resource/TextureResource.cs b/src/StudioCore/Renderer/Resource/TextureResource.cs similarity index 86% rename from src/StudioCore/Resource/TextureResource.cs rename to src/StudioCore/Renderer/Resource/TextureResource.cs index 971e496bc..710887467 100644 --- a/src/StudioCore/Resource/TextureResource.cs +++ b/src/StudioCore/Renderer/Resource/TextureResource.cs @@ -1,8 +1,8 @@ using SoulsFormats; -using StudioCore.Scene; +using StudioCore.Renderer.Scene; using System; -namespace StudioCore.Resource; +namespace StudioCore.Renderer.Resource; public class TextureResource : IResource, IDisposable { @@ -27,11 +27,11 @@ public bool _LoadTexture(AccessLevel al) { if (TexturePool.TextureHandle.IsTPFCube(Texture.Textures[TPFIndex], Texture.Platform)) { - GPUTexture = Renderer.GlobalCubeTexturePool.AllocateTextureDescriptor(); + GPUTexture = Renderer.Scene.Renderer.GlobalCubeTexturePool.AllocateTextureDescriptor(); } else { - GPUTexture = Renderer.GlobalTexturePool.AllocateTextureDescriptor(); + GPUTexture = Renderer.Scene.Renderer.GlobalTexturePool.AllocateTextureDescriptor(); } if (GPUTexture == null) @@ -46,7 +46,7 @@ public bool _LoadTexture(AccessLevel al) if (Texture.Platform == TPF.TPFPlatform.PC || Texture.Platform == TPF.TPFPlatform.PS3) { - Renderer.AddLowPriorityBackgroundUploadTask((d, cl) => + Renderer.Scene.Renderer.AddLowPriorityBackgroundUploadTask((d, cl) => { if (GPUTexture == null) { @@ -60,7 +60,7 @@ public bool _LoadTexture(AccessLevel al) } else if (Texture.Platform == TPF.TPFPlatform.PS4) { - Renderer.AddLowPriorityBackgroundUploadTask((d, cl) => + Renderer.Scene.Renderer.AddLowPriorityBackgroundUploadTask((d, cl) => { if (GPUTexture == null) { diff --git a/src/StudioCore/Scene/CreatePrefabModal.cs b/src/StudioCore/Renderer/Scene/CreatePrefabModal.cs similarity index 98% rename from src/StudioCore/Scene/CreatePrefabModal.cs rename to src/StudioCore/Renderer/Scene/CreatePrefabModal.cs index 454a621b7..85a9249d9 100644 --- a/src/StudioCore/Scene/CreatePrefabModal.cs +++ b/src/StudioCore/Renderer/Scene/CreatePrefabModal.cs @@ -2,7 +2,7 @@ using StudioCore.MsbEditor; using System.Numerics; -namespace StudioCore.Scene; +namespace StudioCore.Renderer.Scene; internal class CreatePrefabModal : IModal { diff --git a/src/StudioCore/Scene/DrawGroup.cs b/src/StudioCore/Renderer/Scene/DrawGroup.cs similarity index 95% rename from src/StudioCore/Scene/DrawGroup.cs rename to src/StudioCore/Renderer/Scene/DrawGroup.cs index 43055d7f2..3204bf27f 100644 --- a/src/StudioCore/Scene/DrawGroup.cs +++ b/src/StudioCore/Renderer/Scene/DrawGroup.cs @@ -1,4 +1,4 @@ -namespace StudioCore.Scene; +namespace StudioCore.Renderer.Scene; public class DrawGroup { diff --git a/src/StudioCore/Scene/FullScreenQuad.cs b/src/StudioCore/Renderer/Scene/FullScreenQuad.cs similarity index 98% rename from src/StudioCore/Scene/FullScreenQuad.cs rename to src/StudioCore/Renderer/Scene/FullScreenQuad.cs index 451a0330b..ab3db7a56 100644 --- a/src/StudioCore/Scene/FullScreenQuad.cs +++ b/src/StudioCore/Renderer/Scene/FullScreenQuad.cs @@ -2,7 +2,7 @@ using Veldrid.Utilities; using Vortice.Vulkan; -namespace StudioCore.Scene; +namespace StudioCore.Renderer.Scene; public class FullScreenQuad { diff --git a/src/StudioCore/Scene/GPUBufferAllocator.cs b/src/StudioCore/Renderer/Scene/GPUBufferAllocator.cs similarity index 99% rename from src/StudioCore/Scene/GPUBufferAllocator.cs rename to src/StudioCore/Renderer/Scene/GPUBufferAllocator.cs index 65a9a54a6..8be12f725 100644 --- a/src/StudioCore/Scene/GPUBufferAllocator.cs +++ b/src/StudioCore/Renderer/Scene/GPUBufferAllocator.cs @@ -6,7 +6,7 @@ using Veldrid; using Vortice.Vulkan; -namespace StudioCore.Scene; +namespace StudioCore.Renderer.Scene; public class GPUBufferAllocator { diff --git a/src/StudioCore/Scene/IDrawable.cs b/src/StudioCore/Renderer/Scene/IDrawable.cs similarity index 98% rename from src/StudioCore/Scene/IDrawable.cs rename to src/StudioCore/Renderer/Scene/IDrawable.cs index b89040cdc..518081c2c 100644 --- a/src/StudioCore/Scene/IDrawable.cs +++ b/src/StudioCore/Renderer/Scene/IDrawable.cs @@ -2,7 +2,7 @@ using System.Numerics; using Veldrid.Utilities; -namespace StudioCore.Scene; +namespace StudioCore.Renderer.Scene; /// /// A drawable is an object that is capable of creating and submiting rendering diff --git a/src/StudioCore/Scene/IModal.cs b/src/StudioCore/Renderer/Scene/IModal.cs similarity index 82% rename from src/StudioCore/Scene/IModal.cs rename to src/StudioCore/Renderer/Scene/IModal.cs index 98a9f299f..516dbf5ef 100644 --- a/src/StudioCore/Scene/IModal.cs +++ b/src/StudioCore/Renderer/Scene/IModal.cs @@ -1,4 +1,4 @@ -namespace StudioCore.Scene; +namespace StudioCore.Renderer.Scene; /// /// Simple interface for a modal dialogue diff --git a/src/StudioCore/Scene/ISelectable.cs b/src/StudioCore/Renderer/Scene/ISelectable.cs similarity index 83% rename from src/StudioCore/Scene/ISelectable.cs rename to src/StudioCore/Renderer/Scene/ISelectable.cs index e33d6d922..007914afe 100644 --- a/src/StudioCore/Scene/ISelectable.cs +++ b/src/StudioCore/Renderer/Scene/ISelectable.cs @@ -1,4 +1,4 @@ -namespace StudioCore.Scene; +namespace StudioCore.Renderer.Scene; /// /// An abstract object held by a render object that can be selected diff --git a/src/StudioCore/Scene/InstanceData.cs b/src/StudioCore/Renderer/Scene/InstanceData.cs similarity index 88% rename from src/StudioCore/Scene/InstanceData.cs rename to src/StudioCore/Renderer/Scene/InstanceData.cs index c49a6aa40..100fcf1ec 100644 --- a/src/StudioCore/Scene/InstanceData.cs +++ b/src/StudioCore/Renderer/Scene/InstanceData.cs @@ -1,7 +1,7 @@ using System.Numerics; using System.Runtime.InteropServices; -namespace StudioCore.Scene; +namespace StudioCore.Renderer.Scene; [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct InstanceData diff --git a/src/StudioCore/Scene/Material.cs b/src/StudioCore/Renderer/Scene/Material.cs similarity index 93% rename from src/StudioCore/Scene/Material.cs rename to src/StudioCore/Renderer/Scene/Material.cs index ed12b9690..9c0270bc4 100644 --- a/src/StudioCore/Scene/Material.cs +++ b/src/StudioCore/Renderer/Scene/Material.cs @@ -1,6 +1,6 @@ using System.Runtime.InteropServices; -namespace StudioCore.Scene; +namespace StudioCore.Renderer.Scene; [StructLayout(LayoutKind.Sequential, Pack = 1)] public unsafe struct Material diff --git a/src/StudioCore/Scene/MeshProvider.cs b/src/StudioCore/Renderer/Scene/MeshProvider.cs similarity index 99% rename from src/StudioCore/Scene/MeshProvider.cs rename to src/StudioCore/Renderer/Scene/MeshProvider.cs index 7c7b72b2e..f4a3b26f0 100644 --- a/src/StudioCore/Scene/MeshProvider.cs +++ b/src/StudioCore/Renderer/Scene/MeshProvider.cs @@ -1,4 +1,4 @@ -using StudioCore.Resource; +using StudioCore.Renderer.Resource; using System; using System.Collections.Generic; using System.IO; @@ -7,7 +7,7 @@ using Veldrid.Utilities; using Vortice.Vulkan; -namespace StudioCore.Scene; +namespace StudioCore.Renderer.Scene; public interface IMeshProviderEventListener { diff --git a/src/StudioCore/Scene/PickingResult.cs b/src/StudioCore/Renderer/Scene/PickingResult.cs similarity index 84% rename from src/StudioCore/Scene/PickingResult.cs rename to src/StudioCore/Renderer/Scene/PickingResult.cs index 982a86a72..d07353fad 100644 --- a/src/StudioCore/Scene/PickingResult.cs +++ b/src/StudioCore/Renderer/Scene/PickingResult.cs @@ -1,6 +1,6 @@ using System.Runtime.InteropServices; -namespace StudioCore.Scene; +namespace StudioCore.Renderer.Scene; [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct PickingResult diff --git a/src/StudioCore/Scene/RenderFilter.cs b/src/StudioCore/Renderer/Scene/RenderFilter.cs similarity index 86% rename from src/StudioCore/Scene/RenderFilter.cs rename to src/StudioCore/Renderer/Scene/RenderFilter.cs index dd46bf095..70561f76e 100644 --- a/src/StudioCore/Scene/RenderFilter.cs +++ b/src/StudioCore/Renderer/Scene/RenderFilter.cs @@ -1,6 +1,6 @@ using System; -namespace StudioCore.Scene; +namespace StudioCore.Renderer.Scene; [Flags] public enum RenderFilter diff --git a/src/StudioCore/Scene/RenderKey.cs b/src/StudioCore/Renderer/Scene/RenderKey.cs similarity index 96% rename from src/StudioCore/Scene/RenderKey.cs rename to src/StudioCore/Renderer/Scene/RenderKey.cs index 10acf2d3f..d92d3296c 100644 --- a/src/StudioCore/Scene/RenderKey.cs +++ b/src/StudioCore/Renderer/Scene/RenderKey.cs @@ -1,7 +1,7 @@ using System; using System.Runtime.CompilerServices; -namespace StudioCore.Scene; +namespace StudioCore.Renderer.Scene; public struct RenderKey : IComparable, IComparable { diff --git a/src/StudioCore/Scene/RenderScene.cs b/src/StudioCore/Renderer/Scene/RenderScene.cs similarity index 99% rename from src/StudioCore/Scene/RenderScene.cs rename to src/StudioCore/Renderer/Scene/RenderScene.cs index e79c70ac8..b4d53ce9c 100644 --- a/src/StudioCore/Scene/RenderScene.cs +++ b/src/StudioCore/Renderer/Scene/RenderScene.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using Veldrid.Utilities; -namespace StudioCore.Scene; +namespace StudioCore.Renderer.Scene; /// /// A scene in the context of rendering. This isn't focused on the heirarchy or properties of an object, diff --git a/src/StudioCore/Scene/Renderable.cs b/src/StudioCore/Renderer/Scene/Renderable.cs similarity index 99% rename from src/StudioCore/Scene/Renderable.cs rename to src/StudioCore/Renderer/Scene/Renderable.cs index 44a14cf41..823474558 100644 --- a/src/StudioCore/Scene/Renderable.cs +++ b/src/StudioCore/Renderer/Scene/Renderable.cs @@ -4,7 +4,7 @@ using Veldrid.Utilities; using Vortice.Vulkan; -namespace StudioCore.Scene; +namespace StudioCore.Renderer.Scene; /// /// Contains if the component is visible/valid. Valid means that there's an actual diff --git a/src/StudioCore/Scene/RenderableProxy.cs b/src/StudioCore/Renderer/Scene/RenderableProxy.cs similarity index 99% rename from src/StudioCore/Scene/RenderableProxy.cs rename to src/StudioCore/Renderer/Scene/RenderableProxy.cs index ecbd010d1..d65052d49 100644 --- a/src/StudioCore/Scene/RenderableProxy.cs +++ b/src/StudioCore/Renderer/Scene/RenderableProxy.cs @@ -1,6 +1,7 @@ #nullable enable -using StudioCore.DebugPrimitives; -using StudioCore.Resource; +using StudioCore.Renderer.DebugPrimitives; +using StudioCore.Renderer.Resource; +using StudioCore.Utilities; using System; using System.Collections.Generic; using System.Drawing; @@ -11,7 +12,7 @@ using Veldrid.Utilities; using Vortice.Vulkan; -namespace StudioCore.Scene; +namespace StudioCore.Renderer.Scene; /// /// Model marker type for meshes that may not be visible in the editor (c0000, fogwalls, etc) diff --git a/src/StudioCore/Scene/Renderer.cs b/src/StudioCore/Renderer/Scene/Renderer.cs similarity index 99% rename from src/StudioCore/Scene/Renderer.cs rename to src/StudioCore/Renderer/Scene/Renderer.cs index 7b9e967ee..4902ff1a6 100644 --- a/src/StudioCore/Scene/Renderer.cs +++ b/src/StudioCore/Renderer/Scene/Renderer.cs @@ -10,7 +10,7 @@ using Veldrid; using Vortice.Vulkan; -namespace StudioCore.Scene; +namespace StudioCore.Renderer.Scene; public class Renderer { diff --git a/src/StudioCore/Scene/SamplerSet.cs b/src/StudioCore/Renderer/Scene/SamplerSet.cs similarity index 98% rename from src/StudioCore/Scene/SamplerSet.cs rename to src/StudioCore/Renderer/Scene/SamplerSet.cs index 727c716cd..826364a35 100644 --- a/src/StudioCore/Scene/SamplerSet.cs +++ b/src/StudioCore/Renderer/Scene/SamplerSet.cs @@ -1,7 +1,7 @@ using Veldrid; using Vortice.Vulkan; -namespace StudioCore.Scene; +namespace StudioCore.Renderer.Scene; /// /// Helper class that contains descriptor sets and layouts for samplers diff --git a/src/StudioCore/Scene/SceneParam.cs b/src/StudioCore/Renderer/Scene/SceneParam.cs similarity index 93% rename from src/StudioCore/Scene/SceneParam.cs rename to src/StudioCore/Renderer/Scene/SceneParam.cs index dd51dffed..7f38091d3 100644 --- a/src/StudioCore/Scene/SceneParam.cs +++ b/src/StudioCore/Renderer/Scene/SceneParam.cs @@ -1,7 +1,7 @@ using System.Numerics; using System.Runtime.InteropServices; -namespace StudioCore.Scene; +namespace StudioCore.Renderer.Scene; [StructLayout(LayoutKind.Sequential, Pack = 1)] public unsafe struct SceneParam diff --git a/src/StudioCore/Scene/SceneRenderPipeline.cs b/src/StudioCore/Renderer/Scene/SceneRenderPipeline.cs similarity index 99% rename from src/StudioCore/Scene/SceneRenderPipeline.cs rename to src/StudioCore/Renderer/Scene/SceneRenderPipeline.cs index a58a776c3..340527d8c 100644 --- a/src/StudioCore/Scene/SceneRenderPipeline.cs +++ b/src/StudioCore/Renderer/Scene/SceneRenderPipeline.cs @@ -5,7 +5,7 @@ using Veldrid.Utilities; using Vortice.Vulkan; -namespace StudioCore.Scene; +namespace StudioCore.Renderer.Scene; /// /// The "renderer" for a scene. This pipeline is instantiated for every real or virtual viewport, and will diff --git a/src/StudioCore/Scene/ShaderHelper.cs b/src/StudioCore/Renderer/Scene/ShaderHelper.cs similarity index 98% rename from src/StudioCore/Scene/ShaderHelper.cs rename to src/StudioCore/Renderer/Scene/ShaderHelper.cs index 11ad7de61..851e94251 100644 --- a/src/StudioCore/Scene/ShaderHelper.cs +++ b/src/StudioCore/Renderer/Scene/ShaderHelper.cs @@ -5,7 +5,7 @@ using Veldrid.SPIRV; using Vortice.Vulkan; -namespace StudioCore.Scene; +namespace StudioCore.Renderer.Scene; public static class ShaderHelper { diff --git a/src/StudioCore/Scene/ShaderSetCacheKey.cs b/src/StudioCore/Renderer/Scene/ShaderSetCacheKey.cs similarity index 96% rename from src/StudioCore/Scene/ShaderSetCacheKey.cs rename to src/StudioCore/Renderer/Scene/ShaderSetCacheKey.cs index a535bf286..c48d4fba0 100644 --- a/src/StudioCore/Scene/ShaderSetCacheKey.cs +++ b/src/StudioCore/Renderer/Scene/ShaderSetCacheKey.cs @@ -1,7 +1,7 @@ using System; using Veldrid; -namespace StudioCore.Scene; +namespace StudioCore.Renderer.Scene; public struct ShaderSetCacheKey : IEquatable { diff --git a/src/StudioCore/Scene/StaticResourceCache.cs b/src/StudioCore/Renderer/Scene/StaticResourceCache.cs similarity index 99% rename from src/StudioCore/Scene/StaticResourceCache.cs rename to src/StudioCore/Renderer/Scene/StaticResourceCache.cs index 086f2a46f..8b0d0d55f 100644 --- a/src/StudioCore/Scene/StaticResourceCache.cs +++ b/src/StudioCore/Renderer/Scene/StaticResourceCache.cs @@ -2,7 +2,7 @@ using Veldrid; using Vortice.Vulkan; -namespace StudioCore.Scene; +namespace StudioCore.Renderer.Scene; internal static class StaticResourceCache { diff --git a/src/StudioCore/Scene/TexturePool.cs b/src/StudioCore/Renderer/Scene/TexturePool.cs similarity index 99% rename from src/StudioCore/Scene/TexturePool.cs rename to src/StudioCore/Renderer/Scene/TexturePool.cs index 6e14fed8a..547953265 100644 --- a/src/StudioCore/Scene/TexturePool.cs +++ b/src/StudioCore/Renderer/Scene/TexturePool.cs @@ -9,7 +9,7 @@ using Vortice.Vulkan; using Rectangle = Veldrid.Rectangle; -namespace StudioCore.Scene; +namespace StudioCore.Renderer.Scene; /// /// Low level texture pool that maintains an array of descriptor sets that can diff --git a/src/StudioCore/WorldView.cs b/src/StudioCore/Renderer/WorldView.cs similarity index 99% rename from src/StudioCore/WorldView.cs rename to src/StudioCore/Renderer/WorldView.cs index 0fd876c21..25115fbfc 100644 --- a/src/StudioCore/WorldView.cs +++ b/src/StudioCore/Renderer/WorldView.cs @@ -1,10 +1,11 @@ -using Silk.NET.SDL; +using StudioCore.Utilities; +using Silk.NET.SDL; using System; using System.Numerics; using Veldrid; using Veldrid.Sdl2; -namespace StudioCore; +namespace StudioCore.Renderer; public class WorldView { diff --git a/src/StudioCore/ResDirectory.cs b/src/StudioCore/ResDirectory.cs new file mode 100644 index 000000000..4a1cb8c4d --- /dev/null +++ b/src/StudioCore/ResDirectory.cs @@ -0,0 +1,26 @@ +using System.Collections.Generic; +using Microsoft.AspNetCore.Identity.Data; +using SoulsFormats; +using StudioCore.Editor; +using StudioCore.ParamEditor; +using StudioCore.TextEditor; +using System; +using System.Globalization; +using System.IO; +using System.Linq; + +namespace StudioCore; + +/// +/// Static data not tied to a project, but perhaps tied to a loaded game. +/// +public class ResDirectory +{ + public static ResDirectory CurrentGame { get; set; } = new(); + + public Dictionary AuxProjects = new(); + + public ParamDefBank ParamDefBank = new(); + public ParamMetaBank ParamMetaBank = new(); + +} diff --git a/src/StudioCore/SettingsMenu.cs b/src/StudioCore/SettingsMenu.cs index c741aa355..0806ebd2c 100644 --- a/src/StudioCore/SettingsMenu.cs +++ b/src/StudioCore/SettingsMenu.cs @@ -3,7 +3,7 @@ using StudioCore.Editor; using StudioCore.MsbEditor; using StudioCore.ParamEditor; -using StudioCore.Scene; +using StudioCore.Renderer.Scene; using StudioCore.TextEditor; using StudioCore.Utilities; using System; @@ -12,8 +12,10 @@ using System.Numerics; using System.Reflection; using Veldrid; -using StudioCore.Interface; +using StudioCore.Editor; using System.Globalization; +using System.Collections; +using System.Collections.Generic; namespace StudioCore; @@ -44,26 +46,14 @@ private void DisplaySettings_System() { if (ImGui.CollapsingHeader("General", ImGuiTreeNodeFlags.DefaultOpen)) { - if (CFG.Current.ShowUITooltips) - { - ShowHelpMarker("When enabled DSMS will automatically check for new versions upon program start."); - ImGui.SameLine(); - } + EditorDecorations.ShowHelpMarker("When enabled DSMS will automatically check for new versions upon program start."); ImGui.Checkbox("Check for new versions of DSMapStudio during startup", ref CFG.Current.EnableCheckProgramUpdate); - if (CFG.Current.ShowUITooltips) - { - ShowHelpMarker("This is a tooltip."); - ImGui.SameLine(); - } + EditorDecorations.ShowHelpMarker("This is a tooltip."); ImGui.Checkbox("Show UI tooltips", ref CFG.Current.ShowUITooltips); - if (CFG.Current.ShowUITooltips) - { - ShowHelpMarker("Adjusts the scale of the user interface throughout all of DSMS."); - ImGui.SameLine(); - } + EditorDecorations.ShowHelpMarker("Adjusts the scale of the user interface throughout all of DSMS."); ImGui.SliderFloat("UI scale", ref _tempUiScale, 0.5f, 4.0f); if (ImGui.IsItemDeactivatedAfterEdit()) { @@ -81,11 +71,7 @@ private void DisplaySettings_System() MapStudioNew.UIScaleChanged?.Invoke(null, EventArgs.Empty); } - if (CFG.Current.ShowUITooltips) - { - ShowHelpMarker("Multiplies the user interface scale by your monitor's DPI setting."); - ImGui.SameLine(); - } + EditorDecorations.ShowHelpMarker("Multiplies the user interface scale by your monitor's DPI setting."); ImGui.Checkbox($"Multiply UI scale by DPI ({(MapStudioNew.Dpi / 96).ToString("P0", new NumberFormatInfo { PercentPositivePattern = 1, PercentNegativePattern = 1 })})", ref CFG.Current.UIScaleByDPI); if (ImGui.IsItemDeactivatedAfterEdit()) { @@ -106,51 +92,31 @@ private void DisplaySettings_System() // Additional Language Fonts if (ImGui.CollapsingHeader("Additional Language Fonts")) { - if (CFG.Current.ShowUITooltips) - { - ShowHelpMarker("Include Chinese font.\nAdditional fonts take more VRAM and increase startup time."); - ImGui.SameLine(); - } + EditorDecorations.ShowHelpMarker("Include Chinese font.\nAdditional fonts take more VRAM and increase startup time."); if (ImGui.Checkbox("Chinese", ref CFG.Current.FontChinese)) { MapStudioNew.FontRebuildRequest = true; } - if (CFG.Current.ShowUITooltips) - { - ShowHelpMarker("Include Korean font.\nAdditional fonts take more VRAM and increase startup time."); - ImGui.SameLine(); - } + EditorDecorations.ShowHelpMarker("Include Korean font.\nAdditional fonts take more VRAM and increase startup time."); if (ImGui.Checkbox("Korean", ref CFG.Current.FontKorean)) { MapStudioNew.FontRebuildRequest = true; } - if (CFG.Current.ShowUITooltips) - { - ShowHelpMarker("Include Thai font.\nAdditional fonts take more VRAM and increase startup time."); - ImGui.SameLine(); - } + EditorDecorations.ShowHelpMarker("Include Thai font.\nAdditional fonts take more VRAM and increase startup time."); if (ImGui.Checkbox("Thai", ref CFG.Current.FontThai)) { MapStudioNew.FontRebuildRequest = true; } - if (CFG.Current.ShowUITooltips) - { - ShowHelpMarker("Include Vietnamese font.\nAdditional fonts take more VRAM and increase startup time."); - ImGui.SameLine(); - } + EditorDecorations.ShowHelpMarker("Include Vietnamese font.\nAdditional fonts take more VRAM and increase startup time."); if (ImGui.Checkbox("Vietnamese", ref CFG.Current.FontVietnamese)) { MapStudioNew.FontRebuildRequest = true; } - if (CFG.Current.ShowUITooltips) - { - ShowHelpMarker("Include Cyrillic font.\nAdditional fonts take more VRAM and increase startup time."); - ImGui.SameLine(); - } + EditorDecorations.ShowHelpMarker("Include Cyrillic font.\nAdditional fonts take more VRAM and increase startup time."); if (ImGui.Checkbox("Cyrillic", ref CFG.Current.FontCyrillic)) { MapStudioNew.FontRebuildRequest = true; @@ -160,7 +126,7 @@ private void DisplaySettings_System() if (ImGui.CollapsingHeader("Resources", ImGuiTreeNodeFlags.DefaultOpen)) { ImGui.Checkbox("Alias Banks - Editor Mode", ref CFG.Current.AliasBank_EditorMode); - ImguiUtils.ShowHelpMarker("If enabled, editing the name and tags for alias banks will commit the changes to the DSMS base version instead of the mod-specific version."); + Editor.EditorDecorations.ShowHelpMarker("If enabled, editing the name and tags for alias banks will commit the changes to the DSMS base version instead of the mod-specific version."); } if (ImGui.CollapsingHeader("Project", ImGuiTreeNodeFlags.DefaultOpen)) @@ -169,7 +135,7 @@ private void DisplaySettings_System() { if (CFG.Current.ShowUITooltips) { - ShowHelpMarker("No project has been loaded yet."); + EditorDecorations.ShowHelpMarker("No project has been loaded yet."); ImGui.SameLine(); } ImGui.Text("No project loaded"); @@ -178,20 +144,12 @@ private void DisplaySettings_System() { if (TaskManager.AnyActiveTasks()) { - if (CFG.Current.ShowUITooltips) - { - ShowHelpMarker("DSMS must finished all program tasks before it can load a project."); - ImGui.SameLine(); - } + EditorDecorations.ShowHelpMarker("DSMS must finished all program tasks before it can load a project."); ImGui.Text("Waiting for program tasks to finish..."); } else { - if (CFG.Current.ShowUITooltips) - { - ShowHelpMarker("This is the currently loaded project."); - ImGui.SameLine(); - } + EditorDecorations.ShowHelpMarker("This is the currently loaded project."); ImGui.Text($@"Project: {ProjSettings.ProjectName}"); if (ImGui.Button("Open project settings file")) @@ -203,12 +161,7 @@ private void DisplaySettings_System() var useLoose = ProjSettings.UseLooseParams; if (ProjSettings.GameType is GameType.DarkSoulsIISOTFS or GameType.DarkSoulsIII) { - if (CFG.Current.ShowUITooltips) - { - ShowHelpMarker("Loose params means the .PARAM files will be saved outside of the regulation.bin file.\n\nFor Dark Souls II: Scholar of the First Sin, it is recommended that you enable this if add any additional rows."); - ImGui.SameLine(); - } - + EditorDecorations.ShowHelpMarker("Loose params means the .PARAM files will be saved outside of the regulation.bin file.\n\nFor Dark Souls II: Scholar of the First Sin, it is recommended that you enable this if add any additional rows."); if (ImGui.Checkbox("Use loose params", ref useLoose)) { ProjSettings.UseLooseParams = useLoose; @@ -222,621 +175,6 @@ private void DisplaySettings_System() } } - private unsafe void DisplaySettings_MapEditor() - { - if (ImGui.BeginTabItem("Map Editor")) - { - if (ImGui.CollapsingHeader("General", ImGuiTreeNodeFlags.DefaultOpen)) - { - if (CFG.Current.ShowUITooltips) - { - ShowHelpMarker("Viewport FPS when window is focused."); - ImGui.SameLine(); - } - ImGui.DragFloat("Frame Limit", ref CFG.Current.GFX_Framerate_Limit, 1.0f, 5.0f, 300.0f); - - if (CFG.Current.ShowUITooltips) - { - ShowHelpMarker("Viewport FPS when window is not focused."); - ImGui.SameLine(); - } - ImGui.DragFloat("Frame Limit (Unfocused)", ref CFG.Current.GFX_Framerate_Limit_Unfocused, 1.0f, 1.0f, 60.0f); - - if (CFG.Current.ShowUITooltips) - { - ShowHelpMarker("Enabling this option will allow DSMS to render the textures of models within the viewport.\n\nNote, this feature is in an alpha state."); - ImGui.SameLine(); - } - ImGui.Checkbox("Enable texturing", ref CFG.Current.EnableTexturing); - - if (CFG.Current.ShowUITooltips) - { - ShowHelpMarker("This option will cause loaded maps to always be visible within the map list, ignoring the search filter."); - ImGui.SameLine(); - } - ImGui.Checkbox("Exclude loaded maps from search filter", ref CFG.Current.Map_AlwaysListLoadedMaps); - - if (ProjSettings.GameType is GameType.EldenRing) - { - if (CFG.Current.ShowUITooltips) - { - ShowHelpMarker(""); - ImGui.SameLine(); - } - ImGui.Checkbox("Enable Elden Ring auto map offset", ref CFG.Current.EnableEldenRingAutoMapOffset); - } - } - - // Scene View - // Scene View - if (ImGui.CollapsingHeader("Map Object List")) - { - ImGui.Checkbox("Display map names", ref CFG.Current.MapEditor_MapObjectList_ShowMapNames); - ImguiUtils.ShowHoverTooltip("Map names will be displayed within the scene view list."); - - ImGui.Checkbox("Display character names", ref CFG.Current.MapEditor_MapObjectList_ShowCharacterNames); - ImguiUtils.ShowHoverTooltip("Characters names will be displayed within the scene view list."); - - ImGui.Checkbox("Display asset names", ref CFG.Current.MapEditor_MapObjectList_ShowAssetNames); - ImguiUtils.ShowHoverTooltip("Asset/object names will be displayed within the scene view list."); - - ImGui.Checkbox("Display map piece names", ref CFG.Current.MapEditor_MapObjectList_ShowMapPieceNames); - ImguiUtils.ShowHoverTooltip("Map piece names will be displayed within the scene view list."); - - ImGui.Checkbox("Display treasure names", ref CFG.Current.MapEditor_MapObjectList_ShowTreasureNames); - ImguiUtils.ShowHoverTooltip("Treasure itemlot names will be displayed within the scene view list."); - } - - if (ImGui.CollapsingHeader("Selection")) - { - var arbitrary_rotation_x = CFG.Current.Map_ArbitraryRotation_X_Shift; - var arbitrary_rotation_y = CFG.Current.Map_ArbitraryRotation_Y_Shift; - var camera_radius_offset = CFG.Current.Map_MoveSelectionToCamera_Radius; - - ImGui.Checkbox("Enable selection outline", ref CFG.Current.Viewport_Enable_Selection_Outline); - ImguiUtils.ShowHoverTooltip("Enable the selection outline around map entities."); - - if (CFG.Current.ShowUITooltips) - { - ShowHelpMarker("Set the angle increment amount used by Arbitary Rotation in the X-axis."); - ImGui.SameLine(); - } - if (ImGui.InputFloat("Rotation increment degrees: Roll", ref arbitrary_rotation_x)) - { - CFG.Current.Map_ArbitraryRotation_X_Shift = Math.Clamp(arbitrary_rotation_x, -180.0f, 180.0f); - } - - if (CFG.Current.ShowUITooltips) - { - ShowHelpMarker("Set the angle increment amount used by Arbitary Rotation in the Y-axis."); - ImGui.SameLine(); - } - if (ImGui.InputFloat("Rotation increment degrees: Yaw", ref arbitrary_rotation_y)) - { - CFG.Current.Map_ArbitraryRotation_Y_Shift = Math.Clamp(arbitrary_rotation_y, -180.0f, 180.0f); - ; - } - - if (CFG.Current.ShowUITooltips) - { - ShowHelpMarker("Set the distance at which the current select is offset from the camera when using the Move Selection to Camera action."); - ImGui.SameLine(); - } - if (ImGui.DragFloat("Move selection to camera (offset distance)", ref camera_radius_offset)) - { - CFG.Current.Map_MoveSelectionToCamera_Radius = camera_radius_offset; - } - } - - if (ImGui.CollapsingHeader("Camera")) - { - if (CFG.Current.ShowUITooltips) - { - ShowHelpMarker("Resets all of the values within this section to their default values."); - ImGui.SameLine(); - } - if (ImGui.Button("Reset##ViewportCamera")) - { - CFG.Current.GFX_Camera_Sensitivity = CFG.Default.GFX_Camera_Sensitivity; - - CFG.Current.GFX_Camera_FOV = CFG.Default.GFX_Camera_FOV; - - CFG.Current.GFX_RenderDistance_Max = CFG.Default.GFX_RenderDistance_Max; - - MsbEditor.Viewport.WorldView.CameraMoveSpeed_Slow = CFG.Default.GFX_Camera_MoveSpeed_Slow; - CFG.Current.GFX_Camera_MoveSpeed_Slow = MsbEditor.Viewport.WorldView.CameraMoveSpeed_Slow; - - MsbEditor.Viewport.WorldView.CameraMoveSpeed_Normal = CFG.Default.GFX_Camera_MoveSpeed_Normal; - CFG.Current.GFX_Camera_MoveSpeed_Normal = MsbEditor.Viewport.WorldView.CameraMoveSpeed_Normal; - - MsbEditor.Viewport.WorldView.CameraMoveSpeed_Fast = CFG.Default.GFX_Camera_MoveSpeed_Fast; - CFG.Current.GFX_Camera_MoveSpeed_Fast = MsbEditor.Viewport.WorldView.CameraMoveSpeed_Fast; - } - - var cam_sensitivity = CFG.Current.GFX_Camera_Sensitivity; - - if (CFG.Current.ShowUITooltips) - { - ShowHelpMarker("Mouse sensitivty for turning the camera."); - ImGui.SameLine(); - } - if (ImGui.SliderFloat("Camera sensitivity", ref cam_sensitivity, 0.0f, 0.1f)) - { - CFG.Current.GFX_Camera_Sensitivity = cam_sensitivity; - } - - var cam_fov = CFG.Current.GFX_Camera_FOV; - - if (CFG.Current.ShowUITooltips) - { - ShowHelpMarker("Set the field of view used by the camera within DSMS."); - ImGui.SameLine(); - } - if (ImGui.SliderFloat("Camera FOV", ref cam_fov, 40.0f, 140.0f)) - { - CFG.Current.GFX_Camera_FOV = cam_fov; - } - - var farClip = CFG.Current.GFX_RenderDistance_Max; - if (CFG.Current.ShowUITooltips) - { - ShowHelpMarker("Set the maximum distance at which entities will be rendered within the DSMS viewport."); - ImGui.SameLine(); - } - if (ImGui.SliderFloat("Map max render distance", ref farClip, 10.0f, 500000.0f)) - { - CFG.Current.GFX_RenderDistance_Max = farClip; - } - - if (CFG.Current.ShowUITooltips) - { - ShowHelpMarker("Set the speed at which the camera will move when the Left or Right Shift key is pressed whilst moving."); - ImGui.SameLine(); - } - if (ImGui.SliderFloat("Map camera speed (slow)", - ref MsbEditor.Viewport.WorldView.CameraMoveSpeed_Slow, 0.1f, 999.0f)) - { - CFG.Current.GFX_Camera_MoveSpeed_Slow = MsbEditor.Viewport.WorldView.CameraMoveSpeed_Slow; - } - - if (CFG.Current.ShowUITooltips) - { - ShowHelpMarker("Set the speed at which the camera will move whilst moving normally."); - ImGui.SameLine(); - } - if (ImGui.SliderFloat("Map camera speed (normal)", - ref MsbEditor.Viewport.WorldView.CameraMoveSpeed_Normal, 0.1f, 999.0f)) - { - CFG.Current.GFX_Camera_MoveSpeed_Normal = MsbEditor.Viewport.WorldView.CameraMoveSpeed_Normal; - } - - if (CFG.Current.ShowUITooltips) - { - ShowHelpMarker("Set the speed at which the camera will move when the Left or Right Control key is pressed whilst moving."); - ImGui.SameLine(); - } - if (ImGui.SliderFloat("Map camera speed (fast)", - ref MsbEditor.Viewport.WorldView.CameraMoveSpeed_Fast, 0.1f, 999.0f)) - { - CFG.Current.GFX_Camera_MoveSpeed_Fast = MsbEditor.Viewport.WorldView.CameraMoveSpeed_Fast; - } - } - - if (ImGui.CollapsingHeader("Limits")) - { - if (CFG.Current.ShowUITooltips) - { - ShowHelpMarker("Reset the values within this section to their default values."); - ImGui.SameLine(); - } - if (ImGui.Button("Reset##MapLimits")) - { - CFG.Current.GFX_Limit_Renderables = CFG.Default.GFX_Limit_Renderables; - CFG.Current.GFX_Limit_Buffer_Indirect_Draw = CFG.Default.GFX_Limit_Buffer_Indirect_Draw; - CFG.Current.GFX_Limit_Buffer_Flver_Bone = CFG.Default.GFX_Limit_Buffer_Flver_Bone; - } - - ImGui.Text("Please restart the program for changes to take effect."); - - ImGui.TextColored(new Vector4(1.0f, 0.0f, 0.0f, 1.0f), - @"Try smaller increments (+25%%) at first, as high values will cause issues."); - - if (CFG.Current.ShowUITooltips) - { - ShowHelpMarker("This value constrains the number of renderable entities that are allowed. Exceeding this value will throw an exception."); - ImGui.SameLine(); - } - if (ImGui.InputInt("Renderables", ref CFG.Current.GFX_Limit_Renderables, 0, 0)) - { - if (CFG.Current.GFX_Limit_Renderables < CFG.Default.GFX_Limit_Renderables) - { - CFG.Current.GFX_Limit_Renderables = CFG.Default.GFX_Limit_Renderables; - } - } - - if (CFG.Current.ShowUITooltips) - { - ShowHelpMarker("This value constrains the size of the indirect draw buffer. Exceeding this value will throw an exception."); - ImGui.SameLine(); - } - Utils.ImGui_InputUint("Indirect Draw buffer", ref CFG.Current.GFX_Limit_Buffer_Indirect_Draw); - - if (CFG.Current.ShowUITooltips) - { - ShowHelpMarker("This value constrains the size of the FLVER bone buffer. Exceeding this value will throw an exception."); - ImGui.SameLine(); - } - Utils.ImGui_InputUint("FLVER Bone buffer", ref CFG.Current.GFX_Limit_Buffer_Flver_Bone); - } - - if (FeatureFlags.ViewportGrid) - { - if (ImGui.CollapsingHeader("Grid")) - { - if (CFG.Current.ShowUITooltips) - { - ShowHelpMarker("Enable the viewport grid when in the Map Editor."); - ImGui.SameLine(); - } - ImGui.Checkbox("Enable viewport grid", ref CFG.Current.Map_EnableViewportGrid); - - if (CFG.Current.ShowUITooltips) - { - ShowHelpMarker("The overall maximum size of the grid.\nThe grid will only update upon restarting DSMS after changing this value."); - ImGui.SameLine(); - } - ImGui.SliderInt("Grid size", ref CFG.Current.Map_ViewportGrid_TotalSize, 100, 1000); - - if (CFG.Current.ShowUITooltips) - { - ShowHelpMarker("The increment size of the grid."); - ImGui.SameLine(); - } - ImGui.SliderInt("Grid increment", ref CFG.Current.Map_ViewportGrid_IncrementSize, 1, 100); - - if (CFG.Current.ShowUITooltips) - { - ShowHelpMarker("The height at which the horizontal grid sits."); - ImGui.SameLine(); - } - ImGui.SliderFloat("Grid height", ref CFG.Current.Map_ViewportGrid_Offset, -1000, 1000); - - if (CFG.Current.ShowUITooltips) - { - ShowHelpMarker("The amount to lower or raise the viewport grid height via the shortcuts."); - ImGui.SameLine(); - } - ImGui.SliderFloat("Grid height increment", ref CFG.Current.Map_ViewportGrid_ShortcutIncrement, 0.1f, 100); - - ImGui.ColorEdit3("Grid color", ref CFG.Current.GFX_Viewport_Grid_Color); - - if (CFG.Current.ShowUITooltips) - { - ShowHelpMarker("Resets all of the values within this section to their default values."); - ImGui.SameLine(); - } - if (ImGui.Button("Reset")) - { - CFG.Current.GFX_Viewport_Grid_Color = Utils.GetDecimalColor(Color.Red); - CFG.Current.Map_ViewportGrid_TotalSize = 1000; - CFG.Current.Map_ViewportGrid_IncrementSize = 10; - CFG.Current.Map_ViewportGrid_Offset = 0; - } - } - } - - if (ImGui.CollapsingHeader("Wireframes")) - { - if (CFG.Current.ShowUITooltips) - { - ShowHelpMarker("Resets all of the values within this section to their default values."); - ImGui.SameLine(); - } - if (ImGui.Button("Reset")) - { - // Proxies - CFG.Current.GFX_Renderable_Box_BaseColor = Utils.GetDecimalColor(Color.Blue); - CFG.Current.GFX_Renderable_Box_HighlightColor = Utils.GetDecimalColor(Color.DarkViolet); - - CFG.Current.GFX_Renderable_Cylinder_BaseColor = Utils.GetDecimalColor(Color.Blue); - CFG.Current.GFX_Renderable_Cylinder_HighlightColor = Utils.GetDecimalColor(Color.DarkViolet); - - CFG.Current.GFX_Renderable_Sphere_BaseColor = Utils.GetDecimalColor(Color.Blue); - CFG.Current.GFX_Renderable_Sphere_HighlightColor = Utils.GetDecimalColor(Color.DarkViolet); - - CFG.Current.GFX_Renderable_Point_BaseColor = Utils.GetDecimalColor(Color.Yellow); - CFG.Current.GFX_Renderable_Point_HighlightColor = Utils.GetDecimalColor(Color.DarkViolet); - - CFG.Current.GFX_Renderable_DummyPoly_BaseColor = Utils.GetDecimalColor(Color.Yellow); - CFG.Current.GFX_Renderable_DummyPoly_HighlightColor = Utils.GetDecimalColor(Color.DarkViolet); - - CFG.Current.GFX_Renderable_BonePoint_BaseColor = Utils.GetDecimalColor(Color.Blue); - CFG.Current.GFX_Renderable_BonePoint_HighlightColor = Utils.GetDecimalColor(Color.DarkViolet); - - CFG.Current.GFX_Renderable_ModelMarker_Chr_BaseColor = Utils.GetDecimalColor(Color.Firebrick); - CFG.Current.GFX_Renderable_ModelMarker_Chr_HighlightColor = Utils.GetDecimalColor(Color.Tomato); - - CFG.Current.GFX_Renderable_ModelMarker_Object_BaseColor = Utils.GetDecimalColor(Color.MediumVioletRed); - CFG.Current.GFX_Renderable_ModelMarker_Object_HighlightColor = Utils.GetDecimalColor(Color.DeepPink); - - CFG.Current.GFX_Renderable_ModelMarker_Player_BaseColor = Utils.GetDecimalColor(Color.DarkOliveGreen); - CFG.Current.GFX_Renderable_ModelMarker_Player_HighlightColor = Utils.GetDecimalColor(Color.OliveDrab); - - CFG.Current.GFX_Renderable_ModelMarker_Other_BaseColor = Utils.GetDecimalColor(Color.Wheat); - CFG.Current.GFX_Renderable_ModelMarker_Other_HighlightColor = Utils.GetDecimalColor(Color.AntiqueWhite); - - CFG.Current.GFX_Renderable_PointLight_BaseColor = Utils.GetDecimalColor(Color.YellowGreen); - CFG.Current.GFX_Renderable_PointLight_HighlightColor = Utils.GetDecimalColor(Color.Yellow); - - CFG.Current.GFX_Renderable_SpotLight_BaseColor = Utils.GetDecimalColor(Color.Goldenrod); - CFG.Current.GFX_Renderable_SpotLight_HighlightColor = Utils.GetDecimalColor(Color.Violet); - - CFG.Current.GFX_Renderable_DirectionalLight_BaseColor = Utils.GetDecimalColor(Color.Cyan); - CFG.Current.GFX_Renderable_DirectionalLight_HighlightColor = Utils.GetDecimalColor(Color.AliceBlue); - - // Gizmos - CFG.Current.GFX_Gizmo_X_BaseColor = new Vector3(0.952f, 0.211f, 0.325f); - CFG.Current.GFX_Gizmo_X_HighlightColor = new Vector3(1.0f, 0.4f, 0.513f); - - CFG.Current.GFX_Gizmo_Y_BaseColor = new Vector3(0.525f, 0.784f, 0.082f); - CFG.Current.GFX_Gizmo_Y_HighlightColor = new Vector3(0.713f, 0.972f, 0.270f); - - CFG.Current.GFX_Gizmo_Z_BaseColor = new Vector3(0.219f, 0.564f, 0.929f); - CFG.Current.GFX_Gizmo_Z_HighlightColor = new Vector3(0.407f, 0.690f, 1.0f); - - // Color Variance - CFG.Current.GFX_Wireframe_Color_Variance = CFG.Default.GFX_Wireframe_Color_Variance; - } - - ImGui.SliderFloat("Wireframe color variance", ref CFG.Current.GFX_Wireframe_Color_Variance, 0.0f, 1.0f); - - // Proxies - ImGui.ColorEdit3("Box region - base color", ref CFG.Current.GFX_Renderable_Box_BaseColor); - ImGui.ColorEdit3("Box region - highlight color", ref CFG.Current.GFX_Renderable_Box_HighlightColor); - - ImGui.ColorEdit3("Cylinder region - base color", ref CFG.Current.GFX_Renderable_Cylinder_BaseColor); - ImGui.ColorEdit3("Cylinder region - highlight color", ref CFG.Current.GFX_Renderable_Cylinder_HighlightColor); - - ImGui.ColorEdit3("Sphere region - base color", ref CFG.Current.GFX_Renderable_Sphere_BaseColor); - ImGui.ColorEdit3("Sphere region - highlight color", ref CFG.Current.GFX_Renderable_Sphere_HighlightColor); - - ImGui.ColorEdit3("Point region - base color", ref CFG.Current.GFX_Renderable_Point_BaseColor); - ImGui.ColorEdit3("Point region - highlight color", ref CFG.Current.GFX_Renderable_Point_HighlightColor); - - ImGui.ColorEdit3("Dummy poly - base color", ref CFG.Current.GFX_Renderable_DummyPoly_BaseColor); - ImGui.ColorEdit3("Dummy poly - highlight color", ref CFG.Current.GFX_Renderable_DummyPoly_HighlightColor); - - ImGui.ColorEdit3("Bone point - base color", ref CFG.Current.GFX_Renderable_BonePoint_BaseColor); - ImGui.ColorEdit3("Bone point - highlight color", ref CFG.Current.GFX_Renderable_BonePoint_HighlightColor); - - ImGui.ColorEdit3("Chr marker - base color", ref CFG.Current.GFX_Renderable_ModelMarker_Chr_BaseColor); - ImGui.ColorEdit3("Chr marker - highlight color", ref CFG.Current.GFX_Renderable_ModelMarker_Chr_HighlightColor); - - ImGui.ColorEdit3("Object marker - base color", ref CFG.Current.GFX_Renderable_ModelMarker_Object_BaseColor); - ImGui.ColorEdit3("Object marker - highlight color", ref CFG.Current.GFX_Renderable_ModelMarker_Object_HighlightColor); - - ImGui.ColorEdit3("Player marker - base color", ref CFG.Current.GFX_Renderable_ModelMarker_Player_BaseColor); - ImGui.ColorEdit3("Player marker - highlight color", ref CFG.Current.GFX_Renderable_ModelMarker_Player_HighlightColor); - - ImGui.ColorEdit3("Other marker - base color", ref CFG.Current.GFX_Renderable_ModelMarker_Other_BaseColor); - ImGui.ColorEdit3("Other marker - highlight color", ref CFG.Current.GFX_Renderable_ModelMarker_Other_HighlightColor); - - ImGui.ColorEdit3("Point light - base color", ref CFG.Current.GFX_Renderable_PointLight_BaseColor); - ImGui.ColorEdit3("Point light - highlight color", ref CFG.Current.GFX_Renderable_PointLight_HighlightColor); - - ImGui.ColorEdit3("Spot light - base color", ref CFG.Current.GFX_Renderable_SpotLight_BaseColor); - ImGui.ColorEdit3("Spot light - highlight color", ref CFG.Current.GFX_Renderable_SpotLight_HighlightColor); - - ImGui.ColorEdit3("Directional light - base color", ref CFG.Current.GFX_Renderable_DirectionalLight_BaseColor); - ImGui.ColorEdit3("Directional light - highlight color", ref CFG.Current.GFX_Renderable_DirectionalLight_HighlightColor); - - // Gizmos - ImGui.ColorEdit3("Gizmo - X Axis - base color", ref CFG.Current.GFX_Gizmo_X_BaseColor); - ImGui.ColorEdit3("Gizmo - X Axis - highlight color", ref CFG.Current.GFX_Gizmo_X_HighlightColor); - - ImGui.ColorEdit3("Gizmo - Y Axis - base color", ref CFG.Current.GFX_Gizmo_Y_BaseColor); - ImGui.ColorEdit3("Gizmo - Y Axis - highlight color", ref CFG.Current.GFX_Gizmo_Y_HighlightColor); - - ImGui.ColorEdit3("Gizmo - Z Axis - base color", ref CFG.Current.GFX_Gizmo_Z_BaseColor); - ImGui.ColorEdit3("Gizmo - Z Axis - highlight color", ref CFG.Current.GFX_Gizmo_Z_HighlightColor); - } - - if (ImGui.CollapsingHeader("Map Object Display Presets")) - { - ImGui.Text("Configure each of the six display presets available."); - - if (CFG.Current.ShowUITooltips) - { - ShowHelpMarker("Reset the values within this section to their default values."); - ImGui.SameLine(); - } - if (ImGui.Button("Reset##DisplayPresets")) - { - CFG.Current.SceneFilter_Preset_01.Name = CFG.Default.SceneFilter_Preset_01.Name; - CFG.Current.SceneFilter_Preset_01.Filters = CFG.Default.SceneFilter_Preset_01.Filters; - CFG.Current.SceneFilter_Preset_02.Name = CFG.Default.SceneFilter_Preset_02.Name; - CFG.Current.SceneFilter_Preset_02.Filters = CFG.Default.SceneFilter_Preset_02.Filters; - CFG.Current.SceneFilter_Preset_03.Name = CFG.Default.SceneFilter_Preset_03.Name; - CFG.Current.SceneFilter_Preset_03.Filters = CFG.Default.SceneFilter_Preset_03.Filters; - CFG.Current.SceneFilter_Preset_04.Name = CFG.Default.SceneFilter_Preset_04.Name; - CFG.Current.SceneFilter_Preset_04.Filters = CFG.Default.SceneFilter_Preset_04.Filters; - CFG.Current.SceneFilter_Preset_05.Name = CFG.Default.SceneFilter_Preset_05.Name; - CFG.Current.SceneFilter_Preset_05.Filters = CFG.Default.SceneFilter_Preset_05.Filters; - CFG.Current.SceneFilter_Preset_06.Name = CFG.Default.SceneFilter_Preset_06.Name; - CFG.Current.SceneFilter_Preset_06.Filters = CFG.Default.SceneFilter_Preset_06.Filters; - } - - SettingsRenderFilterPresetEditor(CFG.Current.SceneFilter_Preset_01); - SettingsRenderFilterPresetEditor(CFG.Current.SceneFilter_Preset_02); - SettingsRenderFilterPresetEditor(CFG.Current.SceneFilter_Preset_03); - SettingsRenderFilterPresetEditor(CFG.Current.SceneFilter_Preset_04); - SettingsRenderFilterPresetEditor(CFG.Current.SceneFilter_Preset_05); - SettingsRenderFilterPresetEditor(CFG.Current.SceneFilter_Preset_06); - } - - ImGui.Unindent(); - ImGui.EndTabItem(); - } - } - - private void DisplaySettings_ModelEditor() - { - if (ImGui.BeginTabItem("Model Editor")) - { - if (ImGui.CollapsingHeader("General", ImGuiTreeNodeFlags.DefaultOpen)) - { - - } - - ImGui.EndTabItem(); - } - } - - private void DisplaySettings_ParamEditor() - { - if (ImGui.BeginTabItem("Param Editor")) - { - if (ImGui.CollapsingHeader("General", ImGuiTreeNodeFlags.DefaultOpen)) - { - if (CFG.Current.ShowUITooltips) - { - ShowHelpMarker("Reduces the line height within the the Param Editor screen."); - ImGui.SameLine(); - } - ImGui.Checkbox("Use compact param editor", ref CFG.Current.UI_CompactParams); - - if (CFG.Current.ShowUITooltips) - { - ShowHelpMarker("Show additional options within the MassEdit context menu."); - ImGui.SameLine(); - } - ImGui.Checkbox("Show advanced massedit options", ref CFG.Current.Param_AdvancedMassedit); - - if (CFG.Current.ShowUITooltips) - { - ShowHelpMarker("Show the shortcut tools in the right-click context menu."); - ImGui.SameLine(); - } - ImGui.Checkbox("Show shortcut tools in context menus", ref CFG.Current.Param_ShowHotkeysInContextMenu); - } - - if (ImGui.CollapsingHeader("Params")) - { - if (CFG.Current.ShowUITooltips) - { - ShowHelpMarker("Sort the Param View list alphabetically."); - ImGui.SameLine(); - } - if (ImGui.Checkbox("Sort params alphabetically", ref CFG.Current.Param_AlphabeticalParams)) - { - UICache.ClearCaches(); - } - } - - if (ImGui.CollapsingHeader("Rows")) - { - if (CFG.Current.ShowUITooltips) - { - ShowHelpMarker("Disable the row names from wrapping within the Row View list."); - ImGui.SameLine(); - } - ImGui.Checkbox("Disable line wrapping", ref CFG.Current.Param_DisableLineWrapping); - - if (CFG.Current.ShowUITooltips) - { - ShowHelpMarker("Disable the grouping of connected rows in certain params, such as ItemLotParam within the Row View list."); - ImGui.SameLine(); - } - ImGui.Checkbox("Disable row grouping", ref CFG.Current.Param_DisableRowGrouping); - } - - if (ImGui.CollapsingHeader("Fields")) - { - if (CFG.Current.ShowUITooltips) - { - ShowHelpMarker("Crowd-sourced names will appear before the canonical name in the Field View list."); - ImGui.SameLine(); - } - ImGui.Checkbox("Show community field names first", ref CFG.Current.Param_MakeMetaNamesPrimary); - - if (CFG.Current.ShowUITooltips) - { - ShowHelpMarker("The crowd-sourced name (or the canonical name if the above option is enabled) will appear after the initial name in the Field View list."); - ImGui.SameLine(); - } - ImGui.Checkbox("Show secondary field names", ref CFG.Current.Param_ShowSecondaryNames); - - if (CFG.Current.ShowUITooltips) - { - ShowHelpMarker("The field offset within the .PARAM file will be show to the left in the Field View List."); - ImGui.SameLine(); - } - ImGui.Checkbox("Show field data offsets", ref CFG.Current.Param_ShowFieldOffsets); - - if (CFG.Current.ShowUITooltips) - { - ShowHelpMarker("Hide the generated param references for fields that link to other params."); - ImGui.SameLine(); - } - ImGui.Checkbox("Hide field references", ref CFG.Current.Param_HideReferenceRows); - - if (CFG.Current.ShowUITooltips) - { - ShowHelpMarker("Hide the crowd-sourced namelist for index-based enum fields."); - ImGui.SameLine(); - } - ImGui.Checkbox("Hide field enums", ref CFG.Current.Param_HideEnums); - - if (CFG.Current.ShowUITooltips) - { - ShowHelpMarker("Allow the field order to be changed by an alternative order as defined within the Paramdex META file."); - ImGui.SameLine(); - } - ImGui.Checkbox("Allow field reordering", ref CFG.Current.Param_AllowFieldReorder); - } - - ImGui.EndTabItem(); - } - } - - private void DisplaySettings_TextEditor() - { - if (ImGui.BeginTabItem("Text Editor")) - { - if (ImGui.CollapsingHeader("General", ImGuiTreeNodeFlags.DefaultOpen)) - { - if (CFG.Current.ShowUITooltips) - { - ShowHelpMarker("Show the original FMG file names within the Text Editor file list."); - ImGui.SameLine(); - } - ImGui.Checkbox("Show original FMG names", ref CFG.Current.FMG_ShowOriginalNames); - - if (CFG.Current.ShowUITooltips) - { - ShowHelpMarker("If enabled then FMG entries will not be grouped automatically."); - ImGui.SameLine(); - } - if (ImGui.Checkbox("Separate related FMGs and entries", ref CFG.Current.FMG_NoGroupedFmgEntries)) - { - TextEditor.OnProjectChanged(ProjSettings); - } - - if (CFG.Current.ShowUITooltips) - { - ShowHelpMarker("If enabled then FMG files added from DLCs will not be grouped with vanilla FMG files."); - ImGui.SameLine(); - } - if (ImGui.Checkbox("Separate patch FMGs", ref CFG.Current.FMG_NoFmgPatching)) - { - TextEditor.OnProjectChanged(ProjSettings); - } - } - - ImGui.EndTabItem(); - } - } - private void DisplaySettings_Keybinds() { if (ImGui.BeginTabItem("Keybinds")) @@ -905,20 +243,20 @@ private void DisplaySettings_AssetBrowser() if (ImGui.CollapsingHeader("General", ImGuiTreeNodeFlags.DefaultOpen)) { ImGui.Checkbox("Display aliases in browser list", ref CFG.Current.AssetBrowser_ShowAliasesInBrowser); - ImguiUtils.ShowHoverTooltip("Show the aliases for each entry within the browser list as part of their displayed name."); + Editor.EditorDecorations.ShowHoverTooltip("Show the aliases for each entry within the browser list as part of their displayed name."); ImGui.Checkbox("Display tags in browser list", ref CFG.Current.AssetBrowser_ShowTagsInBrowser); - ImguiUtils.ShowHoverTooltip("Show the tags for each entry within the browser list as part of their displayed name."); + Editor.EditorDecorations.ShowHoverTooltip("Show the tags for each entry within the browser list as part of their displayed name."); ImGui.Checkbox("Display low-detail parts in browser list", ref CFG.Current.AssetBrowser_ShowLowDetailParts); - ImguiUtils.ShowHoverTooltip("Show the _l (low-detail) part entries in the Model Editor instance of the Asset Browser."); + Editor.EditorDecorations.ShowHoverTooltip("Show the _l (low-detail) part entries in the Model Editor instance of the Asset Browser."); } ImGui.EndTabItem(); } } - public void Display() + public void Display(IEnumerable editorScreens) { var scale = MapStudioNew.GetUIScale(); if (!MenuOpenState) @@ -942,10 +280,14 @@ public void Display() // Settings Order DisplaySettings_System(); DisplaySettings_AssetBrowser(); - DisplaySettings_MapEditor(); - //DisplaySettings_ModelEditor(); - DisplaySettings_ParamEditor(); - DisplaySettings_TextEditor(); + foreach (EditorScreen scr in editorScreens) + { + if (ImGui.BeginTabItem(scr.EditorName)) + { + scr.SettingsMenu(); + ImGui.EndTabItem(); + } + } DisplaySettings_Keybinds(); ImGui.PopItemWidth(); @@ -958,57 +300,4 @@ public void Display() ImGui.PopStyleVar(3); ImGui.PopStyleColor(2); } - - public void ShowHelpMarker(string desc) - { - ImGui.TextDisabled("(?)"); - if (ImGui.IsItemHovered(0)) - { - ImGui.BeginTooltip(); - ImGui.PushTextWrapPos(450.0f); - ImGui.TextUnformatted(desc); - ImGui.PopTextWrapPos(); - ImGui.EndTooltip(); - } - } - - private void SettingsRenderFilterPresetEditor(CFG.RenderFilterPreset preset) - { - ImGui.PushID($"{preset.Name}##PresetEdit"); - if (ImGui.CollapsingHeader($"{preset.Name}##Header")) - { - ImGui.Indent(); - var nameInput = preset.Name; - ImGui.InputText("Preset Name", ref nameInput, 32); - if (ImGui.IsItemDeactivatedAfterEdit()) - { - preset.Name = nameInput; - } - - foreach (RenderFilter e in Enum.GetValues(typeof(RenderFilter))) - { - var ticked = false; - if (preset.Filters.HasFlag(e)) - { - ticked = true; - } - - if (ImGui.Checkbox(e.ToString(), ref ticked)) - { - if (ticked) - { - preset.Filters |= e; - } - else - { - preset.Filters &= ~e; - } - } - } - - ImGui.Unindent(); - } - - ImGui.PopID(); - } } diff --git a/src/StudioCore/StudioResource.cs b/src/StudioCore/StudioResource.cs new file mode 100644 index 000000000..471c8d2e8 --- /dev/null +++ b/src/StudioCore/StudioResource.cs @@ -0,0 +1,82 @@ +using StudioCore.Editor; +using System.Collections.Generic; + +namespace StudioCore; + +/// +/// Class that stores a collection of mapstudio data independent of a given project +/// +public abstract class StudioResource +{ + public GameType GameType; + public readonly string nameForUI; + + public StudioResource(GameType gameType, string name) + { + GameType = gameType; + nameForUI = name; + } + + public bool IsLoaded { get; private set; } + public bool IsLoading { get; private set; } + + private void Load(Project project) + { + if (IsLoaded || IsLoading) + return; + // Locking on this isn't ideal if anything else could lock the object. But we don't have Lock yet. + lock (this) + { + IsLoading = true; + List tasks = new(); + foreach (StudioResource res in GetDependencies(project)) + { + if (!res.IsLoaded) + { + TaskManager.LiveTask t = new TaskManager.LiveTask(res.GetTaskName(), TaskManager.RequeueType.None, true, () => { + res.Load(project); + }); + t = TaskManager.Run(t); + tasks.Add(t); + } + } + foreach (TaskManager.LiveTask t in tasks) + { + if (!t.Task.IsCompleted) + t.Task.Wait(); + } + Load(); + IsLoaded = true; + IsLoading = false; + } + } + + public virtual string GetTaskName() + { + return $@"Resource - Loading {nameForUI}"; + } + protected abstract void Load(); + protected abstract IEnumerable GetDependencies(Project project); + + public static bool AreResourcesLoaded(IEnumerable res) + { + foreach (StudioResource r in res) + { + if (!r.IsLoaded) + return false; + } + return true; + } + public static void Load(Project project, IEnumerable resources) + { + foreach (StudioResource res in resources) + { + if (!res.IsLoaded) + { + TaskManager.Run(new TaskManager.LiveTask(res.GetTaskName(), TaskManager.RequeueType.None, true, () => { + res.Load(project); + })); + } + } + } +} diff --git a/src/StudioCore/Tests/BTLTests.cs b/src/StudioCore/Tests/BTLTests.cs index 4c614f567..243036e86 100644 --- a/src/StudioCore/Tests/BTLTests.cs +++ b/src/StudioCore/Tests/BTLTests.cs @@ -11,7 +11,7 @@ public static class BTLReadWrite { public static bool Run(AssetLocator locator) { - List msbs = locator.GetFullMapList(); + List msbs = Locator.ActiveProject.MSBBank.GetFullMapList(); List floats = new(); List noWrite = new(); List ver = new(); diff --git a/src/StudioCore/Tests/GlyphCatcher.cs b/src/StudioCore/Tests/GlyphCatcher.cs index bdcf3f1b6..76e4a5ec8 100644 --- a/src/StudioCore/Tests/GlyphCatcher.cs +++ b/src/StudioCore/Tests/GlyphCatcher.cs @@ -34,12 +34,12 @@ private static void WriteToFile(HashSet chars) /// public static unsafe void CheckMSB(AssetLocator locator) { - var maps = locator.GetFullMapList(); + var maps = Locator.ActiveProject.MSBBank.GetFullMapList(); HashSet msbChars = new(); foreach (var mapName in maps) { IMsb msb = null; - var path = locator.GetMapMSB(mapName).AssetPath; + var path = Locator.ActiveProject.MSBBank.GetMapMSB(mapName).AssetPath; switch (locator.Type) { diff --git a/src/StudioCore/Tests/MSBReadWrite.cs b/src/StudioCore/Tests/MSBReadWrite.cs index 328d81fc2..552bd7bb9 100644 --- a/src/StudioCore/Tests/MSBReadWrite.cs +++ b/src/StudioCore/Tests/MSBReadWrite.cs @@ -9,10 +9,10 @@ public static class MSBReadWrite { public static bool Run(AssetLocator locator) { - List msbs = locator.GetFullMapList(); + List msbs = Locator.ActiveProject.MSBBank.GetFullMapList(); foreach (var msb in msbs) { - AssetDescription path = locator.GetMapMSB(msb); + AssetDescription path = Locator.ActiveProject.MSBBank.GetMapMSB(msb); var bytes = File.ReadAllBytes(path.AssetPath); Memory decompressed = DCX.Decompress(bytes); MSBE m = MSBE.Read(decompressed); diff --git a/src/StudioCore/Tests/MSB_AC6_Read_Write.cs b/src/StudioCore/Tests/MSB_AC6_Read_Write.cs index ec5e8cd7f..a8959f786 100644 --- a/src/StudioCore/Tests/MSB_AC6_Read_Write.cs +++ b/src/StudioCore/Tests/MSB_AC6_Read_Write.cs @@ -8,7 +8,7 @@ public static class MSB_AC6_Read_Write { public static bool Run(AssetLocator locator) { - List msbs = locator.GetFullMapList(); + List msbs = Locator.ActiveProject.MSBBank.GetFullMapList(); // m00_90_00_00 @@ -16,7 +16,7 @@ public static bool Run(AssetLocator locator) { if (msb == "m00_90_00_00") { - AssetDescription path = locator.GetMapMSB(msb); + AssetDescription path = Locator.ActiveProject.MSBBank.GetMapMSB(msb); var bytes = File.ReadAllBytes(path.AssetPath); Memory decompressed = DCX.Decompress(bytes); MSB_AC6 m = MSB_AC6.Read(decompressed); diff --git a/src/StudioCore/TextEditor/FMGAction.cs b/src/StudioCore/TextEditor/FMGAction.cs new file mode 100644 index 000000000..f71c15c1f --- /dev/null +++ b/src/StudioCore/TextEditor/FMGAction.cs @@ -0,0 +1,58 @@ +using Andre.Formats; +using StudioCore.ParamEditor; +using StudioCore.TextEditor; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; + +namespace StudioCore.Editor; + +public class DuplicateFMGEntryAction : EditorAction +{ + private readonly FMGEntryGroup EntryGroup; + private FMGEntryGroup NewEntryGroup; + + public DuplicateFMGEntryAction(FMGEntryGroup entryGroup) + { + EntryGroup = entryGroup; + } + + public override ActionEvent Execute() + { + NewEntryGroup = EntryGroup.DuplicateFMGEntries(); + NewEntryGroup.SetNextUnusedID(); + return ActionEvent.NoEvent; + } + + public override ActionEvent Undo() + { + NewEntryGroup.DeleteEntries(); + return ActionEvent.NoEvent; + } +} + +public class DeleteFMGEntryAction : EditorAction +{ + private FMGEntryGroup BackupEntryGroup = new(); + private FMGEntryGroup EntryGroup; + + public DeleteFMGEntryAction(FMGEntryGroup entryGroup) + { + EntryGroup = entryGroup; + } + + public override ActionEvent Execute() + { + BackupEntryGroup = EntryGroup.CloneEntryGroup(); + EntryGroup.DeleteEntries(); + return ActionEvent.NoEvent; + } + + public override ActionEvent Undo() + { + EntryGroup = BackupEntryGroup; + EntryGroup.ImplementEntryGroup(); + return ActionEvent.NoEvent; + } +} diff --git a/src/StudioCore/TextEditor/FMGBank.cs b/src/StudioCore/TextEditor/FMGBank.cs index caf2af43b..93ee7e9df 100644 --- a/src/StudioCore/TextEditor/FMGBank.cs +++ b/src/StudioCore/TextEditor/FMGBank.cs @@ -551,11 +551,11 @@ private void SaveFMGsNormal() /// /// Class that stores all the strings for a Souls project. /// -public class FMGBank +public class FMGBank : DataBank { public Project Project; - public FMGBank(Project project) + public FMGBank(Project project) : base(project, "FMGs") { Project = project; } @@ -611,9 +611,9 @@ internal static string RemovePatchStrings(string str) return str; } - public static void ReloadFMGs() + protected override void Load() { - Locator.ActiveProject.FMGBank.LoadFMGs(); + LoadFMGs(); } public void LoadFMGs(string languageFolder = "") { @@ -646,8 +646,8 @@ public void LoadFMGs(string languageFolder = "") fmgLangs.Add(lang.LanguageFolder, lang); })); } - - public void SaveFMGs() + + public override void Save() { foreach (FMGLanguage lang in fmgLangs.Values) { @@ -795,6 +795,11 @@ public FMGEntryGroup GenerateEntryGroup(int id, FMGInfo fmgInfo) return eGroup; } + + protected override IEnumerable GetDependencies(Project project) + { + return []; + } } /// diff --git a/src/StudioCore/TextEditor/TextCFG.cs b/src/StudioCore/TextEditor/TextCFG.cs new file mode 100644 index 000000000..8788114af --- /dev/null +++ b/src/StudioCore/TextEditor/TextCFG.cs @@ -0,0 +1,17 @@ +using StudioCore.Platform; +using StudioCore.Renderer.Scene; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.IO; +using System.Numerics; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace StudioCore; +public partial class CFG +{ + public bool FMG_NoFmgPatching = false; + public bool FMG_NoGroupedFmgEntries = false; + public bool FMG_ShowOriginalNames = false; +} diff --git a/src/StudioCore/TextEditor/TextEditorScreen.cs b/src/StudioCore/TextEditor/TextEditorScreen.cs index 6bff6cc73..92bced791 100644 --- a/src/StudioCore/TextEditor/TextEditorScreen.cs +++ b/src/StudioCore/TextEditor/TextEditorScreen.cs @@ -295,12 +295,12 @@ public void OnProjectChanged(ProjectSettings newSettings) public void Save() { - Locator.ActiveProject.FMGBank.SaveFMGs(); + Locator.ActiveProject.FMGBank.Save(); } public void SaveAll() { - Locator.ActiveProject.FMGBank.SaveFMGs(); + Locator.ActiveProject.FMGBank.Save(); } private void ClearTextEditorCache() @@ -770,4 +770,32 @@ private void ChangeLanguage(string path) ResetActionManager(); Locator.ActiveProject.FMGBank.LoadFMGs(path); } + + IEnumerable EditorScreen.GetDependencies(Project project) + { + return [project.FMGBank]; + } + + public void SettingsMenu() + { + if (ImGui.CollapsingHeader("General", ImGuiTreeNodeFlags.DefaultOpen)) + { + EditorDecorations.ShowHelpMarker("Show the original FMG file names within the Text Editor file list."); + ImGui.Checkbox("Show original FMG names", ref CFG.Current.FMG_ShowOriginalNames); + + EditorDecorations.ShowHelpMarker("If enabled then FMG entries will not be grouped automatically."); + if (ImGui.Checkbox("Separate related FMGs and entries", ref CFG.Current.FMG_NoGroupedFmgEntries)) + { + //This is still ghastly + OnProjectChanged(_projectSettings); + } + + EditorDecorations.ShowHelpMarker("If enabled then FMG files added from DLCs will not be grouped with vanilla FMG files."); + if (ImGui.Checkbox("Separate patch FMGs", ref CFG.Current.FMG_NoFmgPatching)) + { + //no really this has to go + OnProjectChanged(_projectSettings); + } + } + } } diff --git a/src/StudioCore/EulerUtils.cs b/src/StudioCore/Utilities/EulerUtils.cs similarity index 99% rename from src/StudioCore/EulerUtils.cs rename to src/StudioCore/Utilities/EulerUtils.cs index c879e5bb6..b13390912 100644 --- a/src/StudioCore/EulerUtils.cs +++ b/src/StudioCore/Utilities/EulerUtils.cs @@ -1,7 +1,7 @@ using System; using System.Numerics; -namespace StudioCore; +namespace StudioCore.Utilities; public static class EulerUtils { diff --git a/src/StudioCore/ForkAwesomFont.cs b/src/StudioCore/Utilities/ForkAwesomFont.cs similarity index 99% rename from src/StudioCore/ForkAwesomFont.cs rename to src/StudioCore/Utilities/ForkAwesomFont.cs index 6f62a5056..5500b611c 100644 --- a/src/StudioCore/ForkAwesomFont.cs +++ b/src/StudioCore/Utilities/ForkAwesomFont.cs @@ -2,7 +2,7 @@ // from https://raw.githubusercontent.com/ForkAwesome/Fork-Awesome/master/src/icons/icons.yml // for use with https://github.com/ForkAwesome/Fork-Awesome/blob/master/fonts/forkawesome-webfont.ttf -namespace StudioCore; +namespace StudioCore.Utilities; public class ForkAwesome { diff --git a/src/StudioCore/Utilities/MapValidationTest.cs b/src/StudioCore/Utilities/MapValidationTest.cs index c9fe0b83a..324fd8c8b 100644 --- a/src/StudioCore/Utilities/MapValidationTest.cs +++ b/src/StudioCore/Utilities/MapValidationTest.cs @@ -32,7 +32,7 @@ public static void ValidateMSB() if (entry.Contains(".msb.dcx")) { var name = Path.GetFileNameWithoutExtension(Path.GetFileNameWithoutExtension(entry)); - AssetDescription ad = Locator.ActiveProject.AssetLocator.GetMapMSB(name); + AssetDescription ad = Locator.ActiveProject.MSBBank.GetMapMSB(name); if (ad.AssetPath != null) { resMaps.Add(ad); diff --git a/src/StudioCore/Utilities/ParamValidationTest.cs b/src/StudioCore/Utilities/ParamValidationTest.cs index 7271b98a0..5775c7f41 100644 --- a/src/StudioCore/Utilities/ParamValidationTest.cs +++ b/src/StudioCore/Utilities/ParamValidationTest.cs @@ -77,7 +77,7 @@ public static void ValidatePaddingForParam(string selectedParamName) public static void ValidateParamdef() { // Read params from regulation.bin via SF PARAM impl - _paramdefs = ParamBank.PrimaryBank.GetParamDefs(); + _paramdefs = ResDirectory.CurrentGame.ParamDefBank.GetParamDefs(); var dir = Locator.ActiveProject.ParentProject.AssetLocator.RootDirectory; var mod = Locator.ActiveProject.AssetLocator.RootDirectory; diff --git a/src/StudioCore/StructExtensions.cs b/src/StudioCore/Utilities/StructExtensions.cs similarity index 84% rename from src/StudioCore/StructExtensions.cs rename to src/StudioCore/Utilities/StructExtensions.cs index 1d407f396..6b4bf891d 100644 --- a/src/StudioCore/StructExtensions.cs +++ b/src/StudioCore/Utilities/StructExtensions.cs @@ -1,6 +1,6 @@ using System.Numerics; -namespace StudioCore; +namespace StudioCore.Utilities; public static class StructExtensions { diff --git a/src/StudioCore/Transform.cs b/src/StudioCore/Utilities/Transform.cs similarity index 99% rename from src/StudioCore/Transform.cs rename to src/StudioCore/Utilities/Transform.cs index e02ada0a8..6ec265510 100644 --- a/src/StudioCore/Transform.cs +++ b/src/StudioCore/Utilities/Transform.cs @@ -1,7 +1,7 @@ using System; using System.Numerics; -namespace StudioCore; +namespace StudioCore.Utilities; public struct Transform {