generated from DevPlus1/Unity-Customer-Template
Initial commit
This commit is contained in:
commit
ed87277ef8
64 changed files with 4639 additions and 0 deletions
34
Assets/RL_DevPlus1/Docs/AI_CONTEXT.md
Normal file
34
Assets/RL_DevPlus1/Docs/AI_CONTEXT.md
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
# AI Context
|
||||
|
||||
The primary AI-ready file is:
|
||||
|
||||
`Assets/RL_DevPlus1/Reports/RL_AI_Project_Context.md`
|
||||
|
||||
This file is intended to be pasted into or read by AI/Codex before deeper work on a customer Unity project.
|
||||
|
||||
It summarizes:
|
||||
|
||||
- project name
|
||||
- Unity version
|
||||
- scenes
|
||||
- likely entry scene
|
||||
- GameObjects
|
||||
- managers/controllers
|
||||
- MonoBehaviour scripts
|
||||
- ScriptableObjects
|
||||
- lifecycle methods
|
||||
- public methods
|
||||
- serialized fields
|
||||
- UnityEvents
|
||||
- scene transitions
|
||||
- prefabs
|
||||
- missing scripts and references
|
||||
- imported Git report status
|
||||
- suggested first files to inspect
|
||||
- risks and unknowns
|
||||
|
||||
The JSON companion file is:
|
||||
|
||||
`Assets/RL_DevPlus1/Reports/RL_AI_Project_Context.json`
|
||||
|
||||
Use cautious interpretation. The report is designed to accelerate understanding, not replace manual review.
|
||||
30
Assets/RL_DevPlus1/Docs/CODEX_INSTRUCTIONS.md
Normal file
30
Assets/RL_DevPlus1/Docs/CODEX_INSTRUCTIONS.md
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
# Codex Instructions For Unity Analyzer
|
||||
|
||||
## Purpose
|
||||
|
||||
This Unity package gives Runlevel Systems DevPlus1 a safe Editor-only analyzer for customer Unity projects.
|
||||
|
||||
## Rules
|
||||
|
||||
- Read generated reports before changing customer Unity code.
|
||||
- Treat findings as best-effort and confirm manually.
|
||||
- Do not modify customer scenes, prefabs, scripts, assets, or project settings unless explicitly asked.
|
||||
- Do not generate C# files into `Assets/RL_DevPlus1/Reports/`.
|
||||
- Keep analyzer Editor scripts under `Assets/RL_DevPlus1/Editor/`.
|
||||
- Keep docs under `Assets/RL_DevPlus1/Docs/`.
|
||||
- Keep report outputs under `Assets/RL_DevPlus1/Reports/`.
|
||||
|
||||
## Recommended AI Reading Order
|
||||
|
||||
1. `Assets/RL_DevPlus1/Reports/RL_AI_Project_Context.md`
|
||||
2. `Assets/RL_DevPlus1/Reports/RL_Unity_Report_Index.md`
|
||||
3. `Assets/RL_DevPlus1/Reports/RL_Unity_Project_Summary.md`
|
||||
4. `reports/api-reference.md`
|
||||
5. `reports/call-map.md`
|
||||
6. `Assets/RL_DevPlus1/Reports/RL_Unity_Scene_Map.md`
|
||||
7. `Assets/RL_DevPlus1/Reports/RL_Unity_Script_Map.md`
|
||||
8. `Assets/RL_DevPlus1/Reports/RL_Unity_Event_Map.md`
|
||||
|
||||
## Maintenance
|
||||
|
||||
Update this file when analyzer behavior, report locations, or recommended reading order changes.
|
||||
26
Assets/RL_DevPlus1/Docs/README.md
Normal file
26
Assets/RL_DevPlus1/Docs/README.md
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
# Runlevel DevPlus1 Unity Analyzer
|
||||
|
||||
This folder contains the Unity-side Runlevel Systems DevPlus1 project analyzer.
|
||||
|
||||
The analyzer is an Editor-only tool. It reads Unity project structure, scenes, prefabs, scripts, UnityEvents, and existing Git-generated reports, then writes safe markdown and JSON reports under:
|
||||
|
||||
`Assets/RL_DevPlus1/Reports/`
|
||||
|
||||
It does not modify customer scenes, prefabs, scripts, project settings, or assets.
|
||||
|
||||
## Menu Location
|
||||
|
||||
Unity menu:
|
||||
|
||||
`Runlevel Systems/DevPlus1/Analyze Unity Project`
|
||||
|
||||
## Main Reports
|
||||
|
||||
- `RL_AI_Project_Context.md`
|
||||
- `RL_Unity_Report_Index.md`
|
||||
- `RL_Unity_Project_Summary.md`
|
||||
- `RL_Unity_Scene_Map.md`
|
||||
- `RL_Unity_Script_Map.md`
|
||||
- `RL_Unity_Event_Map.md`
|
||||
|
||||
Future Codex sessions should read `RL_AI_Project_Context.md` first after reports are generated.
|
||||
28
Assets/RL_DevPlus1/Docs/REPORTS.md
Normal file
28
Assets/RL_DevPlus1/Docs/REPORTS.md
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
# Unity Analyzer Reports
|
||||
|
||||
Reports are written under:
|
||||
|
||||
`Assets/RL_DevPlus1/Reports/`
|
||||
|
||||
## Human-Readable Reports
|
||||
|
||||
- `RL_Unity_Project_Summary.md`: high-level counts and project status.
|
||||
- `RL_Unity_Scene_Map.md`: scene paths, root objects, counts, and missing reference totals.
|
||||
- `RL_Unity_GameObject_Map.md`: GameObject hierarchy, tags, layers, and components.
|
||||
- `RL_Unity_Script_Map.md`: script classes, lifecycle methods, fields, methods, and Unity API usage.
|
||||
- `RL_Unity_Event_Map.md`: UnityEvent and Button callback bindings where detectable.
|
||||
- `RL_Unity_Prefab_Map.md`: prefab components, scripts, nested prefabs, and references.
|
||||
- `RL_Unity_Execution_Order.md`: custom script execution order and probable lifecycle order.
|
||||
- `RL_Unity_Missing_References.md`: missing scripts and missing serialized references.
|
||||
- `RL_Unity_Git_Report_Summary.md`: summary of repository-root Git reports if present.
|
||||
- `RL_Unity_Report_Index.md`: index of generated reports.
|
||||
|
||||
## AI-Ready Reports
|
||||
|
||||
- `RL_AI_Project_Context.md`: primary Codex/AI context report.
|
||||
- `RL_AI_Project_Context.json`: machine-readable AI context.
|
||||
- `RL_Unity_Project_Data.json`: full machine-readable project analysis data.
|
||||
|
||||
## Limitations
|
||||
|
||||
Reports are best-effort. Runtime-created objects, reflection, dependency injection, generated content, addressable content, and custom serialization may require manual confirmation.
|
||||
47
Assets/RL_DevPlus1/Docs/UNITY_ANALYZER.md
Normal file
47
Assets/RL_DevPlus1/Docs/UNITY_ANALYZER.md
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
# Unity Analyzer
|
||||
|
||||
## What It Does
|
||||
|
||||
The Runlevel DevPlus1 Unity Analyzer creates project-understanding reports for customer Unity projects.
|
||||
|
||||
It can inspect:
|
||||
|
||||
- open scenes
|
||||
- build settings scenes
|
||||
- all asset scenes
|
||||
- prefabs
|
||||
- C# scripts
|
||||
- Unity lifecycle methods
|
||||
- UnityEvents and Button callbacks where serialized data is visible
|
||||
- missing scripts
|
||||
- missing serialized object references where detectable
|
||||
- root Git-generated reports under `reports/`
|
||||
|
||||
## Menu Items
|
||||
|
||||
- `Runlevel Systems/DevPlus1/Analyze Unity Project`
|
||||
- `Runlevel Systems/DevPlus1/Open Report Folder`
|
||||
- `Runlevel Systems/DevPlus1/Refresh Git Reports`
|
||||
|
||||
## Safety
|
||||
|
||||
The analyzer is read-only against customer source files and Unity assets.
|
||||
|
||||
It does not:
|
||||
|
||||
- save scenes
|
||||
- modify prefabs
|
||||
- edit scripts
|
||||
- write generated C# files
|
||||
- modify project settings
|
||||
- create asmdef files
|
||||
|
||||
If open scenes have unsaved changes, broad scene-scan operations skip scene switching rather than saving or discarding changes.
|
||||
|
||||
## How To Run
|
||||
|
||||
1. Open the Unity project.
|
||||
2. Wait for Unity to compile Editor scripts.
|
||||
3. Open `Runlevel Systems/DevPlus1/Analyze Unity Project`.
|
||||
4. Click `Generate All Reports`.
|
||||
5. Open `Assets/RL_DevPlus1/Reports/`.
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace RunlevelSystems.DevPlus1.EditorTools
|
||||
{
|
||||
public static class RLAIContextExporter
|
||||
{
|
||||
public static void EnrichProjectContext(RLProjectAnalysisData data)
|
||||
{
|
||||
data.suggestedFirstFiles.Clear();
|
||||
data.risksOrUnknowns.Clear();
|
||||
|
||||
foreach (RLScriptInfo script in data.scripts)
|
||||
{
|
||||
string lower = (script.className + " " + script.possibleRole).ToLowerInvariant();
|
||||
if (lower.Contains("manager") || lower.Contains("controller") || script.lifecycleMethods.Count > 0)
|
||||
{
|
||||
AddUnique(data.suggestedFirstFiles, script.scriptPath);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (string file in data.gitReports.importantFiles)
|
||||
{
|
||||
AddUnique(data.suggestedFirstFiles, file);
|
||||
}
|
||||
|
||||
if (data.scenes.Count == 0)
|
||||
{
|
||||
data.risksOrUnknowns.Add("No scenes were analyzed. Scene flow needs manual confirmation.");
|
||||
}
|
||||
|
||||
if (data.gitReports.validationFoundErrors)
|
||||
{
|
||||
data.risksOrUnknowns.Add("Git validation reports customer code errors. Review reports/errors.md before feature work.");
|
||||
}
|
||||
|
||||
int missingScripts = 0;
|
||||
int missingReferences = 0;
|
||||
foreach (RLSceneInfo scene in data.scenes)
|
||||
{
|
||||
missingScripts += scene.missingScriptCount;
|
||||
missingReferences += scene.missingReferenceCount;
|
||||
}
|
||||
foreach (RLPrefabInfo prefab in data.prefabs)
|
||||
{
|
||||
missingScripts += prefab.missingScriptCount;
|
||||
missingReferences += prefab.missingReferenceCount;
|
||||
}
|
||||
|
||||
if (missingScripts > 0)
|
||||
{
|
||||
data.risksOrUnknowns.Add("Missing scripts were detected. Inspect RL_Unity_Missing_References.md.");
|
||||
}
|
||||
if (missingReferences > 0)
|
||||
{
|
||||
data.risksOrUnknowns.Add("Missing serialized object references were detected. Inspect RL_Unity_Missing_References.md.");
|
||||
}
|
||||
|
||||
data.risksOrUnknowns.Add("Analysis is best-effort and may miss runtime-created objects, reflection, addressables, or dependency injection.");
|
||||
}
|
||||
|
||||
private static void AddUnique(List<string> values, string value)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(value) && !values.Contains(value))
|
||||
{
|
||||
values.Add(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
114
Assets/RL_DevPlus1/Editor/ProjectAnalyzer/RLGitReportImporter.cs
Normal file
114
Assets/RL_DevPlus1/Editor/ProjectAnalyzer/RLGitReportImporter.cs
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text.RegularExpressions;
|
||||
using UnityEngine;
|
||||
|
||||
namespace RunlevelSystems.DevPlus1.EditorTools
|
||||
{
|
||||
public static class RLGitReportImporter
|
||||
{
|
||||
private static readonly string[] ExpectedReports =
|
||||
{
|
||||
"errors.md",
|
||||
"api-reference.md",
|
||||
"file-purpose.md",
|
||||
"call-map.md",
|
||||
"unity-scripts.md",
|
||||
"code-docs-summary.md",
|
||||
"project-flow.md",
|
||||
"summary.md",
|
||||
"generated-files.md"
|
||||
};
|
||||
|
||||
public static RLGitReportSummary ImportGitReports()
|
||||
{
|
||||
RLGitReportSummary summary = new RLGitReportSummary();
|
||||
string repoRoot = Directory.GetParent(Application.dataPath).FullName;
|
||||
string reportsFolder = Path.Combine(repoRoot, "reports");
|
||||
summary.reportsFolderFound = Directory.Exists(reportsFolder);
|
||||
|
||||
if (!summary.reportsFolderFound)
|
||||
{
|
||||
summary.notes = "Repository-root reports folder was not found. Run Forgejo reports or local scripts first if Git analysis is needed.";
|
||||
foreach (string report in ExpectedReports)
|
||||
{
|
||||
summary.missingReports.Add("reports/" + report);
|
||||
}
|
||||
return summary;
|
||||
}
|
||||
|
||||
foreach (string report in ExpectedReports)
|
||||
{
|
||||
string path = Path.Combine(reportsFolder, report);
|
||||
if (File.Exists(path))
|
||||
{
|
||||
summary.foundReports.Add("reports/" + report);
|
||||
}
|
||||
else
|
||||
{
|
||||
summary.missingReports.Add("reports/" + report);
|
||||
}
|
||||
}
|
||||
|
||||
string errorsPath = Path.Combine(reportsFolder, "errors.md");
|
||||
summary.validationReportFound = File.Exists(errorsPath);
|
||||
if (summary.validationReportFound)
|
||||
{
|
||||
string text = File.ReadAllText(errorsPath);
|
||||
summary.validationFoundErrors = text.Contains("CUSTOMER CODE ERRORS FOUND");
|
||||
summary.validationWarnings = ExtractCount(text, @"Warnings:\s*(\d+)");
|
||||
summary.validationErrors = ExtractCount(text, @"Errors:\s*(\d+)");
|
||||
}
|
||||
|
||||
summary.apiReferenceFound = File.Exists(Path.Combine(reportsFolder, "api-reference.md"));
|
||||
summary.filePurposeFound = File.Exists(Path.Combine(reportsFolder, "file-purpose.md"));
|
||||
summary.staticCallMapFound = File.Exists(Path.Combine(reportsFolder, "call-map.md"));
|
||||
summary.unityScriptReportFound = File.Exists(Path.Combine(reportsFolder, "unity-scripts.md"));
|
||||
|
||||
ReadProjectFlow(Path.Combine(reportsFolder, "project-flow.md"), summary);
|
||||
summary.notes = "Imported repository-root Git reports with best-effort parsing.";
|
||||
return summary;
|
||||
}
|
||||
|
||||
private static int ExtractCount(string text, string pattern)
|
||||
{
|
||||
Match match = Regex.Match(text, pattern);
|
||||
if (match.Success && int.TryParse(match.Groups[1].Value, out int value))
|
||||
{
|
||||
return value;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
private static void ReadProjectFlow(string path, RLGitReportSummary summary)
|
||||
{
|
||||
if (!File.Exists(path))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
string[] lines = File.ReadAllLines(path);
|
||||
bool inEntry = false;
|
||||
bool inImportant = false;
|
||||
|
||||
foreach (string line in lines)
|
||||
{
|
||||
if (line.StartsWith("## "))
|
||||
{
|
||||
inEntry = line.Contains("Likely Entry Point") || line.Contains("Possible Startup");
|
||||
inImportant = line.Contains("Important Files");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (line.StartsWith("- ") && inEntry)
|
||||
{
|
||||
summary.likelyEntryPoints.Add(line.Substring(2));
|
||||
}
|
||||
else if (line.StartsWith("- ") && inImportant)
|
||||
{
|
||||
summary.importantFiles.Add(line.Substring(2));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace RunlevelSystems.DevPlus1.EditorTools
|
||||
{
|
||||
public static class RLPrefabAnalyzer
|
||||
{
|
||||
public static List<RLPrefabInfo> AnalyzePrefabs()
|
||||
{
|
||||
List<RLPrefabInfo> results = new List<RLPrefabInfo>();
|
||||
string[] guids = AssetDatabase.FindAssets("t:Prefab");
|
||||
|
||||
foreach (string guid in guids)
|
||||
{
|
||||
string path = AssetDatabase.GUIDToAssetPath(guid);
|
||||
GameObject prefab = AssetDatabase.LoadAssetAtPath<GameObject>(path);
|
||||
if (prefab == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
RLPrefabInfo info = new RLPrefabInfo();
|
||||
info.prefabPath = path;
|
||||
TraversePrefab(prefab, info);
|
||||
results.Add(info);
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
private static void TraversePrefab(GameObject gameObject, RLPrefabInfo info)
|
||||
{
|
||||
info.missingScriptCount += GameObjectUtility.GetMonoBehavioursWithMissingScriptCount(gameObject);
|
||||
|
||||
Component[] components = gameObject.GetComponents<Component>();
|
||||
foreach (Component component in components)
|
||||
{
|
||||
if (component == null)
|
||||
{
|
||||
AddUnique(info.components, "Missing Script");
|
||||
continue;
|
||||
}
|
||||
|
||||
AddUnique(info.components, component.GetType().Name);
|
||||
if (component is MonoBehaviour)
|
||||
{
|
||||
AddUnique(info.attachedScripts, component.GetType().Name);
|
||||
}
|
||||
|
||||
CollectReferences(component, info);
|
||||
}
|
||||
|
||||
string prefabSource = PrefabUtility.GetPrefabAssetPathOfNearestInstanceRoot(gameObject);
|
||||
if (!string.IsNullOrEmpty(prefabSource) && prefabSource != info.prefabPath)
|
||||
{
|
||||
AddUnique(info.nestedPrefabs, prefabSource);
|
||||
}
|
||||
|
||||
foreach (Transform child in gameObject.transform)
|
||||
{
|
||||
TraversePrefab(child.gameObject, info);
|
||||
}
|
||||
}
|
||||
|
||||
private static void CollectReferences(Component component, RLPrefabInfo info)
|
||||
{
|
||||
SerializedObject serializedObject = new SerializedObject(component);
|
||||
SerializedProperty property = serializedObject.GetIterator();
|
||||
bool enterChildren = true;
|
||||
while (property.NextVisible(enterChildren))
|
||||
{
|
||||
enterChildren = false;
|
||||
if (property.propertyType != SerializedPropertyType.ObjectReference)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (property.objectReferenceValue != null)
|
||||
{
|
||||
AddUnique(info.importantReferences, component.GetType().Name + "." + property.displayName + " -> " + property.objectReferenceValue.name);
|
||||
}
|
||||
else if (property.objectReferenceInstanceIDValue != 0)
|
||||
{
|
||||
info.missingReferenceCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void AddUnique(List<string> values, string value)
|
||||
{
|
||||
if (!values.Contains(value))
|
||||
{
|
||||
values.Add(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,145 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace RunlevelSystems.DevPlus1.EditorTools
|
||||
{
|
||||
public class RLProjectAnalyzerWindow : EditorWindow
|
||||
{
|
||||
private RLProjectAnalysisData data = new RLProjectAnalysisData();
|
||||
private string lastRunTime = "Not run yet";
|
||||
private Vector2 scroll;
|
||||
|
||||
[MenuItem("Runlevel Systems/DevPlus1/Analyze Unity Project")]
|
||||
public static void ShowWindow()
|
||||
{
|
||||
RLProjectAnalyzerWindow window = GetWindow<RLProjectAnalyzerWindow>("Runlevel DevPlus1 Project Analyzer");
|
||||
window.minSize = new Vector2(520f, 520f);
|
||||
}
|
||||
|
||||
[MenuItem("Runlevel Systems/DevPlus1/Open Report Folder")]
|
||||
public static void OpenReportFolder()
|
||||
{
|
||||
RLReportExporter.RevealReportFolder();
|
||||
}
|
||||
|
||||
[MenuItem("Runlevel Systems/DevPlus1/Refresh Git Reports")]
|
||||
public static void RefreshGitReportsMenu()
|
||||
{
|
||||
RLGitReportSummary git = RLGitReportImporter.ImportGitReports();
|
||||
RLReportExporter.WriteGitSummary(git);
|
||||
AssetDatabase.Refresh();
|
||||
Debug.Log("Runlevel DevPlus1 Git report summary refreshed.");
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
RLReportExporter.EnsureFolders();
|
||||
data.projectName = Application.productName;
|
||||
data.unityVersion = Application.unityVersion;
|
||||
}
|
||||
|
||||
private void OnGUI()
|
||||
{
|
||||
scroll = EditorGUILayout.BeginScrollView(scroll);
|
||||
|
||||
EditorGUILayout.LabelField("Runlevel DevPlus1 Project Analyzer", EditorStyles.boldLabel);
|
||||
EditorGUILayout.Space();
|
||||
|
||||
if (GUILayout.Button("Import Git Reports")) ImportGitReports();
|
||||
if (GUILayout.Button("Analyze Open Scene")) AnalyzeOpenScenes();
|
||||
if (GUILayout.Button("Analyze Build Settings Scenes")) AnalyzeBuildSettingsScenes();
|
||||
if (GUILayout.Button("Analyze All Asset Scenes")) AnalyzeAllAssetScenes();
|
||||
if (GUILayout.Button("Analyze Prefabs")) AnalyzePrefabs();
|
||||
if (GUILayout.Button("Analyze Scripts")) AnalyzeScripts();
|
||||
if (GUILayout.Button("Generate All Reports")) GenerateAllReports();
|
||||
if (GUILayout.Button("Open Reports Folder")) RLReportExporter.RevealReportFolder();
|
||||
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.LabelField("Last run time", lastRunTime);
|
||||
EditorGUILayout.LabelField("Scenes analyzed", data.scenes.Count.ToString());
|
||||
EditorGUILayout.LabelField("Scripts analyzed", data.scripts.Count.ToString());
|
||||
EditorGUILayout.LabelField("Prefabs analyzed", data.prefabs.Count.ToString());
|
||||
EditorGUILayout.LabelField("Missing script count", CountMissingScripts().ToString());
|
||||
EditorGUILayout.LabelField("Missing reference count", CountMissingReferences().ToString());
|
||||
EditorGUILayout.LabelField("Report folder path", RLReportExporter.AbsoluteReportFolder);
|
||||
|
||||
EditorGUILayout.EndScrollView();
|
||||
}
|
||||
|
||||
private void ImportGitReports()
|
||||
{
|
||||
data.gitReports = RLGitReportImporter.ImportGitReports();
|
||||
RLReportExporter.WriteGitSummary(data.gitReports);
|
||||
MarkRun();
|
||||
}
|
||||
|
||||
private void AnalyzeOpenScenes()
|
||||
{
|
||||
data.scenes = RLSceneAnalyzer.AnalyzeOpenScenes();
|
||||
MarkRun();
|
||||
}
|
||||
|
||||
private void AnalyzeBuildSettingsScenes()
|
||||
{
|
||||
data.scenes = RLSceneAnalyzer.AnalyzeBuildSettingsScenes();
|
||||
MarkRun();
|
||||
}
|
||||
|
||||
private void AnalyzeAllAssetScenes()
|
||||
{
|
||||
data.scenes = RLSceneAnalyzer.AnalyzeAllAssetScenes();
|
||||
MarkRun();
|
||||
}
|
||||
|
||||
private void AnalyzePrefabs()
|
||||
{
|
||||
data.prefabs = RLPrefabAnalyzer.AnalyzePrefabs();
|
||||
MarkRun();
|
||||
}
|
||||
|
||||
private void AnalyzeScripts()
|
||||
{
|
||||
data.scripts = RLScriptAnalyzer.AnalyzeScripts();
|
||||
MarkRun();
|
||||
}
|
||||
|
||||
private void GenerateAllReports()
|
||||
{
|
||||
data.projectName = Application.productName;
|
||||
data.unityVersion = Application.unityVersion;
|
||||
data.generatedAt = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
|
||||
data.gitReports = RLGitReportImporter.ImportGitReports();
|
||||
data.scenes = RLSceneAnalyzer.AnalyzeOpenScenes();
|
||||
data.prefabs = RLPrefabAnalyzer.AnalyzePrefabs();
|
||||
data.scripts = RLScriptAnalyzer.AnalyzeScripts();
|
||||
RLAIContextExporter.EnrichProjectContext(data);
|
||||
RLReportExporter.ExportAll(data);
|
||||
MarkRun();
|
||||
Debug.Log("Runlevel DevPlus1 Unity reports generated.");
|
||||
}
|
||||
|
||||
private void MarkRun()
|
||||
{
|
||||
lastRunTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
|
||||
Repaint();
|
||||
}
|
||||
|
||||
private int CountMissingScripts()
|
||||
{
|
||||
int count = 0;
|
||||
foreach (RLSceneInfo scene in data.scenes) count += scene.missingScriptCount;
|
||||
foreach (RLPrefabInfo prefab in data.prefabs) count += prefab.missingScriptCount;
|
||||
return count;
|
||||
}
|
||||
|
||||
private int CountMissingReferences()
|
||||
{
|
||||
int count = 0;
|
||||
foreach (RLSceneInfo scene in data.scenes) count += scene.missingReferenceCount;
|
||||
foreach (RLPrefabInfo prefab in data.prefabs) count += prefab.missingReferenceCount;
|
||||
return count;
|
||||
}
|
||||
}
|
||||
}
|
||||
567
Assets/RL_DevPlus1/Editor/ProjectAnalyzer/RLReportExporter.cs
Normal file
567
Assets/RL_DevPlus1/Editor/ProjectAnalyzer/RLReportExporter.cs
Normal file
|
|
@ -0,0 +1,567 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace RunlevelSystems.DevPlus1.EditorTools
|
||||
{
|
||||
[Serializable]
|
||||
public class RLProjectAnalysisData
|
||||
{
|
||||
public string projectName;
|
||||
public string unityVersion;
|
||||
public string generatedAt;
|
||||
public List<RLSceneInfo> scenes = new List<RLSceneInfo>();
|
||||
public List<RLScriptInfo> scripts = new List<RLScriptInfo>();
|
||||
public List<RLPrefabInfo> prefabs = new List<RLPrefabInfo>();
|
||||
public RLGitReportSummary gitReports = new RLGitReportSummary();
|
||||
public List<string> suggestedFirstFiles = new List<string>();
|
||||
public List<string> risksOrUnknowns = new List<string>();
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class RLSceneInfo
|
||||
{
|
||||
public string scenePath;
|
||||
public string sceneName;
|
||||
public int buildIndex = -1;
|
||||
public int rootGameObjectCount;
|
||||
public int totalGameObjects;
|
||||
public int activeGameObjects;
|
||||
public int inactiveGameObjects;
|
||||
public int missingScriptCount;
|
||||
public int missingReferenceCount;
|
||||
public List<string> rootGameObjects = new List<string>();
|
||||
public List<RLGameObjectInfo> gameObjects = new List<RLGameObjectInfo>();
|
||||
public List<RLUnityEventInfo> unityEvents = new List<RLUnityEventInfo>();
|
||||
public string notes;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class RLGameObjectInfo
|
||||
{
|
||||
public string hierarchyPath;
|
||||
public bool activeSelf;
|
||||
public string tag;
|
||||
public int layer;
|
||||
public List<string> components = new List<string>();
|
||||
public List<string> attachedScripts = new List<string>();
|
||||
public List<string> referencedObjects = new List<string>();
|
||||
public int missingScriptCount;
|
||||
public int missingReferenceCount;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class RLScriptInfo
|
||||
{
|
||||
public string scriptPath;
|
||||
public string className;
|
||||
public string baseClass;
|
||||
public bool isMonoBehaviour;
|
||||
public bool isScriptableObject;
|
||||
public List<string> lifecycleMethods = new List<string>();
|
||||
public List<string> publicMethods = new List<string>();
|
||||
public List<string> serializedFields = new List<string>();
|
||||
public List<string> publicFields = new List<string>();
|
||||
public List<string> unityApiUsage = new List<string>();
|
||||
public string possibleRole;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class RLPrefabInfo
|
||||
{
|
||||
public string prefabPath;
|
||||
public List<string> components = new List<string>();
|
||||
public List<string> attachedScripts = new List<string>();
|
||||
public List<string> nestedPrefabs = new List<string>();
|
||||
public List<string> importantReferences = new List<string>();
|
||||
public int missingScriptCount;
|
||||
public int missingReferenceCount;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class RLUnityEventInfo
|
||||
{
|
||||
public string sourcePath;
|
||||
public string gameObjectPath;
|
||||
public string componentName;
|
||||
public string eventName;
|
||||
public string targetObject;
|
||||
public string targetComponent;
|
||||
public string targetMethod;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class RLGitReportSummary
|
||||
{
|
||||
public bool reportsFolderFound;
|
||||
public bool validationReportFound;
|
||||
public bool validationFoundErrors;
|
||||
public int validationWarnings = -1;
|
||||
public int validationErrors = -1;
|
||||
public bool apiReferenceFound;
|
||||
public bool filePurposeFound;
|
||||
public bool staticCallMapFound;
|
||||
public bool unityScriptReportFound;
|
||||
public List<string> likelyEntryPoints = new List<string>();
|
||||
public List<string> importantFiles = new List<string>();
|
||||
public List<string> foundReports = new List<string>();
|
||||
public List<string> missingReports = new List<string>();
|
||||
public string notes;
|
||||
}
|
||||
|
||||
public static class RLReportExporter
|
||||
{
|
||||
public const string RootFolder = "Assets/RL_DevPlus1";
|
||||
public const string ReportFolder = RootFolder + "/Reports";
|
||||
|
||||
public static void EnsureFolders()
|
||||
{
|
||||
EnsureAssetFolder("Assets", "RL_DevPlus1");
|
||||
EnsureAssetFolder(RootFolder, "Reports");
|
||||
EnsureAssetFolder(RootFolder, "Docs");
|
||||
EnsureAssetFolder(RootFolder, "Runtime");
|
||||
}
|
||||
|
||||
public static string AbsoluteReportFolder
|
||||
{
|
||||
get { return Path.GetFullPath(Path.Combine(Application.dataPath, "RL_DevPlus1/Reports")); }
|
||||
}
|
||||
|
||||
public static void ExportAll(RLProjectAnalysisData data)
|
||||
{
|
||||
EnsureFolders();
|
||||
WriteProjectSummary(data);
|
||||
WriteSceneMap(data);
|
||||
WriteGameObjectMap(data);
|
||||
WriteScriptMap(data);
|
||||
WriteEventMap(data);
|
||||
WritePrefabMap(data);
|
||||
WriteExecutionOrder(data);
|
||||
WriteMissingReferences(data);
|
||||
WriteGitSummary(data.gitReports);
|
||||
WriteProjectDataJson(data);
|
||||
WriteAIContext(data);
|
||||
WriteReportIndex();
|
||||
AssetDatabase.Refresh();
|
||||
}
|
||||
|
||||
public static void WriteGitSummary(RLGitReportSummary git)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.AppendLine("# Runlevel Unity Git Report Summary");
|
||||
sb.AppendLine();
|
||||
sb.AppendLine("- Git reports folder found: " + BoolText(git.reportsFolderFound));
|
||||
sb.AppendLine("- Validation report found: " + BoolText(git.validationReportFound));
|
||||
sb.AppendLine("- Validation found errors: " + BoolText(git.validationFoundErrors));
|
||||
sb.AppendLine("- Validation warnings: " + ValueOrUnknown(git.validationWarnings));
|
||||
sb.AppendLine("- Validation errors: " + ValueOrUnknown(git.validationErrors));
|
||||
sb.AppendLine("- API reference found: " + BoolText(git.apiReferenceFound));
|
||||
sb.AppendLine("- File purpose report found: " + BoolText(git.filePurposeFound));
|
||||
sb.AppendLine("- Static call map found: " + BoolText(git.staticCallMapFound));
|
||||
sb.AppendLine("- Unity script report found: " + BoolText(git.unityScriptReportFound));
|
||||
AppendList(sb, "Likely Entry Points From Git Reports", git.likelyEntryPoints);
|
||||
AppendList(sb, "Important Files From Git Reports", git.importantFiles);
|
||||
AppendList(sb, "Found Reports", git.foundReports);
|
||||
AppendList(sb, "Missing Reports", git.missingReports);
|
||||
sb.AppendLine("## Notes");
|
||||
sb.AppendLine();
|
||||
sb.AppendLine(string.IsNullOrEmpty(git.notes) ? "Best-effort import only. Missing Git reports are allowed." : git.notes);
|
||||
WriteReport("RL_Unity_Git_Report_Summary.md", sb.ToString());
|
||||
}
|
||||
|
||||
private static void WriteProjectSummary(RLProjectAnalysisData data)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.AppendLine("# Runlevel Unity Project Summary");
|
||||
sb.AppendLine();
|
||||
sb.AppendLine("- Project name: " + data.projectName);
|
||||
sb.AppendLine("- Unity version: " + data.unityVersion);
|
||||
sb.AppendLine("- Generated at: " + data.generatedAt);
|
||||
sb.AppendLine("- Scenes analyzed: " + data.scenes.Count);
|
||||
sb.AppendLine("- Scripts analyzed: " + data.scripts.Count);
|
||||
sb.AppendLine("- Prefabs analyzed: " + data.prefabs.Count);
|
||||
sb.AppendLine("- Missing scripts detected: " + CountMissingScripts(data));
|
||||
sb.AppendLine("- Missing references detected: " + CountMissingReferences(data));
|
||||
sb.AppendLine();
|
||||
sb.AppendLine("This report is best-effort and needs manual confirmation before project changes are made.");
|
||||
WriteReport("RL_Unity_Project_Summary.md", sb.ToString());
|
||||
}
|
||||
|
||||
private static void WriteSceneMap(RLProjectAnalysisData data)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.AppendLine("# Runlevel Unity Scene Map");
|
||||
sb.AppendLine();
|
||||
foreach (RLSceneInfo scene in data.scenes)
|
||||
{
|
||||
sb.AppendLine("## " + scene.sceneName);
|
||||
sb.AppendLine();
|
||||
sb.AppendLine("- Scene path: `" + scene.scenePath + "`");
|
||||
sb.AppendLine("- Build index: " + scene.buildIndex);
|
||||
sb.AppendLine("- Root GameObjects: " + scene.rootGameObjectCount);
|
||||
sb.AppendLine("- Total GameObjects: " + scene.totalGameObjects);
|
||||
sb.AppendLine("- Active/Inactive: " + scene.activeGameObjects + "/" + scene.inactiveGameObjects);
|
||||
sb.AppendLine("- Missing scripts: " + scene.missingScriptCount);
|
||||
sb.AppendLine("- Missing references: " + scene.missingReferenceCount);
|
||||
AppendList(sb, "Root GameObjects", scene.rootGameObjects);
|
||||
if (!string.IsNullOrEmpty(scene.notes))
|
||||
{
|
||||
sb.AppendLine("Notes: " + scene.notes);
|
||||
sb.AppendLine();
|
||||
}
|
||||
}
|
||||
WriteReport("RL_Unity_Scene_Map.md", sb.ToString());
|
||||
}
|
||||
|
||||
private static void WriteGameObjectMap(RLProjectAnalysisData data)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.AppendLine("# Runlevel Unity GameObject Map");
|
||||
sb.AppendLine();
|
||||
foreach (RLSceneInfo scene in data.scenes)
|
||||
{
|
||||
sb.AppendLine("## Scene: " + scene.sceneName);
|
||||
sb.AppendLine();
|
||||
foreach (RLGameObjectInfo go in scene.gameObjects)
|
||||
{
|
||||
sb.AppendLine("- `" + go.hierarchyPath + "` | active=" + go.activeSelf + " | tag=" + go.tag + " | layer=" + go.layer + " | components=" + string.Join(", ", go.components.ToArray()));
|
||||
}
|
||||
sb.AppendLine();
|
||||
}
|
||||
WriteReport("RL_Unity_GameObject_Map.md", sb.ToString());
|
||||
}
|
||||
|
||||
private static void WriteScriptMap(RLProjectAnalysisData data)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.AppendLine("# Runlevel Unity Script Map");
|
||||
sb.AppendLine();
|
||||
foreach (RLScriptInfo script in data.scripts)
|
||||
{
|
||||
sb.AppendLine("## `" + script.scriptPath + "`");
|
||||
sb.AppendLine();
|
||||
sb.AppendLine("- Class: " + script.className);
|
||||
sb.AppendLine("- Base class: " + script.baseClass);
|
||||
sb.AppendLine("- MonoBehaviour: " + BoolText(script.isMonoBehaviour));
|
||||
sb.AppendLine("- ScriptableObject: " + BoolText(script.isScriptableObject));
|
||||
sb.AppendLine("- Possible role: " + script.possibleRole);
|
||||
AppendList(sb, "Lifecycle Methods", script.lifecycleMethods);
|
||||
AppendList(sb, "Public Methods", script.publicMethods);
|
||||
AppendList(sb, "Serialized Fields", script.serializedFields);
|
||||
AppendList(sb, "Public Fields", script.publicFields);
|
||||
AppendList(sb, "Unity API Usage", script.unityApiUsage);
|
||||
}
|
||||
WriteReport("RL_Unity_Script_Map.md", sb.ToString());
|
||||
}
|
||||
|
||||
private static void WriteEventMap(RLProjectAnalysisData data)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.AppendLine("# Runlevel Unity Event Map");
|
||||
sb.AppendLine();
|
||||
bool any = false;
|
||||
foreach (RLSceneInfo scene in data.scenes)
|
||||
{
|
||||
foreach (RLUnityEventInfo evt in scene.unityEvents)
|
||||
{
|
||||
any = true;
|
||||
sb.AppendLine("- Scene `" + scene.scenePath + "` GameObject `" + evt.gameObjectPath + "` component `" + evt.componentName + "` event `" + evt.eventName + "` targets `" + evt.targetObject + "." + evt.targetMethod + "`");
|
||||
}
|
||||
}
|
||||
if (!any)
|
||||
{
|
||||
sb.AppendLine("No UnityEvent or Button callback bindings detected in analyzed scenes.");
|
||||
}
|
||||
WriteReport("RL_Unity_Event_Map.md", sb.ToString());
|
||||
}
|
||||
|
||||
private static void WritePrefabMap(RLProjectAnalysisData data)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.AppendLine("# Runlevel Unity Prefab Map");
|
||||
sb.AppendLine();
|
||||
foreach (RLPrefabInfo prefab in data.prefabs)
|
||||
{
|
||||
sb.AppendLine("## `" + prefab.prefabPath + "`");
|
||||
sb.AppendLine();
|
||||
AppendList(sb, "Components", prefab.components);
|
||||
AppendList(sb, "Attached Scripts", prefab.attachedScripts);
|
||||
AppendList(sb, "Nested Prefabs", prefab.nestedPrefabs);
|
||||
AppendList(sb, "Important References", prefab.importantReferences);
|
||||
sb.AppendLine("- Missing scripts: " + prefab.missingScriptCount);
|
||||
sb.AppendLine("- Missing references: " + prefab.missingReferenceCount);
|
||||
sb.AppendLine();
|
||||
}
|
||||
WriteReport("RL_Unity_Prefab_Map.md", sb.ToString());
|
||||
}
|
||||
|
||||
private static void WriteExecutionOrder(RLProjectAnalysisData data)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.AppendLine("# Runlevel Unity Execution Order");
|
||||
sb.AppendLine();
|
||||
sb.AppendLine("## Script Execution Order Settings");
|
||||
sb.AppendLine();
|
||||
bool any = false;
|
||||
string[] scriptGuids = AssetDatabase.FindAssets("t:MonoScript");
|
||||
foreach (string guid in scriptGuids)
|
||||
{
|
||||
string path = AssetDatabase.GUIDToAssetPath(guid);
|
||||
MonoScript script = AssetDatabase.LoadAssetAtPath<MonoScript>(path);
|
||||
if (script == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
int order = MonoImporter.GetExecutionOrder(script);
|
||||
if (order != 0)
|
||||
{
|
||||
any = true;
|
||||
sb.AppendLine("- " + script.name + ": " + order);
|
||||
}
|
||||
}
|
||||
if (!any)
|
||||
{
|
||||
sb.AppendLine("- No custom script execution order detected.");
|
||||
}
|
||||
sb.AppendLine();
|
||||
sb.AppendLine("## Probable Runtime Order");
|
||||
sb.AppendLine();
|
||||
sb.AppendLine("- Scene load");
|
||||
sb.AppendLine("- Awake");
|
||||
sb.AppendLine("- OnEnable");
|
||||
sb.AppendLine("- Start");
|
||||
sb.AppendLine("- Update / FixedUpdate / LateUpdate");
|
||||
sb.AppendLine("- UnityEvents / UI callbacks");
|
||||
sb.AppendLine("- Scene transitions");
|
||||
AppendList(sb, "Lifecycle Methods By Script", BuildLifecycleLines(data.scripts));
|
||||
WriteReport("RL_Unity_Execution_Order.md", sb.ToString());
|
||||
}
|
||||
|
||||
private static void WriteMissingReferences(RLProjectAnalysisData data)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.AppendLine("# Runlevel Unity Missing References");
|
||||
sb.AppendLine();
|
||||
foreach (RLSceneInfo scene in data.scenes)
|
||||
{
|
||||
foreach (RLGameObjectInfo go in scene.gameObjects)
|
||||
{
|
||||
if (go.missingScriptCount > 0 || go.missingReferenceCount > 0)
|
||||
{
|
||||
sb.AppendLine("- Scene `" + scene.scenePath + "` GameObject `" + go.hierarchyPath + "` missing scripts=" + go.missingScriptCount + " missing references=" + go.missingReferenceCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach (RLPrefabInfo prefab in data.prefabs)
|
||||
{
|
||||
if (prefab.missingScriptCount > 0 || prefab.missingReferenceCount > 0)
|
||||
{
|
||||
sb.AppendLine("- Prefab `" + prefab.prefabPath + "` missing scripts=" + prefab.missingScriptCount + " missing references=" + prefab.missingReferenceCount);
|
||||
}
|
||||
}
|
||||
if (sb.ToString().TrimEnd().EndsWith("References", StringComparison.Ordinal))
|
||||
{
|
||||
sb.AppendLine("No missing scripts or missing serialized object references detected in analyzed assets.");
|
||||
}
|
||||
WriteReport("RL_Unity_Missing_References.md", sb.ToString());
|
||||
}
|
||||
|
||||
private static void WriteProjectDataJson(RLProjectAnalysisData data)
|
||||
{
|
||||
WriteReport("RL_Unity_Project_Data.json", JsonUtility.ToJson(data, true));
|
||||
}
|
||||
|
||||
private static void WriteAIContext(RLProjectAnalysisData data)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.AppendLine("# Runlevel AI Project Context");
|
||||
sb.AppendLine();
|
||||
sb.AppendLine("This report is intended to be fed into AI/Codex before deeper Unity project work.");
|
||||
sb.AppendLine();
|
||||
sb.AppendLine("- Project name: " + data.projectName);
|
||||
sb.AppendLine("- Unity version: " + data.unityVersion);
|
||||
sb.AppendLine("- Main likely entry scene: " + GetLikelyEntryScene(data));
|
||||
sb.AppendLine("- Git validation status: " + (data.gitReports.validationFoundErrors ? "Detected customer code errors" : "No customer code errors detected or report missing"));
|
||||
AppendList(sb, "Scenes", SceneLines(data.scenes));
|
||||
AppendList(sb, "Important Managers/Controllers", ManagerLines(data.scripts));
|
||||
AppendList(sb, "MonoBehaviour Scripts", ScriptLines(data.scripts, true));
|
||||
AppendList(sb, "ScriptableObjects", ScriptLines(data.scripts, false));
|
||||
AppendList(sb, "Prefabs", PrefabLines(data.prefabs));
|
||||
AppendList(sb, "Scene Transitions", UsageLines(data.scripts, "SceneManager"));
|
||||
AppendList(sb, "Suggested First Files For AI To Inspect", data.suggestedFirstFiles);
|
||||
AppendList(sb, "Suggested Risks Or Unknowns", data.risksOrUnknowns);
|
||||
sb.AppendLine("## Limitations");
|
||||
sb.AppendLine();
|
||||
sb.AppendLine("- Best-effort static and editor inspection only.");
|
||||
sb.AppendLine("- Runtime-created objects, reflection, dependency injection, addressable content, and generated code may be incomplete.");
|
||||
sb.AppendLine("- Findings need manual confirmation before changes are made.");
|
||||
WriteReport("RL_AI_Project_Context.md", sb.ToString());
|
||||
WriteReport("RL_AI_Project_Context.json", JsonUtility.ToJson(data, true));
|
||||
}
|
||||
|
||||
private static void WriteReportIndex()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.AppendLine("# Runlevel Unity Report Index");
|
||||
sb.AppendLine();
|
||||
sb.AppendLine("- `RL_Unity_Project_Summary.md`: high-level project counts and status.");
|
||||
sb.AppendLine("- `RL_Unity_Scene_Map.md`: scene paths, roots, counts, and missing reference totals.");
|
||||
sb.AppendLine("- `RL_Unity_GameObject_Map.md`: GameObject hierarchy and component overview.");
|
||||
sb.AppendLine("- `RL_Unity_Script_Map.md`: C# script lifecycle, fields, methods, and Unity API usage.");
|
||||
sb.AppendLine("- `RL_Unity_Event_Map.md`: detected UnityEvent and Button callback bindings.");
|
||||
sb.AppendLine("- `RL_Unity_Prefab_Map.md`: prefab components, scripts, nested prefabs, and missing references.");
|
||||
sb.AppendLine("- `RL_Unity_Execution_Order.md`: script execution order settings and probable lifecycle order.");
|
||||
sb.AppendLine("- `RL_Unity_Missing_References.md`: missing scripts and serialized reference issues.");
|
||||
sb.AppendLine("- `RL_Unity_Git_Report_Summary.md`: imported root `reports/` summary if available.");
|
||||
sb.AppendLine("- `RL_Unity_Project_Data.json`: AI-readable Unity analysis data.");
|
||||
sb.AppendLine("- `RL_AI_Project_Context.md`: primary AI/Codex context report.");
|
||||
sb.AppendLine("- `RL_AI_Project_Context.json`: machine-readable AI context data.");
|
||||
WriteReport("RL_Unity_Report_Index.md", sb.ToString());
|
||||
}
|
||||
|
||||
public static void WriteReport(string fileName, string contents)
|
||||
{
|
||||
EnsureFolders();
|
||||
File.WriteAllText(Path.Combine(AbsoluteReportFolder, fileName), contents, Encoding.UTF8);
|
||||
}
|
||||
|
||||
public static void RevealReportFolder()
|
||||
{
|
||||
EnsureFolders();
|
||||
EditorUtility.RevealInFinder(AbsoluteReportFolder);
|
||||
}
|
||||
|
||||
private static void EnsureAssetFolder(string parent, string child)
|
||||
{
|
||||
string full = parent + "/" + child;
|
||||
if (!AssetDatabase.IsValidFolder(full))
|
||||
{
|
||||
AssetDatabase.CreateFolder(parent, child);
|
||||
}
|
||||
}
|
||||
|
||||
private static string BoolText(bool value)
|
||||
{
|
||||
return value ? "yes" : "no";
|
||||
}
|
||||
|
||||
private static string ValueOrUnknown(int value)
|
||||
{
|
||||
return value >= 0 ? value.ToString() : "unknown";
|
||||
}
|
||||
|
||||
private static void AppendList(StringBuilder sb, string title, List<string> values)
|
||||
{
|
||||
sb.AppendLine("## " + title);
|
||||
sb.AppendLine();
|
||||
if (values == null || values.Count == 0)
|
||||
{
|
||||
sb.AppendLine("- None detected.");
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (string value in values)
|
||||
{
|
||||
sb.AppendLine("- " + value);
|
||||
}
|
||||
}
|
||||
sb.AppendLine();
|
||||
}
|
||||
|
||||
private static int CountMissingScripts(RLProjectAnalysisData data)
|
||||
{
|
||||
int count = 0;
|
||||
foreach (RLSceneInfo scene in data.scenes) count += scene.missingScriptCount;
|
||||
foreach (RLPrefabInfo prefab in data.prefabs) count += prefab.missingScriptCount;
|
||||
return count;
|
||||
}
|
||||
|
||||
private static int CountMissingReferences(RLProjectAnalysisData data)
|
||||
{
|
||||
int count = 0;
|
||||
foreach (RLSceneInfo scene in data.scenes) count += scene.missingReferenceCount;
|
||||
foreach (RLPrefabInfo prefab in data.prefabs) count += prefab.missingReferenceCount;
|
||||
return count;
|
||||
}
|
||||
|
||||
private static List<string> BuildLifecycleLines(List<RLScriptInfo> scripts)
|
||||
{
|
||||
List<string> lines = new List<string>();
|
||||
foreach (RLScriptInfo script in scripts)
|
||||
{
|
||||
if (script.lifecycleMethods.Count > 0)
|
||||
{
|
||||
lines.Add(script.className + ": " + string.Join(", ", script.lifecycleMethods.ToArray()));
|
||||
}
|
||||
}
|
||||
return lines;
|
||||
}
|
||||
|
||||
private static string GetLikelyEntryScene(RLProjectAnalysisData data)
|
||||
{
|
||||
foreach (RLSceneInfo scene in data.scenes)
|
||||
{
|
||||
if (scene.buildIndex == 0) return scene.scenePath;
|
||||
}
|
||||
return data.scenes.Count > 0 ? data.scenes[0].scenePath : "No scene analyzed";
|
||||
}
|
||||
|
||||
private static List<string> SceneLines(List<RLSceneInfo> scenes)
|
||||
{
|
||||
List<string> lines = new List<string>();
|
||||
foreach (RLSceneInfo scene in scenes) lines.Add(scene.scenePath + " (" + scene.totalGameObjects + " GameObjects)");
|
||||
return lines;
|
||||
}
|
||||
|
||||
private static List<string> ManagerLines(List<RLScriptInfo> scripts)
|
||||
{
|
||||
List<string> lines = new List<string>();
|
||||
foreach (RLScriptInfo script in scripts)
|
||||
{
|
||||
string lower = (script.className + " " + script.possibleRole).ToLowerInvariant();
|
||||
if (lower.Contains("manager") || lower.Contains("controller"))
|
||||
{
|
||||
lines.Add(script.scriptPath + " - " + script.possibleRole);
|
||||
}
|
||||
}
|
||||
return lines;
|
||||
}
|
||||
|
||||
private static List<string> ScriptLines(List<RLScriptInfo> scripts, bool monoBehaviour)
|
||||
{
|
||||
List<string> lines = new List<string>();
|
||||
foreach (RLScriptInfo script in scripts)
|
||||
{
|
||||
if ((monoBehaviour && script.isMonoBehaviour) || (!monoBehaviour && script.isScriptableObject))
|
||||
{
|
||||
lines.Add(script.scriptPath + " - " + script.className);
|
||||
}
|
||||
}
|
||||
return lines;
|
||||
}
|
||||
|
||||
private static List<string> PrefabLines(List<RLPrefabInfo> prefabs)
|
||||
{
|
||||
List<string> lines = new List<string>();
|
||||
foreach (RLPrefabInfo prefab in prefabs) lines.Add(prefab.prefabPath);
|
||||
return lines;
|
||||
}
|
||||
|
||||
private static List<string> UsageLines(List<RLScriptInfo> scripts, string usage)
|
||||
{
|
||||
List<string> lines = new List<string>();
|
||||
foreach (RLScriptInfo script in scripts)
|
||||
{
|
||||
if (script.unityApiUsage.Contains(usage))
|
||||
{
|
||||
lines.Add(script.scriptPath);
|
||||
}
|
||||
}
|
||||
return lines;
|
||||
}
|
||||
}
|
||||
}
|
||||
193
Assets/RL_DevPlus1/Editor/ProjectAnalyzer/RLSceneAnalyzer.cs
Normal file
193
Assets/RL_DevPlus1/Editor/ProjectAnalyzer/RLSceneAnalyzer.cs
Normal file
|
|
@ -0,0 +1,193 @@
|
|||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEditor.SceneManagement;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
namespace RunlevelSystems.DevPlus1.EditorTools
|
||||
{
|
||||
public static class RLSceneAnalyzer
|
||||
{
|
||||
public static List<RLSceneInfo> AnalyzeOpenScenes()
|
||||
{
|
||||
List<RLSceneInfo> results = new List<RLSceneInfo>();
|
||||
for (int i = 0; i < SceneManager.sceneCount; i++)
|
||||
{
|
||||
Scene scene = SceneManager.GetSceneAt(i);
|
||||
if (scene.IsValid() && scene.isLoaded)
|
||||
{
|
||||
results.Add(AnalyzeLoadedScene(scene));
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
public static List<RLSceneInfo> AnalyzeBuildSettingsScenes()
|
||||
{
|
||||
List<string> paths = new List<string>();
|
||||
foreach (EditorBuildSettingsScene scene in EditorBuildSettings.scenes)
|
||||
{
|
||||
if (scene.enabled)
|
||||
{
|
||||
paths.Add(scene.path);
|
||||
}
|
||||
}
|
||||
return AnalyzeScenePaths(paths);
|
||||
}
|
||||
|
||||
public static List<RLSceneInfo> AnalyzeAllAssetScenes()
|
||||
{
|
||||
List<string> paths = new List<string>();
|
||||
foreach (string guid in AssetDatabase.FindAssets("t:Scene"))
|
||||
{
|
||||
paths.Add(AssetDatabase.GUIDToAssetPath(guid));
|
||||
}
|
||||
return AnalyzeScenePaths(paths);
|
||||
}
|
||||
|
||||
private static List<RLSceneInfo> AnalyzeScenePaths(List<string> paths)
|
||||
{
|
||||
List<RLSceneInfo> results = new List<RLSceneInfo>();
|
||||
if (HasDirtyOpenScenes())
|
||||
{
|
||||
RLSceneInfo skipped = new RLSceneInfo();
|
||||
skipped.sceneName = "Scene analysis skipped";
|
||||
skipped.scenePath = "Open scenes contain unsaved changes";
|
||||
skipped.notes = "The analyzer does not save scenes. Save or discard changes manually, then run scene analysis again.";
|
||||
results.Add(skipped);
|
||||
return results;
|
||||
}
|
||||
|
||||
SceneSetup[] setup = EditorSceneManager.GetSceneManagerSetup();
|
||||
try
|
||||
{
|
||||
foreach (string path in paths)
|
||||
{
|
||||
if (string.IsNullOrEmpty(path))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Scene scene = EditorSceneManager.OpenScene(path, OpenSceneMode.Single);
|
||||
results.Add(AnalyzeLoadedScene(scene));
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (setup != null && setup.Length > 0)
|
||||
{
|
||||
EditorSceneManager.RestoreSceneManagerSetup(setup);
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
private static bool HasDirtyOpenScenes()
|
||||
{
|
||||
for (int i = 0; i < SceneManager.sceneCount; i++)
|
||||
{
|
||||
Scene scene = SceneManager.GetSceneAt(i);
|
||||
if (scene.isDirty)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static RLSceneInfo AnalyzeLoadedScene(Scene scene)
|
||||
{
|
||||
RLSceneInfo info = new RLSceneInfo();
|
||||
info.scenePath = scene.path;
|
||||
info.sceneName = scene.name;
|
||||
info.buildIndex = scene.buildIndex;
|
||||
GameObject[] roots = scene.GetRootGameObjects();
|
||||
info.rootGameObjectCount = roots.Length;
|
||||
|
||||
foreach (GameObject root in roots)
|
||||
{
|
||||
info.rootGameObjects.Add(root.name);
|
||||
AnalyzeGameObjectRecursive(root, root.name, scene.path, info);
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
public static void AnalyzeGameObjectRecursive(GameObject gameObject, string hierarchyPath, string sourcePath, RLSceneInfo sceneInfo)
|
||||
{
|
||||
RLGameObjectInfo goInfo = AnalyzeGameObject(gameObject, hierarchyPath);
|
||||
sceneInfo.gameObjects.Add(goInfo);
|
||||
sceneInfo.totalGameObjects++;
|
||||
if (gameObject.activeSelf) sceneInfo.activeGameObjects++;
|
||||
else sceneInfo.inactiveGameObjects++;
|
||||
sceneInfo.missingScriptCount += goInfo.missingScriptCount;
|
||||
sceneInfo.missingReferenceCount += goInfo.missingReferenceCount;
|
||||
sceneInfo.unityEvents.AddRange(RLUnityEventAnalyzer.ExtractUnityEvents(gameObject, sourcePath, hierarchyPath));
|
||||
|
||||
foreach (Transform child in gameObject.transform)
|
||||
{
|
||||
AnalyzeGameObjectRecursive(child.gameObject, hierarchyPath + "/" + child.name, sourcePath, sceneInfo);
|
||||
}
|
||||
}
|
||||
|
||||
public static RLGameObjectInfo AnalyzeGameObject(GameObject gameObject, string hierarchyPath)
|
||||
{
|
||||
RLGameObjectInfo info = new RLGameObjectInfo();
|
||||
info.hierarchyPath = hierarchyPath;
|
||||
info.activeSelf = gameObject.activeSelf;
|
||||
info.tag = gameObject.tag;
|
||||
info.layer = gameObject.layer;
|
||||
info.missingScriptCount = GameObjectUtility.GetMonoBehavioursWithMissingScriptCount(gameObject);
|
||||
|
||||
Component[] components = gameObject.GetComponents<Component>();
|
||||
foreach (Component component in components)
|
||||
{
|
||||
if (component == null)
|
||||
{
|
||||
info.components.Add("Missing Script");
|
||||
continue;
|
||||
}
|
||||
|
||||
info.components.Add(component.GetType().Name);
|
||||
MonoBehaviour monoBehaviour = component as MonoBehaviour;
|
||||
if (monoBehaviour != null)
|
||||
{
|
||||
info.attachedScripts.Add(component.GetType().Name);
|
||||
}
|
||||
|
||||
CollectSerializedReferences(component, info);
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
private static void CollectSerializedReferences(Component component, RLGameObjectInfo info)
|
||||
{
|
||||
SerializedObject serializedObject = new SerializedObject(component);
|
||||
SerializedProperty property = serializedObject.GetIterator();
|
||||
bool enterChildren = true;
|
||||
while (property.NextVisible(enterChildren))
|
||||
{
|
||||
enterChildren = false;
|
||||
if (property.propertyType != SerializedPropertyType.ObjectReference)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (property.objectReferenceValue != null)
|
||||
{
|
||||
string referenceName = property.displayName + " -> " + property.objectReferenceValue.name;
|
||||
if (!info.referencedObjects.Contains(referenceName))
|
||||
{
|
||||
info.referencedObjects.Add(referenceName);
|
||||
}
|
||||
}
|
||||
else if (property.objectReferenceInstanceIDValue != 0)
|
||||
{
|
||||
info.missingReferenceCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
147
Assets/RL_DevPlus1/Editor/ProjectAnalyzer/RLScriptAnalyzer.cs
Normal file
147
Assets/RL_DevPlus1/Editor/ProjectAnalyzer/RLScriptAnalyzer.cs
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text.RegularExpressions;
|
||||
using UnityEditor;
|
||||
|
||||
namespace RunlevelSystems.DevPlus1.EditorTools
|
||||
{
|
||||
public static class RLScriptAnalyzer
|
||||
{
|
||||
private static readonly string[] LifecycleMethods =
|
||||
{
|
||||
"Awake", "OnEnable", "Start", "Update", "FixedUpdate", "LateUpdate",
|
||||
"OnDisable", "OnDestroy", "OnTriggerEnter", "OnTriggerExit",
|
||||
"OnCollisionEnter", "OnCollisionExit"
|
||||
};
|
||||
|
||||
private static readonly string[] UnityApiMarkers =
|
||||
{
|
||||
"SceneManager", "Instantiate", "Destroy", "GetComponent",
|
||||
"FindObjectOfType", "FindFirstObjectByType", "Resources.Load",
|
||||
"Addressables", "Input", "UnityEvent"
|
||||
};
|
||||
|
||||
public static List<RLScriptInfo> AnalyzeScripts()
|
||||
{
|
||||
List<RLScriptInfo> results = new List<RLScriptInfo>();
|
||||
string[] guids = AssetDatabase.FindAssets("t:MonoScript");
|
||||
|
||||
foreach (string guid in guids)
|
||||
{
|
||||
string path = AssetDatabase.GUIDToAssetPath(guid);
|
||||
if (path.StartsWith("Assets/RL_DevPlus1/Editor/"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
MonoScript monoScript = AssetDatabase.LoadAssetAtPath<MonoScript>(path);
|
||||
if (monoScript == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
string text = File.Exists(path) ? File.ReadAllText(path) : string.Empty;
|
||||
System.Type scriptClass = monoScript.GetClass();
|
||||
RLScriptInfo info = new RLScriptInfo();
|
||||
info.scriptPath = path;
|
||||
info.className = scriptClass != null ? scriptClass.Name : GuessClassName(text);
|
||||
info.baseClass = scriptClass != null && scriptClass.BaseType != null ? scriptClass.BaseType.Name : GuessBaseClass(text);
|
||||
info.isMonoBehaviour = scriptClass != null && typeof(UnityEngine.MonoBehaviour).IsAssignableFrom(scriptClass);
|
||||
info.isScriptableObject = scriptClass != null && typeof(UnityEngine.ScriptableObject).IsAssignableFrom(scriptClass);
|
||||
info.lifecycleMethods.AddRange(FindLifecycleMethods(text));
|
||||
info.publicMethods.AddRange(FindPublicMethods(text));
|
||||
info.serializedFields.AddRange(FindSerializedFields(text));
|
||||
info.publicFields.AddRange(FindPublicFields(text));
|
||||
info.unityApiUsage.AddRange(FindUnityApiUsage(text));
|
||||
info.possibleRole = GuessRole(path, info);
|
||||
results.Add(info);
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
private static string GuessClassName(string text)
|
||||
{
|
||||
Match match = Regex.Match(text, @"class\s+([A-Za-z_][A-Za-z0-9_]*)");
|
||||
return match.Success ? match.Groups[1].Value : "not detected";
|
||||
}
|
||||
|
||||
private static string GuessBaseClass(string text)
|
||||
{
|
||||
Match match = Regex.Match(text, @"class\s+[A-Za-z_][A-Za-z0-9_]*\s*:\s*([A-Za-z_][A-Za-z0-9_]*)");
|
||||
return match.Success ? match.Groups[1].Value : "not detected";
|
||||
}
|
||||
|
||||
private static List<string> FindLifecycleMethods(string text)
|
||||
{
|
||||
List<string> results = new List<string>();
|
||||
foreach (string method in LifecycleMethods)
|
||||
{
|
||||
if (Regex.IsMatch(text, @"\b" + method + @"\s*\("))
|
||||
{
|
||||
results.Add(method);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
private static List<string> FindPublicMethods(string text)
|
||||
{
|
||||
return UniqueMatches(text, @"public\s+[A-Za-z_][A-Za-z0-9_<>,\[\]\?]*\s+([A-Za-z_][A-Za-z0-9_]*)\s*\(");
|
||||
}
|
||||
|
||||
private static List<string> FindSerializedFields(string text)
|
||||
{
|
||||
return UniqueMatches(text, @"\[SerializeField\]\s*(private|protected|public)?\s*[A-Za-z_][A-Za-z0-9_<>,\[\]]*\s+([A-Za-z_][A-Za-z0-9_]*)", 2);
|
||||
}
|
||||
|
||||
private static List<string> FindPublicFields(string text)
|
||||
{
|
||||
return UniqueMatches(text, @"public\s+[A-Za-z_][A-Za-z0-9_<>,\[\]]*\s+([A-Za-z_][A-Za-z0-9_]*)\s*(=|;)");
|
||||
}
|
||||
|
||||
private static List<string> FindUnityApiUsage(string text)
|
||||
{
|
||||
List<string> results = new List<string>();
|
||||
foreach (string marker in UnityApiMarkers)
|
||||
{
|
||||
if (text.Contains(marker))
|
||||
{
|
||||
results.Add(marker);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
private static List<string> UniqueMatches(string text, string pattern, int group = 1)
|
||||
{
|
||||
List<string> results = new List<string>();
|
||||
foreach (Match match in Regex.Matches(text, pattern))
|
||||
{
|
||||
string value = match.Groups[group].Value;
|
||||
if (!string.IsNullOrEmpty(value) && !results.Contains(value))
|
||||
{
|
||||
results.Add(value);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
private static string GuessRole(string path, RLScriptInfo info)
|
||||
{
|
||||
string value = (path + " " + info.className).ToLowerInvariant();
|
||||
if (value.Contains("player")) return "Possible player controller";
|
||||
if (value.Contains("enemy") || value.Contains("ai")) return "Possible enemy AI";
|
||||
if (value.Contains("ui") || value.Contains("menu") || value.Contains("hud")) return "Possible UI controller";
|
||||
if (value.Contains("game") && value.Contains("manager")) return "Possible game manager";
|
||||
if (value.Contains("spawner") || value.Contains("spawn")) return "Possible spawner";
|
||||
if (value.Contains("inventory")) return "Possible inventory system";
|
||||
if (value.Contains("health") || value.Contains("damage")) return "Possible health/damage system";
|
||||
if (value.Contains("camera")) return "Possible camera controller";
|
||||
if (value.Contains("audio") || value.Contains("music")) return "Possible audio manager";
|
||||
if (value.Contains("scene")) return "Possible scene loader";
|
||||
if (info.isScriptableObject) return "Possible data/config asset";
|
||||
return "Possible utility or gameplay script";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace RunlevelSystems.DevPlus1.EditorTools
|
||||
{
|
||||
public static class RLUnityEventAnalyzer
|
||||
{
|
||||
public static List<RLUnityEventInfo> ExtractUnityEvents(GameObject gameObject, string sourcePath, string hierarchyPath)
|
||||
{
|
||||
List<RLUnityEventInfo> events = new List<RLUnityEventInfo>();
|
||||
Component[] components = gameObject.GetComponents<Component>();
|
||||
|
||||
foreach (Component component in components)
|
||||
{
|
||||
if (component == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
SerializedObject serializedObject = new SerializedObject(component);
|
||||
SerializedProperty iterator = serializedObject.GetIterator();
|
||||
bool enterChildren = true;
|
||||
|
||||
while (iterator.NextVisible(enterChildren))
|
||||
{
|
||||
enterChildren = false;
|
||||
if (iterator.propertyType == SerializedPropertyType.Generic &&
|
||||
(iterator.type.Contains("UnityEvent") || iterator.displayName.Contains("On Click") || iterator.name.Contains("m_OnClick")))
|
||||
{
|
||||
ExtractPersistentCalls(events, iterator.Copy(), sourcePath, hierarchyPath, component);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return events;
|
||||
}
|
||||
|
||||
private static void ExtractPersistentCalls(List<RLUnityEventInfo> events, SerializedProperty eventProperty, string sourcePath, string hierarchyPath, Component component)
|
||||
{
|
||||
SerializedProperty calls = eventProperty.FindPropertyRelative("m_PersistentCalls.m_Calls");
|
||||
if (calls == null || !calls.isArray)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < calls.arraySize; i++)
|
||||
{
|
||||
SerializedProperty call = calls.GetArrayElementAtIndex(i);
|
||||
Object target = ReadObject(call, "m_Target");
|
||||
string method = ReadString(call, "m_MethodName");
|
||||
|
||||
RLUnityEventInfo info = new RLUnityEventInfo();
|
||||
info.sourcePath = sourcePath;
|
||||
info.gameObjectPath = hierarchyPath;
|
||||
info.componentName = component.GetType().Name;
|
||||
info.eventName = eventProperty.displayName;
|
||||
info.targetObject = target != null ? target.name : "missing or none";
|
||||
info.targetComponent = target != null ? target.GetType().Name : "not detected";
|
||||
info.targetMethod = string.IsNullOrEmpty(method) ? "not detected" : method;
|
||||
events.Add(info);
|
||||
}
|
||||
}
|
||||
|
||||
private static Object ReadObject(SerializedProperty parent, string relativePath)
|
||||
{
|
||||
SerializedProperty property = parent.FindPropertyRelative(relativePath);
|
||||
return property != null ? property.objectReferenceValue : null;
|
||||
}
|
||||
|
||||
private static string ReadString(SerializedProperty parent, string relativePath)
|
||||
{
|
||||
SerializedProperty property = parent.FindPropertyRelative(relativePath);
|
||||
return property != null ? property.stringValue : string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
5
Assets/RL_DevPlus1/Reports/README.md
Normal file
5
Assets/RL_DevPlus1/Reports/README.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
# Runlevel DevPlus1 Reports
|
||||
|
||||
Unity analyzer reports are generated here.
|
||||
|
||||
This folder must only contain safe report files such as `.md`, `.txt`, and `.json`.
|
||||
3
Assets/RL_DevPlus1/Reports/RL_AI_Project_Context.json
Normal file
3
Assets/RL_DevPlus1/Reports/RL_AI_Project_Context.json
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"status": "not generated yet"
|
||||
}
|
||||
3
Assets/RL_DevPlus1/Reports/RL_AI_Project_Context.md
Normal file
3
Assets/RL_DevPlus1/Reports/RL_AI_Project_Context.md
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# Runlevel AI Project Context
|
||||
|
||||
Not generated yet. Run `Generate All Reports` from the Unity analyzer. This is the first file future AI/Codex sessions should read after generation.
|
||||
3
Assets/RL_DevPlus1/Reports/RL_Unity_Event_Map.md
Normal file
3
Assets/RL_DevPlus1/Reports/RL_Unity_Event_Map.md
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# Runlevel Unity Event Map
|
||||
|
||||
Not generated yet. Run the Unity analyzer to populate this report.
|
||||
3
Assets/RL_DevPlus1/Reports/RL_Unity_Execution_Order.md
Normal file
3
Assets/RL_DevPlus1/Reports/RL_Unity_Execution_Order.md
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# Runlevel Unity Execution Order
|
||||
|
||||
Not generated yet. Run the Unity analyzer to populate this report.
|
||||
3
Assets/RL_DevPlus1/Reports/RL_Unity_GameObject_Map.md
Normal file
3
Assets/RL_DevPlus1/Reports/RL_Unity_GameObject_Map.md
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# Runlevel Unity GameObject Map
|
||||
|
||||
Not generated yet. Run the Unity analyzer to populate this report.
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
# Runlevel Unity Git Report Summary
|
||||
|
||||
Not generated yet. Use `Runlevel Systems/DevPlus1/Refresh Git Reports` or generate all reports.
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
# Runlevel Unity Missing References
|
||||
|
||||
Not generated yet. Run the Unity analyzer to populate this report.
|
||||
3
Assets/RL_DevPlus1/Reports/RL_Unity_Prefab_Map.md
Normal file
3
Assets/RL_DevPlus1/Reports/RL_Unity_Prefab_Map.md
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# Runlevel Unity Prefab Map
|
||||
|
||||
Not generated yet. Run the Unity analyzer to populate this report.
|
||||
3
Assets/RL_DevPlus1/Reports/RL_Unity_Project_Data.json
Normal file
3
Assets/RL_DevPlus1/Reports/RL_Unity_Project_Data.json
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"status": "not generated yet"
|
||||
}
|
||||
3
Assets/RL_DevPlus1/Reports/RL_Unity_Project_Summary.md
Normal file
3
Assets/RL_DevPlus1/Reports/RL_Unity_Project_Summary.md
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# Runlevel Unity Project Summary
|
||||
|
||||
Not generated yet. Run `Runlevel Systems/DevPlus1/Analyze Unity Project` in Unity, then click `Generate All Reports`.
|
||||
3
Assets/RL_DevPlus1/Reports/RL_Unity_Report_Index.md
Normal file
3
Assets/RL_DevPlus1/Reports/RL_Unity_Report_Index.md
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# Runlevel Unity Report Index
|
||||
|
||||
Not generated yet. Run the Unity analyzer to populate this report.
|
||||
3
Assets/RL_DevPlus1/Reports/RL_Unity_Scene_Map.md
Normal file
3
Assets/RL_DevPlus1/Reports/RL_Unity_Scene_Map.md
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# Runlevel Unity Scene Map
|
||||
|
||||
Not generated yet. Run the Unity analyzer to populate this report.
|
||||
3
Assets/RL_DevPlus1/Reports/RL_Unity_Script_Map.md
Normal file
3
Assets/RL_DevPlus1/Reports/RL_Unity_Script_Map.md
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# Runlevel Unity Script Map
|
||||
|
||||
Not generated yet. Run the Unity analyzer to populate this report.
|
||||
4
Assets/RL_DevPlus1/Runtime/README.txt
Normal file
4
Assets/RL_DevPlus1/Runtime/README.txt
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
Runtime scripts are not required for the DevPlus1 analyzer.
|
||||
|
||||
The current analyzer is Editor-only and lives under:
|
||||
Assets/RL_DevPlus1/Editor/
|
||||
Loading…
Add table
Add a link
Reference in a new issue