svn merge https://svn.blender.org/svnroot/bf-blender/trunk/blender -r22668:22701
[blender.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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, 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
32 #include "KX_PythonSeq.h"
33 #include "KX_GameObject.h"
34 #include "SCA_ISensor.h"
35 #include "SCA_IController.h"
36 #include "SCA_IActuator.h"
37
38
39 PyObject *KX_PythonSeq_CreatePyObject( PyObject *base, short type )
40 {
41         KX_PythonSeq *seq = PyObject_NEW( KX_PythonSeq, &KX_PythonSeq_Type);
42         seq->base = base;
43         Py_INCREF(base); /* so we can always access to check if its valid */
44         seq->type = type;
45         seq->iter = -1; /* init */
46         return (PyObject *)seq;
47  }
48  
49  static void KX_PythonSeq_dealloc( KX_PythonSeq * self )
50 {
51         Py_DECREF(self->base);
52         PyObject_DEL( self );
53 }
54
55 static Py_ssize_t KX_PythonSeq_len( PyObject * self )
56 {
57         PyObjectPlus *self_plus= BGE_PROXY_REF(((KX_PythonSeq *)self)->base);
58          
59         if(self_plus==NULL) {
60                 PyErr_SetString(PyExc_SystemError, "len(seq): "BGE_PROXY_ERROR_MSG);
61                 return -1;
62         }
63         
64         switch(((KX_PythonSeq *)self)->type) {
65         case KX_PYGENSEQ_CONT_TYPE_SENSORS:
66                 return ((SCA_IController *)self_plus)->GetLinkedSensors().size();
67         case KX_PYGENSEQ_CONT_TYPE_ACTUATORS:
68                 return ((SCA_IController *)self_plus)->GetLinkedActuators().size();
69         case KX_PYGENSEQ_OB_TYPE_SENSORS:
70                 return ((KX_GameObject *)self_plus)->GetSensors().size();
71         case KX_PYGENSEQ_OB_TYPE_CONTROLLERS:
72                 return ((KX_GameObject *)self_plus)->GetControllers().size();
73         case KX_PYGENSEQ_OB_TYPE_ACTUATORS:
74                 return ((KX_GameObject *)self_plus)->GetActuators().size();
75         default:
76                 /* Should never happen */
77                 PyErr_SetString(PyExc_SystemError, "invalid type, internal error");
78                 return -1;
79         }
80 }
81
82 static PyObject *KX_PythonSeq_getIndex(PyObject* self, int index)
83 {
84         PyObjectPlus *self_plus= BGE_PROXY_REF(((KX_PythonSeq *)self)->base);
85          
86         if(self_plus==NULL) {
87                 PyErr_SetString(PyExc_SystemError, "val = seq[i]: "BGE_PROXY_ERROR_MSG);
88                 return NULL;
89         }
90         
91         switch(((KX_PythonSeq *)self)->type) {
92                 case KX_PYGENSEQ_CONT_TYPE_SENSORS:
93                 {
94                         vector<SCA_ISensor*>& linkedsensors = ((SCA_IController *)self_plus)->GetLinkedSensors();
95                         if(index<0) index += linkedsensors.size();
96                         if(index<0 || index>= linkedsensors.size()) {
97                                 PyErr_SetString(PyExc_IndexError, "seq[i]: index out of range");
98                                 return NULL;
99                         }
100                         return linkedsensors[index]->GetProxy();
101                 }
102                 case KX_PYGENSEQ_CONT_TYPE_ACTUATORS:
103                 {
104                         vector<SCA_IActuator*>& linkedactuators = ((SCA_IController *)self_plus)->GetLinkedActuators();
105                         if(index<0) index += linkedactuators.size();
106                         if(index<0 || index>= linkedactuators.size()) {
107                                 PyErr_SetString(PyExc_IndexError, "seq[i]: index out of range");
108                                 return NULL;
109                         }
110                         return linkedactuators[index]->GetProxy();
111                 }
112                 case KX_PYGENSEQ_OB_TYPE_SENSORS:
113                 {
114                         SCA_SensorList& linkedsensors= ((KX_GameObject *)self_plus)->GetSensors();
115                         if(index<0) index += linkedsensors.size();
116                         if(index<0 || index>= linkedsensors.size()) {
117                                 PyErr_SetString(PyExc_IndexError, "seq[i]: index out of range");
118                                 return NULL;
119                         }
120                         return linkedsensors[index]->GetProxy();
121                 }
122                 case KX_PYGENSEQ_OB_TYPE_CONTROLLERS:
123                 {
124                         SCA_ControllerList& linkedcontrollers= ((KX_GameObject *)self_plus)->GetControllers();
125                         if(index<0) index += linkedcontrollers.size();
126                         if(index<0 || index>= linkedcontrollers.size()) {
127                                 PyErr_SetString(PyExc_IndexError, "seq[i]: index out of range");
128                                 return NULL;
129                         }
130                         return linkedcontrollers[index]->GetProxy();
131                 }
132                 case KX_PYGENSEQ_OB_TYPE_ACTUATORS:
133                 {
134                         SCA_ActuatorList& linkedactuators= ((KX_GameObject *)self_plus)->GetActuators();
135                         if(index<0) index += linkedactuators.size();
136                         if(index<0 || index>= linkedactuators.size()) {
137                                 PyErr_SetString(PyExc_IndexError, "seq[i]: index out of range");
138                                 return NULL;
139                         }
140                         return linkedactuators[index]->GetProxy();
141                 }
142         }
143         
144         PyErr_SetString(PyExc_SystemError, "invalid sequence type, this is a bug");
145         return NULL;
146 }
147
148 static PyObjectPlus * KX_PythonSeq_subscript__internal(PyObject *self, char *key)
149 {
150         PyObjectPlus *self_plus= BGE_PROXY_REF(((KX_PythonSeq *)self)->base);
151         
152         switch(((KX_PythonSeq *)self)->type) {
153                 case KX_PYGENSEQ_CONT_TYPE_SENSORS:
154                 {
155                         vector<SCA_ISensor*>& linkedsensors = ((SCA_IController *)self_plus)->GetLinkedSensors();
156                         SCA_ISensor* sensor;
157                         for (unsigned int index=0;index<linkedsensors.size();index++) {
158                                 sensor = linkedsensors[index];
159                                 if (sensor->GetName() == key)
160                                         return static_cast<PyObjectPlus *>(sensor);
161                                 
162                         }
163                         break;
164                 }
165                 case KX_PYGENSEQ_CONT_TYPE_ACTUATORS:
166                 {
167                         vector<SCA_IActuator*>& linkedactuators = ((SCA_IController *)self_plus)->GetLinkedActuators();
168                         SCA_IActuator* actuator;
169                         for (unsigned int index=0;index<linkedactuators.size();index++) {
170                                 actuator = linkedactuators[index];
171                                 if (actuator->GetName() == key)
172                                         return static_cast<PyObjectPlus *>(actuator);
173                         }
174                         break;
175                 }
176                 case KX_PYGENSEQ_OB_TYPE_SENSORS:
177                 {
178                         SCA_SensorList& linkedsensors= ((KX_GameObject *)self_plus)->GetSensors();
179                         SCA_ISensor *sensor;
180                         for (unsigned int index=0;index<linkedsensors.size();index++) {
181                                 sensor= linkedsensors[index];
182                                 if (sensor->GetName() == key)
183                                         return static_cast<PyObjectPlus *>(sensor);
184                         }
185                         break;
186                 }
187                 case KX_PYGENSEQ_OB_TYPE_CONTROLLERS:
188                 {
189                         SCA_ControllerList& linkedcontrollers= ((KX_GameObject *)self_plus)->GetControllers();
190                         SCA_IController *controller;
191                         for (unsigned int index=0;index<linkedcontrollers.size();index++) {
192                                 controller= linkedcontrollers[index];
193                                 if (controller->GetName() == key)
194                                         return static_cast<PyObjectPlus *>(controller);
195                         }
196                         break;
197                 }
198                 case KX_PYGENSEQ_OB_TYPE_ACTUATORS:
199                 {
200                         SCA_ActuatorList& linkedactuators= ((KX_GameObject *)self_plus)->GetActuators();
201                         SCA_IActuator *actuator;
202                         for (unsigned int index=0;index<linkedactuators.size();index++) {
203                                 actuator= linkedactuators[index];
204                                 if (actuator->GetName() == key)
205                                         return static_cast<PyObjectPlus *>(actuator);
206                         }
207                         break;
208                 }
209         }
210         
211         return NULL;
212 }
213
214
215 static PyObject * KX_PythonSeq_subscript(PyObject * self, PyObject *key)
216 {
217         PyObjectPlus *self_plus= BGE_PROXY_REF(((KX_PythonSeq *)self)->base);
218         
219         if(self_plus==NULL) {
220                 PyErr_SetString(PyExc_SystemError, "val = seq[key], KX_PythonSeq: "BGE_PROXY_ERROR_MSG);
221                 return NULL;
222         }
223         
224         if (PyLong_Check(key)) {
225                 return KX_PythonSeq_getIndex(self, PyLong_AsSsize_t( key ));
226         }
227         else if ( PyUnicode_Check(key) ) {
228                 char *name = _PyUnicode_AsString(key);
229                 PyObjectPlus *ret = KX_PythonSeq_subscript__internal(self, name);
230                 
231                 if(ret) {
232                         return ret->GetProxy();
233                 } else {
234                         PyErr_Format( PyExc_KeyError, "requested item \"%s\" does not exist", name);
235                         return NULL;
236                 }
237         }
238         else {
239                 PyErr_SetString( PyExc_TypeError, "expected a string or an index" );
240                 return NULL;
241         }
242 }
243
244
245 static int KX_PythonSeq_contains(PyObject *self, PyObject *key)
246 {
247         PyObjectPlus *self_plus= BGE_PROXY_REF(((KX_PythonSeq *)self)->base);
248         
249         if(self_plus==NULL) {
250                 PyErr_SetString(PyExc_SystemError, "key in seq, KX_PythonSeq: "BGE_PROXY_ERROR_MSG);
251                 return -1;
252         }
253         if(!PyUnicode_Check(key)) {
254                 PyErr_SetString(PyExc_SystemError, "key in seq, KX_PythonSeq: key must be a string");
255                 return -1;
256         }
257         
258         if(KX_PythonSeq_subscript__internal(self, _PyUnicode_AsString(key)))
259                 return 1;
260         
261         return 0;
262 }
263
264 /* Matches python dict.get(key, [default]) */
265 PyObject* KX_PythonSeq_get(PyObject * self, PyObject *args)
266 {
267         char *key;
268         PyObject* def = Py_None;
269         PyObjectPlus* ret_plus;
270
271         if (!PyArg_ParseTuple(args, "s|O:get", &key, &def))
272                 return NULL;
273         
274         if((ret_plus = KX_PythonSeq_subscript__internal(self, key)))
275                 return ret_plus->GetProxy();
276         
277         Py_INCREF(def);
278         return def;
279 }
280
281 PySequenceMethods KX_PythonSeq_as_sequence = {
282         NULL,           /* Cant set the len otherwise it can evaluate as false */
283         NULL,           /* sq_concat */
284         NULL,           /* sq_repeat */
285         NULL,           /* sq_item */
286         NULL,           /* sq_slice */
287         NULL,           /* sq_ass_item */
288         NULL,           /* sq_ass_slice */
289         (objobjproc)KX_PythonSeq_contains,      /* sq_contains */
290 };
291
292 static PyMappingMethods KX_PythonSeq_as_mapping = {
293         KX_PythonSeq_len,       /* mp_length */
294         KX_PythonSeq_subscript, /* mp_subscript */
295         0,      /* mp_ass_subscript */
296 };
297
298 PyMethodDef KX_PythonSeq_methods[] = {
299         // dict style access for props
300         {"get",(PyCFunction) KX_PythonSeq_get, METH_VARARGS},
301         {NULL,NULL} //Sentinel
302 };
303
304 /*
305  * Initialize the interator index
306  */
307
308 static PyObject *KX_PythonSeq_getIter(KX_PythonSeq *self)
309 {
310         if(BGE_PROXY_REF(self->base)==NULL) {
311                 PyErr_SetString(PyExc_SystemError, "for i in seq: "BGE_PROXY_ERROR_MSG);
312                 return NULL;
313         }
314         
315         /* create a new iterator if were alredy using this one */
316         if (self->iter == -1) {
317                 self->iter = 0;
318                 Py_INCREF(self);
319                 return (PyObject *)self;
320         } else {
321                 return KX_PythonSeq_CreatePyObject(self->base, self->type);
322         }
323  }
324  
325
326 /*
327  * Return next KX_PythonSeq iter.
328  */
329  
330 static PyObject *KX_PythonSeq_nextIter(KX_PythonSeq *self)
331 {
332         PyObject *object = KX_PythonSeq_getIndex((PyObject *)self, self->iter);
333         
334         self->iter++;
335         if( object==NULL ) {
336                 self->iter= -1; /* for reuse */
337                 PyErr_SetString(PyExc_StopIteration,    "iterator at end");
338         }
339         return object; /* can be NULL for end of iterator */
340 }
341
342
343 static int KX_PythonSeq_compare( KX_PythonSeq * a, KX_PythonSeq * b ) /* TODO - python3.x wants richcmp */
344 {
345         return ( a->type == b->type && a->base == b->base) ? 0 : -1;    
346 }
347
348 /*
349  * repr function
350  * convert to a list and get its string value
351  */
352 static PyObject *KX_PythonSeq_repr( KX_PythonSeq * self )
353 {
354         PyObject *list = PySequence_List((PyObject *)self);
355         PyObject *repr = PyObject_Repr(list);
356         Py_DECREF(list);
357         return repr;
358 }
359
360
361 /*****************************************************************************/
362 /* Python KX_PythonSeq_Type structure definition:                               */
363 /*****************************************************************************/
364 PyTypeObject KX_PythonSeq_Type = {
365         PyVarObject_HEAD_INIT(NULL, 0)
366         /*  For printing, in format "<module>.<name>" */
367         "KX_PythonSeq",           /* char *tp_name; */
368         sizeof( KX_PythonSeq ),       /* int tp_basicsize; */
369         0,                          /* tp_itemsize;  For allocation */
370
371         /* Methods to implement standard operations */
372
373         ( destructor ) KX_PythonSeq_dealloc, /* destructor tp_dealloc; */
374         NULL,                       /* printfunc tp_print; */
375         NULL,                       /* getattrfunc tp_getattr; */
376         NULL,                       /* setattrfunc tp_setattr; */
377         /* TODO, richcmp */
378         NULL, /* ( cmpfunc ) KX_PythonSeq_compare, // cmpfunc tp_compare; */
379         ( reprfunc ) KX_PythonSeq_repr,   /* reprfunc tp_repr; */
380
381         /* Method suites for standard classes */
382
383         NULL,                       /* PyNumberMethods *tp_as_number; */
384         &KX_PythonSeq_as_sequence,          /* PySequenceMethods *tp_as_sequence; */
385         &KX_PythonSeq_as_mapping,                       /* PyMappingMethods *tp_as_mapping; */
386
387         /* More standard operations (here for binary compatibility) */
388
389         NULL,                       /* hashfunc tp_hash; */
390         NULL,                       /* ternaryfunc tp_call; */
391         NULL,                       /* reprfunc tp_str; */
392         NULL,                       /* getattrofunc tp_getattro; */
393         NULL,                       /* setattrofunc tp_setattro; */
394
395         /* Functions to access object as input/output buffer */
396         NULL,                       /* PyBufferProcs *tp_as_buffer; */
397
398   /*** Flags to define presence of optional/expanded features ***/
399         Py_TPFLAGS_DEFAULT,         /* long tp_flags; */
400
401         NULL,                       /*  char *tp_doc;  Documentation string */
402   /*** Assigned meaning in release 2.0 ***/
403         /* call function for all accessible objects */
404         NULL,                       /* traverseproc tp_traverse; */
405
406         /* delete references to contained objects */
407         NULL,                       /* inquiry tp_clear; */
408
409   /***  Assigned meaning in release 2.1 ***/
410   /*** rich comparisons ***/
411         NULL,                       /* richcmpfunc tp_richcompare; */
412
413   /***  weak reference enabler ***/
414         0,                          /* long tp_weaklistoffset; */
415
416   /*** Added in release 2.2 ***/
417         /*   Iterators */
418         ( getiterfunc) KX_PythonSeq_getIter, /* getiterfunc tp_iter; */
419         ( iternextfunc ) KX_PythonSeq_nextIter, /* iternextfunc tp_iternext; */
420
421   /*** Attribute descriptor and subclassing stuff ***/
422         KX_PythonSeq_methods,       /* struct PyMethodDef *tp_methods; */
423         NULL,                       /* struct PyMemberDef *tp_members; */
424         NULL,       /* struct PyGetSetDef *tp_getset; */
425         NULL,                       /* struct _typeobject *tp_base; */
426         NULL,                       /* PyObject *tp_dict; */
427         NULL,                       /* descrgetfunc tp_descr_get; */
428         NULL,                       /* descrsetfunc tp_descr_set; */
429         0,                          /* long tp_dictoffset; */
430         NULL,                       /* initproc tp_init; */
431         NULL,                       /* allocfunc tp_alloc; */
432         NULL,                       /* newfunc tp_new; */
433         /*  Low-level free-memory routine */
434         NULL,                       /* freefunc tp_free;  */
435         /* For PyObject_IS_GC */
436         NULL,                       /* inquiry tp_is_gc;  */
437         NULL,                       /* PyObject *tp_bases; */
438         /* method resolution order */
439         NULL,                       /* PyObject *tp_mro;  */
440         NULL,                       /* PyObject *tp_cache; */
441         NULL,                       /* PyObject *tp_subclasses; */
442         NULL,                       /* PyObject *tp_weaklist; */
443         NULL
444 };