Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
91052a54db | ||
|
|
7f4d87ef2c |
+7
-1
File diff suppressed because one or more lines are too long
@@ -98,6 +98,7 @@ vet: bootstrap
|
|||||||
|
|
||||||
lint: bootstrap
|
lint: bootstrap
|
||||||
go run honnef.co/go/tools/cmd/staticcheck@$(STATICCHECK_VERSION) $(LINT_PKGS)
|
go run honnef.co/go/tools/cmd/staticcheck@$(STATICCHECK_VERSION) $(LINT_PKGS)
|
||||||
|
go run honnef.co/go/tools/cmd/staticcheck@$(STATICCHECK_VERSION) -tags aego_editor ./editor/... ./app/... ./tests/...
|
||||||
|
|
||||||
# All graph variants, the semantic pass and the negative rule tests.
|
# All graph variants, the semantic pass and the negative rule tests.
|
||||||
depcheck:
|
depcheck:
|
||||||
|
|||||||
@@ -116,12 +116,8 @@ func TestPlayLeavesEditSceneByteIdentical(t *testing.T) {
|
|||||||
t.Fatal("Spin is not registered")
|
t.Fatal("Spin is not registered")
|
||||||
}
|
}
|
||||||
speed, _ := td.Field("speed")
|
speed, _ := td.Field("speed")
|
||||||
add := &commands.AddComponent{
|
add := commands.NewMutation("Add "+td.FullName, commands.EnvFor(es),
|
||||||
Node: spinner,
|
commands.AddComp(es, spinner, td, []commands.FieldValue{{Field: speed.ID, Value: schema.Float32(3)}}))
|
||||||
Type: td.ID,
|
|
||||||
Name: td.FullName,
|
|
||||||
Values: []commands.FieldValue{{Field: speed.ID, Value: schema.Float32(3)}},
|
|
||||||
}
|
|
||||||
if err := d.History.Exec(add); err != nil {
|
if err := d.History.Exec(add); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ func TestColliderFitsSprite(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, name := range []string{"Crate", "Bare"} {
|
for _, name := range []string{"Crate", "Bare"} {
|
||||||
id := es.ID(es.Find(es.Root(), name))
|
id := es.ID(es.Find(es.Root(), name))
|
||||||
if err := d.History.Exec(&commands.AddComponent{Node: id, Type: td.ID, Name: td.FullName, OnAdd: ctx.OnAdd(td)}); err != nil {
|
if err := d.History.Exec(commands.NewMutation("Add "+td.FullName, commands.WithOnAdd(commands.EnvFor(es), ctx.OnAdd), commands.AddComp(es, id, td, nil))); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,12 +51,8 @@ func openSpinner(t *testing.T) *spinFixture {
|
|||||||
}
|
}
|
||||||
fd, _ := td.Field("speed")
|
fd, _ := td.Field("speed")
|
||||||
f.typ, f.speed = td.ID, fd.ID
|
f.typ, f.speed = td.ID, fd.ID
|
||||||
add := &commands.AddComponent{
|
add := commands.NewMutation("Add "+td.FullName, commands.EnvFor(es),
|
||||||
Node: f.spinner,
|
commands.AddComp(es, f.spinner, td, []commands.FieldValue{{Field: fd.ID, Value: schema.Float32(3)}}))
|
||||||
Type: td.ID,
|
|
||||||
Name: td.FullName,
|
|
||||||
Values: []commands.FieldValue{{Field: fd.ID, Value: schema.Float32(3)}},
|
|
||||||
}
|
|
||||||
if err := d.History.Exec(add); err != nil {
|
if err := d.History.Exec(add); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
"aego/editor/core/history/commands"
|
"aego/editor/core/history/commands"
|
||||||
"aego/format/aetext"
|
"aego/format/aetext"
|
||||||
"aego/scene"
|
"aego/scene"
|
||||||
|
"aego/scene/mutate"
|
||||||
"aego/scene/sceneio"
|
"aego/scene/sceneio"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -237,12 +238,24 @@ func Paste(ctx *context.Editor) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
frags, err := commands.Fragments(data)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
parent, index := pasteTarget(ctx)
|
parent, index := pasteTarget(ctx)
|
||||||
cmd := &commands.Create{Parent: parent, Index: index, Fragment: data, Name: "Paste"}
|
ops := make([]mutate.Op, len(frags))
|
||||||
|
for i, f := range frags {
|
||||||
|
at := -1
|
||||||
|
if index >= 0 {
|
||||||
|
at = index + i
|
||||||
|
}
|
||||||
|
ops[i] = commands.Insert(parent, at, f)
|
||||||
|
}
|
||||||
|
cmd := commands.NewMutation("Create Paste", commands.EnvFor(d.Scene()), ops...)
|
||||||
if err := d.History.Exec(cmd); err != nil {
|
if err := d.History.Exec(cmd); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
ctx.Select(append([]ids.NodeID(nil), cmd.Roots()...)...)
|
ctx.Select(cmd.Created()...)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -267,17 +280,13 @@ func Duplicate(ctx *context.Editor) error {
|
|||||||
tx.Abort()
|
tx.Abort()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
c := &commands.Create{
|
c := commands.NewMutation("Create "+s.Name(h), commands.EnvFor(s),
|
||||||
Parent: s.ID(s.Parent(h)),
|
commands.Insert(s.ID(s.Parent(h)), commands.ChildIndex(s, h)+1, string(data)))
|
||||||
Index: commands.ChildIndex(s, h) + 1,
|
|
||||||
Fragment: data,
|
|
||||||
Name: s.Name(h),
|
|
||||||
}
|
|
||||||
if err := tx.Exec(c); err != nil {
|
if err := tx.Exec(c); err != nil {
|
||||||
tx.Abort()
|
tx.Abort()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
created = append(created, c.Roots()...)
|
created = append(created, c.Created()...)
|
||||||
}
|
}
|
||||||
tx.Commit()
|
tx.Commit()
|
||||||
ctx.Select(created...)
|
ctx.Select(created...)
|
||||||
@@ -294,18 +303,13 @@ func Delete(ctx *context.Editor) error {
|
|||||||
if len(tops) == 0 {
|
if len(tops) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
targets := make([]ids.NodeID, len(tops))
|
ops := make([]mutate.Op, len(tops))
|
||||||
for i, h := range tops {
|
for i, h := range tops {
|
||||||
targets[i] = s.ID(h)
|
ops[i] = mutate.RemoveNode(commands.Ref(s.ID(h)))
|
||||||
}
|
}
|
||||||
tx := d.History.Begin("Delete")
|
if err := d.History.Exec(commands.NewMutation("Delete", commands.EnvFor(s), ops...)); err != nil {
|
||||||
for _, id := range targets {
|
|
||||||
if err := tx.Exec(&commands.Delete{Node: id}); err != nil {
|
|
||||||
tx.Abort()
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
|
||||||
tx.Commit()
|
|
||||||
ctx.Select()
|
ctx.Select()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -113,8 +113,7 @@ func (e Env) encodeComponent(td *schema.TypeDescriptor, values []commands.FieldV
|
|||||||
sc := e.scratch()
|
sc := e.scratch()
|
||||||
h := sc.Create(sc.Root(), "component")
|
h := sc.Create(sc.Root(), "component")
|
||||||
sc.Flush()
|
sc.Flush()
|
||||||
add := &commands.AddComponent{Node: sc.ID(h), Type: td.ID, Name: td.FullName, Values: values}
|
if err := putComponent(sc, h, td, values); err != nil {
|
||||||
if err := add.Do(target{sc}); err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return sceneio.SaveSubtree(sc, h, true), nil
|
return sceneio.SaveSubtree(sc, h, true), nil
|
||||||
@@ -122,18 +121,14 @@ func (e Env) encodeComponent(td *schema.TypeDescriptor, values []commands.FieldV
|
|||||||
|
|
||||||
func (e Env) decodeComponent(data []byte) (*schema.TypeDescriptor, []commands.FieldValue, error) {
|
func (e Env) decodeComponent(data []byte) (*schema.TypeDescriptor, []commands.FieldValue, error) {
|
||||||
sc := e.scratch()
|
sc := e.scratch()
|
||||||
c := &commands.Create{Index: -1, Fragment: data}
|
root, err := loadScratch(sc, data)
|
||||||
if err := c.Do(target{sc}); err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
roots := c.Roots()
|
|
||||||
if len(roots) == 0 {
|
|
||||||
return nil, nil, errs.New(errs.EditorCommand, "clipboard component is empty")
|
|
||||||
}
|
|
||||||
reg := sc.Registry()
|
reg := sc.Registry()
|
||||||
unknown, hasUnknown := reg.ByName("engine.Unknown")
|
unknown, hasUnknown := reg.ByName("engine.Unknown")
|
||||||
var td *schema.TypeDescriptor
|
var td *schema.TypeDescriptor
|
||||||
sc.ComponentsOf(sc.Handle(roots[0]), func(t schema.TypeID) {
|
sc.ComponentsOf(sc.Handle(root), func(t schema.TypeID) {
|
||||||
if td != nil || (hasUnknown && t == unknown.ID) {
|
if td != nil || (hasUnknown && t == unknown.ID) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -142,7 +137,7 @@ func (e Env) decodeComponent(data []byte) (*schema.TypeDescriptor, []commands.Fi
|
|||||||
if td == nil {
|
if td == nil {
|
||||||
return nil, nil, errs.New(errs.EditorCommand, "clipboard component type is not loaded in this editor")
|
return nil, nil, errs.New(errs.EditorCommand, "clipboard component type is not loaded in this editor")
|
||||||
}
|
}
|
||||||
values, err := componentValues(sc, roots[0], td)
|
values, err := componentValues(sc, root, td)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
@@ -189,13 +184,6 @@ func (e Env) ReadComponent() (*schema.TypeDescriptor, []commands.FieldValue, boo
|
|||||||
return td, values, true
|
return td, values, true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e Env) onAdd(td *schema.TypeDescriptor) func(*scene.Scene, scene.NodeHandle) {
|
|
||||||
if e.OnAdd == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return e.OnAdd(td)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e Env) PasteComponent(d *document.SceneDocument, nodes []ids.NodeID) error {
|
func (e Env) PasteComponent(d *document.SceneDocument, nodes []ids.NodeID) error {
|
||||||
td, values, ok := e.ReadComponent()
|
td, values, ok := e.ReadComponent()
|
||||||
if !ok {
|
if !ok {
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package clipboard
|
||||||
|
|
||||||
|
import (
|
||||||
|
"aego/core/errs"
|
||||||
|
"aego/core/ids"
|
||||||
|
"aego/editor/core/history/commands"
|
||||||
|
"aego/scene"
|
||||||
|
"aego/scene/sceneio"
|
||||||
|
"aego/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func loadScratch(sc *scene.Scene, data []byte) (ids.NodeID, error) {
|
||||||
|
root := sc.Root()
|
||||||
|
created, _, err := sceneio.LoadInto(sc, root, data, "fragment", sceneio.LoadOptions{KeepIDs: true})
|
||||||
|
if err != nil {
|
||||||
|
return ids.NodeID{}, err
|
||||||
|
}
|
||||||
|
for _, h := range created {
|
||||||
|
if sc.Parent(h) == root {
|
||||||
|
return sc.ID(h), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ids.NodeID{}, errs.New(errs.EditorCommand, "the fragment holds no node")
|
||||||
|
}
|
||||||
|
|
||||||
|
func putComponent(sc *scene.Scene, h scene.NodeHandle, td *schema.TypeDescriptor, list []commands.FieldValue) error {
|
||||||
|
return commands.NewMutation("", commands.EnvFor(sc), commands.AddRaw(sc, sc.ID(h), td, list)).Do(target{sc})
|
||||||
|
}
|
||||||
@@ -22,6 +22,7 @@ type compData struct {
|
|||||||
|
|
||||||
func (e Env) pasteInto(tx *history.Transaction, d *document.SceneDocument, nodes []ids.NodeID, td *schema.TypeDescriptor, values []commands.FieldValue) error {
|
func (e Env) pasteInto(tx *history.Transaction, d *document.SceneDocument, nodes []ids.NodeID, td *schema.TypeDescriptor, values []commands.FieldValue) error {
|
||||||
s := d.Scene()
|
s := d.Scene()
|
||||||
|
env := commands.WithOnAdd(commands.EnvFor(s), e.OnAdd)
|
||||||
for _, n := range nodes {
|
for _, n := range nodes {
|
||||||
h := s.Handle(n)
|
h := s.Handle(n)
|
||||||
if h.IsZero() || !s.IsAlive(h) {
|
if h.IsZero() || !s.IsAlive(h) {
|
||||||
@@ -31,7 +32,7 @@ func (e Env) pasteInto(tx *history.Transaction, d *document.SceneDocument, nodes
|
|||||||
if !s.Accepts(h, td.ID) {
|
if !s.Accepts(h, td.ID) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if err := tx.Exec(&commands.AddComponent{Node: n, Type: td.ID, Name: td.FullName, Values: values, OnAdd: e.onAdd(td)}); err != nil {
|
if err := tx.Exec(commands.NewMutation("Add "+td.FullName, env, commands.AddComp(s, n, td, values))); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
@@ -94,8 +95,7 @@ func (e Env) CopyComponents(s *scene.Scene, node ids.NodeID, types []schema.Type
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
add := &commands.AddComponent{Node: sc.ID(h), Type: td.ID, Name: td.FullName, Values: values}
|
if err := putComponent(sc, h, td, values); err != nil {
|
||||||
if err := add.Do(target{sc}); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -118,11 +118,10 @@ func (e Env) readComponents() ([]compData, bool) {
|
|||||||
data = []byte(strings.TrimPrefix(t, componentsText))
|
data = []byte(strings.TrimPrefix(t, componentsText))
|
||||||
}
|
}
|
||||||
sc := e.scratch()
|
sc := e.scratch()
|
||||||
cr := &commands.Create{Index: -1, Fragment: data}
|
root, err := loadScratch(sc, data)
|
||||||
if err := cr.Do(target{sc}); err != nil || len(cr.Roots()) == 0 {
|
if err != nil {
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
root := cr.Roots()[0]
|
|
||||||
reg := sc.Registry()
|
reg := sc.Registry()
|
||||||
unknown, hasUnknown := reg.ByName("engine.Unknown")
|
unknown, hasUnknown := reg.ByName("engine.Unknown")
|
||||||
var out []compData
|
var out []compData
|
||||||
@@ -186,14 +185,11 @@ func (e Env) EncodeScript(s *scene.Scene, node ids.NodeID, name string) ([]byte,
|
|||||||
|
|
||||||
func (e Env) decodeScript(data []byte) (string, schema.PropertyBag, error) {
|
func (e Env) decodeScript(data []byte) (string, schema.PropertyBag, error) {
|
||||||
sc := e.scratch()
|
sc := e.scratch()
|
||||||
cr := &commands.Create{Index: -1, Fragment: data}
|
root, err := loadScratch(sc, data)
|
||||||
if err := cr.Do(target{sc}); err != nil {
|
if err != nil {
|
||||||
return "", schema.PropertyBag{}, err
|
return "", schema.PropertyBag{}, err
|
||||||
}
|
}
|
||||||
if len(cr.Roots()) == 0 {
|
scs, ok := scriptcomp.ScriptsOf(sc, sc.Handle(root))
|
||||||
return "", schema.PropertyBag{}, errs.New(errs.EditorCommand, "the preset is empty")
|
|
||||||
}
|
|
||||||
scs, ok := scriptcomp.ScriptsOf(sc, sc.Handle(cr.Roots()[0]))
|
|
||||||
if !ok || len(scs.Attachments) == 0 {
|
if !ok || len(scs.Attachments) == 0 {
|
||||||
return "", schema.PropertyBag{}, errs.New(errs.EditorCommand, "the preset holds no script")
|
return "", schema.PropertyBag{}, errs.New(errs.EditorCommand, "the preset holds no script")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,9 +4,11 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"aego/core/errs"
|
"aego/core/errs"
|
||||||
|
"aego/core/ids"
|
||||||
"aego/core/mathx"
|
"aego/core/mathx"
|
||||||
"aego/editor/core/history"
|
"aego/editor/core/history"
|
||||||
"aego/scene"
|
"aego/scene"
|
||||||
|
"aego/scene/mutate"
|
||||||
"aego/scene/sceneio"
|
"aego/scene/sceneio"
|
||||||
"aego/schema"
|
"aego/schema"
|
||||||
)
|
)
|
||||||
@@ -45,6 +47,14 @@ func newScene(t *testing.T) *scene.Scene {
|
|||||||
return scene.New(types, nil, scene.Options{})
|
return scene.New(types, nil, scene.Options{})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func del(s *scene.Scene, id ids.NodeID) *Mutation {
|
||||||
|
return NewMutation("Delete", EnvFor(s), mutate.RemoveNode(Ref(id)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func reparent(s *scene.Scene, n, p scene.NodeHandle) *Mutation {
|
||||||
|
return NewMutation("Reparent", EnvFor(s), Move(s.ID(n), s.ID(p), -1, true))
|
||||||
|
}
|
||||||
|
|
||||||
func TestDeleteUndoRestoresIDsAndRefs(t *testing.T) {
|
func TestDeleteUndoRestoresIDsAndRefs(t *testing.T) {
|
||||||
s := newScene(t)
|
s := newScene(t)
|
||||||
first := s.Create(s.Root(), "First")
|
first := s.Create(s.Root(), "First")
|
||||||
@@ -57,7 +67,7 @@ func TestDeleteUndoRestoresIDsAndRefs(t *testing.T) {
|
|||||||
aID, childID := s.ID(a), s.ID(child)
|
aID, childID := s.ID(a), s.ID(child)
|
||||||
|
|
||||||
h := history.New(target{s})
|
h := history.New(target{s})
|
||||||
if err := h.Exec(&Delete{Node: aID}); err != nil {
|
if err := h.Exec(del(s, aID)); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if !s.Handle(aID).IsZero() || !s.Handle(childID).IsZero() {
|
if !s.Handle(aID).IsZero() || !s.Handle(childID).IsZero() {
|
||||||
@@ -100,7 +110,7 @@ func TestReparentPreservesWorld(t *testing.T) {
|
|||||||
before := s.World(n)
|
before := s.World(n)
|
||||||
|
|
||||||
h := history.New(target{s})
|
h := history.New(target{s})
|
||||||
if err := h.Exec(&Reparent{Node: s.ID(n), NewParent: s.ID(p), NewIndex: -1, KeepWorld: true}); err != nil {
|
if err := h.Exec(reparent(s, n, p)); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if s.Parent(n) != p {
|
if s.Parent(n) != p {
|
||||||
@@ -126,7 +136,7 @@ func TestReparentUnderZeroScaleFails(t *testing.T) {
|
|||||||
s.SetLocal(p, scene.Transform2D{Scale: mathx.Vec2{X: 0, Y: 1e-9}})
|
s.SetLocal(p, scene.Transform2D{Scale: mathx.Vec2{X: 0, Y: 1e-9}})
|
||||||
s.Flush()
|
s.Flush()
|
||||||
h := history.New(target{s})
|
h := history.New(target{s})
|
||||||
err := h.Exec(&Reparent{Node: s.ID(n), NewParent: s.ID(p), NewIndex: -1, KeepWorld: true})
|
err := h.Exec(reparent(s, n, p))
|
||||||
if !errs.Has(err, errs.SceneBadReparent) {
|
if !errs.Has(err, errs.SceneBadReparent) {
|
||||||
t.Fatalf("err = %v", err)
|
t.Fatalf("err = %v", err)
|
||||||
}
|
}
|
||||||
@@ -170,16 +180,17 @@ func TestCreateAndComponentRoundTrip(t *testing.T) {
|
|||||||
|
|
||||||
s := newScene(t)
|
s := newScene(t)
|
||||||
h := history.New(target{s})
|
h := history.New(target{s})
|
||||||
c := &Create{Index: -1, Fragment: fragment, Name: "Enemy"}
|
c := NewMutation("Create Enemy", EnvFor(s), Insert(ids.NodeID{}, -1, string(fragment)))
|
||||||
if err := h.Exec(c); err != nil {
|
if err := h.Exec(c); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if len(c.Roots()) != 1 {
|
roots := c.Created()
|
||||||
t.Fatalf("roots = %d", len(c.Roots()))
|
if len(roots) != 1 {
|
||||||
|
t.Fatalf("roots = %d", len(roots))
|
||||||
}
|
}
|
||||||
n := s.Handle(c.Roots()[0])
|
n := s.Handle(roots[0])
|
||||||
typeID := scene.Store[Health](s).Type()
|
td, _ := s.Registry().ByID(scene.Store[Health](s).Type())
|
||||||
if err := h.Exec(&RemoveComponent{Node: s.ID(n), Type: typeID, Name: "Health"}); err != nil {
|
if err := h.Exec(NewMutation("Remove Health", EnvFor(s), RemoveComp(s.ID(n), td))); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if scene.Has[Health](s, n) {
|
if scene.Has[Health](s, n) {
|
||||||
@@ -190,11 +201,11 @@ func TestCreateAndComponentRoundTrip(t *testing.T) {
|
|||||||
t.Fatal("component data not restored")
|
t.Fatal("component data not restored")
|
||||||
}
|
}
|
||||||
h.Undo()
|
h.Undo()
|
||||||
if !s.Handle(c.Roots()[0]).IsZero() {
|
if !s.Handle(roots[0]).IsZero() {
|
||||||
t.Fatal("create not undone")
|
t.Fatal("create not undone")
|
||||||
}
|
}
|
||||||
h.Redo()
|
h.Redo()
|
||||||
if s.Handle(c.Roots()[0]).IsZero() {
|
if s.Handle(roots[0]).IsZero() {
|
||||||
t.Fatal("redo must recreate the same node id")
|
t.Fatal("redo must recreate the same node id")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -3,61 +3,10 @@ package commands
|
|||||||
import (
|
import (
|
||||||
"aego/core/errs"
|
"aego/core/errs"
|
||||||
"aego/core/ids"
|
"aego/core/ids"
|
||||||
"aego/core/log"
|
|
||||||
"aego/editor/core/history"
|
|
||||||
"aego/scene"
|
"aego/scene"
|
||||||
"aego/scene/sceneio"
|
"aego/scene/sceneio"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Replace struct {
|
|
||||||
Node ids.NodeID
|
|
||||||
Before []byte
|
|
||||||
After []byte
|
|
||||||
Name string
|
|
||||||
Post func(s *scene.Scene)
|
|
||||||
parent ids.NodeID
|
|
||||||
index int
|
|
||||||
ready bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Replace) Label() string {
|
|
||||||
if c.Name != "" {
|
|
||||||
return c.Name
|
|
||||||
}
|
|
||||||
return "Replace"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Replace) Do(t history.Target) error {
|
|
||||||
s := t.Scene()
|
|
||||||
if err := c.swap(s, c.After); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if c.Post != nil {
|
|
||||||
c.Post(s)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Replace) Undo(t history.Target) error {
|
|
||||||
return c.swap(t.Scene(), c.Before)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Replace) Merge(history.Command) bool {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Replace) swap(s *scene.Scene, data []byte) error {
|
|
||||||
if !c.ready {
|
|
||||||
h := s.Handle(c.Node)
|
|
||||||
if h.IsZero() || !s.IsAlive(h) {
|
|
||||||
return errs.New(errs.SceneDeadNode, "node is not in the scene", log.F("node", c.Node.String()))
|
|
||||||
}
|
|
||||||
c.parent, c.index, c.ready = s.ID(s.Parent(h)), ChildIndex(s, h), true
|
|
||||||
}
|
|
||||||
_, err := ReplaceNode(s, c.Node, c.parent, c.index, data, nil)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func ReplaceNode(s *scene.Scene, node, parent ids.NodeID, index int, data []byte, lib *sceneio.Library) (scene.NodeHandle, error) {
|
func ReplaceNode(s *scene.Scene, node, parent ids.NodeID, index int, data []byte, lib *sceneio.Library) (scene.NodeHandle, error) {
|
||||||
if h := s.Handle(node); !h.IsZero() && s.IsAlive(h) {
|
if h := s.Handle(node); !h.IsZero() && s.IsAlive(h) {
|
||||||
s.Destroy(h)
|
s.Destroy(h)
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ func TestReparent3DPreservesWorld(t *testing.T) {
|
|||||||
s.Flush()
|
s.Flush()
|
||||||
before := s.World4(n)
|
before := s.World4(n)
|
||||||
h := history.New(target{s})
|
h := history.New(target{s})
|
||||||
if err := h.Exec(&Reparent{Node: s.ID(n), NewParent: s.ID(p), NewIndex: -1, KeepWorld: true}); err != nil {
|
if err := h.Exec(reparent(s, n, p)); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if s.Parent(n) != p {
|
if s.Parent(n) != p {
|
||||||
@@ -39,7 +39,7 @@ func TestReparent3DUnderTwoDFails(t *testing.T) {
|
|||||||
n := s.Create3D(s.Root(), "N")
|
n := s.Create3D(s.Root(), "N")
|
||||||
s.Flush()
|
s.Flush()
|
||||||
h := history.New(target{s})
|
h := history.New(target{s})
|
||||||
err := h.Exec(&Reparent{Node: s.ID(n), NewParent: s.ID(flat), NewIndex: -1, KeepWorld: true})
|
err := h.Exec(reparent(s, n, flat))
|
||||||
if !errs.Has(err, errs.SceneSpaceMismatch) {
|
if !errs.Has(err, errs.SceneSpaceMismatch) {
|
||||||
t.Fatalf("err = %v", err)
|
t.Fatalf("err = %v", err)
|
||||||
}
|
}
|
||||||
@@ -57,7 +57,7 @@ func TestReparent2DIntoThreeDKeepsWorld(t *testing.T) {
|
|||||||
s.Flush()
|
s.Flush()
|
||||||
before := s.World4(n)
|
before := s.World4(n)
|
||||||
h := history.New(target{s})
|
h := history.New(target{s})
|
||||||
if err := h.Exec(&Reparent{Node: s.ID(n), NewParent: s.ID(p), NewIndex: -1, KeepWorld: true}); err != nil {
|
if err := h.Exec(reparent(s, n, p)); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if !s.Under3D(n) || !s.World4(n).NearlyEqual(before, 1e-4) {
|
if !s.Under3D(n) || !s.World4(n).NearlyEqual(before, 1e-4) {
|
||||||
@@ -97,7 +97,7 @@ func TestDeleteUndoKeepsSpace(t *testing.T) {
|
|||||||
s.Flush()
|
s.Flush()
|
||||||
id := s.ID(n)
|
id := s.ID(n)
|
||||||
h := history.New(target{s})
|
h := history.New(target{s})
|
||||||
if err := h.Exec(&Delete{Node: id}); err != nil {
|
if err := h.Exec(del(s, id)); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
h.Undo()
|
h.Undo()
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -480,6 +480,7 @@ func (c *Controller) CopyToEdit(nodes []ids.NodeID, t schema.TypeID) error {
|
|||||||
if !ok {
|
if !ok {
|
||||||
return errs.New(errs.SchemaUnknownType, "component type is not registered")
|
return errs.New(errs.SchemaUnknownType, "component type is not registered")
|
||||||
}
|
}
|
||||||
|
env := commands.EnvFor(es)
|
||||||
tx := real.History.Begin("Copy " + td.FullName + " from Play")
|
tx := real.History.Begin("Copy " + td.FullName + " from Play")
|
||||||
for _, n := range nodes {
|
for _, n := range nodes {
|
||||||
if _, has := es.GetByType(es.Handle(n), t); !has {
|
if _, has := es.GetByType(es.Handle(n), t); !has {
|
||||||
@@ -492,7 +493,7 @@ func (c *Controller) CopyToEdit(nodes []ids.NodeID, t schema.TypeID) error {
|
|||||||
}
|
}
|
||||||
values = append(values, commands.FieldValue{Field: td.Fields[i].ID, Value: v})
|
values = append(values, commands.FieldValue{Field: td.Fields[i].ID, Value: v})
|
||||||
}
|
}
|
||||||
if err := tx.Exec(&commands.AddComponent{Node: n, Type: t, Name: td.FullName, Values: values}); err != nil {
|
if err := tx.Exec(commands.NewMutation("Add "+td.FullName, env, commands.AddComp(es, n, td, values))); err != nil {
|
||||||
tx.Abort()
|
tx.Abort()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package playdiff
|
|||||||
import (
|
import (
|
||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"aego/core/curve"
|
"aego/core/curve"
|
||||||
"aego/core/ids"
|
"aego/core/ids"
|
||||||
@@ -12,6 +13,7 @@ import (
|
|||||||
"aego/editor/core/history/commands"
|
"aego/editor/core/history/commands"
|
||||||
"aego/editor/core/props"
|
"aego/editor/core/props"
|
||||||
"aego/scene"
|
"aego/scene"
|
||||||
|
"aego/scene/mutate"
|
||||||
"aego/scene/scriptcomp"
|
"aego/scene/scriptcomp"
|
||||||
"aego/schema"
|
"aego/schema"
|
||||||
)
|
)
|
||||||
@@ -96,6 +98,16 @@ func Touched(h *history.History) map[Key]bool {
|
|||||||
switch c := c.(type) {
|
switch c := c.(type) {
|
||||||
case *commands.SetProperty:
|
case *commands.SetProperty:
|
||||||
out[Key{Node: c.Node, Type: c.Type, Field: c.Field}] = true
|
out[Key{Node: c.Node, Type: c.Type, Field: c.Field}] = true
|
||||||
|
case *commands.Mutation:
|
||||||
|
for _, ch := range c.Changes() {
|
||||||
|
switch {
|
||||||
|
case ch.Op != mutate.KindSet && ch.Op != mutate.KindReset:
|
||||||
|
case ch.Type != 0:
|
||||||
|
out[Key{Node: ch.NodeID, Type: ch.Type, Field: ch.Field}] = true
|
||||||
|
case strings.HasPrefix(ch.Path, "transform."):
|
||||||
|
out[Key{Node: ch.NodeID}] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
case *commands.SetTransform:
|
case *commands.SetTransform:
|
||||||
out[Key{Node: c.Node}] = true
|
out[Key{Node: c.Node}] = true
|
||||||
case *commands.SetTransform3D:
|
case *commands.SetTransform3D:
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ func pair(t *testing.T) (*document.SceneDocument, *document.SceneDocument, ids.N
|
|||||||
}
|
}
|
||||||
s.Flush()
|
s.Flush()
|
||||||
d := m.New(rel, s)
|
d := m.New(rel, s)
|
||||||
if err := d.History.Exec(&commands.AddComponent{Node: id, Type: td.ID, Name: td.FullName}); err != nil {
|
if err := d.History.Exec(commands.NewMutation("Add "+td.FullName, commands.EnvFor(s), commands.AddComp(s, id, td, nil))); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
docs[i] = d
|
docs[i] = d
|
||||||
@@ -108,3 +108,14 @@ func TestApplyIsOneStep(t *testing.T) {
|
|||||||
t.Fatal("undo must restore the edit scene")
|
t.Fatal("undo must restore the edit scene")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestTouchedSeesInspectorEdits(t *testing.T) {
|
||||||
|
_, play, id, td := pair(t)
|
||||||
|
fd, _ := td.Field("tint")
|
||||||
|
if err := play.Props.Set(nil, []ids.NodeID{id}, td.ID, fd.ID, schema.Color(mathx.Color{G: 1, A: 1})); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if !playdiff.Touched(play.History)[playdiff.Key{Node: id, Type: td.ID, Field: fd.ID}] {
|
||||||
|
t.Fatal("a field set through the Inspector is not touched")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+27
-112
File diff suppressed because it is too large
Load Diff
@@ -15,6 +15,7 @@ import (
|
|||||||
"aego/editor/core/document"
|
"aego/editor/core/document"
|
||||||
"aego/editor/core/history/commands"
|
"aego/editor/core/history/commands"
|
||||||
"aego/scene"
|
"aego/scene"
|
||||||
|
"aego/scene/mutate"
|
||||||
"aego/scene/prefab"
|
"aego/scene/prefab"
|
||||||
"aego/scene/sceneio"
|
"aego/scene/sceneio"
|
||||||
)
|
)
|
||||||
@@ -217,7 +218,7 @@ func (s *Service) CreateFrom(d *document.SceneDocument, nodes []ids.NodeID, dir
|
|||||||
tx.Abort()
|
tx.Abort()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := tx.Exec(&commands.Replace{Node: sc.ID(h), Before: before, After: after, Name: "Create Prefab"}); err != nil {
|
if err := tx.Exec(commands.NewMutation("Create Prefab", s.env(sc), mutate.Replace(commands.Ref(sc.ID(h)), string(after)))); err != nil {
|
||||||
tx.Abort()
|
tx.Abort()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"aego/editor/core/history"
|
"aego/editor/core/history"
|
||||||
"aego/editor/core/history/commands"
|
"aego/editor/core/history/commands"
|
||||||
"aego/scene"
|
"aego/scene"
|
||||||
|
"aego/scene/mutate"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (a *Access) Rename(tx *history.Transaction, node ids.NodeID, name string) error {
|
func (a *Access) Rename(tx *history.Transaction, node ids.NodeID, name string) error {
|
||||||
@@ -13,27 +14,29 @@ func (a *Access) Rename(tx *history.Transaction, node ids.NodeID, name string) e
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
before := a.s.Name(h)
|
if a.s.Name(h) == name || name == "" {
|
||||||
if before == name || name == "" {
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return a.within(tx, "Rename", func(tx *history.Transaction) error {
|
return a.within(tx, "Rename", func(tx *history.Transaction) error {
|
||||||
return tx.Exec(&commands.Rename{Node: node, Before: before, After: name})
|
return tx.Exec(commands.NewMutation("Rename", commands.EnvFor(a.s), mutate.Rename(commands.Ref(node), name)))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Access) SetEnabled(tx *history.Transaction, nodes []ids.NodeID, v bool) error {
|
func (a *Access) SetEnabled(tx *history.Transaction, nodes []ids.NodeID, v bool) error {
|
||||||
|
text := "false"
|
||||||
|
if v {
|
||||||
|
text = "true"
|
||||||
|
}
|
||||||
return a.within(tx, "Toggle Enabled", func(tx *history.Transaction) error {
|
return a.within(tx, "Toggle Enabled", func(tx *history.Transaction) error {
|
||||||
for _, n := range nodes {
|
for _, n := range nodes {
|
||||||
h, err := a.handle(n)
|
h, err := a.handle(n)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
before := a.s.Enabled(h)
|
if a.s.Enabled(h) == v {
|
||||||
if before == v {
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if err := tx.Exec(&commands.SetEnabled{Node: n, Before: before, After: v}); err != nil {
|
if err := tx.Exec(commands.NewMutation("Toggle Enabled", commands.EnvFor(a.s), mutate.Set(commands.Ref(n), "enabled", text))); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ func (a *Access) within(tx *history.Transaction, label string, fn func(*history.
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *Access) Set(tx *history.Transaction, nodes []ids.NodeID, t schema.TypeID, f schema.FieldID, v schema.Value) error {
|
func (a *Access) Set(tx *history.Transaction, nodes []ids.NodeID, t schema.TypeID, f schema.FieldID, v schema.Value) error {
|
||||||
_, fd, err := a.Descriptor(t, f)
|
td, fd, err := a.Descriptor(t, f)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -131,7 +131,7 @@ func (a *Access) Set(tx *history.Transaction, nodes []ids.NodeID, t schema.TypeI
|
|||||||
if Equal(before, nv) {
|
if Equal(before, nv) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if err := tx.Exec(&commands.SetProperty{Node: n, Type: t, Field: f, Before: before, After: nv, Name: name}); err != nil {
|
if err := tx.Exec(commands.SetField(a.s, n, td, fd, nv, name)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -372,16 +372,12 @@ func InstantiatePlace(ctx *context.Editor, t Template, parent ids.NodeID, index
|
|||||||
if err := place(s, scratch, h, parent, pl); err != nil {
|
if err := place(s, scratch, h, parent, pl); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
cmd := &commands.Create{
|
cmd := commands.NewMutation("Create "+t.Name, commands.EnvFor(s),
|
||||||
Parent: parent,
|
commands.Insert(parent, index, string(sceneio.SaveSubtree(scratch, h, true))))
|
||||||
Index: index,
|
|
||||||
Fragment: sceneio.SaveSubtree(scratch, h, true),
|
|
||||||
Name: t.Name,
|
|
||||||
}
|
|
||||||
if err := d.History.Exec(cmd); err != nil {
|
if err := d.History.Exec(cmd); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
created := append([]ids.NodeID(nil), cmd.Roots()...)
|
created := cmd.Created()
|
||||||
ctx.Select(created...)
|
ctx.Select(created...)
|
||||||
return created, nil
|
return created, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -681,33 +681,29 @@ func (p *Panel) move(d *document.SceneDocument, nodes []ids.NodeID, target ids.N
|
|||||||
if n == th {
|
if n == th {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
cmd := &commands.Reparent{Node: s.ID(n), KeepWorld: true}
|
parent, index := target, -1
|
||||||
switch zone {
|
switch zone {
|
||||||
case zoneInto:
|
|
||||||
cmd.NewParent = target
|
|
||||||
cmd.NewIndex = -1
|
|
||||||
case zoneBefore:
|
case zoneBefore:
|
||||||
parent := s.Parent(th)
|
ph := s.Parent(th)
|
||||||
idx := commands.ChildIndex(s, th)
|
idx := commands.ChildIndex(s, th)
|
||||||
if s.Parent(n) == parent && commands.ChildIndex(s, n) < idx {
|
if s.Parent(n) == ph && commands.ChildIndex(s, n) < idx {
|
||||||
idx--
|
idx--
|
||||||
}
|
}
|
||||||
cmd.NewParent = s.ID(parent)
|
parent, index = s.ID(ph), idx
|
||||||
cmd.NewIndex = idx
|
|
||||||
case zoneAfter:
|
case zoneAfter:
|
||||||
parent := s.Parent(anchor)
|
ph := s.Parent(anchor)
|
||||||
idx := commands.ChildIndex(s, anchor) + 1
|
idx := commands.ChildIndex(s, anchor) + 1
|
||||||
if s.Parent(n) == parent && commands.ChildIndex(s, n) < idx {
|
if s.Parent(n) == ph && commands.ChildIndex(s, n) < idx {
|
||||||
idx--
|
idx--
|
||||||
}
|
}
|
||||||
cmd.NewParent = s.ID(parent)
|
parent, index = s.ID(ph), idx
|
||||||
cmd.NewIndex = idx
|
|
||||||
}
|
}
|
||||||
if p.d.Prefabs != nil && cmd.NewParent != s.ID(s.Parent(n)) && p.d.Prefabs.Locked(d, s.ID(n)) {
|
if p.d.Prefabs != nil && parent != s.ID(s.Parent(n)) && p.d.Prefabs.Locked(d, s.ID(n)) {
|
||||||
tx.Abort()
|
tx.Abort()
|
||||||
p.d.Notices.Notify(context.LevelWarn, s.Name(n)+" comes from a prefab and keeps its parent, unpack the instance to move it")
|
p.d.Notices.Notify(context.LevelWarn, s.Name(n)+" comes from a prefab and keeps its parent, unpack the instance to move it")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
cmd := commands.NewMutation("Reparent", commands.EnvFor(s), commands.Move(s.ID(n), parent, index, true))
|
||||||
if err := tx.Exec(cmd); err != nil {
|
if err := tx.Exec(cmd); err != nil {
|
||||||
tx.Abort()
|
tx.Abort()
|
||||||
p.d.Notices.Notify(context.LevelError, err.Error())
|
p.d.Notices.Notify(context.LevelError, err.Error())
|
||||||
|
|||||||
@@ -647,9 +647,10 @@ func (p *Panel) component(d *document.SceneDocument, t schema.TypeID) {
|
|||||||
|
|
||||||
func (p *Panel) remove(d *document.SceneDocument, td *schema.TypeDescriptor) {
|
func (p *Panel) remove(d *document.SceneDocument, td *schema.TypeDescriptor) {
|
||||||
p.confirm(d, "Remove "+p.reg.Meta(td).DisplayName, func() error {
|
p.confirm(d, "Remove "+p.reg.Meta(td).DisplayName, func() error {
|
||||||
|
env := commands.EnvFor(d.Scene())
|
||||||
tx := d.History.Begin("Remove " + td.FullName)
|
tx := d.History.Begin("Remove " + td.FullName)
|
||||||
for _, id := range p.nodes {
|
for _, id := range p.nodes {
|
||||||
if err := tx.Exec(&commands.RemoveComponent{Node: id, Type: td.ID, Name: td.FullName}); err != nil {
|
if err := tx.Exec(commands.NewMutation("Remove "+td.FullName, env, commands.RemoveComp(id, td))); err != nil {
|
||||||
tx.Abort()
|
tx.Abort()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -661,13 +662,16 @@ func (p *Panel) remove(d *document.SceneDocument, td *schema.TypeDescriptor) {
|
|||||||
|
|
||||||
func (p *Panel) reset(d *document.SceneDocument, td *schema.TypeDescriptor) {
|
func (p *Panel) reset(d *document.SceneDocument, td *schema.TypeDescriptor) {
|
||||||
p.confirm(d, "Reset "+p.reg.Meta(td).DisplayName, func() error {
|
p.confirm(d, "Reset "+p.reg.Meta(td).DisplayName, func() error {
|
||||||
|
s := d.Scene()
|
||||||
|
env := commands.EnvFor(s)
|
||||||
|
defaults := p.reg.Defaults(td.ID)
|
||||||
tx := d.History.Begin("Reset " + td.FullName)
|
tx := d.History.Begin("Reset " + td.FullName)
|
||||||
for _, id := range p.nodes {
|
for _, id := range p.nodes {
|
||||||
if err := tx.Exec(&commands.RemoveComponent{Node: id, Type: td.ID, Name: td.FullName}); err != nil {
|
if err := tx.Exec(commands.NewMutation("Remove "+td.FullName, env, commands.RemoveComp(id, td))); err != nil {
|
||||||
tx.Abort()
|
tx.Abort()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := tx.Exec(&commands.AddComponent{Node: id, Type: td.ID, Name: td.FullName, Values: p.reg.Defaults(td.ID)}); err != nil {
|
if err := tx.Exec(commands.NewMutation("Add "+td.FullName, env, commands.AddComp(s, id, td, defaults))); err != nil {
|
||||||
tx.Abort()
|
tx.Abort()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -796,12 +800,14 @@ func (p *Panel) addComponent(d *document.SceneDocument) {
|
|||||||
func (p *Panel) add(d *document.SceneDocument, td *schema.TypeDescriptor) {
|
func (p *Panel) add(d *document.SceneDocument, td *schema.TypeDescriptor) {
|
||||||
p.confirm(d, "Add "+p.reg.Meta(td).DisplayName, func() error {
|
p.confirm(d, "Add "+p.reg.Meta(td).DisplayName, func() error {
|
||||||
s := d.Scene()
|
s := d.Scene()
|
||||||
|
env := commands.WithOnAdd(commands.EnvFor(s), p.d.Clip.OnAdd)
|
||||||
|
defaults := p.reg.Defaults(td.ID)
|
||||||
tx := d.History.Begin("Add " + td.FullName)
|
tx := d.History.Begin("Add " + td.FullName)
|
||||||
for _, n := range p.nodes {
|
for _, n := range p.nodes {
|
||||||
if _, ok := s.GetByType(s.Handle(n), td.ID); ok {
|
if _, ok := s.GetByType(s.Handle(n), td.ID); ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if err := tx.Exec(&commands.AddComponent{Node: n, Type: td.ID, Name: td.FullName, Values: p.reg.Defaults(td.ID), OnAdd: p.d.Clip.OnAdd(td)}); err != nil {
|
if err := tx.Exec(commands.NewMutation("Add "+td.FullName, env, commands.AddComp(s, n, td, defaults))); err != nil {
|
||||||
tx.Abort()
|
tx.Abort()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,87 @@
|
|||||||
|
package mutate
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
|
||||||
|
"aego/asset"
|
||||||
|
"aego/core/ids"
|
||||||
|
"aego/scene"
|
||||||
|
"aego/scene/sceneio"
|
||||||
|
"aego/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
const RootName = "Root"
|
||||||
|
|
||||||
|
type Env struct {
|
||||||
|
Types *scene.Types
|
||||||
|
Resolver asset.Resolver
|
||||||
|
Library *sceneio.Library
|
||||||
|
Assets func(ids.AssetID) bool
|
||||||
|
Lookup func(path string) (ids.AssetID, bool)
|
||||||
|
OnAdd func(td *schema.TypeDescriptor, s *scene.Scene, h scene.NodeHandle)
|
||||||
|
OnRemove func(td *schema.TypeDescriptor, s *scene.Scene, h scene.NodeHandle)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Problem struct {
|
||||||
|
Error bool `json:"error"`
|
||||||
|
Node string `json:"node,omitempty"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Document struct {
|
||||||
|
Name string
|
||||||
|
Prefab bool
|
||||||
|
Scene *scene.Scene
|
||||||
|
Problems []Problem
|
||||||
|
env Env
|
||||||
|
reg *schema.Registry
|
||||||
|
}
|
||||||
|
|
||||||
|
func isPrefab(src []byte) bool {
|
||||||
|
return bytes.HasPrefix(bytes.TrimSpace(src), []byte("prefab"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func Load(src []byte, name string, env Env) (*Document, error) {
|
||||||
|
s, rep, err := sceneio.Load(src, name, env.Types, env.Resolver, sceneio.LoadOptions{KeepIDs: true, Prefabs: env.Library})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
d := &Document{Name: name, Prefab: isPrefab(src), Scene: s, env: env, reg: s.Registry()}
|
||||||
|
for _, w := range rep.Warnings {
|
||||||
|
d.Problems = append(d.Problems, Problem{Node: w.Path, Message: w.Msg})
|
||||||
|
}
|
||||||
|
for _, u := range rep.Unknown {
|
||||||
|
d.Problems = append(d.Problems, Problem{Message: "component " + u + " is not registered; it is kept unchanged"})
|
||||||
|
}
|
||||||
|
return d, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func Wrap(s *scene.Scene, name string, prefab bool, env Env) *Document {
|
||||||
|
return &Document{Name: name, Prefab: prefab, Scene: s, env: env, reg: s.Registry()}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Document) Bytes() []byte {
|
||||||
|
if d.Prefab {
|
||||||
|
return sceneio.SavePrefab(d.Scene)
|
||||||
|
}
|
||||||
|
return sceneio.Save(d.Scene)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Document) library() *sceneio.Library {
|
||||||
|
if d.env.Library == nil {
|
||||||
|
d.env.Library = sceneio.NewLibrary(d.reg, d.Scene.Resolver())
|
||||||
|
}
|
||||||
|
return d.env.Library
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Document) assetID(text string) (ids.AssetID, error) {
|
||||||
|
if id, err := ids.ParseAssetID(text); err == nil {
|
||||||
|
return id, nil
|
||||||
|
}
|
||||||
|
if d.env.Lookup != nil {
|
||||||
|
if id, ok := d.env.Lookup(text); ok {
|
||||||
|
return id, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ids.AssetID{}, errNoAsset(text)
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,94 @@
|
|||||||
|
package prefab
|
||||||
|
|
||||||
|
type Level uint8
|
||||||
|
|
||||||
|
const (
|
||||||
|
LevelProperty Level = iota
|
||||||
|
LevelComponent
|
||||||
|
LevelNode
|
||||||
|
LevelAll
|
||||||
|
LevelOrphan
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
OwnerAdded = "#node"
|
||||||
|
OwnerRemove = "#remove"
|
||||||
|
OwnerOrder = "#order"
|
||||||
|
)
|
||||||
|
|
||||||
|
var levelNames = [...]string{"property", "component", "node", "all", "orphan"}
|
||||||
|
|
||||||
|
func (l Level) String() string {
|
||||||
|
if int(l) < len(levelNames) {
|
||||||
|
return levelNames[l]
|
||||||
|
}
|
||||||
|
return "all"
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParseLevel(s string) (Level, bool) {
|
||||||
|
if s == "" {
|
||||||
|
return LevelAll, true
|
||||||
|
}
|
||||||
|
for i, n := range levelNames {
|
||||||
|
if n == s {
|
||||||
|
return Level(i), true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return LevelAll, false
|
||||||
|
}
|
||||||
|
|
||||||
|
type Pick struct {
|
||||||
|
Level Level
|
||||||
|
Key Key
|
||||||
|
Prop PropKey
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p Pick) wants(orphan bool, k Key, owner, field string, rootKey Key) bool {
|
||||||
|
if p.Level == LevelOrphan {
|
||||||
|
if !orphan || k != p.Key {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return p.Prop.Owner == "" || (owner == p.Prop.Owner && (p.Prop.Field == "" || field == p.Prop.Field))
|
||||||
|
}
|
||||||
|
if orphan || (k == rootKey && owner == OwnerTransform) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
switch p.Level {
|
||||||
|
case LevelProperty:
|
||||||
|
return k == p.Key && owner == p.Prop.Owner && field == p.Prop.Field
|
||||||
|
case LevelComponent:
|
||||||
|
return k == p.Key && owner == p.Prop.Owner
|
||||||
|
case LevelNode:
|
||||||
|
return k == p.Key
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p Pick) Split(o Overrides, rootKey Key) (sel, rest Overrides) {
|
||||||
|
put := func(take bool, fn func(*Overrides)) {
|
||||||
|
if take {
|
||||||
|
fn(&sel)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fn(&rest)
|
||||||
|
}
|
||||||
|
for _, x := range o.Props {
|
||||||
|
put(p.wants(x.Orphan, x.Node, x.Prop.Owner, x.Prop.Field, rootKey), func(t *Overrides) { t.Props = append(t.Props, x) })
|
||||||
|
}
|
||||||
|
for _, x := range o.AddComps {
|
||||||
|
put(p.wants(x.Orphan, x.Node, x.Comp.Owner, "", rootKey), func(t *Overrides) { t.AddComps = append(t.AddComps, x) })
|
||||||
|
}
|
||||||
|
for _, x := range o.RemoveComps {
|
||||||
|
put(p.wants(false, x.Node, x.Owner, "", rootKey), func(t *Overrides) { t.RemoveComps = append(t.RemoveComps, x) })
|
||||||
|
}
|
||||||
|
for _, x := range o.AddNodes {
|
||||||
|
put(p.wants(x.Orphan, LocalKey(x.Node.Local), OwnerAdded, "", rootKey), func(t *Overrides) { t.AddNodes = append(t.AddNodes, x) })
|
||||||
|
}
|
||||||
|
for _, k := range o.Remove {
|
||||||
|
put(p.wants(false, k, OwnerRemove, "", rootKey), func(t *Overrides) { t.Remove = append(t.Remove, k) })
|
||||||
|
}
|
||||||
|
for _, x := range o.Order {
|
||||||
|
put(p.wants(false, x.Parent, OwnerOrder, "", rootKey), func(t *Overrides) { t.Order = append(t.Order, x) })
|
||||||
|
}
|
||||||
|
return sel, rest
|
||||||
|
}
|
||||||
@@ -50,7 +50,7 @@ func TestEditorPlayDiff(t *testing.T) {
|
|||||||
}
|
}
|
||||||
s.Flush()
|
s.Flush()
|
||||||
d := m.New(rel, s)
|
d := m.New(rel, s)
|
||||||
if err := d.History.Exec(&commands.AddComponent{Node: id, Type: td.ID, Name: td.FullName}); err != nil {
|
if err := d.History.Exec(commands.NewMutation("Add "+td.FullName, commands.EnvFor(s), commands.AddComp(s, id, td, nil))); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
docs[i] = d
|
docs[i] = d
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ func spriteNodes(t *testing.T, n int) (*testEditor, []ids.NodeID, *schema.TypeDe
|
|||||||
h := sc.Create(sc.Root(), "N")
|
h := sc.Create(sc.Root(), "N")
|
||||||
sc.Flush()
|
sc.Flush()
|
||||||
id := sc.ID(h)
|
id := sc.ID(h)
|
||||||
if err := d.History.Exec(&commands.AddComponent{Node: id, Type: td.ID, Name: td.FullName}); err != nil {
|
if err := d.History.Exec(commands.NewMutation("Add "+td.FullName, commands.EnvFor(sc), commands.AddComp(sc, id, td, nil))); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
nodes = append(nodes, id)
|
nodes = append(nodes, id)
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ func keyHold(s interface{ Input() *input.State }, k input.Scancode, down bool) {
|
|||||||
|
|
||||||
func drive(e interface{ Input() *input.State }, pc *play.Controller, from, to int, at func(frame int)) {
|
func drive(e interface{ Input() *input.State }, pc *play.Controller, from, to int, at func(frame int)) {
|
||||||
for i := from; i < to; i++ {
|
for i := from; i < to; i++ {
|
||||||
|
e.Input().BeginFrame()
|
||||||
keyHold(e, input.KeyD, i%400 >= 20 && i%400 < 200)
|
keyHold(e, input.KeyD, i%400 >= 20 && i%400 < 200)
|
||||||
keyHold(e, input.KeyA, i%400 >= 220 && i%400 < 380)
|
keyHold(e, input.KeyA, i%400 >= 220 && i%400 < 380)
|
||||||
keyHold(e, input.KeySpace, i%90 >= 60 && i%90 < 64)
|
keyHold(e, input.KeySpace, i%90 >= 60 && i%90 < 64)
|
||||||
@@ -194,6 +195,7 @@ func TestKeyframeReplayWritesNoSaves(t *testing.T) {
|
|||||||
s, pc := rewindSession(t)
|
s, pc := rewindSession(t)
|
||||||
e := s.Host.Engine
|
e := s.Host.Engine
|
||||||
drive(e, pc, 0, 99, nil)
|
drive(e, pc, 0, 99, nil)
|
||||||
|
e.Input().BeginFrame()
|
||||||
keyHold(e, input.KeyF5, true)
|
keyHold(e, input.KeyF5, true)
|
||||||
pc.Tick(1.0 / 60)
|
pc.Tick(1.0 / 60)
|
||||||
keyHold(e, input.KeyF5, false)
|
keyHold(e, input.KeyF5, false)
|
||||||
|
|||||||
@@ -141,3 +141,41 @@ func TestPrefabEditorFlow(t *testing.T) {
|
|||||||
t.Fatal("instances without an override follow the prefab")
|
t.Fatal("instances without an override follow the prefab")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCreatePrefabUndo(t *testing.T) {
|
||||||
|
_, ctx := openEditor(t)
|
||||||
|
if err := ctx.NewScene("scenes/undo.aescene"); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
d := ctx.Doc()
|
||||||
|
sc := d.Scene()
|
||||||
|
crate := sc.Create(sc.Root(), "Crate")
|
||||||
|
sc.Create(crate, "Lid")
|
||||||
|
sc.Flush()
|
||||||
|
id := sc.ID(crate)
|
||||||
|
before := sceneio.SaveSubtree(sc, crate, true)
|
||||||
|
if err := prefabs.New(ctx).CreateFrom(d, []ids.NodeID{id}, ""); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if pi, ok := sceneio.InstanceOf(sc, sc.Handle(id)); !ok || !pi.Owner {
|
||||||
|
t.Fatal("node must become a prefab instance")
|
||||||
|
}
|
||||||
|
if got := d.History.Steps(nil); len(got) == 0 || got[len(got)-1] != "Create Prefab" {
|
||||||
|
t.Fatalf("history %v", got)
|
||||||
|
}
|
||||||
|
if err := d.History.Undo(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if _, ok := sceneio.InstanceOf(sc, sc.Handle(id)); ok {
|
||||||
|
t.Fatal("undo must turn the instance back into plain nodes")
|
||||||
|
}
|
||||||
|
if got := sceneio.SaveSubtree(sc, sc.Handle(id), true); string(got) != string(before) {
|
||||||
|
t.Fatalf("undo changed the subtree:\n%s", got)
|
||||||
|
}
|
||||||
|
if err := d.History.Redo(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if pi, ok := sceneio.InstanceOf(sc, sc.Handle(id)); !ok || !pi.Owner {
|
||||||
|
t.Fatal("redo must link the instance again")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -164,7 +164,7 @@ func TestFakeComponentHooks(t *testing.T) {
|
|||||||
ctx := f.s.App.Context()
|
ctx := f.s.App.Context()
|
||||||
d := f.doc
|
d := f.doc
|
||||||
crate := f.node("Crate")
|
crate := f.node("Crate")
|
||||||
add := &commands.AddComponent{Node: crate, Type: f.body.ID, Name: f.body.FullName, OnAdd: ctx.OnAdd(f.body)}
|
add := commands.NewMutation("Add "+f.body.FullName, commands.WithOnAdd(commands.EnvFor(d.Scene()), ctx.OnAdd), commands.AddComp(d.Scene(), crate, f.body, nil))
|
||||||
if err := d.History.Exec(add); err != nil {
|
if err := d.History.Exec(add); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -184,7 +184,7 @@ func TestFakeComponentHooks(t *testing.T) {
|
|||||||
if f.m.Changed != 3 {
|
if f.m.Changed != 3 {
|
||||||
t.Fatalf("OnChanged after set and undo ran %d times, want 3", f.m.Changed)
|
t.Fatalf("OnChanged after set and undo ran %d times, want 3", f.m.Changed)
|
||||||
}
|
}
|
||||||
if err := d.History.Exec(&commands.RemoveComponent{Node: crate, Type: f.body.ID, Name: f.body.FullName}); err != nil {
|
if err := d.History.Exec(commands.NewMutation("Remove "+f.body.FullName, commands.EnvFor(d.Scene()), commands.RemoveComp(crate, f.body))); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if f.m.Removed != 1 || f.m.LastRemoved.Size != 2 {
|
if f.m.Removed != 1 || f.m.LastRemoved.Size != 2 {
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,87 @@
|
|||||||
|
//go:build aego_editor
|
||||||
|
|
||||||
|
package mutate_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"aego/editor/core/history/commands"
|
||||||
|
"aego/scene"
|
||||||
|
"aego/scene/scriptcomp"
|
||||||
|
"aego/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func defaults(td *schema.TypeDescriptor) []commands.FieldValue {
|
||||||
|
var p unsafe.Pointer
|
||||||
|
switch {
|
||||||
|
case td.Default != nil:
|
||||||
|
p = td.Default()
|
||||||
|
case td.New != nil:
|
||||||
|
p = td.New()
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := make([]commands.FieldValue, 0, len(td.Fields))
|
||||||
|
for i := range td.Fields {
|
||||||
|
var v schema.Value
|
||||||
|
td.Fields[i].Get(p, &v)
|
||||||
|
out = append(out, commands.FieldValue{Field: td.Fields[i].ID, Value: v})
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
func freshNode(s *scene.Scene, td *schema.TypeDescriptor) scene.NodeHandle {
|
||||||
|
var h scene.NodeHandle
|
||||||
|
if td.Space.Allows(scene.Space2D.Kind()) {
|
||||||
|
h = s.Create2D(s.Root(), "N")
|
||||||
|
} else {
|
||||||
|
h = s.Create3D(s.Root(), "N")
|
||||||
|
}
|
||||||
|
s.Flush()
|
||||||
|
return h
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEveryComponentPassesTheEditorPaths(t *testing.T) {
|
||||||
|
e := env(t)
|
||||||
|
reg := e.Types.Schema()
|
||||||
|
types, fields := 0, 0
|
||||||
|
for _, td := range reg.Components() {
|
||||||
|
if td.Hidden || td.FullName == "engine.Unknown" || td.ID == scriptcomp.ScriptTypeID {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
types++
|
||||||
|
list := defaults(td)
|
||||||
|
s := scene.New(e.Types, nil, scene.Options{})
|
||||||
|
h := freshNode(s, td)
|
||||||
|
id := s.ID(h)
|
||||||
|
if err := commands.NewMutation("Add", commands.EnvFor(s), commands.AddComp(s, id, td, list)).Do(target{s}); err != nil {
|
||||||
|
t.Errorf("%s: add-comp: %v", td.FullName, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
scratch := scene.New(e.Types, nil, scene.Options{})
|
||||||
|
sh := freshNode(scratch, td)
|
||||||
|
if err := commands.NewMutation("", commands.EnvFor(scratch), commands.AddRaw(scratch, scratch.ID(sh), td, list)).Do(target{scratch}); err != nil {
|
||||||
|
t.Errorf("%s: raw add-comp: %v", td.FullName, err)
|
||||||
|
}
|
||||||
|
for i := range td.Fields {
|
||||||
|
fd := &td.Fields[i]
|
||||||
|
if !fd.Flags.Has(schema.FlagSerialize) || !fd.Flags.Has(schema.FlagEditor) || fd.Flags.Has(schema.FlagReadOnly) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
fields++
|
||||||
|
cur, err := s.GetProperty(h, td.ID, fd.ID)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("%s.%s: %v", td.FullName, fd.Name, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if err := commands.SetField(s, id, td, fd, cur, fd.Name).Do(target{s}); err != nil {
|
||||||
|
t.Errorf("%s.%s: set: %v", td.FullName, fd.Name, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if types < 10 || fields < 50 {
|
||||||
|
t.Fatalf("only %d components and %d fields were checked", types, fields)
|
||||||
|
}
|
||||||
|
t.Logf("%d components, %d fields", types, fields)
|
||||||
|
}
|
||||||
@@ -109,6 +109,7 @@ var rules = []rule{
|
|||||||
{"app", []string{"..."}, nil},
|
{"app", []string{"..."}, nil},
|
||||||
{"app/docstool", []string{"..."}, nil},
|
{"app/docstool", []string{"..."}, nil},
|
||||||
{"app/docsview", []string{"..."}, nil},
|
{"app/docsview", []string{"..."}, nil},
|
||||||
|
{"scene/mutate", []string{"core/...", "schema", "asset", "format/...", "scene", "scene/sceneio", "scene/prefab", "scene/scriptcomp", "data"}, nil},
|
||||||
{"app/edit", []string{"..."}, nil},
|
{"app/edit", []string{"..."}, nil},
|
||||||
{"app/projects", []string{"..."}, nil},
|
{"app/projects", []string{"..."}, nil},
|
||||||
{"app/supervise", []string{"..."}, nil},
|
{"app/supervise", []string{"..."}, nil},
|
||||||
@@ -241,6 +242,7 @@ var denied = []struct {
|
|||||||
{"engine/base", []string{"modules/render3d", "modules/render3d/...", "asset/pipeline", "asset/importers/...", "editor/..."}},
|
{"engine/base", []string{"modules/render3d", "modules/render3d/...", "asset/pipeline", "asset/importers/...", "editor/..."}},
|
||||||
{"app/playground", []string{"platform/sdl", "gpu/gl33", "gpu/gl33/...", "asset/pipeline", "asset/importers/...", "modules/render3d", "modules/render3d/...", "editor/..."}},
|
{"app/playground", []string{"platform/sdl", "gpu/gl33", "gpu/gl33/...", "asset/pipeline", "asset/importers/...", "modules/render3d", "modules/render3d/...", "editor/..."}},
|
||||||
{"app/docsview", []string{"platform/sdl", "gpu/gl33", "gpu/gl33/...", "editor/shell", "editor/shell/...", "asset/importers/...", "script/compiler", "script/workspace"}},
|
{"app/docsview", []string{"platform/sdl", "gpu/gl33", "gpu/gl33/...", "editor/shell", "editor/shell/...", "asset/importers/...", "script/compiler", "script/workspace"}},
|
||||||
|
{"scene/mutate", []string{"editor/...", "ui/...", "platform/...", "engine", "engine/...", "app/..."}},
|
||||||
{"runtime/...", []string{"editor/..."}},
|
{"runtime/...", []string{"editor/..."}},
|
||||||
{"runtime/...", []string{"asset/pipeline", "asset/importers/...", "project", "app/run", "app/edit", "app/export", "app/export/..."}},
|
{"runtime/...", []string{"asset/pipeline", "asset/importers/...", "project", "app/run", "app/edit", "app/export", "app/export/..."}},
|
||||||
{"sdk", []string{"editor/..."}},
|
{"sdk", []string{"editor/..."}},
|
||||||
|
|||||||
Reference in New Issue
Block a user