BGE: generic python callback list + replace KX_PythonSeq.
authorPorteries Tristan <republicthunderbolt9@gmail.com>
Mon, 26 Oct 2015 19:27:08 +0000 (20:27 +0100)
committerPorteries Tristan <republicthunderbolt9@gmail.com>
Mon, 26 Oct 2015 19:27:08 +0000 (20:27 +0100)
I made this patch to declared a python list without converting all elements in python object (too slow) or use a CListValue which required CValue items (too expensive in memory).  In the case of a big list of points like a collision contacts points list, to use a CListValue we must implement a new class based on CValue for 3D vector to create a python proxy even if mathutils do it perfectly, we must also convert all points (frequently ~100 points) when fill the CListValue even if the list is not used (in the case of the collision callback). The easy way is to use callback (it doesn't worth to do an inheritance) which convert the item in PyObject only during an acces.
5 callbacks are used :
- Check if the list is valid = allow acces (like PyObjectPlus.invalid)
- Get the list size
- Get an item in the list by index.
- Get an item name in the list by index (used for operator `list["name"]`)
- Set an item in the list at the index position.
All of these callback take as first argument the client instance.
Why do we use a void * for the client instance ? : In KX_PythonInitTypes.cpp we have to initialize each python inherited class, if we use a template (the only other way) we must add this class each time we use a new type with in KX_PythonInitTypes.cpp

To check if the list can be accessed from python by the user, we check if the python proxy,  which is the `m_base` member, is still a valid proxy like in PyObjectPlus. But we can use a callback for more control of user access (e.g a list of collision point invalidate a frame later, in this case no real python owner).

This python list is easily defined with :
```
CPythonCallBackList(
void *client, // The client instance
PyObject *base, // The python instance which owned this list, used to know if the list is valid (like in KX_PythonSeq)
bool (*checkValid)(void *), // A callback to check if this list is till valid (optional)
int (*getSize)(void *), // A callback to get size
PyObject *(*getItem)(void *, int), // A callback to get an item
const char *(*getItemName)(void *, int), // A callback to get an item name (optional) use for acces by string key
bool (*setItem)(void *, int, PyObject *) // A callback to set an item (optional)
)
```
To show its usecase i replaced the odd KX_PythonSeq, it modify KX_Gameobject.sensors/controllers/actuators, SCA_IController.sensors/actuators and BL_ArmatureObject.constraints/channels.

Example : {F245193}, See message in console, press R to erase the object and see invalid proxy error message.

Reviewers: brita_, #game_python, youle, campbellbarton, moguri, agoose77, sergey

Reviewed By: campbellbarton, moguri, agoose77, sergey

Subscribers: sergey

Projects: #game_engine

Differential Revision: https://developer.blender.org/D1363

source/gameengine/Converter/BL_ArmatureChannel.h
source/gameengine/Converter/BL_ArmatureObject.cpp
source/gameengine/Expressions/CMakeLists.txt
source/gameengine/Expressions/EXP_ListWrapper.h [new file with mode: 0644]
source/gameengine/Expressions/intern/ListWrapper.cpp [new file with mode: 0644]
source/gameengine/GameLogic/SCA_IController.cpp
source/gameengine/Ketsji/CMakeLists.txt
source/gameengine/Ketsji/KX_GameObject.cpp
source/gameengine/Ketsji/KX_PythonInitTypes.cpp
source/gameengine/Ketsji/KX_PythonSeq.cpp [deleted file]
source/gameengine/Ketsji/KX_PythonSeq.h [deleted file]

index d349e6e9dae835ba77b6b9975c133e3420e245d1..a07097f8178e8799c1dbccc746eb55124ab10822 100644 (file)
@@ -60,6 +60,11 @@ public:
                                                struct bPoseChannel *posechannel);
        virtual ~BL_ArmatureChannel();
 
+       inline const char *GetName()
+       {
+               return m_posechannel->name;
+       }
+
 #ifdef WITH_PYTHON
        // Python access
        virtual PyObject *py_repr(void);
