From cc569504d0468ec19a1018ea804aa418c134cb0f Mon Sep 17 00:00:00 2001 From: Benoit Bolsee Date: Fri, 2 Jan 2009 17:43:56 +0000 Subject: BGE API Cleanup: update the python attribute definition framework. * Value clamping to min/max is now supported as an option for integer, float and string attribute (for string clamping=trim to max length) * Post check function now take PyAttributeDef parameter so that more generic function can be written. * Definition of SCA_ILogicBrick::CheckProperty() function to check that a string attribute contains a valid property name of the parent game object. * Definition of enum attribute vi KX_PYATTRIBUTE_ENUM... macros. Enum are handled just like integer but to be totally paranoid, the sizeof() of the enum member is check at run time to match integer size. * More bricks updated to use the framework. --- source/gameengine/Expressions/PyObjectPlus.cpp | 142 +++++++++++++++++---- source/gameengine/Expressions/PyObjectPlus.h | 92 +++++++------ source/gameengine/GameLogic/SCA_ActuatorSensor.cpp | 39 +++--- source/gameengine/GameLogic/SCA_ActuatorSensor.h | 1 + source/gameengine/GameLogic/SCA_DelaySensor.cpp | 45 ++----- source/gameengine/GameLogic/SCA_ILogicBrick.cpp | 18 ++- source/gameengine/GameLogic/SCA_ILogicBrick.h | 3 + source/gameengine/GameLogic/SCA_ISensor.cpp | 73 +++-------- source/gameengine/GameLogic/SCA_JoystickSensor.cpp | 10 +- source/gameengine/GameLogic/SCA_JoystickSensor.h | 22 ++-- source/gameengine/GameLogic/SCA_KeyboardSensor.cpp | 10 +- source/gameengine/GameLogic/SCA_MouseSensor.cpp | 6 +- source/gameengine/GameLogic/SCA_MouseSensor.h | 2 +- .../gameengine/GameLogic/SCA_PropertyActuator.cpp | 37 ++---- source/gameengine/GameLogic/SCA_PropertySensor.cpp | 65 +++------- source/gameengine/GameLogic/SCA_PropertySensor.h | 9 +- source/gameengine/GameLogic/SCA_RandomActuator.cpp | 61 +++------ source/gameengine/GameLogic/SCA_RandomActuator.h | 1 - 18 files changed, 325 insertions(+), 311 deletions(-) diff --git a/source/gameengine/Expressions/PyObjectPlus.cpp b/source/gameengine/Expressions/PyObjectPlus.cpp index c31587628b0..8fd99c8d267 100644 --- a/source/gameengine/Expressions/PyObjectPlus.cpp +++ b/source/gameengine/Expressions/PyObjectPlus.cpp @@ -164,6 +164,14 @@ PyObject *PyObjectPlus::_getattr_self(const PyAttributeDef attrlist[], void *sel PyList_SetItem(resultlist,i,PyInt_FromLong(*val)); break; } + case KX_PYATTRIBUTE_TYPE_ENUM: + // enum are like int, just make sure the field size is the same + if (sizeof(int) != attrdef->m_size) + { + Py_DECREF(resultlist); + return NULL; + } + // walkthrough case KX_PYATTRIBUTE_TYPE_INT: { int *val = reinterpret_cast(ptr); @@ -180,6 +188,7 @@ PyObject *PyObjectPlus::_getattr_self(const PyAttributeDef attrlist[], void *sel } default: // no support for array of complex data + Py_DECREF(resultlist); return NULL; } } @@ -198,6 +207,13 @@ PyObject *PyObjectPlus::_getattr_self(const PyAttributeDef attrlist[], void *sel short int *val = reinterpret_cast(ptr); return PyInt_FromLong(*val); } + case KX_PYATTRIBUTE_TYPE_ENUM: + // enum are like int, just make sure the field size is the same + if (sizeof(int) != attrdef->m_size) + { + return NULL; + } + // walkthrough case KX_PYATTRIBUTE_TYPE_INT: { int *val = reinterpret_cast(ptr); @@ -260,6 +276,7 @@ int PyObjectPlus::_setattr_self(const PyAttributeDef attrlist[], void *self, con case KX_PYATTRIBUTE_TYPE_SHORT: bufferSize = sizeof(short int); break; + case KX_PYATTRIBUTE_TYPE_ENUM: case KX_PYATTRIBUTE_TYPE_INT: bufferSize = sizeof(int); break; @@ -313,7 +330,14 @@ int PyObjectPlus::_setattr_self(const PyAttributeDef attrlist[], void *self, con if (PyInt_Check(item)) { long val = PyInt_AsLong(item); - if (val < attrdef->m_imin || val > attrdef->m_imax) + if (attrdef->m_clamp) + { + if (val < attrdef->m_imin) + val = attrdef->m_imin; + else if (val > attrdef->m_imax) + val = attrdef->m_imax; + } + else if (val < attrdef->m_imin || val > attrdef->m_imax) { PyErr_SetString(PyExc_ValueError, "item value out of range"); goto UNDO_AND_ERROR; @@ -327,6 +351,14 @@ int PyObjectPlus::_setattr_self(const PyAttributeDef attrlist[], void *self, con } break; } + case KX_PYATTRIBUTE_TYPE_ENUM: + // enum are equivalent to int, just make sure that the field size matches: + if (sizeof(int) != attrdef->m_size) + { + PyErr_SetString(PyExc_AttributeError, "attribute size check error, report to blender.org"); + goto UNDO_AND_ERROR; + } + // walkthrough case KX_PYATTRIBUTE_TYPE_INT: { int *var = reinterpret_cast(ptr); @@ -334,7 +366,14 @@ int PyObjectPlus::_setattr_self(const PyAttributeDef attrlist[], void *self, con if (PyInt_Check(item)) { long val = PyInt_AsLong(item); - if (val < attrdef->m_imin || val > attrdef->m_imax) + if (attrdef->m_clamp) + { + if (val < attrdef->m_imin) + val = attrdef->m_imin; + else if (val > attrdef->m_imax) + val = attrdef->m_imax; + } + else if (val < attrdef->m_imin || val > attrdef->m_imax) { PyErr_SetString(PyExc_ValueError, "item value out of range"); goto UNDO_AND_ERROR; @@ -352,21 +391,25 @@ int PyObjectPlus::_setattr_self(const PyAttributeDef attrlist[], void *self, con { float *var = reinterpret_cast(ptr); ptr += sizeof(float); - if (PyFloat_Check(item)) + double val = PyFloat_AsDouble(item); + if (val == -1.0 && PyErr_Occurred()) { - double val = PyFloat_AsDouble(item); - if (val < attrdef->m_fmin || val > attrdef->m_fmax) - { - PyErr_SetString(PyExc_ValueError, "item value out of range"); - goto UNDO_AND_ERROR; - } - *var = (float)val; + PyErr_SetString(PyExc_TypeError, "expected a float"); + goto UNDO_AND_ERROR; } - else + else if (attrdef->m_clamp) { - PyErr_SetString(PyExc_TypeError, "expected a float"); + 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_SetString(PyExc_ValueError, "item value out of range"); goto UNDO_AND_ERROR; } + *var = (float)val; break; } default: @@ -378,7 +421,7 @@ int PyObjectPlus::_setattr_self(const PyAttributeDef attrlist[], void *self, con // no error, call check function if any if (attrdef->m_function != NULL) { - if ((*attrdef->m_function)(self) != 0) + if ((*attrdef->m_function)(self, attrdef) != 0) { // post check returned an error, restore values UNDO_AND_ERROR: @@ -409,6 +452,7 @@ int PyObjectPlus::_setattr_self(const PyAttributeDef attrlist[], void *self, con case KX_PYATTRIBUTE_TYPE_SHORT: bufferSize = sizeof(short); break; + case KX_PYATTRIBUTE_TYPE_ENUM: case KX_PYATTRIBUTE_TYPE_INT: bufferSize = sizeof(int); break; @@ -460,7 +504,14 @@ int PyObjectPlus::_setattr_self(const PyAttributeDef attrlist[], void *self, con if (PyInt_Check(value)) { long val = PyInt_AsLong(value); - if (val < attrdef->m_imin || val > attrdef->m_imax) + if (attrdef->m_clamp) + { + if (val < attrdef->m_imin) + val = attrdef->m_imin; + else if (val > attrdef->m_imax) + val = attrdef->m_imax; + } + else if (val < attrdef->m_imin || val > attrdef->m_imax) { PyErr_SetString(PyExc_ValueError, "value out of range"); goto FREE_AND_ERROR; @@ -474,13 +525,28 @@ int PyObjectPlus::_setattr_self(const PyAttributeDef attrlist[], void *self, con } break; } + case KX_PYATTRIBUTE_TYPE_ENUM: + // enum are equivalent to int, just make sure that the field size matches: + if (sizeof(int) != attrdef->m_size) + { + PyErr_SetString(PyExc_AttributeError, "attribute size check error, report to blender.org"); + goto FREE_AND_ERROR; + } + // walkthrough case KX_PYATTRIBUTE_TYPE_INT: { int *var = reinterpret_cast(ptr); if (PyInt_Check(value)) { long val = PyInt_AsLong(value); - if (val < attrdef->m_imin || val > attrdef->m_imax) + if (attrdef->m_clamp) + { + if (val < attrdef->m_imin) + val = attrdef->m_imin; + else if (val > attrdef->m_imax) + val = attrdef->m_imax; + } + else if (val < attrdef->m_imin || val > attrdef->m_imax) { PyErr_SetString(PyExc_ValueError, "value out of range"); goto FREE_AND_ERROR; @@ -497,21 +563,25 @@ int PyObjectPlus::_setattr_self(const PyAttributeDef attrlist[], void *self, con case KX_PYATTRIBUTE_TYPE_FLOAT: { float *var = reinterpret_cast(ptr); - if (PyFloat_Check(value)) + double val = PyFloat_AsDouble(value); + if (val == -1.0 && PyErr_Occurred()) { - double val = PyFloat_AsDouble(value); - if (val < attrdef->m_fmin || val > attrdef->m_fmax) - { - PyErr_SetString(PyExc_ValueError, "value out of range"); - goto FREE_AND_ERROR; - } - *var = (float)val; + PyErr_SetString(PyExc_TypeError, "expected a float"); + goto FREE_AND_ERROR; } - else + else if (attrdef->m_clamp) { - PyErr_SetString(PyExc_TypeError, "expected a float"); + 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_SetString(PyExc_ValueError, "value out of range"); goto FREE_AND_ERROR; } + *var = (float)val; break; } case KX_PYATTRIBUTE_TYPE_STRING: @@ -520,7 +590,24 @@ int PyObjectPlus::_setattr_self(const PyAttributeDef attrlist[], void *self, con if (PyString_Check(value)) { char *val = PyString_AsString(value); - if (strlen(val) < attrdef->m_imin || strlen(val) > attrdef->m_imax) + if (attrdef->m_clamp) + { + if (strlen(val) < attrdef->m_imin) + { + // can't increase the length of the string + PyErr_SetString(PyExc_ValueError, "string length too short"); + goto FREE_AND_ERROR; + } + else if (strlen(val) > attrdef->m_imax) + { + // trim the string + char c = val[attrdef->m_imax]; + val[attrdef->m_imax] = 0; + *var = val; + val[attrdef->m_imax] = c; + break; + } + } else if (strlen(val) < attrdef->m_imin || strlen(val) > attrdef->m_imax) { PyErr_SetString(PyExc_ValueError, "string length out of range"); goto FREE_AND_ERROR; @@ -543,9 +630,10 @@ int PyObjectPlus::_setattr_self(const PyAttributeDef attrlist[], void *self, con // check if post processing is needed if (attrdef->m_function != NULL) { - if ((*attrdef->m_function)(self) != 0) + if ((*attrdef->m_function)(self, attrdef) != 0) { // restore value + RESTORE_AND_ERROR: if (undoBuffer) { if (attrdef->m_type == KX_PYATTRIBUTE_TYPE_STRING) diff --git a/source/gameengine/Expressions/PyObjectPlus.h b/source/gameengine/Expressions/PyObjectPlus.h index 016fa293d73..e0e2213d984 100644 --- a/source/gameengine/Expressions/PyObjectPlus.h +++ b/source/gameengine/Expressions/PyObjectPlus.h @@ -216,6 +216,7 @@ PyObject* class_name::Py##method_name(PyObject*) */ enum KX_PYATTRIBUTE_TYPE { KX_PYATTRIBUTE_TYPE_BOOL, + KX_PYATTRIBUTE_TYPE_ENUM, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_TYPE_FLOAT, @@ -228,17 +229,20 @@ enum KX_PYATTRIBUTE_ACCESS { KX_PYATTRIBUTE_RO }; -typedef int (*KX_PYATTRIBUTE_FUNCTION)(void *self); +struct KX_PYATTRIBUTE_DEF; +typedef int (*KX_PYATTRIBUTE_FUNCTION)(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); typedef struct KX_PYATTRIBUTE_DEF { const char *m_name; // name of the python attribute KX_PYATTRIBUTE_TYPE m_type; // type of value KX_PYATTRIBUTE_ACCESS m_access; // read/write access or read-only - int m_imin; // minimum value in case of integer attributes - int m_imax; // maximum value in case of integer attributes + int m_imin; // minimum value in case of integer attributes (for string: minimum string length) + int m_imax; // maximum value in case of integer attributes (for string: maximum string length) float m_fmin; // minimum value in case of float attributes float m_fmax; // maximum value in case of float attributes + bool m_clamp; // enforce min/max value by clamping size_t m_offset; // position of field in structure + size_t m_size; // size of field for runtime verification (enum only) size_t m_length; // length of array, 1=simple attribute KX_PYATTRIBUTE_FUNCTION m_function; // static function to check the assignment, returns 0 if no error // The following pointers are just used to have compile time check for attribute type. @@ -254,60 +258,70 @@ typedef struct KX_PYATTRIBUTE_DEF { } PyAttributeDef; #define KX_PYATTRIBUTE_DUMMY(name) \ - { name, KX_PYATTRIBUTE_TYPE_DUMMY, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, 0, 1, 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} } #define KX_PYATTRIBUTE_BOOL_RW(name,object,field) \ - { name, KX_PYATTRIBUTE_TYPE_BOOL, KX_PYATTRIBUTE_RW, 0, 1, 0.f, 0.f, offsetof(object,field), 1, 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, {&((object *)0)->field, 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, offsetof(object,field), 1, &object::function, {&((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, {&((object *)0)->field, 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, offsetof(object,field), 1, NULL, {&((object *)0)->field, NULL, NULL, NULL, NULL} } - -#define KX_PYATTRIBUTE_SHORT_RW(name,min,max,object,field) \ - { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, offsetof(object,field), 1, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL} } -#define KX_PYATTRIBUTE_SHORT_RW_CHECK(name,min,max,object,field,function) \ - { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, offsetof(object,field), 1, &object::function, {NULL, &((object *)0)->field, NULL, NULL, NULL} } + { name, KX_PYATTRIBUTE_TYPE_BOOL, KX_PYATTRIBUTE_RO, 0, 1, 0.f, 0.f, false, offsetof(object,field), 0, 1, NULL, {&((object *)0)->field, 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} } +#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} } +#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} } + +#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, &((object *)0)->field, 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, &((object *)0)->field, 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, offsetof(object,field), 1, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL} } -#define KX_PYATTRIBUTE_SHORT_ARRAY_RW(name,min,max,object,field,length) \ - { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, offsetof(object,field), length, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL} } -#define KX_PYATTRIBUTE_SHORT_ARRAY_RW_CHECK(name,min,max,object,field,length,function) \ - { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, offsetof(object,field), length, &object::function, {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, &((object *)0)->field, 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, &((object *)0)->field, 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, &((object *)0)->field, 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, offsetof(object,field), length, 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, &((object *)0)->field, NULL, NULL, NULL} } -#define KX_PYATTRIBUTE_INT_RW(name,min,max,object,field) \ - { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, offsetof(object,field), 1, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL} } -#define KX_PYATTRIBUTE_INT_RW_CHECK(name,min,max,object,field,function) \ - { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, offsetof(object,field), 1, &object::function, {NULL, NULL, &((object *)0)->field, 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, &((object *)0)->field, 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, &((object *)0)->field, NULL, NULL} } #define KX_PYATTRIBUTE_INT_RO(name,object,field) \ - { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, offsetof(object,field), 1, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL} } -#define KX_PYATTRIBUTE_INT_ARRAY_RW(name,min,max,object,field,length) \ - { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, offsetof(object,field), length, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL} } -#define KX_PYATTRIBUTE_INT_ARRAY_RW_CHECK(name,min,max,object,field,length,function) \ - { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, offsetof(object,field), length, &object::function, {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, &((object *)0)->field, 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, &((object *)0)->field, 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, &((object *)0)->field, 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, offsetof(object,field), length, 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, &((object *)0)->field, 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, offsetof(object,field), 1, 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, &((object *)0)->field, 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, offsetof(object,field), 1, &object::function, {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, &((object *)0)->field, NULL} } #define KX_PYATTRIBUTE_FLOAT_RO(name,object,field) \ - { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, offsetof(object,field), 1, 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, &((object *)0)->field, 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, offsetof(object,field), length, 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, &((object *)0)->field, 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, offsetof(object,field), length, &object::function, {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, &((object *)0)->field, 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, offsetof(object,field), length, 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, &((object *)0)->field, NULL} } -#define KX_PYATTRIBUTE_STRING_RW(name,min,max,object,field) \ - { name, KX_PYATTRIBUTE_TYPE_STRING, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, offsetof(object,field), 1, NULL, {NULL, NULL, NULL, NULL, &((object *)0)->field} } -#define KX_PYATTRIBUTE_STRING_RW_CHECK(name,min,max,object,field,function) \ - { name, KX_PYATTRIBUTE_TYPE_STRING, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, offsetof(object,field), 1, &object::function, {NULL, NULL, NULL, NULL, &((object *)0)->field} } +#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, &((object *)0)->field} } +#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, &((object *)0)->field} } #define KX_PYATTRIBUTE_STRING_RO(name,object,field) \ - { name, KX_PYATTRIBUTE_TYPE_STRING, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, offsetof(object,field), 1 , 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, &((object *)0)->field} } /*------------------------------ * PyObjectPlus diff --git a/source/gameengine/GameLogic/SCA_ActuatorSensor.cpp b/source/gameengine/GameLogic/SCA_ActuatorSensor.cpp index 5ad28dbf329..fae8d2ba5a7 100644 --- a/source/gameengine/GameLogic/SCA_ActuatorSensor.cpp +++ b/source/gameengine/GameLogic/SCA_ActuatorSensor.cpp @@ -156,27 +156,34 @@ PyMethodDef SCA_ActuatorSensor::Methods[] = { {NULL,NULL} //Sentinel }; +PyAttributeDef SCA_ActuatorSensor::Attributes[] = { + KX_PYATTRIBUTE_STRING_RW_CHECK("actuator",0,100,false,SCA_ActuatorSensor,m_checkactname,CheckActuator), + { NULL } //Sentinel +}; + PyObject* SCA_ActuatorSensor::_getattr(const STR_String& attr) { - if (attr == "actuator") { - return PyString_FromString(m_checkactname); - } + PyObject* object = _getattr_self(Attributes, this, attr); + if (object != NULL) + return object; _getattr_up(SCA_ISensor); /* implicit return! */ } -int SCA_ActuatorSensor::_setattr(const STR_String& attr, PyObject *value) { - if (PyString_Check(value)) { - char* sval = PyString_AsString(value); - if (attr == "actuator") { - SCA_IActuator* act = GetParent()->FindActuator(STR_String(sval)); - if (act) { - m_checkactname = sval; - m_actuator = act; - return 0; - } - PyErr_SetString(PyExc_AttributeError, "string does not correspond to an actuator"); - return 1; - } +int SCA_ActuatorSensor::CheckActuator(void *self, const PyAttributeDef*) +{ + SCA_ActuatorSensor* sensor = reinterpret_cast(self); + SCA_IActuator* act = sensor->GetParent()->FindActuator(sensor->m_checkactname); + if (act) { + sensor->m_actuator = act; + return 0; } + PyErr_SetString(PyExc_AttributeError, "string does not correspond to an actuator"); + return 1; +} + +int SCA_ActuatorSensor::_setattr(const STR_String& attr, PyObject *value) { + int ret = _setattr_self(Attributes, this, attr, value); + if (ret >= 0) + return ret; return SCA_ISensor::_setattr(attr, value); } diff --git a/source/gameengine/GameLogic/SCA_ActuatorSensor.h b/source/gameengine/GameLogic/SCA_ActuatorSensor.h index 4fe4700602c..3d64247461c 100644 --- a/source/gameengine/GameLogic/SCA_ActuatorSensor.h +++ b/source/gameengine/GameLogic/SCA_ActuatorSensor.h @@ -69,6 +69,7 @@ public: /* 4. getProperty */ KX_PYMETHOD_DOC_NOARGS(SCA_ActuatorSensor,GetActuator); + static int CheckActuator(void *self, const PyAttributeDef*); }; #endif diff --git a/source/gameengine/GameLogic/SCA_DelaySensor.cpp b/source/gameengine/GameLogic/SCA_DelaySensor.cpp index 362483b58a2..4c97ca98d72 100644 --- a/source/gameengine/GameLogic/SCA_DelaySensor.cpp +++ b/source/gameengine/GameLogic/SCA_DelaySensor.cpp @@ -171,43 +171,24 @@ PyMethodDef SCA_DelaySensor::Methods[] = { {NULL,NULL} //Sentinel }; +PyAttributeDef SCA_DelaySensor::Attributes[] = { + KX_PYATTRIBUTE_INT_RW("delay",0,100000,true,SCA_DelaySensor,m_delay), + KX_PYATTRIBUTE_INT_RW("duration",0,100000,true,SCA_DelaySensor,m_duration), + KX_PYATTRIBUTE_BOOL_RW("repeat",SCA_DelaySensor,m_repeat), + { NULL } //Sentinel +}; + PyObject* SCA_DelaySensor::_getattr(const STR_String& attr) { - if (attr == "delay") { - return PyInt_FromLong(m_delay); - } - if (attr == "duration") { - return PyInt_FromLong(m_duration); - } - if (attr == "repeat") { - return PyInt_FromLong(m_repeat); - } + PyObject* object = _getattr_self(Attributes, this, attr); + if (object != NULL) + return object; _getattr_up(SCA_ISensor); } int SCA_DelaySensor::_setattr(const STR_String& attr, PyObject *value) { - if (PyInt_Check(value)) { - int ival = PyInt_AsLong(value); - if (attr == "delay") { - if (ival < 0) { - PyErr_SetString(PyExc_ValueError, "Delay cannot be negative"); - return 1; - } - m_delay = ival; - return 0; - } - if (attr == "duration") { - if (ival < 0) { - PyErr_SetString(PyExc_ValueError, "Duration cannot be negative"); - return 1; - } - m_duration = ival; - return 0; - } - if (attr == "repeat") { - m_repeat = (ival != 0); - return 0; - } - } + int ret = _setattr_self(Attributes, this, attr, value); + if (ret >= 0) + return ret; return SCA_ISensor::_setattr(attr, value); } diff --git a/source/gameengine/GameLogic/SCA_ILogicBrick.cpp b/source/gameengine/GameLogic/SCA_ILogicBrick.cpp index 515b485061d..37658480c05 100644 --- a/source/gameengine/GameLogic/SCA_ILogicBrick.cpp +++ b/source/gameengine/GameLogic/SCA_ILogicBrick.cpp @@ -252,7 +252,23 @@ PyMethodDef SCA_ILogicBrick::Methods[] = { {NULL,NULL} //Sentinel }; - +int SCA_ILogicBrick::CheckProperty(void *self, const PyAttributeDef *attrdef) +{ + if (attrdef->m_type != KX_PYATTRIBUTE_TYPE_STRING || attrdef->m_length != 1) { + PyErr_SetString(PyExc_AttributeError, "inconsistent check function for attribute type, report to blender.org"); + return 1; + } + SCA_ILogicBrick* brick = reinterpret_cast(self); + STR_String* var = reinterpret_cast((char*)self+attrdef->m_offset); + CValue* prop = brick->GetParent()->FindIdentifier(*var); + bool error = prop->IsError(); + prop->Release(); + if (error) { + PyErr_SetString(PyExc_ValueError, "string does not correspond to a property"); + return 1; + } + return 0; +} PyObject* SCA_ILogicBrick::_getattr(const STR_String& attr) diff --git a/source/gameengine/GameLogic/SCA_ILogicBrick.h b/source/gameengine/GameLogic/SCA_ILogicBrick.h index c28711ac0f6..38ec80d4096 100644 --- a/source/gameengine/GameLogic/SCA_ILogicBrick.h +++ b/source/gameengine/GameLogic/SCA_ILogicBrick.h @@ -89,6 +89,9 @@ public: KX_PYMETHOD(SCA_ILogicBrick,SetExecutePriority); KX_PYMETHOD_NOARGS(SCA_ILogicBrick,GetExecutePriority); + // check that attribute is a property + static int CheckProperty(void *self, const PyAttributeDef *attrdef); + enum KX_BOOL_TYPE { KX_BOOL_NODEF = 0, KX_TRUE, diff --git a/source/gameengine/GameLogic/SCA_ISensor.cpp b/source/gameengine/GameLogic/SCA_ISensor.cpp index 6e46c8504bb..68a3a93eab0 100644 --- a/source/gameengine/GameLogic/SCA_ISensor.cpp +++ b/source/gameengine/GameLogic/SCA_ISensor.cpp @@ -448,19 +448,24 @@ PyMethodDef SCA_ISensor::Methods[] = { {NULL,NULL} //Sentinel }; +PyAttributeDef SCA_ISensor::Attributes[] = { + KX_PYATTRIBUTE_BOOL_RW("usePosPulseMode",SCA_ISensor,m_pos_pulsemode), + KX_PYATTRIBUTE_BOOL_RW("useNegPulseMode",SCA_ISensor,m_neg_pulsemode), + KX_PYATTRIBUTE_INT_RW("frequency",0,100000,true,SCA_ISensor,m_pulse_frequency), + KX_PYATTRIBUTE_BOOL_RW("invert",SCA_ISensor,m_invert), + KX_PYATTRIBUTE_BOOL_RW("level",SCA_ISensor,m_level), + // make these properties read-only in _setaddr, must still implement them in _getattr + KX_PYATTRIBUTE_DUMMY("triggered"), + KX_PYATTRIBUTE_DUMMY("positive"), + { NULL } //Sentinel +}; + PyObject* SCA_ISensor::_getattr(const STR_String& attr) { - if (attr == "usePosPulseMode") - return PyInt_FromLong(m_pos_pulsemode); - if (attr == "useNegPulseMode") - return PyInt_FromLong(m_neg_pulsemode); - if (attr == "frequency") - return PyInt_FromLong(m_pulse_frequency); - if (attr == "invert") - return PyInt_FromLong(m_invert); - if (attr == "level") - return PyInt_FromLong(m_level); + PyObject* object = _getattr_self(Attributes, this, attr); + if (object != NULL) + return object; if (attr == "triggered") { int retval = 0; @@ -473,54 +478,14 @@ SCA_ISensor::_getattr(const STR_String& attr) int retval = IsPositiveTrigger(); return PyInt_FromLong(retval); } - - _getattr_up(SCA_ILogicBrick); + _getattr_up(SCA_ILogicBrick); } int SCA_ISensor::_setattr(const STR_String& attr, PyObject *value) { - if (attr == "triggered") - PyErr_SetString(PyExc_AttributeError, "attribute \"triggered\" is read only"); - if (attr == "positive") - PyErr_SetString(PyExc_AttributeError, "attribute \"positive\" is read only"); - - if (PyInt_Check(value)) - { - int val = PyInt_AsLong(value); - - if (attr == "usePosPulseMode") - { - m_pos_pulsemode = (val != 0); - return 0; - } - - if (attr == "useNegPulseMode") - { - m_neg_pulsemode = (val != 0); - return 0; - } - - if (attr == "invert") - { - m_invert = (val != 0); - return 0; - } - - if (attr == "level") - { - m_level = (val != 0); - return 0; - } - - if (attr == "frequency") - { - if (val < 0) - val = 0; - m_pulse_frequency = val; - return 0; - } - } - + int ret = _setattr_self(Attributes, this, attr, value); + if (ret >= 0) + return ret; return SCA_ILogicBrick::_setattr(attr, value); } /* eof */ diff --git a/source/gameengine/GameLogic/SCA_JoystickSensor.cpp b/source/gameengine/GameLogic/SCA_JoystickSensor.cpp index ce9058448ac..694bca9bac5 100644 --- a/source/gameengine/GameLogic/SCA_JoystickSensor.cpp +++ b/source/gameengine/GameLogic/SCA_JoystickSensor.cpp @@ -328,11 +328,11 @@ PyMethodDef SCA_JoystickSensor::Methods[] = { }; PyAttributeDef SCA_JoystickSensor::Attributes[] = { - KX_PYATTRIBUTE_SHORT_RW("index",0,JOYINDEX_MAX-1,SCA_JoystickSensor,m_joyindex), - KX_PYATTRIBUTE_INT_RW("threshold",0,32768,SCA_JoystickSensor,m_precision), - KX_PYATTRIBUTE_INT_RW("button",0,100,SCA_JoystickSensor,m_button), - KX_PYATTRIBUTE_INT_ARRAY_RW_CHECK("axis",0,3,SCA_JoystickSensor,m_axis,2,CheckAxis), - KX_PYATTRIBUTE_INT_ARRAY_RW_CHECK("hat",0,12,SCA_JoystickSensor,m_hat,2,CheckHat), + KX_PYATTRIBUTE_SHORT_RW("index",0,JOYINDEX_MAX-1,true,SCA_JoystickSensor,m_joyindex), + KX_PYATTRIBUTE_INT_RW("threshold",0,32768,true,SCA_JoystickSensor,m_precision), + KX_PYATTRIBUTE_INT_RW("button",0,100,false,SCA_JoystickSensor,m_button), + KX_PYATTRIBUTE_INT_ARRAY_RW_CHECK("axis",0,3,true,SCA_JoystickSensor,m_axis,2,CheckAxis), + KX_PYATTRIBUTE_INT_ARRAY_RW_CHECK("hat",0,12,true,SCA_JoystickSensor,m_hat,2,CheckHat), // dummy attributes will just be read-only in _setattr // you still need to defined them in _getattr KX_PYATTRIBUTE_DUMMY("axisPosition"), diff --git a/source/gameengine/GameLogic/SCA_JoystickSensor.h b/source/gameengine/GameLogic/SCA_JoystickSensor.h index 25103b3c6bc..fa11f1cc3d0 100644 --- a/source/gameengine/GameLogic/SCA_JoystickSensor.h +++ b/source/gameengine/GameLogic/SCA_JoystickSensor.h @@ -149,24 +149,22 @@ public: KX_PYMETHOD_DOC_NOARGS(SCA_JoystickSensor,Connected); /* attribute check */ - static int CheckAxis(void *self) + static int CheckAxis(void *self, const PyAttributeDef*) { SCA_JoystickSensor* sensor = reinterpret_cast(self); - if (sensor->m_axis < 1 || sensor->m_axis > 2) - { - PyErr_SetString(PyExc_ValueError, "axis number must be 1 or 2"); - return 1; - } + if (sensor->m_axis < 1) + sensor->m_axis = 1; + else if (sensor->m_axis > 2) + sensor->m_axis = 2; return 0; } - static int CheckHat(void *self) + static int CheckHat(void *self, const PyAttributeDef*) { SCA_JoystickSensor* sensor = reinterpret_cast(self); - if (sensor->m_hat < 1 || sensor->m_hat > 2) - { - PyErr_SetString(PyExc_ValueError, "hat number must be 1 or 2"); - return 1; - } + if (sensor->m_hat < 1) + sensor->m_hat = 1; + else if (sensor->m_hat > 2) + sensor->m_hat = 2; return 0; } diff --git a/source/gameengine/GameLogic/SCA_KeyboardSensor.cpp b/source/gameengine/GameLogic/SCA_KeyboardSensor.cpp index a05f9ae9879..981d165287b 100644 --- a/source/gameengine/GameLogic/SCA_KeyboardSensor.cpp +++ b/source/gameengine/GameLogic/SCA_KeyboardSensor.cpp @@ -822,11 +822,11 @@ PyMethodDef SCA_KeyboardSensor::Methods[] = { PyAttributeDef SCA_KeyboardSensor::Attributes[] = { KX_PYATTRIBUTE_BOOL_RW("useAllKeys",SCA_KeyboardSensor,m_bAllKeys), - KX_PYATTRIBUTE_INT_RW("key",0,1000,SCA_KeyboardSensor,m_hotkey), - KX_PYATTRIBUTE_SHORT_RW("hold1",0,1000,SCA_KeyboardSensor,m_qual), - KX_PYATTRIBUTE_SHORT_RW("hold2",0,1000,SCA_KeyboardSensor,m_qual2), - KX_PYATTRIBUTE_STRING_RW("toggleProperty",0,100,SCA_KeyboardSensor,m_toggleprop), - KX_PYATTRIBUTE_STRING_RW("targetProperty",0,100,SCA_KeyboardSensor,m_targetprop), + KX_PYATTRIBUTE_INT_RW("key",0,SCA_IInputDevice::KX_ENDKEY,true,SCA_KeyboardSensor,m_hotkey), + KX_PYATTRIBUTE_SHORT_RW("hold1",0,SCA_IInputDevice::KX_ENDKEY,true,SCA_KeyboardSensor,m_qual), + KX_PYATTRIBUTE_SHORT_RW("hold2",0,SCA_IInputDevice::KX_ENDKEY,true,SCA_KeyboardSensor,m_qual2), + KX_PYATTRIBUTE_STRING_RW("toggleProperty",0,100,false,SCA_KeyboardSensor,m_toggleprop), + KX_PYATTRIBUTE_STRING_RW("targetProperty",0,100,false,SCA_KeyboardSensor,m_targetprop), { NULL } //Sentinel }; diff --git a/source/gameengine/GameLogic/SCA_MouseSensor.cpp b/source/gameengine/GameLogic/SCA_MouseSensor.cpp index 14d9c898980..09b46e6443e 100644 --- a/source/gameengine/GameLogic/SCA_MouseSensor.cpp +++ b/source/gameengine/GameLogic/SCA_MouseSensor.cpp @@ -59,7 +59,7 @@ SCA_MouseSensor::SCA_MouseSensor(SCA_MouseManager* eventmgr, m_mousemode = mousemode; m_triggermode = true; - UpdateHotkey(this); + UpdateHotkey(this, NULL); Init(); } @@ -74,7 +74,7 @@ SCA_MouseSensor::~SCA_MouseSensor() /* Nothing to be done here. */ } -int SCA_MouseSensor::UpdateHotkey(void *self) +int SCA_MouseSensor::UpdateHotkey(void *self, const PyAttributeDef*) { // gosh, this function is so damn stupid // its here because of a design mistake in the mouse sensor, it should only @@ -336,7 +336,7 @@ PyMethodDef SCA_MouseSensor::Methods[] = { }; PyAttributeDef SCA_MouseSensor::Attributes[] = { - KX_PYATTRIBUTE_SHORT_RW_CHECK("mode",KX_MOUSESENSORMODE_NODEF,KX_MOUSESENSORMODE_MAX-1,SCA_MouseSensor,m_mousemode,UpdateHotkey), + KX_PYATTRIBUTE_SHORT_RW_CHECK("mode",KX_MOUSESENSORMODE_NODEF,KX_MOUSESENSORMODE_MAX-1,true,SCA_MouseSensor,m_mousemode,UpdateHotkey), KX_PYATTRIBUTE_SHORT_ARRAY_RO("position",SCA_MouseSensor,m_x,2), { NULL } //Sentinel }; diff --git a/source/gameengine/GameLogic/SCA_MouseSensor.h b/source/gameengine/GameLogic/SCA_MouseSensor.h index 58ee96c8856..82af2ce9c04 100644 --- a/source/gameengine/GameLogic/SCA_MouseSensor.h +++ b/source/gameengine/GameLogic/SCA_MouseSensor.h @@ -87,7 +87,7 @@ class SCA_MouseSensor : public SCA_ISensor bool isValid(KX_MOUSESENSORMODE); - static int UpdateHotkey(void *self); + static int UpdateHotkey(void *self, const PyAttributeDef*); SCA_MouseSensor(class SCA_MouseManager* keybdmgr, int startx,int starty, diff --git a/source/gameengine/GameLogic/SCA_PropertyActuator.cpp b/source/gameengine/GameLogic/SCA_PropertyActuator.cpp index f8509fe380e..566d3b63487 100644 --- a/source/gameengine/GameLogic/SCA_PropertyActuator.cpp +++ b/source/gameengine/GameLogic/SCA_PropertyActuator.cpp @@ -254,36 +254,23 @@ PyMethodDef SCA_PropertyActuator::Methods[] = { {NULL,NULL} //Sentinel }; +PyAttributeDef SCA_PropertyActuator::Attributes[] = { + KX_PYATTRIBUTE_STRING_RW_CHECK("property",0,100,false,SCA_PropertyActuator,m_propname,CheckProperty), + KX_PYATTRIBUTE_STRING_RW("value",0,100,false,SCA_PropertyActuator,m_exprtxt), + { NULL } //Sentinel +}; + PyObject* SCA_PropertyActuator::_getattr(const STR_String& attr) { - if (attr == "property") { - return PyString_FromString(m_propname); - } - if (attr == "value") { - return PyString_FromString(m_exprtxt); - } + PyObject* object = _getattr_self(Attributes, this, attr); + if (object != NULL) + return object; _getattr_up(SCA_IActuator); } int SCA_PropertyActuator::_setattr(const STR_String& attr, PyObject *value) { - if (PyString_Check(value)) { - char* sval = PyString_AsString(value); - if (attr == "property") { - CValue* prop = GetParent()->FindIdentifier(sval); - bool error = prop->IsError(); - prop->Release(); - if (!prop->IsError()) { - m_propname = sval; - return 0; - } else { - PyErr_SetString(PyExc_ValueError, "string does not correspond to a property"); - return 1; - } - } - if (attr == "value") { - m_exprtxt = sval; - return 0; - } - } + int ret = _setattr_self(Attributes, this, attr, value); + if (ret >= 0) + return ret; return SCA_IActuator::_setattr(attr, value); } diff --git a/source/gameengine/GameLogic/SCA_PropertySensor.cpp b/source/gameengine/GameLogic/SCA_PropertySensor.cpp index 19ee85207bb..a6f7a9cd82b 100644 --- a/source/gameengine/GameLogic/SCA_PropertySensor.cpp +++ b/source/gameengine/GameLogic/SCA_PropertySensor.cpp @@ -293,7 +293,7 @@ CValue* SCA_PropertySensor::FindIdentifier(const STR_String& identifiername) return GetParent()->FindIdentifier(identifiername); } -bool SCA_PropertySensor::validValueForProperty(char *val, STR_String &prop) +int SCA_PropertySensor::validValueForProperty(void *self, const PyAttributeDef*) { bool result = true; /* There is no type checking at this moment, unfortunately... */ @@ -344,51 +344,25 @@ PyMethodDef SCA_PropertySensor::Methods[] = { {NULL,NULL} //Sentinel }; +PyAttributeDef SCA_PropertySensor::Attributes[] = { + KX_PYATTRIBUTE_INT_RW("type",KX_PROPSENSOR_NODEF,KX_PROPSENSOR_MAX-1,false,SCA_PropertySensor,m_checktype), + KX_PYATTRIBUTE_STRING_RW_CHECK("property",0,100,false,SCA_PropertySensor,m_checkpropname,CheckProperty), + KX_PYATTRIBUTE_STRING_RW_CHECK("value",0,100,false,SCA_PropertySensor,m_checkpropval,validValueForProperty), + { NULL } //Sentinel +}; + + PyObject* SCA_PropertySensor::_getattr(const STR_String& attr) { - if (attr == "type") { - return PyInt_FromLong(m_checktype); - } - if (attr == "property") { - return PyString_FromString(m_checkpropname); - } - if (attr == "value") { - return PyString_FromString(m_checkpropval); - } + PyObject* object = _getattr_self(Attributes, this, attr); + if (object != NULL) + return object; _getattr_up(SCA_ISensor); /* implicit return! */ } int SCA_PropertySensor::_setattr(const STR_String& attr, PyObject *value) { - if (PyInt_Check(value)) { - int ival = PyInt_AsLong(value); - if (attr == "type") { - if ((ival <= KX_PROPSENSOR_NODEF) || (ival >= KX_PROPSENSOR_MAX)) { - PyErr_SetString(PyExc_ValueError, "type out of range"); - return 1; - } - m_checktype = ival; - } - return 0; - } - if (PyString_Check(value)) { - char* sval = PyString_AsString(value); - if (attr == "property") { - CValue *prop = FindIdentifier(STR_String(sval)); - bool error = prop->IsError(); - prop->Release(); - if (error) { - PyErr_SetString(PyExc_ValueError, "string does not correspond to a property"); - return 1; - } - m_checkpropname = sval; - } else if (attr == "value") { - if (!validValueForProperty(sval, m_checkpropname)) { - PyErr_SetString(PyExc_ValueError, "string does not represent a suitable value for the property"); - return 1; - } - m_checkpropval = sval; - } - return 0; - } + int ret = _setattr_self(Attributes, this, attr, value); + if (ret >= 0) + return ret; return SCA_ISensor::_setattr(attr, value); } @@ -490,11 +464,12 @@ PyObject* SCA_PropertySensor::PySetValue(PyObject* self, PyObject* args, PyObjec if(!PyArg_ParseTuple(args, "s", &propValArg)) { return NULL; } - - if (validValueForProperty(propValArg, m_checkpropname)) { - m_checkpropval = propValArg; + STR_String oldval = m_checkpropval; + m_checkpropval = propValArg; + if (validValueForProperty(self, NULL)) { + m_checkpropval = oldval; + return NULL; } - Py_Return; } diff --git a/source/gameengine/GameLogic/SCA_PropertySensor.h b/source/gameengine/GameLogic/SCA_PropertySensor.h index 81203c78f9d..e625e84a36f 100644 --- a/source/gameengine/GameLogic/SCA_PropertySensor.h +++ b/source/gameengine/GameLogic/SCA_PropertySensor.h @@ -47,10 +47,6 @@ class SCA_PropertySensor : public SCA_ISensor bool m_recentresult; CExpression* m_range_expr; - /** - * Test whether this is a sensible value (type check) - */ - bool validValueForProperty(char *val, STR_String &prop); protected: public: @@ -104,7 +100,10 @@ public: KX_PYMETHOD_DOC(SCA_PropertySensor,GetValue); /* 6. setValue */ KX_PYMETHOD_DOC(SCA_PropertySensor,SetValue); - + /** + * Test whether this is a sensible value (type check) + */ + static int validValueForProperty(void* self, const PyAttributeDef*); }; #endif diff --git a/source/gameengine/GameLogic/SCA_RandomActuator.cpp b/source/gameengine/GameLogic/SCA_RandomActuator.cpp index 8dd405c3d82..840b95d559a 100644 --- a/source/gameengine/GameLogic/SCA_RandomActuator.cpp +++ b/source/gameengine/GameLogic/SCA_RandomActuator.cpp @@ -361,57 +361,38 @@ PyMethodDef SCA_RandomActuator::Methods[] = { {NULL,NULL} //Sentinel }; +PyAttributeDef SCA_RandomActuator::Attributes[] = { + KX_PYATTRIBUTE_FLOAT_RO("para1",SCA_RandomActuator,m_parameter1), + KX_PYATTRIBUTE_FLOAT_RO("para2",SCA_RandomActuator,m_parameter2), + KX_PYATTRIBUTE_ENUM_RO("distribution",SCA_RandomActuator,m_distribution), + KX_PYATTRIBUTE_STRING_RW_CHECK("property",0,100,false,SCA_RandomActuator,m_propname,CheckProperty), + { NULL } //Sentinel +}; + PyObject* SCA_RandomActuator::_getattr(const STR_String& attr) { + PyObject* object = _getattr_self(Attributes, this, attr); + if (object != NULL) + return object; if (attr == "seed") { return PyInt_FromLong(m_base->GetSeed()); } - if (attr == "para1") { - return PyFloat_FromDouble(m_parameter1); - } - if (attr == "para2") { - return PyFloat_FromDouble(m_parameter2); - } - if (attr == "distribution") { - return PyInt_FromLong(m_distribution); - } - if (attr == "property") { - return PyString_FromString(m_propname); - } _getattr_up(SCA_IActuator); } int SCA_RandomActuator::_setattr(const STR_String& attr, PyObject *value) { - if (attr == "para1") { - PyErr_SetString(PyExc_AttributeError, "para1 is read only"); - } - if (attr == "para2") { - PyErr_SetString(PyExc_AttributeError, "para2 is read only"); - } - if (attr == "distribution") { - PyErr_SetString(PyExc_AttributeError, "distribution is read only"); - } - if (PyInt_Check(value)) { - int ival = PyInt_AsLong(value); - if (attr == "seed") { + int ret = _setattr_self(Attributes, this, attr, value); + if (ret >= 0) + return ret; + if (attr == "seed") { + if (PyInt_Check(value)) { + int ival = PyInt_AsLong(value); m_base->SetSeed(ival); + return 0; + } else { + PyErr_SetString(PyExc_TypeError, "expected an integer"); + return 1; } - return 0; - } - if (PyString_Check(value)) { - char* sval = PyString_AsString(value); - if (attr == "property") { - CValue* prop = GetParent()->FindIdentifier(sval); - bool error = prop->IsError(); - prop->Release(); - if (!prop->IsError()) { - m_propname = sval; - return 0; - } else { - PyErr_SetString(PyExc_ValueError, "string does not correspond to a property"); - return 1; - } - } } return SCA_IActuator::_setattr(attr, value); } diff --git a/source/gameengine/GameLogic/SCA_RandomActuator.h b/source/gameengine/GameLogic/SCA_RandomActuator.h index 2fc14f9a0b7..de8faaf9c72 100644 --- a/source/gameengine/GameLogic/SCA_RandomActuator.h +++ b/source/gameengine/GameLogic/SCA_RandomActuator.h @@ -136,7 +136,6 @@ class SCA_RandomActuator : public SCA_IActuator KX_PYMETHOD_DOC(SCA_RandomActuator,SetFloatNormal); /* 20. setFloatNegativeExponential, */ KX_PYMETHOD_DOC(SCA_RandomActuator,SetFloatNegativeExponential); - }; /* end of class KX_EditObjectActuator : public SCA_PropertyActuator */ #endif -- cgit v1.2.3