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