Files
aego/scene/propclaim/propclaim.go
T
sanspie 515f4ca1b3 Stage 11a: animation (D333–D340, D344, D354–D357)
Clips (.aeanim) and controllers (.aectrl) with importers, AnimationPlayer and Animator with crossfades, root motion and events on fixed steps, rewind support. Editor: Animation panel (dope sheet, curves, record, preview, trajectory), Animator panel, sprite sheet slicer and flipbooks, Programming workspace, export panel redesign. Motion 2D ledge climb. 11c: the component and Create palette.
2026-10-25 15:31:22 +03:00

207 lines
3.5 KiB
Go

package propclaim
import (
"aego/scene"
"aego/scene/propref"
)
const ServiceID = "scene.claims"
type Owner uint8
const NoOwner Owner = 0
type Services interface {
ServiceAny(id string) (any, bool)
SetView(id string, v any)
}
type Key struct {
node scene.NodeHandle
prop uint64
}
func KeyOf(node scene.NodeHandle, r *propref.Ref) Key {
return Key{node: node, prop: r.Hash()}
}
type entry struct {
owner Owner
ref propref.Ref
mark uint32
}
// Slot remembers where a claim lives; it is valid while the table revision does not change.
type Slot struct {
rev uint64
ent *entry
}
func (s *Slot) set(rev uint64, e *entry) {
if s != nil {
s.rev, s.ent = rev, e
}
}
type owner struct {
name string
mark uint32
held int
seen int
}
type Table struct {
owners []owner
m map[Key][]entry
rev uint64
total int
}
func New() *Table {
return &Table{owners: []owner{{}}, m: map[Key][]entry{}}
}
func Of(w Services) *Table {
v, ok := w.ServiceAny(ServiceID)
if !ok {
return nil
}
t, _ := v.(*Table)
return t
}
// Ensure sets the table as a view: claims are rebuilt by their owners, rewind keys skip it.
func Ensure(w Services) *Table {
if t := Of(w); t != nil {
return t
}
t := New()
w.SetView(ServiceID, t)
return t
}
func (t *Table) Register(name string) Owner {
for i := 1; i < len(t.owners); i++ {
if t.owners[i].name == name {
return Owner(i)
}
}
if len(t.owners) > 255 {
return NoOwner
}
t.owners = append(t.owners, owner{name: name})
return Owner(len(t.owners) - 1)
}
func (t *Table) Name(o Owner) string {
if t == nil || int(o) >= len(t.owners) {
return ""
}
return t.owners[o].name
}
func (t *Table) Revision() uint64 {
if t == nil {
return 0
}
return t.rev
}
func (t *Table) Begin(o Owner) {
if t == nil || o == NoOwner {
return
}
ow := &t.owners[o]
ow.mark++
ow.seen = 0
}
func (t *Table) Claim(o Owner, node scene.NodeHandle, r *propref.Ref) {
t.ClaimAt(o, KeyOf(node, r), r, nil)
}
func (t *Table) ClaimAt(o Owner, k Key, r *propref.Ref, s *Slot) {
if t == nil || o == NoOwner {
return
}
ow := &t.owners[o]
if s != nil && s.ent != nil && s.rev == t.rev {
if e := s.ent; e.mark != ow.mark {
e.mark = ow.mark
ow.seen++
}
return
}
es := t.m[k]
for i := range es {
if e := &es[i]; e.owner == o && e.ref.Same(r) {
if e.mark != ow.mark {
e.mark = ow.mark
ow.seen++
}
s.set(t.rev, e)
return
}
}
es = append(es, entry{owner: o, ref: *r, mark: ow.mark})
t.m[k] = es
ow.held++
ow.seen++
t.total++
t.rev++
s.set(t.rev, &es[len(es)-1])
}
func (t *Table) End(o Owner) {
if t == nil || o == NoOwner {
return
}
ow := &t.owners[o]
if ow.seen == ow.held {
return
}
for k, es := range t.m {
out := es[:0]
for _, e := range es {
if e.owner == o && e.mark != ow.mark {
ow.held--
t.total--
continue
}
out = append(out, e)
}
if len(out) == 0 {
delete(t.m, k)
continue
}
clear(es[len(out):])
t.m[k] = out
}
t.rev++
}
func (t *Table) Drop(o Owner) {
t.Begin(o)
t.End(o)
}
func (t *Table) Held(node scene.NodeHandle, r *propref.Ref, except Owner) (Owner, bool) {
return t.HeldKey(KeyOf(node, r), r, except)
}
func (t *Table) HeldKey(k Key, r *propref.Ref, except Owner) (Owner, bool) {
if t == nil || t.total == 0 {
return NoOwner, false
}
if except != NoOwner && int(except) < len(t.owners) && t.owners[except].held == t.total {
return NoOwner, false
}
es := t.m[k]
for i := range es {
if e := &es[i]; e.owner != except && e.ref.Overlaps(r) {
return e.owner, true
}
}
return NoOwner, false
}