Skip to content

Commit ca117e4

Browse files
WIP of refactoring to use YAML parser
1 parent 5624378 commit ca117e4

File tree

10 files changed

+435
-18
lines changed

10 files changed

+435
-18
lines changed

Assets/EventReferenceSeeker/Editor/ReferenceFinder.cs

Lines changed: 179 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,17 @@
55
using System.Reflection;
66
using System.Linq;
77
using System.IO;
8-
8+
using YamlDotNet;
9+
using YamlDotNet.RepresentationModel;
910

1011
public class ReferenceFinder : EditorWindow
1112
{
1213
string searchedFunction;
1314
string searchResult = "";
1415
string valueToSearch = "";
1516

17+
System.Type typeSearched;
18+
1619
string tempSearchResult = "";
1720

1821
Vector2 scrollViewPosition;
@@ -37,7 +40,9 @@ private void Update()
3740
int purcentage = Mathf.FloorToInt(currentParseFile / (float)filesList.Count * 100.0f);
3841
searchResult = "Searching " + purcentage + "%";
3942

40-
HandleFile(filesList[currentParseFile]);
43+
//HandleFile(filesList[currentParseFile]);
44+
NewHandleFile(filesList[currentParseFile]);
45+
4146
currentParseFile += 1;
4247

4348
if (currentParseFile == filesList.Count)
@@ -117,7 +122,8 @@ private void Search()
117122
valueToSearch = func[0].Name;
118123
}
119124

120-
valueToSearch = "m_MethodName: " + valueToSearch;
125+
typeSearched = type;
126+
//valueToSearch = valueToSearch;
121127

122128
//Now that we checked the function name exist and is valid, we list all object that is suceptible of having an unity event data to it, meaning Scene & prefab.
123129
filesList = new List<string>();
@@ -127,10 +133,177 @@ private void Search()
127133
currentParseFile = 0;
128134
}
129135