index 3d863bf380af6cd505d59e24be1c40021527c5d9..a1819a8dc92a91397c773f66ab165b3cfed2d6a6 100644 (file)
@@ -60,10 +60,11 @@ extern "C" {
 #include "DNA_scene_types.h"
 #include "DNA_constraint_types.h"
 #include "RNA_access.h"
-#include "KX_PythonSeq.h"
 #include "KX_PythonInit.h"
 #include "KX_KetsjiEngine.h"
 
+#include "EXP_ListWrapper.h"
+
 #include "MT_Matrix4x4.h"
 
 /** 
@@ -619,16 +620,58 @@ PyAttributeDef BL_ArmatureObject::Attributes[] = {
        {NULL} //Sentinel
 };
 
+static int bl_armature_object_get_constraints_size_cb(void *self_v)
+{
+       return ((BL_ArmatureObject *)self_v)->GetConstraintNumber();
+}
+
+static PyObject *bl_armature_object_get_constraints_item_cb(void *self_v, int index)
+{
+       return ((BL_ArmatureObject *)self_v)->GetConstraint(index)->GetProxy();
+}
+
+static const char *bl_armature_object_get_constraints_item_name_cb(void *self_v, int index)
+{
+       return ((BL_ArmatureObject *)self_v)->GetConstraint(index)->GetName();
+}
+
 PyObject *BL_ArmatureObject::pyattr_get_constraints(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
 {
-       return KX_PythonSeq_CreatePyObject((static_cast<BL_ArmatureObject*>(self_v))->m_proxy, KX_PYGENSEQ_OB_TYPE_CONSTRAINTS);
+       return (new CListWrapper(self_v,
+                                                        ((BL_ArmatureObject *)self_v)->GetProxy(),
+                                                        NULL,
+                                                        bl_armature_object_get_constraints_size_cb,
+                                                        bl_armature_object_get_constraints_item_cb,
+                                                        bl_armature_object_get_constraints_item_name_cb,
+                                                        NULL))->NewProxy(true);
+}
+
+static int bl_armature_object_get_channels_size_cb(void *self_v)
+{
+       return ((BL_ArmatureObject *)self_v)->GetChannelNumber();
+}
+
+static PyObject *bl_armature_object_get_channels_item_cb(void *self_v, int index)
+{
+       return ((BL_ArmatureObject *)self_v)->GetChannel(index)->GetProxy();
+}
+
+static const char *bl_armature_object_get_channels_item_name_cb(void *self_v, int index)
+{
+       return ((BL_ArmatureObject *)self_v)->GetChannel(index)->GetName();
 }
 
 PyObject *BL_ArmatureObject::pyattr_get_channels(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
 {
-       BL_ArmatureObject* self = static_cast<BL_ArmatureObject*>(self_v);
+       BL_ArmatureObject *self = static_cast<BL_ArmatureObject *>(self_v);
        self->LoadChannels(); // make sure we have the channels
-       return KX_PythonSeq_CreatePyObject((static_cast<BL_ArmatureObject*>(self_v))->m_proxy, KX_PYGENSEQ_OB_TYPE_CHANNELS);
+       return (new CListWrapper(self_v,
+                                                        self->GetProxy(),
+                                                        NULL,
+                                                        bl_armature_object_get_channels_size_cb,
+                                                        bl_armature_object_get_channels_item_cb,
+                                                        bl_armature_object_get_channels_item_name_cb,
+                                                        NULL))->NewProxy(true);
 }
 
 KX_PYMETHODDEF_DOC_NOARGS(BL_ArmatureObject, update, 
index 6ab4d3fdaccb58612743b3a7d3943924c454cd16..9c563a46ea2b13c27f670d9721dbc12d49062a2c 100644 (file)
@@ -54,6 +54,7 @@ set(SRC
        intern/StringValue.cpp
        intern/Value.cpp
        intern/VectorValue.cpp
+       intern/ListWrapper.cpp
 
        EXP_BoolValue.h
        EXP_ConstExpr.h
@@ -75,6 +76,8 @@ set(SRC
        EXP_Value.h
        EXP_VectorValue.h
        EXP_VoidValue.h
+       EXP_ListWrapper.h
+
 )
 
 if(WITH_PYTHON)
diff --git a/source/gameengine/Expressions/EXP_ListWrapper.h b/source/gameengine/Expressions/EXP_ListWrapper.h
new file mode 100644 (file)
index 0000000..e4c9769
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Porteries Tristan.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file EXP_ListWrapper.h
+ *  \ingroup expressions
+ */
+
+#ifdef WITH_PYTHON
+
+#ifndef __EXP_LISTWRAPPER_H__
+#define __EXP_LISTWRAPPER_H__
+
+#include "EXP_Value.h"
+
+class CListWrapper : public CValue  
+{
+       Py_Header
+private:
+       /** The client instance passed as first argument of each callback.
+        * We use a void * instead of a template to avoid to declare this class
+        * for each use in KX_PythonInitTypes.
+        */
+       void *m_client;
+
+       // The python object which owned this list.
+       PyObject *m_base;
+
+       /// Returns true if the list is still valid, else each call will raise an error.
+       bool (*m_checkValid)(void *);
+
+       /// Returns the list size.
+       int (*m_getSize)(void *);
+
+       /// Returns the list item for the giving index.
+       PyObject *(*m_getItem)(void *, int);
+
+       /// Returns name item for the giving index, used for python operator list["name"].
+       const char *(*m_getItemName)(void *, int);
+
+       /// Sets the nex item to the index place, return false when failed item conversion.
+       bool (*m_setItem)(void *, int, PyObject *);
+
+public:
+       CListWrapper(void *client,
+                                               PyObject *base,
+                                               bool (*checkValid)(void *),
+                                               int (*getSize)(void *),
+                                               PyObject *(*getItem)(void *, int),
+                                               const char *(*getItemName)(void *, int),
+                                               bool (*setItem)(void *, int, PyObject *));
+       ~CListWrapper();
+
+       /// \section Python Interface
+       bool CheckValid();
+       int GetSize();
+       PyObject *GetItem(int index);
+       const char *GetItemName(int index);
+       bool SetItem(int index, PyObject *item);
+       bool AllowSetItem();
+       bool AllowGetItemByName();
+
+       /// \section CValue Inherited Functions.
+       virtual const STR_String &GetText();
+       virtual void SetName(const char *name);
+       virtual STR_String &GetName();
+       virtual CValue *GetReplica();
+       virtual CValue *Calc(VALUE_OPERATOR op, CValue *val);
+       virtual CValue *CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue *val);
+       virtual double GetNumber();
+       virtual int GetValueType();
+       virtual PyObject *py_repr();
+
+       // Python list operators.
+       static PySequenceMethods py_as_sequence;
+       // Python dictionnary operators.
+       static PyMappingMethods py_as_mapping;
+
+       static Py_ssize_t py_len(PyObject *self);
+       static PyObject *py_get_item(PyObject *self, Py_ssize_t index);
+       static int py_set_item(PyObject *self, Py_ssize_t index, PyObject *value);
+       static PyObject *py_mapping_subscript(PyObject *self, PyObject *key);
+       static int py_mapping_ass_subscript(PyObject *self, PyObject *key, PyObject *value);
+       static int py_contains(PyObject *self, PyObject *key);
+
+       KX_PYMETHOD_VARARGS(CListWrapper, Get);
+};
+
+#endif // __EXP_LISTWRAPPER_H__
+
+#endif // WITH_PYTHON
diff --git a/source/gameengine/Expressions/intern/ListWrapper.cpp b/source/gameengine/Expressions/intern/ListWrapper.cpp
new file mode 100644 (file)
index 0000000..db1518a
--- /dev/null
@@ -0,0 +1,424 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Porteries Tristan.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file ListWrapper.cpp
+ *  \ingroup expressions
+ */
+
+#ifdef WITH_PYTHON
+
+#include "EXP_ListWrapper.h"
+
+static STR_String pythonGeneratorList = "ListWrapper";
+
+CListWrapper::CListWrapper(void *client,
+                                                  PyObject *base,
+                                                  bool (*checkValid)(void *),
+                                                  int (*getSize)(void *),
+                                                  PyObject *(*getItem)(void *, int),
+                                                  const char *(*getItemName)(void *, int),
+                                                  bool (*setItem)(void *, int, PyObject *))
+:m_client(client),
+m_base(base),
+m_checkValid(checkValid),
+m_getSize(getSize),
+m_getItem(getItem),
+m_getItemName(getItemName),
+m_setItem(setItem)
+{
+       // Incref to always have a existing pointer.
+       Py_INCREF(m_base);
+}
+
+CListWrapper::~CListWrapper()
+{
+       Py_DECREF(m_base);
+}
+
+bool CListWrapper::CheckValid()
+{
+       if (m_base && !BGE_PROXY_REF(m_base)) {
+               return false;
+       }
+       return m_checkValid ? (*m_checkValid)(m_client) : true;
+}
+
+int CListWrapper::GetSize()
+{
+       return (*m_getSize)(m_client);
+}
+
+PyObject *CListWrapper::GetItem(int index)
+{
+       return (*m_getItem)(m_client, index);
+}
+
+const char *CListWrapper::GetItemName(int index)
+{
+       return (*m_getItemName)(m_client, index);
+}
+
+bool CListWrapper::SetItem(int index, PyObject *item)
+{
+       return (*m_setItem)(m_client, index, item);
+}
+
+bool CListWrapper::AllowSetItem()
+{
+       return m_setItem != NULL;
+}
+
+bool CListWrapper::AllowGetItemByName()
+{
+       return m_getItemName != NULL;
+}
+
+// ================================================================
+
+const STR_String &CListWrapper::GetText()
+{
+       return pythonGeneratorList;
+}
+
+void CListWrapper::SetName(const char *name)
+{
+}
+
+STR_String &CListWrapper::GetName()
+{
+       return pythonGeneratorList;
+}
+
+CValue *CListWrapper::GetReplica()
+{
+       return NULL;
+}
+
+CValue *CListWrapper::Calc(VALUE_OPERATOR op, CValue *val)
+{
+       return NULL;
+}
+
+CValue *CListWrapper::CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue *val)
+{
+       return NULL;
+}
+
+double CListWrapper::GetNumber()
+{
+       return -1;
+}
+
+int CListWrapper::GetValueType()
+{
+       return -1;
+}
+
+// We convert all elements to python objects to make a proper repr string.
+PyObject *CListWrapper::py_repr()
+{
+       if (!CheckValid()) {
+               PyErr_SetString(PyExc_SystemError, "CListWrapper : repr, " BGE_PROXY_ERROR_MSG);
+               return NULL;
+       }
+
+       PyObject *py_proxy = GetProxy();
+       PyObject *py_list = PySequence_List(py_proxy);
+       PyObject *py_string = PyObject_Repr(py_list);
+       Py_DECREF(py_list);
+       Py_DECREF(py_proxy);
+       return py_string;
+}
+
+
+Py_ssize_t CListWrapper::py_len(PyObject *self)
+{
+       CListWrapper *list = (CListWrapper *)BGE_PROXY_REF(self);
+       // Invalid list.
+       if (!list->CheckValid()) {
+               PyErr_SetString(PyExc_SystemError, "len(CListWrapper), " BGE_PROXY_ERROR_MSG);
+               return 0;
+       }
+
+       return (Py_ssize_t)list->GetSize();
+}
+
+PyObject *CListWrapper::py_get_item(PyObject *self, Py_ssize_t index)
+{
+       CListWrapper *list = (CListWrapper *)BGE_PROXY_REF(self);
+       // Invalid list.
+       if (!list->CheckValid()) {
+               PyErr_SetString(PyExc_SystemError, "val = CListWrapper[i], " BGE_PROXY_ERROR_MSG);
+               return NULL;
+       }
+
+       int size = list->GetSize();
+
+       if (index < 0) {
+               index = size + index;
+       }
+       if (index < 0 || index >= size) {
+               PyErr_SetString(PyExc_IndexError, "CListWrapper[i]: List index out of range in CListWrapper");
+               return NULL;
+       }
+
+       PyObject *pyobj = list->GetItem(index);
+
+       return pyobj;
+}
+
+int CListWrapper::py_set_item(PyObject *self, Py_ssize_t index, PyObject *value)
+{
+       CListWrapper *list = (CListWrapper *)BGE_PROXY_REF(self);
+       // Invalid list.
+       if (!list->CheckValid()) {
+               PyErr_SetString(PyExc_SystemError, "CListWrapper[i] = val, " BGE_PROXY_ERROR_MSG);
+               return -1;
+       }
+
+       if (!list->AllowSetItem()) {
+               PyErr_SetString(PyExc_TypeError, "CListWrapper's item type doesn't support assignment");
+               return -1;
+       }
+
+       if (!value) {
+               PyErr_SetString(PyExc_TypeError, "CListWrapper doesn't support item deletion");
+               return -1;
+       }
+
+       int size = list->GetSize();
+
+       if (index < 0) {
+               index = size + index;
+       }
+       if (index < 0 || index >= size) {
+               PyErr_SetString(PyExc_IndexError, "CListWrapper[i]: List index out of range in CListWrapper");
+               return -1;
+       }
+
+       if (!list->SetItem(index, value)) {
+               return -1;
+       }
+       return 0;
+}
+
+PyObject *CListWrapper::py_mapping_subscript(PyObject *self, PyObject *key)
+{
+       CListWrapper *list = (CListWrapper *)BGE_PROXY_REF(self);
+       // Invalid list.
+       if (!list->CheckValid()) {
+               PyErr_SetString(PyExc_SystemError, "val = CListWrapper[key], " BGE_PROXY_ERROR_MSG);
+               return NULL;
+       }
+
+       if (PyIndex_Check(key)) {
+               Py_ssize_t index = PyLong_AsSsize_t(key);
+               return py_get_item(self, index);
+       }
+       else if (PyUnicode_Check(key)) {
+               if (!list->AllowGetItemByName()) {
+                       PyErr_SetString(PyExc_SystemError, "CListWrapper's item type doesn't support access by key");
+                       return NULL;
+               }
+
+               const char *name = _PyUnicode_AsString(key);
+               int size = list->GetSize();
+
+               for (unsigned int i = 0; i < size; ++i) {
+                       if (strcmp(list->GetItemName(i), name) == 0) {
+                               return list->GetItem(i);
+                       }
+               }
+
+               PyErr_Format(PyExc_KeyError, "requested item \"%s\" does not exist", name);
+               return NULL;
+       }
+
+       PyErr_Format(PyExc_KeyError, "CListWrapper[key]: '%R' key not in list", key);
+       return NULL;
+}
+
+int CListWrapper::py_mapping_ass_subscript(PyObject *self, PyObject *key, PyObject *value)
+{
+       CListWrapper *list = (CListWrapper *)BGE_PROXY_REF(self);
+       // Invalid list.
+       if (!list->CheckValid()) {
+               PyErr_SetString(PyExc_SystemError, "val = CListWrapper[key], " BGE_PROXY_ERROR_MSG);
+               return -1;
+       }
+
+       if (!list->AllowSetItem()) {
+               PyErr_SetString(PyExc_TypeError, "CListWrapper's item type doesn't support assignment");
+               return -1;
+       }
+
+       if (PyIndex_Check(key)) {
+               Py_ssize_t index = PyLong_AsSsize_t(key);
+               return py_set_item(self, index, value);
+       }
+       else if (PyUnicode_Check(key)) {
+               if (!list->AllowGetItemByName()) {
+                       PyErr_SetString(PyExc_SystemError, "CListWrapper's item type doesn't support access by key");
+                       return -1;
+               }
+
+               const char *name = _PyUnicode_AsString(key);
+               int size = list->GetSize();
+
+               for (unsigned int i = 0; i < size; ++i) {
+                       if (strcmp(list->GetItemName(i), name) == 0) {
+                               if (!list->SetItem(i, value)) {
+                                       return -1;
+                               }
+                               return 0;
+                       }
+               }
+
+               PyErr_Format(PyExc_KeyError, "requested item \"%s\" does not exist", name);
+               return -1;
+       }
+
+       PyErr_Format(PyExc_KeyError, "CListWrapper[key]: '%R' key not in list", key);
+       return -1;
+}
+
+int CListWrapper::py_contains(PyObject *self, PyObject *key)
+{
+       CListWrapper *list = (CListWrapper *)BGE_PROXY_REF(self);
+       // Invalid list.
+       if (!list->CheckValid()) {
+               PyErr_SetString(PyExc_SystemError, "val = CListWrapper[i], " BGE_PROXY_ERROR_MSG);
+               return -1;
+       }
+
+       if (!list->AllowGetItemByName()) {
+               PyErr_SetString(PyExc_SystemError, "CListWrapper's item type doesn't support access by key");
+               return -1;
+       }
+
+       if (!PyUnicode_Check(key)) {
+               PyErr_SetString(PyExc_SystemError, "key in list, CListWrapper: key must be a string");
+               return -1;
+       }
+
+       const char *name = _PyUnicode_AsString(key);
+       int size = list->GetSize();
+
+       for (unsigned int i = 0; i < size; ++i) {
+               if (strcmp(list->GetItemName(i), name) == 0) {
+                       return 1;
+               }
+       }
+
+       return 0;
+}
+
+PySequenceMethods CListWrapper::py_as_sequence = {
+       py_len, // sq_length
+       NULL, // sq_concat
+       NULL, // sq_repeat
+       py_get_item, // sq_item
+       NULL, // sq_slice
+       py_set_item, // sq_ass_item
+       NULL, // sq_ass_slice
+       (objobjproc)py_contains, // sq_contains
+       (binaryfunc) NULL, // sq_inplace_concat
+       (ssizeargfunc) NULL, // sq_inplace_repeat
+};
+
+PyMappingMethods CListWrapper::py_as_mapping = {
+       py_len, // mp_length
+       py_mapping_subscript, // mp_subscript
+       py_mapping_ass_subscript // mp_ass_subscript
+};
+
+PyTypeObject CListWrapper::Type = {
+       PyVarObject_HEAD_INIT(NULL, 0)
+       "CListWrapper", // tp_name
+       sizeof(PyObjectPlus_Proxy), // tp_basicsize
+       0, // tp_itemsize
+       py_base_dealloc, // tp_dealloc
+       0, // tp_print
+       0, // tp_getattr
+       0, // tp_setattr
+       0, // tp_compare
+       py_base_repr, // tp_repr
+       0, // tp_as_number
+       &py_as_sequence, // tp_as_sequence
+       &py_as_mapping, // tp_as_mapping
+       0, // tp_hash
+       0, // tp_call
+       0,
+       NULL,
+       NULL,
+       0,
+       Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+       0,0,0,0,0,0,0,
+       Methods,
+       0,
+       0,
+       &CValue::Type,
+       0,0,0,0,0,0,
+       py_base_new
+};
+
+PyMethodDef CListWrapper::Methods[] = {
+       {"get", (PyCFunction)CListWrapper::sPyGet, METH_VARARGS},
+       {NULL, NULL} //Sentinel
+};
+
+PyAttributeDef CListWrapper::Attributes[] = {
+       {NULL} //Sentinel
+};
+
+/* Matches python dict.get(key, [default]) */
+PyObject *CListWrapper::PyGet(PyObject *args)
+{
+       char *name;
+       PyObject *def = Py_None;
+
+       // Invalid list.
+       if (!CheckValid()) {
+               PyErr_SetString(PyExc_SystemError, "val = CListWrapper[i], " BGE_PROXY_ERROR_MSG);
+               return NULL;
+       }
+
+       if (!AllowGetItemByName()) {
+               PyErr_SetString(PyExc_SystemError, "CListWrapper's item type doesn't support access by key");
+               return NULL;
+       }
+
+       if (!PyArg_ParseTuple(args, "s|O:get", &name, &def)) {
+               return NULL;
+       }
+
+       for (unsigned int i = 0; i < GetSize(); ++i) {
+               if (strcmp(GetItemName(i), name) == 0) {
+                       return GetItem(i);
+               }
+       }
+
+       Py_INCREF(def);
+       return def;
+}
+
+#endif // WITH_PYTHON
index 2bb04fe7be00024d509e3eb057efcaf4fd6b8520..c4176d666888c1e4ca79716dfa9ed35dfa637bb3 100644 (file)
@@ -37,7 +37,7 @@
 #include "SCA_IActuator.h"
 #include "SCA_ISensor.h"
 #include "EXP_PyObjectPlus.h"
