1 /* 2 __ 3 / _| 4 __ _ _ _ _ __ ___ _ __ __ _ | |_ ___ ___ ___ 5 / _` | | | | '__/ _ \| '__/ _` | | _/ _ \/ __/ __| 6 | (_| | |_| | | | (_) | | | (_| | | || (_) \__ \__ \ 7 \__,_|\__,_|_| \___/|_| \__,_| |_| \___/|___/___/ 8 9 Copyright (C) 2019 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 48 final class SystemHandlingException : Exception 49 { 50 mixin basicExceptionCtors; 51 } 52 53 54 class SystemManager 55 { 56 // unittesting only 57 @safe pure 58 private this() 59 {} 60 61 @safe pure 62 public this(EntityManager entity) 63 { 64 _entity = entity; 65 } 66 67 68 /** 69 * Create a new system 70 * 71 * Examples: 72 * -------------------- 73 * world.system.create(new FooSystem()); 74 * -------------------- 75 * 76 * SeeAlso: create(S : System)() 77 */ 78 @safe pure 79 public void create(S : System)(S s) 80 { 81 enum id = fullyQualifiedName!S; 82 83 if (id in this.systems) 84 throw new SystemHandlingException( 85 "Cannot add system. " ~ __traits(identifier, S) ~ " is already created!" 86 ); 87 88 s.manager = this; 89 this.systems[id] = s; 90 } 91 92 93 /** 94 * Create a new System 95 * 96 * Examples: 97 * -------------------- 98 * world.system.create!FooSystem; 99 * -------------------- 100 */ 101 @safe pure 102 public void create(S : System)() 103 { 104 create(new S()); 105 } 106 107 108 /** 109 * Get a system 110 * 111 * Returns: the type you're passing 112 * 113 * Examples: 114 * -------------------- 115 * world.system.get!FooSystem 116 * -------------------- 117 */ 118 @safe pure 119 public S get(S : System)() 120 { 121 enum id = fullyQualifiedName!S; 122 System* p; 123 p = id in this.systems; 124 125 return p !is null ? cast(S)(*p) : null; 126 } 127 128 129 /** 130 * Remove 131 * 132 * Deletes a system from the world's scope 133 * 134 * Examples: 135 * -------------------- 136 * world.system.remove!FooSystem 137 * -------------------- 138 */ 139 @safe pure 140 public void remove(S : System)() 141 { 142 enum id = fullyQualifiedName!S; 143 144 if (id in this.systems) 145 this.systems.remove(id); 146 147 else 148 throw new SystemHandlingException( 149 "Cannot remove system. " ~ __traits(identifier, S) ~ " was already removed or it wasn't created!" 150 ); 151 } 152 153 154 /** 155 * Clear 156 * 157 * Deletes every system in the world's scope 158 * 159 * Examples: 160 * -------------------- 161 * world.system.clear(); 162 * -------------------- 163 */ 164 @safe pure 165 public void clear() 166 { 167 foreach(key, value; this.systems) 168 this.systems.remove(key); 169 } 170 171 172 /** 173 * Update 174 * 175 * Updates every component with the Automatic Update Policy 176 * 177 * Examples: 178 * -------------------- 179 * world.system.update(); 180 * -------------------- 181 */ 182 @safe pure 183 public void update() 184 { 185 foreach(System s; this.systems) 186 if (s.updatePolicy == s.UpdatePolicy.Automatic) 187 s.update(); 188 } 189 190 191 /** 192 * Update 193 * 194 * Updates any system passed 195 * It's useful when you only want to update systems manualy 196 * 197 * Examples: 198 * -------------------- 199 * world.system.update!FooSystem; 200 * -------------------- 201 */ 202 @safe pure 203 public void update(S : System)() 204 { 205 this.systems[fullyQualifiedName!S].update(); 206 } 207 208 209 @safe pure 210 public EntityManager entity() { return _entity; } @property 211 212 213 private EntityManager _entity; 214 private System[string] systems; 215 } 216 217 218 version(unittest) 219 { 220 private class unittest_FooSystem : System 221 { 222 override public void update() { this.updatePolicy = UpdatePolicy.Manual; } 223 } 224 225 private class unittest_BarSystem : System 226 { 227 @safe pure 228 public this () { super(UpdatePolicy.Manual); } 229 230 override public void update() { this.updatePolicy = UpdatePolicy.Automatic; } 231 } 232 } 233 234 235 /// 236 @safe pure 237 @("System Manager: System creation") 238 unittest 239 { 240 SystemManager system = new SystemManager(); 241 242 system.create(new unittest_FooSystem()); 243 244 import std.traits : ReturnType; 245 assertTrue(is(ReturnType!(system.get!unittest_FooSystem) == unittest_FooSystem)); 246 247 assertThrown!SystemHandlingException(system.create(new unittest_FooSystem())); // System created twice 248 } 249 250 251 /// 252 @safe pure 253 @("System Manager: Accessing system properties") 254 unittest 255 { 256 SystemManager system = new SystemManager(); 257 258 system.create(new unittest_FooSystem()); 259 260 import std.traits : ReturnType; 261 assertTrue((system.get!(unittest_FooSystem)).manager is system); 262 assertTrue(is(ReturnType!(system.get!unittest_FooSystem) == unittest_FooSystem)); 263 assertTrue(system.get!(unittest_BarSystem) is null); // System wasn't created 264 } 265 266 267 /// 268 @safe pure 269 @("System Manager: System update") 270 unittest 271 { 272 SystemManager system = new SystemManager(); 273 274 unittest_FooSystem fooSys = new unittest_FooSystem(); 275 unittest_BarSystem barSys = new unittest_BarSystem(); 276 system.create(fooSys); 277 system.create(barSys); 278 279 assertEquals(fooSys.updatePolicy, fooSys.UpdatePolicy.Automatic); 280 assertEquals(barSys.updatePolicy, barSys.UpdatePolicy.Manual); 281 282 system.update(); // Only updates systems with Automatic Update Policy 283 284 assertEquals(fooSys.updatePolicy, fooSys.UpdatePolicy.Manual); // Got updated 285 assertEquals(barSys.updatePolicy, barSys.UpdatePolicy.Manual); // Didn't get updated 286 287 system.update!unittest_BarSystem; // Systems can be updated manualy 288 289 assertEquals(barSys.updatePolicy, barSys.UpdatePolicy.Automatic); // Got updated 290 } 291 292 293 /// 294 @safe pure 295 @("System Manager: System clear") 296 unittest 297 { 298 SystemManager system = new SystemManager(); 299 300 system.create!unittest_FooSystem; 301 system.clear(); 302 303 assertEquals(0, system.systems.length); 304 }