1 module unecht.core.component;
2 
3 import derelict.util.system;
4 
5 public import unecht.core.serialization.serializer;
6 public import unecht.core.serialization.mixins;
7 import unecht.core.events:UEEventType;
8 import unecht.core.entity;
9 import unecht.core.components.sceneNode;
10 import unecht.core.object;
11 
12 ///
13 template UEObjectCreateMenuItem()
14 {
15     enum UEObjectCreateMenuItem = q{
16         static if(!is(typeof(this) == UEComponent) && is(typeof(this) : UEComponent))
17         {
18             version(UEIncludeEditor)import unecht.core.components.editor.menus;
19             version(UEIncludeEditor)import unecht.meta.uda;
20             
21             version(UEIncludeEditor)override void getMenuItems(ref EditorMenuItem[] items)
22             {
23                 super.getMenuItems(items);
24                 
25                 alias T = typeof(this);
26                 
27                 foreach(m; __traits(derivedMembers, T))
28                 {
29                     static if(__traits(isStaticFunction, __traits(getMember, T, m)))
30                     {
31                         static if(hasUDA!(__traits(getMember, T, m), MenuItem))
32                         {
33                             alias MemberType = typeof(&__traits(getMember, T, m));
34                             
35                             static if(is(MemberType : MenuItemFunc))
36                             {
37                                 alias uda = getUDA!(__traits(getMember, T, m), MenuItem);
38                                 
39                                 items ~= EditorMenuItem(uda.name, &__traits(getMember, T, m), uda.validate);
40                             }
41                             else
42                             {
43                                 static assert(false, format("%s.%s is annotated as MenuItem but has type: '%s' expected '%s'",
44                                         T.stringof,m,MemberType.stringof,MenuItemFunc.stringof));
45                             }
46                         }
47                     }
48                 }
49             }
50         }
51     };
52 }
53 
54 ///
55 template UEObjectSerialization()
56 {
57     enum UEObjectSerialization = q{
58 
59         private{
60             mixin generateObjectSerializeFunc!(serializeMember, UESerializer, "serialize");
61             mixin generateObjectSerializeFunc!(deserializeMember, UEDeserializer, "deserialize");
62 
63             void serializeMember(T,M)(string m,ref M member, ref UESerializer serializer, UECustomFuncSerialize!M customFunc=null)
64             {
65                 serializer.serializeObjectMember!(T,M)(this, m, member, customFunc);
66             }
67 
68             void deserializeMember(T,M)(string m, ref M member, ref UEDeserializer serializer, UECustomFuncDeserialize!M customFunc=null)
69             {
70                 serializer.deserializeObjectMember!(T,M)(this, this.instanceId.toString(), m, member, customFunc);
71             }
72         }
73 
74         override void serialize(ref UESerializer serializer) 
75         {
76             import unecht.core.hideFlags;
77             if(hideFlags.isSet(HideFlags.dontSaveInScene))
78                 return;
79 
80             alias T = typeof(this);
81 
82             iterateAllSerializables!(T)(this, serializer);
83 
84             super.serialize(serializer);
85         }
86 
87         override void deserialize(ref UEDeserializer serializer, string uid=null) 
88         {
89             super.deserialize(serializer,uid);
90             
91             alias T = typeof(this);
92 
93             iterateAllSerializables!(T)(this, serializer);
94         }
95     };
96 }
97 
98 ///
99 template UEObjectCreateEditor()
100 {
101     enum UEObjectCreateEditor = q{
102 
103         version(UEIncludeEditor)import unecht.core.componentManager:IComponentEditor;
104 
105         version(UEIncludeEditor)
106         override IComponentEditor createEditor()
107         {
108             import unecht.core.defaultInspector;
109             
110             alias T = typeof(this);
111 
112             static UEDefaultInspector!T editor;
113 
114             if(editor is null)
115                 editor = new UEDefaultInspector!T();
116 
117             return editor;
118         }
119     };
120 }
121 
122 ///
123 template UERegisterObject()
124 {
125     enum UERegisterObject = 
126         UEObjectSerialization!() 
127         ~ UEObjectCreateMenuItem!() 
128         ~ UEObjectCreateEditor!() 
129         ~ q{version(UEIncludeEditor)override @property string typename() { return typeof(this).stringof; }};
130 }
131 
132 /// binding component between an GameEntity and a SceneNode
133 abstract class UEComponent : UEObject
134 {
135     import unecht.core.events:UEEventCallback,UEEventReceiver;
136 
137     mixin(UERegisterObject!());
138 
139 	//void OnEnable() {}
140     ///
141 	void onUpdate() {}
142 	//void OnDisable() {}
143 	
144     ///
145 	void onCreate() {}
146     ///
147     void onDestroy() {}
148     ///
149     void onCollision(UEComponent /+_collider+/) {}
150 	
151     @nogc final nothrow {
152     	///
153     	@property bool enabled() const { return _enabled; }
154     	///
155     	@property void enabled(bool _value) { _enabled = _value; }
156     	///
157     	@property UEEntity entity() { return _entity; }
158     	///
159     	@property UESceneNode sceneNode() { return _entity.sceneNode; }
160     }
161 	
162 	/// helper
163 	final void registerEvent(UEEventType _type, UEEventCallback _callback)
164 	{
165 		_entity.events.register(UEEventReceiver(this,_type,_callback));
166 	}
167 
168     version(UEIncludeEditor){
169         import unecht.core.components.editor.menus:EditorMenuItem;
170         ///
171         void getMenuItems(ref EditorMenuItem[] items){}
172     }
173 
174 package:
175     ///
176 	final void setEntity(UEEntity _entity) { this._entity = _entity; }
177 
178 private:
179     @Serialize
180 	UEEntity _entity;
181 
182 	//TODO: disabled by default
183     @Serialize
184 	bool _enabled = true;
185 }