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.
This commit is contained in:
Benoit Bolsee 2009-01-02 17:43:56 +00:00
parent abd4934d1a
commit cc569504d0
18 changed files with 326 additions and 312 deletions

@ -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<int*>(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<short int*>(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<int*>(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<int*>(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<float*>(ptr);
ptr += sizeof(float);
if (PyFloat_Check(item))
{
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;
}
else
double val = PyFloat_AsDouble(item);
if (val == -1.0 && PyErr_Occurred())
{
PyErr_SetString(PyExc_TypeError, "expected a float");
goto UNDO_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_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<int*>(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<float*>(ptr);
if (PyFloat_Check(value))
{
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;
}
else
double val = PyFloat_AsDouble(value);
if (val == -1.0 && PyErr_Occurred())
{
PyErr_SetString(PyExc_TypeError, "expected a float");
goto FREE_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_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)

@ -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} }
{ 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} }
#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} }
// 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

@ -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<SCA_ActuatorSensor*>(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);
}

@ -69,6 +69,7 @@ public:
/* 4. getProperty */
KX_PYMETHOD_DOC_NOARGS(SCA_ActuatorSensor,GetActuator);
static int CheckActuator(void *self, const PyAttributeDef*);
};
#endif

@ -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);
}

@ -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<SCA_ILogicBrick*>(self);
STR_String* var = reinterpret_cast<STR_String*>((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)

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

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

@ -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"),

@ -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<SCA_JoystickSensor*>(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<SCA_JoystickSensor*>(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;
}

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

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

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

@ -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);
}

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

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

@ -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);
}

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