Editing a script through code?

Hey all! I am creating a script editor for Unity3D. It currently supports reading scripts but it can’t edit scripts because MonoScriptObject.text is read-only and I cannot modify the existing script. Do you know of any way I can modify a script using code?

Sounds like you need to overwrite the actual .js / .cs file in your file system. If Asset.CreateAsset doesn’t work, you could use System.IO functions to just write to the file, bypassing Unity’s classes altogether.

I thought of that, but how do I get the path of the original file through the MonoScript class?

Only thing I can think of is that you’ll have to get the object in such a way that you already know where it came from, using AssetDatabase.Load or something.

I actually have them drop the script (as an asset) on an object field. Is there any way I can get its path?

None that I know of. I did get tired of Unity’s useless object selector popup, so I wrote a quick little plugin that actually filters Project prefabs by type, using their path to locate them. You could alter this to find cs/js files, and store the object’s path along with the object (probably in the findings variable):

static function ObjectSelector( cur : UnityEngine.Object, environment : String, type : System.Type, allowHierarchy : boolean ) : UnityEngine.Object {
	var objs : UnityEngine.Object[] = GetAll( type, environment, allowHierarchy );
	
	GUILayout.BeginVertical();
	GUILayout.BeginHorizontal();
	for ( var ix : int = 0; ix < objs.length; ix++ ) {
		if ( ix % 5 == 0 ) {
			GUILayout.EndHorizontal();
			GUILayout.BeginHorizontal();
		}
		if ( cur == objs[ix] ) {
			GUILayout.Label(GUIContent(objs[ix].name,objs[ix].name),GUILayout.Width(100));
		} else if ( GUILayout.Button( GUIContent(objs[ix].name,objs[ix].name), GUILayout.Width(100) ) ) {
			cur = objs[ix];
		}
	}
	GUILayout.EndHorizontal();
	GUILayout.EndVertical();
	return cur;
}

static private var findings : Hashtable;
static private function GetAll( type : System.Type, element : String, allowHierarchy : boolean ) : UnityEngine.Object[] {
	var go : GameObject;
	var accept : boolean = true;
	
	if ( !findings ) findings = new Hashtable();
	if ( GUILayout.Button("Refresh findings") || !findings.Contains(element) ) {
		if ( findings.Contains(element) ) findings.Remove(element);
		
		var obs : Array = new Array();
		if ( allowHierarchy ) {
			for ( var ob : UnityEngine.Object in Resources.FindObjectsOfTypeAll(type) as UnityEngine.Object[] ) {
				obs.Add(ob);
			}
		} else {
			var files : String[] = System.IO.Directory.GetFiles(Application.dataPath,"*.prefab", System.IO.SearchOption.AllDirectories);
			var pathlen : int = Application.dataPath.Length+1;
			
			
			for ( var ix : int = files.Length; ix > 0; ix-- ) {
				files[ix-1] = "Assets\\" + files[ix-1].Substring(pathlen);
				go = UnityEditor.AssetDatabase.LoadAssetAtPath( files[ix-1], GameObject ) as GameObject;
				if ( go.GetComponent(type) ) {
					obs.Add( go.GetComponent(type) );
				}
			}
		}
//		Debug.Log("Found " + obs.length + " " + type + " object" + (obs.length==1?"":"s"));
		findings.Add(element, obs.ToBuiltin(type) as UnityEngine.Object[]);
	}
	return findings[element] as UnityEngine.Object[];
}

ObjectSelector works like an EditorGUILayout function (put it in Inspector or Window GUI functions):

var myScript : Script;
myScript = GUIUtils.ObjectSelector ( myScript, “AllScripts”, Script, false );
// script2 = GUIUtils.ObjectSelector(myScript,“AllScripts”, Script, false );
// texture = GUIUtils.ObjectSelector(myScript,“Textures”,Texture,false);