diff options
Diffstat (limited to 'source/gameengine/Expressions')
25 files changed, 778 insertions, 402 deletions
diff --git a/source/gameengine/Expressions/BoolValue.cpp b/source/gameengine/Expressions/BoolValue.cpp index 13c870b68e5..d90da8b3a92 100644 --- a/source/gameengine/Expressions/BoolValue.cpp +++ b/source/gameengine/Expressions/BoolValue.cpp @@ -26,6 +26,9 @@ // Construction/Destruction ////////////////////////////////////////////////////////////////////// +const STR_String CBoolValue::sTrueString = "TRUE"; +const STR_String CBoolValue::sFalseString = "FALSE"; + CBoolValue::CBoolValue() /* @@ -45,7 +48,7 @@ CBoolValue::CBoolValue(bool inBool) -CBoolValue::CBoolValue(bool innie,STR_String name,AllocationTYPE alloctype) +CBoolValue::CBoolValue(bool innie,const char *name,AllocationTYPE alloctype) { m_bool = innie; SetName(name); @@ -190,9 +193,6 @@ double CBoolValue::GetNumber() const STR_String& CBoolValue::GetText() { - static STR_String sTrueString = STR_String("TRUE"); - static STR_String sFalseString = STR_String("FALSE"); - return m_bool ? sTrueString : sFalseString; } @@ -201,7 +201,7 @@ const STR_String& CBoolValue::GetText() CValue* CBoolValue::GetReplica() { CBoolValue* replica = new CBoolValue(*this); - CValue::AddDataToReplica(replica); + replica->ProcessReplica(); return replica; } diff --git a/source/gameengine/Expressions/BoolValue.h b/source/gameengine/Expressions/BoolValue.h index 9352b9d4b92..726619e7193 100644 --- a/source/gameengine/Expressions/BoolValue.h +++ b/source/gameengine/Expressions/BoolValue.h @@ -28,9 +28,12 @@ class CBoolValue : public CPropValue //PLUGIN_DECLARE_SERIAL(CBoolValue,CValue) public: + static const STR_String sTrueString; + static const STR_String sFalseString; + CBoolValue(); CBoolValue(bool inBool); - CBoolValue(bool innie, STR_String name, AllocationTYPE alloctype = CValue::HEAPVALUE); + CBoolValue(bool innie, const char *name, AllocationTYPE alloctype = CValue::HEAPVALUE); virtual const STR_String& GetText(); virtual double GetNumber(); diff --git a/source/gameengine/Expressions/CMakeLists.txt b/source/gameengine/Expressions/CMakeLists.txt index 6b2a835d648..e3942b46557 100644 --- a/source/gameengine/Expressions/CMakeLists.txt +++ b/source/gameengine/Expressions/CMakeLists.txt @@ -31,6 +31,7 @@ SET(INC ../../../source/kernel/gen_system ../../../intern/string ../../../intern/moto/include + ../../../source/gameengine/SceneGraph ${PYTHON_INC} ) diff --git a/source/gameengine/Expressions/EmptyValue.cpp b/source/gameengine/Expressions/EmptyValue.cpp index f72ddc47096..5d1273b5301 100644 --- a/source/gameengine/Expressions/EmptyValue.cpp +++ b/source/gameengine/Expressions/EmptyValue.cpp @@ -121,7 +121,7 @@ const STR_String & CEmptyValue::GetText() CValue* CEmptyValue::GetReplica() { CEmptyValue* replica = new CEmptyValue(*this); - CValue::AddDataToReplica(replica); + replica->ProcessReplica(); return replica; } diff --git a/source/gameengine/Expressions/ErrorValue.cpp b/source/gameengine/Expressions/ErrorValue.cpp index 651a772db19..a44abf8b22e 100644 --- a/source/gameengine/Expressions/ErrorValue.cpp +++ b/source/gameengine/Expressions/ErrorValue.cpp @@ -34,13 +34,15 @@ effect: constructs a new CErrorValue containing errormessage "Error" -CErrorValue::CErrorValue(STR_String errmsg) +CErrorValue::CErrorValue(const char *errmsg) /* pre: effect: constructs a new CErrorValue containing errormessage errmsg */ { - m_strErrorText = "[" + errmsg + "]"; + m_strErrorText = "["; + m_strErrorText += errmsg; + m_strErrorText += "]"; SetError(true); } diff --git a/source/gameengine/Expressions/ErrorValue.h b/source/gameengine/Expressions/ErrorValue.h index 5b5795196ba..b4b758feea7 100644 --- a/source/gameengine/Expressions/ErrorValue.h +++ b/source/gameengine/Expressions/ErrorValue.h @@ -25,7 +25,7 @@ public: virtual const STR_String & GetText(); virtual double GetNumber(); CErrorValue(); - CErrorValue(STR_String errmsg); + CErrorValue(const char *errmsg); virtual ~CErrorValue(); virtual CValue* Calc(VALUE_OPERATOR op, CValue* val); virtual CValue* CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue *val); diff --git a/source/gameengine/Expressions/FloatValue.cpp b/source/gameengine/Expressions/FloatValue.cpp index 212a55fe457..4de685a82c1 100644 --- a/source/gameengine/Expressions/FloatValue.cpp +++ b/source/gameengine/Expressions/FloatValue.cpp @@ -50,7 +50,7 @@ effect: constructs a new CFloatValue containing value fl -CFloatValue::CFloatValue(float fl,STR_String name,AllocationTYPE alloctype) +CFloatValue::CFloatValue(float fl,const char *name,AllocationTYPE alloctype) /* pre: effect: constructs a new CFloatValue containing value fl @@ -307,8 +307,8 @@ const STR_String & CFloatValue::GetText() CValue* CFloatValue::GetReplica() { CFloatValue* replica = new CFloatValue(*this); - replica->m_pstrRep = NULL; - CValue::AddDataToReplica(replica); + replica->m_pstrRep = NULL; /* should be in CFloatValue::ProcessReplica() but its not defined, no matter */ + replica->ProcessReplica(); return replica; } diff --git a/source/gameengine/Expressions/FloatValue.h b/source/gameengine/Expressions/FloatValue.h index 41f70b5c54c..fb75b7c702b 100644 --- a/source/gameengine/Expressions/FloatValue.h +++ b/source/gameengine/Expressions/FloatValue.h @@ -23,7 +23,7 @@ class CFloatValue : public CPropValue public: CFloatValue(); CFloatValue(float fl); - CFloatValue(float fl,STR_String name,AllocationTYPE alloctype=CValue::HEAPVALUE); + CFloatValue(float fl,const char *name,AllocationTYPE alloctype=CValue::HEAPVALUE); virtual const STR_String & GetText(); diff --git a/source/gameengine/Expressions/IfExpr.cpp b/source/gameengine/Expressions/IfExpr.cpp index 5d3eb3641ca..fcb37bff52d 100644 --- a/source/gameengine/Expressions/IfExpr.cpp +++ b/source/gameengine/Expressions/IfExpr.cpp @@ -15,6 +15,7 @@ #include "IfExpr.h" #include "EmptyValue.h" #include "ErrorValue.h" +#include "BoolValue.h" #ifdef HAVE_CONFIG_H #include <config.h> @@ -72,14 +73,14 @@ ret: a new object containing the value of m_e1 if m_guard is a boolean TRUE { CValue *guardval; guardval = m_guard->Calculate(); - STR_String text = guardval->GetText(); + const STR_String& text = guardval->GetText(); guardval->Release(); - if (text == STR_String("TRUE")) + if (&text == &CBoolValue::sTrueString) { return m_e1->Calculate(); } - else if (text == STR_String("FALSE")) + else if (&text == &CBoolValue::sFalseString) { return m_e2->Calculate(); } diff --git a/source/gameengine/Expressions/InputParser.cpp b/source/gameengine/Expressions/InputParser.cpp index 66075dd8d42..b15b206a38a 100644 --- a/source/gameengine/Expressions/InputParser.cpp +++ b/source/gameengine/Expressions/InputParser.cpp @@ -38,7 +38,7 @@ // cool things like (IF(LOD==1,CCurvedValue,IF(LOD==2,CCurvedValue2)) etc... #include "IfExpr.h" -#if defined(WIN32) || defined(WIN64) +#if (defined(WIN32) || defined(WIN64)) && !defined(FREE_WINDOWS) #define strcasecmp _stricmp #ifndef strtoll @@ -66,7 +66,7 @@ CParser::~CParser() -void CParser::ScanError(STR_String str) +void CParser::ScanError(const char *str) { // sets the global variable errmsg to an errormessage with // contents str, appending if it already exists @@ -81,7 +81,7 @@ void CParser::ScanError(STR_String str) -CExpression* CParser::Error(STR_String str) +CExpression* CParser::Error(const char *str) { // makes and returns a new CConstExpr filled with an CErrorValue // with string str @@ -537,7 +537,7 @@ CExpression *CParser::Expr() { } CExpression* CParser::ProcessText -(STR_String intext) { +(const char *intext) { // and parses the string in intext and returns it. @@ -574,7 +574,7 @@ CExpression* CParser::ProcessText -float CParser::GetFloat(STR_String txt) +float CParser::GetFloat(STR_String& txt) { // returns parsed text into a float // empty string returns -1 @@ -599,7 +599,7 @@ float CParser::GetFloat(STR_String txt) return result; } -CValue* CParser::GetValue(STR_String txt, bool bFallbackToText) +CValue* CParser::GetValue(STR_String& txt, bool bFallbackToText) { // returns parsed text into a value, // empty string returns NULL value ! @@ -658,10 +658,41 @@ static PyMethodDef CParserMethods[] = { NULL,NULL} // Sentinel }; + +#if (PY_VERSION_HEX >= 0x03000000) +static struct PyModuleDef Expression_module_def = { + {}, /* m_base */ + "Expression", /* m_name */ + 0, /* m_doc */ + 0, /* m_size */ + CParserMethods, /* m_methods */ + 0, /* m_reload */ + 0, /* m_traverse */ + 0, /* m_clear */ + 0, /* m_free */ +}; +#endif + extern "C" { void initExpressionModule(void) { - Py_InitModule("Expression",CParserMethods); + PyObject *m; + /* Use existing module where possible + * be careful not to init any runtime vars after this */ + m = PyImport_ImportModule( "Expression" ); + if(m) { + Py_DECREF(m); + //return m; + } + else { + PyErr_Clear(); + +#if (PY_VERSION_HEX >= 0x03000000) + PyModule_Create(&Expression_module_def); +#else + Py_InitModule("Expression",CParserMethods); +#endif + } } } diff --git a/source/gameengine/Expressions/InputParser.h b/source/gameengine/Expressions/InputParser.h index 3d517222639..810bdc244a8 100644 --- a/source/gameengine/Expressions/InputParser.h +++ b/source/gameengine/Expressions/InputParser.h @@ -27,9 +27,9 @@ public: CParser(); virtual ~CParser(); - float GetFloat(STR_String txt); - CValue* GetValue(STR_String txt, bool bFallbackToText=false); - CExpression* ProcessText(STR_String intext); + float GetFloat(STR_String& txt); + CValue* GetValue(STR_String& txt, bool bFallbackToText=false); + CExpression* ProcessText(const char *intext); void SetContext(CValue* context); private: @@ -86,8 +86,8 @@ private: CValue* m_identifierContext;// context in which identifiers are looked up - void ScanError(STR_String str); - CExpression* Error(STR_String str); + void ScanError(const char *str); + CExpression* Error(const char *str); void NextCh(); void TermChar(char c); void DigRep(); diff --git a/source/gameengine/Expressions/IntValue.cpp b/source/gameengine/Expressions/IntValue.cpp index 4e86f7bf789..227518e9439 100644 --- a/source/gameengine/Expressions/IntValue.cpp +++ b/source/gameengine/Expressions/IntValue.cpp @@ -54,7 +54,7 @@ effect: constructs a new CIntValue containing cInt innie -CIntValue::CIntValue(cInt innie,STR_String name,AllocationTYPE alloctype) +CIntValue::CIntValue(cInt innie,const char *name,AllocationTYPE alloctype) { m_int = innie; SetName(name); @@ -311,7 +311,7 @@ const STR_String & CIntValue::GetText() CValue* CIntValue::GetReplica() { CIntValue* replica = new CIntValue(*this); - CValue::AddDataToReplica(replica); + replica->ProcessReplica(); replica->m_pstrRep = NULL; return replica; diff --git a/source/gameengine/Expressions/IntValue.h b/source/gameengine/Expressions/IntValue.h index 0f3a38b274b..06bf1755749 100644 --- a/source/gameengine/Expressions/IntValue.h +++ b/source/gameengine/Expressions/IntValue.h @@ -32,7 +32,7 @@ public: CIntValue(); CIntValue(cInt innie); CIntValue(cInt innie, - STR_String name, + const char *name, AllocationTYPE alloctype=CValue::HEAPVALUE); virtual CValue* Calc(VALUE_OPERATOR op, diff --git a/source/gameengine/Expressions/ListValue.cpp b/source/gameengine/Expressions/ListValue.cpp index dd9b296dce1..a0d73c75d60 100644 --- a/source/gameengine/Expressions/ListValue.cpp +++ b/source/gameengine/Expressions/ListValue.cpp @@ -18,6 +18,7 @@ #include "StringValue.h" #include "VoidValue.h" #include <algorithm> +#include "BoolValue.h" #ifdef HAVE_CONFIG_H #include <config.h> @@ -39,8 +40,10 @@ Py_ssize_t listvalue_bufferlen(PyObject* self) PyObject* listvalue_buffer_item(PyObject* self, Py_ssize_t index) { CListValue *list= static_cast<CListValue *>(BGE_PROXY_REF(self)); + CValue *cval; + if (list==NULL) { - PyErr_SetString(PyExc_IndexError, BGE_PROXY_ERROR_MSG); + PyErr_SetString(PyExc_SystemError, "val = CList[i], "BGE_PROXY_ERROR_MSG); return NULL; } @@ -49,43 +52,47 @@ PyObject* listvalue_buffer_item(PyObject* self, Py_ssize_t index) if (index < 0) index = count+index; - if (index >= 0 && index < count) - { - PyObject* pyobj = list->GetValue(index)->ConvertValueToPython(); - if (pyobj) - return pyobj; - else - return list->GetValue(index)->GetProxy(); - + if (index < 0 || index >= count) { + PyErr_SetString(PyExc_IndexError, "CList[i]: Python ListIndex out of range in CValueList"); + return NULL; } - PyErr_SetString(PyExc_IndexError, "list[i]: Python ListIndex out of range in CValueList"); - return NULL; + + cval= list->GetValue(index); + + PyObject* pyobj = cval->ConvertValueToPython(); + if (pyobj) + return pyobj; + else + return cval->GetProxy(); } PyObject* listvalue_mapping_subscript(PyObject* self, PyObject* pyindex) { CListValue *list= static_cast<CListValue *>(BGE_PROXY_REF(self)); if (list==NULL) { - PyErr_SetString(PyExc_IndexError, BGE_PROXY_ERROR_MSG); + PyErr_SetString(PyExc_SystemError, "value = CList[i], "BGE_PROXY_ERROR_MSG); return NULL; } if (PyString_Check(pyindex)) { - STR_String index(PyString_AsString(pyindex)); - CValue *item = ((CListValue*) list)->FindValue(index); - if (item) - return item->GetProxy(); - + CValue *item = ((CListValue*) list)->FindValue(PyString_AsString(pyindex)); + if (item) { + PyObject* pyobj = item->ConvertValueToPython(); + if(pyobj) + return pyobj; + else + return item->GetProxy(); + } } - if (PyInt_Check(pyindex)) + else if (PyInt_Check(pyindex)) { int index = PyInt_AsLong(pyindex); - return listvalue_buffer_item(self, index); + return listvalue_buffer_item(self, index); /* wont add a ref */ } PyObject *pyindex_str = PyObject_Repr(pyindex); /* new ref */ - PyErr_Format(PyExc_KeyError, "list[key]: '%s' key not in list", PyString_AsString(pyindex_str)); + PyErr_Format(PyExc_KeyError, "CList[key]: '%s' key not in list", PyString_AsString(pyindex_str)); Py_DECREF(pyindex_str); return NULL; } @@ -96,7 +103,7 @@ PyObject* listvalue_buffer_slice(PyObject* self,Py_ssize_t ilow, Py_ssize_t ihig { CListValue *list= static_cast<CListValue *>(BGE_PROXY_REF(self)); if (list==NULL) { - PyErr_SetString(PyExc_IndexError, BGE_PROXY_ERROR_MSG); + PyErr_SetString(PyExc_SystemError, "val = CList[i:j], "BGE_PROXY_ERROR_MSG); return NULL; } @@ -127,73 +134,79 @@ PyObject* listvalue_buffer_slice(PyObject* self,Py_ssize_t ilow, Py_ssize_t ihig } - -static PyObject * -listvalue_buffer_concat(PyObject * self, PyObject * other) +/* clist + list, return a list that python owns */ +static PyObject *listvalue_buffer_concat(PyObject * self, PyObject * other) { CListValue *listval= static_cast<CListValue *>(BGE_PROXY_REF(self)); + int i, numitems, numitems_orig; + if (listval==NULL) { - PyErr_SetString(PyExc_IndexError, BGE_PROXY_ERROR_MSG); + PyErr_SetString(PyExc_SystemError, "CList+other, "BGE_PROXY_ERROR_MSG); return NULL; } + numitems_orig= listval->GetCount(); + // for now, we support CListValue concatenated with items // and CListValue concatenated to Python Lists // and CListValue concatenated with another CListValue - listval->AddRef(); - if (other->ob_type == &PyList_Type) + /* Shallow copy, dont use listval->GetReplica(), it will screw up with KX_GameObjects */ + CListValue* listval_new = new CListValue(); + + if (PyList_Check(other)) { + CValue* listitemval; bool error = false; - - int i; - int numitems = PyList_Size(other); + + numitems = PyList_Size(other); + + /* copy the first part of the list */ + listval_new->Resize(numitems_orig + numitems); + for (i=0;i<numitems_orig;i++) + listval_new->SetValue(i, listval->GetValue(i)->AddRef()); + for (i=0;i<numitems;i++) { - PyObject* listitem = PyList_GetItem(other,i); - CValue* listitemval = listval->ConvertPythonToValue(listitem); - if (listitemval) - { - listval->Add(listitemval); - } else - { - error = true; + listitemval = listval->ConvertPythonToValue(PyList_GetItem(other,i), "cList + pyList: CListValue, "); + + if (listitemval) { + listval_new->SetValue(i+numitems_orig, listitemval); + } else { + error= true; + break; } } - + if (error) { - PyErr_SetString(PyExc_SystemError, "list.append(val): couldn't add one or more items to this CValueList"); - return NULL; + listval_new->Resize(numitems_orig+i); /* resize so we dont try release NULL pointers */ + listval_new->Release(); + return NULL; /* ConvertPythonToValue above sets the error */ } - - } else - { - if (other->ob_type == &CListValue::Type) - { - // add items from otherlist to this list - CListValue* otherval = (CListValue*) other; - - - for (int i=0;i<otherval->GetCount();i++) - { - otherval->Add(listval->GetValue(i)->AddRef()); - } - } - else - { - CValue* objval = listval->ConvertPythonToValue(other); - if (objval) - { - listval->Add(objval); - } else - { - PyErr_SetString(PyExc_SystemError, "list.append(i): couldn't add item to this CValueList"); - return NULL; - } + + } + else if (PyObject_TypeCheck(other, &CListValue::Type)) { + // add items from otherlist to this list + CListValue* otherval = static_cast<CListValue *>(BGE_PROXY_REF(other)); + if(otherval==NULL) { + listval_new->Release(); + PyErr_SetString(PyExc_SystemError, "CList+other, "BGE_PROXY_ERROR_MSG); + return NULL; } + + numitems = otherval->GetCount(); + + /* copy the first part of the list */ + listval_new->Resize(numitems_orig + numitems); /* resize so we dont try release NULL pointers */ + for (i=0;i<numitems_orig;i++) + listval_new->SetValue(i, listval->GetValue(i)->AddRef()); + + /* now copy the other part of the list */ + for (i=0;i<numitems;i++) + listval_new->SetValue(i+numitems_orig, otherval->GetValue(i)->AddRef()); + } - - return self; + return listval_new->NewProxy(true); /* python owns this list */ } @@ -203,9 +216,15 @@ static PySequenceMethods listvalue_as_sequence = { listvalue_buffer_concat, /*sq_concat*/ NULL, /*sq_repeat*/ listvalue_buffer_item, /*sq_item*/ +#if (PY_VERSION_HEX >= 0x03000000) // TODO, slicing in py3? + NULL, + NULL, + NULL, +#else listvalue_buffer_slice, /*sq_slice*/ NULL, /*sq_ass_item*/ - NULL /*sq_ass_slice*/ + NULL, /*sq_ass_slice*/ +#endif }; @@ -220,8 +239,13 @@ static PyMappingMethods instance_as_mapping = { PyTypeObject CListValue::Type = { - PyObject_HEAD_INIT(NULL) +#if (PY_VERSION_HEX >= 0x02060000) + PyVarObject_HEAD_INIT(NULL, 0) +#else + /* python 2.5 and below */ + PyObject_HEAD_INIT( NULL ) /* required py macro */ 0, /*ob_size*/ +#endif "CListValue", /*tp_name*/ sizeof(PyObjectPlus_Proxy), /*tp_basicsize*/ 0, /*tp_itemsize*/ @@ -256,10 +280,17 @@ PyParentObject CListValue::Parents[] = { PyMethodDef CListValue::Methods[] = { + /* List style access */ {"append", (PyCFunction)CListValue::sPyappend,METH_O}, {"reverse", (PyCFunction)CListValue::sPyreverse,METH_NOARGS}, {"index", (PyCFunction)CListValue::sPyindex,METH_O}, {"count", (PyCFunction)CListValue::sPycount,METH_O}, + + /* Dict style access */ + {"get", (PyCFunction)CListValue::sPyget,METH_VARARGS}, + {"has_key", (PyCFunction)CListValue::sPyhas_key,METH_O}, + + /* Own cvalue funcs */ {"from_id", (PyCFunction)CListValue::sPyfrom_id,METH_O}, {NULL,NULL} //Sentinel @@ -273,6 +304,10 @@ PyObject* CListValue::py_getattro(PyObject* attr) { py_getattro_up(CValue); } +PyObject* CListValue::py_getattro_dict() { + py_getattro_dict_up(CValue); +} + ////////////////////////////////////////////////////////////////////// // Construction/Destruction @@ -320,7 +355,7 @@ const STR_String & CListValue::GetText() CValue* CListValue::GetReplica() { CListValue* replica = new CListValue(*this); - CValue::AddDataToReplica(replica); + replica->ProcessReplica(); replica->m_bReleaseContents=true; // for copy, complete array is copied for now... // copy all values @@ -370,23 +405,21 @@ void CListValue::ReleaseAndRemoveAll() CValue* CListValue::FindValue(const STR_String & name) { - CValue* resultval = NULL; - int i=0; + for (int i=0; i < GetCount(); i++) + if (GetValue(i)->GetName() == name) + return GetValue(i); - while (!resultval && i < GetCount()) - { - CValue* myval = GetValue(i); - - if (myval->GetName() == name) - resultval = GetValue(i)->AddRef(); // add referencecount - else - i++; - - } - return resultval; + return NULL; } - +CValue* CListValue::FindValue(const char * name) +{ + for (int i=0; i < GetCount(); i++) + if (GetValue(i)->GetName() == name) + return GetValue(i); + + return NULL; +} bool CListValue::SearchValue(CValue *val) { @@ -433,14 +466,24 @@ void CListValue::MergeList(CListValue *otherlist) { SetValue(i+numelements,otherlist->GetValue(i)->AddRef()); } - } - PyObject* CListValue::Pyappend(PyObject* value) { - return listvalue_buffer_concat(m_proxy, value); /* m_proxy is the same as self */ + CValue* objval = ConvertPythonToValue(value, "CList.append(i): CValueList, "); + + if (!objval) /* ConvertPythonToValue sets the error */ + return NULL; + + if (!BGE_PROXY_PYOWNS(m_proxy)) { + PyErr_SetString(PyExc_TypeError, "CList.append(i): this CValueList is used internally for the game engine and can't be modified"); + return NULL; + } + + Add(objval); + + Py_RETURN_NONE; } @@ -461,13 +504,12 @@ bool CListValue::CheckEqual(CValue* first,CValue* second) if (eqval==NULL) return false; - - STR_String txt = eqval->GetText(); - eqval->Release(); - if (txt=="TRUE") + const STR_String& text = eqval->GetText(); + if (&text==&CBoolValue::sTrueString) { result = true; } + eqval->Release(); return result; } @@ -478,7 +520,7 @@ PyObject* CListValue::Pyindex(PyObject *value) { PyObject* result = NULL; - CValue* checkobj = ConvertPythonToValue(value); + CValue* checkobj = ConvertPythonToValue(value, "val = cList[i]: CValueList, "); if (checkobj==NULL) return NULL; /* ConvertPythonToValue sets the error */ @@ -495,7 +537,7 @@ PyObject* CListValue::Pyindex(PyObject *value) checkobj->Release(); if (result==NULL) { - PyErr_SetString(PyExc_ValueError, "list.index(x): x not in CListValue"); + PyErr_SetString(PyExc_ValueError, "CList.index(x): x not in CListValue"); } return result; @@ -507,7 +549,7 @@ PyObject* CListValue::Pycount(PyObject* value) { int numfound = 0; - CValue* checkobj = ConvertPythonToValue(value); + CValue* checkobj = ConvertPythonToValue(value, ""); /* error ignored */ if (checkobj==NULL) { /* in this case just return that there are no items in the list */ PyErr_Clear(); @@ -528,7 +570,35 @@ PyObject* CListValue::Pycount(PyObject* value) return PyInt_FromLong(numfound); } +/* Matches python dict.get(key, [default]) */ +PyObject* CListValue::Pyget(PyObject *args) +{ + char *key; + PyObject* def = Py_None; + + if (!PyArg_ParseTuple(args, "s|O:get", &key, &def)) + return NULL; + + CValue *item = FindValue((const char *)key); + if (item) { + PyObject* pyobj = item->ConvertValueToPython(); + if (pyobj) + return pyobj; + else + return item->GetProxy(); + } + Py_INCREF(def); + return def; +} +/* Matches python dict.has_key() */ +PyObject* CListValue::Pyhas_key(PyObject* value) +{ + if (PyString_Check(value) && FindValue((const char *)PyString_AsString(value))) + Py_RETURN_TRUE; + + Py_RETURN_FALSE; +} PyObject* CListValue::Pyfrom_id(PyObject* value) { @@ -555,18 +625,24 @@ PyObject* CListValue::Pyfrom_id(PyObject* value) CValue* CListValue::Calc(VALUE_OPERATOR op,CValue *val) { //assert(false); // todo: implement me! - fprintf(stderr, "CValueList::Calc not yet implimented\n"); + static int error_printed = 0; + if (error_printed==0) { + fprintf(stderr, "CValueList::Calc not yet implimented\n"); + error_printed = 1; + } return NULL; } - - CValue* CListValue::CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue* val) { //assert(false); // todo: implement me! - fprintf(stderr, "CValueList::CalcFinal not yet implimented\n"); + static int error_printed = 0; + if (error_printed==0) { + fprintf(stderr, "CValueList::CalcFinal not yet implimented\n"); + error_printed = 1; + } return NULL; } diff --git a/source/gameengine/Expressions/ListValue.h b/source/gameengine/Expressions/ListValue.h index 2af5a330c43..68e900e25e0 100644 --- a/source/gameengine/Expressions/ListValue.h +++ b/source/gameengine/Expressions/ListValue.h @@ -46,6 +46,7 @@ public: bool SearchValue(CValue* val); CValue* FindValue(const STR_String & name); + CValue* FindValue(const char *name); void ReleaseAndRemoveAll(); virtual void SetModified(bool bModified); @@ -60,6 +61,7 @@ public: bool CheckEqual(CValue* first,CValue* second); virtual PyObject* py_getattro(PyObject* attr); + virtual PyObject* py_getattro_dict(); virtual PyObject* py_repr(void) { PyObject *py_proxy= this->GetProxy(); PyObject *py_list= PySequence_List(py_proxy); @@ -73,6 +75,8 @@ public: KX_PYMETHOD_NOARGS(CListValue,reverse); KX_PYMETHOD_O(CListValue,index); KX_PYMETHOD_O(CListValue,count); + KX_PYMETHOD_VARARGS(CListValue,get); + KX_PYMETHOD_O(CListValue,has_key); KX_PYMETHOD_O(CListValue,from_id); diff --git a/source/gameengine/Expressions/Makefile b/source/gameengine/Expressions/Makefile index 6736149bbcd..f46c0037200 100644 --- a/source/gameengine/Expressions/Makefile +++ b/source/gameengine/Expressions/Makefile @@ -41,4 +41,5 @@ CPPFLAGS += -I../../blender/makesdna CPPFLAGS += -I$(NAN_STRING)/include CPPFLAGS += -I$(NAN_MOTO)/include CPPFLAGS += -I../../kernel/gen_system +CPPFLAGS += -I../../gameengine/SceneGraph diff --git a/source/gameengine/Expressions/PyObjectPlus.cpp b/source/gameengine/Expressions/PyObjectPlus.cpp index 6cfa14ddc80..defb6853e67 100644 --- a/source/gameengine/Expressions/PyObjectPlus.cpp +++ b/source/gameengine/Expressions/PyObjectPlus.cpp @@ -50,14 +50,20 @@ #include "stdlib.h" #include "PyObjectPlus.h" #include "STR_String.h" +#include "MT_Vector3.h" /*------------------------------ * PyObjectPlus Type -- Every class, even the abstract one should have a Type ------------------------------*/ PyTypeObject PyObjectPlus::Type = { - PyObject_HEAD_INIT(NULL) +#if (PY_VERSION_HEX >= 0x02060000) + PyVarObject_HEAD_INIT(NULL, 0) +#else + /* python 2.5 and below */ + PyObject_HEAD_INIT( NULL ) /* required py macro */ 0, /*ob_size*/ +#endif "PyObjectPlus", /*tp_name*/ sizeof(PyObjectPlus_Proxy), /*tp_basicsize*/ 0, /*tp_itemsize*/ @@ -90,6 +96,7 @@ void PyObjectPlus::py_base_dealloc(PyObject *self) // python wrapper PyObjectPlus *self_plus= BGE_PROXY_REF(self); if(self_plus) { if(BGE_PROXY_PYOWNS(self)) { /* Does python own this?, then delete it */ + self_plus->m_proxy = NULL; /* Need this to stop ~PyObjectPlus from decrefing m_proxy otherwise its decref'd twice and py-debug crashes */ delete self_plus; } @@ -98,7 +105,7 @@ void PyObjectPlus::py_base_dealloc(PyObject *self) // python wrapper PyObject_DEL( self ); }; -PyObjectPlus::PyObjectPlus(PyTypeObject *T) // constructor +PyObjectPlus::PyObjectPlus(PyTypeObject *T) : SG_QList() // constructor { MT_assert(T != NULL); m_proxy= NULL; @@ -113,13 +120,13 @@ PyMethodDef PyObjectPlus::Methods[] = { }; PyAttributeDef PyObjectPlus::Attributes[] = { - KX_PYATTRIBUTE_RO_FUNCTION("isValid", PyObjectPlus, pyattr_get_is_valid), + KX_PYATTRIBUTE_RO_FUNCTION("invalid", PyObjectPlus, pyattr_get_invalid), {NULL} //Sentinel }; -PyObject* PyObjectPlus::pyattr_get_is_valid(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject* PyObjectPlus::pyattr_get_invalid(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { - Py_RETURN_TRUE; + Py_RETURN_FALSE; } /*------------------------------ @@ -137,13 +144,33 @@ PyObject *PyObjectPlus::py_base_getattro(PyObject * self, PyObject *attr) { PyObjectPlus *self_plus= BGE_PROXY_REF(self); if(self_plus==NULL) { - if(!strcmp("isValid", PyString_AsString(attr))) { + if(!strcmp("invalid", PyString_AsString(attr))) { Py_RETURN_TRUE; } - PyErr_SetString(PyExc_RuntimeError, BGE_PROXY_ERROR_MSG); + PyErr_SetString(PyExc_SystemError, BGE_PROXY_ERROR_MSG); return NULL; } - return self_plus->py_getattro(attr); + + PyObject *ret= self_plus->py_getattro(attr); + + /* Attribute not found, was this a __dict__ lookup?, otherwise set an error if none is set */ + if(ret==NULL) { + char *attr_str= PyString_AsString(attr); + + if (strcmp(attr_str, "__dict__")==0) + { + /* the error string will probably not + * be set but just incase clear it */ + PyErr_Clear(); + ret= self_plus->py_getattro_dict(); + } + else if (!PyErr_Occurred()) { + /* We looked for an attribute but it wasnt found + * since py_getattro didnt set the error, set it here */ + PyErr_Format(PyExc_AttributeError, "'%s' object has no attribute '%s'", self->ob_type->tp_name, attr_str); + } + } + return ret; } /* This should be the entry in Type since it takes the C++ class from PyObjectPlus_Proxy */ @@ -151,7 +178,7 @@ int PyObjectPlus::py_base_setattro(PyObject *self, PyObject *attr, PyObject *val { PyObjectPlus *self_plus= BGE_PROXY_REF(self); if(self_plus==NULL) { - PyErr_SetString(PyExc_RuntimeError, BGE_PROXY_ERROR_MSG); + PyErr_SetString(PyExc_SystemError, BGE_PROXY_ERROR_MSG); return -1; } @@ -166,7 +193,7 @@ PyObject *PyObjectPlus::py_base_repr(PyObject *self) // This should be the ent PyObjectPlus *self_plus= BGE_PROXY_REF(self); if(self_plus==NULL) { - PyErr_SetString(PyExc_RuntimeError, BGE_PROXY_ERROR_MSG); + PyErr_SetString(PyExc_SystemError, BGE_PROXY_ERROR_MSG); return NULL; } @@ -177,11 +204,7 @@ PyObject *PyObjectPlus::py_getattro(PyObject* attr) { PyObject *descr = PyDict_GetItem(Type.tp_dict, attr); \ if (descr == NULL) { - if (strcmp(PyString_AsString(attr), "__dict__")==0) { - return py_getattr_dict(NULL, Type.tp_dict); /* no Attributes yet */ - } - PyErr_Format(PyExc_AttributeError, "attribute \"%s\" not found", PyString_AsString(attr)); - return NULL; + return NULL; /* py_base_getattro sets the error, this way we can avoid setting the error at many levels */ } else { /* Copied from py_getattro_up */ if (PyCObject_Check(descr)) { @@ -189,13 +212,16 @@ PyObject *PyObjectPlus::py_getattro(PyObject* attr) } else if (descr->ob_type->tp_descr_get) { return PyCFunction_New(((PyMethodDescrObject *)descr)->d_method, this->m_proxy); } else { - fprintf(stderr, "Unknown attribute type (PyObjectPlus::py_getattro)"); - return descr; + return NULL; } /* end py_getattro_up copy */ } } +PyObject* PyObjectPlus::py_getattro_dict() { + return py_getattr_dict(NULL, Type.tp_dict); +} + int PyObjectPlus::py_delattro(PyObject* attr) { PyErr_SetString(PyExc_AttributeError, "attribute cant be deleted"); @@ -233,14 +259,14 @@ PyObject *PyObjectPlus::py_get_attrdef(void *self, const PyAttributeDef *attrdef { bool *val = reinterpret_cast<bool*>(ptr); ptr += sizeof(bool); - PyList_SetItem(resultlist,i,PyInt_FromLong(*val)); + PyList_SET_ITEM(resultlist,i,PyInt_FromLong(*val)); break; } case KX_PYATTRIBUTE_TYPE_SHORT: { short int *val = reinterpret_cast<short int*>(ptr); ptr += sizeof(short int); - PyList_SetItem(resultlist,i,PyInt_FromLong(*val)); + PyList_SET_ITEM(resultlist,i,PyInt_FromLong(*val)); break; } case KX_PYATTRIBUTE_TYPE_ENUM: @@ -255,14 +281,14 @@ PyObject *PyObjectPlus::py_get_attrdef(void *self, const PyAttributeDef *attrdef { int *val = reinterpret_cast<int*>(ptr); ptr += sizeof(int); - PyList_SetItem(resultlist,i,PyInt_FromLong(*val)); + PyList_SET_ITEM(resultlist,i,PyInt_FromLong(*val)); break; } case KX_PYATTRIBUTE_TYPE_FLOAT: { float *val = reinterpret_cast<float*>(ptr); ptr += sizeof(float); - PyList_SetItem(resultlist,i,PyFloat_FromDouble(*val)); + PyList_SET_ITEM(resultlist,i,PyFloat_FromDouble(*val)); break; } default: @@ -303,6 +329,16 @@ PyObject *PyObjectPlus::py_get_attrdef(void *self, const PyAttributeDef *attrdef float *val = reinterpret_cast<float*>(ptr); return PyFloat_FromDouble(*val); } + case KX_PYATTRIBUTE_TYPE_VECTOR: + { + PyObject* resultlist = PyList_New(3); + MT_Vector3 *val = reinterpret_cast<MT_Vector3*>(ptr); + for (unsigned int i=0; i<3; i++) + { + PyList_SET_ITEM(resultlist,i,PyFloat_FromDouble((*val)[i])); + } + return resultlist; + } case KX_PYATTRIBUTE_TYPE_STRING: { STR_String *val = reinterpret_cast<STR_String*>(ptr); @@ -326,12 +362,12 @@ int PyObjectPlus::py_set_attrdef(void *self, const PyAttributeDef *attrdef, PyOb if (!PySequence_Check(value)) { PyErr_Format(PyExc_TypeError, "expected a sequence for attribute \"%s\"", attrdef->m_name); - return 1; + return PY_SET_ATTR_FAIL; } if (PySequence_Size(value) != attrdef->m_length) { PyErr_Format(PyExc_TypeError, "incorrect number of elements in sequence for attribute \"%s\"", attrdef->m_name); - return 1; + return PY_SET_ATTR_FAIL; } switch (attrdef->m_type) { @@ -339,7 +375,7 @@ int PyObjectPlus::py_set_attrdef(void *self, const PyAttributeDef *attrdef, PyOb if (attrdef->m_setFunction == NULL) { PyErr_Format(PyExc_AttributeError, "function attribute without function for attribute \"%s\", report to blender.org", attrdef->m_name); - return 1; + return PY_SET_ATTR_FAIL; } return (*attrdef->m_setFunction)(self, attrdef, value); case KX_PYATTRIBUTE_TYPE_BOOL: @@ -358,7 +394,7 @@ int PyObjectPlus::py_set_attrdef(void *self, const PyAttributeDef *attrdef, PyOb default: // should not happen PyErr_Format(PyExc_AttributeError, "Unsupported attribute type for attribute \"%s\", report to blender.org", attrdef->m_name); - return 1; + return PY_SET_ATTR_FAIL; } // let's implement a smart undo method bufferSize *= attrdef->m_length; @@ -495,6 +531,10 @@ int PyObjectPlus::py_set_attrdef(void *self, const PyAttributeDef *attrdef, PyOb { if ((*attrdef->m_checkFunction)(self, attrdef) != 0) { + // if the checing function didnt set an error then set a generic one here so we dont set an error with no exception + if (PyErr_Occurred()==0) + PyErr_Format(PyExc_AttributeError, "type check error for attribute \"%s\", reasion unknown", attrdef->m_name); + // post check returned an error, restore values UNDO_AND_ERROR: if (undoBuffer) @@ -502,12 +542,12 @@ int PyObjectPlus::py_set_attrdef(void *self, const PyAttributeDef *attrdef, PyOb memcpy(sourceBuffer, undoBuffer, bufferSize); free(undoBuffer); } - return 1; + return PY_SET_ATTR_FAIL; } } if (undoBuffer) free(undoBuffer); - return 0; + return PY_SET_ATTR_SUCCESS; } else // simple attribute value { @@ -516,11 +556,11 @@ int PyObjectPlus::py_set_attrdef(void *self, const PyAttributeDef *attrdef, PyOb if (attrdef->m_setFunction == NULL) { PyErr_Format(PyExc_AttributeError, "function attribute without function \"%s\", report to blender.org", attrdef->m_name); - return 1; + return PY_SET_ATTR_FAIL; } return (*attrdef->m_setFunction)(self, attrdef, value); } - if (attrdef->m_checkFunction != NULL) + if (attrdef->m_checkFunction != NULL || attrdef->m_type == KX_PYATTRIBUTE_TYPE_VECTOR) { // post check function is provided, prepare undo buffer sourceBuffer = ptr; @@ -544,9 +584,12 @@ int PyObjectPlus::py_set_attrdef(void *self, const PyAttributeDef *attrdef, PyOb if (sourceBuffer) bufferSize = strlen(reinterpret_cast<char*>(sourceBuffer))+1; break; + case KX_PYATTRIBUTE_TYPE_VECTOR: + bufferSize = sizeof(MT_Vector3); + break; default: PyErr_Format(PyExc_AttributeError, "unknown type for attribute \"%s\", report to blender.org", attrdef->m_name); - return 1; + return PY_SET_ATTR_FAIL; } if (bufferSize) { @@ -664,6 +707,42 @@ int PyObjectPlus::py_set_attrdef(void *self, const PyAttributeDef *attrdef, PyOb *var = (float)val; break; } + case KX_PYATTRIBUTE_TYPE_VECTOR: + { + if (!PySequence_Check(value) || PySequence_Size(value) != 3) + { + PyErr_Format(PyExc_TypeError, "expected a sequence of 3 floats for attribute \"%s\"", attrdef->m_name); + return PY_SET_ATTR_FAIL; + } + MT_Vector3 *var = reinterpret_cast<MT_Vector3*>(ptr); + for (int i=0; i<3; i++) + { + PyObject *item = PySequence_GetItem(value, i); /* new ref */ + // we can decrement the reference immediately, the reference count + // is at least 1 because the item is part of an array + Py_DECREF(item); + double val = PyFloat_AsDouble(item); + if (val == -1.0 && PyErr_Occurred()) + { + PyErr_Format(PyExc_TypeError, "expected a sequence of 3 floats for attribute \"%s\"", attrdef->m_name); + goto RESTORE_AND_ERROR; + } + else if (attrdef->m_clamp) + { + if (val < attrdef->m_fmin) + val = attrdef->m_fmin; + else if (val > attrdef->m_fmax) + val = attrdef->m_fmax; + } + else if (val < attrdef->m_fmin || val > attrdef->m_fmax) + { + PyErr_Format(PyExc_ValueError, "value out of range for attribute \"%s\"", attrdef->m_name); + goto RESTORE_AND_ERROR; + } + (*var)[i] = (MT_Scalar)val; + } + break; + } case KX_PYATTRIBUTE_TYPE_STRING: { STR_String *var = reinterpret_cast<STR_String*>(ptr); @@ -791,6 +870,31 @@ PyObject *PyObjectPlus::PyisA(PyObject *value) // Python wrapper for isA return NULL; } + +void PyObjectPlus::ProcessReplica() +{ + /* Clear the proxy, will be created again if needed with GetProxy() + * otherwise the PyObject will point to the wrong reference */ + m_proxy= NULL; +} + +/* Sometimes we might want to manually invalidate a BGE type even if + * it hasnt been released by the BGE, say for example when an object + * is removed from a scene, accessing it may cause problems. + * + * In this case the current proxy is made invalid, disowned, + * and will raise an error on access. However if python can get access + * to this class again it will make a new proxy and work as expected. + */ +void PyObjectPlus::InvalidateProxy() // check typename of each parent +{ + if(m_proxy) { + BGE_PROXY_REF(m_proxy)=NULL; + Py_DECREF(m_proxy); + m_proxy= NULL; + } +} + /* Utility function called by the macro py_getattro_up() * for getting ob.__dict__() values from our PyObject * this is used by python for doing dir() on an object, so its good @@ -852,5 +956,80 @@ PyObject *PyObjectPlus::NewProxy_Ext(PyObjectPlus *self, PyTypeObject *tp, bool return self->m_proxy; } +/////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////// +/* deprecation warning management */ + +bool PyObjectPlus::m_ignore_deprecation_warnings(false); +void PyObjectPlus::SetDeprecationWarnings(bool ignoreDeprecationWarnings) +{ + m_ignore_deprecation_warnings = ignoreDeprecationWarnings; +} + +void PyObjectPlus::ShowDeprecationWarning_func(const char* old_way,const char* new_way) +{ + { + printf("Method %s is deprecated, please use %s instead.\n", old_way, new_way); + + // import sys; print '\t%s:%d' % (sys._getframe(0).f_code.co_filename, sys._getframe(0).f_lineno) + + PyObject *getframe, *frame; + PyObject *f_lineno, *f_code, *co_filename; + + getframe = PySys_GetObject((char *)"_getframe"); // borrowed + if (getframe) { + frame = PyObject_CallObject(getframe, NULL); + if (frame) { + f_lineno= PyObject_GetAttrString(frame, "f_lineno"); + f_code= PyObject_GetAttrString(frame, "f_code"); + if (f_lineno && f_code) { + co_filename= PyObject_GetAttrString(f_code, "co_filename"); + if (co_filename) { + + printf("\t%s:%d\n", PyString_AsString(co_filename), (int)PyInt_AsLong(f_lineno)); + + Py_DECREF(f_lineno); + Py_DECREF(f_code); + Py_DECREF(co_filename); + Py_DECREF(frame); + return; + } + } + + Py_XDECREF(f_lineno); + Py_XDECREF(f_code); + Py_DECREF(frame); + } + + } + PyErr_Clear(); + printf("\tERROR - Could not access sys._getframe(0).f_lineno or sys._getframe().f_code.co_filename\n"); + } +} + +void PyObjectPlus::ClearDeprecationWarning() +{ + WarnLink *wlink_next; + WarnLink *wlink = GetDeprecationWarningLinkFirst(); + + while(wlink) + { + wlink->warn_done= false; /* no need to NULL the link, its cleared before adding to the list next time round */ + wlink_next= reinterpret_cast<WarnLink *>(wlink->link); + wlink->link= NULL; + wlink= wlink_next; + } + NullDeprecationWarning(); +} + +WarnLink* m_base_wlink_first= NULL; +WarnLink* m_base_wlink_last= NULL; + +WarnLink* PyObjectPlus::GetDeprecationWarningLinkFirst(void) {return m_base_wlink_first;} +WarnLink* PyObjectPlus::GetDeprecationWarningLinkLast(void) {return m_base_wlink_last;} +void PyObjectPlus::SetDeprecationWarningFirst(WarnLink* wlink) {m_base_wlink_first= wlink;} +void PyObjectPlus::SetDeprecationWarningLinkLast(WarnLink* wlink) {m_base_wlink_last= wlink;} +void PyObjectPlus::NullDeprecationWarning() {m_base_wlink_first= m_base_wlink_last= NULL;} + #endif //NO_EXP_PYTHON_EMBEDDING diff --git a/source/gameengine/Expressions/PyObjectPlus.h b/source/gameengine/Expressions/PyObjectPlus.h index 370717a919b..369c00782cc 100644 --- a/source/gameengine/Expressions/PyObjectPlus.h +++ b/source/gameengine/Expressions/PyObjectPlus.h @@ -38,11 +38,30 @@ #include "KX_Python.h" #include "STR_String.h" +#include "MT_Vector3.h" +#include "SG_QList.h" /*------------------------------ * Python defines ------------------------------*/ + + +#if PY_VERSION_HEX > 0x03000000 +#define PyString_FromString PyUnicode_FromString +#define PyString_FromFormat PyUnicode_FromFormat +#define PyString_Check PyUnicode_Check +#define PyString_Size PyUnicode_GetSize + +#define PyInt_FromLong PyLong_FromSsize_t +#define PyInt_AsLong PyLong_AsSsize_t +#define PyString_AsString _PyUnicode_AsString +#define PyInt_Check PyLong_Check +#define PyInt_AS_LONG PyLong_AsLong // TODO - check this one +#endif + + + /* Py_RETURN_NONE Python 2.4 macro. @@ -81,6 +100,36 @@ static inline void Py_Fatal(const char *M) { exit(-1); }; + +/* Use with ShowDeprecationWarning macro */ +typedef struct { + bool warn_done; + void *link; +} WarnLink; + +#define ShowDeprecationWarning(old_way, new_way) \ +{ \ + static WarnLink wlink = {false, NULL}; \ + if ((m_ignore_deprecation_warnings || wlink.warn_done)==0) \ + { \ + ShowDeprecationWarning_func(old_way, new_way); \ + WarnLink *wlink_last= GetDeprecationWarningLinkLast(); \ + ShowDeprecationWarning_func(old_way, new_way); \ + wlink.warn_done = true; \ + wlink.link = NULL; \ + \ + if(wlink_last) { \ + wlink_last->link= (void *)&(wlink); \ + SetDeprecationWarningLinkLast(&(wlink)); \ + } else { \ + SetDeprecationWarningFirst(&(wlink)); \ + SetDeprecationWarningLinkLast(&(wlink)); \ + } \ + } \ +} \ + + + typedef struct { PyObject_HEAD /* required python macro */ class PyObjectPlus *ref; @@ -92,7 +141,7 @@ typedef struct { #define BGE_PROXY_PYOWNS(_self) (((PyObjectPlus_Proxy *)_self)->py_owns) /* Note, sometimes we dont care what BGE type this is as long as its a proxy */ -#define BGE_PROXY_CHECK_TYPE(_self) ((_self)->ob_type->tp_dealloc == py_base_dealloc) +#define BGE_PROXY_CHECK_TYPE(_self) ((_self)->ob_type->tp_dealloc == PyObjectPlus::py_base_dealloc) // This must be the first line of each @@ -114,6 +163,9 @@ typedef struct { // This defines the py_getattro_up macro // which allows attribute and method calls // to be properly passed up the hierarchy. + // + // Note, PyDict_GetItem() WONT set an exception! + // let the py_base_getattro function do this. #define py_getattro_up(Parent) \ \ @@ -125,21 +177,14 @@ typedef struct { } else if (descr->ob_type->tp_descr_get) { \ return PyCFunction_New(((PyMethodDescrObject *)descr)->d_method, this->m_proxy); \ } else { \ - fprintf(stderr, "unknown attribute type"); \ - return descr; \ + return NULL; \ } \ } else { \ - PyErr_Clear(); \ - PyObject *rvalue= Parent::py_getattro(attr); \ - \ - if (strcmp(PyString_AsString(attr), "__dict__")==0) { \ - return py_getattr_dict(rvalue, Type.tp_dict); \ - } \ - \ - return rvalue; \ - } \ - return NULL; + return Parent::py_getattro(attr); \ + } +#define py_getattro_dict_up(Parent) \ + return py_getattr_dict(Parent::py_getattro_dict(), Type.tp_dict); /* * nonzero values are an error for setattr @@ -182,30 +227,35 @@ typedef struct { #define KX_PYMETHOD(class_name, method_name) \ PyObject* Py##method_name(PyObject* args, PyObject* kwds); \ static PyObject* sPy##method_name( PyObject* self, PyObject* args, PyObject* kwds) { \ + if(BGE_PROXY_REF(self)==NULL) { PyErr_SetString(PyExc_SystemError, #class_name "." #method_name "() - " BGE_PROXY_ERROR_MSG); return NULL; } \ return ((class_name*)BGE_PROXY_REF(self))->Py##method_name(args, kwds); \ }; \ #define KX_PYMETHOD_VARARGS(class_name, method_name) \ PyObject* Py##method_name(PyObject* args); \ static PyObject* sPy##method_name( PyObject* self, PyObject* args) { \ + if(BGE_PROXY_REF(self)==NULL) { PyErr_SetString(PyExc_SystemError, #class_name "." #method_name "() - " BGE_PROXY_ERROR_MSG); return NULL; } \ return ((class_name*)BGE_PROXY_REF(self))->Py##method_name(args); \ }; \ #define KX_PYMETHOD_NOARGS(class_name, method_name) \ PyObject* Py##method_name(); \ static PyObject* sPy##method_name( PyObject* self) { \ + if(BGE_PROXY_REF(self)==NULL) { PyErr_SetString(PyExc_SystemError, #class_name "." #method_name "() - " BGE_PROXY_ERROR_MSG); return NULL; } \ return ((class_name*)BGE_PROXY_REF(self))->Py##method_name(); \ }; \ #define KX_PYMETHOD_O(class_name, method_name) \ PyObject* Py##method_name(PyObject* value); \ static PyObject* sPy##method_name( PyObject* self, PyObject* value) { \ + if(BGE_PROXY_REF(self)==NULL) { PyErr_SetString(PyExc_SystemError, #class_name "." #method_name "(value) - " BGE_PROXY_ERROR_MSG); return NULL; } \ return ((class_name*)BGE_PROXY_REF(self))->Py##method_name(value); \ }; \ #define KX_PYMETHOD_DOC(class_name, method_name) \ PyObject* Py##method_name(PyObject* args, PyObject* kwds); \ static PyObject* sPy##method_name( PyObject* self, PyObject* args, PyObject* kwds) { \ + if(BGE_PROXY_REF(self)==NULL) { PyErr_SetString(PyExc_SystemError, #class_name "." #method_name "(...) - " BGE_PROXY_ERROR_MSG); return NULL; } \ return ((class_name*)BGE_PROXY_REF(self))->Py##method_name(args, kwds); \ }; \ static const char method_name##_doc[]; \ @@ -213,6 +263,7 @@ typedef struct { #define KX_PYMETHOD_DOC_VARARGS(class_name, method_name) \ PyObject* Py##method_name(PyObject* args); \ static PyObject* sPy##method_name( PyObject* self, PyObject* args) { \ + if(BGE_PROXY_REF(self)==NULL) { PyErr_SetString(PyExc_SystemError, #class_name "." #method_name "(...) - " BGE_PROXY_ERROR_MSG); return NULL; } \ return ((class_name*)BGE_PROXY_REF(self))->Py##method_name(args); \ }; \ static const char method_name##_doc[]; \ @@ -220,6 +271,7 @@ typedef struct { #define KX_PYMETHOD_DOC_O(class_name, method_name) \ PyObject* Py##method_name(PyObject* value); \ static PyObject* sPy##method_name( PyObject* self, PyObject* value) { \ + if(BGE_PROXY_REF(self)==NULL) { PyErr_SetString(PyExc_SystemError, #class_name "." #method_name "(value) - " BGE_PROXY_ERROR_MSG); return NULL; } \ return ((class_name*)BGE_PROXY_REF(self))->Py##method_name(value); \ }; \ static const char method_name##_doc[]; \ @@ -227,6 +279,7 @@ typedef struct { #define KX_PYMETHOD_DOC_NOARGS(class_name, method_name) \ PyObject* Py##method_name(); \ static PyObject* sPy##method_name( PyObject* self) { \ + if(BGE_PROXY_REF(self)==NULL) { PyErr_SetString(PyExc_SystemError, #class_name "." #method_name "() - " BGE_PROXY_ERROR_MSG); return NULL; } \ return ((class_name*)BGE_PROXY_REF(self))->Py##method_name(); \ }; \ static const char method_name##_doc[]; \ @@ -276,6 +329,7 @@ enum KX_PYATTRIBUTE_TYPE { KX_PYATTRIBUTE_TYPE_STRING, KX_PYATTRIBUTE_TYPE_DUMMY, KX_PYATTRIBUTE_TYPE_FUNCTION, + KX_PYATTRIBUTE_TYPE_VECTOR, }; enum KX_PYATTRIBUTE_ACCESS { @@ -313,97 +367,105 @@ typedef struct KX_PYATTRIBUTE_DEF { int *m_intPtr; float *m_floatPtr; STR_String *m_stringPtr; + MT_Vector3 *m_vectorPtr; } m_typeCheck; } PyAttributeDef; #define KX_PYATTRIBUTE_DUMMY(name) \ - { name, KX_PYATTRIBUTE_TYPE_DUMMY, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, 0, 0, 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_DUMMY, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, 0, 0, 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_BOOL_RW(name,object,field) \ - { name, KX_PYATTRIBUTE_TYPE_BOOL, KX_PYATTRIBUTE_RW, 0, 1, 0.f, 0.f, false, offsetof(object,field), 0, 1, NULL, NULL, NULL, {&((object *)0)->field, NULL, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_BOOL, KX_PYATTRIBUTE_RW, 0, 1, 0.f, 0.f, false, offsetof(object,field), 0, 1, NULL, NULL, NULL, {&((object *)0)->field, NULL, NULL, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_BOOL_RW_CHECK(name,object,field,function) \ - { name, KX_PYATTRIBUTE_TYPE_BOOL, KX_PYATTRIBUTE_RW, 0, 1, 0.f, 0.f, false, offsetof(object,field), 0, 1, &object::function, NULL, NULL, {&((object *)0)->field, NULL, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_BOOL, KX_PYATTRIBUTE_RW, 0, 1, 0.f, 0.f, false, offsetof(object,field), 0, 1, &object::function, NULL, NULL, {&((object *)0)->field, NULL, NULL, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_BOOL_RO(name,object,field) \ - { name, KX_PYATTRIBUTE_TYPE_BOOL, KX_PYATTRIBUTE_RO, 0, 1, 0.f, 0.f, false, offsetof(object,field), 0, 1, NULL, NULL, NULL, {&((object *)0)->field, NULL, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_BOOL, KX_PYATTRIBUTE_RO, 0, 1, 0.f, 0.f, false, offsetof(object,field), 0, 1, NULL, NULL, NULL, {&((object *)0)->field, NULL, NULL, NULL, NULL, NULL} } // enum field cannot be mapped to pointer (because we would need a pointer for each enum) // use field size to verify mapping at runtime only, assuming enum size is equal to int size. #define KX_PYATTRIBUTE_ENUM_RW(name,min,max,clamp,object,field) \ - { name, KX_PYATTRIBUTE_TYPE_ENUM, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_ENUM, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_ENUM_RW_CHECK(name,min,max,clamp,object,field,function) \ - { name, KX_PYATTRIBUTE_TYPE_ENUM, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), sizeof(((object *)0)->field), 1, &object::function, NULL, NULL, {NULL, NULL, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_ENUM, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), sizeof(((object *)0)->field), 1, &object::function, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_ENUM_RO(name,object,field) \ - { name, KX_PYATTRIBUTE_TYPE_ENUM, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, offsetof(object,field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_ENUM, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, offsetof(object,field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_SHORT_RW(name,min,max,clamp,object,field) \ - { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), 0, 1, NULL, NULL, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), 0, 1, NULL, NULL, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_SHORT_RW_CHECK(name,min,max,clamp,object,field,function) \ - { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), 0, 1, &object::function, NULL, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), 0, 1, &object::function, NULL, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_SHORT_RO(name,object,field) \ - { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, offsetof(object,field), 0, 1, NULL, NULL, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, offsetof(object,field), 0, 1, NULL, NULL, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_SHORT_ARRAY_RW(name,min,max,clamp,object,field,length) \ - { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, ((object *)0)->field, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, ((object *)0)->field, NULL, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_SHORT_ARRAY_RW_CHECK(name,min,max,clamp,object,field,length,function) \ - { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), 0, length, &object::function, NULL, NULL, {NULL, ((object *)0)->field, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), 0, length, &object::function, NULL, NULL, {NULL, ((object *)0)->field, NULL, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_SHORT_ARRAY_RO(name,object,field,length) \ - { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, ((object *)0)->field, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, ((object *)0)->field, NULL, NULL, NULL, NULL} } // SHORT_LIST #define KX_PYATTRIBUTE_SHORT_LIST_RW(name,min,max,clamp,object,field,length) \ - { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_SHORT_LIST_RW_CHECK(name,min,max,clamp,object,field,length,function) \ - { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), 0, length, &object::function, NULL, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), 0, length, &object::function, NULL, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_SHORT_LIST_RO(name,object,field,length) \ - { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_INT_RW(name,min,max,clamp,object,field) \ - { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), 0, 1, NULL, NULL, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), 0, 1, NULL, NULL, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_INT_RW_CHECK(name,min,max,clamp,object,field,function) \ - { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), 0, 1, &object::function, NULL, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), 0, 1, &object::function, NULL, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_INT_RO(name,object,field) \ - { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, offsetof(object,field), 0, 1, NULL, NULL, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, offsetof(object,field), 0, 1, NULL, NULL, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_INT_ARRAY_RW(name,min,max,clamp,object,field,length) \ - { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, NULL, ((object *)0)->field, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, NULL, ((object *)0)->field, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_INT_ARRAY_RW_CHECK(name,min,max,clamp,object,field,length,function) \ - { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), 0, length, &object::function, NULL, NULL, {NULL, NULL, ((object *)0)->field, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), 0, length, &object::function, NULL, NULL, {NULL, NULL, ((object *)0)->field, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_INT_ARRAY_RO(name,object,field,length) \ - { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, NULL, ((object *)0)->field, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, NULL, ((object *)0)->field, NULL, NULL, NULL} } // INT_LIST #define KX_PYATTRIBUTE_INT_LIST_RW(name,min,max,clamp,object,field,length) \ - { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_INT_LIST_RW_CHECK(name,min,max,clamp,object,field,length,function) \ - { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), 0, length, &object::function, NULL, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), 0, length, &object::function, NULL, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_INT_LIST_RO(name,object,field,length) \ - { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL, NULL} } // always clamp for float #define KX_PYATTRIBUTE_FLOAT_RW(name,min,max,object,field) \ - { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, 0, 0, min, max, true, offsetof(object,field), 0, 1, NULL, NULL, NULL, {NULL, NULL, NULL, &((object *)0)->field, NULL} } + { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, 0, 0, min, max, true, offsetof(object,field), 0, 1, NULL, NULL, NULL, {NULL, NULL, NULL, &((object *)0)->field, NULL, NULL} } #define KX_PYATTRIBUTE_FLOAT_RW_CHECK(name,min,max,object,field,function) \ - { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, 0, 0, min, max, true, offsetof(object,field), 0, 1, &object::function, NULL, NULL, {NULL, NULL, NULL, &((object *)0)->field, NULL} } + { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, 0, 0, min, max, true, offsetof(object,field), 0, 1, &object::function, NULL, NULL, {NULL, NULL, NULL, &((object *)0)->field, NULL, NULL} } #define KX_PYATTRIBUTE_FLOAT_RO(name,object,field) \ - { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, offsetof(object,field), 0, 1, NULL, NULL, NULL, {NULL, NULL, NULL, &((object *)0)->field, NULL} } + { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, offsetof(object,field), 0, 1, NULL, NULL, NULL, {NULL, NULL, NULL, &((object *)0)->field, NULL, NULL} } #define KX_PYATTRIBUTE_FLOAT_ARRAY_RW(name,min,max,object,field,length) \ - { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, 0, 0, min, max, true, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field, NULL} } + { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, 0, 0, min, max, true, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field, NULL, NULL} } #define KX_PYATTRIBUTE_FLOAT_ARRAY_RW_CHECK(name,min,max,object,field,length,function) \ - { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, 0, 0, min, max, true, offsetof(object,field), 0, length, &object::function, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field, NULL} } + { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, 0, 0, min, max, true, offsetof(object,field), 0, length, &object::function, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field, NULL, NULL} } #define KX_PYATTRIBUTE_FLOAT_ARRAY_RO(name,object,field,length) \ - { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field, NULL} } + { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field, NULL, NULL} } #define KX_PYATTRIBUTE_STRING_RW(name,min,max,clamp,object,field) \ - { name, KX_PYATTRIBUTE_TYPE_STRING, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), 0, 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, &((object *)0)->field} } + { name, KX_PYATTRIBUTE_TYPE_STRING, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), 0, 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, &((object *)0)->field, NULL} } #define KX_PYATTRIBUTE_STRING_RW_CHECK(name,min,max,clamp,object,field,function) \ - { name, KX_PYATTRIBUTE_TYPE_STRING, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), 0, 1, &object::function, NULL, NULL, {NULL, NULL, NULL, NULL, &((object *)0)->field} } + { name, KX_PYATTRIBUTE_TYPE_STRING, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), 0, 1, &object::function, NULL, NULL, {NULL, NULL, NULL, NULL, &((object *)0)->field, NULL} } #define KX_PYATTRIBUTE_STRING_RO(name,object,field) \ - { name, KX_PYATTRIBUTE_TYPE_STRING, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, offsetof(object,field), 0, 1 , NULL, NULL, NULL, {NULL, NULL, NULL, NULL, &((object *)0)->field} } + { name, KX_PYATTRIBUTE_TYPE_STRING, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, offsetof(object,field), 0, 1 , NULL, NULL, NULL, {NULL, NULL, NULL, NULL, &((object *)0)->field, NULL} } + +#define KX_PYATTRIBUTE_VECTOR_RW(name,min,max,object,field) \ + { name, KX_PYATTRIBUTE_TYPE_VECTOR, KX_PYATTRIBUTE_RW, 0, 0, min, max, true, offsetof(object,field), 0, 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, &((object *)0)->field} } +#define KX_PYATTRIBUTE_VECTOR_RW_CHECK(name,min,max,clamp,object,field,function) \ + { name, KX_PYATTRIBUTE_TYPE_VECTOR, KX_PYATTRIBUTE_RW, 0, 0, min, max, true, offsetof(object,field), 0, 1, &object::function, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, &((object *)0)->field} } +#define KX_PYATTRIBUTE_VECTOR_RO(name,object,field) \ + { name, KX_PYATTRIBUTE_TYPE_VECTOR, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, offsetof(object,field), 0, 1 , NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, &((object *)0)->field} } #define KX_PYATTRIBUTE_RW_FUNCTION(name,object,getfunction,setfunction) \ - { name, KX_PYATTRIBUTE_TYPE_FUNCTION, KX_PYATTRIBUTE_RW, 0, 0, 0.f, 0.f, false, 0, 0, 1, NULL, &object::setfunction, &object::getfunction, {NULL, NULL, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_FUNCTION, KX_PYATTRIBUTE_RW, 0, 0, 0.f, 0.f, false, 0, 0, 1, NULL, &object::setfunction, &object::getfunction, {NULL, NULL, NULL, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_RO_FUNCTION(name,object,getfunction) \ - { name, KX_PYATTRIBUTE_TYPE_FUNCTION, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, 0, 0, 1, NULL, NULL, &object::getfunction, {NULL, NULL, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_FUNCTION, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, 0, 0, 1, NULL, NULL, &object::getfunction, {NULL, NULL, NULL, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_ARRAY_RW_FUNCTION(name,object,length,getfunction,setfunction) \ - { name, KX_PYATTRIBUTE_TYPE_FUNCTION, KX_PYATTRIBUTE_RW, 0, 0, 0.f, 0,f, false, 0, 0, length, NULL, &object::setfunction, &object::getfunction, {NULL, NULL, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_FUNCTION, KX_PYATTRIBUTE_RW, 0, 0, 0.f, 0,f, false, 0, 0, length, NULL, &object::setfunction, &object::getfunction, {NULL, NULL, NULL, NULL, NULL, NULL} } #define KX_PYATTRIBUTE_ARRAY_RO_FUNCTION(name,object,length,getfunction) \ - { name, KX_PYATTRIBUTE_TYPE_FUNCTION, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0,f, false, 0, 0, length, NULL, NULL, &object::getfunction, {NULL, NULL, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_FUNCTION, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0,f, false, 0, 0, length, NULL, NULL, &object::getfunction, {NULL, NULL, NULL, NULL, NULL, NULL} } /*------------------------------ @@ -411,7 +473,18 @@ typedef struct KX_PYATTRIBUTE_DEF { ------------------------------*/ typedef PyTypeObject * PyParentObject; // Define the PyParent Object -class PyObjectPlus +// By making SG_QList the ultimate parent for PyObjectPlus objects, it +// allows to put them in 2 different dynamic lists at the same time +// The use of these links is interesting because they free of memory allocation +// but it's very important not to mess up with them. If you decide that +// the SG_QList or SG_DList component is used for something for a certain class, +// they cannot can be used for anything else at a parent level! +// What these lists are and what they are used for must be carefully documented +// at the level where they are used. +// DON'T MAKE ANY USE OF THESE LIST AT THIS LEVEL, they are already used +// at SCA_IActuator, SCA_ISensor, SCA_IController level which rules out the +// possibility to use them at SCA_ILogicBrick, CValue and PyObjectPlus level. +class PyObjectPlus : public SG_QList { // The PyObjectPlus abstract class Py_Header; // Always start with Py_Header @@ -434,6 +507,7 @@ public: /* These are all virtual python methods that are defined in each class * Our own fake subclassing calls these on each class, then calls the parent */ virtual PyObject* py_getattro(PyObject *attr); + virtual PyObject* py_getattro_dict(); virtual int py_delattro(PyObject *attr); virtual int py_setattro(PyObject *attr, PyObject *value); virtual PyObject* py_repr(void); @@ -449,12 +523,36 @@ public: KX_PYMETHOD_O(PyObjectPlus,isA); /* Kindof dumb, always returns True, the false case is checked for, before this function gets accessed */ - static PyObject* pyattr_get_is_valid(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_invalid(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); static PyObject *GetProxy_Ext(PyObjectPlus *self, PyTypeObject *tp); static PyObject *NewProxy_Ext(PyObjectPlus *self, PyTypeObject *tp, bool py_owns); + + void InvalidateProxy(); + + /** + * Makes sure any internal data owned by this class is deep copied. + */ + virtual void ProcessReplica(); + + + static bool m_ignore_deprecation_warnings; + + static WarnLink* GetDeprecationWarningLinkFirst(void); + static WarnLink* GetDeprecationWarningLinkLast(void); + static void SetDeprecationWarningFirst(WarnLink* wlink); + static void SetDeprecationWarningLinkLast(WarnLink* wlink); + static void NullDeprecationWarning(); + + /** enable/disable display of deprecation warnings */ + static void SetDeprecationWarnings(bool ignoreDeprecationWarnings); + /** Shows a deprecation warning */ + static void ShowDeprecationWarning_func(const char* method,const char* prop); + static void ClearDeprecationWarning(); + }; + PyObject *py_getattr_dict(PyObject *pydict, PyObject *tp_dict); #endif // _adr_py_lib_h_ diff --git a/source/gameengine/Expressions/SConscript b/source/gameengine/Expressions/SConscript index 25adcf3e895..b5c69eafe6b 100644 --- a/source/gameengine/Expressions/SConscript +++ b/source/gameengine/Expressions/SConscript @@ -3,7 +3,7 @@ Import ('env') sources = env.Glob('*.cpp') -incs ='. #source/kernel/gen_system #intern/string #intern/moto/include' +incs ='. #source/kernel/gen_system #intern/string #intern/moto/include #source/gameengine/SceneGraph' incs += ' ' + env['BF_PYTHON_INC'] cxxflags = [] diff --git a/source/gameengine/Expressions/StringValue.cpp b/source/gameengine/Expressions/StringValue.cpp index 2b3c62c411e..a7033fcf11c 100644 --- a/source/gameengine/Expressions/StringValue.cpp +++ b/source/gameengine/Expressions/StringValue.cpp @@ -34,7 +34,7 @@ effect: constructs a new CStringValue m_strString = "[Illegal String constructor call]"; } -CStringValue::CStringValue(STR_String txt,STR_String name,AllocationTYPE alloctype) +CStringValue::CStringValue(const char *txt,const char *name,AllocationTYPE alloctype) /* pre: effect: constructs a new CStringValue containing text txt @@ -133,7 +133,7 @@ bool CStringValue::IsEqual(const STR_String & other) CValue* CStringValue::GetReplica() { CStringValue* replica = new CStringValue(*this); - CValue::AddDataToReplica(replica); + replica->ProcessReplica(); return replica; }; diff --git a/source/gameengine/Expressions/StringValue.h b/source/gameengine/Expressions/StringValue.h index 16575ed7ffa..52f8a580f4d 100644 --- a/source/gameengine/Expressions/StringValue.h +++ b/source/gameengine/Expressions/StringValue.h @@ -26,7 +26,7 @@ class CStringValue : public CPropValue public: /// Construction / destruction CStringValue(); - CStringValue (STR_String txt, STR_String name , AllocationTYPE alloctype = CValue::HEAPVALUE); + CStringValue (const char *txt, const char *name , AllocationTYPE alloctype = CValue::HEAPVALUE); virtual ~CStringValue() { }; diff --git a/source/gameengine/Expressions/Value.cpp b/source/gameengine/Expressions/Value.cpp index 7cb97909119..e6ef9733da8 100644 --- a/source/gameengine/Expressions/Value.cpp +++ b/source/gameengine/Expressions/Value.cpp @@ -32,13 +32,17 @@ ////////////////////////////////////////////////////////////////////// double CValue::m_sZeroVec[3] = {0.0,0.0,0.0}; -bool CValue::m_ignore_deprecation_warnings(false); #ifndef NO_EXP_PYTHON_EMBEDDING PyTypeObject CValue::Type = { - PyObject_HEAD_INIT(NULL) - 0, +#if (PY_VERSION_HEX >= 0x02060000) + PyVarObject_HEAD_INIT(NULL, 0) +#else + /* python 2.5 and below */ + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ +#endif "CValue", sizeof(PyObjectPlus_Proxy), 0, @@ -62,13 +66,14 @@ PyParentObject CValue::Parents[] = { }; PyMethodDef CValue::Methods[] = { -// { "printHello", (PyCFunction) CValue::sPyPrintHello, METH_VARARGS}, { "getName", (PyCFunction) CValue::sPyGetName, METH_NOARGS}, {NULL,NULL} //Sentinel }; PyObject* CValue::PyGetName() { + ShowDeprecationWarning("getName()", "the name property"); + return PyString_FromString(this->GetName()); } @@ -287,13 +292,15 @@ CValue* CValue::GetProperty(const char *inName) // // Get text description of property with name <inName>, returns an empty string if there is no property named <inName> // -STR_String CValue::GetPropertyText(const STR_String & inName,const STR_String& deftext) +const STR_String& CValue::GetPropertyText(const STR_String & inName) { + const static STR_String sEmpty(""); + CValue *property = GetProperty(inName); if (property) return property->GetText(); else - return deftext;//String::sEmpty; + return sEmpty; } float CValue::GetPropertyNumber(const STR_String& inName,float defnumber) @@ -439,27 +446,6 @@ int CValue::GetPropertyCount() } - - - -void CValue::CloneProperties(CValue *replica) -{ - - if (m_pNamedPropertyArray) - { - replica->m_pNamedPropertyArray=NULL; - std::map<STR_String,CValue*>::iterator it; - for (it= m_pNamedPropertyArray->begin(); (it != m_pNamedPropertyArray->end()); it++) - { - CValue *val = (*it).second->GetReplica(); - replica->SetProperty((*it).first,val); - val->Release(); - } - } - - -} - double* CValue::GetVector3(bool bGetTransformedVec) { assertd(false); // don;t get vector from me @@ -470,50 +456,12 @@ double* CValue::GetVector3(bool bGetTransformedVec) /*--------------------------------------------------------------------------------------------------------------------- Reference Counting ---------------------------------------------------------------------------------------------------------------------*/ -// -// Add a reference to this value -// -CValue *CValue::AddRef() -{ - // Increase global reference count, used to see at the end of the program - // if all CValue-derived classes have been dereferenced to 0 - //debug(gRefCountValue++); -#ifdef _DEBUG - //gRefCountValue++; -#endif - m_refcount++; - return this; -} // // Release a reference to this value (when reference count reaches 0, the value is removed from the heap) // -int CValue::Release() -{ - // Decrease global reference count, used to see at the end of the program - // if all CValue-derived classes have been dereferenced to 0 - //debug(gRefCountValue--); -#ifdef _DEBUG - //gRefCountValue--; -#endif - // Decrease local reference count, if it reaches 0 the object should be freed - if (--m_refcount > 0) - { - // Reference count normal, return new reference count - return m_refcount; - } - else - { - // Reference count reached 0, delete ourselves and return 0 -// MT_assert(m_refcount==0, "Reference count reached sub-zero, object released too much"); - - delete this; - return 0; - } - -} @@ -534,23 +482,32 @@ void CValue::DisableRefCount() -void CValue::AddDataToReplica(CValue *replica) +void CValue::ProcessReplica() /* was AddDataToReplica in 2.48 */ { - replica->m_refcount = 1; - + m_refcount = 1; + #ifdef _DEBUG //gRefCountValue++; #endif - replica->m_ValFlags.RefCountDisabled = false; + PyObjectPlus::ProcessReplica(); - replica->ReplicaSetName(GetName()); + m_ValFlags.RefCountDisabled = false; - //copy all props - CloneProperties(replica); + /* copy all props */ + if (m_pNamedPropertyArray) + { + std::map<STR_String,CValue*> *pOldArray = m_pNamedPropertyArray; + m_pNamedPropertyArray=NULL; + std::map<STR_String,CValue*>::iterator it; + for (it= pOldArray->begin(); (it != pOldArray->end()); it++) + { + CValue *val = (*it).second->GetReplica(); + SetProperty((*it).first,val); + val->Release(); + } + } } - - CValue* CValue::FindIdentifier(const STR_String& identifiername) { @@ -592,18 +549,22 @@ static PyMethodDef CValueMethods[] = }; PyAttributeDef CValue::Attributes[] = { + KX_PYATTRIBUTE_RO_FUNCTION("name", CValue, pyattr_get_name), { NULL } //Sentinel }; PyObject* CValue::py_getattro(PyObject *attr) -{ +{ char *attr_str= PyString_AsString(attr); CValue* resultattr = GetProperty(attr_str); if (resultattr) { + /* only show the wanting here because python inspects for __class__ and KX_MeshProxy uses CValues name attr */ + ShowDeprecationWarning("val = ob.attr", "val = ob['attr']"); + PyObject* pyconvert = resultattr->ConvertValueToPython(); - + if (pyconvert) return pyconvert; else @@ -612,7 +573,16 @@ PyObject* CValue::py_getattro(PyObject *attr) py_getattro_up(PyObjectPlus); } -CValue* CValue::ConvertPythonToValue(PyObject* pyobj) +PyObject* CValue::py_getattro_dict() { + py_getattro_dict_up(PyObjectPlus); +} + +PyObject * CValue::pyattr_get_name(void * self_v, const KX_PYATTRIBUTE_DEF * attrdef) { + CValue * self = static_cast<CValue *> (self_v); + return PyString_FromString(self->GetName()); +} + +CValue* CValue::ConvertPythonToValue(PyObject* pyobj, const char *error_prefix) { CValue* vallie = NULL; @@ -628,7 +598,7 @@ CValue* CValue::ConvertPythonToValue(PyObject* pyobj) for (i=0;i<numitems;i++) { PyObject* listitem = PyList_GetItem(pyobj,i); /* borrowed ref */ - CValue* listitemval = ConvertPythonToValue(listitem); + CValue* listitemval = ConvertPythonToValue(listitem, error_prefix); if (listitemval) { listval->Add(listitemval); @@ -665,13 +635,22 @@ CValue* CValue::ConvertPythonToValue(PyObject* pyobj) { vallie = new CStringValue(PyString_AsString(pyobj),""); } else - if (pyobj->ob_type==&CValue::Type || pyobj->ob_type==&CListValue::Type) + if (BGE_PROXY_CHECK_TYPE(pyobj)) /* Note, dont let these get assigned to GameObject props, must check elsewhere */ { - vallie = ((CValue*) pyobj)->AddRef(); + if (BGE_PROXY_REF(pyobj) && (BGE_PROXY_REF(pyobj))->isA(&CValue::Type)) + { + vallie = (static_cast<CValue *>(BGE_PROXY_REF(pyobj)))->AddRef(); + } else { + + if(BGE_PROXY_REF(pyobj)) /* this is not a CValue */ + PyErr_Format(PyExc_TypeError, "%sgame engine python type cannot be used as a property", error_prefix); + else /* PyObjectPlus_Proxy has been removed, cant use */ + PyErr_Format(PyExc_SystemError, "%s"BGE_PROXY_ERROR_MSG, error_prefix); + } } else { /* return an error value from the caller */ - PyErr_SetString(PyExc_TypeError, "This python type could not be converted to a to a game engine property"); + PyErr_Format(PyExc_TypeError, "%scould convert python value to a game engine property", error_prefix); } return vallie; @@ -679,21 +658,26 @@ CValue* CValue::ConvertPythonToValue(PyObject* pyobj) int CValue::py_delattro(PyObject *attr) { + ShowDeprecationWarning("del ob.attr", "del ob['attr']"); + char *attr_str= PyString_AsString(attr); - if (RemoveProperty(STR_String(attr_str))) + if (RemoveProperty(attr_str)) return 0; PyErr_Format(PyExc_AttributeError, "attribute \"%s\" dosnt exist", attr_str); - return 1; + return PY_SET_ATTR_MISSING; } int CValue::py_setattro(PyObject *attr, PyObject* pyobj) { - char *attr_str= PyString_AsString(attr); - CValue* oldprop = GetProperty(attr_str); + ShowDeprecationWarning("ob.attr = val", "ob['attr'] = val"); - CValue* vallie = ConvertPythonToValue(pyobj); - if (vallie) + char *attr_str= PyString_AsString(attr); + CValue* oldprop = GetProperty(attr_str); + CValue* vallie; + + /* Dissallow python to assign GameObjects, Scenes etc as values */ + if ((BGE_PROXY_CHECK_TYPE(pyobj)==0) && (vallie = ConvertPythonToValue(pyobj, "cvalue.attr = value: "))) { if (oldprop) oldprop->SetValue(vallie); @@ -750,10 +734,40 @@ PyObject* CValue::PyMake(PyObject* ignored,PyObject* args) } */ +#if (PY_VERSION_HEX >= 0x03000000) +static struct PyModuleDef CValue_module_def = { + {}, /* m_base */ + "CValue", /* m_name */ + 0, /* m_doc */ + 0, /* m_size */ + CValueMethods, /* m_methods */ + 0, /* m_reload */ + 0, /* m_traverse */ + 0, /* m_clear */ + 0, /* m_free */ +}; +#endif + extern "C" { void initCValue(void) { - Py_InitModule("CValue",CValueMethods); + PyObject *m; + /* Use existing module where possible + * be careful not to init any runtime vars after this */ + m = PyImport_ImportModule( "CValue" ); + if(m) { + Py_DECREF(m); + //return m; + } + else { + PyErr_Clear(); + +#if (PY_VERSION_HEX >= 0x03000000) + PyModule_Create(&CValue_module_def); +#else + Py_InitModule("CValue",CValueMethods); +#endif + } } } @@ -779,52 +793,3 @@ void CValue::SetValue(CValue* newval) // no one should get here assertd(newval->GetNumber() == 10121969); } -/////////////////////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////////////////// -/* deprecation warning management */ -void CValue::SetDeprecationWarnings(bool ignoreDeprecationWarnings) -{ - m_ignore_deprecation_warnings = ignoreDeprecationWarnings; -} - -void CValue::ShowDeprecationWarning(const char* old_way,const char* new_way) -{ - if (!m_ignore_deprecation_warnings) { - printf("Method %s is deprecated, please use %s instead.\n", old_way, new_way); - - // import sys; print '\t%s:%d' % (sys._getframe(0).f_code.co_filename, sys._getframe(0).f_lineno) - - PyObject *getframe, *frame; - PyObject *f_lineno, *f_code, *co_filename; - - getframe = PySys_GetObject((char *)"_getframe"); // borrowed - if (getframe) { - frame = PyObject_CallObject(getframe, NULL); - if (frame) { - f_lineno= PyObject_GetAttrString(frame, "f_lineno"); - f_code= PyObject_GetAttrString(frame, "f_code"); - if (f_lineno && f_code) { - co_filename= PyObject_GetAttrString(f_code, "co_filename"); - if (co_filename) { - - printf("\t%s:%d\n", PyString_AsString(co_filename), (int)PyInt_AsLong(f_lineno)); - - Py_DECREF(f_lineno); - Py_DECREF(f_code); - Py_DECREF(co_filename); - Py_DECREF(frame); - return; - } - } - - Py_XDECREF(f_lineno); - Py_XDECREF(f_code); - Py_DECREF(frame); - } - - } - PyErr_Clear(); - printf("\tERROR - Could not access sys._getframe(0).f_lineno or sys._getframe().f_code.co_filename\n"); - } -} - diff --git a/source/gameengine/Expressions/Value.h b/source/gameengine/Expressions/Value.h index a687e1a493c..29ef19b46c9 100644 --- a/source/gameengine/Expressions/Value.h +++ b/source/gameengine/Expressions/Value.h @@ -225,16 +225,19 @@ public: virtual PyObject* py_getattro(PyObject *attr); + virtual PyObject* py_getattro_dict(); virtual PyObject* ConvertValueToPython() { return NULL; } - virtual CValue* ConvertPythonToValue(PyObject* pyobj); + virtual CValue* ConvertPythonToValue(PyObject* pyobj, const char *error_prefix); virtual int py_delattro(PyObject *attr); virtual int py_setattro(PyObject *attr, PyObject* value); + static PyObject * pyattr_get_name(void * self, const KX_PYATTRIBUTE_DEF * attrdef); + virtual PyObject* ConvertKeysToPython( void ); KX_PYMETHOD_NOARGS(CValue,GetName); @@ -258,17 +261,56 @@ public: }; /// Reference Counting - int GetRefCount() { return m_refcount; } - virtual CValue* AddRef(); // Add a reference to this value - virtual int Release(); // Release a reference to this value (when reference count reaches 0, the value is removed from the heap) - + int GetRefCount() + { + return m_refcount; + } + + // Add a reference to this value + CValue* AddRef() + { + // Increase global reference count, used to see at the end of the program + // if all CValue-derived classes have been dereferenced to 0 + //debug(gRefCountValue++); + #ifdef _DEBUG + //gRefCountValue++; + #endif + m_refcount++; + return this; + } + + // Release a reference to this value (when reference count reaches 0, the value is removed from the heap) + int Release() + { + // Decrease global reference count, used to see at the end of the program + // if all CValue-derived classes have been dereferenced to 0 + //debug(gRefCountValue--); + #ifdef _DEBUG + //gRefCountValue--; + #endif + // Decrease local reference count, if it reaches 0 the object should be freed + if (--m_refcount > 0) + { + // Reference count normal, return new reference count + return m_refcount; + } + else + { + // Reference count reached 0, delete ourselves and return 0 + // MT_assert(m_refcount==0, "Reference count reached sub-zero, object released too much"); + + delete this; + return 0; + } + } + /// Property Management virtual void SetProperty(const STR_String& name,CValue* ioProperty); // Set property <ioProperty>, overwrites and releases a previous property with the same name if needed virtual void SetProperty(const char* name,CValue* ioProperty); virtual CValue* GetProperty(const char* inName); // Get pointer to a property with name <inName>, returns NULL if there is no property named <inName> virtual CValue* GetProperty(const STR_String & inName); - STR_String GetPropertyText(const STR_String & inName,const STR_String& deftext=""); // Get text description of property with name <inName>, returns an empty string if there is no property named <inName> + const STR_String& GetPropertyText(const STR_String & inName); // Get text description of property with name <inName>, returns an empty string if there is no property named <inName> float GetPropertyNumber(const STR_String& inName,float defnumber); virtual bool RemoveProperty(const char *inName); // Remove the property named <inName>, returns true if the property was succesfully removed, false if property was not found or could not be removed virtual vector<STR_String> GetPropertyNames(); @@ -280,7 +322,6 @@ public: virtual CValue* GetProperty(int inIndex); // Get property number <inIndex> virtual int GetPropertyCount(); // Get the amount of properties assiocated with this value - virtual void CloneProperties(CValue* replica); virtual CValue* FindIdentifier(const STR_String& identifiername); /** Set the wireframe color of this value depending on the CSG * operator type <op> @@ -292,21 +333,17 @@ public: double* ZeroVector() { return m_sZeroVec; }; virtual double* GetVector3(bool bGetTransformedVec = false); - virtual STR_String GetName() = 0; // Retrieve the name of the value - virtual void SetName(STR_String name) = 0; // Set the name of the value - virtual void ReplicaSetName(STR_String name) = 0; + virtual STR_String& GetName() = 0; // Retrieve the name of the value + virtual void SetName(const char *name) = 0; // Set the name of the value /** Sets the value to this cvalue. * @attention this particular function should never be called. Why not abstract? */ virtual void SetValue(CValue* newval); virtual CValue* GetReplica() =0; + virtual void ProcessReplica(); //virtual CValue* Copy() = 0; STR_String op2str(VALUE_OPERATOR op); - /** enable/disable display of deprecation warnings */ - static void SetDeprecationWarnings(bool ignoreDeprecationWarnings); - /** Shows a deprecation warning */ - static void ShowDeprecationWarning(const char* method,const char* prop); // setting / getting flags inline void SetSelected(bool bSelected) { m_ValFlags.Selected = bSelected; } @@ -327,10 +364,10 @@ public: virtual void SetCustomFlag2(bool bCustomFlag) { m_ValFlags.CustomFlag2 = bCustomFlag;}; virtual bool IsCustomFlag2() { return m_ValFlags.CustomFlag2;}; - + protected: virtual void DisableRefCount(); // Disable reference counting for this value - virtual void AddDataToReplica(CValue* replica); + //virtual void AddDataToReplica(CValue* replica); virtual ~CValue(); private: // Member variables @@ -338,7 +375,6 @@ private: ValueFlags m_ValFlags; // Frequently used flags in a bitfield (low memoryusage) int m_refcount; // Reference Counter static double m_sZeroVec[3]; - static bool m_ignore_deprecation_warnings; }; @@ -386,49 +422,28 @@ public: #else CPropValue() : #endif //NO_EXP_PYTHON_EMBEDDING - m_pstrNewName(NULL) + m_strNewName() { } virtual ~CPropValue() { - if (m_pstrNewName) - { - delete m_pstrNewName; - m_pstrNewName = NULL; - } } - virtual void SetName(STR_String name) { - if (m_pstrNewName) - { - delete m_pstrNewName; - m_pstrNewName = NULL; - } - if (name.Length()) - m_pstrNewName = new STR_String(name); - } - virtual void ReplicaSetName(STR_String name) { - m_pstrNewName=NULL; - if (name.Length()) - m_pstrNewName = new STR_String(name); + virtual void SetName(const char *name) { + m_strNewName = name; } - virtual STR_String GetName() { + virtual STR_String& GetName() { //STR_String namefromprop = GetPropertyText("Name"); //if (namefromprop.Length() > 0) // return namefromprop; - - if (m_pstrNewName) - { - return *m_pstrNewName; - } - return STR_String(""); + return m_strNewName; }; // name of Value protected: - STR_String* m_pstrNewName; // Identification + STR_String m_strNewName; // Identification }; #endif // !defined _VALUEBASECLASS_H diff --git a/source/gameengine/Expressions/VectorValue.cpp b/source/gameengine/Expressions/VectorValue.cpp index 497a50b90e7..c58c78e6ebe 100644 --- a/source/gameengine/Expressions/VectorValue.cpp +++ b/source/gameengine/Expressions/VectorValue.cpp @@ -48,7 +48,7 @@ CVectorValue::CVectorValue(float x,float y,float z, AllocationTYPE alloctype) m_vec[KX_Z] = m_transformedvec[KX_Z] = z; } -CVectorValue::CVectorValue(double vec[],STR_String name,AllocationTYPE alloctype) { +CVectorValue::CVectorValue(double vec[],const char *name,AllocationTYPE alloctype) { SetCustomFlag1(false);//FancyOutput=false; @@ -204,7 +204,7 @@ const STR_String & CVectorValue::GetText() CValue* CVectorValue::GetReplica() { CVectorValue* replica = new CVectorValue(*this); - CValue::AddDataToReplica(replica); + replica->ProcessReplica(); return replica; }; diff --git a/source/gameengine/Expressions/VectorValue.h b/source/gameengine/Expressions/VectorValue.h index 99bf0abb11b..19c7dd30076 100644 --- a/source/gameengine/Expressions/VectorValue.h +++ b/source/gameengine/Expressions/VectorValue.h @@ -41,7 +41,7 @@ public: CValue* CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue *val); - CVectorValue(double vec[],STR_String name,AllocationTYPE alloctype=CValue::HEAPVALUE); + CVectorValue(double vec[],const char *name,AllocationTYPE alloctype=CValue::HEAPVALUE); CVectorValue() {}; CVectorValue(double vec[],AllocationTYPE alloctype=CValue::HEAPVALUE); |