1 module artemisd.entitysystem; 2 3 import std.bitmanip; 4 import std.algorithm; 5 import core.bitop; 6 import artemisd.utils.bag; 7 import artemisd.aspect; 8 import artemisd.entityobserver; 9 import artemisd.world; 10 import artemisd.entity; 11 import artemisd.utils.ext; 12 import artemisd.utils.type; 13 14 abstract class EntitySystem : EntityObserver 15 { 16 mixin TypeDecl; 17 18 private const int systemIndex; 19 20 protected World world; 21 22 private Bag!Entity actives; 23 24 private Aspect aspect; 25 26 private BitArray allSet; 27 private BitArray exclusionSet; 28 private BitArray oneSet; 29 30 private bool passive; 31 32 private bool dummy; 33 34 this(Aspect aspect) 35 { 36 actives = new Bag!Entity(); 37 this.aspect = aspect; 38 allSet = aspect.getAllSet(); 39 exclusionSet = aspect.getExclusionSet(); 40 oneSet = aspect.getOneSet(); 41 systemIndex = GetTypeId(); 42 dummy = allSet.isEmpty() && oneSet.isEmpty(); // This system can't possibly be interested in any entity, so it must be "dummy" 43 } 44 45 protected void begin() {} 46 47 final void process() 48 { 49 if(checkProcessing()) 50 { 51 begin(); 52 processEntities(actives); 53 end(); 54 } 55 } 56 57 protected void end() {} 58 59 protected void processEntities(Bag!Entity entities); 60 protected bool checkProcessing(); 61 62 void initialize() {}; 63 protected void inserted(Entity e) {}; 64 protected void removed(Entity e) {}; 65 66 protected final void check(Entity e) 67 { 68 if(dummy) return; 69 70 bool contains = e.getSystemBits()[systemIndex]; 71 bool interested = true; // possibly interested, let's try to prove it wrong. 72 73 BitArray componentBits = e.getComponentBits(); 74 75 // Check if the entity possesses ALL of the components defined in the aspect. 76 if(!allSet.isEmpty()) 77 { 78 for (auto i = allSet.nextSetBit(0); i >= 0; i = allSet.nextSetBit(i+1)) 79 { 80 if(!componentBits[i]) 81 { 82 interested = false; 83 break; 84 } 85 } 86 } 87 88 // Check if the entity possesses ANY of the exclusion components, if it does then the system is not interested. 89 if(!exclusionSet.isEmpty() && interested) 90 { 91 interested = !exclusionSet.intersects(componentBits); 92 } 93 94 // Check if the entity possesses ANY of the components in the oneSet. If so, the system is interested. 95 if(!oneSet.isEmpty()) 96 { 97 interested = oneSet.intersects(componentBits); 98 } 99 100 if (interested && !contains) 101 { 102 insertToSystem(e); 103 } 104 else if (!interested && contains) 105 { 106 removeFromSystem(e); 107 } 108 } 109 110 private final void removeFromSystem(Entity e) 111 { 112 actives.remove(e); 113 e.getSystemBits()[systemIndex]=0; 114 removed(e); 115 } 116 117 private final void insertToSystem(Entity e) 118 { 119 actives.add(e); 120 e.getSystemBits()[systemIndex] = 1; 121 inserted(e); 122 } 123 124 final override void added(Entity e) 125 { 126 check(e); 127 } 128 129 final override void changed(Entity e) 130 { 131 check(e); 132 } 133 134 final override void deleted(Entity e) 135 { 136 if(e.getSystemBits()[systemIndex]) 137 { 138 removeFromSystem(e); 139 } 140 } 141 142 final override void disabled(Entity e) 143 { 144 if(e.getSystemBits()[systemIndex]) 145 { 146 removeFromSystem(e); 147 } 148 } 149 150 final override void enabled(Entity e) 151 { 152 check(e); 153 } 154 155 final void setWorld(World world) 156 { 157 this.world = world; 158 } 159 160 final bool isPassive() 161 { 162 return passive; 163 } 164 165 final void setPassive(bool passive) 166 { 167 this.passive = passive; 168 } 169 170 final Bag!Entity getActives() 171 { 172 return actives; 173 } 174 }