[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [18267] trunk/blender/source/gameengine: BGE API Cleanup: update the python attribute definition framework.

Benoit Bolsee benoit.bolsee at online.be
Fri Jan 2 18:43:57 CET 2009


Revision: 18267
          http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=18267
Author:   ben2610
Date:     2009-01-02 18:43:56 +0100 (Fri, 02 Jan 2009)

Log Message:
-----------
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.

Modified Paths:
--------------
    trunk/blender/source/gameengine/Expressions/PyObjectPlus.cpp
    trunk/blender/source/gameengine/Expressions/PyObjectPlus.h
    trunk/blender/source/gameengine/GameLogic/SCA_ActuatorSensor.cpp
    trunk/blender/source/gameengine/GameLogic/SCA_ActuatorSensor.h
    trunk/blender/source/gameengine/GameLogic/SCA_DelaySensor.cpp
    trunk/blender/source/gameengine/GameLogic/SCA_ILogicBrick.cpp
    trunk/blender/source/gameengine/GameLogic/SCA_ILogicBrick.h
    trunk/blender/source/gameengine/GameLogic/SCA_ISensor.cpp
    trunk/blender/source/gameengine/GameLogic/SCA_JoystickSensor.cpp
    trunk/blender/source/gameengine/GameLogic/SCA_JoystickSensor.h
    trunk/blender/source/gameengine/GameLogic/SCA_KeyboardSensor.cpp
    trunk/blender/source/gameengine/GameLogic/SCA_MouseSensor.cpp
    trunk/blender/source/gameengine/GameLogic/SCA_MouseSensor.h
    trunk/blender/source/gameengine/GameLogic/SCA_PropertyActuator.cpp
    trunk/blender/source/gameengine/GameLogic/SCA_PropertySensor.cpp
    trunk/blender/source/gameengine/GameLogic/SCA_PropertySensor.h
    trunk/blender/source/gameengine/GameLogic/SCA_RandomActuator.cpp
    trunk/blender/source/gameengine/GameLogic/SCA_RandomActuator.h

Modified: trunk/blender/source/gameengine/Expressions/PyObjectPlus.cpp
===================================================================
--- trunk/blender/source/gameengine/Expressions/PyObjectPlus.cpp	2009-01-02 16:58:09 UTC (rev 18266)
+++ trunk/blender/source/gameengine/Expressions/PyObjectPlus.cpp	2009-01-02 17:43:56 UTC (rev 18267)
@@ -164,6 +164,14 @@
 							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 @@
 						}
 					default:
 						// no support for array of complex data
+						Py_DECREF(resultlist);
 						return NULL;
 					}
 				}
@@ -198,6 +207,13 @@
 						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 @@
 				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,8 +330,15 @@
 							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 @@
 							}
 							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,8 +366,15 @@
 							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 @@
 						{
 							float *var = reinterpret_cast<float*>(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 @@
 				// 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 @@
 					case KX_PYATTRIBUTE_TYPE_SHORT:
 						bufferSize = sizeof(short);
 						break;
+					case KX_PYATTRIBUTE_TYPE_ENUM:
 					case KX_PYATTRIBUTE_TYPE_INT:
 						bufferSize = sizeof(int);
 						break;
@@ -460,8 +504,15 @@
 						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,14 +525,29 @@
 						}
 						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 @@
 				case KX_PYATTRIBUTE_TYPE_FLOAT:
 					{
 						float *var = reinterpret_cast<float*>(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,8 +590,25 @@
 						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 @@
 			// 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)

Modified: trunk/blender/source/gameengine/Expressions/PyObjectPlus.h
===================================================================
--- trunk/blender/source/gameengine/Expressions/PyObjectPlus.h	2009-01-02 16:58:09 UTC (rev 18266)
+++ trunk/blender/source/gameengine/Expressions/PyObjectPlus.h	2009-01-02 17:43:56 UTC (rev 18267)
@@ -216,6 +216,7 @@
  */
 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 @@
 	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

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list