Files
aego/scene/mutate/prefab.go
T

141 lines
3.4 KiB
Go

package mutate
import (
"maps"
"strings"
"aego/core/errs"
"aego/core/ids"
"aego/scene"
"aego/scene/prefab"
"aego/scene/sceneio"
)
func (d *Document) instantiate(op Op, res *Result) (step, error) {
s := d.Scene
p, err := d.node(op.Parent)
if err != nil {
return step{}, err
}
id, err := d.assetID(op.Prefab)
if err != nil {
return step{}, err
}
lib := d.library()
if _, err := lib.Template(id); err != nil {
return step{}, err
}
h, err := d.load(p, sceneio.EncodeInstance(d.reg, ids.NewNodeID(), &prefab.Instance{Prefab: id}), "prefab")
if err != nil {
return step{}, err
}
s.Flush()
if op.Name != "" {
s.SetName(h, op.Name)
}
if err := d.place(h, p, op); err != nil {
s.Destroy(h)
s.Flush()
return step{}, err
}
res.Created = append(res.Created, idRef(s, h))
redo := Op{Kind: KindInsert, Parent: idRef(s, p), Fragment: string(d.subtree(h)), Index: childIndex(s, h), HasIndex: true}
ch := d.change(op.Kind, h)
ch.Path = id.String()
return step{inv: RemoveNode(idRef(s, h)), redo: redo, change: ch}, nil
}
func (d *Document) owner(ref string) (scene.NodeHandle, ids.NodeID, *sceneio.PrefabInstance, error) {
s := d.Scene
h, err := d.node(ref)
if err != nil {
return h, ids.NodeID{}, nil, err
}
root, pi, ok := sceneio.OwnerRoot(s, h)
if !ok {
return h, ids.NodeID{}, nil, errs.New(errs.EditorCommand, d.nodeName(h)+" is not part of a prefab instance")
}
return root, s.ID(h), pi, nil
}
func (d *Document) revertPrefab(op Op) (step, error) {
s := d.Scene
root, node, pi, err := d.owner(op.Node)
if err != nil {
return step{}, err
}
if pi.Missing {
return step{}, errs.New(errs.EditorCommand, "the prefab of "+d.nodeName(root)+" is missing")
}
level, ok := prefab.ParseLevel(op.Level)
if !ok {
return step{}, errs.New(errs.EditorCommand, "level is property, component, node, all or orphan")
}
key := prefab.Key(op.Key)
if key == "" {
if k, ok := pi.Keys[node]; ok {
key = k
} else {
key = prefab.LocalKey(node)
}
}
lib := d.library()
inst, err := sceneio.Overrides(s, root, lib)
if err != nil {
return step{}, err
}
pick := prefab.Pick{Level: level, Key: key, Prop: prefab.PropKey{Owner: op.Owner, Field: op.Field}}
sel, rest := pick.Split(inst.Overrides, pi.Keys[s.ID(root)])
if sel.Empty() {
return step{}, ErrNothing
}
inst.Overrides = rest
st, _, err := d.replaceWith(root, sceneio.EncodeInstance(d.reg, s.ID(root), inst), op.Kind)
return st, err
}
func (d *Document) unpack(op Op) (step, error) {
s := d.Scene
root, _, pi, err := d.owner(op.Node)
if err != nil {
return step{}, err
}
keys := maps.Clone(pi.Keys)
missing := pi.Missing
st, nh, err := d.replaceWith(root, sceneio.SaveFlat(s, root, op.Deep), op.Kind)
if err != nil {
return step{}, err
}
if !op.Deep && !missing {
d.promote(keys)
st.redo.Fragment = string(d.subtree(nh))
}
return st, nil
}
func (d *Document) promote(keys map[ids.NodeID]prefab.Key) {
s := d.Scene
lib := d.library()
for id, k := range keys {
if k.Nested() {
continue
}
pi, ok := sceneio.InstanceOf(s, s.Handle(id))
if !ok || !pi.Nested {
continue
}
q, ok := lib.Prefab(pi.Prefab)
if !ok {
continue
}
own := map[ids.NodeID]prefab.Key{id: prefab.LocalKey(q.Local)}
prefix := string(k) + "/"
for sid, kk := range keys {
if rest, ok := strings.CutPrefix(string(kk), prefix); ok {
own[sid] = prefab.Key(rest)
}
}
pi.Owner, pi.Nested, pi.Keys = true, false, own
}
}