rhys_vdw
New member
I'm trying to migrate my BT's to use a new node, but the code misbehaves. They claim to have no root node. I have tried to force the assets to load by assigning them to a GameObject and calling `EnableBehavior`, but that doesn't work either.
In every case `tree.BehaviorSource.RootTask` is null.
In every case `tree.BehaviorSource.RootTask` is null.

C#:
[MenuItem("Effort Star/Migrate/Migrate use inventory item BT action")]
public static void MigrateUseInventory() {
var go = new GameObject { hideFlags = HideFlags.HideAndDontSave };
try {
var btComponent = go.AddComponent<BehaviorTree>();
var seen = new HashSet<ExternalBehaviorTree>();
foreach (var actor in AssetUtility.LoadAssetsOfType<ActorConfig>()) {
var tree = actor.ExternalBehaviorTree;
if (tree == null) {
continue;
}
if (!seen.Add(tree)) {
Debug.LogWarning($"Skipped '{tree.name}' as it was already processed", tree);
continue;
}
// Init tree.
btComponent.ExternalBehavior = tree;
btComponent.EnableBehavior();
if (tree.BehaviorSource.RootTask == null) {
Debug.LogWarning($"'{tree.name}' has no root task!", tree); // <-- point of failure
continue;
}
var changed = ReplaceChildTasks(
tree.BehaviorSource.RootTask,
(UseInventoryItemAction from) => {
var index = from.Index;
var item = actor.InitialItems[index];
return new UseItemAction(item);
},
tree.name
);
if (changed) EditorUtility.SetDirty(tree);
}
} finally {
UnityEngine.Object.DestroyImmediate(go);
}
}
static FieldInfo _btChildrenField = typeof(ParentTask).GetField(
"_children",
BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic
);
static bool ReplaceChildTasks<TFrom, TTo>(
Task root, Func<TFrom, TTo> cb, string graphName
) where TFrom : Task where TTo : Task {
if (root.GetType().Equals(typeof(TFrom))) {
throw new InvalidOperationException("Can't replace root task");
}
if (root is not ParentTask { Children: not null } parent) {
return false;
}
var anyChanged = false;
for (int i = 0; i < parent.Children.Count; ++i) {
var child = parent.Children[i];
if (child is TFrom from) {
var fromChildren = from is ParentTask { Children: not null } fp
? fp.Children
: null;
var nodeData = from.NodeData;
var to = cb(from);
parent.Children[i] = to;
Debug.Log($"{graphName} Replaced {typeof(TFrom).Name} with {typeof(TTo).Name}");
to.NodeData = nodeData;
if (fromChildren != null) {
if (to is not ParentTask toParent) {
throw new InvalidOperationException($"Expected {typeof(TTo)} to be a parent task");
}
_btChildrenField.SetValue(toParent, fromChildren);
}
}
anyChanged |= ReplaceChildTasks(child, cb, graphName);
}
return anyChanged;
}