Files
aego/scene/sceneio/scripts.go
T

190 lines
5.1 KiB
Go

package sceneio
import (
"unsafe"
"aego/core/errs"
"aego/core/ids"
"aego/core/mathx"
"aego/format/aetext"
"aego/scene"
"aego/scene/scriptcomp"
"aego/schema"
)
func (l *loader) loadScripts(h scene.NodeHandle, n *aetext.Node) error {
sc := scene.Add[scriptcomp.ScriptComponent](l.scene, h)
if sc == nil {
return nil
}
for _, b := range n.Blocks {
if b.Head != "script" {
l.report.warn(l.name, b.Pos, "unknown block "+b.Head+" in "+scriptcomp.ScriptName)
continue
}
var refs []deferredRef
att := scriptcomp.Attachment{TypeName: b.Label, Enabled: true}
if v, ok := b.Attr("enabled"); ok {
att.Enabled = v.Bool
}
td, known := l.reg.ByName(b.Label)
if known && td.Kind == schema.TypeScript {
att.TypeName = td.FullName
for _, f := range b.Fields {
fd, ok := td.Field(f.Name)
if !ok {
att.Unknown = append(att.Unknown, f)
l.report.warn(l.name, f.Pos, "unknown property "+td.FullName+"."+f.Name+" kept as is")
continue
}
v, err := scriptValue(fd, f.Value)
if err != nil {
if l.opt.Strict {
return err
}
att.Unknown = append(att.Unknown, f)
l.report.warn(l.name, f.Pos, err.Error())
continue
}
if hasNodes(v) {
refs = append(refs, deferredRef{node: h, value: v, fname: fd.Name})
}
att.Props.Set(fd.Name, v)
}
} else {
att.Unknown = append(att.Unknown, b.Fields...)
l.report.Unknown = append(l.report.Unknown, "script "+b.Label)
}
if sc.Index(att.TypeName) >= 0 {
l.report.warn(l.name, b.Pos, "script "+att.TypeName+" is attached twice, the second copy is dropped")
continue
}
sc.Attachments = append(sc.Attachments, att)
for _, r := range refs {
r.script, r.name = att.TypeName, att.TypeName
l.deferred = append(l.deferred, r)
}
}
return nil
}
func scriptValue(fd *schema.FieldDescriptor, v aetext.Value) (schema.Value, error) {
bad := errs.New(errs.SceneIOParse, "value does not fit script property "+fd.Name)
numeric := v.Kind == aetext.VInt || v.Kind == aetext.VFloat
switch fd.Kind {
case schema.KindBool:
if v.Kind == aetext.VBool {
return schema.Bool(v.Bool), nil
}
case schema.KindInt32:
if numeric {
return schema.Int32(int32(v.AsInt())), nil
}
case schema.KindInt64:
if numeric {
return schema.Int64(v.AsInt()), nil
}
case schema.KindFloat32:
if numeric {
return schema.Float32(float32(v.AsFloat())), nil
}
case schema.KindFloat64:
if numeric {
return schema.Float64(v.AsFloat()), nil
}
case schema.KindString:
if v.Kind == aetext.VString {
return schema.String(v.Str), nil
}
case schema.KindVec2:
if v.Kind == aetext.VList && len(v.List) == 2 {
return schema.Vec2(readVec2(v, schema.Value{}.V)), nil
}
case schema.KindVec3:
if v.Kind == aetext.VList && len(v.List) == 3 {
return schema.Vec3(readVec3(v, schema.Value{}.V3)), nil
}
case schema.KindVec4:
if v.Kind == aetext.VList && len(v.List) == 4 {
return schema.Vec4(readVec4(v, schema.Value{}.V4)), nil
}
case schema.KindQuat:
if v.Kind == aetext.VList && len(v.List) == 4 {
q := readVec4(v, schema.Value{}.V4)
return schema.Quat(mathx.Quat(q)), nil
}
case schema.KindColor:
if v.Kind == aetext.VColor {
return schema.Color(unpackColor(v.Color)), nil
}
case schema.KindRect:
if v.Kind == aetext.VList && len(v.List) == 4 {
return schema.Rect(readRect(v)), nil
}
case schema.KindEnum:
if v.Kind == aetext.VIdent {
if n, ok := fd.EnumValueOf(v.Ident); ok {
return schema.Enum(n), nil
}
return schema.Value{}, errs.New(errs.SceneIOParse, "unknown enum value "+v.Ident+" for "+fd.Name)
}
if numeric {
return schema.Enum(v.AsInt()), nil
}
case schema.KindAssetRef:
if v.Kind == aetext.VAsset || v.Kind == aetext.VString {
if v.Str == "" {
return schema.Asset(ids.AssetID{}), nil
}
id, err := ids.ParseAssetID(v.Str)
if err != nil {
return schema.Value{}, err
}
return schema.Asset(id), nil
}
case schema.KindNodeRef:
if v.Kind == aetext.VNode || v.Kind == aetext.VString {
if v.Str == "" {
return schema.Node(ids.NodeID{}), nil
}
id, err := ids.ParseNodeID(v.Str)
if err != nil {
return schema.Value{}, err
}
return schema.Node(id), nil
}
}
return schema.Value{}, bad
}
func (w *writer) scripts(sc *scriptcomp.ScriptComponent) *aetext.Node {
n := &aetext.Node{Head: "component", Label: scriptcomp.ScriptName}
n.Attrs = append(n.Attrs, aetext.Field{Name: "version", Value: aetext.Int(1)})
for i := range sc.Attachments {
a := &sc.Attachments[i]
b := &aetext.Node{Head: "script", Label: a.TypeName}
b.Attrs = append(b.Attrs, aetext.Field{Name: "enabled", Value: aetext.Bool(a.Enabled)})
td, known := w.reg.ByName(a.TypeName)
known = known && td.Kind == schema.TypeScript
if known {
b.Label = td.FullName
for j := range td.Fields {
fd := &td.Fields[j]
var v schema.Value
fd.Get(unsafe.Pointer(&a.Props), &v)
b.Fields = append(b.Fields, aetext.Field{Name: fd.Name, Value: w.value(fd, v)})
}
}
for _, f := range a.Unknown {
if known {
if _, dup := td.Field(f.Name); dup {
continue
}
}
b.Fields = append(b.Fields, f)
}
n.Blocks = append(n.Blocks, b)
}
return n
}