Skip to content

Commit 50892a5

Browse files
committed
feat: Added a new toggle in the project settings to force a prefab revert on all LDtk prefab instances in loaded scenes
1 parent 4cc21d6 commit 50892a5

File tree

9 files changed

+234
-133
lines changed

9 files changed

+234
-133
lines changed

Assets/LDtkUnity/Editor/Prefs/LDtkProjectSettings.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,15 @@ namespace LDtkUnity.Editor
66
internal sealed class LDtkProjectSettings : ScriptableObject
77
{
88
public const string PROPERTY_INTERAL_ICONS_TEXTURE = nameof(_internalIconsTexture);
9+
public const string PROPERTY_REVERT_OVERRIDES_IN_SCENE = nameof(_revertOverridesInScene);
910

1011
[SerializeField] private Texture2D _internalIconsTexture = null;
12+
[SerializeField] private bool _revertOverridesInScene = false;
1113

1214
private static LDtkProjectSettings Instance => LDtkProjectSettingsProvider.Instance;
1315

1416
public static Texture2D InternalIconsTexture => Instance._internalIconsTexture;
1517
public static string InternalIconsTexturePath => Instance._internalIconsTexture ? AssetDatabase.GetAssetPath(Instance._internalIconsTexture) : null;
18+
public static bool RevertOverridesInScene => Instance._revertOverridesInScene;
1619
}
1720
}

Assets/LDtkUnity/Editor/Prefs/LDtkProjectSettingsGUI.cs

Lines changed: 82 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@ internal sealed class LDtkProjectSettingsGUI
1414

1515
private readonly Action _saveAction;
1616
private readonly SerializedProperty _internalIconsTexture;
17+
private readonly SerializedProperty _revertOverridesInScene;
18+
19+
private readonly GUILayoutOption _buttonWidth = GUILayout.Width(180);
20+
private readonly GUILayoutOption _buttonWidthSmall = GUILayout.Width(88.5f);
21+
private readonly EditorGUIUtility.IconSizeScope _iconSizeScope = new EditorGUIUtility.IconSizeScope(new Vector2(16, 16));
1722

1823
private static readonly GUIContent InternalIconsTexture = new GUIContent
1924
{
@@ -65,12 +70,25 @@ internal sealed class LDtkProjectSettingsGUI
6570
tooltip = "Reimports all tileset files",
6671
image = LDtkIconUtility.LoadTilesetFileIcon()
6772
};
73+
private static readonly GUIContent RevertOverridesInScene = new GUIContent
74+
{
75+
text = "Revert Overrides On Import",
76+
tooltip = "If enabled, then after any LDtk asset import, will attempt a prefab revert of all LDtk prefab instances in all currently loaded scenes.\n" +
77+
"This is used for when you always want to maintain an unchanged state of the imported hierarchy in the scene, because Unity's tilemaps and other various components can accidentally change without notice nor intention.",
78+
image = LDtkIconUtility.GetUnityIcon("PrefabModel On")
79+
};
80+
private static readonly GUIContent RevertOverridesInSceneButton = new GUIContent
81+
{
82+
text = "Revert Now",
83+
tooltip = "Revert all LDtk prefab instances in all loaded scenes immediately",
84+
};
6885

6986
public LDtkProjectSettingsGUI(SerializedObject obj, Action saveAction)
7087
{
7188
_saveAction = saveAction;
7289
_serializedObject = obj;
7390
_internalIconsTexture = obj.FindProperty(LDtkProjectSettings.PROPERTY_INTERAL_ICONS_TEXTURE);
91+
_revertOverridesInScene = obj.FindProperty(LDtkProjectSettings.PROPERTY_REVERT_OVERRIDES_IN_SCENE);
7492
}
7593

7694
public void OnGUI(string searchContext)
@@ -82,86 +100,97 @@ public void OnGUI(string searchContext)
82100
LDtkSettingsSwitchGUI.DrawSwitchPrefsButton();
83101
LDtkEditorGUIUtility.DrawDivider();
84102

