Preserve childs positions on prefab apply

So I got prefab with child object and I want to preserve this child’s position, which unique for every created prefab. Is there a way to keep this position on prefabs apply?

And yet another tiny question. Is there a way to not Apply some script public/serializable fields? For example bool “IsAgressive” field on NPC prefab. And I don’t want to mess up with this field on Applying NPC prefab. So is there a way? Maybe some Attribute or tricky asset (I don’t found one though)

@Deadcow_

I’ve been considering this point for a while as there do appear to be cases where it would be advantageous to mark specific fields as always overridden or not applied to prefab.

Rationale

For example, consider a case where I’ve got a prefab of a teleporter. It contains a model, collision, materials etc AND a teleporter script. This script contains a field ‘scene name’ that contains the name of the scene to load when the player uses the teleporter.

Initially it’s placed and the ‘scene name’ field is set. This field goes bold as it’s overridden by the scene. This occurs multiple times in multiple scenes as the teleporter is placed.

BUT

Person A modifies an instance of the prefab in scene A (e.g. changes collision) and applies the prefab. The overridden ‘scene name’ field is applied to prefab and is no longer overridden i.e. not bold, changes to the prefab will cause this field to change.

At a later date, person B modifies a different instance of the prefab in scene B and applies it. The scene name set on the instance in scene B then becomes the scene name set in the previously applied instance in scene A :o(

However, I could guarantee that the ‘scene name’ field should always be overridden & never applied to prefab. After the nth time such a thing breaks somewhere in a game, a game designer could quite easily say to me ‘Surely you know that that value should never be applied to prefab, can’t you just mark it as not applied to prefab?’. What am I to say? ‘Look mate, that’s not how it works, don’t you understand?’ Prefabs is prefabs, if you don’t like it, tough. That’s the way it works.’

Hmm, well, I can see them looking at me as if I’m a bit stupid because it’s surely solvable…

Simple Solution

The only solution I can see that works (without code) is to never apply changes from any placed instance. Drag in a new instance of the prefab, modify it, apply it, save the scene & then delete the prefab you just dragged in to the scene. Making sure that at some point you save the scene again without the temporary prefab. This process is not what I’d consider to be good. Artists, designers, animators etc are not going to easily follow such rules UNLESS they always do this for everything, which isn’t great. However, if it’s a one/two man band then this maybe isn’t so bad.

Better Soultion

I figure that it’s possible to do this from code using OnWillSaveAssets (docs)

I’m struggling at little for detail here but the quick and dirty solution (off the top of my head) is something like;

Define an interface for prefabs of don’t override this field (N.B. alternatively you could use reflection which may be better, or a bit slow?)

using UnityEngine;
using System.Collections;

public interface IPrefabOverride
{
	void OnWillSavePrefab();
	void OnSavePrefabComplete();
}

Add the interface to the type you need to have values not applied to;

using UnityEngine;
using System.Collections;

[ExecuteInEditMode]
public class PrefabOverrideTest : MonoBehaviour, IPrefabOverride 
{
	public  int m_exposedValue = 0;
	private int m_stashedValueNotApplied;

	void Awake()
	{
		if(!Application.isPlaying)
		{
			// wake up on load and stash defaults;
			m_stashedValueNotApplied = m_exposedValue;
			return;
		}
	}

	public void OnWillSavePrefab()
	{
		Debug.Log ("setting default prefab values");
		int tmp 				 = m_exposedValue;
		m_exposedValue 			 = m_stashedValueNotApplied;
		m_stashedValueNotApplied = m_exposedValue;
	}

	public void OnSavePrefabComplete()
	{
		Debug.Log ("restoring override prefab values");
		int tmp 				 = m_exposedValue;
		m_exposedValue 			 = m_stashedValueNotApplied;
		m_stashedValueNotApplied = tmp;
	}
}

Implement a save processor;

using UnityEngine;
using UnityEditor;
using System.Collections;
using System.Collections.Generic;

public class MyAssetModificationProcessor : AssetModificationProcessor
{
	List<IPrefabOverride> m_overrides = new List<IPrefabOverride> ();

	public static string[] OnWillSaveAssets(string[] paths)
	{
		Transform [] alltrans = Object.FindObjectOfType<Transform> ();
		m_overrides.Clear ();

		foreach (Transform trans in alltrans) 
		{
			IPrefabOverride prefaboverride = trans.GetComponent<IPrefabOverride>();
			if(prefaboverride)
			{
				prefaboverride.OnWillSavePrefab(); // notify them that they're saving
				m_overrides.Add(prefaboverride);
			}
		}
		EditorApplication.isSceneDirty = true;

		return paths;
	}
}

Missing bits… callback for when the prefab is saved. I think that it may be possible to use something on the editor update that monitors EditorApplication.isSceneDirty with a callback you can set such that it calls you back once the scene is not dirty and then clears the callback. I’ve done something like this before. So you get a callback after save and then run through the m_overrides list and call OnSavePrefabComplete(). May also be necessary to mark fields as dirty using EditorUtility.SetDirty in the implementation of OnSavePrefabComplete().

Note that the use of [ExecuteInEditMode] isn’t ideal as you would have to be careful not to do anything that’s game specific when editing e.g. bail out of Start(). OnEnable() etc if not playing.
Also note that the Awake() could register the instance with a list of things to call in the save processor which would speed things up BUT ensure that an OnDestory removes from the callback from the list etc.

Reflection could make the solution much nicer e.g.

[DontApplyToPrefab]
public string m_sceneName;

Note that any of this WILL slow down save, but I already do in a lot on save in pretty big projects without any complaint. So I recon it’s doable on save.

Erm, something like this. It’s on my todo list & I’ll work on better solution at a later date. Posting now to re-enforce that it’s a valid question that requires a valid solution… a solution is certainly attainable and valid.