Skip to content

Commit

Permalink
add the world as argument to listener function, tweak docs and examples
Browse files Browse the repository at this point in the history
  • Loading branch information
mlange-42 committed Jan 16, 2024
1 parent 1715035 commit 7f85627
Show file tree
Hide file tree
Showing 14 changed files with 130 additions and 71 deletions.
1 change: 1 addition & 0 deletions doc.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Package arche is an archetype-based Entity Component System for Go.
//
// See the sub-packages:
//
// - Core API -- [github.com/mlange-42/arche/ecs]
// - Generic queries -- [github.com/mlange-42/arche/generic]
// - Advanced filters -- [github.com/mlange-42/arche/filter]
Expand Down
4 changes: 4 additions & 0 deletions ecs/doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,8 @@
// [Resources.Get], [Resources.Add] and [Resources.Remove].
// - [Listener] provides [EntityEvent] notifications for ECS operations.
// - Useful functions: [All], [ComponentID], [ResourceID], [GetResource], [AddResource].
//
// # Sub-packages
// - [github.com/mlange-42/arche/ecs/event] provides event subscription masks.
// - [github.com/mlange-42/arche/ecs/stats] provides world statistics for monitoring purposes.
package ecs
10 changes: 5 additions & 5 deletions ecs/event.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ func (e *EntityEvent) Contains(bit event.Subscription) bool {
// See package [github.com/mlange-42/arche/listener] for Listener implementations.
type Listener interface {
// Notify the listener about a subscribed event.
Notify(evt EntityEvent)
Notify(world *World, evt EntityEvent)
// Subscriptions to event types.
Subscriptions() event.Subscription
// Components the listener subscribes to.
Expand All @@ -54,21 +54,21 @@ type Listener interface {

// testListener for [EntityEvent]s.
type testListener struct {
Callback func(e EntityEvent)
Callback func(world *World, e EntityEvent)
Subscribe event.Subscription
}

// newTestListener creates a new [CallbackListener] that subscribes to all event types.
func newTestListener(callback func(e EntityEvent)) testListener {
func newTestListener(callback func(world *World, e EntityEvent)) testListener {
return testListener{
Callback: callback,
Subscribe: event.EntityCreated | event.EntityRemoved | event.ComponentAdded | event.ComponentRemoved | event.RelationChanged | event.TargetChanged,
}
}

// Notify the listener.
func (l *testListener) Notify(e EntityEvent) {
l.Callback(e)
func (l *testListener) Notify(world *World, e EntityEvent) {
l.Callback(world, e)
}

// Subscriptions of the listener in terms of event types.
Expand Down
22 changes: 22 additions & 0 deletions ecs/event/event_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package event_test

import (
"fmt"
"testing"

"github.com/mlange-42/arche/ecs/event"
Expand All @@ -16,3 +17,24 @@ func TestSubscriptions(t *testing.T) {
assert.True(t, m1.ContainsAny(event.ComponentAdded|event.TargetChanged))
assert.False(t, m1.Contains(event.ComponentAdded|event.RelationChanged))
}

func ExampleSubscription() {
mask := event.EntityCreated | event.EntityRemoved

fmt.Printf("%08b contains\n%08b -> %t\n\n", mask, event.EntityRemoved, mask.Contains(event.EntityRemoved))
fmt.Printf("%08b contains\n%08b -> %t\n\n", mask, event.ComponentAdded, mask.Contains(event.ComponentAdded))

fmt.Printf("%08b contains any\n%08b -> %t\n\n", mask, event.EntityRemoved|event.ComponentAdded, mask.ContainsAny(event.EntityRemoved|event.ComponentAdded))
fmt.Printf("%08b contains any\n%08b -> %t\n\n", mask, event.ComponentAdded|event.ComponentRemoved, mask.ContainsAny(event.ComponentAdded|event.ComponentRemoved))
// Output: 00000011 contains
// 00000010 -> true
//
// 00000011 contains
// 00000100 -> false
//
// 00000011 contains any
// 00000110 -> true
//
// 00000011 contains any
// 00001100 -> false
}
8 changes: 4 additions & 4 deletions ecs/event_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ func ExampleEntityEvent() {
world := ecs.NewWorld()

listener := TestListener{
Callback: func(evt ecs.EntityEvent) { fmt.Println(evt) },
Callback: func(world *ecs.World, evt ecs.EntityEvent) { fmt.Println(evt) },
}
world.SetListener(&listener)

Expand All @@ -121,10 +121,10 @@ func ExampleEntityEvent() {
}

func ExampleEntityEvent_Contains() {
mask := event.EntityCreated | event.EntityRemoved
evt := ecs.EntityEvent{EventTypes: event.EntityCreated | event.EntityRemoved}

fmt.Println(mask.Contains(event.EntityRemoved))
fmt.Println(mask.Contains(event.RelationChanged))
fmt.Println(evt.Contains(event.EntityRemoved))
fmt.Println(evt.Contains(event.RelationChanged))
// Output: true
// false
}
22 changes: 11 additions & 11 deletions ecs/world.go
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ func (w *World) NewEntity(comps ...ID) Entity {
bits := subscription(true, false, len(comps) > 0, false, newRel != nil, false)
if w.listener.Subscriptions().ContainsAny(bits) &&
subscribes(bits, &arch.Mask, w.listener.Components(), nil, newRel) {
w.listener.Notify(EntityEvent{entity, arch.Mask, comps, nil, nil, newRel, Entity{}, bits})
w.listener.Notify(w, EntityEvent{entity, arch.Mask, comps, nil, nil, newRel, Entity{}, bits})
}
}
return entity
Expand Down Expand Up @@ -265,7 +265,7 @@ func (w *World) NewEntityWith(comps ...Component) Entity {
bits := subscription(true, false, len(comps) > 0, false, newRel != nil, false)
if w.listener.Subscriptions().ContainsAny(bits) &&
subscribes(bits, &arch.Mask, w.listener.Components(), nil, newRel) {
w.listener.Notify(EntityEvent{entity, arch.Mask, ids, nil, nil, newRel, Entity{}, bits})
w.listener.Notify(w, EntityEvent{entity, arch.Mask, ids, nil, nil, newRel, Entity{}, bits})
}
}
return entity
Expand Down Expand Up @@ -296,7 +296,7 @@ func (w *World) newEntityTarget(targetID ID, target Entity, comps ...ID) Entity
bits := subscription(true, false, len(comps) > 0, false, true, !target.IsZero())
if w.listener.Subscriptions().ContainsAny(bits) &&
subscribes(bits, &arch.Mask, w.listener.Components(), nil, &targetID) {
w.listener.Notify(EntityEvent{entity, arch.Mask, comps, nil, nil, &targetID, Entity{}, bits})
w.listener.Notify(w, EntityEvent{entity, arch.Mask, comps, nil, nil, &targetID, Entity{}, bits})
}
}
return entity
Expand Down Expand Up @@ -333,7 +333,7 @@ func (w *World) newEntityTargetWith(targetID ID, target Entity, comps ...Compone
bits := subscription(true, false, len(comps) > 0, false, true, !target.IsZero())
if w.listener.Subscriptions().ContainsAny(bits) &&
subscribes(bits, &arch.Mask, w.listener.Components(), nil, &targetID) {
w.listener.Notify(EntityEvent{entity, arch.Mask, ids, nil, nil, &targetID, Entity{}, bits})
w.listener.Notify(w, EntityEvent{entity, arch.Mask, ids, nil, nil, &targetID, Entity{}, bits})
}
}
return entity
Expand All @@ -357,7 +357,7 @@ func (w *World) newEntities(count int, targetID ID, hasTarget bool, target Entit
for i = 0; i < cnt; i++ {
idx := startIdx + i
entity := arch.GetEntity(idx)
w.listener.Notify(EntityEvent{entity, arch.Mask, comps, nil, nil, newRel, Entity{}, bits})
w.listener.Notify(w, EntityEvent{entity, arch.Mask, comps, nil, nil, newRel, Entity{}, bits})
}
}
}
Expand Down Expand Up @@ -402,7 +402,7 @@ func (w *World) newEntitiesWith(count int, targetID ID, hasTarget bool, target E
for i = 0; i < cnt; i++ {
idx := startIdx + i
entity := arch.GetEntity(idx)
w.listener.Notify(EntityEvent{entity, arch.Mask, ids, nil, nil, newRel, Entity{}, bits})
w.listener.Notify(w, EntityEvent{entity, arch.Mask, ids, nil, nil, newRel, Entity{}, bits})
}
}
}
Expand Down Expand Up @@ -456,7 +456,7 @@ func (w *World) RemoveEntity(entity Entity) {
if w.listener.Subscriptions().ContainsAny(bits) &&
subscribes(bits, &oldArch.Mask, w.listener.Components(), oldRel, nil) {
lock := w.lock()
w.listener.Notify(EntityEvent{entity, oldArch.Mask, nil, oldIds, oldRel, nil, oldArch.RelationTarget, bits})
w.listener.Notify(w, EntityEvent{entity, oldArch.Mask, nil, oldIds, oldRel, nil, oldArch.RelationTarget, bits})
w.unlock(lock)
}
}
Expand Down Expand Up @@ -525,7 +525,7 @@ func (w *World) removeEntities(filter Filter) int {
for j = 0; j < ln; j++ {
entity := arch.GetEntity(j)
if listen {
w.listener.Notify(EntityEvent{entity, arch.Mask, nil, oldIds, oldRel, nil, Entity{}, bits})
w.listener.Notify(w, EntityEvent{entity, arch.Mask, nil, oldIds, oldRel, nil, Entity{}, bits})
}
index := &w.entities[entity.id]
index.arch = nil
Expand Down Expand Up @@ -781,7 +781,7 @@ func (w *World) exchange(entity Entity, add []ID, rem []ID, relation ID, hasRela
if w.listener.Subscriptions().ContainsAny(bits) {
changed := oldMask.Xor(&arch.Mask)
if subscribes(bits, &changed, w.listener.Components(), oldRel, newRel) {
w.listener.Notify(EntityEvent{entity, changed, add, rem, oldRel, newRel, oldTarget, bits})
w.listener.Notify(w, EntityEvent{entity, changed, add, rem, oldRel, newRel, oldTarget, bits})
}
}
}
Expand Down Expand Up @@ -982,7 +982,7 @@ func (w *World) setRelation(entity Entity, comp ID, target Entity) {

if w.listener != nil && w.listener.Subscriptions().Contains(event.TargetChanged) &&
subscribes(event.TargetChanged, nil, w.listener.Components(), &comp, &comp) {
w.listener.Notify(EntityEvent{entity, Mask{}, nil, nil, &comp, &comp, oldTarget, event.TargetChanged})
w.listener.Notify(w, EntityEvent{entity, Mask{}, nil, nil, &comp, &comp, oldTarget, event.TargetChanged})
}
}

Expand Down Expand Up @@ -1725,7 +1725,7 @@ func (w *World) notifyQuery(batchArch *batchArchetypes) {
for e = start; e < end; e++ {
entity := arch.GetEntity(e)
event.Entity = entity
w.listener.Notify(event)
w.listener.Notify(w, event)
}
}
}
Expand Down
12 changes: 6 additions & 6 deletions ecs/world_benchmark_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,7 @@ func BenchmarkWorldNewEntityNoEvent_1000(b *testing.B) {
world.Batch().RemoveEntities(filterPos)

var temp event.Subscription
listener := newTestListener(func(e EntityEvent) { temp = e.EventTypes })
listener := newTestListener(func(world *World, e EntityEvent) { temp = e.EventTypes })
listener.Subscribe = 0

world.SetListener(&listener)
Expand Down Expand Up @@ -349,7 +349,7 @@ func BenchmarkWorldNewEntityEvent_1000(b *testing.B) {
world.Batch().RemoveEntities(filterPos)

var temp event.Subscription
listener := newTestListener(func(e EntityEvent) { temp = e.EventTypes })
listener := newTestListener(func(world *World, e EntityEvent) { temp = e.EventTypes })
world.SetListener(&listener)

for i := 0; i < b.N; i++ {
Expand Down Expand Up @@ -428,7 +428,7 @@ func BenchmarkWorldExchangeNoEvent_1000(b *testing.B) {
world.Batch().Exchange(filterVel, pos, vel)

var temp event.Subscription
listener := newTestListener(func(e EntityEvent) { temp = e.EventTypes })
listener := newTestListener(func(world *World, e EntityEvent) { temp = e.EventTypes })
listener.Subscribe = 0
world.SetListener(&listener)

Expand Down Expand Up @@ -474,7 +474,7 @@ func BenchmarkWorldExchangeEvent_1000(b *testing.B) {
world.Batch().Exchange(filterVel, pos, vel)

var temp event.Subscription
listener := newTestListener(func(e EntityEvent) { temp = e.EventTypes })
listener := newTestListener(func(world *World, e EntityEvent) { temp = e.EventTypes })
world.SetListener(&listener)

b.StartTimer()
Expand Down Expand Up @@ -547,7 +547,7 @@ func BenchmarkWorldExchangeBatchNoEvent_1000(b *testing.B) {
world.Batch().Exchange(filterVel, pos, vel)

var temp event.Subscription
listener := newTestListener(func(e EntityEvent) { temp = e.EventTypes })
listener := newTestListener(func(world *World, e EntityEvent) { temp = e.EventTypes })
listener.Subscribe = 0
world.SetListener(&listener)

Expand Down Expand Up @@ -585,7 +585,7 @@ func BenchmarkWorldExchangeBatchEvent_1000(b *testing.B) {
world.Batch().Exchange(filterVel, pos, vel)

var temp event.Subscription
listener := newTestListener(func(e EntityEvent) { temp = e.EventTypes })
listener := newTestListener(func(world *World, e EntityEvent) { temp = e.EventTypes })
world.SetListener(&listener)

b.StartTimer()
Expand Down
8 changes: 4 additions & 4 deletions ecs/world_examples_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ func ExampleWorld_SetListener() {
world := ecs.NewWorld()

listener := TestListener{
Callback: func(evt ecs.EntityEvent) {
Callback: func(world *ecs.World, evt ecs.EntityEvent) {
fmt.Println(evt)
},
}
Expand All @@ -296,13 +296,13 @@ func ExampleWorld_Stats() {

// TestListener for all [EntityEvent]s.
type TestListener struct {
Callback func(e ecs.EntityEvent)
Callback func(world *ecs.World, evt ecs.EntityEvent)
}

// Notify the listener.
// Calls the Callback.
func (l *TestListener) Notify(e ecs.EntityEvent) {
l.Callback(e)
func (l *TestListener) Notify(world *ecs.World, evt ecs.EntityEvent) {
l.Callback(world, evt)
}

// Subscriptions of the listener.
Expand Down
Loading

0 comments on commit 7f85627

Please sign in to comment.