1 /* 2 __ 3 / _| 4 __ _ _ _ _ __ ___ _ __ __ _ | |_ ___ ___ ___ 5 / _` | | | | '__/ _ \| '__/ _` | | _/ _ \/ __/ __| 6 | (_| | |_| | | | (_) | | | (_| | | || (_) \__ \__ \ 7 \__,_|\__,_|_| \___/|_| \__,_| |_| \___/|___/___/ 8 9 Copyright (C) 2019-2020 Aurora Free Open Source Software. 10 Copyright (C) 2019 João Lourenço <joao@aurorafoss.org> 11 12 This file is part of the Aurora Free Open Source Software. This 13 organization promote free and open source software that you can 14 redistribute and/or modify under the terms of the GNU Lesser General 15 Public License Version 3 as published by the Free Software Foundation or 16 (at your option) any later version approved by the Aurora Free Open Source 17 Software Organization. The license is available in the package root path 18 as 'LICENSE' file. Please review the following information to ensure the 19 GNU Lesser General Public License version 3 requirements will be met: 20 https://www.gnu.org/licenses/lgpl.html . 21 22 Alternatively, this file may be used under the terms of the GNU General 23 Public License version 3 or later as published by the Free Software 24 Foundation. Please review the following information to ensure the GNU 25 General Public License requirements will be met: 26 https://www.gnu.org/licenses/gpl-3.0.html. 27 28 NOTE: All products, services or anything associated to trademarks and 29 service marks used or referenced on this file are the property of their 30 respective companies/owners or its subsidiaries. Other names and brands 31 may be claimed as the property of others. 32 33 For more info about intellectual property visit: aurorafoss.org or 34 directly send an email to: contact (at) aurorafoss.org . 35 */ 36 37 module aurorafw.entity.systemmanager; 38 39 import aurorafw.entity.system; 40 import aurorafw.entity.entitymanager; 41 42 version (unittest) import aurorafw.unit.assertion; 43 44 import std.traits : fullyQualifiedName; 45 import std.exception; 46 47 final class SystemHandlingException : Exception 48 { 49 mixin basicExceptionCtors; 50 } 51 52 class SystemManager 53 { 54 // unittesting only 55 @safe pure 56 private this() 57 { 58 } 59 60 @safe pure 61 public this(EntityManager entity) 62 { 63 _entity = entity; 64 } 65 66 /** 67 * Create a new system 68 * 69 * Examples: 70 * -------------------- 71 * world.system.create(new FooSystem()); 72 * -------------------- 73 * 74 * SeeAlso: create(S : System)() 75 */ 76 public void create(S : System)(S system) 77 { 78 enum id = fullyQualifiedName!S; 79 80 if (id in this.systems) 81 throw new SystemHandlingException( 82 "Cannot add system. " ~ __traits(identifier, S) ~ " is already created!" 83 ); 84 85 system.manager = this; 86 this.systems[id] = system; 87 } 88 89 /** 90 * Create a new System 91 * 92 * Examples: 93 * -------------------- 94 * world.system.create!FooSystem; 95 * -------------------- 96 */ 97 public void create(S : System)() 98 { 99 create(new S()); 100 } 101 102 /** 103 * Get a system 104 * 105 * Returns: the type you're passing 106 * 107 * Examples: 108 * -------------------- 109 * world.system.get!FooSystem 110 * -------------------- 111 */ 112 @safe pure 113 public S get(S : System)() 114 { 115 enum id = fullyQualifiedName!S; 116 System* p; 117 p = id in this.systems; 118 119 return p !is null ? cast(S)(*p) : null; 120 } 121 122 /** 123 * Remove 124 * 125 * Deletes a system from the world's scope 126 * 127 * Examples: 128 * -------------------- 129 * world.system.remove!FooSystem 130 * -------------------- 131 */ 132 @safe 133 public void remove(S : System)() 134 { 135 enum id = fullyQualifiedName!S; 136 137 if (id in this.systems) 138 this.systems.remove(id); 139 140 else 141 throw new SystemHandlingException( 142 "Cannot remove system. " ~ __traits(identifier, S) ~ " was already removed or it wasn't created!" 143 ); 144 } 145 146 /** 147 * Clear 148 * 149 * Deletes every system in the world's scope 150 * 151 * Examples: 152 * -------------------- 153 * world.system.clear(); 154 * -------------------- 155 */ 156 @safe pure 157 public void clear() 158 { 159 foreach (key, value; this.systems) 160 this.systems.remove(key); 161 } 162 163 /** 164 * Update 165 * 166 * Updates every component with the Automatic Update Policy 167 * 168 * Examples: 169 * -------------------- 170 * world.system.update(); 171 * -------------------- 172 */ 173 public void update() 174 { 175 foreach (System s; this.systems) 176 if (s.updatePolicy == s.UpdatePolicy.Automatic) 177 s.update(); 178 } 179 180 /** 181 * Update 182 * 183 * Updates any system passed 184 * It's useful when you only want to update systems manualy 185 * 186 * Examples: 187 * -------------------- 188 * world.system.update!FooSystem; 189 * -------------------- 190 */ 191 public void update(S : System)() 192 { 193 this.systems[fullyQualifiedName!S].update(); 194 } 195 196 /** 197 * Entity 198 * 199 * Returns the entity manager 200 * 201 * Examples: 202 * -------------------- 203 * auto entity = entity; 204 * -------------------- 205 */ 206 @safe pure 207 public EntityManager entity() 208 { 209 return _entity; 210 } 211 212 @property 213 214 private EntityManager _entity; 215 private System[string] systems; 216 } 217 218 version (unittest) 219 { 220 private class unittest_FooSystem : System 221 { 222 @safe 223 override public void update() 224 { 225 this.updatePolicy = UpdatePolicy.Manual; 226 } 227 } 228 229 private class unittest_BarSystem : System 230 { 231 @safe pure 232 public this() 233 { 234 super(UpdatePolicy.Manual); 235 } 236 237 @safe 238 override public void update() 239 { 240 this.updatePolicy = UpdatePolicy.Automatic; 241 } 242 } 243 } 244 245 /// 246 @safe pure 247 @("System Manager: System creation") 248 unittest 249 { 250 SystemManager system = new SystemManager(); 251 252 system.create(new unittest_FooSystem()); 253 254 import std.traits : ReturnType; 255 256 assertTrue(is(ReturnType!(system.get!unittest_FooSystem) == unittest_FooSystem)); 257 258 assertThrown!SystemHandlingException(system.create(new unittest_FooSystem())); // System created twice 259 } 260 261 /// 262 @safe pure 263 @("System Manager: Accessing system properties") 264 unittest 265 { 266 SystemManager system = new SystemManager(); 267 268 system.create(new unittest_FooSystem()); 269 270 import std.traits : ReturnType; 271 272 assertTrue((system.get!(unittest_FooSystem)).manager is system); 273 assertTrue(is(ReturnType!(system.get!unittest_FooSystem) == unittest_FooSystem)); 274 assertTrue(system.get!(unittest_BarSystem) is null); // System wasn't created 275 } 276 277 /// 278 @("System Manager: System update") 279 unittest 280 { 281 SystemManager system = new SystemManager(); 282 283 unittest_FooSystem fooSys = new unittest_FooSystem(); 284 unittest_BarSystem barSys = new unittest_BarSystem(); 285 system.create(fooSys); 286 system.create(barSys); 287 288 assertEquals(fooSys.updatePolicy, fooSys.UpdatePolicy.Automatic); 289 assertEquals(barSys.updatePolicy, barSys.UpdatePolicy.Manual); 290 291 system.update(); // Only updates systems with Automatic Update Policy 292 293 assertEquals(fooSys.updatePolicy, fooSys.UpdatePolicy.Manual); // Got updated 294 assertEquals(barSys.updatePolicy, barSys.UpdatePolicy.Manual); // Didn't get updated 295 296 system.update!unittest_BarSystem; // Systems can be updated manualy 297 298 assertEquals(barSys.updatePolicy, barSys.UpdatePolicy.Automatic); // Got updated 299 } 300 301 /// 302 @safe pure 303 @("System Manager: System clear") 304 unittest 305 { 306 SystemManager system = new SystemManager(); 307 308 system.create!unittest_FooSystem; 309 system.clear(); 310 311 assertEquals(0, system.systems.length); 312 }