1 module unecht.core.entity;
2 
3 import derelict.util.system;
4 
5 import unecht.core.components.sceneNode;
6 import unecht.core.object;
7 import unecht.core.serialization.serializer;
8 import unecht.core.stdex;
9 import unecht.ue;
10 import unecht.core.events;
11 
12 ///
13 enum UELayer : uint
14 {
15     all=0,
16     editor,
17 }
18 
19 ///
20 static immutable uint UECameraDefaultLayers = 0xffffffff ^ (1<<UELayer.editor);
21 
22 static assert(false == testBit(UECameraDefaultLayers,UELayer.editor));
23 static assert(true == testBit(UECameraDefaultLayers,UELayer.all));
24 
25 /// 
26 final class UEEntity : UEObject
27 {
28     import unecht.core.component:UERegisterObject,UEComponent;
29     import unecht.core.serialization.mixins:generateObjectSerializeFunc;
30     mixin(UERegisterObject!());
31 
32     @nogc @property{
33     	///
34         UESceneNode sceneNode() nothrow { return _sceneNode; } 
35         ///
36         const(UESceneNode) sceneNode() const nothrow { return _sceneNode; } 
37         ///
38         bool destroyed() nothrow { return _destroyed; } 
39     	///
40         string name() const { return _name; } 
41         ///
42         void name(string v) { _name = v; } 
43         ///
44         UELayer layer() const { return _layer; }
45         ///
46         void layer(UELayer layer) { _layer = layer; }
47     	///
48         UEComponent[] components() { return _components; } 
49     }
50 
51     ///
52     void broadcast(string _method,ARG)(ARG _arg)
53     {
54         import std..string:format;
55         foreach(component; _components)
56         {
57             enum mix = format("component.%s(_arg);",_method);
58             mixin(mix);
59         }
60     }
61 
62     ///
63     void broadcast(string _method)()
64     {
65         import std..string:format;
66         foreach(component; _components)
67         {
68             enum mix = format("component.%s();",_method);
69             
70             mixin(mix);
71         }
72     }
73 
74     //TODO: optimize ?
75     /// find first component of type T
76     @nogc auto getComponent(T : UEComponent)() nothrow
77     {
78         foreach(c; _components)
79         {
80             auto c2t = cast(T)c;
81             if(c2t)
82                 return c2t;
83         }
84 
85         return null;
86     }
87 
88     ///
89     @nogc bool hasComponent(T : UEComponent)() nothrow
90     {
91         return getComponent!T !is null;
92     }
93 
94 	///
95 	auto addComponent(T : UEComponent)()
96 	{
97 		auto newT = new T();
98 		auto newcomp = cast(UEComponent)newT;
99 
100 		addComponent(newcomp);
101 
102 		return newT;
103 	}
104 
105 	///
106 	UEComponent addComponent(string _type)
107 	{
108 		auto newcomp = cast(UEComponent)Object.factory(_type);
109 		assert(newcomp);
110 
111 		addComponent(newcomp);
112 
113 		return newcomp;
114 	}
115 
116     ///
117 	void removeComponent(UEComponent c)
118 	{
119 		import std.algorithm:countUntil,remove;
120 
121 		auto idx = _components.countUntil(c);
122 		if(idx > -1)
123 		{
124 			c.onDestroy();
125             ue.events.removeComponent(c);
126 			.destroy(c);
127 
128 			_components = _components.remove(idx);
129 		}
130 	}
131 
132 	/// factory method
133 	static auto create(string _name = null, UESceneNode _parent = null)
134 	{
135         return new UEEntity(_parent ? _parent : ue.scene.root, _name);
136 	}
137 
138     ///
139     static auto createForDeserialize()
140     {
141         return new UEEntity();
142     }
143 
144     ///
145     static void destroy(UEEntity entity)
146     {
147         assert(entity);
148         assert(entity._sceneNode.parent);
149         entity._destroyed = true;
150     }
151 
152     ///
153     static void destroyImmediate(UEEntity entity)
154     {
155         assert(entity);
156         entity.doDestroy();
157     }
158 
159     /// can go once ue is removed and we have DI
160     @property UEEvents events(){ return ue.events; }
161 
162 private:
163 
164     /// used for default construction in the deserializer
165     this()
166     {}
167 
168 	this(UESceneNode _parent, string _name)
169 	{
170 		if(_name)
171 			this._name = _name;
172 
173 		this._sceneNode = new UESceneNode();
174         addComponent(this._sceneNode);
175 
176 		this._sceneNode.parent = _parent;
177     }
178 
179 	void addComponent(UEComponent _comp)
180 	{
181 		_comp.setEntity(this);
182 
183 		_components ~= _comp;
184 
185 		_comp.onCreate();
186 	}
187 
188     void doDestroy()
189     {
190         while(_sceneNode.children.length > 0)
191         {
192             auto child = _sceneNode.children[0];
193 
194             assert(child.entity);
195             child.entity.doDestroy();
196         }
197 
198         //unparenting of local components
199         broadcast!("onDestroy")();
200 
201         _destroyed = true;
202         _sceneNode = null;
203         _name = null;
204 
205         foreach(component; _components)
206         {
207             component.setEntity(null);
208             ue.events.removeComponent(component);
209             .destroy(component);
210         }
211         _components.length = 0;
212     }
213 	
214 private:
215     //TODO: non public as soon as @Serialize works
216     @Serialize
217 	string _name = "entity";
218 
219     bool _destroyed = false;
220 
221     //TODO: non public as soon as @Serialize works
222     @Serialize
223     UELayer _layer = UELayer.all;
224 
225     @Serialize
226 	UESceneNode _sceneNode;
227 	
228     //TODO: non public as soon as @Serialize works
229     @Serialize
230 	UEComponent[] _components;
231 }