1 module tests.basic; 2 3 import bubel.ecs.core; 4 import bubel.ecs.manager; 5 import bubel.ecs.system; 6 import bubel.ecs.attributes; 7 8 version(GNU) 9 { 10 pragma(inline, true) T[n] staticArray(T, size_t n)(auto ref T[n] a) 11 { 12 return a; 13 } 14 } 15 else import std.array : staticArray; 16 17 struct CInt 18 { 19 // mixin ECS.Component; 20 21 alias value this; 22 23 int value = 1; 24 } 25 26 struct CFloat 27 { 28 // mixin ECS.Component; 29 30 alias value this; 31 32 float value = 2.0; 33 } 34 35 struct CDouble 36 { 37 // mixin ECS.Component; 38 39 alias value this; 40 41 double value = 3.0; 42 } 43 44 struct CLong 45 { 46 // mixin ECS.Component; 47 48 alias value this; 49 50 long value = 10; 51 } 52 53 struct CShort 54 { 55 // mixin ECS.Component; 56 57 alias value this; 58 59 short value = 12; 60 } 61 62 struct CUnregistered 63 { 64 // mixin ECS.Component; 65 66 alias value this; 67 68 short value = 12; 69 } 70 71 struct CFlag 72 { 73 // mixin ECS.Component; 74 } 75 76 struct LongAddSystem 77 { 78 mixin ECS.System; 79 80 struct EntitiesData 81 { 82 int length; 83 84 CLong[] long_; 85 } 86 87 void onUpdate(EntitiesData data) 88 { 89 updates_count++; 90 foreach(i;0..data.length) 91 { 92 data.long_[i] += 1; 93 } 94 } 95 96 int updates_count = 0; 97 } 98 99 struct EmptySystem 100 { 101 mixin ECS.System!16; 102 103 struct EntitiesData 104 { 105 int thread_id; 106 } 107 108 void onUpdate(EntitiesData data) 109 { 110 count++; 111 } 112 113 int count = 0; 114 } 115 116 struct EntityCounterSystem 117 { 118 mixin ECS.System!1; 119 120 struct EntitiesData 121 { 122 int thread_id; 123 uint length; 124 Entity[] entity; 125 } 126 127 bool onBegin() 128 { 129 count = 0; 130 return true; 131 } 132 133 void onUpdate(EntitiesData data) 134 { 135 count += data.length; 136 } 137 138 int count = 0; 139 } 140 141 void beforeEveryTest() 142 { 143 becsID!CUnregistered = ushort.max; 144 gEntityManager.initialize(0); 145 146 gEntityManager.beginRegister(); 147 148 gEntityManager.registerComponent!CInt; 149 gEntityManager.registerComponent!CFloat; 150 gEntityManager.registerComponent!CDouble; 151 gEntityManager.registerComponent!CLong; 152 gEntityManager.registerComponent!CShort; 153 gEntityManager.registerComponent!CFlag; 154 155 gEntityManager.endRegister(); 156 } 157 158 void afterEveryTest() 159 { 160 gEntityManager.destroy(); 161 } 162 163 @("EntityMeta") 164 unittest 165 { 166 EntityTemplate* tmpl_ = gEntityManager.allocateTemplate([becsID!CInt, becsID!CFloat, becsID!CFlag].staticArray); 167 scope(exit)gEntityManager.freeTemplate(tmpl_); 168 Entity* entity = gEntityManager.addEntity(tmpl_); 169 EntityMeta meta = entity.getMeta(); 170 assert(meta.hasComponent(becsID!CInt)); 171 assert(meta.getComponent!CInt); 172 assert(meta.hasComponent(becsID!CFloat)); 173 assert(meta.getComponent!CFloat); 174 assert(!meta.getComponent!CLong); 175 assert(!meta.hasComponent(becsID!CLong)); 176 assert(!meta.getComponent!CUnregistered); 177 assert(!meta.hasComponent(becsID!CUnregistered)); 178 assert(*meta.getComponent!CInt == 1); 179 assert(*meta.getComponent!CFloat == 2.0); 180 } 181 182 @("AddEntity") 183 unittest 184 { 185 EntityTemplate* tmpl_ = gEntityManager.allocateTemplate([becsID!CInt, becsID!CFloat, becsID!CFlag].staticArray); 186 scope(exit)gEntityManager.freeTemplate(tmpl_); 187 assert(tmpl_.info.components.length == 3); 188 assert(tmpl_.info.size == (CInt.sizeof + CFloat.sizeof + EntityID.sizeof)); 189 assert(tmpl_.getComponent!CInt); 190 assert(tmpl_.getComponent!CFloat); 191 assert(tmpl_.getComponent!CFlag); 192 assert(!tmpl_.getComponent!CLong); 193 assert(!tmpl_.getComponent!CUnregistered); 194 assert(*tmpl_.getComponent!CInt == 1); 195 assert(*tmpl_.getComponent!CFloat == 2.0); 196 197 Entity* entity = gEntityManager.addEntity(tmpl_); 198 assert(entity.getComponent!CInt); 199 assert(entity.getComponent!CFloat); 200 assert(*entity.getComponent!CInt == 1); 201 assert(*entity.getComponent!CFloat == 2.0); 202 *entity.getComponent!CInt = 2; 203 204 Entity* entity2 = gEntityManager.addEntityCopy(entity.id); 205 assert(entity2.getComponent!CInt); 206 assert(entity2.getComponent!CFloat); 207 assert(*entity2.getComponent!CInt == 2); 208 assert(*entity2.getComponent!CFloat == 2.0); 209 210 CInt int1 = CInt(10); 211 CLong long1 = CLong(); 212 CFlag flag1 = CFlag(); 213 Entity* entity3 = gEntityManager.addEntity(tmpl_, [ComponentRef(&int1, becsID(int1)), ComponentRef(&long1, becsID(long1)), ComponentRef(&flag1, becsID(flag1))].staticArray); 214 EntityID id = entity3.id; 215 assert(entity3.hasComponent(becsID!CInt)); 216 assert(entity3.hasComponent(becsID!CFloat)); 217 assert(*entity3.getComponent!CInt == 10); 218 assert(*entity3.getComponent!CFloat == 2.0); 219 220 CShort short1 = CShort(2); 221 gEntityManager.addComponents(entity3.id, [ComponentRef(&flag1, becsID(flag1)),ComponentRef(&short1, becsID(short1))].staticArray); 222 gEntityManager.commit(); 223 entity3 = gEntityManager.getEntity(id); 224 assert(entity3.getComponent!CInt); 225 assert(entity3.getComponent!CFloat); 226 assert(entity3.getComponent!CFlag); 227 assert(entity3.getComponent!CShort); 228 assert(*entity3.getComponent!CInt == 10); 229 assert(*entity3.getComponent!CFloat == 2.0); 230 assert(*entity3.getComponent!CShort == 2); 231 232 gEntityManager.removeComponents(entity3.id, [becsID!CFlag,becsID!CShort].staticArray); 233 gEntityManager.commit(); 234 entity3 = gEntityManager.getEntity(id); 235 assert(entity3.getComponent!CInt); 236 assert(entity3.getComponent!CFloat); 237 assert(!entity3.getComponent!CFlag); 238 assert(!entity3.getComponent!CShort); 239 assert(*entity3.getComponent!CInt == 10); 240 assert(*entity3.getComponent!CFloat == 2.0); 241 242 gEntityManager.addComponents(entity3.id, [ComponentRef(&flag1, becsID(flag1)),ComponentRef(&short1, becsID(short1))].staticArray); 243 gEntityManager.removeComponents(entity3.id, [becsID!CUnregistered].staticArray); 244 gEntityManager.commit(); 245 entity3 = gEntityManager.getEntity(id); 246 assert(entity3.getComponent!CInt); 247 assert(entity3.getComponent!CFloat); 248 assert(entity3.getComponent!CFlag); 249 assert(entity3.getComponent!CShort); 250 assert(*entity3.getComponent!CInt == 10); 251 assert(*entity3.getComponent!CFloat == 2.0); 252 assert(*entity3.getComponent!CShort == 2); 253 254 gEntityManager.beginRegister(); 255 256 gEntityManager.registerComponent!CUnregistered; 257 258 gEntityManager.endRegister(); 259 260 CUnregistered unregistered1 = CUnregistered(4); 261 gEntityManager.addComponents(entity3.id, [ComponentRef(&unregistered1, becsID(unregistered1))].staticArray); 262 gEntityManager.commit(); 263 entity3 = gEntityManager.getEntity(id); 264 assert(entity3.getComponent!CUnregistered); 265 assert(*entity3.getComponent!CUnregistered == 4); 266 267 gEntityManager.removeComponents(entity3.id, [becsID!CUnregistered].staticArray); 268 gEntityManager.commit(); 269 entity3 = gEntityManager.getEntity(id); 270 assert(!entity3.getComponent!CUnregistered); 271 } 272 273 @("AddEmptyEntity") 274 unittest 275 { 276 struct OnAddRemoveChangeCounter 277 { 278 mixin ECS.System!1; 279 280 struct EntitiesData 281 { 282 int thread_id; 283 uint length; 284 Entity[] entity; 285 } 286 287 void onAddEntity(EntitiesData data) 288 { 289 add += data.length; 290 } 291 292 void onRemoveEntity(EntitiesData data) 293 { 294 assert(0, "It's impossible to remove entity from being updated by system which accept empty entity"); 295 } 296 297 int add = 0; 298 } 299 300 gEntityManager.beginRegister(); 301 302 gEntityManager.registerSystem!EntityCounterSystem(0); 303 gEntityManager.registerSystem!OnAddRemoveChangeCounter(1); 304 305 gEntityManager.endRegister(); 306 307 CLong long_component = CLong(3); 308 309 Entity* entity = null; 310 EntityID entity_id = gEntityManager.addEntity(null).id; 311 312 EntityCounterSystem* system = gEntityManager.getSystem!EntityCounterSystem; 313 assert(system !is null); 314 assert(system.count == 0); 315 316 OnAddRemoveChangeCounter* add_remove_change_system = gEntityManager.getSystem!OnAddRemoveChangeCounter; 317 assert(add_remove_change_system !is null); 318 assert(add_remove_change_system.add == 0); 319 320 gEntityManager.commit(); 321 assert(add_remove_change_system.add == 1); 322 323 entity = gEntityManager.getEntity(entity_id); 324 assert(!entity.hasComponent(becsID!CLong)); 325 assert(entity.getComponent(becsID!CLong) is null); 326 327 328 gEntityManager.begin(); 329 gEntityManager.update(); 330 assert(system.count == 1); 331 gEntityManager.end(); 332 333 gEntityManager.addEntityCopy(entity_id); 334 gEntityManager.addEntityCopy(entity_id); 335 gEntityManager.addComponents(entity_id, [ComponentRef(&long_component, becsID(long_component))].staticArray); 336 gEntityManager.commit(); 337 assert(add_remove_change_system.add == 3, "onAddEntity missed"); 338 339 entity = gEntityManager.getEntity(entity_id); 340 assert(entity.hasComponent(becsID!CLong)); 341 assert(*entity.getComponent!CLong == 3); 342 343 gEntityManager.begin(); 344 gEntityManager.update(); 345 assert(system.count == 3); 346 gEntityManager.end(); 347 } 348 349 //allocate templates 350 @("AllocateTemplates") 351 unittest 352 { 353 //basic template allocation 354 ushort[2] ids = [becsID!CInt, becsID!CFloat]; 355 EntityTemplate* tmpl_ = gEntityManager.allocateTemplate(ids); 356 EntityTemplate* tmpl_d = gEntityManager.allocateTemplate([becsID!CFloat, becsID!CInt, becsID!CFloat].staticArray); 357 EntityTemplate* tmpl_cp = gEntityManager.allocateTemplate(tmpl_); 358 assert(tmpl_d.info == tmpl_.info); 359 assert(tmpl_cp.info == tmpl_cp.info); 360 assert(tmpl_.info.components.length == 2); 361 assert(tmpl_.getComponent!CInt); 362 assert(tmpl_.getComponent!CFloat); 363 assert(*tmpl_.getComponent!CInt == 1); 364 assert(*tmpl_.getComponent!CFloat == 2.0); 365 assert(tmpl_cp.getComponent!CFloat); 366 assert(tmpl_cp.getComponent!CInt); 367 assert(tmpl_.getComponent!CInt != tmpl_cp.getComponent!CInt); 368 assert(tmpl_.getComponent!CFloat != tmpl_cp.getComponent!CFloat); 369 assert(*tmpl_.getComponent!CInt == *tmpl_cp.getComponent!CInt); 370 assert(*tmpl_.getComponent!CFloat == *tmpl_cp.getComponent!CFloat); 371 *tmpl_.getComponent!CInt = 4; 372 *tmpl_.getComponent!CFloat = 5.0; 373 374 //allocate template from template with additional components 375 ushort[2] ids2 = [becsID!CDouble,becsID!CFlag]; 376 EntityTemplate* tmpl_2 = gEntityManager.allocateTemplate(tmpl_, ids2); 377 assert(tmpl_2.info.components.length == 4); 378 assert(tmpl_2.getComponent!CInt); 379 assert(tmpl_2.getComponent!CFloat); 380 assert(tmpl_2.getComponent!CDouble); 381 assert(tmpl_2.getComponent!CFlag); 382 assert(*tmpl_2.getComponent!CInt == 4); 383 assert(*tmpl_2.getComponent!CFloat == 5.0); 384 assert(*tmpl_2.getComponent!CDouble == 3.0); 385 386 assert(tmpl_.info.blocksCount() == 0); 387 388 Entity* entity = gEntityManager.addEntity(tmpl_); 389 gEntityManager.addComponents(entity.id, CFloat(100)); 390 gEntityManager.addComponents(entity.id, CDouble(8.0), CFloat(100)); 391 392 assert(tmpl_.info.blocksCount() == 1); 393 394 //apply entity changes 395 gEntityManager.commit(); 396 397 assert(tmpl_.info.blocksCount() == 0); 398 399 //allocate template as entity copy 400 EntityTemplate* tmpl_3 = gEntityManager.allocateTemplate(entity.id); 401 assert(tmpl_3.info.components.length == 3); 402 assert(tmpl_3.getComponent!CInt); 403 assert(tmpl_3.getComponent!CFloat); 404 assert(tmpl_3.getComponent!CDouble); 405 assert(*tmpl_3.getComponent!CInt == 4); 406 assert(*tmpl_3.getComponent!CFloat == 5.0); 407 assert(*tmpl_3.getComponent!CDouble == 8.0); 408 409 //allocate template with entity data but default values 410 EntityTemplate* tmpl_4 = gEntityManager.allocateTemplate(entity.id, true); 411 assert(tmpl_4.info.components.length == 3); 412 assert(tmpl_4.getComponent!CInt); 413 assert(tmpl_4.getComponent!CFloat); 414 assert(tmpl_4.getComponent!CDouble); 415 assert(*tmpl_4.getComponent!CInt == 1); 416 assert(*tmpl_4.getComponent!CFloat == 2.0); 417 assert(*tmpl_4.getComponent!CDouble == 3.0); 418 419 //allocate template from template with three additional component 420 ushort[3] ids3 = [becsID!CDouble, becsID!CLong, becsID!CShort]; 421 EntityTemplate* tmpl_5 = gEntityManager.allocateTemplate(tmpl_2, ids3); 422 assert(tmpl_5.info.components.length == 6); 423 assert(tmpl_5.getComponent!CInt); 424 assert(tmpl_5.getComponent!CFloat); 425 assert(tmpl_5.getComponent!CDouble); 426 assert(tmpl_5.getComponent!CLong); 427 assert(tmpl_5.getComponent!CShort); 428 assert(*tmpl_5.getComponent!CInt == 4); 429 assert(*tmpl_5.getComponent!CFloat == 5.0); 430 assert(*tmpl_5.getComponent!CDouble == 3.0); 431 assert(*tmpl_5.getComponent!CLong == 10); 432 assert(*tmpl_5.getComponent!CShort == 12); 433 434 //allocate template from template without one component 435 ushort[1] rem_ids = [becsID!CFloat]; 436 EntityTemplate* tmpl_6 = gEntityManager.allocateTemplate(tmpl_, null, rem_ids); 437 assert(tmpl_6.info.components.length == 1); 438 assert(tmpl_6.getComponent!CInt); 439 assert(*tmpl_6.getComponent!CInt == 4); 440 441 //allocate template from template without one component and two additional 442 EntityTemplate* tmpl_7 = gEntityManager.allocateTemplate(tmpl_, ids3, rem_ids); 443 assert(tmpl_7.info.components.length == 4); 444 assert(tmpl_7.getComponent!CInt); 445 assert(tmpl_7.getComponent!CDouble); 446 assert(tmpl_7.getComponent!CLong); 447 assert(*tmpl_7.getComponent!CInt == 4); 448 assert(*tmpl_7.getComponent!CDouble == 3.0); 449 assert(*tmpl_7.getComponent!CLong == 10); 450 451 gEntityManager.freeTemplate(tmpl_d); 452 gEntityManager.freeTemplate(tmpl_cp); 453 gEntityManager.freeTemplate(tmpl_); 454 gEntityManager.freeTemplate(tmpl_2); 455 gEntityManager.freeTemplate(tmpl_3); 456 gEntityManager.freeTemplate(tmpl_4); 457 gEntityManager.freeTemplate(tmpl_5); 458 gEntityManager.freeTemplate(tmpl_6); 459 gEntityManager.freeTemplate(tmpl_7); 460 } 461 462 @("UnsortedComponentIDs") 463 unittest 464 { 465 //basic template allocation 466 ushort[2] ids = [becsID!CFloat, becsID!CInt]; 467 ushort[2] ids2 = [becsID!CInt, becsID!CFloat]; 468 EntityTemplate* tmpl_ = gEntityManager.allocateTemplate(ids); 469 EntityTemplate* tmpl_2 = gEntityManager.allocateTemplate(ids2); 470 assert(tmpl_.info.components.length == 2); 471 assert(tmpl_.getComponent!CInt); 472 assert(tmpl_.getComponent!CFloat); 473 assert(*tmpl_.getComponent!CInt == 1); 474 assert(*tmpl_.getComponent!CFloat == 2.0); 475 assert(tmpl_.info == tmpl_2.info); 476 gEntityManager.freeTemplate(tmpl_); 477 gEntityManager.freeTemplate(tmpl_2); 478 } 479 480 @("MultiRegister") 481 unittest 482 { 483 gEntityManager.beginRegister(); 484 485 gEntityManager.endRegister(); 486 487 gEntityManager.beginRegister(); 488 489 gEntityManager.registerComponent!CLong; 490 gEntityManager.registerComponent!CShort; 491 492 gEntityManager.endRegister(); 493 } 494 495 @("EmptySystem") 496 unittest 497 { 498 gEntityManager.beginRegister(); 499 500 gEntityManager.registerSystem!EmptySystem(0); 501 502 gEntityManager.endRegister(); 503 504 EmptySystem* system = gEntityManager.getSystem!EmptySystem; 505 assert(system !is null); 506 assert(system.count == 0); 507 508 System* ecs_system = gEntityManager.getSystem(becsID!EmptySystem); 509 assert(ecs_system !is null); 510 assert(ecs_system.id == becsID!EmptySystem); 511 assert(ecs_system.name == "tests.basic.EmptySystem"); 512 513 gEntityManager.begin(); 514 515 gEntityManager.update(); 516 517 gEntityManager.end(); 518 519 assert(system.count == 1); 520 } 521 522 @("SystemCallbacks") 523 unittest 524 { 525 struct TestSystem 526 { 527 mixin ECS.System!16; 528 529 mixin ECS.ExcludedComponents!(CShort); 530 531 struct EntitiesData 532 { 533 int length; 534 CLong[] long_; 535 @optional CInt[] int_; 536 } 537 538 void onCreate() 539 { 540 create++; 541 } 542 543 void onDestroy() 544 { 545 if(destroy)(*destroy)++; 546 } 547 548 void onEnable() 549 { 550 enable++; 551 } 552 553 void onDisable() 554 { 555 disable++; 556 } 557 558 bool onBegin() 559 { 560 begin++; 561 update = 0; 562 return pass; 563 } 564 565 void onEnd() 566 { 567 end++; 568 } 569 570 void onUpdate(EntitiesData data) 571 { 572 update++; 573 } 574 575 int create = 0; 576 int* destroy; 577 int update = 0; 578 int begin = 0; 579 int end = 0; 580 int enable = 0; 581 int disable = 0; 582 bool pass = true; 583 } 584 585 gEntityManager.beginRegister(); 586 587 gEntityManager.registerSystem!TestSystem(0); 588 589 gEntityManager.endRegister(); 590 591 TestSystem* system = gEntityManager.getSystem!TestSystem; 592 int destroy = 0; 593 system.destroy = &destroy; 594 595 gEntityManager.beginRegister(); 596 597 gEntityManager.registerSystem!TestSystem(0); 598 599 gEntityManager.endRegister(); 600 601 system = gEntityManager.getSystem!TestSystem; 602 system.destroy = &destroy; 603 assert(system !is null); 604 assert(system.create == 1); 605 assert(system.begin == 0); 606 assert(system.end == 0); 607 assert(system.enable == 1); 608 assert(system.disable == 0); 609 //FIXME: currently destroy is only called with Manager.destory which is bug, but there is no workaround for this by now 610 //assert(destroy == 1); 611 612 System* ecs_system = gEntityManager.getSystem(system.becsID); 613 614 ecs_system.enable(); 615 assert(system.enable == 1); 616 ecs_system.disable(); 617 ecs_system.disable(); 618 ecs_system.enable(); 619 assert(system.enable == 2); 620 assert(system.disable == 1); 621 622 623 ushort[2] ids = [becsID!CLong,becsID!CFloat]; 624 EntityTemplate* tmpl = gEntityManager.allocateTemplate(ids); 625 scope (exit) gEntityManager.freeTemplate(tmpl); 626 gEntityManager.addEntity(tmpl); 627 628 gEntityManager.begin(); 629 assert(system.begin == 1); 630 631 gEntityManager.update(); 632 assert(system.update == 1); 633 634 gEntityManager.end(); 635 assert(system.end == 1); 636 637 ushort[2] ids2 = [becsID!CLong, becsID!CInt]; 638 EntityTemplate* tmpl2 = gEntityManager.allocateTemplate(ids2); 639 scope (exit) gEntityManager.freeTemplate(tmpl2); 640 gEntityManager.addEntity(tmpl2); 641 gEntityManager.addEntity(tmpl2); 642 643 gEntityManager.begin(); 644 assert(system.begin == 2); 645 646 gEntityManager.update(); 647 assert(system.update == 2);//system is updated number of entity blocks times 648 649 gEntityManager.end(); 650 assert(system.end == 2); 651 652 ushort[2] ids3 = [becsID!CLong, becsID!CShort]; 653 EntityTemplate* tmpl3 = gEntityManager.allocateTemplate(ids3); 654 scope (exit) gEntityManager.freeTemplate(tmpl3); 655 gEntityManager.addEntity(tmpl3); 656 657 //entity with excluded component shouldn't be updated 658 gEntityManager.begin(); 659 assert(system.begin == 3); 660 661 gEntityManager.update(); 662 assert(system.update == 2); 663 664 gEntityManager.end(); 665 assert(system.end == 3); 666 667 //system can be disable form update in onBegin() callback, onEnd() callback is called 668 system.pass = false; 669 gEntityManager.begin(); 670 assert(system.begin == 4); 671 672 gEntityManager.update(); 673 assert(system.update == 0); 674 675 gEntityManager.end(); 676 assert(system.end == 4); 677 system.pass = true; 678 679 //disabled system is't called 680 ecs_system.disable(); 681 gEntityManager.begin(); 682 assert(system.begin == 4); 683 684 gEntityManager.update(); 685 assert(system.update == 0); 686 687 gEntityManager.end(); 688 assert(system.end == 4); 689 ecs_system.enable(); 690 system.destroy = null; 691 } 692 693 @("CustomPass") 694 unittest 695 { 696 gEntityManager.beginRegister(); 697 698 gEntityManager.registerPass("custom"); 699 gEntityManager.registerSystem!LongAddSystem(-1,"custom"); 700 701 gEntityManager.endRegister(); 702 703 assert(gEntityManager.getPass("custom")); 704 assert(!gEntityManager.getPass("custommm")); 705 706 707 LongAddSystem* system = gEntityManager.getSystem!LongAddSystem; 708 assert(system !is null); 709 assert(system.updates_count == 0); 710 711 System* ecs_system = gEntityManager.getSystem(becsID!LongAddSystem); 712 assert(ecs_system !is null); 713 assert(ecs_system.id == becsID!LongAddSystem); 714 assert(ecs_system.priority == -1); 715 assert(ecs_system.name == "tests.basic.LongAddSystem"); 716 717 ushort[1] ids = [becsID!CLong]; 718 EntityTemplate* tmpl = gEntityManager.allocateTemplate(ids); 719 scope (exit) gEntityManager.freeTemplate(tmpl); 720 gEntityManager.addEntity(tmpl); 721 722 gEntityManager.begin(); 723 724 gEntityManager.update(); 725 assert(system.updates_count == 0); 726 gEntityManager.update("custom"); 727 assert(system.updates_count == 1); 728 729 gEntityManager.end(); 730 } 731 732 @("SystemEntityCallbacks") 733 unittest 734 { 735 static int add_order = 0; 736 static int rem_order = 0; 737 static int change_order = 0; 738 struct TestSystem 739 { 740 mixin ECS.System!16; 741 742 mixin ECS.ExcludedComponents!(CShort); 743 744 struct EntitiesData 745 { 746 int length; 747 CLong[] long_; 748 @optional CInt[] int_; 749 } 750 751 void onAddEntity(EntitiesData data) 752 { 753 add++; 754 assert(add_order == 1); 755 add_order++; 756 } 757 758 void onRemoveEntity(EntitiesData data) 759 { 760 remove++; 761 assert(rem_order == 1); 762 rem_order++; 763 } 764 765 void onChangeEntity(EntitiesData data) 766 { 767 change++; 768 assert(change_order == 1); 769 change_order++; 770 } 771 772 void onUpdate(EntitiesData data) 773 { 774 } 775 776 int add = 0; 777 int remove = 0; 778 int change = 0; 779 } 780 781 struct TestSystem2 782 { 783 mixin ECS.System!16; 784 785 mixin ECS.ExcludedComponents!(CShort); 786 787 struct EntitiesData 788 { 789 int length; 790 CLong[] long_; 791 @optional CInt[] int_; 792 } 793 794 void onAddEntity(EntitiesData data) 795 { 796 assert(add_order == 2); 797 add_order = 0; 798 } 799 800 void onRemoveEntity(EntitiesData data) 801 { 802 assert(rem_order == 2); 803 rem_order = 0 ; 804 } 805 806 void onChangeEntity(EntitiesData data) 807 { 808 assert(change_order == 2); 809 change_order = 0; 810 } 811 812 void onUpdate(EntitiesData data) 813 { 814 } 815 } 816 817 struct TestSystem3 818 { 819 mixin ECS.System!16; 820 821 mixin ECS.ExcludedComponents!(CShort); 822 823 struct EntitiesData 824 { 825 int length; 826 CLong[] long_; 827 @optional CInt[] int_; 828 } 829 830 void onAddEntity(EntitiesData data) 831 { 832 assert(add_order == 0); 833 add_order++; 834 } 835 836 void onRemoveEntity(EntitiesData data) 837 { 838 assert(rem_order == 0); 839 rem_order++; 840 } 841 842 void onChangeEntity(EntitiesData data) 843 { 844 assert(change_order == 0); 845 change_order++; 846 } 847 848 void onUpdate(EntitiesData data) 849 { 850 } 851 } 852 853 gEntityManager.beginRegister(); 854 855 gEntityManager.registerSystem!TestSystem3(-1); 856 gEntityManager.registerSystem!TestSystem(0); 857 gEntityManager.registerSystem!TestSystem2(1); 858 859 gEntityManager.endRegister(); 860 861 TestSystem* system = gEntityManager.getSystem!TestSystem; 862 assert(system !is null); 863 assert(system.add == 0); 864 assert(system.remove == 0); 865 assert(system.change == 0); 866 867 EntityTemplate* tmpl = gEntityManager.allocateTemplate([becsID!CLong,becsID!CFloat].staticArray); 868 scope (exit) gEntityManager.freeTemplate(tmpl); 869 EntityID id0 = gEntityManager.addEntity(tmpl).id; 870 gEntityManager.commit(); 871 assert(system.add == 1); 872 873 EntityTemplate* tmpl2 = gEntityManager.allocateTemplate([becsID!CLong, becsID!CInt].staticArray); 874 scope (exit) gEntityManager.freeTemplate(tmpl2); 875 EntityID id1 = gEntityManager.addEntity(tmpl2).id; 876 gEntityManager.commit(); 877 assert(system.add == 2); 878 879 EntityTemplate* tmpl3 = gEntityManager.allocateTemplate([becsID!CLong, becsID!CShort].staticArray); 880 scope (exit) gEntityManager.freeTemplate(tmpl3); 881 EntityID id2 = gEntityManager.addEntity(tmpl3).id; 882 gEntityManager.commit(); 883 assert(system.add == 2); 884 885 gEntityManager.beginRegister(); 886 gEntityManager.endRegister(); 887 888 gEntityManager.removeComponents(id0, [becsID!CFloat].staticArray); 889 gEntityManager.commit(); 890 assert(system.add == 2); 891 assert(system.remove == 0); 892 assert(system.change == 0); 893 894 gEntityManager.removeComponents(id1, [becsID!CInt].staticArray); 895 gEntityManager.commit(); 896 assert(system.add == 2); 897 assert(system.remove == 0); 898 assert(system.change == 1); 899 900 gEntityManager.removeComponents(id2, [becsID!CShort].staticArray); 901 gEntityManager.commit(); 902 assert(system.add == 3); 903 assert(system.remove == 0); 904 assert(system.change == 1); 905 906 gEntityManager.addComponents(id2, CShort(1)); 907 gEntityManager.commit(); 908 assert(system.add == 3); 909 assert(system.remove == 1); 910 assert(system.change == 1); 911 912 gEntityManager.removeEntity(id0); 913 gEntityManager.commit(); 914 assert(system.add == 3); 915 assert(system.remove == 2); 916 assert(system.change == 1); 917 918 gEntityManager.addComponents(id1, CInt(1)); 919 gEntityManager.commit(); 920 assert(system.add == 3); 921 assert(system.remove == 2); 922 assert(system.change == 2); 923 924 gEntityManager.addComponents(id0, CFloat(1)); 925 gEntityManager.commit(); 926 assert(system.add == 3); 927 assert(system.remove == 2); 928 assert(system.change == 2); 929 930 gEntityManager.removeEntity(id1); 931 gEntityManager.commit(); 932 assert(system.add == 3); 933 assert(system.remove == 3); 934 assert(system.change == 2); 935 936 gEntityManager.removeEntity(id2); 937 gEntityManager.commit(); 938 assert(system.add == 3); 939 assert(system.remove == 3); 940 assert(system.change == 2); 941 } 942 943 @("TemplateCoverage") 944 unittest 945 { 946 struct TestSystem 947 { 948 mixin ECS.System; 949 950 struct EntitiesData 951 { 952 int length; 953 Entity[] entity; 954 @readonly CLong[] long_; 955 @optional CInt[] int_; 956 @readonly CFloat[] float_; 957 } 958 959 mixin ECS.ExcludedComponents!(CUnregistered); 960 961 void onUpdate(EntitiesData data) 962 { 963 964 } 965 } 966 967 gEntityManager.beginRegister(); 968 969 gEntityManager.registerComponent!CUnregistered; 970 971 gEntityManager.registerSystem!TestSystem(0); 972 973 gEntityManager.endRegister(); 974 } 975 976 @("UnregisteredSystem") 977 unittest 978 { 979 struct TestSystem 980 { 981 mixin ECS.System; 982 983 struct EntitiesData 984 { 985 int length; 986 Entity[] entity; 987 @readonly CLong[] long_; 988 @optional CInt[] int_; 989 @readonly CFloat[] float_; 990 } 991 992 void onUpdate(EntitiesData data) 993 { 994 995 } 996 } 997 998 assert(gEntityManager.getSystem!TestSystem is null); 999 assert(gEntityManager.getSystem(becsID!TestSystem) is null); 1000 } 1001 1002 @("MultithreadedUpdate") 1003 unittest 1004 { 1005 struct TestSystem 1006 { 1007 mixin ECS.System!64; 1008 1009 struct EntitiesData 1010 { 1011 int length; 1012 Entity[] entity; 1013 @readonly CLong[] long_; 1014 @optional CInt[] int_; 1015 @readonly CFloat[] float_; 1016 } 1017 1018 void onUpdate(EntitiesData data) 1019 { 1020 update++; 1021 entities += data.length; 1022 } 1023 1024 int update = 0; 1025 int entities = 0; 1026 } 1027 1028 struct TestEmptySystem 1029 { 1030 mixin ECS.System; 1031 1032 struct EntitiesData 1033 { 1034 int length; 1035 } 1036 1037 void onUpdate(EntitiesData data) 1038 { 1039 update++; 1040 } 1041 1042 int update = 0; 1043 } 1044 1045 void dispatch(EntityManager.JobGroup grp) 1046 { 1047 foreach(job; grp.jobs) 1048 { 1049 job.execute(); 1050 } 1051 } 1052 1053 uint getID() 1054 { 1055 return 0; 1056 } 1057 1058 gEntityManager.setMultithreadingCallbacks(&dispatch, &getID); 1059 1060 gEntityManager.beginRegister(); 1061 1062 gEntityManager.registerPass("custom"); 1063 gEntityManager.registerSystem!TestSystem(-1,"custom"); 1064 gEntityManager.registerSystem!TestEmptySystem(1,"custom"); 1065 1066 gEntityManager.endRegister(); 1067 1068 TestSystem* system = gEntityManager.getSystem!TestSystem; 1069 TestEmptySystem* empty_system = gEntityManager.getSystem!TestEmptySystem; 1070 1071 ushort[2] ids = [becsID!CLong,becsID!CFloat]; 1072 EntityTemplate* tmpl = gEntityManager.allocateTemplate(ids); 1073 scope (exit) gEntityManager.freeTemplate(tmpl); 1074 EntityTemplate* tmpl2 = gEntityManager.allocateTemplate([becsID!CLong,becsID!CInt,becsID!CShort,becsID!CFloat].staticArray); 1075 scope (exit) gEntityManager.freeTemplate(tmpl2); 1076 1077 gEntityManager.begin(); 1078 1079 gEntityManager.updateMT("custom"); 1080 1081 gEntityManager.end(); 1082 1083 assert(system.update == 0); 1084 assert(system.entities == 0); 1085 assert(empty_system.update == 1); 1086 1087 gEntityManager.addEntity(tmpl); 1088 1089 gEntityManager.begin(); 1090 1091 gEntityManager.updateMT("custom"); 1092 1093 gEntityManager.end(); 1094 1095 assert(system.update == 1); 1096 assert(system.entities == 1); 1097 assert(empty_system.update == 2); 1098 system.entities = 0; 1099 1100 foreach(i;0..2000)gEntityManager.addEntity(tmpl); 1101 1102 gEntityManager.begin(); 1103 1104 gEntityManager.updateMT("custom"); 1105 1106 gEntityManager.end(); 1107 1108 assert(system.update > 2); 1109 assert(system.entities == 2001); 1110 assert(empty_system.update == 3); 1111 system.entities = 0; 1112 1113 // foreach(i;0..10000)gEntityManager.addEntity(tmpl); 1114 1115 // gEntityManager.begin(); 1116 1117 // gEntityManager.updateMT("custom"); 1118 1119 // gEntityManager.end(); 1120 1121 // assert(system.entities == 12001); 1122 1123 void clearEntities(TestSystem.EntitiesData data) 1124 { 1125 foreach(i;0..data.length) 1126 { 1127 gEntityManager.removeEntity(data.entity[i].id); 1128 } 1129 } 1130 gEntityManager.callEntitiesFunction!TestSystem(&clearEntities); 1131 gEntityManager.commit(); 1132 1133 foreach(i;0..2000) 1134 { 1135 gEntityManager.addEntity(tmpl); 1136 1137 gEntityManager.begin(); 1138 gEntityManager.updateMT("custom"); 1139 gEntityManager.end(); 1140 1141 assert(system.entities == i+1); 1142 system.entities = 0; 1143 } 1144 1145 foreach(i;0..90000)gEntityManager.addEntity(tmpl); 1146 1147 foreach(i;0..2000) 1148 { 1149 gEntityManager.addEntity(tmpl); 1150 1151 gEntityManager.begin(); 1152 gEntityManager.updateMT("custom"); 1153 gEntityManager.end(); 1154 1155 assert(system.entities == i+92001); 1156 system.entities = 0; 1157 } 1158 } 1159 1160 unittest 1161 { 1162 assert(gEntityManager.pageSize == 32768); 1163 assert(gEntityManager.pagesInBlock == 128); 1164 } 1165 1166 @("AddRemoveEntities") 1167 unittest 1168 { 1169 ushort[3] ids = [becsID!CLong,becsID!CFloat,becsID!CShort]; 1170 EntityTemplate* tmpl = gEntityManager.allocateTemplate(ids); 1171 scope (exit) gEntityManager.freeTemplate(tmpl); 1172 1173 EntityID[5000] entities; 1174 1175 foreach(i;0..4) 1176 { 1177 foreach(j;0..5000) 1178 { 1179 entities[j] = gEntityManager.addEntity(tmpl).id; 1180 } 1181 gEntityManager.commit(); 1182 foreach(j;0..5000) 1183 { 1184 gEntityManager.removeEntity(entities[j]); 1185 } 1186 gEntityManager.commit(); 1187 } 1188 } 1189 1190 @("ChangeEntityComponents") 1191 unittest 1192 { 1193 gEntityManager.beginRegister(); 1194 1195 gEntityManager.registerComponent!CUnregistered; 1196 1197 gEntityManager.endRegister(); 1198 1199 ushort[1] ids = [becsID!CLong]; 1200 EntityTemplate* tmpl = gEntityManager.allocateTemplate(ids); 1201 scope (exit) gEntityManager.freeTemplate(tmpl); 1202 1203 EntityID id = gEntityManager.addEntity(tmpl).id; 1204 gEntityManager.commit(); 1205 Entity* entity = gEntityManager.getEntity(id); 1206 assert(entity.id == id); 1207 assert(entity.getComponent!CLong !is null); 1208 assert(entity.getComponent!CFloat is null); 1209 assert(entity.getComponent!CUnregistered is null); 1210 assert(entity.getComponent!CShort is null); 1211 assert(entity.getComponent!CInt is null); 1212 assert(*entity.getComponent!CLong == 10); 1213 1214 gEntityManager.addComponents(id, CShort(15), CFloat(13)); 1215 gEntityManager.commit(); 1216 1217 entity = gEntityManager.getEntity(id); 1218 assert(entity.id == id); 1219 assert(entity.getComponent!CLong !is null); 1220 assert(entity.getComponent!CFloat !is null); 1221 assert(entity.getComponent!CUnregistered is null); 1222 assert(entity.getComponent!CShort !is null); 1223 assert(entity.getComponent!CInt is null); 1224 assert(*entity.getComponent!CLong == 10); 1225 assert(*entity.getComponent!CShort == 15); 1226 assert(*entity.getComponent!CFloat == 13); 1227 1228 ushort[3] ids2 = [becsID!CFloat, becsID!CLong, becsID!CUnregistered]; 1229 gEntityManager.removeComponents(id, ids2); 1230 gEntityManager.commit(); 1231 1232 entity = gEntityManager.getEntity(id); 1233 assert(entity.id == id); 1234 assert(entity.getComponent!CLong is null); 1235 assert(entity.getComponent!CFloat is null); 1236 assert(entity.getComponent!CUnregistered is null); 1237 assert(entity.getComponent!CShort !is null); 1238 assert(entity.getComponent!CInt is null); 1239 assert(*entity.getComponent!CShort == 15); 1240 1241 gEntityManager.removeComponents(id, ids2); 1242 gEntityManager.addComponents(id, CShort(11), CLong(2)); //wrong order of components 1243 gEntityManager.commit(); 1244 1245 entity = gEntityManager.getEntity(id); 1246 assert(entity.id == id); 1247 assert(entity.getComponent!CLong !is null); 1248 assert(entity.getComponent!CFloat is null); 1249 assert(entity.getComponent!CUnregistered is null); 1250 assert(entity.getComponent!CShort !is null); 1251 assert(entity.getComponent!CInt is null); 1252 assert(*entity.getComponent!CLong == 2); 1253 assert(*entity.getComponent!CShort == 15); 1254 1255 gEntityManager.removeEntity(id); 1256 1257 entity = gEntityManager.getEntity(id); 1258 assert(entity !is null); 1259 assert(entity.id == id); 1260 1261 gEntityManager.commit(); 1262 entity = gEntityManager.getEntity(id); 1263 assert(entity is null); 1264 } 1265 1266 @("EventCallbacks") 1267 unittest 1268 { 1269 struct ETest 1270 { 1271 // mixin ECS.Event; 1272 } 1273 1274 struct ETest2 1275 { 1276 // mixin ECS.Event; 1277 1278 void onDestroy() 1279 { 1280 destory++; 1281 } 1282 1283 int super_liczba = 0; 1284 static int destory = 0; 1285 } 1286 1287 struct TestSystem 1288 { 1289 mixin ECS.System; 1290 1291 struct EntitiesData 1292 { 1293 int length; 1294 Entity[] entity; 1295 @readonly CLong[] long_; 1296 @optional CInt[] int_; 1297 } 1298 1299 void onUpdate(EntitiesData data) 1300 { 1301 1302 } 1303 1304 void handleEvent(Entity* entity, ETest event) 1305 { 1306 CLong* long_ = entity.getComponent!CLong; 1307 CInt* int_ = entity.getComponent!CInt; 1308 *long_ += 16; 1309 if(int_)*int_ += 6; 1310 } 1311 1312 void handleEvent(Entity* entity, ETest2 event) 1313 { 1314 CLong* long_ = entity.getComponent!CLong; 1315 CInt* int_ = entity.getComponent!CInt; 1316 *long_ += event.super_liczba * 2; 1317 if(int_)*int_ += event.super_liczba * 4; 1318 } 1319 } 1320 1321 struct TestSystem2 1322 { 1323 mixin ECS.System; 1324 1325 struct EntitiesData 1326 { 1327 int length; 1328 Entity[] entity; 1329 CShort[] short_; 1330 @optional CInt[] int_; 1331 } 1332 1333 void handleEvent(Entity* entity, ETest event) 1334 { 1335 CShort* short_ = entity.getComponent!CShort; 1336 CInt* int_ = entity.getComponent!CInt; 1337 *short_ += 8; 1338 if(int_)*int_ += 2; 1339 } 1340 1341 void handleEvent(Entity* entity, ETest2 event) 1342 { 1343 CShort* short_ = entity.getComponent!CShort; 1344 CInt* int_ = entity.getComponent!CInt; 1345 *short_ += event.super_liczba; 1346 if(int_)*int_ *= event.super_liczba; 1347 } 1348 } 1349 1350 gEntityManager.beginRegister(); 1351 1352 gEntityManager.registerEvent!ETest; 1353 gEntityManager.registerEvent!ETest2; 1354 1355 gEntityManager.registerEvent!ETest; 1356 gEntityManager.registerEvent!ETest2; 1357 1358 gEntityManager.registerSystem!TestSystem2(1); 1359 gEntityManager.registerSystem!TestSystem(0); 1360 1361 gEntityManager.endRegister(); 1362 1363 ushort[1] ids = [becsID!CLong]; 1364 EntityTemplate* tmpl = gEntityManager.allocateTemplate(ids); 1365 scope (exit) gEntityManager.freeTemplate(tmpl); 1366 ushort[1] ids2 = [becsID!CShort]; 1367 EntityTemplate* tmpl2 = gEntityManager.allocateTemplate(ids2); 1368 scope (exit) gEntityManager.freeTemplate(tmpl2); 1369 1370 Entity* entity = gEntityManager.addEntity(tmpl); 1371 EntityID id = entity.id; 1372 assert(*entity.getComponent!CLong == 10); 1373 Entity* entity2 = gEntityManager.addEntity(tmpl2); 1374 EntityID id2 = entity2.id; 1375 assert(*entity2.getComponent!CShort == 12); 1376 1377 gEntityManager.sendEvent(id,ETest()); 1378 gEntityManager.sendEvent(id,ETest2(10)); 1379 gEntityManager.sendEvent(id2,ETest()); 1380 gEntityManager.sendEvent(id2,ETest2(12)); 1381 gEntityManager.commit(); 1382 assert(ETest2.destory == 2); 1383 1384 entity = gEntityManager.getEntity(id); 1385 entity2 = gEntityManager.getEntity(id2); 1386 assert(*entity.getComponent!CLong == 46); 1387 assert(*entity2.getComponent!CShort == 32); 1388 1389 gEntityManager.addComponents(id, CInt(2), CShort(1)); 1390 gEntityManager.sendEvent(id,ETest()); 1391 gEntityManager.sendEvent(id,ETest2(2)); 1392 gEntityManager.commit(); 1393 assert(ETest2.destory == 3); 1394 1395 entity = gEntityManager.getEntity(id); 1396 assert(*entity.getComponent!CLong == 66); 1397 assert(*entity.getComponent!CInt == 2);//36); 1398 1399 //test for multiple event blocks 1400 long result = *entity.getComponent!CLong; 1401 foreach(i;0..10000) 1402 { 1403 gEntityManager.sendEvent(id,ETest()); 1404 gEntityManager.sendEvent(id,ETest2(4)); 1405 result += 16; 1406 result += 8; 1407 } 1408 gEntityManager.commit(); 1409 assert(ETest2.destory == 10003); 1410 entity = gEntityManager.getEntity(id); 1411 assert(*entity.getComponent!CLong == result); 1412 1413 //cover funcion to clearEvents before destroying manager 1414 gEntityManager.sendEvent(id,ETest()); 1415 } 1416 1417 @("EntitiesFunction") 1418 unittest 1419 { 1420 struct TestSystem 1421 { 1422 mixin ECS.System; 1423 1424 struct EntitiesData 1425 { 1426 uint length; 1427 CInt[] int_; 1428 } 1429 1430 void onUpdate(EntitiesData entities) 1431 { 1432 1433 } 1434 } 1435 1436 void func1(TestSystem.EntitiesData entities) 1437 { 1438 foreach(i;0 .. entities.length) 1439 { 1440 entities.int_[i] += entities.int_[i] / 2; 1441 } 1442 } 1443 1444 void func2(TestSystem.EntitiesData entities) 1445 { 1446 foreach(i;0 .. entities.length) 1447 { 1448 entities.int_[i] += 8; 1449 } 1450 } 1451 1452 gEntityManager.beginRegister(); 1453 1454 gEntityManager.registerSystem!TestSystem(1); 1455 1456 gEntityManager.endRegister(); 1457 1458 EntityTemplate* tmpl = gEntityManager.allocateTemplate([becsID!CInt].staticArray); 1459 scope (exit) gEntityManager.freeTemplate(tmpl); 1460 EntityID id1 = gEntityManager.addEntity(tmpl).id; 1461 1462 EntityTemplate* tmpl2 = gEntityManager.allocateTemplate([becsID!CInt, becsID!CLong].staticArray); 1463 scope (exit) gEntityManager.freeTemplate(tmpl2); 1464 EntityID id2 = gEntityManager.addEntity(tmpl2).id; 1465 1466 gEntityManager.begin(); 1467 1468 Entity* entity1 = gEntityManager.getEntity(id1); 1469 Entity* entity2 = gEntityManager.getEntity(id2); 1470 assert(*entity1.getComponent!CInt == 1); 1471 assert(*entity2.getComponent!CInt == 1); 1472 1473 gEntityManager.callEntitiesFunction!TestSystem(&func2); 1474 assert(*entity1.getComponent!CInt == 9); 1475 assert(*entity2.getComponent!CInt == 9); 1476 1477 gEntityManager.callEntitiesFunction!TestSystem(&func1); 1478 assert(*entity1.getComponent!CInt == 13); 1479 assert(*entity2.getComponent!CInt == 13); 1480 1481 gEntityManager.end(); 1482 } 1483 1484 @("SystemDependencies") 1485 unittest 1486 { 1487 struct TestSystem 1488 { 1489 mixin ECS.System; 1490 1491 struct EntitiesData 1492 { 1493 uint length; 1494 @readonly CInt[] int_; 1495 } 1496 1497 void onUpdate(EntitiesData entities) 1498 { 1499 1500 } 1501 } 1502 1503 struct TestSystem2 1504 { 1505 mixin ECS.System; 1506 1507 struct EntitiesData 1508 { 1509 uint length; 1510 CInt[] int_; 1511 } 1512 1513 void onUpdate(EntitiesData entities) 1514 { 1515 1516 } 1517 } 1518 1519 struct TestSystem3 1520 { 1521 mixin ECS.System; 1522 1523 struct EntitiesData 1524 { 1525 uint length; 1526 @readonly CInt[] int_; 1527 } 1528 1529 void onUpdate(EntitiesData entities) 1530 { 1531 1532 } 1533 } 1534 1535 struct TestSystem4 1536 { 1537 mixin ECS.System; 1538 1539 struct EntitiesData 1540 { 1541 uint length; 1542 CInt[] int_; 1543 CLong[] long_; 1544 } 1545 1546 void onUpdate(EntitiesData entities) 1547 { 1548 1549 } 1550 } 1551 1552 struct TestSystem5 1553 { 1554 mixin ECS.System; 1555 1556 struct EntitiesData 1557 { 1558 uint length; 1559 @readonly CLong[] int_; 1560 } 1561 1562 void onUpdate(EntitiesData entities) 1563 { 1564 1565 } 1566 } 1567 1568 gEntityManager.beginRegister(); 1569 1570 gEntityManager.registerSystem!TestSystem(0); 1571 gEntityManager.registerSystem!TestSystem2(1); 1572 gEntityManager.registerSystem!TestSystem3(2); 1573 gEntityManager.registerSystem!TestSystem4(3); 1574 gEntityManager.registerSystem!TestSystem5(4); 1575 1576 gEntityManager.endRegister(); 1577 1578 const (EntityManager.UpdatePass)* pass = gEntityManager.getPass("update"); 1579 assert(pass != null); 1580 assert(pass.system_callers.length == 5); 1581 assert(pass.system_callers[0].system_id == becsID!TestSystem); 1582 assert(pass.system_callers[1].system_id == becsID!TestSystem2); 1583 assert(pass.system_callers[2].system_id == becsID!TestSystem3); 1584 assert(pass.system_callers[3].system_id == becsID!TestSystem4); 1585 assert(pass.system_callers[4].system_id == becsID!TestSystem5); 1586 assert(pass.system_callers[0].dependencies.length == 0); 1587 assert(pass.system_callers[1].dependencies.length == 1); 1588 assert(pass.system_callers[2].dependencies.length == 1); 1589 assert(pass.system_callers[3].dependencies.length == 3); 1590 assert(pass.system_callers[4].dependencies.length == 1); 1591 assert(pass.system_callers[1].dependencies[0].system_id == becsID!TestSystem); 1592 assert(pass.system_callers[2].dependencies[0].system_id == becsID!TestSystem2); 1593 assert(pass.system_callers[3].dependencies[0].system_id == becsID!TestSystem); 1594 assert(pass.system_callers[3].dependencies[1].system_id == becsID!TestSystem2); 1595 assert(pass.system_callers[3].dependencies[2].system_id == becsID!TestSystem3); 1596 assert(pass.system_callers[4].dependencies[0].system_id == becsID!TestSystem4); 1597 } 1598 1599 @("ExternalSystemDependencies") 1600 unittest 1601 { 1602 enum TestDependency = "TestDepencency"; 1603 1604 struct TestSystem 1605 { 1606 mixin ECS.System; 1607 1608 mixin ECS.ReadOnlyDependencies!(TestDependency); 1609 1610 struct EntitiesData 1611 { 1612 uint length; 1613 @readonly CInt[] int_; 1614 } 1615 1616 void onUpdate(EntitiesData entities) 1617 { 1618 1619 } 1620 } 1621 1622 struct TestSystem2 1623 { 1624 mixin ECS.System; 1625 1626 mixin ECS.WritableDependencies!(TestDependency); 1627 1628 struct EntitiesData 1629 { 1630 uint length; 1631 @readonly CInt[] int_; 1632 } 1633 1634 void onUpdate(EntitiesData entities) 1635 { 1636 1637 } 1638 } 1639 1640 struct TestSystem3 1641 { 1642 mixin ECS.System; 1643 1644 mixin ECS.ReadOnlyDependencies!(TestDependency); 1645 1646 struct EntitiesData 1647 { 1648 uint thread_id; 1649 } 1650 1651 void onUpdate(EntitiesData entities) 1652 { 1653 1654 } 1655 } 1656 1657 struct TestSystem4 1658 { 1659 mixin ECS.System; 1660 1661 mixin ECS.WritableDependencies!(TestDependency); 1662 1663 struct EntitiesData 1664 { 1665 uint length; 1666 @readonly CInt[] int_; 1667 } 1668 1669 void onUpdate(EntitiesData entities) 1670 { 1671 1672 } 1673 } 1674 1675 struct TestSystem5 1676 { 1677 mixin ECS.System; 1678 1679 mixin ECS.ReadOnlyDependencies!(TestDependency); 1680 1681 struct EntitiesData 1682 { 1683 uint length; 1684 @readonly CLong[] int_; 1685 } 1686 1687 void onUpdate(EntitiesData entities) 1688 { 1689 1690 } 1691 } 1692 1693 gEntityManager.beginRegister(); 1694 1695 gEntityManager.registerDependency(TestDependency); 1696 1697 gEntityManager.registerSystem!TestSystem(0); 1698 gEntityManager.registerSystem!TestSystem2(1); 1699 gEntityManager.registerSystem!TestSystem3(2); 1700 gEntityManager.registerSystem!TestSystem4(3); 1701 gEntityManager.registerSystem!TestSystem5(4); 1702 1703 gEntityManager.endRegister(); 1704 1705 const (EntityManager.UpdatePass)* pass = gEntityManager.getPass("update"); 1706 assert(pass != null); 1707 assert(pass.system_callers.length == 5); 1708 assert(pass.system_callers[0].system_id == becsID!TestSystem); 1709 assert(pass.system_callers[1].system_id == becsID!TestSystem2); 1710 assert(pass.system_callers[2].system_id == becsID!TestSystem3); 1711 assert(pass.system_callers[3].system_id == becsID!TestSystem4); 1712 assert(pass.system_callers[4].system_id == becsID!TestSystem5); 1713 assert(pass.system_callers[0].dependencies.length == 0); 1714 assert(pass.system_callers[1].dependencies.length == 1); 1715 assert(pass.system_callers[2].dependencies.length == 1); 1716 assert(pass.system_callers[3].dependencies.length == 3); 1717 assert(pass.system_callers[4].dependencies.length == 2); 1718 assert(pass.system_callers[1].dependencies[0].system_id == becsID!TestSystem); 1719 assert(pass.system_callers[2].dependencies[0].system_id == becsID!TestSystem2); 1720 assert(pass.system_callers[3].dependencies[0].system_id == becsID!TestSystem); 1721 assert(pass.system_callers[3].dependencies[1].system_id == becsID!TestSystem2); 1722 assert(pass.system_callers[3].dependencies[2].system_id == becsID!TestSystem3); 1723 assert(pass.system_callers[4].dependencies[0].system_id == becsID!TestSystem2); 1724 assert(pass.system_callers[4].dependencies[1].system_id == becsID!TestSystem4); 1725 } 1726 1727 1728 @("CustomFilter") 1729 unittest 1730 { 1731 struct TestSystem 1732 { 1733 mixin ECS.System; 1734 1735 struct EntitiesData 1736 { 1737 uint length; 1738 @optional CInt[] int_; 1739 @optional CLong[] long_; 1740 @optional CFloat[] float_; 1741 @optional CDouble[] double_; 1742 } 1743 1744 bool filterEntity(EntityManager.EntityInfo* info) 1745 { 1746 if(!info.hasComponent(becsID!CInt))return false; 1747 int one_from = 0; 1748 if(info.hasComponent(becsID!CLong))one_from++; 1749 if(info.hasComponent(becsID!CFloat))one_from++; 1750 if(info.hasComponent(becsID!CDouble))one_from++; 1751 if(one_from == 1)return true; 1752 return false; 1753 } 1754 1755 void onUpdate(EntitiesData entities) 1756 { 1757 updates++; 1758 } 1759 1760 uint updates = 0; 1761 } 1762 1763 struct TestSystem2 1764 { 1765 mixin ECS.System; 1766 1767 struct EntitiesData 1768 { 1769 uint length; 1770 @optional CInt[] int_; 1771 @optional CLong[] long_; 1772 @optional CFloat[] float_; 1773 @optional CDouble[] double_; 1774 } 1775 1776 bool filterEntity(EntityManager.EntityInfo* info) 1777 { 1778 if(info.hasComponent(becsID!CInt) && info.hasComponent(becsID!CFloat) && !info.hasComponent(becsID!CLong) && !info.hasComponent(becsID!CDouble))return true; 1779 if(info.hasComponent(becsID!CLong) && info.hasComponent(becsID!CDouble) && !info.hasComponent(becsID!CInt) && !info.hasComponent(becsID!CFloat))return true; 1780 return false; 1781 } 1782 1783 void onUpdate(EntitiesData entities) 1784 { 1785 updates++; 1786 } 1787 1788 uint updates = 0; 1789 } 1790 1791 gEntityManager.beginRegister(); 1792 1793 gEntityManager.registerSystem!TestSystem(0); 1794 gEntityManager.registerSystem!TestSystem2(1); 1795 1796 gEntityManager.endRegister(); 1797 1798 1799 EntityTemplate* tmpl_ = gEntityManager.allocateTemplate([becsID!CInt, becsID!CLong, becsID!CFloat, becsID!CDouble].staticArray); 1800 scope(exit)gEntityManager.freeTemplate(tmpl_); 1801 EntityTemplate* tmpl_2 = gEntityManager.allocateTemplate([becsID!CInt, becsID!CFloat].staticArray); 1802 scope(exit)gEntityManager.freeTemplate(tmpl_2); 1803 EntityTemplate* tmpl_3 = gEntityManager.allocateTemplate([becsID!CLong, becsID!CDouble].staticArray); 1804 scope(exit)gEntityManager.freeTemplate(tmpl_3); 1805 EntityTemplate* tmpl_4 = gEntityManager.allocateTemplate([becsID!CInt, becsID!CLong, becsID!CDouble].staticArray); 1806 scope(exit)gEntityManager.freeTemplate(tmpl_4); 1807 EntityTemplate* tmpl_5 = gEntityManager.allocateTemplate([becsID!CInt, becsID!CDouble].staticArray); 1808 scope(exit)gEntityManager.freeTemplate(tmpl_5); 1809 EntityTemplate* tmpl_6 = gEntityManager.allocateTemplate([becsID!CDouble].staticArray); 1810 scope(exit)gEntityManager.freeTemplate(tmpl_6); 1811 1812 gEntityManager.addEntity(tmpl_); 1813 gEntityManager.addEntity(tmpl_2); 1814 gEntityManager.addEntity(tmpl_3); 1815 gEntityManager.addEntity(tmpl_4); 1816 gEntityManager.addEntity(tmpl_5); 1817 gEntityManager.addEntity(tmpl_6); 1818 1819 TestSystem* test_system = gEntityManager.getSystem!TestSystem; 1820 TestSystem2* test_system2 = gEntityManager.getSystem!TestSystem2; 1821 1822 gEntityManager.begin(); 1823 gEntityManager.update(); 1824 gEntityManager.end(); 1825 1826 assert(test_system.updates == 2); 1827 assert(test_system2.updates == 2); 1828 }