BGE: generic python callback list + replace KX_PythonSeq.

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
This commit is contained in:
Porteries Tristan 2015-10-26 20:27:08 +01:00
parent 5b3af3dd46
commit 95164a09a7
Notes: blender-bot 2023-02-14 08:29:54 +01:00
Referenced by issue #46616, Painting Mode "Image" is disabled in viewport
11 changed files with 702 additions and 612 deletions

View 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);

View 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,

View 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)

View File

@ -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

View File

@ -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

View 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

View 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

View 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 */

View 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();

View File

@ -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

View File

@ -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__ */