85-
using (new EditorGUIUtility.IconSizeScope(new Vector2(16, 16)))
103+
LDtkScriptingDefines.PreprocessorAddRemoveGui();
104+
105+
using (_iconSizeScope)
86106
{
87-
LDtkScriptingDefines.PreprocessorAddRemoveGui();
88-
EditorGUILayout.PropertyField(_internalIconsTexture, InternalIconsTexture);
89-
90-
if (_internalIconsTexture.objectReferenceValue is Texture2D tex)
91-
{
92-
if (tex.width != 512 || tex.height != 1024)
93-
{
94-
LDtkDebug.LogWarning("Only assigning the internal icons texture is valid. (Needs a 512x1024 resolution)");
95-
_internalIconsTexture.objectReferenceValue = null;
96-
}
97-
}
107+
DrawFieldInternalIcons();
108+
DrawRevertInstancesField();
109+
DrawItchButtons();
110+
LDtkEditorGUIUtility.DrawDivider();
111+
DrawReimportAllButtons();
98112
}
99-
DrawItchButton();
100-
LDtkEditorGUIUtility.DrawDivider();
101-
DrawReimportAllButton();
102113

103-
104114
if (_serializedObject.ApplyModifiedPropertiesWithoutUndo())
105115
{
106116
_saveAction?.Invoke();
107117
}
108118
}
109119

110-
private static void DrawItchButton()
120+
private void DrawFieldInternalIcons()
121+
{
122+
EditorGUILayout.PropertyField(_internalIconsTexture, InternalIconsTexture);
123+
if (_internalIconsTexture.objectReferenceValue is Texture2D tex)
124+
{
125+
if (tex.width != 512 || tex.height != 1024)
126+
{
127+
LDtkDebug.LogWarning("Only assigning the internal icons texture is valid. (Needs a 512x1024 resolution)");
128+
_internalIconsTexture.objectReferenceValue = null;
129+
}
130+
}
131+
}
132+
133+
private void DrawItchButtons()
111134
{
112135
EditorGUILayout.BeginHorizontal();
113136
GUILayout.FlexibleSpace();
114137

115-
using (new EditorGUIUtility.IconSizeScope(new Vector2(16, 16)))
138+
if (GUILayout.Button(GithubButton, _buttonWidthSmall))
116139
{
117-
if (GUILayout.Button(GithubButton, GUILayout.Width(89)))
118-
{
119-
Application.OpenURL(GITHUB_LINK);
120-
}
121-
if (GUILayout.Button(ItchButton, GUILayout.Width(88)))
122-
{
123-
Application.OpenURL(ITCH_LINK);
124-
}
140+
Application.OpenURL(GITHUB_LINK);
141+
}
142+
if (GUILayout.Button(ItchButton, _buttonWidthSmall))
143+
{
144+
Application.OpenURL(ITCH_LINK);
125145
}
126146

127147
EditorGUILayout.EndHorizontal();
128148
}
129-
private static void DrawReimportAllButton()
149+
150+
private void DrawRevertInstancesField()
151+
{
152+
EditorGUILayout.BeginHorizontal();
153+
EditorGUILayout.PropertyField(_revertOverridesInScene, RevertOverridesInScene);
154+
if (GUILayout.Button(RevertOverridesInSceneButton, _buttonWidth))
155+
{
156+
LDtkPostImportSceneAlterations.QueueRevertPrefabs(InteractionMode.UserAction);
157+
}
158+
EditorGUILayout.EndHorizontal();
159+
}
160+
161+
private void DrawReimportAllButtons()
130162
{
131163
EditorGUILayout.BeginHorizontal();
132164
GUILayout.FlexibleSpace();
133165
EditorGUILayout.BeginVertical();
134166

135-
using (new EditorGUIUtility.IconSizeScope(new Vector2(16, 16)))
167+
if (GUILayout.Button(ReimportAllButton, _buttonWidth))
136168
{
137-
if (GUILayout.Button(ReimportAllButton, GUILayout.Width(180)))
138-
{
139-
WrapInAssetEditing(ReimportAll);
140-
}
141-
if (GUILayout.Button(ReimportAllProjectsButton, GUILayout.Width(180)))
169+
WrapInAssetEditing(ReimportAll);
170+
}
171+
if (GUILayout.Button(ReimportAllProjectsButton, _buttonWidth))
172+
{
173+
WrapInAssetEditing(() =>
142174
{
143-
WrapInAssetEditing(() =>
144-
{
145-
string[] allPaths = AssetDatabase.GetAllAssetPaths();
146-
ReimportAllFiles(allPaths, ".ldtk");
147-
});
148-
}
149-
if (GUILayout.Button(ReimportAllLevelsButton, GUILayout.Width(180)))
175+
string[] allPaths = AssetDatabase.GetAllAssetPaths();
176+
ReimportAllFiles(allPaths, ".ldtk");
177+
});
178+
}
179+
if (GUILayout.Button(ReimportAllLevelsButton, _buttonWidth))
180+
{
181+
WrapInAssetEditing(() =>
150182
{
151-
WrapInAssetEditing(() =>
152-
{
153-
string[] allPaths = AssetDatabase.GetAllAssetPaths();
154-
ReimportAllFiles(allPaths, ".ldtkl");
155-
});
156-
}
157-
if (GUILayout.Button(ReimportAllTilesetFilesButton, GUILayout.Width(180)))
183+
string[] allPaths = AssetDatabase.GetAllAssetPaths();
184+
ReimportAllFiles(allPaths, ".ldtkl");
185+
});
186+
}
187+
if (GUILayout.Button(ReimportAllTilesetFilesButton, _buttonWidth))
188+
{
189+
WrapInAssetEditing(() =>
158190
{
159-
WrapInAssetEditing(() =>
160-
{
161-
string[] allPaths = AssetDatabase.GetAllAssetPaths();
162-
ReimportAllFiles(allPaths, ".ldtkt");
163-
});
164-
}
191+
string[] allPaths = AssetDatabase.GetAllAssetPaths();
192+
ReimportAllFiles(allPaths, ".ldtkt");
193+
});
165194
}
166195

