Pulni's Editor Tools
This is a set of useful editor tools for Unity: - TypePicker - an attribute for SerializeReference fields of abstract/interface types which allows picking concrete types - ExposedProperties - a component that visualizes/groups properties of other components - DebugHelper - a set of menu items and APIs that allow you to debug specific object instances
com.pulni.editor-tools Install via UPM
Add to Unity Package Manager using this URL
https://www.pkglnk.dev/pulni4kiya-editor-tools.git README Markdown
Copy this to your project's README.md
## Installation
Add **Pulni's Editor Tools** to your Unity project via Package Manager:
1. Open **Window > Package Manager**
2. Click **+** > **Add package from git URL**
3. Enter:
```
https://www.pkglnk.dev/pulni4kiya-editor-tools.git
```
[](https://www.pkglnk.dev/pkg/pulni4kiya-editor-tools)README
Pulni's Editor Tools for Unity
- You shouldn't put your name in the name of an open source package, Pulni! ๐คจ
- You're probably right, but this way I can call it "PETs for U", and who doesn't like pets?! ๐
- You're an idiot! ... But also, fair point. ๐พ
Features
- TypePicker - an attribute for SerializeReference fields of abstract/interface types which allows picking which concrete types to use
- ManagedReferenceFixerWindow - a window solving a common issue related to
[SerializeReference]fields
- ManagedReferenceFixerWindow - a window solving a common issue related to
- ExposedProperties - a component that visualizes/groups properties of other components
- DebugHelper - a set of menu items and APIs that allow you to debug specific object instances
System Requirements
Unity 2021.3 or later.
Installation
- You can install this via git url by adding a new package from the package manager and pasting this address
https://github.com/pulni4kiya/unity-editor-tools.git
- Alternatively, you can manually add this entry in your manifest.json
"com.pulni.editor-tools": "https://github.com/pulni4kiya/unity-editor-tools.git"
- The package is also available on the openupm registry. You can install it via openupm-cli.
openupm add com.pulni.editor-tools
Note from Pulni
Hey! I hope you'll find these tools useful! I use them pretty much all the time and wanted to share them with others.
If you do like these, and wanna support me, you can "buy me a cake" on ko-fi! ๐๐ฐ
Feature details
TypePicker
Easily add more flexibility to your components and scriptable objects!
TypePicker is an attribute with a property drawer which - in combination with the SerializeReference attribute - allows you to serialize interfaces and abstract classes and choose which concrete implementation you want to use and make it editable in the inspector.
How to use
All you need to do is put the SerializeReference and TypePicker attributes on a field of an abstract/interface type!
public class MyMono : MonoBehaviour {
[SerializeReference, TypePicker] private IMyInterface myInteraface;
}
// You can have whatever you want in the interface
public interface IMyInterface { }
public class MyNumber : IMyInterface {
[SerializeField] private int number;
}
public class MyString : IMyInterface {
[SerializeField] private string text;
}
public class MyData : IMyInterface {
[SerializeField] private UnityEngine.Object obj;
[SerializeField] private Color color;
}
And the result is:
Additional options and features
- Copy and paste - this package comes with functionality that allows you to copy and paste all
[SerializeReference]fields. - Custom order and names - the options in the dropdown are sorted by their order (0 by default) and then by their name. You can customize these by adding the
[TypePickerInfo("ClassDisplayName", OrderNumber)]attribute to the classes that you want. - Group types - using the
TypePickerInfoattribute, you can also specify the name asSomeGroup/SomeNamewhich allow you to build a tree of options. - Custom type filter - you can implement a custom instance function in the class containing a serialized reference that filters the type options that you can pick in whatever way you want.
Here's example code:
public class MyMono : MonoBehaviour {
[SerializeField] private bool allowNodes;
[SerializeReference, TypePicker(nameof(GetTypeOptions))] private IMyInterface myInteraface;
private TypePickerOptions GetTypeOptions() {
if (allowNodes) {
return TypePickerHelper.GetAvailableTypes(typeof(IMyInterface));
} else {
var result = new TypePickerOptions();
result.subtypes = new System.Type[] { typeof(MyNumber), typeof(MyString) };
result.FillNamesFromTypes();
return result;
}
}
}
public interface IMyInterface { }
[TypePickerInfo("Primitive/My Number")]
public class MyNumber : IMyInterface {
[SerializeField] private int number;
}
[TypePickerInfo("Primitive/My String")]
public class MyString : IMyInterface {
[SerializeField] private string text;
}
[TypePickerInfo(order: 10)] // Make this show after the others
public class MyNode : IMyInterface {
[SerializeField] private string text;
[SerializeReference, TypePicker] private IMyInterface childElement1;
[SerializeReference, TypePicker] private IMyInterface childElement2;
}
And here's the result:
And an example of copying SerializeReference objects:
Problems you'll likely encounter and their solutions
Changing the name of a class, namespace or assembly that is serialized using
[SerializeReference]will cause serialization problems, but these can be solved by using the[MovedFrom]attribute (from theUnityEngine.Scripting.APIUpdatingnamespace) and specifying the old name.Every now and then you may get an error like
Trying to update the managed reference registry with invalid propertyPath(likely caused by a missing reference instance)'managedReferences[X].Y', with value 'Z'
which happens because data is serialized (usually as prefab override) but the serialized reference it's supposed to override no longer exists. This can be resolved by using the
SerializedReferenceFixerWindow.SerializeReference has some limitations when it comes to Generics or UnityEngine.Object objects. You can read more details here.
SerializedReferenceFixerWindow
This is a window that basically cleans up old and unused [SerializeReference] data (specifically prefab overrides to objects that no longer exist).
Using the window below, you can find all instances of such issues and clear them with the press of a button.
ExposedProperties
Add a facade for your complex prefabs in the inspector!
ExposedProperties ia s simple component that just shows properties from other components, allowing you to control the most relevant/common properties of a hierarchy at its root. This makes it much easier to set things up for a new instance of a prefab, and less likely to forget some important field.
Additionally, in the UI of the component, you can:
- Show custom (more descriptive) names for the properties
- Group the proprties into a foldout
- Make some (or all) properties read-only
How to use
DebugHelper
Improve your debug speed when dealing with many objects
The DebugHelper allows you to debug specific instances of your objects and components - very useful when you have many instances of the same component getting in the way of debugging the one that has a problem.
How to use
The DebugHelper adds a "Toggle Debug" menu item that allow you to toggle debugging on any component or game object (which means all of its components).
As soon as you click that menu item, you'll get a log whether debugging was enabled or disabled for the object / component.
Note: The flag is stored by the component instance as key, so it resets to disabled when an instance is destroyed.
Once you've enabled debugging for a component, you can put conditional breakpoints inside its code with the DBG.Check(this) as condition.
Note: Conditional breakpoints are rather slow, you may want to use the methods mentioned below instead.
Additionally, you can use DBG.LogIfDebugged, DBG.BreakIfDebugged and DBG.ActionIfDebugged to log messages, trigger a debugger break or do some custom action only if a component is being debugged. These calls will get removed from builds (using the Conditional attribute).
Here's some code that we'll try to debug:
public class TestDebugging : MonoBehaviour {
public void Update() {
DBG.LogIfDebugged(this, "Object being debugged: " + this.name, this);
if (Time.frameCount == 100) {
// Lets pretend we want to check this code
this.name.ToString();
}
}
}
And here's a video of the process:
Note: If the class DBG in the global namespace is not convenient for you, you can add the PULNI_NO_DBG compilation symbol, and the class will be removed. Instead you'll be able to use the class DebugHelper (in Pulni.EditorTools namespace) which provides the actual functionality.
Comments
No comments yet. Be the first!
Sign in to join the conversation
Sign In