github.com/15mga/kiwi@v0.0.2-0.20240324021231-b95d5c3ac751/ecs/system.go (about) 1 package ecs 2 3 import ( 4 "github.com/15mga/kiwi" 5 "github.com/15mga/kiwi/ds" 6 "github.com/15mga/kiwi/util" 7 "github.com/15mga/kiwi/worker" 8 "sync" 9 ) 10 11 func NewSystem(t TSystem) System { 12 return System{ 13 typ: t, 14 } 15 } 16 17 type jobData struct { 18 slc *ds.Array[*worker.Job] 19 worker jobWorker 20 } 21 22 type System struct { 23 typ TSystem 24 frame *Frame 25 scene *Scene 26 wg sync.WaitGroup 27 frameBefore *ds.FnLink 28 frameAfter *ds.FnLink 29 jobNameToData map[worker.JobName]*jobData 30 } 31 32 func (s *System) Jobs() []worker.JobName { 33 jobs := make([]worker.JobName, len(s.jobNameToData)) 34 for name := range s.jobNameToData { 35 jobs = append(jobs, name) 36 } 37 return jobs 38 } 39 40 func (s *System) Frame() *Frame { 41 return s.frame 42 } 43 44 func (s *System) Scene() *Scene { 45 return s.scene 46 } 47 48 func (s *System) FrameBefore() *ds.FnLink { 49 return s.frameBefore 50 } 51 52 func (s *System) FrameAfter() *ds.FnLink { 53 return s.frameAfter 54 } 55 56 func (s *System) Type() TSystem { 57 return s.typ 58 } 59 60 func (s *System) OnBeforeStart() { 61 s.jobNameToData = make(map[JobName]*jobData) 62 } 63 64 func (s *System) OnStart(frame *Frame) { 65 s.frame = frame 66 s.scene = frame.scene 67 s.frameBefore = frame.before 68 s.frameAfter = frame.after 69 } 70 71 func (s *System) OnAfterStart() { 72 for name := range s.jobNameToData { 73 s.frame.bindJob(name, s) 74 } 75 } 76 77 func (s *System) OnStop() { 78 79 } 80 81 func (s *System) OnUpdate() { 82 83 } 84 85 func (s *System) PutJob(name worker.JobName, data ...any) { 86 d, ok := s.jobNameToData[name] 87 if !ok { 88 kiwi.Error2(util.EcNotExist, util.M{ 89 "name": name, 90 }) 91 return 92 } 93 j := worker.SpawnJob() 94 j.Name = name 95 j.Data = data 96 d.slc.Add(j) 97 } 98 99 func (s *System) DoJob(name JobName) { 100 d, ok := s.jobNameToData[name] 101 if !ok { 102 kiwi.Error2(util.EcNotExist, util.M{ 103 "name": name, 104 }) 105 return 106 } 107 slc := d.slc.Values() 108 if len(slc) > 0 { 109 d.worker.Do(slc) 110 d.slc.Reset() 111 } 112 } 113 114 func (s *System) BindJob(name JobName, fn util.FnAnySlc) { 115 s.jobNameToData[name] = &jobData{ 116 slc: ds.NewArray[*worker.Job](8), 117 worker: &defWorker{ 118 fn: fn, 119 }, 120 } 121 } 122 123 func (s *System) BindPJob(name JobName, fn util.FnAnySlc) { 124 s.jobNameToData[name] = &jobData{ 125 slc: ds.NewArray[*worker.Job](8), 126 worker: &pWorker{ 127 fn: fn, 128 }, 129 } 130 } 131 132 func (s *System) BindPFnJob(name JobName, fn FnLinkAnySlc) { 133 s.jobNameToData[name] = &jobData{ 134 slc: ds.NewArray[*worker.Job](8), 135 worker: &pLinkWorker{ 136 fn: fn, 137 }, 138 } 139 } 140 141 func (s *System) PTagComponents(tag string, fn func(IComponent)) ([]IComponent, bool) { 142 components, ok := s.Scene().GetTagComponents(tag) 143 if !ok { 144 return nil, false 145 } 146 worker.P[IComponent](components, fn) 147 return components, true 148 } 149 150 func (s *System) PTagComponentsWithParams(tag string, fn func(IComponent, []any), params ...any) ([]IComponent, bool) { 151 components, ok := s.Scene().GetTagComponents(tag) 152 if !ok { 153 return nil, false 154 } 155 worker.PParams[IComponent](components, fn, params...) 156 return components, true 157 } 158 159 func (s *System) PTagComponentsToFnLink(tag string, fn func(IComponent, *ds.FnLink)) ([]IComponent, bool) { 160 components, ok := s.Scene().GetTagComponents(tag) 161 if !ok { 162 return nil, false 163 } 164 worker.PToFnLink[IComponent](components, fn) 165 return components, true 166 } 167 168 func (s *System) PTagComponentsToFnLinkWithParams(tag string, fn func(IComponent, []any, *ds.FnLink), params ...any) ([]IComponent, bool) { 169 components, ok := s.Scene().GetTagComponents(tag) 170 if !ok { 171 return nil, false 172 } 173 worker.PParamsToFnLink[IComponent](components, fn, params...) 174 return components, true 175 } 176 177 func (s *System) PEntities(fn func(*Entity)) []*Entity { 178 entities := s.Scene().Entities() 179 worker.P[*Entity](entities, fn) 180 return entities 181 } 182 183 func (s *System) PEntitiesWithParams(fn func(*Entity, []any), params ...any) []*Entity { 184 entities := s.Scene().Entities() 185 worker.PParams[*Entity](entities, fn, params...) 186 return entities 187 } 188 189 func PTagComponentsTo[T comparable](s *System, tag string, fn func(IComponent) (T, bool), complete func([]T)) ([]IComponent, bool) { 190 components, ok := s.Scene().GetTagComponents(tag) 191 if !ok { 192 return nil, false 193 } 194 worker.PFilter[IComponent, T](components, fn, complete) 195 return components, true 196 } 197 198 func PTagComponentsToLink[T any](s *Scene, tag string, fn func(IComponent, *ds.Link[T]), pcr func(*ds.Link[T])) ([]IComponent, bool) { 199 components, ok := s.GetTagComponents(tag) 200 if !ok { 201 return nil, false 202 } 203 worker.PToLink[IComponent, T](components, fn, pcr) 204 return components, true 205 } 206 207 type jobWorker interface { 208 Type() TJob 209 Do(jobs []*worker.Job) 210 } 211 212 type defWorker struct { 213 fn util.FnAnySlc 214 } 215 216 func (w *defWorker) Type() TJob { 217 return JobDef 218 } 219 220 func (w *defWorker) Do(jobs []*worker.Job) { 221 for _, j := range jobs { 222 w.fn(j.Data) 223 worker.RecycleJob(j) 224 } 225 } 226 227 type pWorker struct { 228 fn util.FnAnySlc 229 } 230 231 func (w *pWorker) Type() TJob { 232 return JobP 233 } 234 235 func (w *pWorker) Do(jobs []*worker.Job) { 236 worker.P[*worker.Job](jobs, func(j *worker.Job) { 237 w.fn(j.Data) 238 worker.RecycleJob(j) 239 }) 240 } 241 242 type pLinkWorker struct { 243 fn FnLinkAnySlc 244 } 245 246 func (w *pLinkWorker) Type() TJob { 247 return JobPLink 248 } 249 250 func (w *pLinkWorker) Do(jobs []*worker.Job) { 251 worker.PToFnLink(jobs, func(j *worker.Job, link *ds.FnLink) { 252 w.fn(link, j.Data) 253 worker.RecycleJob(j) 254 }) 255 }