From eedc6cd9b19dcc405b0d8c7ec740c3f7b4e45840 Mon Sep 17 00:00:00 2001 From: mlange-42 Date: Sat, 8 Mar 2025 02:16:30 +0100 Subject: [PATCH 1/5] Fix wording --- ecs/generate/maps.go.template | 4 ++-- ecs/generate/query.go.template | 2 +- ecs/maps_gen.go | 32 ++++++++++++++++---------------- ecs/query_gen.go | 16 ++++++++-------- 4 files changed, 27 insertions(+), 27 deletions(-) diff --git a/ecs/generate/maps.go.template b/ecs/generate/maps.go.template index 5610f37..36164c7 100644 --- a/ecs/generate/maps.go.template +++ b/ecs/generate/maps.go.template @@ -107,7 +107,7 @@ func (m *Map{{.}}{{$genericsShort}}) NewBatchFn(count int, fn func(entity Entity // Get returns the mapped components for the given entity. // -// ⚠️ Do not store the obtained pointer outside of the current context! +// ⚠️ Do not store the obtained pointers outside of the current context! func (m *Map{{.}}{{$genericsShort}}) Get(entity Entity) {{$return}} { if !m.world.Alive(entity) { panic("can't get components of a dead entity") @@ -119,7 +119,7 @@ func (m *Map{{.}}{{$genericsShort}}) Get(entity Entity) {{$return}} { // In contrast to [Map{{.}}.Get], it does not check whether the entity is alive. // Can be used as an optimization when it is certain that the entity is alive. // -// ⚠️ Do not store the obtained pointer outside of the current context! +// ⚠️ Do not store the obtained pointers outside of the current context! func (m *Map{{.}}{{$genericsShort}}) GetUnchecked(entity Entity) {{$return}} { {{- range $n}} m.world.storage.checkHasComponent(entity, m.ids[{{.}}]) diff --git a/ecs/generate/query.go.template b/ecs/generate/query.go.template index 84c0adb..09b7c20 100644 --- a/ecs/generate/query.go.template +++ b/ecs/generate/query.go.template @@ -83,7 +83,7 @@ func (q *Query{{.}}{{$genericsShort}}) Entity() Entity { {{if . -}} // Get returns the queried components of the current entity. // -// ⚠️ Do not store the obtained pointer outside of the current context (i.e. the query loop)! +// ⚠️ Do not store the obtained pointers outside of the current context (i.e. the query loop)! func (q *Query{{.}}{{$genericsShort}}) Get() {{$return}} { q.world.checkQueryGet(&q.cursor) return {{range $i, $v := $upper}}{{if $i}}, diff --git a/ecs/maps_gen.go b/ecs/maps_gen.go index bab91d3..950263b 100644 --- a/ecs/maps_gen.go +++ b/ecs/maps_gen.go @@ -80,7 +80,7 @@ func (m *Map1[A]) NewBatchFn(count int, fn func(entity Entity, a *A), rel ...Rel // Get returns the mapped components for the given entity. // -// ⚠️ Do not store the obtained pointer outside of the current context! +// ⚠️ Do not store the obtained pointers outside of the current context! func (m *Map1[A]) Get(entity Entity) *A { if !m.world.Alive(entity) { panic("can't get components of a dead entity") @@ -92,7 +92,7 @@ func (m *Map1[A]) Get(entity Entity) *A { // In contrast to [Map1.Get], it does not check whether the entity is alive. // Can be used as an optimization when it is certain that the entity is alive. // -// ⚠️ Do not store the obtained pointer outside of the current context! +// ⚠️ Do not store the obtained pointers outside of the current context! func (m *Map1[A]) GetUnchecked(entity Entity) *A { m.world.storage.checkHasComponent(entity, m.ids[0]) @@ -316,7 +316,7 @@ func (m *Map2[A, B]) NewBatchFn(count int, fn func(entity Entity, a *A, b *B), r // Get returns the mapped components for the given entity. // -// ⚠️ Do not store the obtained pointer outside of the current context! +// ⚠️ Do not store the obtained pointers outside of the current context! func (m *Map2[A, B]) Get(entity Entity) (*A, *B) { if !m.world.Alive(entity) { panic("can't get components of a dead entity") @@ -328,7 +328,7 @@ func (m *Map2[A, B]) Get(entity Entity) (*A, *B) { // In contrast to [Map2.Get], it does not check whether the entity is alive. // Can be used as an optimization when it is certain that the entity is alive. // -// ⚠️ Do not store the obtained pointer outside of the current context! +// ⚠️ Do not store the obtained pointers outside of the current context! func (m *Map2[A, B]) GetUnchecked(entity Entity) (*A, *B) { m.world.storage.checkHasComponent(entity, m.ids[0]) m.world.storage.checkHasComponent(entity, m.ids[1]) @@ -568,7 +568,7 @@ func (m *Map3[A, B, C]) NewBatchFn(count int, fn func(entity Entity, a *A, b *B, // Get returns the mapped components for the given entity. // -// ⚠️ Do not store the obtained pointer outside of the current context! +// ⚠️ Do not store the obtained pointers outside of the current context! func (m *Map3[A, B, C]) Get(entity Entity) (*A, *B, *C) { if !m.world.Alive(entity) { panic("can't get components of a dead entity") @@ -580,7 +580,7 @@ func (m *Map3[A, B, C]) Get(entity Entity) (*A, *B, *C) { // In contrast to [Map3.Get], it does not check whether the entity is alive. // Can be used as an optimization when it is certain that the entity is alive. // -// ⚠️ Do not store the obtained pointer outside of the current context! +// ⚠️ Do not store the obtained pointers outside of the current context! func (m *Map3[A, B, C]) GetUnchecked(entity Entity) (*A, *B, *C) { m.world.storage.checkHasComponent(entity, m.ids[0]) m.world.storage.checkHasComponent(entity, m.ids[1]) @@ -836,7 +836,7 @@ func (m *Map4[A, B, C, D]) NewBatchFn(count int, fn func(entity Entity, a *A, b // Get returns the mapped components for the given entity. // -// ⚠️ Do not store the obtained pointer outside of the current context! +// ⚠️ Do not store the obtained pointers outside of the current context! func (m *Map4[A, B, C, D]) Get(entity Entity) (*A, *B, *C, *D) { if !m.world.Alive(entity) { panic("can't get components of a dead entity") @@ -848,7 +848,7 @@ func (m *Map4[A, B, C, D]) Get(entity Entity) (*A, *B, *C, *D) { // In contrast to [Map4.Get], it does not check whether the entity is alive. // Can be used as an optimization when it is certain that the entity is alive. // -// ⚠️ Do not store the obtained pointer outside of the current context! +// ⚠️ Do not store the obtained pointers outside of the current context! func (m *Map4[A, B, C, D]) GetUnchecked(entity Entity) (*A, *B, *C, *D) { m.world.storage.checkHasComponent(entity, m.ids[0]) m.world.storage.checkHasComponent(entity, m.ids[1]) @@ -1120,7 +1120,7 @@ func (m *Map5[A, B, C, D, E]) NewBatchFn(count int, fn func(entity Entity, a *A, // Get returns the mapped components for the given entity. // -// ⚠️ Do not store the obtained pointer outside of the current context! +// ⚠️ Do not store the obtained pointers outside of the current context! func (m *Map5[A, B, C, D, E]) Get(entity Entity) (*A, *B, *C, *D, *E) { if !m.world.Alive(entity) { panic("can't get components of a dead entity") @@ -1132,7 +1132,7 @@ func (m *Map5[A, B, C, D, E]) Get(entity Entity) (*A, *B, *C, *D, *E) { // In contrast to [Map5.Get], it does not check whether the entity is alive. // Can be used as an optimization when it is certain that the entity is alive. // -// ⚠️ Do not store the obtained pointer outside of the current context! +// ⚠️ Do not store the obtained pointers outside of the current context! func (m *Map5[A, B, C, D, E]) GetUnchecked(entity Entity) (*A, *B, *C, *D, *E) { m.world.storage.checkHasComponent(entity, m.ids[0]) m.world.storage.checkHasComponent(entity, m.ids[1]) @@ -1420,7 +1420,7 @@ func (m *Map6[A, B, C, D, E, F]) NewBatchFn(count int, fn func(entity Entity, a // Get returns the mapped components for the given entity. // -// ⚠️ Do not store the obtained pointer outside of the current context! +// ⚠️ Do not store the obtained pointers outside of the current context! func (m *Map6[A, B, C, D, E, F]) Get(entity Entity) (*A, *B, *C, *D, *E, *F) { if !m.world.Alive(entity) { panic("can't get components of a dead entity") @@ -1432,7 +1432,7 @@ func (m *Map6[A, B, C, D, E, F]) Get(entity Entity) (*A, *B, *C, *D, *E, *F) { // In contrast to [Map6.Get], it does not check whether the entity is alive. // Can be used as an optimization when it is certain that the entity is alive. // -// ⚠️ Do not store the obtained pointer outside of the current context! +// ⚠️ Do not store the obtained pointers outside of the current context! func (m *Map6[A, B, C, D, E, F]) GetUnchecked(entity Entity) (*A, *B, *C, *D, *E, *F) { m.world.storage.checkHasComponent(entity, m.ids[0]) m.world.storage.checkHasComponent(entity, m.ids[1]) @@ -1736,7 +1736,7 @@ func (m *Map7[A, B, C, D, E, F, G]) NewBatchFn(count int, fn func(entity Entity, // Get returns the mapped components for the given entity. // -// ⚠️ Do not store the obtained pointer outside of the current context! +// ⚠️ Do not store the obtained pointers outside of the current context! func (m *Map7[A, B, C, D, E, F, G]) Get(entity Entity) (*A, *B, *C, *D, *E, *F, *G) { if !m.world.Alive(entity) { panic("can't get components of a dead entity") @@ -1748,7 +1748,7 @@ func (m *Map7[A, B, C, D, E, F, G]) Get(entity Entity) (*A, *B, *C, *D, *E, *F, // In contrast to [Map7.Get], it does not check whether the entity is alive. // Can be used as an optimization when it is certain that the entity is alive. // -// ⚠️ Do not store the obtained pointer outside of the current context! +// ⚠️ Do not store the obtained pointers outside of the current context! func (m *Map7[A, B, C, D, E, F, G]) GetUnchecked(entity Entity) (*A, *B, *C, *D, *E, *F, *G) { m.world.storage.checkHasComponent(entity, m.ids[0]) m.world.storage.checkHasComponent(entity, m.ids[1]) @@ -2068,7 +2068,7 @@ func (m *Map8[A, B, C, D, E, F, G, H]) NewBatchFn(count int, fn func(entity Enti // Get returns the mapped components for the given entity. // -// ⚠️ Do not store the obtained pointer outside of the current context! +// ⚠️ Do not store the obtained pointers outside of the current context! func (m *Map8[A, B, C, D, E, F, G, H]) Get(entity Entity) (*A, *B, *C, *D, *E, *F, *G, *H) { if !m.world.Alive(entity) { panic("can't get components of a dead entity") @@ -2080,7 +2080,7 @@ func (m *Map8[A, B, C, D, E, F, G, H]) Get(entity Entity) (*A, *B, *C, *D, *E, * // In contrast to [Map8.Get], it does not check whether the entity is alive. // Can be used as an optimization when it is certain that the entity is alive. // -// ⚠️ Do not store the obtained pointer outside of the current context! +// ⚠️ Do not store the obtained pointers outside of the current context! func (m *Map8[A, B, C, D, E, F, G, H]) GetUnchecked(entity Entity) (*A, *B, *C, *D, *E, *F, *G, *H) { m.world.storage.checkHasComponent(entity, m.ids[0]) m.world.storage.checkHasComponent(entity, m.ids[1]) diff --git a/ecs/query_gen.go b/ecs/query_gen.go index 365d73f..4e3b0bb 100644 --- a/ecs/query_gen.go +++ b/ecs/query_gen.go @@ -196,7 +196,7 @@ func (q *Query1[A]) Entity() Entity { // Get returns the queried components of the current entity. // -// ⚠️ Do not store the obtained pointer outside of the current context (i.e. the query loop)! +// ⚠️ Do not store the obtained pointers outside of the current context (i.e. the query loop)! func (q *Query1[A]) Get() *A { q.world.checkQueryGet(&q.cursor) return (*A)(q.columnA.Get(q.cursor.index)) @@ -344,7 +344,7 @@ func (q *Query2[A, B]) Entity() Entity { // Get returns the queried components of the current entity. // -// ⚠️ Do not store the obtained pointer outside of the current context (i.e. the query loop)! +// ⚠️ Do not store the obtained pointers outside of the current context (i.e. the query loop)! func (q *Query2[A, B]) Get() (*A, *B) { q.world.checkQueryGet(&q.cursor) return (*A)(q.columnA.Get(q.cursor.index)), @@ -496,7 +496,7 @@ func (q *Query3[A, B, C]) Entity() Entity { // Get returns the queried components of the current entity. // -// ⚠️ Do not store the obtained pointer outside of the current context (i.e. the query loop)! +// ⚠️ Do not store the obtained pointers outside of the current context (i.e. the query loop)! func (q *Query3[A, B, C]) Get() (*A, *B, *C) { q.world.checkQueryGet(&q.cursor) return (*A)(q.columnA.Get(q.cursor.index)), @@ -652,7 +652,7 @@ func (q *Query4[A, B, C, D]) Entity() Entity { // Get returns the queried components of the current entity. // -// ⚠️ Do not store the obtained pointer outside of the current context (i.e. the query loop)! +// ⚠️ Do not store the obtained pointers outside of the current context (i.e. the query loop)! func (q *Query4[A, B, C, D]) Get() (*A, *B, *C, *D) { q.world.checkQueryGet(&q.cursor) return (*A)(q.columnA.Get(q.cursor.index)), @@ -812,7 +812,7 @@ func (q *Query5[A, B, C, D, E]) Entity() Entity { // Get returns the queried components of the current entity. // -// ⚠️ Do not store the obtained pointer outside of the current context (i.e. the query loop)! +// ⚠️ Do not store the obtained pointers outside of the current context (i.e. the query loop)! func (q *Query5[A, B, C, D, E]) Get() (*A, *B, *C, *D, *E) { q.world.checkQueryGet(&q.cursor) return (*A)(q.columnA.Get(q.cursor.index)), @@ -976,7 +976,7 @@ func (q *Query6[A, B, C, D, E, F]) Entity() Entity { // Get returns the queried components of the current entity. // -// ⚠️ Do not store the obtained pointer outside of the current context (i.e. the query loop)! +// ⚠️ Do not store the obtained pointers outside of the current context (i.e. the query loop)! func (q *Query6[A, B, C, D, E, F]) Get() (*A, *B, *C, *D, *E, *F) { q.world.checkQueryGet(&q.cursor) return (*A)(q.columnA.Get(q.cursor.index)), @@ -1144,7 +1144,7 @@ func (q *Query7[A, B, C, D, E, F, G]) Entity() Entity { // Get returns the queried components of the current entity. // -// ⚠️ Do not store the obtained pointer outside of the current context (i.e. the query loop)! +// ⚠️ Do not store the obtained pointers outside of the current context (i.e. the query loop)! func (q *Query7[A, B, C, D, E, F, G]) Get() (*A, *B, *C, *D, *E, *F, *G) { q.world.checkQueryGet(&q.cursor) return (*A)(q.columnA.Get(q.cursor.index)), @@ -1316,7 +1316,7 @@ func (q *Query8[A, B, C, D, E, F, G, H]) Entity() Entity { // Get returns the queried components of the current entity. // -// ⚠️ Do not store the obtained pointer outside of the current context (i.e. the query loop)! +// ⚠️ Do not store the obtained pointers outside of the current context (i.e. the query loop)! func (q *Query8[A, B, C, D, E, F, G, H]) Get() (*A, *B, *C, *D, *E, *F, *G, *H) { q.world.checkQueryGet(&q.cursor) return (*A)(q.columnA.Get(q.cursor.index)), From b9794c8352d59bbab45d61729f427ca852999fb0 Mon Sep 17 00:00:00 2001 From: mlange-42 Date: Sat, 8 Mar 2025 02:19:22 +0100 Subject: [PATCH 2/5] Add more warnings --- ecs/exchange_gen.go | 80 +++++++++++++++++++++++++++---- ecs/generate/exchange.go.template | 10 +++- ecs/generate/maps.go.template | 8 ++++ ecs/map.go | 4 ++ ecs/maps_gen.go | 64 +++++++++++++++++++++++++ 5 files changed, 157 insertions(+), 9 deletions(-) diff --git a/ecs/exchange_gen.go b/ecs/exchange_gen.go index a8fa1b6..cdab050 100644 --- a/ecs/exchange_gen.go +++ b/ecs/exchange_gen.go @@ -44,6 +44,8 @@ func (ex *Exchange1[A]) Add(entity Entity, a *A, rel ...Relation) { // AddFn adds the mapped components to the given entity and runs a callback instead of using components for initialization. // The callback can be nil. +// +// ⚠️ Do not store the obtained pointers outside of the current context! func (ex *Exchange1[A]) AddFn(entity Entity, fn func(a *A), rel ...Relation) { ex.relations = relations(rel).toRelations(ex.world, ex.ids, nil, ex.relations) ex.world.exchange(entity, ex.ids, nil, nil, ex.relations) @@ -66,10 +68,12 @@ func (ex *Exchange1[A]) Exchange(entity Entity, a *A, rel ...Relation) { }, ex.relations) } -// Exchange performs the exchange on the given entity, adding the provided components +// ExchangeFn performs the exchange on the given entity, adding the provided components // and removing those previously specified with [Exchange1.Removes]. // It runs a callback instead of using components for initialization. // The callback can be nil. +// +// ⚠️ Do not store the obtained pointers outside of the current context! func (ex *Exchange1[A]) ExchangeFn(entity Entity, fn func(a *A), rel ...Relation) { ex.relations = relations(rel).toRelations(ex.world, ex.ids, nil, ex.relations) ex.world.exchange(entity, ex.ids, ex.remove, nil, ex.relations) @@ -88,6 +92,8 @@ func (ex *Exchange1[A]) AddBatch(batch *Batch, a *A, rel ...Relation) { // AddBatchFn adds the mapped components to all entities matching the given batch filter, // running the given function on each. The function can be nil. +// +// ⚠️ Do not store the obtained pointers outside of the current context! func (ex *Exchange1[A]) AddBatchFn(batch *Batch, fn func(entity Entity, a *A), rel ...Relation) { ex.exchangeBatchFn(batch, fn, false, rel...) } @@ -122,6 +128,8 @@ func (ex *Exchange1[A]) ExchangeBatch(batch *Batch, a *A, rel ...Relation) { // ExchangeBatchFn performs the exchange on all entities matching the given batch filter, // running the given function on each. The function can be nil. +// +// ⚠️ Do not store the obtained pointers outside of the current context! func (ex *Exchange1[A]) ExchangeBatchFn(batch *Batch, fn func(entity Entity, a *A), rel ...Relation) { ex.exchangeBatchFn(batch, fn, true, rel...) } @@ -204,6 +212,8 @@ func (ex *Exchange2[A, B]) Add(entity Entity, a *A, b *B, rel ...Relation) { // AddFn adds the mapped components to the given entity and runs a callback instead of using components for initialization. // The callback can be nil. +// +// ⚠️ Do not store the obtained pointers outside of the current context! func (ex *Exchange2[A, B]) AddFn(entity Entity, fn func(a *A, b *B), rel ...Relation) { ex.relations = relations(rel).toRelations(ex.world, ex.ids, nil, ex.relations) ex.world.exchange(entity, ex.ids, nil, nil, ex.relations) @@ -227,10 +237,12 @@ func (ex *Exchange2[A, B]) Exchange(entity Entity, a *A, b *B, rel ...Relation) }, ex.relations) } -// Exchange performs the exchange on the given entity, adding the provided components +// ExchangeFn performs the exchange on the given entity, adding the provided components // and removing those previously specified with [Exchange2.Removes]. // It runs a callback instead of using components for initialization. // The callback can be nil. +// +// ⚠️ Do not store the obtained pointers outside of the current context! func (ex *Exchange2[A, B]) ExchangeFn(entity Entity, fn func(a *A, b *B), rel ...Relation) { ex.relations = relations(rel).toRelations(ex.world, ex.ids, nil, ex.relations) ex.world.exchange(entity, ex.ids, ex.remove, nil, ex.relations) @@ -250,6 +262,8 @@ func (ex *Exchange2[A, B]) AddBatch(batch *Batch, a *A, b *B, rel ...Relation) { // AddBatchFn adds the mapped components to all entities matching the given batch filter, // running the given function on each. The function can be nil. +// +// ⚠️ Do not store the obtained pointers outside of the current context! func (ex *Exchange2[A, B]) AddBatchFn(batch *Batch, fn func(entity Entity, a *A, b *B), rel ...Relation) { ex.exchangeBatchFn(batch, fn, false, rel...) } @@ -285,6 +299,8 @@ func (ex *Exchange2[A, B]) ExchangeBatch(batch *Batch, a *A, b *B, rel ...Relati // ExchangeBatchFn performs the exchange on all entities matching the given batch filter, // running the given function on each. The function can be nil. +// +// ⚠️ Do not store the obtained pointers outside of the current context! func (ex *Exchange2[A, B]) ExchangeBatchFn(batch *Batch, fn func(entity Entity, a *A, b *B), rel ...Relation) { ex.exchangeBatchFn(batch, fn, true, rel...) } @@ -372,6 +388,8 @@ func (ex *Exchange3[A, B, C]) Add(entity Entity, a *A, b *B, c *C, rel ...Relati // AddFn adds the mapped components to the given entity and runs a callback instead of using components for initialization. // The callback can be nil. +// +// ⚠️ Do not store the obtained pointers outside of the current context! func (ex *Exchange3[A, B, C]) AddFn(entity Entity, fn func(a *A, b *B, c *C), rel ...Relation) { ex.relations = relations(rel).toRelations(ex.world, ex.ids, nil, ex.relations) ex.world.exchange(entity, ex.ids, nil, nil, ex.relations) @@ -396,10 +414,12 @@ func (ex *Exchange3[A, B, C]) Exchange(entity Entity, a *A, b *B, c *C, rel ...R }, ex.relations) } -// Exchange performs the exchange on the given entity, adding the provided components +// ExchangeFn performs the exchange on the given entity, adding the provided components // and removing those previously specified with [Exchange3.Removes]. // It runs a callback instead of using components for initialization. // The callback can be nil. +// +// ⚠️ Do not store the obtained pointers outside of the current context! func (ex *Exchange3[A, B, C]) ExchangeFn(entity Entity, fn func(a *A, b *B, c *C), rel ...Relation) { ex.relations = relations(rel).toRelations(ex.world, ex.ids, nil, ex.relations) ex.world.exchange(entity, ex.ids, ex.remove, nil, ex.relations) @@ -420,6 +440,8 @@ func (ex *Exchange3[A, B, C]) AddBatch(batch *Batch, a *A, b *B, c *C, rel ...Re // AddBatchFn adds the mapped components to all entities matching the given batch filter, // running the given function on each. The function can be nil. +// +// ⚠️ Do not store the obtained pointers outside of the current context! func (ex *Exchange3[A, B, C]) AddBatchFn(batch *Batch, fn func(entity Entity, a *A, b *B, c *C), rel ...Relation) { ex.exchangeBatchFn(batch, fn, false, rel...) } @@ -456,6 +478,8 @@ func (ex *Exchange3[A, B, C]) ExchangeBatch(batch *Batch, a *A, b *B, c *C, rel // ExchangeBatchFn performs the exchange on all entities matching the given batch filter, // running the given function on each. The function can be nil. +// +// ⚠️ Do not store the obtained pointers outside of the current context! func (ex *Exchange3[A, B, C]) ExchangeBatchFn(batch *Batch, fn func(entity Entity, a *A, b *B, c *C), rel ...Relation) { ex.exchangeBatchFn(batch, fn, true, rel...) } @@ -548,6 +572,8 @@ func (ex *Exchange4[A, B, C, D]) Add(entity Entity, a *A, b *B, c *C, d *D, rel // AddFn adds the mapped components to the given entity and runs a callback instead of using components for initialization. // The callback can be nil. +// +// ⚠️ Do not store the obtained pointers outside of the current context! func (ex *Exchange4[A, B, C, D]) AddFn(entity Entity, fn func(a *A, b *B, c *C, d *D), rel ...Relation) { ex.relations = relations(rel).toRelations(ex.world, ex.ids, nil, ex.relations) ex.world.exchange(entity, ex.ids, nil, nil, ex.relations) @@ -573,10 +599,12 @@ func (ex *Exchange4[A, B, C, D]) Exchange(entity Entity, a *A, b *B, c *C, d *D, }, ex.relations) } -// Exchange performs the exchange on the given entity, adding the provided components +// ExchangeFn performs the exchange on the given entity, adding the provided components // and removing those previously specified with [Exchange4.Removes]. // It runs a callback instead of using components for initialization. // The callback can be nil. +// +// ⚠️ Do not store the obtained pointers outside of the current context! func (ex *Exchange4[A, B, C, D]) ExchangeFn(entity Entity, fn func(a *A, b *B, c *C, d *D), rel ...Relation) { ex.relations = relations(rel).toRelations(ex.world, ex.ids, nil, ex.relations) ex.world.exchange(entity, ex.ids, ex.remove, nil, ex.relations) @@ -598,6 +626,8 @@ func (ex *Exchange4[A, B, C, D]) AddBatch(batch *Batch, a *A, b *B, c *C, d *D, // AddBatchFn adds the mapped components to all entities matching the given batch filter, // running the given function on each. The function can be nil. +// +// ⚠️ Do not store the obtained pointers outside of the current context! func (ex *Exchange4[A, B, C, D]) AddBatchFn(batch *Batch, fn func(entity Entity, a *A, b *B, c *C, d *D), rel ...Relation) { ex.exchangeBatchFn(batch, fn, false, rel...) } @@ -635,6 +665,8 @@ func (ex *Exchange4[A, B, C, D]) ExchangeBatch(batch *Batch, a *A, b *B, c *C, d // ExchangeBatchFn performs the exchange on all entities matching the given batch filter, // running the given function on each. The function can be nil. +// +// ⚠️ Do not store the obtained pointers outside of the current context! func (ex *Exchange4[A, B, C, D]) ExchangeBatchFn(batch *Batch, fn func(entity Entity, a *A, b *B, c *C, d *D), rel ...Relation) { ex.exchangeBatchFn(batch, fn, true, rel...) } @@ -732,6 +764,8 @@ func (ex *Exchange5[A, B, C, D, E]) Add(entity Entity, a *A, b *B, c *C, d *D, e // AddFn adds the mapped components to the given entity and runs a callback instead of using components for initialization. // The callback can be nil. +// +// ⚠️ Do not store the obtained pointers outside of the current context! func (ex *Exchange5[A, B, C, D, E]) AddFn(entity Entity, fn func(a *A, b *B, c *C, d *D, e *E), rel ...Relation) { ex.relations = relations(rel).toRelations(ex.world, ex.ids, nil, ex.relations) ex.world.exchange(entity, ex.ids, nil, nil, ex.relations) @@ -758,10 +792,12 @@ func (ex *Exchange5[A, B, C, D, E]) Exchange(entity Entity, a *A, b *B, c *C, d }, ex.relations) } -// Exchange performs the exchange on the given entity, adding the provided components +// ExchangeFn performs the exchange on the given entity, adding the provided components // and removing those previously specified with [Exchange5.Removes]. // It runs a callback instead of using components for initialization. // The callback can be nil. +// +// ⚠️ Do not store the obtained pointers outside of the current context! func (ex *Exchange5[A, B, C, D, E]) ExchangeFn(entity Entity, fn func(a *A, b *B, c *C, d *D, e *E), rel ...Relation) { ex.relations = relations(rel).toRelations(ex.world, ex.ids, nil, ex.relations) ex.world.exchange(entity, ex.ids, ex.remove, nil, ex.relations) @@ -784,6 +820,8 @@ func (ex *Exchange5[A, B, C, D, E]) AddBatch(batch *Batch, a *A, b *B, c *C, d * // AddBatchFn adds the mapped components to all entities matching the given batch filter, // running the given function on each. The function can be nil. +// +// ⚠️ Do not store the obtained pointers outside of the current context! func (ex *Exchange5[A, B, C, D, E]) AddBatchFn(batch *Batch, fn func(entity Entity, a *A, b *B, c *C, d *D, e *E), rel ...Relation) { ex.exchangeBatchFn(batch, fn, false, rel...) } @@ -822,6 +860,8 @@ func (ex *Exchange5[A, B, C, D, E]) ExchangeBatch(batch *Batch, a *A, b *B, c *C // ExchangeBatchFn performs the exchange on all entities matching the given batch filter, // running the given function on each. The function can be nil. +// +// ⚠️ Do not store the obtained pointers outside of the current context! func (ex *Exchange5[A, B, C, D, E]) ExchangeBatchFn(batch *Batch, fn func(entity Entity, a *A, b *B, c *C, d *D, e *E), rel ...Relation) { ex.exchangeBatchFn(batch, fn, true, rel...) } @@ -924,6 +964,8 @@ func (ex *Exchange6[A, B, C, D, E, F]) Add(entity Entity, a *A, b *B, c *C, d *D // AddFn adds the mapped components to the given entity and runs a callback instead of using components for initialization. // The callback can be nil. +// +// ⚠️ Do not store the obtained pointers outside of the current context! func (ex *Exchange6[A, B, C, D, E, F]) AddFn(entity Entity, fn func(a *A, b *B, c *C, d *D, e *E, f *F), rel ...Relation) { ex.relations = relations(rel).toRelations(ex.world, ex.ids, nil, ex.relations) ex.world.exchange(entity, ex.ids, nil, nil, ex.relations) @@ -951,10 +993,12 @@ func (ex *Exchange6[A, B, C, D, E, F]) Exchange(entity Entity, a *A, b *B, c *C, }, ex.relations) } -// Exchange performs the exchange on the given entity, adding the provided components +// ExchangeFn performs the exchange on the given entity, adding the provided components // and removing those previously specified with [Exchange6.Removes]. // It runs a callback instead of using components for initialization. // The callback can be nil. +// +// ⚠️ Do not store the obtained pointers outside of the current context! func (ex *Exchange6[A, B, C, D, E, F]) ExchangeFn(entity Entity, fn func(a *A, b *B, c *C, d *D, e *E, f *F), rel ...Relation) { ex.relations = relations(rel).toRelations(ex.world, ex.ids, nil, ex.relations) ex.world.exchange(entity, ex.ids, ex.remove, nil, ex.relations) @@ -978,6 +1022,8 @@ func (ex *Exchange6[A, B, C, D, E, F]) AddBatch(batch *Batch, a *A, b *B, c *C, // AddBatchFn adds the mapped components to all entities matching the given batch filter, // running the given function on each. The function can be nil. +// +// ⚠️ Do not store the obtained pointers outside of the current context! func (ex *Exchange6[A, B, C, D, E, F]) AddBatchFn(batch *Batch, fn func(entity Entity, a *A, b *B, c *C, d *D, e *E, f *F), rel ...Relation) { ex.exchangeBatchFn(batch, fn, false, rel...) } @@ -1017,6 +1063,8 @@ func (ex *Exchange6[A, B, C, D, E, F]) ExchangeBatch(batch *Batch, a *A, b *B, c // ExchangeBatchFn performs the exchange on all entities matching the given batch filter, // running the given function on each. The function can be nil. +// +// ⚠️ Do not store the obtained pointers outside of the current context! func (ex *Exchange6[A, B, C, D, E, F]) ExchangeBatchFn(batch *Batch, fn func(entity Entity, a *A, b *B, c *C, d *D, e *E, f *F), rel ...Relation) { ex.exchangeBatchFn(batch, fn, true, rel...) } @@ -1124,6 +1172,8 @@ func (ex *Exchange7[A, B, C, D, E, F, G]) Add(entity Entity, a *A, b *B, c *C, d // AddFn adds the mapped components to the given entity and runs a callback instead of using components for initialization. // The callback can be nil. +// +// ⚠️ Do not store the obtained pointers outside of the current context! func (ex *Exchange7[A, B, C, D, E, F, G]) AddFn(entity Entity, fn func(a *A, b *B, c *C, d *D, e *E, f *F, g *G), rel ...Relation) { ex.relations = relations(rel).toRelations(ex.world, ex.ids, nil, ex.relations) ex.world.exchange(entity, ex.ids, nil, nil, ex.relations) @@ -1152,10 +1202,12 @@ func (ex *Exchange7[A, B, C, D, E, F, G]) Exchange(entity Entity, a *A, b *B, c }, ex.relations) } -// Exchange performs the exchange on the given entity, adding the provided components +// ExchangeFn performs the exchange on the given entity, adding the provided components // and removing those previously specified with [Exchange7.Removes]. // It runs a callback instead of using components for initialization. // The callback can be nil. +// +// ⚠️ Do not store the obtained pointers outside of the current context! func (ex *Exchange7[A, B, C, D, E, F, G]) ExchangeFn(entity Entity, fn func(a *A, b *B, c *C, d *D, e *E, f *F, g *G), rel ...Relation) { ex.relations = relations(rel).toRelations(ex.world, ex.ids, nil, ex.relations) ex.world.exchange(entity, ex.ids, ex.remove, nil, ex.relations) @@ -1180,6 +1232,8 @@ func (ex *Exchange7[A, B, C, D, E, F, G]) AddBatch(batch *Batch, a *A, b *B, c * // AddBatchFn adds the mapped components to all entities matching the given batch filter, // running the given function on each. The function can be nil. +// +// ⚠️ Do not store the obtained pointers outside of the current context! func (ex *Exchange7[A, B, C, D, E, F, G]) AddBatchFn(batch *Batch, fn func(entity Entity, a *A, b *B, c *C, d *D, e *E, f *F, g *G), rel ...Relation) { ex.exchangeBatchFn(batch, fn, false, rel...) } @@ -1220,6 +1274,8 @@ func (ex *Exchange7[A, B, C, D, E, F, G]) ExchangeBatch(batch *Batch, a *A, b *B // ExchangeBatchFn performs the exchange on all entities matching the given batch filter, // running the given function on each. The function can be nil. +// +// ⚠️ Do not store the obtained pointers outside of the current context! func (ex *Exchange7[A, B, C, D, E, F, G]) ExchangeBatchFn(batch *Batch, fn func(entity Entity, a *A, b *B, c *C, d *D, e *E, f *F, g *G), rel ...Relation) { ex.exchangeBatchFn(batch, fn, true, rel...) } @@ -1332,6 +1388,8 @@ func (ex *Exchange8[A, B, C, D, E, F, G, H]) Add(entity Entity, a *A, b *B, c *C // AddFn adds the mapped components to the given entity and runs a callback instead of using components for initialization. // The callback can be nil. +// +// ⚠️ Do not store the obtained pointers outside of the current context! func (ex *Exchange8[A, B, C, D, E, F, G, H]) AddFn(entity Entity, fn func(a *A, b *B, c *C, d *D, e *E, f *F, g *G, h *H), rel ...Relation) { ex.relations = relations(rel).toRelations(ex.world, ex.ids, nil, ex.relations) ex.world.exchange(entity, ex.ids, nil, nil, ex.relations) @@ -1361,10 +1419,12 @@ func (ex *Exchange8[A, B, C, D, E, F, G, H]) Exchange(entity Entity, a *A, b *B, }, ex.relations) } -// Exchange performs the exchange on the given entity, adding the provided components +// ExchangeFn performs the exchange on the given entity, adding the provided components // and removing those previously specified with [Exchange8.Removes]. // It runs a callback instead of using components for initialization. // The callback can be nil. +// +// ⚠️ Do not store the obtained pointers outside of the current context! func (ex *Exchange8[A, B, C, D, E, F, G, H]) ExchangeFn(entity Entity, fn func(a *A, b *B, c *C, d *D, e *E, f *F, g *G, h *H), rel ...Relation) { ex.relations = relations(rel).toRelations(ex.world, ex.ids, nil, ex.relations) ex.world.exchange(entity, ex.ids, ex.remove, nil, ex.relations) @@ -1390,6 +1450,8 @@ func (ex *Exchange8[A, B, C, D, E, F, G, H]) AddBatch(batch *Batch, a *A, b *B, // AddBatchFn adds the mapped components to all entities matching the given batch filter, // running the given function on each. The function can be nil. +// +// ⚠️ Do not store the obtained pointers outside of the current context! func (ex *Exchange8[A, B, C, D, E, F, G, H]) AddBatchFn(batch *Batch, fn func(entity Entity, a *A, b *B, c *C, d *D, e *E, f *F, g *G, h *H), rel ...Relation) { ex.exchangeBatchFn(batch, fn, false, rel...) } @@ -1431,6 +1493,8 @@ func (ex *Exchange8[A, B, C, D, E, F, G, H]) ExchangeBatch(batch *Batch, a *A, b // ExchangeBatchFn performs the exchange on all entities matching the given batch filter, // running the given function on each. The function can be nil. +// +// ⚠️ Do not store the obtained pointers outside of the current context! func (ex *Exchange8[A, B, C, D, E, F, G, H]) ExchangeBatchFn(batch *Batch, fn func(entity Entity, a *A, b *B, c *C, d *D, e *E, f *F, g *G, h *H), rel ...Relation) { ex.exchangeBatchFn(batch, fn, true, rel...) } diff --git a/ecs/generate/exchange.go.template b/ecs/generate/exchange.go.template index 27dc752..091f3b6 100644 --- a/ecs/generate/exchange.go.template +++ b/ecs/generate/exchange.go.template @@ -59,6 +59,8 @@ func (ex *Exchange{{.}}{{$genericsShort}}) Add(entity Entity, {{$args}}, rel ... // AddFn adds the mapped components to the given entity and runs a callback instead of using components for initialization. // The callback can be nil. +// +// ⚠️ Do not store the obtained pointers outside of the current context! func (ex *Exchange{{.}}{{$genericsShort}}) AddFn(entity Entity, fn func({{$args}}), rel ...Relation) { ex.relations = relations(rel).toRelations(ex.world, ex.ids, nil, ex.relations) ex.world.exchange(entity, ex.ids, nil, nil, ex.relations) @@ -83,10 +85,12 @@ func (ex *Exchange{{.}}{{$genericsShort}}) Exchange(entity Entity, {{$args}}, re }, ex.relations) } -// Exchange performs the exchange on the given entity, adding the provided components +// ExchangeFn performs the exchange on the given entity, adding the provided components // and removing those previously specified with [Exchange{{.}}.Removes]. // It runs a callback instead of using components for initialization. // The callback can be nil. +// +// ⚠️ Do not store the obtained pointers outside of the current context! func (ex *Exchange{{.}}{{$genericsShort}}) ExchangeFn(entity Entity, fn func({{$args}}), rel ...Relation) { ex.relations = relations(rel).toRelations(ex.world, ex.ids, nil, ex.relations) ex.world.exchange(entity, ex.ids, ex.remove, nil, ex.relations) @@ -107,6 +111,8 @@ func (ex *Exchange{{.}}{{$genericsShort}}) AddBatch(batch *Batch, {{$args}}, rel // AddBatchFn adds the mapped components to all entities matching the given batch filter, // running the given function on each. The function can be nil. +// +// ⚠️ Do not store the obtained pointers outside of the current context! func (ex *Exchange{{.}}{{$genericsShort}}) AddBatchFn(batch *Batch, fn func(entity Entity, {{$args}}), rel ...Relation) { ex.exchangeBatchFn(batch, fn, false, rel...) } @@ -143,6 +149,8 @@ func (ex *Exchange{{.}}{{$genericsShort}}) ExchangeBatch(batch *Batch, {{$args}} // ExchangeBatchFn performs the exchange on all entities matching the given batch filter, // running the given function on each. The function can be nil. +// +// ⚠️ Do not store the obtained pointers outside of the current context! func (ex *Exchange{{.}}{{$genericsShort}}) ExchangeBatchFn(batch *Batch, fn func(entity Entity, {{$args}}), rel ...Relation) { ex.exchangeBatchFn(batch, fn, true, rel...) } diff --git a/ecs/generate/maps.go.template b/ecs/generate/maps.go.template index 36164c7..6557188 100644 --- a/ecs/generate/maps.go.template +++ b/ecs/generate/maps.go.template @@ -53,6 +53,8 @@ func (m *Map{{.}}{{$genericsShort}}) NewEntity({{$args}}, rel ...Relation) Entit // NewEntityFn creates a new entity with the mapped component and runs a callback instead of using a component for initialization. // The callback can be nil. +// +// ⚠️ Do not store the obtained pointers outside of the current context! func (m *Map{{.}}{{$genericsShort}}) NewEntityFn(fn func({{$args}}), rel ...Relation) Entity { m.relations = relations(rel).toRelations(m.world, m.ids, nil, m.relations) entity := m.world.newEntityWith(m.ids, nil, m.relations) @@ -80,6 +82,8 @@ func (m *Map{{.}}{{$genericsShort}}) NewBatch(count int, {{$args}}, rel ...Relat // NewBatchFn creates a batch of new entities with the mapped components, running the given initializer function on each. // The initializer function can be nil. +// +// ⚠️ Do not store the obtained pointers outside of the current context! func (m *Map{{.}}{{$genericsShort}}) NewBatchFn(count int, fn func(entity Entity, {{$args}}), rel ...Relation) { m.relations = relations(rel).toRelations(m.world, m.ids, nil, m.relations) tableID, start := m.world.newEntities(count, m.ids, m.relations) @@ -154,6 +158,8 @@ func (m *Map{{.}}{{$genericsShort}}) Add(entity Entity, {{$args}}, rel ...Relati // AddFn adds the mapped components to the given entity and runs a callback instead of using components for initialization. // The callback can be nil. +// +// ⚠️ Do not store the obtained pointers outside of the current context! func (m *Map{{.}}{{$genericsShort}}) AddFn(entity Entity, fn func({{$args}}), rel ...Relation) { m.relations = relations(rel).toRelations(m.world, m.ids, nil, m.relations) m.world.exchange(entity, m.ids, nil, nil, m.relations) @@ -180,6 +186,8 @@ func (m *Map{{.}}{{$genericsShort}}) AddBatch(batch *Batch, {{$args}}, rel ...Re // AddBatchFn adds the mapped components to all entities matching the given batch filter, // running the given function on each. The function can be nil. +// +// ⚠️ Do not store the obtained pointers outside of the current context! func (m *Map{{.}}{{$genericsShort}}) AddBatchFn(batch *Batch, fn func(entity Entity, {{$args}}), rel ...Relation) { m.relations = relations(rel).toRelations(m.world, m.ids, nil, m.relations) diff --git a/ecs/map.go b/ecs/map.go index 12c0122..2a6436a 100644 --- a/ecs/map.go +++ b/ecs/map.go @@ -28,6 +28,8 @@ func (m *Map[T]) NewEntity(comp *T, rel ...Entity) Entity { // NewEntityFn creates a new entity with the mapped component and runs a callback instead of using a component for initialization. // The callback can be nil. +// +// ⚠️ Do not store the obtained pointer outside of the current context! func (m *Map[T]) NewEntityFn(fn func(a *T), rel ...Entity) Entity { m.relations = relationEntities(rel).toRelation(m.world, m.id, m.relations) entity := m.world.newEntityWith([]ID{m.id}, nil, m.relations) @@ -85,6 +87,8 @@ func (m *Map[T]) Add(entity Entity, comp *T, rel ...Entity) { // AddFn adds the mapped component to the given entity and runs a callback instead of using a component for initialization. // The callback can be nil. +// +// ⚠️ Do not store the obtained pointer outside of the current context! func (m *Map[T]) AddFn(entity Entity, fn func(a *T), rel ...Entity) { if !m.world.Alive(entity) { panic("can't add a component to a dead entity") diff --git a/ecs/maps_gen.go b/ecs/maps_gen.go index 950263b..150f611 100644 --- a/ecs/maps_gen.go +++ b/ecs/maps_gen.go @@ -34,6 +34,8 @@ func (m *Map1[A]) NewEntity(a *A, rel ...Relation) Entity { // NewEntityFn creates a new entity with the mapped component and runs a callback instead of using a component for initialization. // The callback can be nil. +// +// ⚠️ Do not store the obtained pointers outside of the current context! func (m *Map1[A]) NewEntityFn(fn func(a *A), rel ...Relation) Entity { m.relations = relations(rel).toRelations(m.world, m.ids, nil, m.relations) entity := m.world.newEntityWith(m.ids, nil, m.relations) @@ -57,6 +59,8 @@ func (m *Map1[A]) NewBatch(count int, a *A, rel ...Relation) { // NewBatchFn creates a batch of new entities with the mapped components, running the given initializer function on each. // The initializer function can be nil. +// +// ⚠️ Do not store the obtained pointers outside of the current context! func (m *Map1[A]) NewBatchFn(count int, fn func(entity Entity, a *A), rel ...Relation) { m.relations = relations(rel).toRelations(m.world, m.ids, nil, m.relations) tableID, start := m.world.newEntities(count, m.ids, m.relations) @@ -121,6 +125,8 @@ func (m *Map1[A]) Add(entity Entity, a *A, rel ...Relation) { // AddFn adds the mapped components to the given entity and runs a callback instead of using components for initialization. // The callback can be nil. +// +// ⚠️ Do not store the obtained pointers outside of the current context! func (m *Map1[A]) AddFn(entity Entity, fn func(a *A), rel ...Relation) { m.relations = relations(rel).toRelations(m.world, m.ids, nil, m.relations) m.world.exchange(entity, m.ids, nil, nil, m.relations) @@ -143,6 +149,8 @@ func (m *Map1[A]) AddBatch(batch *Batch, a *A, rel ...Relation) { // AddBatchFn adds the mapped components to all entities matching the given batch filter, // running the given function on each. The function can be nil. +// +// ⚠️ Do not store the obtained pointers outside of the current context! func (m *Map1[A]) AddBatchFn(batch *Batch, fn func(entity Entity, a *A), rel ...Relation) { m.relations = relations(rel).toRelations(m.world, m.ids, nil, m.relations) @@ -266,6 +274,8 @@ func (m *Map2[A, B]) NewEntity(a *A, b *B, rel ...Relation) Entity { // NewEntityFn creates a new entity with the mapped component and runs a callback instead of using a component for initialization. // The callback can be nil. +// +// ⚠️ Do not store the obtained pointers outside of the current context! func (m *Map2[A, B]) NewEntityFn(fn func(a *A, b *B), rel ...Relation) Entity { m.relations = relations(rel).toRelations(m.world, m.ids, nil, m.relations) entity := m.world.newEntityWith(m.ids, nil, m.relations) @@ -291,6 +301,8 @@ func (m *Map2[A, B]) NewBatch(count int, a *A, b *B, rel ...Relation) { // NewBatchFn creates a batch of new entities with the mapped components, running the given initializer function on each. // The initializer function can be nil. +// +// ⚠️ Do not store the obtained pointers outside of the current context! func (m *Map2[A, B]) NewBatchFn(count int, fn func(entity Entity, a *A, b *B), rel ...Relation) { m.relations = relations(rel).toRelations(m.world, m.ids, nil, m.relations) tableID, start := m.world.newEntities(count, m.ids, m.relations) @@ -361,6 +373,8 @@ func (m *Map2[A, B]) Add(entity Entity, a *A, b *B, rel ...Relation) { // AddFn adds the mapped components to the given entity and runs a callback instead of using components for initialization. // The callback can be nil. +// +// ⚠️ Do not store the obtained pointers outside of the current context! func (m *Map2[A, B]) AddFn(entity Entity, fn func(a *A, b *B), rel ...Relation) { m.relations = relations(rel).toRelations(m.world, m.ids, nil, m.relations) m.world.exchange(entity, m.ids, nil, nil, m.relations) @@ -385,6 +399,8 @@ func (m *Map2[A, B]) AddBatch(batch *Batch, a *A, b *B, rel ...Relation) { // AddBatchFn adds the mapped components to all entities matching the given batch filter, // running the given function on each. The function can be nil. +// +// ⚠️ Do not store the obtained pointers outside of the current context! func (m *Map2[A, B]) AddBatchFn(batch *Batch, fn func(entity Entity, a *A, b *B), rel ...Relation) { m.relations = relations(rel).toRelations(m.world, m.ids, nil, m.relations) @@ -514,6 +530,8 @@ func (m *Map3[A, B, C]) NewEntity(a *A, b *B, c *C, rel ...Relation) Entity { // NewEntityFn creates a new entity with the mapped component and runs a callback instead of using a component for initialization. // The callback can be nil. +// +// ⚠️ Do not store the obtained pointers outside of the current context! func (m *Map3[A, B, C]) NewEntityFn(fn func(a *A, b *B, c *C), rel ...Relation) Entity { m.relations = relations(rel).toRelations(m.world, m.ids, nil, m.relations) entity := m.world.newEntityWith(m.ids, nil, m.relations) @@ -541,6 +559,8 @@ func (m *Map3[A, B, C]) NewBatch(count int, a *A, b *B, c *C, rel ...Relation) { // NewBatchFn creates a batch of new entities with the mapped components, running the given initializer function on each. // The initializer function can be nil. +// +// ⚠️ Do not store the obtained pointers outside of the current context! func (m *Map3[A, B, C]) NewBatchFn(count int, fn func(entity Entity, a *A, b *B, c *C), rel ...Relation) { m.relations = relations(rel).toRelations(m.world, m.ids, nil, m.relations) tableID, start := m.world.newEntities(count, m.ids, m.relations) @@ -617,6 +637,8 @@ func (m *Map3[A, B, C]) Add(entity Entity, a *A, b *B, c *C, rel ...Relation) { // AddFn adds the mapped components to the given entity and runs a callback instead of using components for initialization. // The callback can be nil. +// +// ⚠️ Do not store the obtained pointers outside of the current context! func (m *Map3[A, B, C]) AddFn(entity Entity, fn func(a *A, b *B, c *C), rel ...Relation) { m.relations = relations(rel).toRelations(m.world, m.ids, nil, m.relations) m.world.exchange(entity, m.ids, nil, nil, m.relations) @@ -643,6 +665,8 @@ func (m *Map3[A, B, C]) AddBatch(batch *Batch, a *A, b *B, c *C, rel ...Relation // AddBatchFn adds the mapped components to all entities matching the given batch filter, // running the given function on each. The function can be nil. +// +// ⚠️ Do not store the obtained pointers outside of the current context! func (m *Map3[A, B, C]) AddBatchFn(batch *Batch, fn func(entity Entity, a *A, b *B, c *C), rel ...Relation) { m.relations = relations(rel).toRelations(m.world, m.ids, nil, m.relations) @@ -778,6 +802,8 @@ func (m *Map4[A, B, C, D]) NewEntity(a *A, b *B, c *C, d *D, rel ...Relation) En // NewEntityFn creates a new entity with the mapped component and runs a callback instead of using a component for initialization. // The callback can be nil. +// +// ⚠️ Do not store the obtained pointers outside of the current context! func (m *Map4[A, B, C, D]) NewEntityFn(fn func(a *A, b *B, c *C, d *D), rel ...Relation) Entity { m.relations = relations(rel).toRelations(m.world, m.ids, nil, m.relations) entity := m.world.newEntityWith(m.ids, nil, m.relations) @@ -807,6 +833,8 @@ func (m *Map4[A, B, C, D]) NewBatch(count int, a *A, b *B, c *C, d *D, rel ...Re // NewBatchFn creates a batch of new entities with the mapped components, running the given initializer function on each. // The initializer function can be nil. +// +// ⚠️ Do not store the obtained pointers outside of the current context! func (m *Map4[A, B, C, D]) NewBatchFn(count int, fn func(entity Entity, a *A, b *B, c *C, d *D), rel ...Relation) { m.relations = relations(rel).toRelations(m.world, m.ids, nil, m.relations) tableID, start := m.world.newEntities(count, m.ids, m.relations) @@ -889,6 +917,8 @@ func (m *Map4[A, B, C, D]) Add(entity Entity, a *A, b *B, c *C, d *D, rel ...Rel // AddFn adds the mapped components to the given entity and runs a callback instead of using components for initialization. // The callback can be nil. +// +// ⚠️ Do not store the obtained pointers outside of the current context! func (m *Map4[A, B, C, D]) AddFn(entity Entity, fn func(a *A, b *B, c *C, d *D), rel ...Relation) { m.relations = relations(rel).toRelations(m.world, m.ids, nil, m.relations) m.world.exchange(entity, m.ids, nil, nil, m.relations) @@ -917,6 +947,8 @@ func (m *Map4[A, B, C, D]) AddBatch(batch *Batch, a *A, b *B, c *C, d *D, rel .. // AddBatchFn adds the mapped components to all entities matching the given batch filter, // running the given function on each. The function can be nil. +// +// ⚠️ Do not store the obtained pointers outside of the current context! func (m *Map4[A, B, C, D]) AddBatchFn(batch *Batch, fn func(entity Entity, a *A, b *B, c *C, d *D), rel ...Relation) { m.relations = relations(rel).toRelations(m.world, m.ids, nil, m.relations) @@ -1058,6 +1090,8 @@ func (m *Map5[A, B, C, D, E]) NewEntity(a *A, b *B, c *C, d *D, e *E, rel ...Rel // NewEntityFn creates a new entity with the mapped component and runs a callback instead of using a component for initialization. // The callback can be nil. +// +// ⚠️ Do not store the obtained pointers outside of the current context! func (m *Map5[A, B, C, D, E]) NewEntityFn(fn func(a *A, b *B, c *C, d *D, e *E), rel ...Relation) Entity { m.relations = relations(rel).toRelations(m.world, m.ids, nil, m.relations) entity := m.world.newEntityWith(m.ids, nil, m.relations) @@ -1089,6 +1123,8 @@ func (m *Map5[A, B, C, D, E]) NewBatch(count int, a *A, b *B, c *C, d *D, e *E, // NewBatchFn creates a batch of new entities with the mapped components, running the given initializer function on each. // The initializer function can be nil. +// +// ⚠️ Do not store the obtained pointers outside of the current context! func (m *Map5[A, B, C, D, E]) NewBatchFn(count int, fn func(entity Entity, a *A, b *B, c *C, d *D, e *E), rel ...Relation) { m.relations = relations(rel).toRelations(m.world, m.ids, nil, m.relations) tableID, start := m.world.newEntities(count, m.ids, m.relations) @@ -1177,6 +1213,8 @@ func (m *Map5[A, B, C, D, E]) Add(entity Entity, a *A, b *B, c *C, d *D, e *E, r // AddFn adds the mapped components to the given entity and runs a callback instead of using components for initialization. // The callback can be nil. +// +// ⚠️ Do not store the obtained pointers outside of the current context! func (m *Map5[A, B, C, D, E]) AddFn(entity Entity, fn func(a *A, b *B, c *C, d *D, e *E), rel ...Relation) { m.relations = relations(rel).toRelations(m.world, m.ids, nil, m.relations) m.world.exchange(entity, m.ids, nil, nil, m.relations) @@ -1207,6 +1245,8 @@ func (m *Map5[A, B, C, D, E]) AddBatch(batch *Batch, a *A, b *B, c *C, d *D, e * // AddBatchFn adds the mapped components to all entities matching the given batch filter, // running the given function on each. The function can be nil. +// +// ⚠️ Do not store the obtained pointers outside of the current context! func (m *Map5[A, B, C, D, E]) AddBatchFn(batch *Batch, fn func(entity Entity, a *A, b *B, c *C, d *D, e *E), rel ...Relation) { m.relations = relations(rel).toRelations(m.world, m.ids, nil, m.relations) @@ -1354,6 +1394,8 @@ func (m *Map6[A, B, C, D, E, F]) NewEntity(a *A, b *B, c *C, d *D, e *E, f *F, r // NewEntityFn creates a new entity with the mapped component and runs a callback instead of using a component for initialization. // The callback can be nil. +// +// ⚠️ Do not store the obtained pointers outside of the current context! func (m *Map6[A, B, C, D, E, F]) NewEntityFn(fn func(a *A, b *B, c *C, d *D, e *E, f *F), rel ...Relation) Entity { m.relations = relations(rel).toRelations(m.world, m.ids, nil, m.relations) entity := m.world.newEntityWith(m.ids, nil, m.relations) @@ -1387,6 +1429,8 @@ func (m *Map6[A, B, C, D, E, F]) NewBatch(count int, a *A, b *B, c *C, d *D, e * // NewBatchFn creates a batch of new entities with the mapped components, running the given initializer function on each. // The initializer function can be nil. +// +// ⚠️ Do not store the obtained pointers outside of the current context! func (m *Map6[A, B, C, D, E, F]) NewBatchFn(count int, fn func(entity Entity, a *A, b *B, c *C, d *D, e *E, f *F), rel ...Relation) { m.relations = relations(rel).toRelations(m.world, m.ids, nil, m.relations) tableID, start := m.world.newEntities(count, m.ids, m.relations) @@ -1481,6 +1525,8 @@ func (m *Map6[A, B, C, D, E, F]) Add(entity Entity, a *A, b *B, c *C, d *D, e *E // AddFn adds the mapped components to the given entity and runs a callback instead of using components for initialization. // The callback can be nil. +// +// ⚠️ Do not store the obtained pointers outside of the current context! func (m *Map6[A, B, C, D, E, F]) AddFn(entity Entity, fn func(a *A, b *B, c *C, d *D, e *E, f *F), rel ...Relation) { m.relations = relations(rel).toRelations(m.world, m.ids, nil, m.relations) m.world.exchange(entity, m.ids, nil, nil, m.relations) @@ -1513,6 +1559,8 @@ func (m *Map6[A, B, C, D, E, F]) AddBatch(batch *Batch, a *A, b *B, c *C, d *D, // AddBatchFn adds the mapped components to all entities matching the given batch filter, // running the given function on each. The function can be nil. +// +// ⚠️ Do not store the obtained pointers outside of the current context! func (m *Map6[A, B, C, D, E, F]) AddBatchFn(batch *Batch, fn func(entity Entity, a *A, b *B, c *C, d *D, e *E, f *F), rel ...Relation) { m.relations = relations(rel).toRelations(m.world, m.ids, nil, m.relations) @@ -1666,6 +1714,8 @@ func (m *Map7[A, B, C, D, E, F, G]) NewEntity(a *A, b *B, c *C, d *D, e *E, f *F // NewEntityFn creates a new entity with the mapped component and runs a callback instead of using a component for initialization. // The callback can be nil. +// +// ⚠️ Do not store the obtained pointers outside of the current context! func (m *Map7[A, B, C, D, E, F, G]) NewEntityFn(fn func(a *A, b *B, c *C, d *D, e *E, f *F, g *G), rel ...Relation) Entity { m.relations = relations(rel).toRelations(m.world, m.ids, nil, m.relations) entity := m.world.newEntityWith(m.ids, nil, m.relations) @@ -1701,6 +1751,8 @@ func (m *Map7[A, B, C, D, E, F, G]) NewBatch(count int, a *A, b *B, c *C, d *D, // NewBatchFn creates a batch of new entities with the mapped components, running the given initializer function on each. // The initializer function can be nil. +// +// ⚠️ Do not store the obtained pointers outside of the current context! func (m *Map7[A, B, C, D, E, F, G]) NewBatchFn(count int, fn func(entity Entity, a *A, b *B, c *C, d *D, e *E, f *F, g *G), rel ...Relation) { m.relations = relations(rel).toRelations(m.world, m.ids, nil, m.relations) tableID, start := m.world.newEntities(count, m.ids, m.relations) @@ -1801,6 +1853,8 @@ func (m *Map7[A, B, C, D, E, F, G]) Add(entity Entity, a *A, b *B, c *C, d *D, e // AddFn adds the mapped components to the given entity and runs a callback instead of using components for initialization. // The callback can be nil. +// +// ⚠️ Do not store the obtained pointers outside of the current context! func (m *Map7[A, B, C, D, E, F, G]) AddFn(entity Entity, fn func(a *A, b *B, c *C, d *D, e *E, f *F, g *G), rel ...Relation) { m.relations = relations(rel).toRelations(m.world, m.ids, nil, m.relations) m.world.exchange(entity, m.ids, nil, nil, m.relations) @@ -1835,6 +1889,8 @@ func (m *Map7[A, B, C, D, E, F, G]) AddBatch(batch *Batch, a *A, b *B, c *C, d * // AddBatchFn adds the mapped components to all entities matching the given batch filter, // running the given function on each. The function can be nil. +// +// ⚠️ Do not store the obtained pointers outside of the current context! func (m *Map7[A, B, C, D, E, F, G]) AddBatchFn(batch *Batch, fn func(entity Entity, a *A, b *B, c *C, d *D, e *E, f *F, g *G), rel ...Relation) { m.relations = relations(rel).toRelations(m.world, m.ids, nil, m.relations) @@ -1994,6 +2050,8 @@ func (m *Map8[A, B, C, D, E, F, G, H]) NewEntity(a *A, b *B, c *C, d *D, e *E, f // NewEntityFn creates a new entity with the mapped component and runs a callback instead of using a component for initialization. // The callback can be nil. +// +// ⚠️ Do not store the obtained pointers outside of the current context! func (m *Map8[A, B, C, D, E, F, G, H]) NewEntityFn(fn func(a *A, b *B, c *C, d *D, e *E, f *F, g *G, h *H), rel ...Relation) Entity { m.relations = relations(rel).toRelations(m.world, m.ids, nil, m.relations) entity := m.world.newEntityWith(m.ids, nil, m.relations) @@ -2031,6 +2089,8 @@ func (m *Map8[A, B, C, D, E, F, G, H]) NewBatch(count int, a *A, b *B, c *C, d * // NewBatchFn creates a batch of new entities with the mapped components, running the given initializer function on each. // The initializer function can be nil. +// +// ⚠️ Do not store the obtained pointers outside of the current context! func (m *Map8[A, B, C, D, E, F, G, H]) NewBatchFn(count int, fn func(entity Entity, a *A, b *B, c *C, d *D, e *E, f *F, g *G, h *H), rel ...Relation) { m.relations = relations(rel).toRelations(m.world, m.ids, nil, m.relations) tableID, start := m.world.newEntities(count, m.ids, m.relations) @@ -2137,6 +2197,8 @@ func (m *Map8[A, B, C, D, E, F, G, H]) Add(entity Entity, a *A, b *B, c *C, d *D // AddFn adds the mapped components to the given entity and runs a callback instead of using components for initialization. // The callback can be nil. +// +// ⚠️ Do not store the obtained pointers outside of the current context! func (m *Map8[A, B, C, D, E, F, G, H]) AddFn(entity Entity, fn func(a *A, b *B, c *C, d *D, e *E, f *F, g *G, h *H), rel ...Relation) { m.relations = relations(rel).toRelations(m.world, m.ids, nil, m.relations) m.world.exchange(entity, m.ids, nil, nil, m.relations) @@ -2173,6 +2235,8 @@ func (m *Map8[A, B, C, D, E, F, G, H]) AddBatch(batch *Batch, a *A, b *B, c *C, // AddBatchFn adds the mapped components to all entities matching the given batch filter, // running the given function on each. The function can be nil. +// +// ⚠️ Do not store the obtained pointers outside of the current context! func (m *Map8[A, B, C, D, E, F, G, H]) AddBatchFn(batch *Batch, fn func(entity Entity, a *A, b *B, c *C, d *D, e *E, f *F, g *G, h *H), rel ...Relation) { m.relations = relations(rel).toRelations(m.world, m.ids, nil, m.relations) From 87384b214e9bedc21d22b9e287932891445c5eff Mon Sep 17 00:00:00 2001 From: mlange-42 Date: Sat, 8 Mar 2025 02:24:41 +0100 Subject: [PATCH 3/5] extend entity docs --- ecs/entity.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ecs/entity.go b/ecs/entity.go index 422a3f4..6646680 100644 --- a/ecs/entity.go +++ b/ecs/entity.go @@ -10,7 +10,12 @@ var entityIndexSize = sizeOf(typeOf[entityIndex]()) //var wildcard = Entity{1, 0} -// Entity identifier. +// Entity is an identifier for entities. +// +// Can be stored safely in components, resources or elsewhere. +// For stored entities, it may be necessary to check their alive status with [World.Alive]. +// +// ⚠️ Always store entities by value, never by pointer! type Entity struct { id entityID // Entity ID gen uint32 // Entity generation From 354053e90a425f00ff3eb0b7dfe2b79b31e1001f Mon Sep 17 00:00:00 2001 From: mlange-42 Date: Sat, 8 Mar 2025 02:29:14 +0100 Subject: [PATCH 4/5] add info on storing filters and maps --- ecs/exchange_gen.go | 16 ++++++++++++++++ ecs/filter_gen.go | 18 ++++++++++++++++++ ecs/generate/exchange.go.template | 2 ++ ecs/generate/filter.go.template | 2 ++ ecs/generate/maps.go.template | 2 ++ ecs/generate/query.go.template | 2 ++ ecs/map.go | 2 ++ ecs/maps_gen.go | 16 ++++++++++++++++ ecs/query_gen.go | 18 ++++++++++++++++++ 9 files changed, 78 insertions(+) diff --git a/ecs/exchange_gen.go b/ecs/exchange_gen.go index cdab050..cb9f6ef 100644 --- a/ecs/exchange_gen.go +++ b/ecs/exchange_gen.go @@ -7,6 +7,8 @@ import "unsafe" // Exchange1 allows to exchange components of entities. // It adds the given components. Use [Exchange1.Removes] // to set components to be removed. +// +// Instances should be created during initialization and stored, e.g. in systems. type Exchange1[A any] struct { world *World ids []ID @@ -173,6 +175,8 @@ func (ex *Exchange1[A]) runCallback(entity Entity, fn func(a *A)) { // Exchange2 allows to exchange components of entities. // It adds the given components. Use [Exchange2.Removes] // to set components to be removed. +// +// Instances should be created during initialization and stored, e.g. in systems. type Exchange2[A any, B any] struct { world *World ids []ID @@ -347,6 +351,8 @@ func (ex *Exchange2[A, B]) runCallback(entity Entity, fn func(a *A, b *B)) { // Exchange3 allows to exchange components of entities. // It adds the given components. Use [Exchange3.Removes] // to set components to be removed. +// +// Instances should be created during initialization and stored, e.g. in systems. type Exchange3[A any, B any, C any] struct { world *World ids []ID @@ -529,6 +535,8 @@ func (ex *Exchange3[A, B, C]) runCallback(entity Entity, fn func(a *A, b *B, c * // Exchange4 allows to exchange components of entities. // It adds the given components. Use [Exchange4.Removes] // to set components to be removed. +// +// Instances should be created during initialization and stored, e.g. in systems. type Exchange4[A any, B any, C any, D any] struct { world *World ids []ID @@ -719,6 +727,8 @@ func (ex *Exchange4[A, B, C, D]) runCallback(entity Entity, fn func(a *A, b *B, // Exchange5 allows to exchange components of entities. // It adds the given components. Use [Exchange5.Removes] // to set components to be removed. +// +// Instances should be created during initialization and stored, e.g. in systems. type Exchange5[A any, B any, C any, D any, E any] struct { world *World ids []ID @@ -917,6 +927,8 @@ func (ex *Exchange5[A, B, C, D, E]) runCallback(entity Entity, fn func(a *A, b * // Exchange6 allows to exchange components of entities. // It adds the given components. Use [Exchange6.Removes] // to set components to be removed. +// +// Instances should be created during initialization and stored, e.g. in systems. type Exchange6[A any, B any, C any, D any, E any, F any] struct { world *World ids []ID @@ -1123,6 +1135,8 @@ func (ex *Exchange6[A, B, C, D, E, F]) runCallback(entity Entity, fn func(a *A, // Exchange7 allows to exchange components of entities. // It adds the given components. Use [Exchange7.Removes] // to set components to be removed. +// +// Instances should be created during initialization and stored, e.g. in systems. type Exchange7[A any, B any, C any, D any, E any, F any, G any] struct { world *World ids []ID @@ -1337,6 +1351,8 @@ func (ex *Exchange7[A, B, C, D, E, F, G]) runCallback(entity Entity, fn func(a * // Exchange8 allows to exchange components of entities. // It adds the given components. Use [Exchange8.Removes] // to set components to be removed. +// +// Instances should be created during initialization and stored, e.g. in systems. type Exchange8[A any, B any, C any, D any, E any, F any, G any, H any] struct { world *World ids []ID diff --git a/ecs/filter_gen.go b/ecs/filter_gen.go index f1985bf..6a9e6db 100644 --- a/ecs/filter_gen.go +++ b/ecs/filter_gen.go @@ -3,6 +3,8 @@ package ecs // Code generated by go generate; DO NOT EDIT. // Filter0 is a filter for 0 components. +// +// Instances should be created during initialization and stored, e.g. in systems. type Filter0 struct { world *World ids []ID @@ -115,6 +117,8 @@ func (f *Filter0) checkCached() { } // Filter1 is a filter for 1 components. +// +// Instances should be created during initialization and stored, e.g. in systems. type Filter1[A any] struct { world *World ids []ID @@ -242,6 +246,8 @@ func (f *Filter1[A]) checkCached() { } // Filter2 is a filter for 2 components. +// +// Instances should be created during initialization and stored, e.g. in systems. type Filter2[A any, B any] struct { world *World ids []ID @@ -370,6 +376,8 @@ func (f *Filter2[A, B]) checkCached() { } // Filter3 is a filter for 3 components. +// +// Instances should be created during initialization and stored, e.g. in systems. type Filter3[A any, B any, C any] struct { world *World ids []ID @@ -499,6 +507,8 @@ func (f *Filter3[A, B, C]) checkCached() { } // Filter4 is a filter for 4 components. +// +// Instances should be created during initialization and stored, e.g. in systems. type Filter4[A any, B any, C any, D any] struct { world *World ids []ID @@ -629,6 +639,8 @@ func (f *Filter4[A, B, C, D]) checkCached() { } // Filter5 is a filter for 5 components. +// +// Instances should be created during initialization and stored, e.g. in systems. type Filter5[A any, B any, C any, D any, E any] struct { world *World ids []ID @@ -760,6 +772,8 @@ func (f *Filter5[A, B, C, D, E]) checkCached() { } // Filter6 is a filter for 6 components. +// +// Instances should be created during initialization and stored, e.g. in systems. type Filter6[A any, B any, C any, D any, E any, F any] struct { world *World ids []ID @@ -892,6 +906,8 @@ func (f *Filter6[A, B, C, D, E, F]) checkCached() { } // Filter7 is a filter for 7 components. +// +// Instances should be created during initialization and stored, e.g. in systems. type Filter7[A any, B any, C any, D any, E any, F any, G any] struct { world *World ids []ID @@ -1025,6 +1041,8 @@ func (f *Filter7[A, B, C, D, E, F, G]) checkCached() { } // Filter8 is a filter for 8 components. +// +// Instances should be created during initialization and stored, e.g. in systems. type Filter8[A any, B any, C any, D any, E any, F any, G any, H any] struct { world *World ids []ID diff --git a/ecs/generate/exchange.go.template b/ecs/generate/exchange.go.template index 091f3b6..d6c5b90 100644 --- a/ecs/generate/exchange.go.template +++ b/ecs/generate/exchange.go.template @@ -18,6 +18,8 @@ import "unsafe" // Exchange{{.}} allows to exchange components of entities. // It adds the given components. Use [Exchange{{.}}.Removes] // to set components to be removed. +// +// Instances should be created during initialization and stored, e.g. in systems. type Exchange{{.}}{{$generics}} struct { world *World ids []ID diff --git a/ecs/generate/filter.go.template b/ecs/generate/filter.go.template index 2ac6f90..e945182 100644 --- a/ecs/generate/filter.go.template +++ b/ecs/generate/filter.go.template @@ -13,6 +13,8 @@ package ecs {{- end}} // Filter{{.}} is a filter for {{.}} components. +// +// Instances should be created during initialization and stored, e.g. in systems. type Filter{{.}}{{$generics}} struct { world *World ids []ID diff --git a/ecs/generate/maps.go.template b/ecs/generate/maps.go.template index 6557188..351ac35 100644 --- a/ecs/generate/maps.go.template +++ b/ecs/generate/maps.go.template @@ -16,6 +16,8 @@ import "unsafe" {{- $mask := join "id" ", id" "" $upper -}} // Map{{.}} is a mapper to access {{.}} components of an entity. +// +// Instances should be created during initialization and stored, e.g. in systems. type Map{{.}}{{$generics}} struct { world *World ids []ID diff --git a/ecs/generate/query.go.template b/ecs/generate/query.go.template index 09b7c20..76abbb1 100644 --- a/ecs/generate/query.go.template +++ b/ecs/generate/query.go.template @@ -26,6 +26,8 @@ type cursor struct { // Query{{.}} is a query for {{.}} components. // Use a [NewFilter{{.}}] to create one. +// +// Queries are one-time use iterators and must be re-created each time before iterating. type Query{{.}}{{$generics}} struct { world *World filter *filter diff --git a/ecs/map.go b/ecs/map.go index 2a6436a..ae16564 100644 --- a/ecs/map.go +++ b/ecs/map.go @@ -3,6 +3,8 @@ package ecs import "unsafe" // Map is a mapper to access and manipulate components of an entity. +// +// Instances should be created during initialization and stored, e.g. in systems. type Map[T any] struct { world *World id ID diff --git a/ecs/maps_gen.go b/ecs/maps_gen.go index 150f611..d4a52a8 100644 --- a/ecs/maps_gen.go +++ b/ecs/maps_gen.go @@ -5,6 +5,8 @@ package ecs import "unsafe" // Map1 is a mapper to access 1 components of an entity. +// +// Instances should be created during initialization and stored, e.g. in systems. type Map1[A any] struct { world *World ids []ID @@ -241,6 +243,8 @@ func (m *Map1[A]) SetRelationsBatch(batch *Batch, fn func(entity Entity), rel .. } // Map2 is a mapper to access 2 components of an entity. +// +// Instances should be created during initialization and stored, e.g. in systems. type Map2[A any, B any] struct { world *World ids []ID @@ -493,6 +497,8 @@ func (m *Map2[A, B]) SetRelationsBatch(batch *Batch, fn func(entity Entity), rel } // Map3 is a mapper to access 3 components of an entity. +// +// Instances should be created during initialization and stored, e.g. in systems. type Map3[A any, B any, C any] struct { world *World ids []ID @@ -761,6 +767,8 @@ func (m *Map3[A, B, C]) SetRelationsBatch(batch *Batch, fn func(entity Entity), } // Map4 is a mapper to access 4 components of an entity. +// +// Instances should be created during initialization and stored, e.g. in systems. type Map4[A any, B any, C any, D any] struct { world *World ids []ID @@ -1045,6 +1053,8 @@ func (m *Map4[A, B, C, D]) SetRelationsBatch(batch *Batch, fn func(entity Entity } // Map5 is a mapper to access 5 components of an entity. +// +// Instances should be created during initialization and stored, e.g. in systems. type Map5[A any, B any, C any, D any, E any] struct { world *World ids []ID @@ -1345,6 +1355,8 @@ func (m *Map5[A, B, C, D, E]) SetRelationsBatch(batch *Batch, fn func(entity Ent } // Map6 is a mapper to access 6 components of an entity. +// +// Instances should be created during initialization and stored, e.g. in systems. type Map6[A any, B any, C any, D any, E any, F any] struct { world *World ids []ID @@ -1661,6 +1673,8 @@ func (m *Map6[A, B, C, D, E, F]) SetRelationsBatch(batch *Batch, fn func(entity } // Map7 is a mapper to access 7 components of an entity. +// +// Instances should be created during initialization and stored, e.g. in systems. type Map7[A any, B any, C any, D any, E any, F any, G any] struct { world *World ids []ID @@ -1993,6 +2007,8 @@ func (m *Map7[A, B, C, D, E, F, G]) SetRelationsBatch(batch *Batch, fn func(enti } // Map8 is a mapper to access 8 components of an entity. +// +// Instances should be created during initialization and stored, e.g. in systems. type Map8[A any, B any, C any, D any, E any, F any, G any, H any] struct { world *World ids []ID diff --git a/ecs/query_gen.go b/ecs/query_gen.go index 4e3b0bb..c93cf65 100644 --- a/ecs/query_gen.go +++ b/ecs/query_gen.go @@ -11,6 +11,8 @@ type cursor struct { // Query0 is a query for 0 components. // Use a [NewFilter0] to create one. +// +// Queries are one-time use iterators and must be re-created each time before iterating. type Query0 struct { world *World filter *filter @@ -142,6 +144,8 @@ func (q *Query0) setTable(index int, table *table) { // Query1 is a query for 1 components. // Use a [NewFilter1] to create one. +// +// Queries are one-time use iterators and must be re-created each time before iterating. type Query1[A any] struct { world *World filter *filter @@ -289,6 +293,8 @@ func (q *Query1[A]) setTable(index int, table *table) { // Query2 is a query for 2 components. // Use a [NewFilter2] to create one. +// +// Queries are one-time use iterators and must be re-created each time before iterating. type Query2[A any, B any] struct { world *World filter *filter @@ -440,6 +446,8 @@ func (q *Query2[A, B]) setTable(index int, table *table) { // Query3 is a query for 3 components. // Use a [NewFilter3] to create one. +// +// Queries are one-time use iterators and must be re-created each time before iterating. type Query3[A any, B any, C any] struct { world *World filter *filter @@ -595,6 +603,8 @@ func (q *Query3[A, B, C]) setTable(index int, table *table) { // Query4 is a query for 4 components. // Use a [NewFilter4] to create one. +// +// Queries are one-time use iterators and must be re-created each time before iterating. type Query4[A any, B any, C any, D any] struct { world *World filter *filter @@ -754,6 +764,8 @@ func (q *Query4[A, B, C, D]) setTable(index int, table *table) { // Query5 is a query for 5 components. // Use a [NewFilter5] to create one. +// +// Queries are one-time use iterators and must be re-created each time before iterating. type Query5[A any, B any, C any, D any, E any] struct { world *World filter *filter @@ -917,6 +929,8 @@ func (q *Query5[A, B, C, D, E]) setTable(index int, table *table) { // Query6 is a query for 6 components. // Use a [NewFilter6] to create one. +// +// Queries are one-time use iterators and must be re-created each time before iterating. type Query6[A any, B any, C any, D any, E any, F any] struct { world *World filter *filter @@ -1084,6 +1098,8 @@ func (q *Query6[A, B, C, D, E, F]) setTable(index int, table *table) { // Query7 is a query for 7 components. // Use a [NewFilter7] to create one. +// +// Queries are one-time use iterators and must be re-created each time before iterating. type Query7[A any, B any, C any, D any, E any, F any, G any] struct { world *World filter *filter @@ -1255,6 +1271,8 @@ func (q *Query7[A, B, C, D, E, F, G]) setTable(index int, table *table) { // Query8 is a query for 8 components. // Use a [NewFilter8] to create one. +// +// Queries are one-time use iterators and must be re-created each time before iterating. type Query8[A any, B any, C any, D any, E any, F any, G any, H any] struct { world *World filter *filter From fbc3f1808b5e131e9bf2342d8c070ac2c752d86f Mon Sep 17 00:00:00 2001 From: mlange-42 Date: Sat, 8 Mar 2025 02:31:08 +0100 Subject: [PATCH 5/5] fix wording --- ecs/generate/query.go.template | 2 +- ecs/query.go | 2 +- ecs/query_gen.go | 18 +++++++++--------- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/ecs/generate/query.go.template b/ecs/generate/query.go.template index 76abbb1..65c79fd 100644 --- a/ecs/generate/query.go.template +++ b/ecs/generate/query.go.template @@ -100,7 +100,7 @@ func (q *Query{{.}}{{$genericsShort}}) GetRelation(index int) Entity { // Close closes the Query and unlocks the world. // -// Automatically called when iteration finishes. +// Automatically called when iteration completes. // Needs to be called only if breaking out of the query iteration or not iterating at all. func (q *Query{{.}}{{$genericsShort}}) Close() { q.cursor.archetype = -2 diff --git a/ecs/query.go b/ecs/query.go index 5865f3c..15bad6c 100644 --- a/ecs/query.go +++ b/ecs/query.go @@ -98,7 +98,7 @@ func (q *Query) IDs() IDs { // Close closes the Query and unlocks the world. // -// Automatically called when iteration finishes. +// Automatically called when iteration completes. // Needs to be called only if breaking out of the query iteration or not iterating at all. func (q *Query) Close() { q.cursor.archetype = -2 diff --git a/ecs/query_gen.go b/ecs/query_gen.go index c93cf65..209aebc 100644 --- a/ecs/query_gen.go +++ b/ecs/query_gen.go @@ -66,7 +66,7 @@ func (q *Query0) Entity() Entity { // Close closes the Query and unlocks the world. // -// Automatically called when iteration finishes. +// Automatically called when iteration completes. // Needs to be called only if breaking out of the query iteration or not iterating at all. func (q *Query0) Close() { q.cursor.archetype = -2 @@ -213,7 +213,7 @@ func (q *Query1[A]) GetRelation(index int) Entity { // Close closes the Query and unlocks the world. // -// Automatically called when iteration finishes. +// Automatically called when iteration completes. // Needs to be called only if breaking out of the query iteration or not iterating at all. func (q *Query1[A]) Close() { q.cursor.archetype = -2 @@ -364,7 +364,7 @@ func (q *Query2[A, B]) GetRelation(index int) Entity { // Close closes the Query and unlocks the world. // -// Automatically called when iteration finishes. +// Automatically called when iteration completes. // Needs to be called only if breaking out of the query iteration or not iterating at all. func (q *Query2[A, B]) Close() { q.cursor.archetype = -2 @@ -519,7 +519,7 @@ func (q *Query3[A, B, C]) GetRelation(index int) Entity { // Close closes the Query and unlocks the world. // -// Automatically called when iteration finishes. +// Automatically called when iteration completes. // Needs to be called only if breaking out of the query iteration or not iterating at all. func (q *Query3[A, B, C]) Close() { q.cursor.archetype = -2 @@ -678,7 +678,7 @@ func (q *Query4[A, B, C, D]) GetRelation(index int) Entity { // Close closes the Query and unlocks the world. // -// Automatically called when iteration finishes. +// Automatically called when iteration completes. // Needs to be called only if breaking out of the query iteration or not iterating at all. func (q *Query4[A, B, C, D]) Close() { q.cursor.archetype = -2 @@ -841,7 +841,7 @@ func (q *Query5[A, B, C, D, E]) GetRelation(index int) Entity { // Close closes the Query and unlocks the world. // -// Automatically called when iteration finishes. +// Automatically called when iteration completes. // Needs to be called only if breaking out of the query iteration or not iterating at all. func (q *Query5[A, B, C, D, E]) Close() { q.cursor.archetype = -2 @@ -1008,7 +1008,7 @@ func (q *Query6[A, B, C, D, E, F]) GetRelation(index int) Entity { // Close closes the Query and unlocks the world. // -// Automatically called when iteration finishes. +// Automatically called when iteration completes. // Needs to be called only if breaking out of the query iteration or not iterating at all. func (q *Query6[A, B, C, D, E, F]) Close() { q.cursor.archetype = -2 @@ -1179,7 +1179,7 @@ func (q *Query7[A, B, C, D, E, F, G]) GetRelation(index int) Entity { // Close closes the Query and unlocks the world. // -// Automatically called when iteration finishes. +// Automatically called when iteration completes. // Needs to be called only if breaking out of the query iteration or not iterating at all. func (q *Query7[A, B, C, D, E, F, G]) Close() { q.cursor.archetype = -2 @@ -1354,7 +1354,7 @@ func (q *Query8[A, B, C, D, E, F, G, H]) GetRelation(index int) Entity { // Close closes the Query and unlocks the world. // -// Automatically called when iteration finishes. +// Automatically called when iteration completes. // Needs to be called only if breaking out of the query iteration or not iterating at all. func (q *Query8[A, B, C, D, E, F, G, H]) Close() { q.cursor.archetype = -2