patch from Mitchell Stokes adding dictionary like access to a scene. (like KX_GameObj...
authorCampbell Barton <ideasman42@gmail.com>
Tue, 25 Aug 2009 13:43:21 +0000 (13:43 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Tue, 25 Aug 2009 13:43:21 +0000 (13:43 +0000)
val = scene["prop"]
scene["prop"] = newval
if "prop" in scene: ...
val = scene.get("prop", fallback_val)

source/gameengine/Ketsji/KX_Scene.cpp
source/gameengine/Ketsji/KX_Scene.h
source/gameengine/PyDoc/GameTypes.py

index 5c19911fe5837554f5f39deb0acb4938747effa4..a9bb583bba76f3b10f941cd76f5435c79d7bbb36 100644 (file)
@@ -1615,7 +1615,10 @@ PyTypeObject KX_Scene::Type = {
        0,
        0,
        py_base_repr,
-       0,0,0,0,0,0,0,0,0,
+       0,
+       &Sequence,
+       &Mapping,
+       0,0,0,0,0,0,
        Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
        0,0,0,0,0,0,0,
        Methods,
@@ -1632,8 +1635,115 @@ PyMethodDef KX_Scene::Methods[] = {
        KX_PYMETHODTABLE_NOARGS(KX_Scene, getName),
        KX_PYMETHODTABLE(KX_Scene, addObject),
        
+       /* dict style access */
+       KX_PYMETHODTABLE(KX_Scene, get),
+       
        {NULL,NULL} //Sentinel
 };
+static PyObject *Map_GetItem(PyObject *self_v, PyObject *item)
+{
+       KX_Scene* self= static_cast<KX_Scene*>BGE_PROXY_REF(self_v);
+       const char *attr_str= _PyUnicode_AsString(item);
+       PyObject* pyconvert;
+       
+       if (self==NULL) {
+               PyErr_SetString(PyExc_SystemError, "val = scene[key]: KX_Scene, "BGE_PROXY_ERROR_MSG);
+               return NULL;
+       }
+       
+       if (self->m_attr_dict && (pyconvert=PyDict_GetItem(self->m_attr_dict, item))) {
+               
+               if (attr_str)
+                       PyErr_Clear();
+               Py_INCREF(pyconvert);
+               return pyconvert;
+       }
+       else {
+               if(attr_str)    PyErr_Format(PyExc_KeyError, "value = scene[key]: KX_Scene, key \"%s\" does not exist", attr_str);
+               else                    PyErr_SetString(PyExc_KeyError, "value = scene[key]: KX_Scene, key does not exist");
+               return NULL;
+       }
+               
+}
+
+static int Map_SetItem(PyObject *self_v, PyObject *key, PyObject *val)
+{
+       KX_Scene* self= static_cast<KX_Scene*>BGE_PROXY_REF(self_v);
+       const char *attr_str= _PyUnicode_AsString(key);
+       if(attr_str==NULL)
+               PyErr_Clear();
+       
+       if (self==NULL) {
+               PyErr_SetString(PyExc_SystemError, "scene[key] = value: KX_Scene, "BGE_PROXY_ERROR_MSG);
+               return -1;
+       }
+       
+       if (val==NULL) { /* del ob["key"] */
+               int del= 0;
+               
+               if(self->m_attr_dict)
+                       del |= (PyDict_DelItem(self->m_attr_dict, key)==0) ? 1:0;
+               
+               if (del==0) {
+                       if(attr_str)    PyErr_Format(PyExc_KeyError, "scene[key] = value: KX_Scene, key \"%s\" could not be set", attr_str);
+                       else                    PyErr_SetString(PyExc_KeyError, "del scene[key]: KX_Scene, key could not be deleted");
+                       return -1;
+               }
+               else if (self->m_attr_dict) {
+                       PyErr_Clear(); /* PyDict_DelItem sets an error when it fails */
+               }
+       }
+       else { /* ob["key"] = value */
+               int set = 0;
+
+               if (self->m_attr_dict==NULL) /* lazy init */
+                       self->m_attr_dict= PyDict_New();
+               
+               
+               if(PyDict_SetItem(self->m_attr_dict, key, val)==0)
+                       set= 1;
+               else
+                       PyErr_SetString(PyExc_KeyError, "scene[key] = value: KX_Scene, key not be added to internal dictionary");
+       
+               if(set==0)
+                       return -1; /* pythons error value */
+               
+       }
+       
+       return 0; /* success */
+}
+
+static int Seq_Contains(PyObject *self_v, PyObject *value)
+{
+       KX_Scene* self= static_cast<KX_Scene*>BGE_PROXY_REF(self_v);
+       
+       if (self==NULL) {
+               PyErr_SetString(PyExc_SystemError, "val in scene: KX_Scene, "BGE_PROXY_ERROR_MSG);
+               return -1;
+       }
+       
+       if (self->m_attr_dict && PyDict_GetItem(self->m_attr_dict, value))
+               return 1;
+       
+       return 0;
+}
+
+PyMappingMethods KX_Scene::Mapping = {
+       (lenfunc)NULL                                   ,                       /*inquiry mp_length */
+       (binaryfunc)Map_GetItem,                /*binaryfunc mp_subscript */
+       (objobjargproc)Map_SetItem,     /*objobjargproc mp_ass_subscript */
+};
+
+PySequenceMethods KX_Scene::Sequence = {
+       NULL,           /* Cant set the len otherwise it can evaluate as false */
+       NULL,           /* sq_concat */
+       NULL,           /* sq_repeat */
+       NULL,           /* sq_item */
+       NULL,           /* sq_slice */
+       NULL,           /* sq_ass_item */
+       NULL,           /* sq_ass_slice */
+       (objobjproc)Seq_Contains,       /* sq_contains */
+};
 
 PyObject* KX_Scene::pyattr_get_name(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
 {
@@ -1765,3 +1875,22 @@ KX_PYMETHODDEF_DOC(KX_Scene, addObject,
        replica->Release();
        return replica->GetProxy();
 }
+
+/* Matches python dict.get(key, [default]) */
+KX_PYMETHODDEF_DOC(KX_Scene, get, "")
+{
+       PyObject *key;
+       PyObject* def = Py_None;
+       PyObject* ret;
+
+       if (!PyArg_ParseTuple(args, "O|O:get", &key, &def))
+               return NULL;
+       
+       if (m_attr_dict && (ret=PyDict_GetItem(m_attr_dict, key))) {
+               Py_INCREF(ret);
+               return ret;
+       }
+       
+       Py_INCREF(def);
+       return def;
+}
index f48e9520f537323f279ffc573f65e8068a194169..8d7c0ad8decae07d18bd8e9a9d8928028bd57c55 100644 (file)
@@ -90,6 +90,7 @@ struct KX_ClientObjectInfo;
 class KX_Scene : public PyObjectPlus, public SCA_IScene
 {
        Py_Header;
+       PyObject*       m_attr_dict;
 
        struct CullingInfo {
                int m_layer;
@@ -262,15 +263,10 @@ protected:
 
        double                          m_suspendedtime;
        double                          m_suspendeddelta;
-       
-       /**
-        * This stores anything from python
-        */
-       PyObject* m_attr_dict;
 
        struct Scene* m_blenderScene;
 
-public:
+public:        
        KX_Scene(class SCA_IInputDevice* keyboarddevice,
                class SCA_IInputDevice* mousedevice,
                class NG_NetworkDeviceInterface* ndi,
@@ -525,6 +521,8 @@ public:
        KX_PYMETHOD_DOC_NOARGS(KX_Scene, getObjectList);
        KX_PYMETHOD_DOC_NOARGS(KX_Scene, getName);
        KX_PYMETHOD_DOC(KX_Scene, addObject);
+       KX_PYMETHOD_DOC(KX_Scene, get);
+       
 /*     
        KX_PYMETHOD_DOC(KX_Scene, getActiveCamera);
        KX_PYMETHOD_DOC(KX_Scene, getActiveCamera);
@@ -549,7 +547,11 @@ public:
        static int                      pyattr_set_active_camera(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value);
 
        virtual PyObject* py_repr(void) { return PyUnicode_FromString(GetName().ReadPtr()); }
-               
+       
+       /* getitem/setitem */
+       static PyMappingMethods Mapping;
+       static PySequenceMethods        Sequence;
+
        /**
         * Sets the time the scene was suspended
         */ 
index c82623e64090fe63548f3edc758ab8d448b2a309..9c426aed8e057cee5c598975511adc52abc0edf5 100644 (file)
@@ -3868,6 +3868,12 @@ class KX_Scene(PyObjectPlus):
                
                @rtype: L{KX_GameObject}
                """
+       
+       def get(key, default=None):
+               """
+               Return the value matching key, or the default value if its not found.
+               @return: The key value or a default.
+               """
 
 class KX_SceneActuator(SCA_IActuator):
        """