package ecs import ( "context" "fmt" "log/slog" "math" "runtime/debug" "time" "github.com/yohamta/donburi" "github.com/yohamta/donburi/features/events" ) type WorldState int type WorldId = donburi.WorldId const ( WorldInit WorldState = 0 WorldRunning WorldState = 1 WorldPause WorldState = 2 WorldError WorldState = 3 WorldClosed WorldState = 4 ) type ( World interface { donburi.World // 世界运行间隔时间 Tick() int // 获取世界状态 State() WorldState // 启动世界 StartUp() // 暂停世界 Pause() // 恢复世界 Resume() // 关闭世界 Close() // 设置运行倍速 SetSpeed(speed float64) error // 添加系统 AddSystem(sys ...ISystem) // 在世界中执行处理逻辑(在世界运行线程中) Execute(fn HandleFunc) error } // 处理函数 HandleFunc func() // 世界状态变更消息 WorldStateChange struct { OldState WorldState NewState WorldState } ) // 世界状态变更事件 var WorldStateChangeEvent = NewEventType[WorldStateChange]() type world struct { donburi.World systems []ISystem state WorldState tick int ticker *time.Ticker // 世界运行倍速 speed float64 // 下一帧系统需要执行的次数 times float64 // 待执行函数 toBeExecuteds chan HandleFunc cancel context.CancelFunc done chan struct{} // 服务协程退出信号 // 世界异常记录 err any } // 新建一个组件类型 func NewComponentType[T any](opts ...interface{}) *ComponentType[T] { ct := donburi.NewComponentType[T](opts...) return &ComponentType[T]{ct} } // 新建一个标签 func NewTag() *ComponentType[struct{}] { return NewComponentType[struct{}]() } // 将entity列表转换为entry列表 func Entries(w World, entities []donburi.Entity) []*Entry { entries := make([]*Entry, len(entities)) for i, entity := range entities { entries[i] = w.Entry(entity) } return entries } // 初始化一个新World // tick 单位为ms,且必须大于0,(小于15ms的值在Windows系统中会达不到,Windows系统中系统中断好像默认是15.6ms,也就是一秒最多64次) func NewWorld(tick int) World { if tick <= 0 { panic(fmt.Errorf("创建World错误: tick必须大于0")) } return &world{ World: donburi.NewWorld(), systems: make([]ISystem, 0), state: WorldInit, tick: tick, ticker: time.NewTicker(time.Duration(tick) * time.Millisecond), speed: 1, times: 1, toBeExecuteds: make(chan HandleFunc, 32), done: make(chan struct{}), } } func (w *world) Tick() int { return w.tick } func (w *world) State() WorldState { return w.state } // 添加系统 func (w *world) AddSystem(sys ...ISystem) { w.systems = append(w.systems, sys...) } // 执行所有事件处理 func (w *world) ProcessAllEvents() { events.ProcessAllEvents(w.World) } // 暂停世界 func (w *world) Pause() { if w.state == WorldRunning { w.updateState(WorldPause) } } // 恢复世界运行 func (w *world) Resume() { if w.state == WorldPause { w.updateState(WorldRunning) } } func (w *world) updateState(state WorldState) { if w.state != state { old := w.state slog.Debug("世界状态变更", "oldstate", old, "state", state) w.state = state WorldStateChangeEvent.Publish(w, &WorldStateChange{ OldState: old, NewState: state, }) WorldStateChangeEvent.ProcessEvents(w) } } const ( speedMin = 0.1 speedMax = 10 ) func WorldSpeedMax() float64 { return speedMax } func WorldSpeedMin() float64 { return speedMin } // 设置世界运行倍速 func (w *world) SetSpeed(speed float64) error { if speed < speedMin || speed > speedMax { return fmt.Errorf("世界倍速必须在[%f, %d]之间", speedMin, speedMax) } w.speed = speed return nil } // 启动世界,世界逻辑开始执行且世界为运行状态 func (w *world) StartUp() { if w.state == WorldInit { // 避免重复运行 slog.Debug("启动世界", "id", w.Id()) ctx, cancle := context.WithCancel(context.Background()) go w.run(ctx) w.cancel = cancle w.updateState(WorldRunning) } } // 在世界线程执行逻辑 func (w *world) Execute(fn HandleFunc) error { if w.state == WorldError { return fmt.Errorf("世界运行异常,无法执行请求") } else if w.state == WorldClosed { return fmt.Errorf("世界已经关闭,无法执行请求") } w.toBeExecuteds <- fn return nil } // 关闭世界 func (w *world) Close() { if w.state == WorldInit { slog.Debug("关闭世界", "id", w.Id()) w.updateState(WorldClosed) return } if w.cancel != nil { w.cancel() <-w.done } } // 执行待处理方法 func (w *world) executeTodos() { funcs := w.toBeExecuteds for { select { case fn := <-funcs: { fn() } default: return } } } // 世界循环 func (w *world) run(ctx context.Context) { defer func() { if err := recover(); err != nil { w.exception(err) slog.Error("世界运行异常", "error", err, "stack", string(debug.Stack())) debug.PrintStack() } }() defer close(w.done) for range w.ticker.C { select { case <-ctx.Done(): w.close() return default: } // start := time.Now() if w.state != WorldRunning { // 世界非运行状态 continue } if w.times >= 1 { times := int(math.Floor(w.times)) for i := 0; i < times; i++ { for _, sys := range w.systems { sys.Update(w) } // 执行待执行逻辑 w.executeTodos() // 处理所有事件 processAllEvents(w) } w.times = w.times - float64(times) + w.speed } else { w.times += w.speed } // dt := time.Since(start) // slog.Info("仿真系统执行耗时:" + dt.Milliseconds() + "ms") } } // 世界运行异常处理 func (w *world) exception(err any) { w.err = err // 世界异常 w.updateState(WorldError) // 关闭定时器 w.ticker.Stop() } // 世界正常关闭逻辑 func (w *world) close() { slog.Debug("关闭世界", "id", w.Id()) // 世界正常关闭 w.updateState(WorldClosed) // 关闭定时器 w.ticker.Stop() slog.Debug("世界关闭finish") }