diff --git a/features/events/events.go b/features/events/events.go index 17c325b..d25ca6b 100644 --- a/features/events/events.go +++ b/features/events/events.go @@ -60,7 +60,7 @@ func NewEventType[T any]() *EventType[T] { return e } -// RegisterHandler registers a subscriber for the event. +// Subscribe registers a subscriber for the event. func (e *EventType[T]) Subscribe(w donburi.World, subscriber Subscriber[T]) { if e.eventBusQuery.Count(w) == 0 { entity := w.Entry(w.Create(e.eventBus, eventType)) @@ -77,6 +77,29 @@ func (e *EventType[T]) Subscribe(w donburi.World, subscriber Subscriber[T]) { eventBus.subscribers = append(eventBus.subscribers, subscriber) } +// Find the index of a subscriber +func (e *EventType[T]) findSubscriber(w donburi.World, subscriber Subscriber[T]) (int, bool) { + if e.eventBusQuery.Count(w) != 0 { + eventBus := e.mustFindEventBus(w) + for i, s := range eventBus.subscribers { + if reflect.ValueOf(s).Pointer() == reflect.ValueOf(subscriber).Pointer() { + return i, true + } + } + } + return 0, false +} + +// Unsubscribe removes a subscriber for the event. +func (e *EventType[T]) Unsubscribe(w donburi.World, subscriber Subscriber[T]) { + index, found := e.findSubscriber(w, subscriber) + if found { + eventBus := e.mustFindEventBus(w) + eventBus.subscribers[index] = eventBus.subscribers[len(eventBus.subscribers)-1] + eventBus.subscribers = eventBus.subscribers[:len(eventBus.subscribers)-1] + } +} + // Publish publishes an event. func (e *EventType[T]) Publish(w donburi.World, event T) { eventBus := e.mustFindEventBus(w) diff --git a/features/events/example_test.go b/features/events/example_test.go index 9abcd54..231bc40 100644 --- a/features/events/example_test.go +++ b/features/events/example_test.go @@ -40,6 +40,36 @@ func TestEvents(t *testing.T) { } } +func TestUnsubscribe(t *testing.T) { + + w := donburi.NewWorld() + + EnemyKilledEvent.Subscribe(w, HandleEnemyKilled) + EnemyKilledEvent.Publish(w, &EnemyKilled{EnemyID: 1}) + + events.ProcessAllEvents(w) + + ev := lastReceivedEvent + + if ev == nil { + t.Errorf("event should be received") + } + + if ev.EnemyID != 1 { + t.Errorf("event should have value 1") + } + + lastReceivedEvent = nil + EnemyKilledEvent.Unsubscribe(w, HandleEnemyKilled) + EnemyKilledEvent.Publish(w, &EnemyKilled{EnemyID: 1}) + + events.ProcessAllEvents(w) + + if lastReceivedEvent != nil { + t.Errorf("event should not be received") + } +} + var ( lastReceivedEvent *EnemyKilled = nil )