diff --git a/events.go b/events.go index e70b54e..70d9944 100644 --- a/events.go +++ b/events.go @@ -1,11 +1,102 @@ package ecs -type ( - EventType[T any] struct { - eventName string - componentType *ComponentType[T] - w World - } +import ( + "reflect" - Subscriber[T any] func(w *World, event T) + "github.com/yohamta/donburi" + "github.com/yohamta/donburi/features/events" ) + +// 注意事件相关操作的最终执行者均为world协程 + +// 事件相关定义 +type ( + // 事件类型定义 + EventType[T any] struct { + et *events.EventType[T] + subscriberMap map[uintptr]events.Subscriber[T] + chanToWorld chan<- ManageEventFunc + } + // 事件订阅者定义 + Subscriber[T any] func(w World, event T) + // 事件管理回调定义 + ManageEventFunc func() +) + +func init() { + //开启事件处理调试 + events.Debug = true +} + +// 创建事件类型的实例 +func NewEventType[T any](w World) *EventType[T] { + return &EventType[T]{ + et: events.NewEventType[T](), + subscriberMap: make(map[uintptr]events.Subscriber[T]), + chanToWorld: w.(*world).chanManageEvent, + } +} + +// 迭代处理所有事件 +// 在world协程中执行 +func processAllEvents(w World) { + events.ProcessAllEvents(w.(*world).world) +} + +// 订阅该类型的事件 +func (me *EventType[T]) Subscribe(wd World, subscriber Subscriber[T]) { + if wd.GoroutineId() == currentGoId() { + me.subscribe(wd, subscriber) + } else { + me.chanToWorld <- func() { + me.subscribe(wd, subscriber) + } + } +} + +// 取消订阅该类型的事件 +func (me *EventType[T]) Unsubscribe(wd World, subscriber Subscriber[T]) { + if wd.GoroutineId() == currentGoId() { + me.unsubscribe(wd, subscriber) + } else { + me.chanToWorld <- func() { + me.unsubscribe(wd, subscriber) + } + } +} + +// 发布该类型的事件 +func (me *EventType[T]) Publish(wd World, event *T) { + if wd.GoroutineId() == currentGoId() { + me.publish(wd, event) + } else { + me.chanToWorld <- func() { + me.publish(wd, event) + } + } +} + +/////////////////////////////////////////////////////////////////////////////////// + +// 订阅该类型的事件 +func (me *EventType[T]) subscribe(wd World, subscriber Subscriber[T]) { + wdSubscriberPointer := reflect.ValueOf(subscriber).Pointer() + me.subscriberMap[wdSubscriberPointer] = func(w donburi.World, event T) { + subscriber(wd, event) + } + me.et.Subscribe(wd.(*world).world, me.subscriberMap[wdSubscriberPointer]) +} + +// 取消订阅该类型的事件 +func (me *EventType[T]) unsubscribe(wd World, subscriber Subscriber[T]) { + wdSubscriberPointer := reflect.ValueOf(subscriber).Pointer() + if sub, ok := me.subscriberMap[wdSubscriberPointer]; ok { + me.et.Unsubscribe(wd.(*world).world, sub) + delete(me.subscriberMap, wdSubscriberPointer) + } +} + +// 发布该类型的事件 +func (me *EventType[T]) publish(wd World, event *T) { + me.et.Publish(wd.(*world).world, *event) +} diff --git a/examples/rtss-event/main.go b/examples/rtss-event/main.go new file mode 100644 index 0000000..cabecb8 --- /dev/null +++ b/examples/rtss-event/main.go @@ -0,0 +1,31 @@ +package main + +import ( + "fmt" + "time" + + "joylink.club/ecs" +) + +type FireSwitchDcEvent struct { + Dc bool +} + +func main() { + world := ecs.NewWorld(1000) + world.StartUp() + // + fireSwitchDcEventType := ecs.NewEventType[FireSwitchDcEvent](world) + fireSwitchDcEventType.Subscribe(world, func(w ecs.World, event FireSwitchDcEvent) { + fmt.Println("==>>1 触发道岔定操事件 : dc = ", event.Dc) + }) + fireSwitchDcEventType.Subscribe(world, func(w ecs.World, event FireSwitchDcEvent) { + fmt.Println("==>>2 触发道岔定操事件 : dc = ", event.Dc) + }) + // + time.Sleep(3 * time.Second) + // + fireSwitchDcEventType.Publish(world, &FireSwitchDcEvent{Dc: true}) + fireSwitchDcEventType.Publish(world, &FireSwitchDcEvent{Dc: false}) + time.Sleep(30 * time.Second) +} diff --git a/world.go b/world.go index b67a590..51ba15a 100644 --- a/world.go +++ b/world.go @@ -1,9 +1,11 @@ package ecs import ( + "bytes" "fmt" "log" - "reflect" + "runtime" + "strconv" "time" "github.com/yohamta/donburi" @@ -47,16 +49,19 @@ type World interface { Close() Tick() int Running() bool + GoroutineId() uint64 } type world struct { + gId uint64 world donburi.World systems []ISystem state WorldState tick int speed float64 - quit chan struct{} + quit chan struct{} + chanManageEvent chan ManageEventFunc } func NewComponentType[T any](opts ...interface{}) *ComponentType[T] { @@ -66,14 +71,18 @@ func NewComponentType[T any](opts ...interface{}) *ComponentType[T] { func NewWorld(tick int) World { return &world{ - world: donburi.NewWorld(), - systems: make([]ISystem, 0), - state: Init, - tick: tick, - speed: 1, - quit: make(chan struct{}), + world: donburi.NewWorld(), + systems: make([]ISystem, 0), + state: Init, + tick: tick, + speed: 1, + quit: make(chan struct{}), + chanManageEvent: make(chan ManageEventFunc, 1024), } } +func (w *world) GoroutineId() uint64 { + return w.gId +} func (w *world) Running() bool { return w.state == Running } @@ -165,7 +174,29 @@ func (w *world) Close() { w.quit <- struct{}{} } +// 获取world与事件系统间的管道的只读引用 +func (w *world) eventChanReader() <-chan ManageEventFunc { + return w.chanManageEvent +} + +// 事件管理相关处理 +func (w *world) processManageEventFuncs() { + manageEventChan := w.eventChanReader() + for { + select { + case callBack := <-manageEventChan: + { + callBack() + } + default: + return + } + + } + +} func (w *world) run() { + w.gId = currentGoId() for { select { case <-w.quit: // 退出信号 @@ -192,10 +223,10 @@ func (w *world) run() { for _, sys := range w.systems { sys.Update(w) } - + // 处理事件管理相关 + w.processManageEventFuncs() // 处理所有事件 - // w.ProcessAllEvents() - + processAllEvents(w) // 执行逻辑花费时间,单位ms ot := time.Duration(time.Now().Nanosecond() - start.Nanosecond()).Milliseconds() // 根据间隔和速度计算休眠时间 @@ -208,14 +239,15 @@ func (w *world) run() { } } -func NewEventType[T any](w World) *EventType[T] { - // events.NewEventType() - ct := NewComponentType[T]() - var et T - name := reflect.TypeOf(et).Name() - return &EventType[T]{ - name, - ct, - w, +// 获取当前协程id +func currentGoId() (gid uint64) { + b := make([]byte, 16) + b = b[:runtime.Stack(b, false)] + b = bytes.TrimPrefix(b, []byte("goroutine ")) + b = b[:bytes.IndexByte(b, ' ')] + n, err := strconv.ParseUint(string(b), 10, 64) + if err != nil { + panic(err) } + return n }