- Home /
Rename a field without losing inspector values
Is there any way to rename a field on a component without losing all the values I've set for that field (in the inspector) in all of my scenes?
And/or, is it possible to automate copying of inspector values from one field to another, either in a single scene or across all scenes? This is basically what I've been doing manually (create new field; copy values from old field to new by hand; delete old field). It's quite tedious but wouldn't be so bad if I could automate that middle step!
UPDATE: Nowadays the best way to do this is probably with the FormerlySerializedAs attribute, as noted in Martin Sharkbomb's answer below.
What do you mean by rena$$anonymous$$g a field? Do you mean just changing the variable name in the script? If that's all you're doing then it should keep its value when you change it.
Use prefabs. You can easily change the values across all instances of the prefab by changing just the prefab values. As long as they remain synced.
Thanks for the thoughts.
@Powdered_sugar: I can rename a variable and keep a value that's set in the script, but I'm talking about keeping values that were set in the inspector. Those disappear when I change the name of the field in the script. (For understandable serialization reasons, as @chris_taylor points out in his answer.)
@PAEvenson: I don't think prefabs will help here. I'm not trying to change the value across a number of instances of the component, I'm trying to change the name of the field and retain the custom inspector values that were already set.
Answer by robertbu · Feb 28, 2014 at 07:47 PM
I don't do much editor scripting, but it sounds like your problem can be solved by an editor script. The process would as follows:
Add the new variable to a script
Modify the editor script to copy that data
Run the editor script on every scene that used that script to copy data from the old variable to the new one.
Disable or modify the editor script (since the variable it references is about to go away)
Delete the old variable.
For example, say a script like this where there was data initialized in the Inspector for the name 'strings' and I wanted to move it to new strings:
#pragma strict
public var strings : String[];
public var newStrings : String[];
I could use the editor script like the following to move the data (the script must be in the Editor folder and the name must match the class):
using UnityEditor;
using UnityEngine;
public class MoveVariableData : EditorWindow {
[MenuItem("Window/MoveVariableData")]
public static void ShowWindow() {
EditorWindow.GetWindow(typeof(MoveVariableData));
}
void OnGUI() {
if(GUILayout.Button("MoveData")) {
DataTest[] dts = Resources.FindObjectsOfTypeAll<DataTest>();
foreach (DataTest dt in dts) {
dt.newStrings = dt.strings;
}
}
}
}
You could then select 'MoveVariableData' from the Windows menu and click on the button to copy it over. For each script you change, you would need to edit the data type passed to FindObjectOfTypeAll(), and then change what info you copied.
Note I've done very little Editor extension work, so there may be easier or better ways to do what I've outlined.
Ah ha! This is exactly the awesome sauce I was imagining; works great. Thanks so much!
For the record, it works fine in my Scripts folder, there doesn't seem to be any need to put it in an Editor folder.
This needed a bit of tweaking but I think I've got it pretty solid now. The most important adjustment was that a PrefabUtility.RecordPrefabInstanceProperty$$anonymous$$odifications(component)
is necessary to make sure changes to instances of prefabs stick. I've also set up a one-click way to apply the copy to all scenes in the Assets/Scenes folder, or you can flip through the scenes and change one at a time.
using UnityEditor;
using UnityEngine;
using System.IO;
public class CopyFieldData : EditorWindow {
int sceneIndex; // scene to advance to next
[$$anonymous$$enuItem("Window/Copy Field Data")]
public static void ShowWindow() {
EditorWindow.GetWindow(typeof(CopyFieldData));
}
void OnGUI () {
// If you only want to change scenes that are in your build, you can do this:
//string[] paths = EditorBuildSettings.scenes.Select(scene => scene.path).ToArray();
// In my case I have debugging scenes that are not in my build, so I do this ins$$anonymous$$d:
string[] paths = Directory.GetFiles("Assets/Scenes", "*.unity");
GUIStyle buttonStyle = new GUIStyle(GUI.skin.button);
buttonStyle.margin = new RectOffset(10, 10, 10, 10);
GUIStyle labelStyle = new GUIStyle(GUI.skin.label);
labelStyle.wordWrap = true;
GUILayout.Label("Look at CopyFieldData.CopyDataInScene() to see/set what field is being copied on which component.", labelStyle);
if (GUILayout.Button("Save and open " + paths[sceneIndex], buttonStyle)) {
EditorApplication.SaveScene();
EditorApplication.OpenScene(paths[sceneIndex]);
sceneIndex++;
if (sceneIndex >= paths.Length) {
sceneIndex = 0;
}
}
if (GUILayout.Button("Copy data in this scene", buttonStyle)) {
CopyDataInScene();
}
if (GUILayout.Button("Copy data in ALL scenes", buttonStyle)) {
if (EditorApplication.SaveCurrentSceneIfUserWantsTo()) {
string originalScene = EditorApplication.currentScene;
foreach (string scene in paths) {
EditorApplication.OpenScene(scene);
EditorUtility.FocusProjectWindow();
CopyDataInScene();
EditorApplication.SaveScene();
}
EditorApplication.OpenScene(originalScene);
}
}
GUILayout.Label("Scenes Found:\n" + string.Join("\n", paths), labelStyle);
}
void CopyDataInScene () {
Debug.Log("Copying data in " + EditorApplication.currentScene);
// Find and replace "Bus" to change the component being worked on
Bus[] components = Resources.FindObjectsOfTypeAll<Bus>();
foreach (Bus component in components) {
// Edit this line to change which field is copied into which
component.newField = component.oldField;
// The following line is necessary to get changes to instances of
// prefabs to stick. If it gives you "unsupported type" errors, see:
// http://answers.unity3d.com/questions/533541/unsupported-type-error-in-custom-editor-script.html
PrefabUtility.RecordPrefabInstanceProperty$$anonymous$$odifications(component);
}
}
}
@mactyr You should place Editor scripts in Editor folders. If you don't, you will not be able to build your game. This is because the UnityEditor namespace is not included in the build, and when attempting to build the game, it'll complain about missing namespaces (UnityEditor).
I know I'm 4 years late, but totally this. However, the example code is overkill for most situations.
[ExecuteInEdit$$anonymous$$ode]
public class YourBehaviour : $$anonymous$$onoBehaviour {
public int oldProperty;
public int newProperty;
void Update() {
newProperty = oldProperty;
}
}
Return to the Editor, let the code recompile, watch the new properties copy the values of the old properties - you might need to tweak something in the scene to cause Update() to fire. Finally, delete your old properties. Boom, you're done.
Answer by Democide · Apr 16, 2015 at 01:00 PM
You might want to look into the [FormerlySerializedAs("m_MyVariable")] attribute
Blog: http://blogs.unity3d.com/2015/02/03/renaming-serialized-fields/
Excellent, I wish this had existed when I first asked the question! Thanks for the tip. Seems like this will likely be the best solution for folks using more recent versions of Unity.
Answer by chris_taylor · Feb 28, 2014 at 05:54 PM
To copy values of a component right click and click copy Component. With the component copied you can now past it as new or past its values into another one of those components.
as far as renaming I assume you are wanting to rename in the script. The problem with keeping the values is to serialization there is no way to tell that the new variable name is the same as it was, I suggest if you found a value you like making it the default when renaming the variable
Thanks Chris. It sounds like a direct rename might be impossible for serialization reasons, but maybe we can figure out something with the copying.
I don't think your copy component suggestion will help since I'm not trying to copy a component's values into another component, but rather to copy a field's value into another field, for all instances of a component. In other words, let's say in my Car class I have a field speed
, I add a field newSpeed
, and now I want all instances of newSpeed
to have the same inspector values that speed
has, for each instance of Car. Let's say I already have many Cars in my scene with speed
values customized in the inspector, so copying manually is time consu$$anonymous$$g.
It seems like there ought to be a way to automate this (with an editor script?) but I'm not sure what it is!