Fix syntax for ID keyword.
[blender-staging.git] / source / gameengine / Ketsji / KX_PythonSeq.cpp
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21  * All rights reserved.
22  *
23  * The Original Code is: none of this file.
24  *
25  * Contributor(s): Campbell Barton
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  * Readonly sequence wrapper for lookups on logic bricks
29  */
30
31 #ifndef DISABLE_PYTHON
32
33 #include "KX_PythonSeq.h"
34 #include "KX_GameObject.h"
35 #include "BL_ArmatureObject.h"
36 #include "SCA_ISensor.h"
37 #include "SCA_IController.h"
38 #include "SCA_IActuator.h"
39
40
41 PyObject *KX_PythonSeq_CreatePyObject( PyObject *base, short type )
42 {
43         KX_PythonSeq *seq = PyObject_NEW( KX_PythonSeq, &KX_PythonSeq_Type);
44         seq->base = base;
45         Py_INCREF(base); /* so we can always access to check if its valid */
46         seq->type = type;
47         seq->iter = -1; /* init */
48         return (PyObject *)seq;
49  }
50  
51  static void KX_PythonSeq_dealloc( KX_PythonSeq * self )
52 {
53         Py_DECREF(self->base);
54         PyObject_DEL( self );
55 }
56
57 static Py_ssize_t KX_PythonSeq_len( PyObject * self )
58 {
59         PyObjectPlus *self_plus= BGE_PROXY_REF(((KX_PythonSeq *)self)->base);
60          
61         if(self_plus==NULL) {
62                 PyErr_SetString(PyExc_SystemError, "len(seq): "BGE_PROXY_ERROR_MSG);
63                 return -1;
64         }
65         
66         switch(((KX_PythonSeq *)self)->type) {
67         case KX_PYGENSEQ_CONT_TYPE_SENSORS:
68                 return ((SCA_IController *)self_plus)->GetLinkedSensors().size();
69         case KX_PYGENSEQ_CONT_TYPE_ACTUATORS:
70                 return ((SCA_IController *)self_plus)->GetLinkedActuators().size();
71         case KX_PYGENSEQ_OB_TYPE_SENSORS:
72                 return ((KX_GameObject *)self_plus)->GetSensors().size();
73         case KX_PYGENSEQ_OB_TYPE_CONTROLLERS:
74                 return ((KX_GameObject *)self_plus)->GetControllers().size();
75         case KX_PYGENSEQ_OB_TYPE_ACTUATORS:
76                 return ((KX_GameObject *)self_plus)->GetActuators().size();
77         case KX_PYGENSEQ_OB_TYPE_CONSTRAINTS:
78                 return ((BL_ArmatureObject *)self_plus)->GetConstraintNumber();
79         case KX_PYGENSEQ_OB_TYPE_CHANNELS:
80                 return ((BL_ArmatureObject *)self_plus)->GetChannelNumber();
81         default:
82                 /* Should never happen */
83                 PyErr_SetString(PyExc_SystemError, "invalid type, internal error");
84                 return -1;
85         }
86 }
87
88 static PyObject *KX_PythonSeq_getIndex(PyObject* self, int index)
89 {
90         PyObjectPlus *self_plus= BGE_PROXY_REF(((KX_PythonSeq *)self)->base);
91          
92         if(self_plus==NULL) {
93                 PyErr_SetString(PyExc_SystemError, "val = seq[i]: "BGE_PROXY_ERROR_MSG);
94                 return NULL;
95         }
96         
97         switch(((KX_PythonSeq *)self)->type) {
98                 case KX_PYGENSEQ_CONT_TYPE_SENSORS:
99                 {
100                         vector<SCA_ISensor*>& linkedsensors = ((SCA_IController *)self_plus)->GetLinkedSensors();
101                         if(index<0) index += linkedsensors.size();
102                         if(index<0 || index>= linkedsensors.size()) {
103                                 PyErr_SetString(PyExc_IndexError, "seq[i]: index out of range");
104                                 return NULL;
105                         }
106                         return linkedsensors[index]->GetProxy();
107                 }
108                 case KX_PYGENSEQ_CONT_TYPE_ACTUATORS:
109                 {
110                         vector<SCA_IActuator*>& linkedactuators = ((SCA_IController *)self_plus)->GetLinkedActuators();
111                         if(index<0) index += linkedactuators.size();
112                         if(index<0 || index>= linkedactuators.size()) {
113                                 PyErr_SetString(PyExc_IndexError, "seq[i]: index out of range");
114                                 return NULL;
115                         }
116                         return linkedactuators[index]->GetProxy();
117                 }
118                 case KX_PYGENSEQ_OB_TYPE_SENSORS:
119                 {
120                         SCA_SensorList& linkedsensors= ((KX_GameObject *)self_plus)->GetSensors();
121                         if(index<0) index += linkedsensors.size();
122                         if(index<0 || index>= linkedsensors.size()) {
123                                 PyErr_SetString(PyExc_IndexError, "seq[i]: index out of range");
124                                 return NULL;
125                         }
126                         return linkedsensors[index]->GetProxy();
127                 }
128                 case KX_PYGENSEQ_OB_TYPE_CONTROLLERS:
129                 {
130                         SCA_ControllerList& linkedcontrollers= ((KX_GameObject *)self_plus)->GetControllers();
131                         if(index<0) index += linkedcontrollers.size();
132                         if(index<0 || index>= linkedcontrollers.size()) {
133                                 PyErr_SetString(PyExc_IndexError, "seq[i]: index out of range");
134                                 return NULL;
135                         }
136                         return linkedcontrollers[index]->GetProxy();
137                 }
138                 case KX_PYGENSEQ_OB_TYPE_ACTUATORS:
139                 {
140                         SCA_ActuatorList& linkedactuators= ((KX_GameObject *)self_plus)->GetActuators();
141                         if(index<0) index += linkedactuators.size();
142                         if(index<0 || index>= linkedactuators.size()) {
143                                 PyErr_SetString(PyExc_IndexError, "seq[i]: index out of range");
144                                 return NULL;
145                         }
146                         return linkedactuators[index]->GetProxy();
147                 }
148                 case KX_PYGENSEQ_OB_TYPE_CONSTRAINTS:
149                 {
150                         int nb_constraint = ((BL_ArmatureObject *)self_plus)->GetConstraintNumber();
151                         if(index<0) 
152                                 index += nb_constraint;
153                         if(index<0 || index>= nb_constraint) {
154                                 PyErr_SetString(PyExc_IndexError, "seq[i]: index out of range");
155                                 return NULL;
156                         }
157                         return ((BL_ArmatureObject *)self_plus)->GetConstraint(index)->GetProxy();
158                 }
159                 case KX_PYGENSEQ_OB_TYPE_CHANNELS:
160                 {
161                         int nb_channel = ((BL_ArmatureObject *)self_plus)->GetChannelNumber();
162                         if(index<0) 
163                                 index += nb_channel;
164                         if(index<0 || index>= nb_channel) {
165                                 PyErr_SetString(PyExc_IndexError, "seq[i]: index out of range");
166                                 return NULL;
167                         }
168                         return ((BL_ArmatureObject *)self_plus)->GetChannel(index)->GetProxy();
169                 }
170
171         }
172         
173         PyErr_SetString(PyExc_SystemError, "invalid sequence type, this is a bug");
174         return NULL;
175 }
176
177 static PyObjectPlus * KX_PythonSeq_subscript__internal(PyObject *self, char *key)
178 {
179         PyObjectPlus *self_plus= BGE_PROXY_REF(((KX_PythonSeq *)self)->base);
180         
181         switch(((KX_PythonSeq *)self)->type) {
182                 case KX_PYGENSEQ_CONT_TYPE_SENSORS:
183                 {
184                         vector<SCA_ISensor*>& linkedsensors = ((SCA_IController *)self_plus)->GetLinkedSensors();
185                         SCA_ISensor* sensor;
186                         for (unsigned int index=0;index<linkedsensors.size();index++) {
187                                 sensor = linkedsensors[index];
188                                 if (sensor->GetName() == key)
189                                         return static_cast<PyObjectPlus *>(sensor);
190                                 
191                         }
192                         break;
193                 }
194                 case KX_PYGENSEQ_CONT_TYPE_ACTUATORS:
195                 {
196                         vector<SCA_IActuator*>& linkedactuators = ((SCA_IController *)self_plus)->GetLinkedActuators();
197                         SCA_IActuator* actuator;
198                         for (unsigned int index=0;index<linkedactuators.size();index++) {
199                                 actuator = linkedactuators[index];
200                                 if (actuator->GetName() == key)
201                                         return static_cast<PyObjectPlus *>(actuator);
202                         }
203                         break;
204                 }
205                 case KX_PYGENSEQ_OB_TYPE_SENSORS:
206                 {
207                         SCA_SensorList& linkedsensors= ((KX_GameObject *)self_plus)->GetSensors();
208                         SCA_ISensor *sensor;
209                         for (unsigned int index=0;index<linkedsensors.size();index++) {
210                                 sensor= linkedsensors[index];
211                                 if (sensor->GetName() == key)
212                                         return static_cast<PyObjectPlus *>(sensor);
213                         }
214                         break;
215                 }
216                 case KX_PYGENSEQ_OB_TYPE_CONTROLLERS:
217                 {
218                         SCA_ControllerList& linkedcontrollers= ((KX_GameObject *)self_plus)->GetControllers();
219                         SCA_IController *controller;
220                         for (unsigned int index=0;index<linkedcontrollers.size();index++) {
221                                 controller= linkedcontrollers[index];
222                                 if (controller->GetName() == key)
223                                         return static_cast<PyObjectPlus *>(controller);
224                         }
225                         break;
226                 }
227                 case KX_PYGENSEQ_OB_TYPE_ACTUATORS:
228                 {
229                         SCA_ActuatorList& linkedactuators= ((KX_GameObject *)self_plus)->GetActuators();
230                         SCA_IActuator *actuator;
231                         for (unsigned int index=0;index<linkedactuators.size();index++) {
232                                 actuator= linkedactuators[index];
233                                 if (actuator->GetName() == key)
234                                         return static_cast<PyObjectPlus *>(actuator);
235                         }
236                         break;
237                 }
238                 case KX_PYGENSEQ_OB_TYPE_CONSTRAINTS:
239                 {
240                         return ((BL_ArmatureObject*)self_plus)->GetConstraint(key);
241                 }
242                 case KX_PYGENSEQ_OB_TYPE_CHANNELS:
243                 {
244                         return ((BL_ArmatureObject*)self_plus)->GetChannel(key);
245                 }
246         }
247         
248         return NULL;
249 }
250
251
252 static PyObject * KX_PythonSeq_subscript(PyObject * self, PyObject *key)
253 {
254         PyObjectPlus *self_plus= BGE_PROXY_REF(((KX_PythonSeq *)self)->base);
255         
256         if(self_plus==NULL) {
257                 PyErr_SetString(PyExc_SystemError, "val = seq[key], KX_PythonSeq: "BGE_PROXY_ERROR_MSG);
258                 return NULL;
259         }
260         
261         if (PyLong_Check(key)) {
262                 return KX_PythonSeq_getIndex(self, PyLong_AsSsize_t( key ));
263         }
264         else if ( PyUnicode_Check(key) ) {
265                 char *name = _PyUnicode_AsString(key);
266                 PyObjectPlus *ret = KX_PythonSeq_subscript__internal(self, name);
267                 
268                 if(ret) {
269                         return ret->GetProxy();
270                 } else {
271                         PyErr_Format( PyExc_KeyError, "requested item \"%s\" does not exist", name);
272                         return NULL;
273                 }
274         }
275         else {
276                 PyErr_SetString( PyExc_TypeError, "expected a string or an index" );
277                 return NULL;
278         }
279 }
280
281
282 static int KX_PythonSeq_contains(PyObject *self, PyObject *key)
283 {
284         PyObjectPlus *self_plus= BGE_PROXY_REF(((KX_PythonSeq *)self)->base);
285         
286         if(self_plus==NULL) {
287                 PyErr_SetString(PyExc_SystemError, "key in seq, KX_PythonSeq: "BGE_PROXY_ERROR_MSG);
288                 return -1;
289         }
290         if(!PyUnicode_Check(key)) {
291                 PyErr_SetString(PyExc_SystemError, "key in seq, KX_PythonSeq: key must be a string");
292                 return -1;
293         }
294         
295         if(KX_PythonSeq_subscript__internal(self, _PyUnicode_AsString(key)))
296                 return 1;
297         
298         return 0;
299 }
300
301 /* Matches python dict.get(key, [default]) */
302 PyObject* KX_PythonSeq_get(PyObject * self, PyObject *args)
303 {
304         char *key;
305         PyObject* def = Py_None;
306         PyObjectPlus* ret_plus;
307
308         if (!PyArg_ParseTuple(args, "s|O:get", &key, &def))
309                 return NULL;
310         
311         if((ret_plus = KX_PythonSeq_subscript__internal(self, key)))
312                 return ret_plus->GetProxy();
313         
314         Py_INCREF(def);
315         return def;
316 }
317
318 PySequenceMethods KX_PythonSeq_as_sequence = {
319         NULL,           /* Cant set the len otherwise it can evaluate as false */
320         NULL,           /* sq_concat */
321         NULL,           /* sq_repeat */
322         NULL,           /* sq_item */
323         NULL,           /* sq_slice */
324         NULL,           /* sq_ass_item */
325         NULL,           /* sq_ass_slice */
326         (objobjproc)KX_PythonSeq_contains,      /* sq_contains */
327 };
328
329 static PyMappingMethods KX_PythonSeq_as_mapping = {
330         KX_PythonSeq_len,       /* mp_length */
331         KX_PythonSeq_subscript, /* mp_subscript */
332         0,      /* mp_ass_subscript */
333 };
334
335 PyMethodDef KX_PythonSeq_methods[] = {
336         // dict style access for props
337         {"get",(PyCFunction) KX_PythonSeq_get, METH_VARARGS},
338         {NULL,NULL} //Sentinel
339 };
340
341 /*
342  * Initialize the interator index
343  */
344
345 static PyObject *KX_PythonSeq_getIter(KX_PythonSeq *self)
346 {
347         if(BGE_PROXY_REF(self->base)==NULL) {
348                 PyErr_SetString(PyExc_SystemError, "for i in seq: "BGE_PROXY_ERROR_MSG);
349                 return NULL;
350         }
351         
352         /* create a new iterator if were alredy using this one */
353         if (self->iter == -1) {
354                 self->iter = 0;
355                 Py_INCREF(self);
356                 return (PyObject *)self;
357         } else {
358                 return KX_PythonSeq_CreatePyObject(self->base, self->type);
359         }
360  }
361  
362
363 /*
364  * Return next KX_PythonSeq iter.
365  */
366  
367 static PyObject *KX_PythonSeq_nextIter(KX_PythonSeq *self)
368 {
369         PyObject *object = KX_PythonSeq_getIndex((PyObject *)self, self->iter);
370         
371         self->iter++;
372         if( object==NULL ) {
373                 self->iter= -1; /* for reuse */
374                 PyErr_SetString(PyExc_StopIteration,    "iterator at end");
375         }
376         return object; /* can be NULL for end of iterator */
377 }
378
379
380 static int KX_PythonSeq_compare( KX_PythonSeq * a, KX_PythonSeq * b )
381 {
382         return ( a->type == b->type && a->base == b->base) ? 0 : -1;    
383 }
384
385 static PyObject *KX_PythonSeq_richcmp(PyObject *a, PyObject *b, int op)
386 {
387         PyObject *res;
388         int ok= -1; /* zero is true */
389
390         if(BPy_KX_PythonSeq_Check(a) && BPy_KX_PythonSeq_Check(b))
391                 ok= KX_PythonSeq_compare((KX_PythonSeq *)a, (KX_PythonSeq *)b);
392         
393         switch (op) {
394         case Py_NE:
395                 ok = !ok; /* pass through */
396         case Py_EQ:
397                 res = ok ? Py_False : Py_True;
398                 break;
399
400         case Py_LT:
401         case Py_LE:
402         case Py_GT:
403         case Py_GE:
404                 res = Py_NotImplemented;
405                 break;
406         default:
407                 PyErr_BadArgument();
408                 return NULL;
409         }
410         
411         Py_INCREF(res);
412         return res;
413 }
414
415
416 /*
417  * repr function
418  * convert to a list and get its string value
419  */
420 static PyObject *KX_PythonSeq_repr( KX_PythonSeq * self )
421 {
422         PyObject *list = PySequence_List((PyObject *)self);
423         PyObject *repr = PyObject_Repr(list);
424         Py_DECREF(list);
425         return repr;
426 }
427
428
429 /*****************************************************************************/
430 /* Python KX_PythonSeq_Type structure definition:                               */
431 /*****************************************************************************/
432 PyTypeObject KX_PythonSeq_Type = {
433         PyVarObject_HEAD_INIT(NULL, 0)
434         /*  For printing, in format "<module>.<name>" */
435         "KX_PythonSeq",           /* char *tp_name; */
436         sizeof( KX_PythonSeq ),       /* int tp_basicsize; */
437         0,                          /* tp_itemsize;  For allocation */
438
439         /* Methods to implement standard operations */
440
441         ( destructor ) KX_PythonSeq_dealloc, /* destructor tp_dealloc; */
442         NULL,                       /* printfunc tp_print; */
443         NULL,                       /* getattrfunc tp_getattr; */
444         NULL,                       /* setattrfunc tp_setattr; */
445         NULL,                                           /* cmpfunc tp_compare; */
446         ( reprfunc ) KX_PythonSeq_repr,   /* reprfunc tp_repr; */
447
448         /* Method suites for standard classes */
449
450         NULL,                       /* PyNumberMethods *tp_as_number; */
451         &KX_PythonSeq_as_sequence,          /* PySequenceMethods *tp_as_sequence; */
452         &KX_PythonSeq_as_mapping,                       /* PyMappingMethods *tp_as_mapping; */
453
454         /* More standard operations (here for binary compatibility) */
455
456         NULL,                       /* hashfunc tp_hash; */
457         NULL,                       /* ternaryfunc tp_call; */
458         NULL,                       /* reprfunc tp_str; */
459         NULL,                       /* getattrofunc tp_getattro; */
460         NULL,                       /* setattrofunc tp_setattro; */
461
462         /* Functions to access object as input/output buffer */
463         NULL,                       /* PyBufferProcs *tp_as_buffer; */
464
465   /*** Flags to define presence of optional/expanded features ***/
466         Py_TPFLAGS_DEFAULT,         /* long tp_flags; */
467
468         NULL,                       /*  char *tp_doc;  Documentation string */
469   /*** Assigned meaning in release 2.0 ***/
470         /* call function for all accessible objects */
471         NULL,                                           /* traverseproc tp_traverse; */
472
473         /* delete references to contained objects */
474         NULL,                       /* inquiry tp_clear; */
475
476   /***  Assigned meaning in release 2.1 ***/
477   /*** rich comparisons ***/
478         (richcmpfunc)KX_PythonSeq_richcmp,      /* richcmpfunc tp_richcompare; */
479
480   /***  weak reference enabler ***/
481         0,                          /* long tp_weaklistoffset; */
482
483   /*** Added in release 2.2 ***/
484         /*   Iterators */
485         ( getiterfunc) KX_PythonSeq_getIter, /* getiterfunc tp_iter; */
486         ( iternextfunc ) KX_PythonSeq_nextIter, /* iternextfunc tp_iternext; */
487
488   /*** Attribute descriptor and subclassing stuff ***/
489         KX_PythonSeq_methods,       /* struct PyMethodDef *tp_methods; */
490         NULL,                       /* struct PyMemberDef *tp_members; */
491         NULL,       /* struct PyGetSetDef *tp_getset; */
492         NULL,                       /* struct _typeobject *tp_base; */
493         NULL,                       /* PyObject *tp_dict; */
494         NULL,                       /* descrgetfunc tp_descr_get; */
495         NULL,                       /* descrsetfunc tp_descr_set; */
496         0,                          /* long tp_dictoffset; */
497         NULL,                       /* initproc tp_init; */
498         NULL,                       /* allocfunc tp_alloc; */
499         NULL,                       /* newfunc tp_new; */
500         /*  Low-level free-memory routine */
501         NULL,                       /* freefunc tp_free;  */
502         /* For PyObject_IS_GC */
503         NULL,                       /* inquiry tp_is_gc;  */
504         NULL,                       /* PyObject *tp_bases; */
505         /* method resolution order */
506         NULL,                       /* PyObject *tp_mro;  */
507         NULL,                       /* PyObject *tp_cache; */
508         NULL,                       /* PyObject *tp_subclasses; */
509         NULL,                       /* PyObject *tp_weaklist; */
510         NULL
511 };
512
513 #endif // DISABLE_PYTHON