Skip to content

Commit fc86d66

Browse files
committed
fix: reload event handling
1 parent 959c459 commit fc86d66

File tree

2 files changed

+53
-34
lines changed

2 files changed

+53
-34
lines changed

Editor/USGEngine.cs

+39-26
Original file line numberDiff line numberDiff line change
@@ -60,36 +60,38 @@ void OnPreprocessAsset()
6060
static void OnPostprocessAllAssets(
6161
string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths)
6262
{
63+
// NOTE: Do NOT handle deleted assets because Unity tracking changes perfectly.
64+
// Even if delete file while Unity shutted down, asset deletion event happens on next Unity launch.
65+
// As a result, delete/import event loops infinitely and file cannot be deleted.
6366
for (int i = 0; i < importedAssets.Length; i++)
6467
{
6568
AddAppropriateTarget(importedAssets[i]);
6669
}
6770

68-
// NOTE: Do NOT handle deleted assets because Unity tracking changes perfectly.
69-
// Even if delete file while Unity shutted down, asset deletion event happens on next Unity launch.
70-
// As a result, delete/import event loops infinitely and file cannot be deleted.
7171
if (s_processingJobQueued) return;
7272
s_processingJobQueued = true;
7373

74-
// NOTE: need to stack jobs. nesting delayCall's causes error.
75-
EditorApplication.delayCall += static () =>
74+
// TODO: Unity sometimes reloads updated scripts by Visual Studio in background automatically.
75+
// In this situation, code generation will be done with script data right before saving.
76+
// It cannot be solved on C#, simply restart Unity.
77+
// Using [DidReloadScripts] or EditorApplication.delayCall, It works fine with Reimport
78+
// menu command but OnPostprocessAllAssets event doesn't work as expected.
79+
// (script runs with static field cleared even though .Clear() is only in ProcessingFiles())
80+
////EditorApplication.delayCall += () =>
7681
{
7782
ProcessingFiles();
78-
s_updatedGeneratorJob?.Invoke();
79-
s_updatedGeneratorJob = null;
80-
81-
IgnoreOverwriteSettingByAttribute = false; // always turn it off.
82-
s_processingJobQueued = false;
8383
};
8484
}
8585

86-
static Action s_updatedGeneratorJob = null;
86+
8787
readonly static HashSet<string> s_updatedGeneratorNames = new();
8888
static void ProcessingFiles()
8989
{
90+
bool somethingUpdated = false;
9091
foreach (string path in s_targetFilePaths)
9192
{
92-
ProcessFile(path);
93+
if (ProcessFile(path))
94+
somethingUpdated = true;
9395
}
9496

9597
// TODO: more efficient way to process related targets
@@ -100,19 +102,30 @@ static void ProcessingFiles()
100102
if (info.TargetClass == null) continue;
101103
if (info.Attribute.GeneratorClass?.Name != generatorName) continue;
102104

103-
s_updatedGeneratorJob += () => USGUtility.ForceGenerate(info.TargetClass.Name, false);
105+
var path = USGUtility.GetScriptFileByName(info.TargetClass.Name);
106+
if (path != null)
107+
{
108+
IgnoreOverwriteSettingByAttribute = true;
109+
if (ProcessFile(path))
110+
somethingUpdated = true;
111+
}
104112
}
105113
}
106-
s_updatedGeneratorNames.Clear();
107114

108-
if (s_targetFilePaths.Count() > 0) AssetDatabase.Refresh();
115+
if (somethingUpdated)
116+
AssetDatabase.Refresh();
109117
s_targetFilePaths.Clear();
118+
s_updatedGeneratorNames.Clear();
119+
120+
IgnoreOverwriteSettingByAttribute = false; // always turn it off.
121+
s_processingJobQueued = false;
110122
}
111123

112124

