Like the OP I have a private bool in my scriptable object, it’s set to true during the course of its lifetime, this state will be serialized so next time the object is instanced it will be true from the get go
Are you sure the private variables are being serialized? I think it’s more likely that your object instances are persisting between runs which is how SerializedObject assets work, they are not scene objects.
Open the asset file in a text editor and see if those private fields are in it.
Try placing a print statement in OnDestroy to see when the object is unloaded. Is it when you expect or is it persisting.
Its persisted between editor runs at least, maybe not between player runs, havent tried. But it’s bad enough its persisted between editor runs. Will look into this more when I get home from boring dayjob.
So two monobehaviours referencing the same scriptable object will get the same object reference? In our case thats fine since we only operate at it from one place at a time. But I can see people getting strange bugs because of this. Maybe document this better?
Yes, you’re referencing an asset so that asset will persist in the editor after it has loaded like other assets do.
This will not be an issue in the player as you wont be restarting play mode.
A simple way to solve this is to Reset your private variables inside the OnEnable function, this gets called at the scene start even for persistent objects.
But you can run into a concurrent problem, you should document this better, I mean you should make it so its no way people can miss that the same reference is used. I know that the core user case is data only. But my use case above were I use the scriptable object both as data object and state machine you could run into problems. For example
[CreateAssetMenu(menuName = "Tutorial/FireStep")]
public class FireStep : TutorialStep, IHandle<FirearmDischarged>
{
public bool EmptyMagazine;
private bool done;
private Firearm firearm;
public override IEnumerator Execute()
{
firearm = Get<Firearm>();
var message = EmptyMagazine ? "Press and hold {0} to empty mag." : "Press {0} to fire a round.";
ShowPopup(firearm.Trigger.transform, string.format(message, GetCommandCaption(Commands.Fire)));
while(!done)
yield return null;
}
public void Handle(FirearmDischarged message)
{
if(firearm != message.Firearm) return;
done = !EmptyMagazine || firearm.Magazine.Empty;
}
}
For me its not a problem since I fire this in a sequential manner, but if two of above execute at the same time that happens to be the same serialized asset you will run into concurrent problems from hell. Both firearm and done properties could potentially be completely wrong
edit: come to think about it, when we use Prefabs in similar manner we always call Instantiate on it to get a clone.
ah, same workflow as for prefabs works Object.Instantiate
I have done alot of noob mistakes these latest days, I need to get alot of red wine and sleep this weekend
Similar to the OP, my SO has logic in it, where I start a Coroutine in it. To prevent the coroutine from firing more than once, I created a private boolean variable called enabled which is defaulted to false. Imagine my surprise where it loads and the value is somehow true despite me not setting it. I’m guessing that somehow it was serialized as true (not sure how), and therefore it deserializes as true when my app loads, thus ignoring my default value. This is completely unexpected behaviour, IMO.