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  }