Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source/gameengine/Expressions/PyObjectPlus.h5
-rw-r--r--source/gameengine/Expressions/Value.cpp29
-rw-r--r--source/gameengine/Ketsji/KX_GameObject.cpp157
-rw-r--r--source/gameengine/Ketsji/KX_GameObject.h119
-rw-r--r--source/gameengine/Ketsji/KX_Scene.h1
5 files changed, 262 insertions, 49 deletions
diff --git a/source/gameengine/Expressions/PyObjectPlus.h b/source/gameengine/Expressions/PyObjectPlus.h
index f61b9f8d0b8..ea26ea1d201 100644
--- a/source/gameengine/Expressions/PyObjectPlus.h
+++ b/source/gameengine/Expressions/PyObjectPlus.h
@@ -130,9 +130,10 @@ static inline void Py_Fatal(const char *M) {
* was because the attribute didnt exits of if there was some problem setting the value
*/
+#define PY_SET_ATTR_COERCE_FAIL 2
#define PY_SET_ATTR_FAIL 1
-#define PY_SET_ATTR_MISSING -1
-#define PY_SET_ATTR_SUCCESS 0
+#define PY_SET_ATTR_MISSING -1
+#define PY_SET_ATTR_SUCCESS 0
#define py_setattro_up(Parent) \
PyObject *descr = PyDict_GetItem(Type.tp_dict, attr); \
diff --git a/source/gameengine/Expressions/Value.cpp b/source/gameengine/Expressions/Value.cpp
index f1e367d6e59..b8b7a05aa64 100644
--- a/source/gameengine/Expressions/Value.cpp
+++ b/source/gameengine/Expressions/Value.cpp
@@ -719,7 +719,8 @@ CValue* CValue::ConvertPythonToValue(PyObject* pyobj)
{
CValue* vallie = NULL;
-
+ /* refcounting is broking here! - this crashes anyway, just store a python list for KX_GameObject */
+#if 0
if (PyList_Check(pyobj))
{
CListValue* listval = new CListValue();
@@ -750,6 +751,7 @@ CValue* CValue::ConvertPythonToValue(PyObject* pyobj)
}
} else
+#endif
if (PyFloat_Check(pyobj))
{
vallie = new CFloatValue( (float)PyFloat_AsDouble(pyobj) );
@@ -790,21 +792,34 @@ int CValue::py_delattro(PyObject *attr)
int CValue::py_setattro(PyObject *attr, PyObject* pyobj)
{
+ char *attr_str= PyString_AsString(attr);
+ CValue* oldprop = GetProperty(attr_str);
+
CValue* vallie = ConvertPythonToValue(pyobj);
if (vallie)
{
- char *attr_str= PyString_AsString(attr);
- CValue* oldprop = GetProperty(attr_str);
-
if (oldprop)
oldprop->SetValue(vallie);
else
SetProperty(attr_str, vallie);
vallie->Release();
- } else
- {
- return PY_SET_ATTR_FAIL; /* ConvertPythonToValue sets the error message */
+ }
+ else {
+ // ConvertPythonToValue sets the error message
+ // must return missing so KX_GameObect knows this
+ // attribute was not a function or bult in attribute,
+ //
+ // CValue attributes override internal attributes
+ // so if it exists as a CValue attribute already,
+ // assume your trying to set it to a differnt CValue attribute
+ // otherwise return PY_SET_ATTR_MISSING so children
+ // classes know they can set it without conflict
+
+ if (GetProperty(attr_str))
+ return PY_SET_ATTR_COERCE_FAIL; /* failed to set an existing attribute */
+ else
+ return PY_SET_ATTR_MISSING; /* allow the KX_GameObject dict to set */
}
//PyObjectPlus::py_setattro(attr,value);
diff --git a/source/gameengine/Ketsji/KX_GameObject.cpp b/source/gameengine/Ketsji/KX_GameObject.cpp
index f5bf868dd59..817afedd205 100644
--- a/source/gameengine/Ketsji/KX_GameObject.cpp
+++ b/source/gameengine/Ketsji/KX_GameObject.cpp
@@ -97,7 +97,8 @@ KX_GameObject::KX_GameObject(
m_pPhysicsEnvironment(NULL),
m_xray(false),
m_pHitObject(NULL),
- m_isDeformable(false)
+ m_isDeformable(false),
+ m_attrlist(NULL)
{
m_ignore_activity_culling = false;
m_pClient_info = new KX_ClientObjectInfo(this, KX_ClientObjectInfo::ACTOR);
@@ -139,6 +140,10 @@ KX_GameObject::~KX_GameObject()
{
delete m_pGraphicController;
}
+
+ if (m_attrlist) {
+ Py_DECREF(m_attrlist);
+ }
}
@@ -323,6 +328,9 @@ void KX_GameObject::ProcessReplica(KX_GameObject* replica)
replica->m_pClient_info = new KX_ClientObjectInfo(*m_pClient_info);
replica->m_pClient_info->m_gameobject = replica;
replica->m_state = 0;
+ if(m_attrlist)
+ replica->m_attrlist= PyDict_Copy(m_attrlist);
+
}
@@ -1138,69 +1146,124 @@ PyObject* KX_GameObject::PyGetPosition(PyObject* self)
Py_ssize_t KX_GameObject::Map_Len(PyObject* self_v)
{
- return (static_cast<KX_GameObject*>(self_v))->GetPropertyCount();
+ KX_GameObject* self= static_cast<KX_GameObject*>(self_v);
+ Py_ssize_t len= self->GetPropertyCount();
+ if(self->m_attrlist)
+ len += PyDict_Size(self->m_attrlist);
+ return len;
}
PyObject *KX_GameObject::Map_GetItem(PyObject *self_v, PyObject *item)
{
KX_GameObject* self= static_cast<KX_GameObject*>(self_v);
- const char *attr= PyString_AsString(item);
+ const char *attr_str= PyString_AsString(item);
CValue* resultattr;
PyObject* pyconvert;
-
- if(attr==NULL) {
- PyErr_SetString(PyExc_TypeError, "KX_GameObject key but a string");
- return NULL;
+ /* first see if the attributes a string and try get the cvalue attribute */
+ if(attr_str && (resultattr=self->GetProperty(attr_str))) {
+ pyconvert = resultattr->ConvertValueToPython();
+ return pyconvert ? pyconvert:resultattr;
}
-
- resultattr = self->GetProperty(attr);
-
- if(resultattr==NULL) {
- PyErr_SetString(PyExc_KeyError, "KX_GameObject key does not exist");
+ /* no CValue attribute, try get the python only m_attrlist attribute */
+ else if (self->m_attrlist && (pyconvert=PyDict_GetItem(self->m_attrlist, item))) {
+
+ if (attr_str)
+ PyErr_Clear();
+ Py_INCREF(pyconvert);
+ return pyconvert;
+ }
+ else {
+ if(attr_str) PyErr_Format(PyExc_KeyError, "KX_GameObject key \"%s\" does not exist", attr_str);
+ else PyErr_SetString(PyExc_KeyError, "KX_GameObject key does not exist");
return NULL;
}
-
- pyconvert = resultattr->ConvertValueToPython();
-
- return pyconvert ? pyconvert:resultattr;
+
}
int KX_GameObject::Map_SetItem(PyObject *self_v, PyObject *key, PyObject *val)
{
KX_GameObject* self= static_cast<KX_GameObject*>(self_v);
- const char *attr= PyString_AsString(key);
-
- if(attr==NULL) {
- PyErr_SetString(PyExc_TypeError, "KX_GameObject key but a string");
- return 1;
- }
+ const char *attr_str= PyString_AsString(key);
+ if(attr_str==NULL)
+ PyErr_Clear();
if (val==NULL) { /* del ob["key"] */
- if (self->RemoveProperty(attr)==false) {
- PyErr_Format(PyExc_KeyError, "KX_GameObject key \"%s\" not found", attr);
- return 1;
+ int del= 0;
+
+ /* try remove both just incase */
+ if(attr_str)
+ del |= (self->RemoveProperty(attr_str)==true) ? 1:0;
+
+ if(self->m_attrlist)
+ del |= (PyDict_DelItem(self->m_attrlist, key)==0) ? 1:0;
+
+ if (del==0) {
+ if(attr_str) PyErr_Format(PyExc_KeyError, "KX_GameObject key \"%s\" not found", attr_str);
+ else PyErr_SetString(PyExc_KeyError, "KX_GameObject key not found");
+ return -1;
+ }
+ else if (self->m_attrlist) {
+ PyErr_Clear(); /* PyDict_DelItem sets an error when it fails */
}
}
else { /* ob["key"] = value */
- CValue* vallie = self->ConvertPythonToValue(val);
+ int set= 0;
- if(vallie==NULL)
- return 1; /* ConvertPythonToValue sets the error */
+ /* as CValue */
+ if(attr_str)
+ {
+ CValue* vallie = self->ConvertPythonToValue(val);
+
+ if(vallie)
+ {
+ CValue* oldprop = self->GetProperty(attr_str);
+
+ if (oldprop)
+ oldprop->SetValue(vallie);
+ else
+ self->SetProperty(attr_str, vallie);
+
+ vallie->Release();
+ set= 1;
+
+ /* try remove dict value to avoid double ups */
+ if (self->m_attrlist){
+ if (PyDict_DelItem(self->m_attrlist, key) != 0)
+ PyErr_Clear();
+ }
+ }
+ else {
+ PyErr_Clear();
+ }
+ }
- CValue* oldprop = self->GetProperty(attr);
+ if(set==0)
+ {
+ if (self->m_attrlist==NULL) /* lazy init */
+ self->m_attrlist= PyDict_New();
+
+
+ if(PyDict_SetItem(self->m_attrlist, key, val)==0)
+ {
+ if(attr_str)
+ self->RemoveProperty(attr_str); /* overwrite the CValue if it exists */
+ set= 1;
+ }
+ else {
+ if(attr_str) PyErr_Format(PyExc_KeyError, "KX_GameObject key \"%s\" not be added to internal dictionary", attr_str);
+ else PyErr_SetString(PyExc_KeyError, "KX_GameObject key not be added to internal dictionary");
+ }
+ }
- if (oldprop)
- oldprop->SetValue(vallie);
- else
- self->SetProperty(attr, vallie);
+ if(set==0)
+ return -1; /* pythons error value */
- vallie->Release();
}
- return 0;
+ return 0; /* success */
}
@@ -1223,9 +1286,11 @@ PyTypeObject KX_GameObject::Type = {
0,
0,
py_base_repr,
- 0,0,0,0,0,0,
- py_base_getattro,
- py_base_setattro,
+ 0,0,
+ &Mapping,
+ 0,0,0,
+ py_base_getattro_gameobject,
+ py_base_setattro_gameobject,
0,0,0,0,0,0,0,0,0,
Methods
};
@@ -1533,6 +1598,10 @@ PyObject* KX_GameObject::pyattr_get_dir_dict(void *self_v, const KX_PYATTRIBUTE_
Py_DECREF(list);
+ /* Add m_attrlist if we have it */
+ if(self->m_attrlist)
+ PyDict_Update(dict, self->m_attrlist);
+
return dict;
}
@@ -2042,7 +2111,17 @@ PyObject* KX_GameObject::PyGetPhysicsId(PyObject* self)
PyObject* KX_GameObject::PyGetPropertyNames(PyObject* self)
{
- return ConvertKeysToPython();
+ PyObject *list= ConvertKeysToPython();
+
+ if(m_attrlist) {
+ PyObject *key, *value;
+ Py_ssize_t pos = 0;
+
+ while (PyDict_Next(m_attrlist, &pos, &key, &value)) {
+ PyList_Append(list, key);
+ }
+ }
+ return list;
}
KX_PYMETHODDEF_DOC_O(KX_GameObject, getDistanceTo,
diff --git a/source/gameengine/Ketsji/KX_GameObject.h b/source/gameengine/Ketsji/KX_GameObject.h
index 58f2c56c1da..172272150c0 100644
--- a/source/gameengine/Ketsji/KX_GameObject.h
+++ b/source/gameengine/Ketsji/KX_GameObject.h
@@ -103,6 +103,26 @@ protected:
public:
bool m_isDeformable;
+ // Python attributes that wont convert into CValue
+ //
+ // there are 2 places attributes can be stored, in the CValue,
+ // where attributes are converted into BGE's CValue types
+ // these can be used with property actuators
+ //
+ // For the python API, For types that cannot be converted into CValues (lists, dicts, GameObjects)
+ // these will be put into "m_attrlist", logic bricks cannot access them.
+ //
+ // rules for setting attributes.
+ //
+ // * there should NEVER be a CValue and a m_attrlist attribute with matching names. get/sets make sure of this.
+ // * if CValue conversion fails, use a PyObject in "m_attrlist"
+ // * when assigning a value, first see if it can be a CValue, if it can remove the "m_attrlist" and set the CValue
+ //
+
+ PyObject* m_attrlist;
+
+
+
virtual void /* This function should be virtual - derived classed override it */
Relink(
GEN_Map<GEN_HashedPtr, void*> *map
@@ -768,11 +788,108 @@ public:
/**
* @section Python interface functions.
*/
-
+
virtual PyObject* py_getattro(PyObject *attr);
virtual int py_setattro(PyObject *attr, PyObject *value); // py_setattro method
virtual PyObject* py_repr(void) { return PyString_FromString(GetName().ReadPtr()); }
+ /* we need our own getattr and setattr types */
+ /* See m_attrlist definition for rules on how this works */
+ static PyObject *py_base_getattro_gameobject(PyObject * self, PyObject *attr)
+ {
+ PyObject *object= ((KX_GameObject *) self)->py_getattro(attr);
+
+ if (object==NULL && ((KX_GameObject *) self)->m_attrlist) {
+ /* backup the exception incase the attr doesnt exist in the dict either */
+ PyObject *err_type, *err_value, *err_tb;
+ PyErr_Fetch(&err_type, &err_value, &err_tb);
+
+ object= PyDict_GetItem(((KX_GameObject *) self)->m_attrlist, attr);
+ if (object) {
+ Py_INCREF(object);
+
+ PyErr_Clear();
+ Py_XDECREF( err_type );
+ Py_XDECREF( err_value );
+ Py_XDECREF( err_tb );
+ }
+ else {
+ PyErr_Restore(err_type, err_value, err_tb); /* use the error from the parent function */
+ }
+ }
+ return object;
+ }
+
+ static int py_base_setattro_gameobject(PyObject * self, PyObject *attr, PyObject *value)
+ {
+ int ret;
+
+ /* Delete the item */
+ if (value==NULL)
+ {
+ ret= ((PyObjectPlus*) self)->py_delattro(attr);
+
+ if (ret != 0) /* CValue attribute failed, try KX_GameObject m_attrlist dict */
+ {
+ if (((KX_GameObject *) self)->m_attrlist)
+ {
+ /* backup the exception incase the attr doesnt exist in the dict either */
+ PyObject *err_type, *err_value, *err_tb;
+ PyErr_Fetch(&err_type, &err_value, &err_tb);
+
+ if (PyDict_DelItem(((KX_GameObject *) self)->m_attrlist, attr) == 0)
+ {
+ ret= 0;
+ PyErr_Clear();
+ Py_XDECREF( err_type );
+ Py_XDECREF( err_value );
+ Py_XDECREF( err_tb );
+ }
+ else {
+ PyErr_Restore(err_type, err_value, err_tb); /* use the error from the parent function */
+ }
+ }
+ }
+ return ret;
+ }
+
+
+ ret= ((PyObjectPlus*) self)->py_setattro(attr, value);
+
+ if (ret==PY_SET_ATTR_SUCCESS) {
+ /* remove attribute in our own dict to avoid double ups */
+ if (((KX_GameObject *) self)->m_attrlist) {
+ if (PyDict_DelItem(((KX_GameObject *) self)->m_attrlist, attr) != 0)
+ PyErr_Clear();
+ }
+ }
+
+ if (ret==PY_SET_ATTR_COERCE_FAIL) {
+ /* CValue attribute exists, remove and add dict value */
+ ((KX_GameObject *) self)->RemoveProperty(STR_String(PyString_AsString(attr)));
+ ret= PY_SET_ATTR_MISSING;
+ }
+
+ if (ret==PY_SET_ATTR_MISSING) {
+ /* Lazy initialization */
+ if (((KX_GameObject *) self)->m_attrlist==NULL)
+ ((KX_GameObject *) self)->m_attrlist = PyDict_New();
+
+ if (PyDict_SetItem(((KX_GameObject *) self)->m_attrlist, attr, value)==0) {
+ PyErr_Clear();
+ ret= PY_SET_ATTR_SUCCESS;
+ }
+ else {
+ PyErr_Format(PyExc_AttributeError, "failed assigning value to KX_GameObject internal dictionary");
+ ret= PY_SET_ATTR_FAIL;
+ }
+ }
+
+ return ret;
+ }
+
+
+
KX_PYMETHOD_NOARGS(KX_GameObject,GetPosition);
KX_PYMETHOD_O(KX_GameObject,SetPosition);
KX_PYMETHOD_O(KX_GameObject,SetWorldPosition);
diff --git a/source/gameengine/Ketsji/KX_Scene.h b/source/gameengine/Ketsji/KX_Scene.h
index b70c6d3e8d3..55e7afa4957 100644
--- a/source/gameengine/Ketsji/KX_Scene.h
+++ b/source/gameengine/Ketsji/KX_Scene.h
@@ -603,6 +603,7 @@ public:
ret= PY_SET_ATTR_SUCCESS;
}
else {
+ PyErr_Format(PyExc_AttributeError, "failed assigning value to KX_Scenes internal dictionary");
ret= PY_SET_ATTR_FAIL;
}
}