I have been interning at the Engine Tools position for nearly a year, where I have modified engine source code and have implemented various requirements. Looking back, it has been a long way, and I am grateful for the help of my colleagues in the group and the excellent blogs online (such as Unity Editor editor extension function related and Intel GPA Android Reverse Related. Here is a brief record of the basic content of the engine tool position, which should be a summary and review of resignation. Percept as you travel; Try your very best; Not fear the unknown; Not regret your choice.

Editor tools

  The program not only has GamePlay orientation, but also Editor orientation, providing tools for planning art to better output content. In individual development/small teams, it may not be very important (or not at all), but if it is a large-scale project, that is a different story.

Editor classification

  It can be roughly divided into two categories: one is to open a single window, and the other is to display it in the Inspector interface

Window editor

  The main structure of the window editor is as follows:

img

1
2
3
4
5
6
7
8
9
10
11
12
13
using UnityEditor;

public class TestWindow : EditorWindow
{
static TestWindow window; //Instance object, must be static
[MenuItem("Windows/TestWindow")] //Define menu bar position
static void Open() //Open window, must be static
{
window = GetWindow<TestWindow>(false, "TestWindow", true); //Instantiation window
window.position = new Rect(600, 100, 450, 500); //(Optional) Window position and size
window.Show(); //Display window
}
}

View editor

img

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
using UnityEditor;
using UnityEngine;

[CustomEditor(typeof(TestScript))] //Specify the Mono type to be bound
public class TestScriptInspector : Editor
{
TestScript m_target;
private void OnEnable()
{
m_target = target as TestScript; //Bind target: The object being inspected
}

public override void OnInspectorGUI()
{
base.OnInspectorGUI(); //Calling parent class methods to draw TestScript's existing serializable data

if (GUILayout.Button("Button"))//Create button
{
Debug.Log("Button down");//Botton event
}
}
}

Editor Panel

  Next is how to organize the various structures in the panel. It is undeniable that Odin is indeed more neat and beautiful now, but Unity’s own Editor is easier to use and modify. The tools I have come into contact with are not as complicated as Player Setting, so I prefer to use Unity’s own Editor.

Object control

img

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
EditorGUILayout.LabelField("标题", "内容");
foldOut = EditorGUILayout.Foldout(foldOut, "显示域");//bool
if (foldOut)
{
toggle = EditorGUILayout.Toggle("开关", toggle);//bool
intVal = EditorGUILayout.IntField("整型输入", intVal);//int
stringVal = EditorGUILayout.TextField("文本输入", stringVal);//string
vecVal = EditorGUILayout.Vector4Field("向量输入", vecVal);//Vector4
layerVal = EditorGUILayout.LayerField("层级选择", layerVal);//int
tagVal = EditorGUILayout.TagField("标签选择", tagVal);//string
color = EditorGUILayout.ColorField("颜色选择", color);//Color
curve = EditorGUILayout.CurveField("动画曲线", curve);//AnimationCurve
}
foldOut = EditorGUILayout.Foldout(foldOut, "枚举对象");//复用折叠栏,主要不想给新变量取名
if (foldOut)
{
testEnum = (TestEnum)EditorGUILayout.EnumPopup("单选枚举", testEnum);//TestEnum
multEnum = (MultEnum)EditorGUILayout.EnumFlagsField("多选枚举", multEnum);//MultEnum
}
if (GUILayout.Button("按钮"))//Create button
{
Debug.Log("按下按钮");//Button Event
}
reorderableList.DoLayoutList(); //Draggable list

The draggable list needs to introduce UnityEditorInternal (optimize array display) and initialize ReorderableList before drawing

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
reorderableList = new ReorderableList(listItems, typeof(string));//list's type isReorderableList,item's type is List<string>
reorderableList.drawHeaderCallback = (Rect rect) =>
{
EditorGUI.LabelField(rect, "可拖动列表");
};
reorderableList.drawElementCallback = (Rect rect, int index, bool isActive, bool isFocused) =>
{
listItems[index] = EditorGUI.TextField(rect, listItems[index]);
};
reorderableList.onAddCallback = (ReorderableList list) =>
{
listItems.Add("New Item");
};
reorderableList.onRemoveCallback = (ReorderableList list) =>
{
listItems.RemoveAt(list.index);
};

Interface layout

img

1
2
3
4
5
6
7
8
9
10
11
12
13
14
EditorGUILayout.BeginHorizontal();//Horizontal layout
GUI.backgroundColor = Color.green;//Green background
if (GUILayout.Button("左按钮"))//Creat button
{
Debug.Log("按下按钮");//Button event
}
EditorGUILayout.Space(10);//Space 10 units
GUI.backgroundColor = Color.blue;//Blue background
if (GUILayout.Button("右按钮"))//Creat button
{
Debug.Log("按下按钮");//Button event
}
EditorGUILayout.EndHorizontal();//End horizontal layout

Message Prompt

img

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
EditorGUILayout.HelpBox("一般提示,最常用的提示", MessageType.Info);
EditorGUILayout.HelpBox("警告提示,不会吧不会吧真有人管warning", MessageType.Warning);
EditorGUILayout.HelpBox("错误提示,噔噔咚恭喜是bug而非feature呢", MessageType.Error);
if(GUILayout.Button("我秦始皇打钱"))
{
string title = "信他还是信我秦始皇", text = "勇士,朕乃始皇帝,现被困于蜀道山中," +
"若勇士能解朕之困,待朕携百万秦甲,重御六合,朕当以勇士为相,赏金千两。";
if (EditorUtility.DisplayDialog(title, text, "义不容辞", "立刻付款"))//提示窗口
{
Debug.Log("与此同时几百公里外的蜀道山中,新建的信号基站被夜色染成了黑色,矗立在山顶," +
"星星在天空中俯瞰着这片大地,只不过这千百年前投下的目光,现在才来得及匆匆一瞥。");
}
else
{
Debug.Log("良久之后,寂朗的山中似乎传来了一声悠悠的叹息:“已经三千年过去了吗?" +
"原来朕竟沉睡了如此之久。”“那宛渠人果不负朕!”");
}
}

Odin Editor

  Since I mentioned it before, I will show it briefly again. After all, Odin Editor is for sale, they create Attributes Example Window to show its various features. I don’t think I need to elaborate on it.

img

Visual Editor

  This is the demand for a dialogue editor that I encountered when I was doing my graduation project after resigning. However, I was developing it alone at that time, so I chose to write it in CSV for efficiency. Later, I started to learn about it, made a dialogue editor, and incorporated the content of the visual editor into this article. Currently, the more famous open source node editors are XNode and NodeGraphProcessor. I personally like the interface of XNode, and finally chose to use it to implement the dialogue editor. The picture below is a phased result, and the content is selected from a passage in “The Glowing Canvas on the Color of Timidity”.

img

  XNode is divided into Graph (the entire visual graph), Node (customized node) and Port (port for connecting nodes). To create a custom visual editor, you need a Graph script (to create the corresponding graph), a Node script (to define the content of the node), and a NodeEditor script (optional, to define how the elements in the node are drawn in the graph). You can fully connect to Odin and let it control it, or you can use Unity for serialization and call the GUI for drawing. I personally choose the latter (poor with no money to buy odin.jpg).

Editor file operations

  It should be noted that modifying the Prefab file directly under Load cannot be saved back, and it must be instantiated before making the modifications and saving.

1
2
3
4
5
6
7
8
9
10
AssetDatabase.CopyAsset(OldPath, NewPath) //Copy file
AssetDatabase.LoadAssetAtPath<Type>(Path) //Load file
PrefabUtility.SaveAsPrefabAsset(File, Path); //Save file

//Basic read, modifly, save operation
GameObject prefab = AssetDatabase.LoadAssetAtPath<GameObject>("Assets/Prefab/Cube.prefab"); //Read
GameObject obj = Instantiate(prefab); //instantiate
obj.AddComponent<TestScript>(); //Modify
PrefabUtility.SaveAsPrefabAsset(obj, "Assets/Prefab/Cube.prefab"); //Save
Destroy(obj); //Destory

Frame truncation, performance analysis, and reverse engineering

Frame truncation

Frame Debug

  Convenient and fast, you can view the rendering order, shaders used for rendering, and texture related information, which can help quickly locate problems

image-20231218174023418

RenderDoc

  You can view vertex data, shader code, and modify preview effects. When encountering tricky rendering problems, you can give it a try.

img

Performance analysis

  You can analyze the overhead of various functions in Unity through the built-in Profiler, and you can also use code to enable logging to understand the performance of new functional modules (further, you can try the Profile Analyzer)

image-20231218181247676

Reverse engineering

  By using Intel GPA you can reverse engineer emulators on a computer. First, open the Auto detect Launched Applications in Graphics Monitor, then run the game, take screenshots of the desired scene, and finally load relevant screenshots in Graphics Frame Analyzer to obtain model resource information.

v2-7b3596110dca547486dd28838e38d401_720w v2-1bc7225b13177b86784ecb3379a3e14b_720w v2-411c3e75909a18c7f110ff3079338b2f_r