113125
///<summary>This method respects "OverwriteIfFileExists" attribute setting.</summary>
114126
///<param name="assetsRelPath">Path need to be started with "Assets/"</param>
115-
public static void ProcessFile(string assetsRelPath)
127+
///<returns>true if file is written</returns>
128+
public static bool ProcessFile(string assetsRelPath)
116129
{
117130
if (!File.Exists(assetsRelPath)) throw new FileNotFoundException(assetsRelPath);
118131

@@ -122,35 +135,35 @@ public static void ProcessFile(string assetsRelPath)
122135
if (!s_typeNameToInfo.ContainsKey(clsName))
123136
{
124137
if (!clsName.EndsWith(GENERATOR_EXT))
125-
return;
138+
return false;
126139

127140
// try find generator
128141
clsName = Path.GetFileNameWithoutExtension(clsName);
129142
clsName = Path.GetExtension(clsName);
130143

131-
if (clsName.Length == 0) return;
144+
if (clsName.Length == 0) return false;
132145
clsName = clsName.Substring(1);
133146

134147
if (!s_typeNameToInfo.ContainsKey(clsName))
135-
return;
148+
return false;
136149
}
137150

138151

139152
var info = s_typeNameToInfo[clsName];
140-
if (info == null) return;
153+
if (info == null) return false;
141154

142155
// TODO: more streamlined.
143156
if (info.TargetClass == null)
144157
{
145158
s_updatedGeneratorNames.Add(clsName);
146-
return;
159+
return false;
147160
}
148161

149162

150163
if (!TryBuildOutputFileName(info))
151164
{
152165
Debug.LogError($"[{nameof(UnitySourceGenerator)}] Output file name is invalid: {info.OutputFileName}");
153-
return;
166+
return false;
154167
}
155168

156169
var generatorCls = info.Attribute.GeneratorClass ?? info.TargetClass;
@@ -187,25 +200,25 @@ public static void ProcessFile(string assetsRelPath)
187200
}
188201

189202
if (!isSaveFile || sb == null || string.IsNullOrWhiteSpace(context.OutputPath))
190-
return;
203+
return false;
204+
191205

192206

193-
//file check
194207
var outputDir = Path.GetDirectoryName(context.OutputPath);
195208
if (!Directory.Exists(outputDir)) Directory.CreateDirectory(outputDir);
196209

197-
198210
if (File.Exists(context.OutputPath) &&
199211
(!info.Attribute.OverwriteIfFileExists && !IgnoreOverwriteSettingByAttribute)
200212
)
201213
{
202-
return;
214+
return false;
203215
}
204216

205217

206218
File.WriteAllText(context.OutputPath, sb.ToString());
207219
Debug.Log($"[{nameof(UnitySourceGenerator)}] Generated: {context.OutputPath}");
208220

221+
return true;
209222
}
210223

211224

Editor/USGUtility.cs

+14-8
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,18 @@ static void ForceGenerateSelectedScripts()
2727

2828

2929
public static void ForceGenerate(string clsName, bool showInProjectPanel = true)
30+
{
31+
var path = GetScriptFileByName(clsName);
32+
if (path == null) return;
33+
34+
if (showInProjectPanel)
35+
EditorGUIUtility.PingObject(AssetDatabase.LoadAssetAtPath<Object>(path));
36+
USGEngine.IgnoreOverwriteSettingByAttribute = true; // always disabled after import event.
37+
AssetDatabase.ImportAsset(path);
38+
}
39+
40+
41+
internal static string GetScriptFileByName(string clsName)
3042
{
3143
var GUIDs = AssetDatabase.FindAssets(clsName);
3244
foreach (var GUID in GUIDs)
@@ -35,17 +47,11 @@ public static void ForceGenerate(string clsName, bool showInProjectPanel = true)
3547
var fileName = Path.GetFileNameWithoutExtension(path);
3648
if (fileName != clsName) continue;
3749

38-
if (showInProjectPanel)
39-
EditorGUIUtility.PingObject(AssetDatabase.LoadAssetAtPath<Object>(path));
40-
41-
42-
USGEngine.IgnoreOverwriteSettingByAttribute = true; // always disabled after import event.
43-
AssetDatabase.ImportAsset(path);
44-
return;
50+
return path;
4551
}
52+
return null;
4653
}
4754

48-
4955
}
5056
}
5157
#endif

0 commit comments

Comments
 (0)