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