forked from SanderMertens/flecs
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathflecs.c
More file actions
22194 lines (18489 loc) · 613 KB
/
flecs.c
File metadata and controls
22194 lines (18489 loc) · 613 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#include "flecs.h"
#ifndef FLECS_PRIVATE_H
#define FLECS_PRIVATE_H
#ifndef FLECS_TYPES_PRIVATE_H
#define FLECS_TYPES_PRIVATE_H
#ifndef __MACH__
#ifndef _POSIX_C_SOURCE
#define _POSIX_C_SOURCE 200809L
#endif
#endif
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <stdarg.h>
#include <stdio.h>
#include <time.h>
#include <ctype.h>
#include <math.h>
#ifdef _MSC_VER
//FIXME
#else
#include <sys/param.h> /* attempt to define endianness */
#endif
#ifdef linux
# include <endian.h> /* attempt to define endianness */
#endif
#ifndef FLECS_ENTITY_INDEX_H
#define FLECS_ENTITY_INDEX_H
#ifdef __cplusplus
extern "C" {
#endif
struct ecs_record_t {
ecs_table_t *table; /* Identifies a type (and table) in world */
int32_t row; /* Table row of the entity */
};
#define ecs_eis_get(world, entity) ecs_sparse_get_sparse((world->store).entity_index, ecs_record_t, entity)
#define ecs_eis_get_any(world, entity) ecs_sparse_get_sparse_any((world->store).entity_index, ecs_record_t, entity)
#define ecs_eis_set(world, entity, ...) (ecs_sparse_set((world->store).entity_index, ecs_record_t, entity, (__VA_ARGS__)))
#define ecs_eis_get_or_create(world, entity) ecs_sparse_get_or_create((world->store).entity_index, ecs_record_t, entity)
#define ecs_eis_delete(world, entity) ecs_sparse_remove((world->store).entity_index, entity)
#define ecs_eis_set_generation(world, entity) ecs_sparse_set_generation((world->store).entity_index, entity)
#define ecs_eis_is_alive(world, entity) ecs_sparse_is_alive((world->store).entity_index, entity)
#define ecs_eis_exists(world, entity) ecs_sparse_exists((world->store).entity_index, entity)
#define ecs_eis_recycle(world) ecs_sparse_new_id((world->store).entity_index)
#define ecs_eis_clear_entity(world, entity, is_watched) ecs_eis_set((world->store).entity_index, entity, &(ecs_record_t){NULL, is_watched})
#define ecs_eis_grow(world, count) ecs_sparse_grow((world->store).entity_index, count)
#define ecs_eis_set_size(world, size) ecs_sparse_set_size((world->store).entity_index, size)
#define ecs_eis_count(world) ecs_sparse_count((world->store).entity_index)
#define ecs_eis_clear(world) ecs_sparse_clear((world->store).entity_index)
#define ecs_eis_copy(world) ecs_sparse_copy((world->store).entity_index)
#define ecs_eis_free(world) ecs_sparse_free((world->store).entity_index)
#define ecs_eis_memory(world, allocd, used) ecs_sparse_memory((world->store).entity_index, allocd, used)
#ifdef __cplusplus
}
#endif
#endif
#ifndef FLECS_TABLE_H_
#define FLECS_TABLE_H_
#ifdef __cplusplus
extern "C" {
#endif
/** Find or create table for a set of components */
ecs_table_t* ecs_table_find_or_create(
ecs_world_t *world,
ecs_entities_t *type);
/** Find or create table for a type */
ecs_table_t* ecs_table_from_type(
ecs_world_t *world,
ecs_type_t type);
/* Get table data */
ecs_data_t *ecs_table_get_data(
ecs_table_t *table);
/* Get or create data */
ecs_data_t *ecs_table_get_or_create_data(
ecs_table_t *table);
/* Activates / deactivates table for systems. A deactivated table will not be
* evaluated when the system is invoked. Tables automatically get activated /
* deactivated when they become non-empty / empty.
*
* If a query is provided, the table will only be activated / deactivated for
* that query. */
void ecs_table_activate(
ecs_world_t *world,
ecs_table_t *table,
ecs_query_t *query,
bool activate);
/* Clear all entities from a table. */
void ecs_table_clear(
ecs_world_t *world,
ecs_table_t *table);
/* Reset a table to its initial state */
void ecs_table_reset(
ecs_world_t *world,
ecs_table_t *table);
/* Clear all entities from the table. Do not invoke OnRemove systems */
void ecs_table_clear_silent(
ecs_world_t *world,
ecs_table_t *table);
/* Clear table data. Don't call OnRemove handlers. */
void ecs_table_clear_data(
ecs_table_t *table,
ecs_data_t *data);
/* Return number of entities in table. */
int32_t ecs_table_count(
ecs_table_t *table);
/* Return number of entities in data */
int32_t ecs_table_data_count(
ecs_data_t *data);
/* Add a new entry to the table for the specified entity */
int32_t ecs_table_append(
ecs_world_t *world,
ecs_table_t *table,
ecs_data_t *data,
ecs_entity_t entity,
ecs_record_t *record,
bool construct);
/* Delete an entity from the table. */
void ecs_table_delete(
ecs_world_t *world,
ecs_table_t *table,
ecs_data_t *data,
int32_t index,
bool destruct);
/* Move a row from one table to another */
void ecs_table_move(
ecs_world_t *world,
ecs_entity_t dst_entity,
ecs_entity_t src_entity,
ecs_table_t *new_table,
ecs_data_t *new_data,
int32_t new_index,
ecs_table_t *old_table,
ecs_data_t *old_data,
int32_t old_index);
/* Grow table with specified number of records. Populate table with entities,
* starting from specified entity id. */
int32_t ecs_table_appendn(
ecs_world_t *world,
ecs_table_t *table,
ecs_data_t *data,
int32_t count,
const ecs_entity_t *ids);
/* Set table to a fixed size. Useful for preallocating memory in advance. */
void ecs_table_set_size(
ecs_world_t *world,
ecs_table_t *table,
ecs_data_t *data,
int32_t count);
/* Set table to a fixed count. Useful for copying data in bulk. */
void ecs_table_set_count(
ecs_world_t *world,
ecs_table_t *table,
ecs_data_t *data,
int32_t count);
/* Match table with filter */
bool ecs_table_match_filter(
ecs_world_t *world,
ecs_table_t *table,
const ecs_filter_t *filter);
/* Get dirty state for table columns */
int32_t* ecs_table_get_dirty_state(
ecs_table_t *table);
/* Get monitor for monitoring table changes */
int32_t* ecs_table_get_monitor(
ecs_table_t *table);
#ifdef __cplusplus
}
#endif
#endif
#define ECS_MAX_JOBS_PER_WORKER (16)
/** Entity id's higher than this number will be stored in a map instead of a
* sparse set. Increasing this value can improve performance at the cost of
* (significantly) higher memory usage. */
#define ECS_HI_ENTITY_ID (1000000)
/** These values are used to verify validity of the pointers passed into the API
* and to allow for passing a thread as a world to some API calls (this allows
* for transparently passing thread context to API functions) */
#define ECS_WORLD_MAGIC (0x65637377)
#define ECS_THREAD_MAGIC (0x65637374)
/* Maximum number of entities that can be added in a single operation.
* Increasing this value will increase consumption of stack space. */
#define ECS_MAX_ADD_REMOVE (32)
/* Maximum length of an entity name, including 0 terminator */
#define ECS_MAX_NAME_LENGTH (64)
/* Simple bitmask structure to store a set of components. This is used amongst
* others to keep track of which components have been overridden from a base. */
typedef struct ecs_comp_set_t {
int32_t hi_count;
ecs_entity_t hi_array[ECS_MAX_ADD_REMOVE];
ecs_entity_t lo_mask[ECS_HI_COMPONENT_ID / 64];
} ecs_comp_set_t;
/** Callback used by the system signature expression parser. */
typedef int (*ecs_parse_action_t)(
ecs_world_t *world,
const char *id,
const char *expr,
int64_t column,
ecs_sig_from_kind_t from_kind,
ecs_sig_oper_kind_t oper_kind,
ecs_sig_inout_kind_t inout_kind,
ecs_entity_t flags,
const char *component,
const char *source,
const char *trait,
const char *name,
void *ctx);
/** Component-specific data */
typedef struct ecs_c_info_t {
ecs_entity_t component;
ecs_vector_t *on_add; /* Systems ran after adding this component */
ecs_vector_t *on_remove; /* Systems ran after removing this component */
EcsComponentLifecycle lifecycle; /* Component lifecycle callbacks */
bool lifecycle_set;
} ecs_c_info_t;
/* Table event type for notifying tables of world events */
typedef enum ecs_table_eventkind_t {
EcsTableQueryMatch,
EcsTableQueryUnmatch,
EcsTableComponentInfo
} ecs_table_eventkind_t;
typedef struct ecs_table_event_t {
ecs_table_eventkind_t kind;
/* Query event */
ecs_query_t *query;
int32_t matched_table_index;
/* Component info event */
ecs_entity_t component;
/* If the nubmer of fields gets out of hand, this can be turned into a union
* but since events are very temporary objects, this works for now and makes
* initializing an event a bit simpler. */
} ecs_table_event_t;
/** A component column. */
struct ecs_column_t {
ecs_vector_t *data; /**< Column data */
int16_t size; /**< Column element size */
int16_t alignment; /**< Column element alignment */
};
/** A switch column. */
typedef struct ecs_sw_column_t {
ecs_switch_t *data; /**< Column data */
ecs_type_t type; /**< Switch type */
} ecs_sw_column_t;
/** Stage-specific component data */
struct ecs_data_t {
ecs_vector_t *entities; /**< Entity identifiers */
ecs_vector_t *record_ptrs; /**< Ptrs to records in main entity index */
ecs_column_t *columns; /**< Component columns */
ecs_sw_column_t *sw_columns; /**< Switch columns */
bool marked_dirty; /**< Was table marked dirty by stage? */
};
/** Small footprint data structure for storing data associated with a table. */
typedef struct ecs_table_leaf_t {
ecs_table_t *table;
ecs_type_t type;
ecs_data_t *data;
} ecs_table_leaf_t;
/** Flags for quickly checking for special properties of a table. */
#define EcsTableHasBuiltins 1u /**< Does table have builtin components */
#define EcsTableIsPrefab 2u /**< Does the table store prefabs */
#define EcsTableHasBase 4u /**< Does the table type has INSTANCEOF */
#define EcsTableHasParent 8u /**< Does the table type has CHILDOF */
#define EcsTableHasComponentData 16u /**< Does the table have component data */
#define EcsTableHasXor 32u /**< Does the table type has XOR */
#define EcsTableIsDisabled 64u /**< Does the table type has EcsDisabled */
#define EcsTableHasCtors 128u
#define EcsTableHasDtors 256u
#define EcsTableHasCopy 512u
#define EcsTableHasMove 1024u
#define EcsTableHasOnAdd 2048u
#define EcsTableHasOnRemove 4096u
#define EcsTableHasOnSet 8192u
#define EcsTableHasUnSet 16384u
#define EcsTableHasMonitors 32768u
#define EcsTableHasSwitch 65536u
/* Composite constants */
#define EcsTableHasLifecycle (EcsTableHasCtors | EcsTableHasDtors)
#define EcsTableIsComplex (EcsTableHasLifecycle | EcsTableHasSwitch)
#define EcsTableHasAddActions (EcsTableHasBase | EcsTableHasSwitch | EcsTableHasCtors | EcsTableHasOnAdd | EcsTableHasOnSet | EcsTableHasMonitors)
#define EcsTableHasRemoveActions (EcsTableHasBase | EcsTableHasDtors | EcsTableHasOnRemove | EcsTableHasUnSet | EcsTableHasMonitors)
/** Edge used for traversing the table graph. */
typedef struct ecs_edge_t {
ecs_table_t *add; /**< Edges traversed when adding */
ecs_table_t *remove; /**< Edges traversed when removing */
} ecs_edge_t;
/** Quey matched with table with backref to query table administration.
* This type is used to store a matched query together with the array index of
* where the table is stored in the query administration. This type is used when
* an action that originates on a table needs to invoke a query (system) and a
* fast lookup is required for the query administration, as is the case with
* OnSet and Monitor systems. */
typedef struct ecs_matched_query_t {
ecs_query_t *query; /**< The query matched with the table */
int32_t matched_table_index; /**< Table index in the query type */
} ecs_matched_query_t;
/** A table is the Flecs equivalent of an archetype. Tables store all entities
* with a specific set of components. Tables are automatically created when an
* entity has a set of components not previously observed before. When a new
* table is created, it is automatically matched with existing column systems */
struct ecs_table_t {
ecs_type_t type; /**< Identifies table type in type_index */
ecs_c_info_t **c_info; /**< Cached pointers to component info */
ecs_edge_t *lo_edges; /**< Edges to low entity ids */
ecs_map_t *hi_edges; /**< Edges to high entity ids */
ecs_data_t *data; /**< Data storage */
ecs_vector_t *queries; /**< Queries matched with table */
ecs_vector_t *monitors; /**< Monitor systems matched with table */
ecs_vector_t **on_set; /**< OnSet systems, broken up by column */
ecs_vector_t *on_set_all; /**< All OnSet systems */
ecs_vector_t *on_set_override; /**< All OnSet systems with overrides */
ecs_vector_t *un_set_all; /**< All OnSet systems */
int32_t *dirty_state; /**< Keep track of changes in columns */
int32_t alloc_count; /**< Increases when columns are reallocd */
uint32_t id; /**< Table id in sparse set */
ecs_flags32_t flags; /**< Flags for testing table properties */
int32_t column_count; /**< Number of data columns in table */
int32_t sw_column_count;
int32_t sw_column_offset;
};
/* Sparse query column */
typedef struct ecs_sparse_column_t {
ecs_sw_column_t *sw_column;
ecs_entity_t sw_case;
int32_t signature_column_index;
} ecs_sparse_column_t;
/** Type containing data for a table matched with a query. */
typedef struct ecs_matched_table_t {
ecs_iter_table_t data; /**< Precomputed data for iterators */
ecs_vector_t *sparse_columns; /**< Column ids of sparse columns */
int32_t *monitor; /**< Used to monitor table for changes */
int32_t rank; /**< Rank used to sort tables */
} ecs_matched_table_t;
/** Type storing an entity range within a table.
* This type is used for iterating in orer across archetypes. A sorting function
* constructs a list of the ranges across archetypes that are in order so that
* when the query iterates over the archetypes, it only needs to iterate the
* list of ranges. */
typedef struct ecs_table_slice_t {
ecs_matched_table_t *table; /**< Reference to the matched table */
int32_t start_row; /**< Start of range */
int32_t count; /**< Number of entities in range */
} ecs_table_slice_t;
#define EcsQueryNeedsTables (1) /* Query needs matching with tables */
#define EcsQueryMonitor (2) /* Query needs to be registered as a monitor */
#define EcsQueryOnSet (4) /* Query needs to be registered as on_set system */
#define EcsQueryUnSet (8) /* Query needs to be registered as un_set system */
#define EcsQueryMatchDisabled (16) /* Does query match disabled */
#define EcsQueryMatchPrefab (32) /* Does query match prefabs */
#define EcsQueryHasRefs (64) /* Does query have references */
#define EcsQueryHasTraits (128) /* Does query have traits */
#define EcsQueryIsSubquery (256) /* Is query a subquery */
#define EcsQueryHasOutColumns (512) /* Does query have out columns */
#define EcsQueryHasOptional (1024) /* Does query have optional columns */
#define EcsQueryNoActivation (EcsQueryMonitor | EcsQueryOnSet | EcsQueryUnSet)
/* Query event type for notifying queries of world events */
typedef enum ecs_query_eventkind_t {
EcsQueryTableMatch,
EcsQueryTableEmpty,
EcsQueryTableNonEmpty,
EcsQueryTableRematch,
EcsQueryTableUnmatch
} ecs_query_eventkind_t;
typedef struct ecs_query_event_t {
ecs_query_eventkind_t kind;
ecs_table_t *table;
ecs_query_t *parent_query;
} ecs_query_event_t;
/** Query that is automatically matched against active tables */
struct ecs_query_t {
/* Signature of query */
ecs_sig_t sig;
/* Reference to world */
ecs_world_t *world;
/* Tables matched with query */
ecs_vector_t *tables;
ecs_vector_t *empty_tables;
/* Handle to system (optional) */
ecs_entity_t system;
/* Used for sorting */
ecs_entity_t sort_on_component;
ecs_compare_action_t compare;
ecs_vector_t *table_slices;
/* Used for table sorting */
ecs_entity_t rank_on_component;
ecs_rank_type_action_t group_table;
/* Subqueries */
ecs_vector_t *subqueries;
/* The query kind determines how it is registered with tables */
ecs_flags32_t flags;
int32_t cascade_by; /* Identify CASCADE column */
int32_t match_count; /* How often have tables been (un)matched */
int32_t prev_match_count; /* Used to track if sorting is needed */
};
/** Keep track of how many [in] columns are active for [out] columns of OnDemand
* systems. */
typedef struct ecs_on_demand_out_t {
ecs_entity_t system; /* Handle to system */
int32_t count; /* Total number of times [out] columns are used */
} ecs_on_demand_out_t;
/** Keep track of which OnDemand systems are matched with which [in] columns */
typedef struct ecs_on_demand_in_t {
int32_t count; /* Number of active systems with [in] column */
ecs_vector_t *systems; /* Systems that have this column as [out] column */
} ecs_on_demand_in_t;
/** Types for deferred operations */
typedef enum ecs_op_kind_t {
EcsOpNone,
EcsOpNew,
EcsOpClone,
EcsOpBulkNew,
EcsOpAdd,
EcsOpRemove,
EcsOpSet,
EcsOpMut,
EcsOpModified,
EcsOpDelete,
EcsOpClear
} ecs_op_kind_t;
typedef struct ecs_op_1_t {
ecs_entity_t entity; /* Entity id */
void *value; /* Value (used for set / get_mut) */
ecs_size_t size; /* Size of value */
bool clone_value; /* Clone entity with value (used for clone) */
} ecs_op_1_t;
typedef struct ecs_op_n_t {
ecs_entity_t *entities;
void **bulk_data;
int32_t count;
} ecs_op_n_t;
typedef struct ecs_op_t {
ecs_op_kind_t kind; /* Operation kind */
ecs_entity_t scope; /* Scope of operation (for new) */
ecs_entity_t component; /* Single component (components.count = 1) */
ecs_entities_t components; /* Multiple components */
union {
ecs_op_1_t _1;
ecs_op_n_t _n;
} is;
} ecs_op_t;
/** A stage is a data structure in which delta's are stored until it is safe to
* merge those delta's with the main world stage. A stage allows flecs systems
* to arbitrarily add/remove/set components and create/delete entities while
* iterating. Additionally, worker threads have their own stage that lets them
* mutate the state of entities without requiring locks. */
struct ecs_stage_t {
/* This points to the world pointer associated with the stage. Even though
* stages belong to the same world, when multithreaded, an application will
* receive a pointer not to the world, but to a thread. This allows for
* transparently passing the thread context without having to fallback on
* more expensive methods such as thread local storage. This world pointer
* is stored in the stage, so that it can be easily passed around when for
* example invoking callbacks, and prevents the API from passing around two
* world pointers (or constantly obtaining the real world when needed). */
ecs_world_t *world;
int32_t id; /* Unique id that identifies the stage */
/* Are operations deferred? */
int32_t defer;
ecs_vector_t *defer_queue;
ecs_vector_t *defer_merge_queue;
/* One-shot actions to be executed after the merge */
ecs_vector_t *post_frame_actions;
/* Namespacing */
ecs_table_t *scope_table; /* Table for current scope */
ecs_entity_t scope; /* Entity of current scope */
/* If a system is progressing it will set this field to its columns. This
* will be used in debug mode to verify that a system is not doing
* unanounced adding/removing of components, as this could cause
* unpredictable behavior during a merge. */
#ifndef NDEBUG
ecs_entity_t system;
ecs_vector_t *system_columns;
#endif
};
typedef struct ecs_store_t {
/* Entity lookup table for (table, row) */
ecs_sparse_t *entity_index;
/* Table graph */
ecs_sparse_t *tables;
ecs_table_t root;
} ecs_store_t;
/** Supporting type to store looked up or derived entity data */
typedef struct ecs_entity_info_t {
ecs_record_t *record; /* Main stage record in entity index */
ecs_table_t *table; /* Table. Not set if entity is empty */
ecs_data_t *data; /* Stage-specific table columns */
int32_t row; /* Actual row (stripped from is_watched bit) */
bool is_watched; /* Is entity being watched */
} ecs_entity_info_t;
/** A type desribing a worker thread. When a system is invoked by a worker
* thread, it receives a pointer to an ecs_thread_t instead of a pointer to an
* ecs_world_t (provided by the ecs_iter_t type). When this ecs_thread_t is passed down
* into the flecs API, the API functions are able to tell whether this is an
* ecs_thread_t or an ecs_world_t by looking at the 'magic' number. This allows the
* API to transparently resolve the stage to which updates should be written,
* without requiring different API calls when working in multi threaded mode. */
typedef struct ecs_thread_t {
int32_t magic; /* Magic number to verify thread pointer */
ecs_world_t *world; /* Reference to world */
ecs_stage_t *stage; /* Stage for thread */
ecs_os_thread_t thread; /* Thread handle */
int32_t index; /* Index of thread */
} ecs_thread_t;
/** Supporting type to store looked up component data in specific table */
typedef struct ecs_column_info_t {
ecs_entity_t id;
ecs_c_info_t *ci;
int32_t column;
} ecs_column_info_t;
/* Component monitors */
typedef struct ecs_component_monitor_t {
bool dirty_flags[ECS_HI_COMPONENT_ID];
ecs_vector_t *monitors[ECS_HI_COMPONENT_ID];
bool rematch;
} ecs_component_monitor_t;
/* fini actions */
typedef struct ecs_action_elem_t {
ecs_fini_action_t action;
void *ctx;
} ecs_action_elem_t;
/* Alias */
typedef struct ecs_alias_t {
char *name;
ecs_entity_t entity;
} ecs_alias_t;
/** The world stores and manages all ECS data. An application can have more than
* one world, but data is not shared between worlds. */
struct ecs_world_t {
int32_t magic; /* Magic number to verify world pointer */
void *context; /* Application context */
ecs_vector_t *fini_actions; /* Callbacks to execute when world exits */
ecs_c_info_t c_info[ECS_HI_COMPONENT_ID]; /* Component callbacks & triggers */
ecs_map_t *t_info; /* Tag triggers */
/* Is entity range checking enabled? */
bool range_check_enabled;
/* -- Data storage -- */
ecs_store_t store;
/* -- Queries -- */
/* Persistent queries registered with the world. Persistent queries are
* stateful and automatically matched with existing and new tables. */
ecs_vector_t *queries;
/* Keep track of components that were added/removed to/from monitored
* entities. Monitored entities are entities that a query has matched with
* specifically, as is the case with PARENT / CASCADE columns, FromEntity
* columns and columns matched from prefabs.
* When these entities change type, queries may have to be rematched.
* Queries register themselves as component monitors for specific components
* and when these components change they are rematched. The component
* monitors are evaluated during a merge. */
ecs_component_monitor_t component_monitors;
/* Parent monitors are like normal component monitors except that the
* conditions under which a parent component is flagged dirty is different.
* Parent component flags are marked dirty when an entity that is a parent
* adds or removes a CHILDOF flag. In that case, every component of that
* parent will be marked dirty. This allows column modifiers like CASCADE
* to correctly determine when the depth ranking of a table has changed. */
ecs_component_monitor_t parent_monitors;
/* -- Systems -- */
ecs_entity_t pipeline; /* Current pipeline */
ecs_map_t *on_activate_components; /* Trigger on activate of [in] column */
ecs_map_t *on_enable_components; /* Trigger on enable of [in] column */
ecs_vector_t *fini_tasks; /* Tasks to execute on ecs_fini */
/* -- Lookup Indices -- */
ecs_map_t *type_handles; /* Handles to named types */
/* -- Aliasses -- */
ecs_vector_t *aliases;
/* -- Staging -- */
ecs_stage_t stage; /* Main storage */
ecs_stage_t temp_stage; /* Stage for when processing systems */
ecs_vector_t *worker_stages; /* Stages for worker threads */
int32_t stage_count; /* Number of stages in world */
/* -- Hierarchy administration -- */
ecs_map_t *child_tables; /* Child tables per parent entity */
const char *name_prefix; /* Remove prefix from C names in modules */
/* -- Multithreading -- */
ecs_vector_t *workers; /* Worker threads */
ecs_os_cond_t worker_cond; /* Signal that worker threads can start */
ecs_os_cond_t sync_cond; /* Signal that worker thread job is done */
ecs_os_mutex_t sync_mutex; /* Mutex for job_cond */
int32_t workers_running; /* Number of threads running */
int32_t workers_waiting; /* Number of workers waiting on sync */
/* -- Time management -- */
ecs_time_t world_start_time; /* Timestamp of simulation start */
ecs_time_t frame_start_time; /* Timestamp of frame start */
float fps_sleep; /* Sleep time to prevent fps overshoot */
/* -- Metrics -- */
ecs_world_info_t stats;
/* -- Settings from command line arguments -- */
int arg_fps;
int arg_threads;
/* -- World lock -- */
ecs_os_mutex_t mutex; /* Locks the world if locking enabled */
ecs_os_mutex_t thr_sync; /* Used to signal threads at end of frame */
ecs_os_cond_t thr_cond; /* Used to signal threads at end of frame */
/* -- World state -- */
bool valid_schedule; /* Is job schedule still valid */
bool quit_workers; /* Signals worker threads to quit */
bool in_progress; /* Is world being progressed */
bool is_merging; /* Is world currently being merged */
bool auto_merge; /* Are stages auto-merged by ecs_progress */
bool measure_frame_time; /* Time spent on each frame */
bool measure_system_time; /* Time spent by each system */
bool should_quit; /* Did a system signal that app should quit */
bool locking_enabled; /* Lock world when in progress */
};
#endif
////////////////////////////////////////////////////////////////////////////////
//// Core bootstrap functions
////////////////////////////////////////////////////////////////////////////////
#define ECS_TYPE_DECL(component)\
static const ecs_entity_t __##component = ecs_entity(component);\
ECS_VECTOR_DECL(FLECS__T##component, ecs_entity_t, 1)
#define ECS_TYPE_IMPL(component)\
ECS_VECTOR_IMPL(FLECS__T##component, ecs_entity_t, &__##component, 1)
/* Bootstrap world */
void ecs_bootstrap(
ecs_world_t *world);
ecs_type_t ecs_bootstrap_type(
ecs_world_t *world,
ecs_entity_t entity);
#define ecs_bootstrap_component(world, name)\
ecs_new_component(world, ecs_entity(name), #name, sizeof(name), ECS_ALIGNOF(name))
#define ecs_bootstrap_tag(world, name)\
ecs_set(world, name, EcsName, {.value = &#name[ecs_os_strlen("Ecs")], .symbol = #name});\
ecs_add_entity(world, name, ECS_CHILDOF | ecs_get_scope(world))
////////////////////////////////////////////////////////////////////////////////
//// Entity API
////////////////////////////////////////////////////////////////////////////////
/* Mark an entity as being watched. This is used to trigger automatic rematching
* when entities used in system expressions change their components. */
void ecs_set_watch(
ecs_world_t *world,
ecs_entity_t entity);
/* Does one of the entity containers has specified component */
ecs_entity_t ecs_find_in_type(
ecs_world_t *world,
ecs_type_t table_type,
ecs_entity_t component,
ecs_entity_t flags);
/* Obtain entity info */
bool ecs_get_info(
ecs_world_t *world,
ecs_entity_t entity,
ecs_entity_info_t *info);
void ecs_run_monitors(
ecs_world_t *world,
ecs_table_t *dst_table,
ecs_vector_t *v_dst_monitors,
int32_t dst_row,
int32_t count,
ecs_vector_t *v_src_monitors);
////////////////////////////////////////////////////////////////////////////////
//// World API
////////////////////////////////////////////////////////////////////////////////
/* Notify systems that there is a new table, which triggers matching */
void ecs_notify_queries_of_table(
ecs_world_t *world,
ecs_table_t *table);
/* Get current thread-specific stage */
ecs_stage_t *ecs_get_stage(
ecs_world_t **world_ptr);
/* Get component callbacks */
ecs_c_info_t *ecs_get_c_info(
ecs_world_t *world,
ecs_entity_t component);
/* Get or create component callbacks */
ecs_c_info_t * ecs_get_or_create_c_info(
ecs_world_t *world,
ecs_entity_t component);
void ecs_eval_component_monitors(
ecs_world_t *world);
void ecs_component_monitor_mark(
ecs_component_monitor_t *mon,
ecs_entity_t component);
void ecs_component_monitor_register(
ecs_component_monitor_t *mon,
ecs_entity_t component,
ecs_query_t *query);
bool ecs_defer_op_begin(
ecs_world_t *world,
ecs_stage_t *stage,
ecs_op_kind_t op_kind,
ecs_entity_t entity,
ecs_entities_t *components,
const void *value,
ecs_size_t size);
void ecs_defer_flush(
ecs_world_t *world,
ecs_stage_t *stage);
void ecs_measure_frame_time(
ecs_world_t *world,
bool enable);
void ecs_measure_system_time(
ecs_world_t *world,
bool enable);
void ecs_notify_tables(
ecs_world_t *world,
ecs_table_event_t *event);
void ecs_notify_queries(
ecs_world_t *world,
ecs_query_event_t *event);
////////////////////////////////////////////////////////////////////////////////
//// Stage API
////////////////////////////////////////////////////////////////////////////////
/* Initialize stage data structures */
void ecs_stage_init(
ecs_world_t *world,
ecs_stage_t *stage);
/* Deinitialize stage */
void ecs_stage_deinit(
ecs_world_t *world,
ecs_stage_t *stage);
/* Merge stage with main stage */
void ecs_stage_merge(
ecs_world_t *world,
ecs_stage_t *stage);
/* Post-frame merge actions */
void ecs_stage_merge_post_frame(
ecs_world_t *world,
ecs_stage_t *stage);
/* Begin defer for stage */
void ecs_stage_defer_begin(
ecs_world_t *world,
ecs_stage_t *stage);
void ecs_stage_defer_end(
ecs_world_t *world,
ecs_stage_t *stage);
/* Delete table from stage */
void ecs_delete_table(
ecs_world_t *world,
ecs_table_t *table);
////////////////////////////////////////////////////////////////////////////////
//// Defer API
////////////////////////////////////////////////////////////////////////////////
bool ecs_defer_none(
ecs_world_t *world,
ecs_stage_t *stage);
bool ecs_defer_modified(
ecs_world_t *world,
ecs_stage_t *stage,
ecs_entity_t entity,
ecs_entity_t component);
bool ecs_defer_new(
ecs_world_t *world,
ecs_stage_t *stage,
ecs_entity_t entity,
ecs_entities_t *components);
bool ecs_defer_clone(
ecs_world_t *world,
ecs_stage_t *stage,
ecs_entity_t entity,
ecs_entity_t src,
bool clone_value);
bool ecs_defer_bulk_new(
ecs_world_t *world,
ecs_stage_t *stage,
int32_t count,
ecs_entities_t *components,
void **component_data,
const ecs_entity_t **ids_out);
bool ecs_defer_delete(
ecs_world_t *world,
ecs_stage_t *stage,
ecs_entity_t entity);
bool ecs_defer_clear(
ecs_world_t *world,
ecs_stage_t *stage,
ecs_entity_t entity);
bool ecs_defer_add(
ecs_world_t *world,
ecs_stage_t *stage,
ecs_entity_t entity,
ecs_entities_t *components);
bool ecs_defer_remove(
ecs_world_t *world,
ecs_stage_t *stage,
ecs_entity_t entity,
ecs_entities_t *components);
bool ecs_defer_set(
ecs_world_t *world,
ecs_stage_t *stage,
ecs_op_kind_t op_kind,
ecs_entity_t entity,
ecs_entity_t component,
ecs_size_t size,
const void *value,
void **value_out,
bool *is_added);
void ecs_defer_flush(
ecs_world_t *world,
ecs_stage_t *stage);
////////////////////////////////////////////////////////////////////////////////
//// Type API
////////////////////////////////////////////////////////////////////////////////
/* Merge add/remove types */
ecs_type_t ecs_type_merge_intern(
ecs_world_t *world,
ecs_stage_t *stage,
ecs_type_t cur_id,
ecs_type_t to_add_id,
ecs_type_t to_remove_id);
/* Test if type_id_1 contains type_id_2 */
ecs_entity_t ecs_type_contains(
ecs_world_t *world,
ecs_type_t type_id_1,
ecs_type_t type_id_2,