-#include "../Ketsji/KX_PythonSeq.h" /* not nice, only need for KX_PythonSeq_CreatePyObject */
+#include "EXP_ListWrapper.h"
 
 #include <stdio.h>
 
@@ -244,13 +244,55 @@ PyObject *SCA_IController::pyattr_get_state(void *self_v, const KX_PYATTRIBUTE_D
        return PyLong_FromLong(self->m_statemask);
 }
 
+static int sca_icontroller_get_sensors_size_cb(void *self_v)
+{
+       return ((SCA_IController *)self_v)->GetLinkedSensors().size();
+}
+
+static PyObject *sca_icontroller_get_sensors_item_cb(void *self_v, int index)
+{
+       return ((SCA_IController *)self_v)->GetLinkedSensors()[index]->GetProxy();
+}
+
+static const char *sca_icontroller_get_sensors_item_name_cb(void *self_v, int index)
+{
+       return ((SCA_IController *)self_v)->GetLinkedSensors()[index]->GetName().ReadPtr();
+}
+
 PyObject *SCA_IController::pyattr_get_sensors(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
 {
-       return KX_PythonSeq_CreatePyObject((static_cast<SCA_IController*>(self_v))->m_proxy, KX_PYGENSEQ_CONT_TYPE_SENSORS);
+       return (new CListWrapper(self_v,
+                                                        ((SCA_IController *)self_v)->GetProxy(),
+                                                        NULL,
+                                                        sca_icontroller_get_sensors_size_cb,
+                                                        sca_icontroller_get_sensors_item_cb,
+                                                        sca_icontroller_get_sensors_item_name_cb,
+                                                        NULL))->NewProxy(true);
+}
+
+static int sca_icontroller_get_actuators_size_cb(void *self_v)
+{
+       return ((SCA_IController *)self_v)->GetLinkedActuators().size();
+}
+
+static PyObject *sca_icontroller_get_actuators_item_cb(void *self_v, int index)
+{
+       return ((SCA_IController *)self_v)->GetLinkedActuators()[index]->GetProxy();
+}
+
+static const char *sca_icontroller_get_actuators_item_name_cb(void *self_v, int index)
+{
+       return ((SCA_IController *)self_v)->GetLinkedActuators()[index]->GetName().ReadPtr();
 }
 
 PyObject *SCA_IController::pyattr_get_actuators(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
 {
-       return KX_PythonSeq_CreatePyObject((static_cast<SCA_IController*>(self_v))->m_proxy, KX_PYGENSEQ_CONT_TYPE_ACTUATORS);
+       return (new CListWrapper(self_v,
+                                                        ((SCA_IController *)self_v)->GetProxy(),
+                                                        NULL,
+                                                        sca_icontroller_get_actuators_size_cb,
+                                                        sca_icontroller_get_actuators_item_cb,
+                                                        sca_icontroller_get_actuators_item_name_cb,
+                                                        NULL))->NewProxy(true);
 }
 #endif // WITH_PYTHON
index 2607e2bb4b7c123e1b916b0597ade42e86c8cf90..a5bdb2c7c5fcebc2678d40118bccd18eb2326bff 100644 (file)
@@ -108,7 +108,6 @@ set(SRC
        KX_PythonInit.cpp
        KX_PythonInitTypes.cpp
        KX_PythonMain.cpp
-       KX_PythonSeq.cpp
        KX_RadarSensor.cpp
        KX_RayCast.cpp
        KX_RayEventManager.cpp
@@ -188,7 +187,6 @@ set(SRC
        KX_PythonInit.h
        KX_PythonInitTypes.h
        KX_PythonMain.h
-       KX_PythonSeq.h
        KX_RadarSensor.h
        KX_RayCast.h
        KX_RayEventManager.h
index 1dbcf14af89d66e7e527b656322ba0d2bcb0a7f3..974a2e56d16d7c6f32c7f67cc5ec582ed29ed1ae 100644 (file)
@@ -55,7 +55,6 @@
 #include "KX_RayCast.h"
 #include "KX_PythonInit.h"
 #include "KX_PyMath.h"
-#include "KX_PythonSeq.h"
 #include "SCA_IActuator.h"
 #include "SCA_ISensor.h"
 #include "SCA_IController.h"
@@ -69,6 +68,7 @@
 #include "BL_Action.h"
 
 #include "EXP_PyObjectPlus.h" /* python stuff */
+#include "EXP_ListWrapper.h"
 #include "BLI_utildefines.h"
 
 #ifdef WITH_PYTHON
@@ -3057,20 +3057,83 @@ int KX_GameObject::pyattr_set_obcolor(void *self_v, const KX_PYATTRIBUTE_DEF *at
        return PY_SET_ATTR_SUCCESS;
 }
 
+static int kx_game_object_get_sensors_size_cb(void *self_v)
+{
+       return ((KX_GameObject *)self_v)->GetSensors().size();
+}
+
+static PyObject *kx_game_object_get_sensors_item_cb(void *self_v, int index)
+{
+       return ((KX_GameObject *)self_v)->GetSensors()[index]->GetProxy();
+}
+
+static const char *kx_game_object_get_sensors_item_name_cb(void *self_v, int index)
+{
+       return ((KX_GameObject *)self_v)->GetSensors()[index]->GetName().ReadPtr();
+}
+
 /* These are experimental! */
 PyObject *KX_GameObject::pyattr_get_sensors(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
 {
-       return KX_PythonSeq_CreatePyObject((static_cast<KX_GameObject*>(self_v))->m_proxy, KX_PYGENSEQ_OB_TYPE_SENSORS);
+       return (new CListWrapper(self_v,
+                                                        ((KX_GameObject *)self_v)->GetProxy(),
+                                                        NULL,
+                                                        kx_game_object_get_sensors_size_cb,
+                                                        kx_game_object_get_sensors_item_cb,
+                                                        kx_game_object_get_sensors_item_name_cb,
+                                                        NULL))->NewProxy(true);
+}
+
+static int kx_game_object_get_controllers_size_cb(void *self_v)
+{
+       return ((KX_GameObject *)self_v)->GetControllers().size();
+}
+
+static PyObject *kx_game_object_get_controllers_item_cb(void *self_v, int index)
+{
+       return ((KX_GameObject *)self_v)->GetControllers()[index]->GetProxy();
+}
+
+static const char *kx_game_object_get_controllers_item_name_cb(void *self_v, int index)
+{
+       return ((KX_GameObject *)self_v)->GetControllers()[index]->GetName().ReadPtr();
 }
 
 PyObject *KX_GameObject::pyattr_get_controllers(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
 {
-       return KX_PythonSeq_CreatePyObject((static_cast<KX_GameObject*>(self_v))->m_proxy, KX_PYGENSEQ_OB_TYPE_CONTROLLERS);
+       return (new CListWrapper(self_v,
+                                                        ((KX_GameObject *)self_v)->GetProxy(),
+                                                        NULL,
+                                                        kx_game_object_get_controllers_size_cb,
+                                                        kx_game_object_get_controllers_item_cb,
+                                                        kx_game_object_get_controllers_item_name_cb,
+                                                        NULL))->NewProxy(true);
+}
+
+static int kx_game_object_get_actuators_size_cb(void *self_v)
+{
+       return ((KX_GameObject *)self_v)->GetActuators().size();
+}
+
+static PyObject *kx_game_object_get_actuators_item_cb(void *self_v, int index)
+{
+       return ((KX_GameObject *)self_v)->GetActuators()[index]->GetProxy();
+}
+
+static const char *kx_game_object_get_actuators_item_name_cb(void *self_v, int index)
+{
+       return ((KX_GameObject *)self_v)->GetActuators()[index]->GetName().ReadPtr();
 }
 
 PyObject *KX_GameObject::pyattr_get_actuators(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
 {
-       return KX_PythonSeq_CreatePyObject((static_cast<KX_GameObject*>(self_v))->m_proxy, KX_PYGENSEQ_OB_TYPE_ACTUATORS);
+       return (new CListWrapper(self_v,
+                                                        ((KX_GameObject *)self_v)->GetProxy(),
+                                                        NULL,
+                                                        kx_game_object_get_actuators_size_cb,
+                                                        kx_game_object_get_actuators_item_cb,
+                                                        kx_game_object_get_actuators_item_name_cb,
+                                                        NULL))->NewProxy(true);
 }
 /* End experimental */
 
index ef6ad4712a5c5acc39c62af27071b9378857d9a5..a86cea58635d2079f5a60e4966806c2e04a75bef 100644 (file)
@@ -58,7 +58,6 @@
 #include "KX_ObjectActuator.h"
 #include "KX_ParentActuator.h"
 #include "KX_PolyProxy.h"
-#include "KX_PythonSeq.h"
 #include "KX_SCA_AddObjectActuator.h"
 #include "KX_SCA_EndObjectActuator.h"
 #include "KX_SCA_ReplaceMeshActuator.h"
@@ -99,6 +98,7 @@
 #include "SCA_IController.h"
 #include "KX_NavMeshObject.h"
 #include "KX_MouseActuator.h"
+#include "EXP_ListWrapper.h"
 
 static void PyType_Attr_Set(PyGetSetDef *attr_getset, PyAttributeDef *attr)
 {
@@ -203,6 +203,7 @@ PyMODINIT_FUNC initGameTypesPythonBinding(void)
                PyType_Ready_AttrPtr(dict, BL_ArmatureChannel, init_getset);
                // PyType_Ready_Attr(dict, CPropValue, init_getset);  // doesn't use Py_Header
                PyType_Ready_Attr(dict, CListValue, init_getset);
+               PyType_Ready_Attr(dict, CListWrapper, init_getset);
                PyType_Ready_Attr(dict, CValue, init_getset);
                PyType_Ready_Attr(dict, KX_ArmatureSensor, init_getset);
                PyType_Ready_Attr(dict, KX_BlenderMaterial, init_getset);
@@ -273,10 +274,6 @@ PyMODINIT_FUNC initGameTypesPythonBinding(void)
                PyType_Ready_Attr(dict, SCA_PythonMouse, init_getset);
        }
 
-
-       /* Normal python type */
-       PyType_Ready(&KX_PythonSeq_Type);
-
 #ifdef USE_MATHUTILS
        /* Init mathutils callbacks */
        KX_GameObject_Mathutils_Callback_Init();
diff --git a/source/gameengine/Ketsji/KX_PythonSeq.cpp b/source/gameengine/Ketsji/KX_PythonSeq.cpp
deleted file mode 100644 (file)
index ab4f2c2..0000000
+++ /dev/null
@@ -1,526 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * Contributor(s): Campbell Barton
- *
- * ***** END GPL LICENSE BLOCK *****
- * Readonly sequence wrapper for lookups on logic bricks
- */
-
-/** \file gameengine/Ketsji/KX_PythonSeq.cpp
- *  \ingroup ketsji
- */
-
-
-#ifdef WITH_PYTHON
-
-#include "KX_PythonSeq.h"
-#include "KX_GameObject.h"
-#include "BL_ArmatureObject.h"
-#include "SCA_ISensor.h"
-#include "SCA_IController.h"
-#include "SCA_IActuator.h"
-
-
-PyObject *KX_PythonSeq_CreatePyObject( PyObject *base, short type )
-{
-       KX_PythonSeq *seq = PyObject_GC_New(KX_PythonSeq, &KX_PythonSeq_Type);
-       seq->base = base;
-       Py_INCREF(base); /* so we can always access to check if its valid */
-       seq->type = type;
-       seq->iter = -1; /* init */
-       return (PyObject *)seq;
-}
-
-static int KX_PythonSeq_traverse(KX_PythonSeq *self, visitproc visit, void *arg)
-{
-       Py_VISIT(self->base);
-       return 0;
-}
-
-static int KX_PythonSeq_clear(KX_PythonSeq *self)
-{
-       Py_CLEAR(self->base);
-       return 0;
-}
-
-static void KX_PythonSeq_dealloc(KX_PythonSeq *self)
-{
-       KX_PythonSeq_clear(self);
-       PyObject_GC_Del(self);
-}
-
-static Py_ssize_t KX_PythonSeq_len( PyObject *self )
-{
-       PyObjectPlus *self_plus= BGE_PROXY_REF(((KX_PythonSeq *)self)->base);
-
-       if (self_plus==NULL) {
-               PyErr_SetString(PyExc_SystemError, "len(seq): " BGE_PROXY_ERROR_MSG);
-               return -1;
-       }
-       
-       switch (((KX_PythonSeq *)self)->type) {
-               case KX_PYGENSEQ_CONT_TYPE_SENSORS:
-                       return ((SCA_IController *)self_plus)->GetLinkedSensors().size();
-               case KX_PYGENSEQ_CONT_TYPE_ACTUATORS:
-                       return ((SCA_IController *)self_plus)->GetLinkedActuators().size();
-               case KX_PYGENSEQ_OB_TYPE_SENSORS:
-                       return ((KX_GameObject *)self_plus)->GetSensors().size();
-               case KX_PYGENSEQ_OB_TYPE_CONTROLLERS:
-                       return ((KX_GameObject *)self_plus)->GetControllers().size();
-               case KX_PYGENSEQ_OB_TYPE_ACTUATORS:
-                       return ((KX_GameObject *)self_plus)->GetActuators().size();
-               case KX_PYGENSEQ_OB_TYPE_CONSTRAINTS:
-                       return ((BL_ArmatureObject *)self_plus)->GetConstraintNumber();
-               case KX_PYGENSEQ_OB_TYPE_CHANNELS:
-                       return ((BL_ArmatureObject *)self_plus)->GetChannelNumber();
-               default:
-                       /* Should never happen */
-                       PyErr_SetString(PyExc_SystemError, "invalid type, internal error");
-                       return -1;
-       }
-}
-
-static PyObject *KX_PythonSeq_getIndex(PyObject *self, Py_ssize_t index)
-{
-       PyObjectPlus *self_plus= BGE_PROXY_REF(((KX_PythonSeq *)self)->base);
-        
-       if (self_plus==NULL) {
-               PyErr_SetString(PyExc_SystemError, "val = seq[i]: " BGE_PROXY_ERROR_MSG);
-               return NULL;
-       }
-       
-       switch (((KX_PythonSeq *)self)->type) {
-               case KX_PYGENSEQ_CONT_TYPE_SENSORS:
-               {
-                       vector<SCA_ISensor*>& linkedsensors = ((SCA_IController *)self_plus)->GetLinkedSensors();
-                       if (index<0) index += linkedsensors.size();
-                       if (index<0 || index>= linkedsensors.size()) {
-                               PyErr_SetString(PyExc_IndexError, "seq[i]: index out of range");
-                               return NULL;
-                       }
-                       return linkedsensors[index]->GetProxy();
-               }
-               case KX_PYGENSEQ_CONT_TYPE_ACTUATORS:
-               {
-                       vector<SCA_IActuator*>& linkedactuators = ((SCA_IController *)self_plus)->GetLinkedActuators();
-                       if (index<0) index += linkedactuators.size();
-                       if (index<0 || index>= linkedactuators.size()) {
-                               PyErr_SetString(PyExc_IndexError, "seq[i]: index out of range");
-                               return NULL;
-                       }
-                       return linkedactuators[index]->GetProxy();
-               }
-               case KX_PYGENSEQ_OB_TYPE_SENSORS:
-               {
-                       SCA_SensorList& linkedsensors= ((KX_GameObject *)self_plus)->GetSensors();
-                       if (index<0) index += linkedsensors.size();
-                       if (index<0 || index>= linkedsensors.size()) {
-                               PyErr_SetString(PyExc_IndexError, "seq[i]: index out of range");
-                               return NULL;
-                       }
-                       return linkedsensors[index]->GetProxy();
-               }
-               case KX_PYGENSEQ_OB_TYPE_CONTROLLERS:
-               {
-                       SCA_ControllerList& linkedcontrollers= ((KX_GameObject *)self_plus)->GetControllers();
-                       if (index<0) index += linkedcontrollers.size();
-                       if (index<0 || index>= linkedcontrollers.size()) {
-                               PyErr_SetString(PyExc_IndexError, "seq[i]: index out of range");
-                               return NULL;
-                       }
-                       return linkedcontrollers[index]->GetProxy();
-               }
-               case KX_PYGENSEQ_OB_TYPE_ACTUATORS:
-               {
-                       SCA_ActuatorList& linkedactuators= ((KX_GameObject *)self_plus)->GetActuators();
-                       if (index<0) index += linkedactuators.size();
-                       if (index<0 || index>= linkedactuators.size()) {
-                               PyErr_SetString(PyExc_IndexError, "seq[i]: index out of range");
-                               return NULL;
-                       }
-                       return linkedactuators[index]->GetProxy();
-               }
-               case KX_PYGENSEQ_OB_TYPE_CONSTRAINTS:
-               {
-                       int nb_constraint = ((BL_ArmatureObject *)self_plus)->GetConstraintNumber();
-                       if (index<0) 
-                               index += nb_constraint;
-                       if (index<0 || index>= nb_constraint) {
-                               PyErr_SetString(PyExc_IndexError, "seq[i]: index out of range");
-                               return NULL;
-                       }
-                       return ((BL_ArmatureObject *)self_plus)->GetConstraint(index)->GetProxy();
-               }
-               case KX_PYGENSEQ_OB_TYPE_CHANNELS:
-               {
-                       int nb_channel = ((BL_ArmatureObject *)self_plus)->GetChannelNumber();
-                       if (index<0) 
-                               index += nb_channel;
-                       if (index<0 || index>= nb_channel) {
-                               PyErr_SetString(PyExc_IndexError, "seq[i]: index out of range");
-                               return NULL;
-                       }
-                       return ((BL_ArmatureObject *)self_plus)->GetChannel(index)->GetProxy();
-               }
-
-       }
-       
-       PyErr_SetString(PyExc_SystemError, "invalid sequence type, this is a bug");
-       return NULL;
-}
-
-static PyObjectPlus *KX_PythonSeq_subscript__internal(PyObject *self, const char *key)
-{
-       PyObjectPlus *self_plus= BGE_PROXY_REF(((KX_PythonSeq *)self)->base);
-       
-       switch (((KX_PythonSeq *)self)->type) {
-               case KX_PYGENSEQ_CONT_TYPE_SENSORS:
-               {
-                       vector<SCA_ISensor*>& linkedsensors = ((SCA_IController *)self_plus)->GetLinkedSensors();
-                       SCA_ISensor* sensor;
-                       for (unsigned int index=0;index<linkedsensors.size();index++) {
-                               sensor = linkedsensors[index];
-                               if (sensor->GetName() == key)
-                                       return static_cast<PyObjectPlus *>(sensor);
-                               
-                       }
-                       break;
-               }
-               case KX_PYGENSEQ_CONT_TYPE_ACTUATORS:
-               {
-                       vector<SCA_IActuator*>& linkedactuators = ((SCA_IController *)self_plus)->GetLinkedActuators();
-                       SCA_IActuator* actuator;
-                       for (unsigned int index=0;index<linkedactuators.size();index++) {
-                               actuator = linkedactuators[index];
-                               if (actuator->GetName() == key)
-                                       return static_cast<PyObjectPlus *>(actuator);
-                       }
-                       break;
-               }
-               case KX_PYGENSEQ_OB_TYPE_SENSORS:
-               {
-                       SCA_SensorList& linkedsensors= ((KX_GameObject *)self_plus)->GetSensors();
-                       SCA_ISensor *sensor;
-                       for (unsigned int index=0;index<linkedsensors.size();index++) {
-                               sensor= linkedsensors[index];
-                               if (sensor->GetName() == key)
-                                       return static_cast<PyObjectPlus *>(sensor);
-                       }
-                       break;
-               }
-               case KX_PYGENSEQ_OB_TYPE_CONTROLLERS:
-               {
-                       SCA_ControllerList& linkedcontrollers= ((KX_GameObject *)self_plus)->GetControllers();
-                       SCA_IController *controller;
-                       for (unsigned int index=0;index<linkedcontrollers.size();index++) {
-                               controller= linkedcontrollers[index];
-                               if (controller->GetName() == key)
-                                       return static_cast<PyObjectPlus *>(controller);
-                       }
-                       break;
-               }
-               case KX_PYGENSEQ_OB_TYPE_ACTUATORS:
-               {
-                       SCA_ActuatorList& linkedactuators= ((KX_GameObject *)self_plus)->GetActuators();
-                       SCA_IActuator *actuator;
-                       for (unsigned int index=0;index<linkedactuators.size();index++) {
-                               actuator= linkedactuators[index];
-                               if (actuator->GetName() == key)
-                                       return static_cast<PyObjectPlus *>(actuator);
-                       }
-                       break;
-               }
-               case KX_PYGENSEQ_OB_TYPE_CONSTRAINTS:
-               {
-                       return ((BL_ArmatureObject*)self_plus)->GetConstraint(key);
-               }
-               case KX_PYGENSEQ_OB_TYPE_CHANNELS:
-               {
-                       return ((BL_ArmatureObject*)self_plus)->GetChannel(key);
-               }
-       }
-       
-       return NULL;
-}
-
-
-static PyObject *KX_PythonSeq_subscript(PyObject *self, PyObject *key)
-{
-       PyObjectPlus *self_plus= BGE_PROXY_REF(((KX_PythonSeq *)self)->base);
-       
-       if (self_plus==NULL) {
-               PyErr_SetString(PyExc_SystemError, "val = seq[key], KX_PythonSeq: " BGE_PROXY_ERROR_MSG);
-               return NULL;
-       }
-       
-       if (PyIndex_Check(key)) {
-               return KX_PythonSeq_getIndex(self, PyLong_AsSsize_t(key));
-       }
-       else if ( PyUnicode_Check(key) ) {
-               const char *name = _PyUnicode_AsString(key);
-               PyObjectPlus *ret = KX_PythonSeq_subscript__internal(self, name);
-               
-               if (ret) {
-                       return ret->GetProxy();
-               } else {
-                       PyErr_Format( PyExc_KeyError, "requested item \"%s\" does not exist", name);
-                       return NULL;
-               }
-       }
-       else {
-               PyErr_SetString( PyExc_TypeError, "expected a string or an index" );
-               return NULL;
-       }
-}
-
-
-static int KX_PythonSeq_contains(PyObject *self, PyObject *key)
-{
-       PyObjectPlus *self_plus= BGE_PROXY_REF(((KX_PythonSeq *)self)->base);
-       
-       if (self_plus==NULL) {
-               PyErr_SetString(PyExc_SystemError, "key in seq, KX_PythonSeq: " BGE_PROXY_ERROR_MSG);
-               return -1;
-       }
-       if (!PyUnicode_Check(key)) {
-               PyErr_SetString(PyExc_SystemError, "key in seq, KX_PythonSeq: key must be a string");
-               return -1;
-       }
-       
-       if (KX_PythonSeq_subscript__internal(self, _PyUnicode_AsString(key)))
-               return 1;
-       
-       return 0;
-}
-
-/* Matches python dict.get(key, [default]) */
-static PyObject *KX_PythonSeq_get(PyObject *self, PyObject *args)
-{
-       char *key;
-       PyObject *def = Py_None;
-       PyObjectPlus* ret_plus;
-
-       if (!PyArg_ParseTuple(args, "s|O:get", &key, &def))
-               return NULL;
-       
-       if ((ret_plus = KX_PythonSeq_subscript__internal(self, key)))
-               return ret_plus->GetProxy();
-       
-       Py_INCREF(def);
-       return def;
-}
-
-static PySequenceMethods KX_PythonSeq_as_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)KX_PythonSeq_contains,      /* sq_contains */
-       (binaryfunc) NULL, /* sq_inplace_concat */
-       (ssizeargfunc) NULL, /* sq_inplace_repeat */
-};
-
-static PyMappingMethods KX_PythonSeq_as_mapping = {
-       KX_PythonSeq_len,       /* mp_length */
-       KX_PythonSeq_subscript, /* mp_subscript */
-       0,      /* mp_ass_subscript */
-};
-
-static PyMethodDef KX_PythonSeq_methods[] = {
-       // dict style access for props
-       {"get",(PyCFunction) KX_PythonSeq_get, METH_VARARGS},
-       {NULL,NULL} //Sentinel
-};
-
-/*
- * Initialize the iterator index
- */
-
-static PyObject *KX_PythonSeq_getIter(KX_PythonSeq *self)
-{
-       if (BGE_PROXY_REF(self->base)==NULL) {
-               PyErr_SetString(PyExc_SystemError, "for i in seq: " BGE_PROXY_ERROR_MSG);
-               return NULL;
-       }
-       
-       /* create a new iterator if were already using this one */
-       if (self->iter == -1) {
-               self->iter = 0;
-               Py_INCREF(self);
-               return (PyObject *)self;
-       } else {
-               return KX_PythonSeq_CreatePyObject(self->base, self->type);
-       }
-}
-
-
-/*
- * Return next KX_PythonSeq iter.
- */
-static PyObject *KX_PythonSeq_nextIter(KX_PythonSeq *self)
-{
-       PyObject *object = KX_PythonSeq_getIndex((PyObject *)self, self->iter);
-       
-       self->iter++;
-       if ( object==NULL ) {
-               self->iter= -1; /* for reuse */
-               PyErr_SetNone(PyExc_StopIteration);
-       }
-       return object; /* can be NULL for end of iterator */
-}
-
-
-static int KX_PythonSeq_compare(KX_PythonSeq *a, KX_PythonSeq *b)
-{
-       return (a->type == b->type && a->base == b->base) ? 0 : -1;
-}
-
-static PyObject *KX_PythonSeq_richcmp(PyObject *a, PyObject *b, int op)
-{
-       PyObject *res;
-       int ok= -1; /* zero is true */
-
-       if (BPy_KX_PythonSeq_Check(a) && BPy_KX_PythonSeq_Check(b))
-               ok= KX_PythonSeq_compare((KX_PythonSeq *)a, (KX_PythonSeq *)b);
-       
-       switch (op) {
-       case Py_NE:
-               ok = !ok;
-               /* fall-through */
-       case Py_EQ:
-               res = ok ? Py_False : Py_True;
-               break;
-
-       case Py_LT:
-       case Py_LE:
-       case Py_GT:
-       case Py_GE:
-               res = Py_NotImplemented;
-               break;
-       default:
-               PyErr_BadArgument();
-               return NULL;
-       }
-       
-       Py_INCREF(res);
-       return res;
-}
-
-
-/*
- * repr function
- * convert to a list and get its string value
- */
-static PyObject *KX_PythonSeq_repr(KX_PythonSeq *self)
-{
-       PyObject *list = PySequence_List((PyObject *)self);
-       PyObject *repr = PyObject_Repr(list);
-       Py_DECREF(list);
-       return repr;
-}
-
-
-/*****************************************************************************/
-/* Python KX_PythonSeq_Type structure definition:                               */
-/*****************************************************************************/
-PyTypeObject KX_PythonSeq_Type = {
-       PyVarObject_HEAD_INIT(NULL, 0)
-       /*  For printing, in format "<module>.<name>" */
-       "KX_PythonSeq",           /* char *tp_name; */
-       sizeof( KX_PythonSeq ),       /* int tp_basicsize; */
-       0,                          /* tp_itemsize;  For allocation */
-
-       /* Methods to implement standard operations */
-
-       ( destructor ) KX_PythonSeq_dealloc, /* destructor tp_dealloc; */
-       NULL,                       /* printfunc tp_print; */
-       NULL,                       /* getattrfunc tp_getattr; */
-       NULL,                       /* setattrfunc tp_setattr; */
-       NULL,                                           /* cmpfunc tp_compare; */
-       ( reprfunc ) KX_PythonSeq_repr,   /* reprfunc tp_repr; */
-
-       /* Method suites for standard classes */
-
-       NULL,                       /* PyNumberMethods *tp_as_number; */
-       &KX_PythonSeq_as_sequence,          /* PySequenceMethods *tp_as_sequence; */
-       &KX_PythonSeq_as_mapping,                       /* PyMappingMethods *tp_as_mapping; */
-
-       /* More standard operations (here for binary compatibility) */
-
-       NULL,                       /* hashfunc tp_hash; */
-       NULL,                       /* ternaryfunc tp_call; */
-       NULL,                       /* reprfunc tp_str; */
-       NULL,                       /* getattrofunc tp_getattro; */
-       NULL,                       /* setattrofunc tp_setattro; */
-
-       /* Functions to access object as input/output buffer */
-       NULL,                       /* PyBufferProcs *tp_as_buffer; */
-
-  /*** Flags to define presence of optional/expanded features ***/
-       Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* long tp_flags; */
-
-       NULL,                       /*  char *tp_doc;  Documentation string */
-  /*** Assigned meaning in release 2.0 ***/
-       /* call function for all accessible objects */
-       (traverseproc)KX_PythonSeq_traverse,    /* traverseproc tp_traverse; */
-
-       /* delete references to contained objects */
-       (inquiry)KX_PythonSeq_clear,    /* inquiry tp_clear; */
-
-  /***  Assigned meaning in release 2.1 ***/
-  /*** rich comparisons ***/
-       (richcmpfunc)KX_PythonSeq_richcmp,      /* richcmpfunc tp_richcompare; */
-
-  /***  weak reference enabler ***/
-       0,                          /* long tp_weaklistoffset; */
-
-  /*** Added in release 2.2 ***/
-       /*   Iterators */
-       ( getiterfunc) KX_PythonSeq_getIter, /* getiterfunc tp_iter; */
-       ( iternextfunc ) KX_PythonSeq_nextIter, /* iternextfunc tp_iternext; */
-
-  /*** Attribute descriptor and subclassing stuff ***/
-       KX_PythonSeq_methods,       /* struct PyMethodDef *tp_methods; */
-       NULL,                       /* struct PyMemberDef *tp_members; */
-       NULL,       /* struct PyGetSetDef *tp_getset; */
-       NULL,                       /* struct _typeobject *tp_base; */
-       NULL,                       /* PyObject *tp_dict; */
-       NULL,                       /* descrgetfunc tp_descr_get; */
-       NULL,                       /* descrsetfunc tp_descr_set; */
-       0,                          /* long tp_dictoffset; */
-       NULL,                       /* initproc tp_init; */
-       NULL,                       /* allocfunc tp_alloc; */
-       NULL,                       /* newfunc tp_new; */
-       /*  Low-level free-memory routine */
-       NULL,                       /* freefunc tp_free;  */
-       /* For PyObject_IS_GC */
-       NULL,                       /* inquiry tp_is_gc;  */
-       NULL,                       /* PyObject *tp_bases; */
-       /* method resolution order */
-       NULL,                       /* PyObject *tp_mro;  */
-       NULL,                       /* PyObject *tp_cache; */
-       NULL,                       /* PyObject *tp_subclasses; */
-       NULL,                       /* PyObject *tp_weaklist; */
-       NULL
-};
-
-#endif // WITH_PYTHON
diff --git a/source/gameengine/Ketsji/KX_PythonSeq.h b/source/gameengine/Ketsji/KX_PythonSeq.h
deleted file mode 100644 (file)
index 33b5335..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): Campbell Barton
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file KX_PythonSeq.h
- *  \ingroup ketsji
- *  \brief Readonly sequence wrapper for lookups on logic bricks
- */
-#ifndef __KX_PYTHONSEQ_H__
-#define __KX_PYTHONSEQ_H__
-
-#ifdef WITH_PYTHON
-
-#include "EXP_PyObjectPlus.h"
-
-// -------------------------
-enum KX_PYGENSEQ_TYPE {
-       KX_PYGENSEQ_CONT_TYPE_SENSORS,
-       KX_PYGENSEQ_CONT_TYPE_ACTUATORS,
-       KX_PYGENSEQ_OB_TYPE_SENSORS,
-       KX_PYGENSEQ_OB_TYPE_CONTROLLERS,
-       KX_PYGENSEQ_OB_TYPE_ACTUATORS,
-       KX_PYGENSEQ_OB_TYPE_CONSTRAINTS,
-       KX_PYGENSEQ_OB_TYPE_CHANNELS,
-};
-
-/* The Main PyType Object defined in Main.c */
-extern PyTypeObject KX_PythonSeq_Type;
-
-#define BPy_KX_PythonSeq_Check(obj)  \
-       (Py_TYPE(obj) == &KX_PythonSeq_Type)
-
-typedef struct {
-       PyObject_VAR_HEAD
-       PyObject *base;
-       short type;
-       short iter;
-} KX_PythonSeq;
-
-PyObject *KX_PythonSeq_CreatePyObject(PyObject *base, short type);
-
-#endif  /* WITH_PYTHON */
-
-#endif  /* __KX_PYTHONSEQ_H__ */