167196
EditorGUILayout.EndVertical();

Assets/LDtkUnity/Editor/ScriptedImporter/LDtkJsonImporter.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Collections.Generic;
33
using System.IO;
44
using System.Text.RegularExpressions;
5+
using UnityEditor;
56
using UnityEngine;
67
#if UNITY_2020_2_OR_NEWER
78
using UnityEditor.AssetImporters;
@@ -68,6 +69,11 @@ private void MainImport()
6869
{
6970
Import();
7071
}
72+
73+
if (LDtkProjectSettings.RevertOverridesInScene)
74+
{
75+
LDtkPostImportSceneAlterations.QueueRevertPrefabs(InteractionMode.AutomatedAction);
76+
}
7177
}
7278

7379
protected abstract void Import();

Assets/LDtkUnity/Editor/ScriptedImporter/LDtkTilesetImporter.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ protected override void Import()
209209

210210
ImportContext.SetMainObject(outputTexture);
211211

212-
LDtkTilemapColliderReset.TilemapColliderTileUpdate();
212+
LDtkPostImportSceneAlterations.QueueTilemapColliderSmartReset();
213213
}
214214

215215
private void ReformatAdditionalTiles()
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
using System.Diagnostics;
2+
using UnityEditor;
3+
using UnityEngine;
4+
using UnityEngine.Tilemaps;
5+
6+
namespace LDtkUnity.Editor
7+
{
8+
/// <summary>
9+
/// class for altering stuff in the active scenes
10+
/// </summary>
11+
internal static class LDtkPostImportSceneAlterations
12+
{
13+
private static bool _willRefreshTilemapsInScene;
14+
private static bool _willRevertOverrides;
15+
private static InteractionMode _interaction;
16+
17+
public static void QueueTilemapColliderSmartReset()
18+
{
19+
//Refresh tilemap colliders in the current scene.
20+
//Tiles would normally not update in the scene view until entering play mode, or reloading the scene, or resetting the component.
21+
//This will immediately update it.
22+
//There is currently no easy solution found for refreshing tilemap colliders in the scene, so this is the best solution I could find for now.
23+
//Related forum: https://forum.unity.com/threads/ispritephysicsoutlinedataprovider-is-not-updating-the-tilemapcollider2d-in-the-scene-immediately.1458874/#post-9358610
24+
25+
if (!_willRefreshTilemapsInScene)
26+
{
27+
TrySetupDeferredEvent();
28+
_willRefreshTilemapsInScene = true;
29+
}
30+
}
31+
32+
public static void QueueRevertPrefabs(InteractionMode interaction)
33+
{
34+
//Revert prefab overrides in the current scene.
35+
//This is by preference for when unity unintentionally dirties the project/level automatically, and the user only wants to maintain a completely immutable project/level
36+
_interaction = interaction;
37+
if (!_willRevertOverrides)
38+
{
39+
TrySetupDeferredEvent();
40+
_willRevertOverrides = true;
41+
}
42+
}
43+
44+
private static void TrySetupDeferredEvent()
45+
{
46+
if (!_willRefreshTilemapsInScene && !_willRevertOverrides)
47+
{
48+
EditorApplication.delayCall += DoAReset;
49+
}
50+
}
51+
52+
private static void DoAReset()
53+
{
54+
//both queued events try a level find, so it's shared here in case it can be reused for both needs at the same time
55+
var levels = LDtkFindInScenes.FindInAllScenes<LDtkComponentLevel>();
56+
57+
RevertPrefabOverrides();
58+
SmartResetTilemaps();
59+
60+
_willRefreshTilemapsInScene = false;
61+
_willRevertOverrides = false;
62+
63+
void RevertPrefabOverrides()
64+
{
65+
if (!_willRevertOverrides) return;
66+
67+
//.ldtk instances
68+
var projects = LDtkFindInScenes.FindInAllScenes<LDtkComponentProject>();
69+
foreach (LDtkComponentProject project in projects)
70+
{
71+
GameObject projectGameObject = project.gameObject;
72+
if (PrefabUtility.IsOutermostPrefabInstanceRoot(projectGameObject))
73+
{
74+
PrefabUtility.RevertPrefabInstance(projectGameObject, _interaction);
75+
}
76+
}
77+
78+
//.ldtkl instances
79+
foreach (LDtkComponentLevel level in levels)
80+
{
81+
GameObject levelGameObject = level.gameObject;
82+
if (PrefabUtility.IsOutermostPrefabInstanceRoot(levelGameObject))
83+
{
84+
PrefabUtility.RevertPrefabInstance(levelGameObject, _interaction);
85+
}
86+
}
87+
}
88+
89+
void SmartResetTilemaps()
90+
{
91+
if (!_willRefreshTilemapsInScene) return;
92+
93+
Stopwatch watch = Stopwatch.StartNew();
94+
int affected = 0;
95+
96+
//should only try resetting tilemaps that are in an LDtk hierarchy
97+
foreach (LDtkComponentLevel level in levels)
98+
{
99+
if (!level) continue;
100+
101+
foreach (LDtkComponentLayer layer in level.LayerInstances)
102+
{
103+
if (!layer) continue;
104+
105+
var colliders = layer.GetComponentsInChildren<TilemapCollider2D>();
106+
foreach (var collider in colliders)
107+
{
108+
Unsupported.SmartReset(collider);
109+
if (LDtkBuilderLayer.ConfigureTilemapCollider(collider))
110+
{
111+
affected++;
112+
}
113+
}
114+
}
115+
}
116+
117+
watch.Stop();
118+
119+
if (affected <= 0)
120+
{
121+
return;
122+
}
123+
124+
float seconds = watch.ElapsedMilliseconds * 0.001f;
125+
SceneView view = SceneView.lastActiveSceneView;
126+
string msg = $"Refreshed LDtk scene tilemaps\n({affected} in {seconds:F2}s)";
127+
128+
if (view != null)
129+
{
130+
view.ShowNotification(new GUIContent(msg), 2.5f);
131+
}
132+
133+
if (LDtkPrefs.VerboseLogging)
134+
{
135+
LDtkDebug.Log(msg);
136+
}
137+
}
138+
}
139+
}
140+
}

Assets/LDtkUnity/Editor/Utility/LDtkTilemapColliderReset.cs.meta renamed to Assets/LDtkUnity/Editor/Utility/LDtkPostImportSceneAlterations.cs.meta

File renamed without changes.

0 commit comments

Comments
 (0)