136+
public class YamlVisitorEvent : IYamlVisitor
137+
{
138+
public ReferenceFinder referenceFinder;
139+
public bool havePersistentCall = false;
140+
public HashSet<string> idToCheck = new HashSet<string>();
141+
142+
public void Visit(YamlStream stream)
143+
{
144+
145+
}
146+
147+
public void Visit(YamlDocument document)
148+
{
149+
150+
}
151+
152+
public void Visit(YamlScalarNode scalar)
153+
{
154+
155+
}
156+
157+
public void Visit(YamlSequenceNode sequence)
158+
{
159+
160+
}
161+
162+
public void Visit(YamlMappingNode mapping)
163+
{
164+
foreach(var n in mapping)
165+
{
166+
n.Value.Accept(this);
167+
if(((YamlScalarNode)n.Key).Value == "m_PersistentCalls")
168+
{
169+
var callsSequence = n.Value["m_Calls"] as YamlSequenceNode;
170+
171+
foreach(var call in callsSequence)
172+
{
173+
if(((YamlScalarNode)call["m_MethodName"]).Value == referenceFinder.valueToSearch)
174+
{
175+
havePersistentCall = true;
176+
idToCheck.Add(((YamlScalarNode)call["m_Target"]["fileID"]).Value);
177+
}
178+
}
179+
}
180+
}
181+
}
182+
}
183+
184+
private void NewHandleFile(string file)
185+
{
186+
bool filenameWrote = false;
187+
188+
var fileContent = File.ReadAllText(file);
189+
//unity seem to use non valid yaml by added a "stripped" keyword on object that are linked to a prefab. Since the pareser itch on those, we remove them
190+
fileContent = fileContent.Replace("stripped", "");
191+
var input = new StringReader(fileContent);
192+
193+
var yaml = new YamlStream();
194+
yaml.Load(input);
195+
196+
YamlVisitorEvent visitor = new YamlVisitorEvent();
197+
visitor.referenceFinder = this;
198+
199+
//map gameobject id to a hashset of monobehaviour to check for type against the searched type
200+
Dictionary<string, HashSet<string>> gameobjectToIdToCheck = new Dictionary<string, HashSet<string>>();
201+
202+
//we store the anchor <-> node mapping, as there don't seem to be anyway to do that quickly through the YAml graph
203+
Dictionary<string, YamlMappingNode> parsedNodes = new Dictionary<string, YamlMappingNode>();
204+
205+
foreach (var doc in yaml.Documents)
206+
{
207+
var root = (YamlMappingNode)doc.RootNode;
208+
209+
parsedNodes[root.Anchor] = root;
210+
211+
foreach (var node in root.Children)
212+
{
213+
var scalarNode = (YamlScalarNode) node.Key;
214+
if (scalarNode.Value == "MonoBehaviour")
215+
{//if it's a monobehaviour, it may have a list of event as child
216+
YamlMappingNode sequenceNode = node.Value as YamlMappingNode;
217+
218+
visitor.havePersistentCall = false;
219+
visitor.idToCheck.Clear();
220+
sequenceNode.Accept(visitor);
221+
222+
if(visitor.havePersistentCall)
223+
{//we found persistent call
224+
string gameobjectID = ((YamlScalarNode)node.Value["m_GameObject"]["fileID"]).Value;
225+
226+
if (!gameobjectToIdToCheck.ContainsKey(gameobjectID))
227+
gameobjectToIdToCheck[gameobjectID] = new HashSet<string>();
228+
229+
gameobjectToIdToCheck[gameobjectID].UnionWith(visitor.idToCheck);
230+
}
231+
}
232+
}
233+
}
234+
235+
//now we go over all our gameobject to check, and if one of the monobehaviour they ahve been associated with are of the researched type, they are added to the result
236+
foreach(var pair in gameobjectToIdToCheck)
237+
{
238+
bool haveOneValidCall = false;
239+
if(!parsedNodes.ContainsKey(pair.Key))
240+
{
241+
Debug.LogError("Tried to check an object id that don't exist : " + pair.Key);
242+
continue;
243+
}
244+
245+
foreach(var id in pair.Value)
246+
{
247+
var targetNode = parsedNodes[id];
248+
var guid = ((YamlScalarNode)targetNode["MonoBehaviour"]["m_Script"]["guid"]).Value;
249+
250+
MonoScript script = AssetDatabase.LoadAssetAtPath<MonoScript>(AssetDatabase.GUIDToAssetPath(guid));
251+
252+
if(script.GetClass() == typeSearched)
253+
{
254+
haveOneValidCall = true;
255+
}
256+
}
257+
258+
if(haveOneValidCall)
259+
{
260+
if (!filenameWrote)
261+
{
262+
filenameWrote = true;
263+
tempSearchResult += Path.GetFileName(file) + "\n";
264+
}
265+
266+
if (((YamlScalarNode)parsedNodes[pair.Key]["GameObject"]["m_PrefabParentObject"]["fileID"]).Value != "0")
267+
{//this is a prefab instance, need to find the prefab value linked to it!!
268+
tempSearchResult += "\t" + "A Prefab";
269+
}
270+
else
271+
{
272+
string fullPath = "";
273+
274+
//make an assumption here that the 1st component of every gameobject will always be its transform.
275+
string currentGOId = pair.Key;
276+
while(currentGOId != "0")
277+
{
278+
fullPath = parsedNodes[currentGOId]["GameObject"]["m_Name"] + (fullPath == "" ? "" : "/" + fullPath);
279+
280+
string transformID = parsedNodes[currentGOId]["GameObject"]["m_Component"][0]["component"]["fileID"].ToString();
281+
282+
Debug.Log("trasnofrmID " + transformID);
283+
284+
string parentTransformID = parsedNodes[transformID]["Transform"]["m_Father"]["fileID"].ToString();
285+
if(parentTransformID != "0")
286+
{
287+
currentGOId = parsedNodes[parentTransformID]["Transform"]["m_GameObject"]["fileID"].ToString();
288+
}
289+
290+
Debug.Log("currentGOID " + currentGOId);
291+
}
292+
293+
tempSearchResult += "\t" + fullPath + "\n";
294+
}
295+
}
296+
}
297+
}
298+
130299
private void HandleFile(string file)
131300
{
132301
bool nameWritten = false;
133302

303+
string relativePath = file.Replace(Application.dataPath, "Assets");
304+
Debug.Log(relativePath);
305+
Debug.Log(AssetDatabase.AssetPathToGUID(relativePath));
306+
134307
string content = File.ReadAllText(file);
135308

136309
//we're doing rough simple parsing here, not robust but way faster than deserializing the YAML & going through object etc...
@@ -174,6 +347,9 @@ private string GetObjectName(string content, string gameobjectID, int startIndex
174347
//if it wasn't found, search in the other direction (most of the time, it will be above, but in some case it can be inverted)
175348
if (parentGOIndex == -1) parentGOIndex = content.IndexOf("&" + gameobjectID, startIndex);
176349

350+
//we check if that object was "stripped". A stripped gameobject don't have any info, it is just a link to a prefab, so we have to go fetch the prefab data?
351+
352+
177353
//if that object have a parent, we go fetch the name of it recursivly too
178354
int fatherIDPlaceIndex = content.IndexOf(gameObjectParentString, parentGOIndex);
179355
if (fatherIDPlaceIndex != -1)

Assets/EventReferenceSeeker/Plugin.meta

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
178 KB
Binary file not shown.

Assets/EventReferenceSeeker/Plugin/YamlDotNet.dll.meta

Lines changed: 99 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Assets/EventReferenceSeeker/ReferenceHolder.cs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,17 @@
55

66
public class ReferenceHolder : MonoBehaviour
77
{
8+
[System.Serializable]
9+
public class InternalClassTest
10+
{
11+
public UnityEvent internalEventTest;
12+
}
13+
814
public UnityEvent testEvent;
15+
public InternalClassTest nestedClass;
916

10-
// Use this for initialization
11-
void Start () {
17+
// Use this for initialization
18+
void Start () {
1219

1320
}
1421

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
using System.Collections;
2+
using System.Collections.Generic;
3+
using UnityEngine;
4+
using UnityEngine.Events;
5+
6+
public class SecondReference : MonoBehaviour
7+
{
8+
public UnityEvent testEvent;
9+
10+
// Use this for initialization
11+
void Start()
12+
{
13+
14+
}
15+
16+
// Update is called once per frame
17+
void Update()
18+
{
19+
20+
}
21+
22+
public void TestFunction()
23+
{
24+
25+
}
26+
}

Assets/EventReferenceSeeker/SecondReference.cs.meta

Lines changed: 13 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)