On 6/30/07, The Watermelon <[EMAIL PROTECTED]> wrote:
1.Fixed some problems with aiChoose* functions,the griditeration didnt check
whether the units from iteration tiles is 'died' or not.

Good!

2.Changed assert (psDroid->numWeaps < MAX_DROIDWEAPS) to (psDroid->numWeaps
<= MAX_DROIDWEAPS),because the numWeaps is equal to
MAX_DROIDWEAPS(MAX_DROIDWEAPS is used to check against array index)

I do not understand this one.

I have committed parts of the patch to make it easier to handle, and
the remaining part is attached. Otherwise there should be no changes.

 - Per
Index: src/base.h
===================================================================
--- src/base.h	(revision 1637)
+++ src/base.h	(working copy)
@@ -54,7 +54,8 @@
 	UWORD				x,y,z;		/* Object's location */ \
 	float				direction;	/* Object's direction +ve rotation about y axis*/ \
 	SWORD				pitch;		/* Object's pitch +ve nose up*/ \
-	SWORD				roll		/* Object's roll +ve left up, right down */
+	SWORD				roll;		/* Object's roll +ve left up, right down */ \
+	SWORD				refCount	/* Object's reference count, for safe deallocation */
 
 #define BASE_ELEMENTS2(pointerType) \
 	SCREEN_DISP_DATA	sDisplay;	/* screen coordinate details */ \
Index: src/structure.h
===================================================================
--- src/structure.h	(revision 1637)
+++ src/structure.h	(working copy)
@@ -28,6 +28,7 @@
 
 #include "objectdef.h"
 #include "structuredef.h"
+#include "objmem.h"
 
 // how long to wait between CALL_STRUCT_ATTACKED's - plus how long to flash on radar for
 #define ATTACK_CB_PAUSE		5000
@@ -396,10 +397,21 @@
 selected - returns TRUE if valid*/
 extern BOOL lasSatStructSelected(STRUCTURE *psStruct);
 
-static inline void setStructureTarget(STRUCTURE *psBuilding, BASE_OBJECT *psNewTarget, UWORD idx)
+#define setStructureTarget(x,y,z) _setStructureTarget(x,y,z, __FILE__, __LINE__)
+
+static inline void _setStructureTarget(STRUCTURE *psBuilding, BASE_OBJECT *psNewTarget, UWORD idx, char *file, int line)
 {
 	assert(idx < STRUCT_MAXWEAPS);
-	psBuilding->psTarget[idx] = psNewTarget;
+	if (psBuilding->psTarget[idx] != NULL)
+	{
+		decrRefCount(psBuilding->psTarget[idx], file, line);
+		psBuilding->psTarget[idx] = NULL;
+	}
+	if (psNewTarget != NULL)
+	{
+		psBuilding->psTarget[idx] = psNewTarget;
+		incrRefCount(psNewTarget, file, line);
+	}
 }
 
 #define CHECK_STRUCTURE(object) \
@@ -416,6 +428,7 @@
 		assert(object->turretRotation[i] <= 360); \
 		if (object->psTarget[i]) \
 		{ \
+			assert(object->psTarget[i]->refCount > 0); \
 			CHECK_OBJECT(object->psTarget[i]); \
 		} \
 	} \
Index: src/projectile.h
===================================================================
--- src/projectile.h	(revision 1637)
+++ src/projectile.h	(working copy)
@@ -126,19 +126,50 @@
 // Watermelon:naybor related functions
 extern void projGetNaybors(PROJ_OBJECT *psObj);
 
-static inline void setProjectileDestination(PROJ_OBJECT *psProj, BASE_OBJECT *psObj)
+#define setProjectileDestination(x,y) _setProjectileDestination(x,y, __FILE__, __LINE__)
+#define setProjectileSource(x,y) _setProjectileSource(x,y, __FILE__, __LINE__)
+#define setProjectileDamaged(x,y) _setProjectileDamaged(x,y, __FILE__, __LINE__)
+
+static inline void _setProjectileDestination(PROJ_OBJECT *psProj, BASE_OBJECT *psObj, char *file, int line)
 {
-	psProj->psDest = psObj;
+	if (psProj->psDest != NULL)
+	{
+		decrRefCount(psProj->psDest, file, line);
+		psProj->psDest = NULL;
+	}
+	if (psObj != NULL)
+	{
+		psProj->psDest = psObj;
+		incrRefCount(psObj, file, line);
+	}
 }
 
-static inline void setProjectileSource(PROJ_OBJECT *psProj, BASE_OBJECT *psObj)
+static inline void _setProjectileSource(PROJ_OBJECT *psProj, BASE_OBJECT *psObj, char *file, int line)
 {
-	psProj->psSource = psObj;
+	if (psProj->psSource != NULL)
+	{
+		decrRefCount(psProj->psSource, file, line);
+		psProj->psSource = NULL;
+	}
+	if (psObj != NULL)
+	{
+		psProj->psSource = psObj;
+		incrRefCount(psObj, file, line);
+	}
 }
 
-static inline void setProjectileDamaged(PROJ_OBJECT *psProj, BASE_OBJECT *psObj)
+static inline void _setProjectileDamaged(PROJ_OBJECT *psProj, BASE_OBJECT *psObj, char *file, int line)
 {
-	psProj->psDamaged = psObj;
+	if (psProj->psDamaged != NULL)
+	{
+		decrRefCount(psProj->psDamaged, file, line);
+		psProj->psDamaged = NULL;
+	}
+	if (psObj != NULL)
+	{
+		psProj->psDamaged = psObj;
+		incrRefCount(psObj, file, line);
+	}
 }
 
 /* assert if projectile is bad */
@@ -153,6 +184,9 @@
 	if (object->psDest) CHECK_OBJECT(object->psDest); \
 	if (object->psSource) CHECK_OBJECT(object->psSource); \
 	if (object->psDamaged) CHECK_OBJECT(object->psDamaged); \
+	assert(!object->psDest || object->psDest->refCount > 0); \
+	assert(!object->psSource || object->psSource->refCount > 0); \
+	assert(!object->psDamaged || object->psDamaged->refCount > 0); \
 } while (0)
 
 
Index: src/objmem.c
===================================================================
--- src/objmem.c	(revision 1637)
+++ src/objmem.c	(working copy)
@@ -21,7 +21,27 @@
  * ObjMem.c
  *
  * Object memory management functions.
+ * 
+ * It works like this:
  *
+ * Dead objects are moved from the general lists to the destroyed lists for a while
+ * until they are released for good. This ensures that pointer references remain
+ * valid. Then we need a way to check that the objects are ready for release:
+ * 
+ * Old version (Pumpkin solution): Each object has a 'died' field which records the time
+ * frame it tied. At the end of the next turn, it is deleted. During the next turn, all
+ * objects are supposed to be iterated through by an update function that checks this
+ * 'died' field and change all references to dead objects. This way no object should point
+ * to the memory of a released object.
+ *
+ * The new version (Ressurection project solution): Each object has a reference count,
+ * and each time some object points at this object, we increase the reference count,
+ * and each time another object stops pointing at it, the counter is decreased. The
+ * object is not released from memory until its reference counter is zero.
+ *
+ * Debug builds currently only use the new way, while release builds use both for
+ * maximum safety (err on the memory usage side rather than on the crash game side).
+ *
  */
 #include <string.h>
 
@@ -106,7 +126,8 @@
 	free(psObj);
 }
 
-/* General housekeeping for the object system */
+/* General housekeeping for the object system. We use both old and new systems for
+ * non-debug builds for maximum safety! */
 void objmemUpdate(void)
 {
 	BASE_OBJECT		*psCurr, *psNext, *psPrev;
@@ -122,11 +143,12 @@
 		scrvUpdateBasePointers();
 	}
 
-	/* Go through the destroyed objects list looking for objects that
-	   were destroyed before this turn */
-
 	/* First remove the objects from the start of the list */
-	while (psDestroyedObj != NULL && psDestroyedObj->died != gameTime)
+	while (psDestroyedObj != NULL && psDestroyedObj->refCount == 0
+#ifndef DEBUG
+	       && pDestroyed->died != gameTime
+#endif
+	       )
 	{
 		psNext = psDestroyedObj->psNext;
 		objmemDestroy(psDestroyedObj);
@@ -138,17 +160,9 @@
 	for(psCurr = psPrev = psDestroyedObj; psCurr != NULL; psCurr = psNext)
 	{
 		psNext = psCurr->psNext;
-		if (psCurr->died != gameTime)
+		if (gameTime == psDestroyedObj->died)
 		{
-			objmemDestroy(psCurr);
-
-			/*set the linked list up - you will never be deleting the top
-			of the list, so don't have to check*/
-			psPrev->psNext = psNext;
-		}
-		else
-		{
-			// do the object died callback
+			// do the object died callback now
 			psCBObjDestroyed = psCurr;
 			eventFireCallbackTrigger((TRIGGER_TYPE)CALL_OBJ_DESTROYED);
 			switch (psCurr->type)
@@ -169,6 +183,18 @@
 
 			psPrev = psCurr;
 		}
+		if (psDestroyedObj->refCount == 0
+#ifndef DEBUG
+		    && pDestroyed->died != gameTime
+#endif
+		   )
+		{
+			objmemDestroy(psCurr);
+
+			/*set the linked list up - you will never be deleting the top
+			of the list because of the above hack, so don't have to check*/
+			psPrev->psNext = psNext;
+		}
 	}
 }
 
@@ -218,6 +244,7 @@
 	objID++;
 	newObject->player = (UBYTE)player;
 	newObject->died = 0;
+	newObject->refCount = 0;
 
 	return newObject;
 }
Index: src/order.c
===================================================================
--- src/order.c	(revision 1637)
+++ src/order.c	(working copy)
@@ -2810,15 +2810,14 @@
 	else
 	{
 		psDroid->asOrderList[psDroid->listSize].order = psOrder->order;
-		//psDroid->asOrderList[psDroid->listSize].psObj = psOrder->psObj;
-        if (psOrder->order == DORDER_BUILD || psOrder->order == DORDER_LINEBUILD)
-        {
-			setDroidOrderTarget(psDroid, (void *)psOrder->psStats, psDroid->listSize);
+		if (psOrder->order == DORDER_BUILD || psOrder->order == DORDER_LINEBUILD)
+		{
+			setDroidOrderTarget(psDroid, (void *)psOrder->psStats, psDroid->listSize, OT_STATS);
 		}
-        else
-        {
-			setDroidOrderTarget(psDroid, (void *)psOrder->psObj[0], psDroid->listSize);
-        }
+		else
+		{
+			setDroidOrderTarget(psDroid, (void *)psOrder->psObj[0], psDroid->listSize, OT_BASE_OBJECT);
+		}
 		psDroid->asOrderList[psDroid->listSize].x = (UWORD)psOrder->x;
 		psDroid->asOrderList[psDroid->listSize].y = (UWORD)psOrder->y;
 		psDroid->asOrderList[psDroid->listSize].x2 = (UWORD)psOrder->x2;
Index: src/objmem.h
===================================================================
--- src/objmem.h	(revision 1637)
+++ src/objmem.h	(working copy)
@@ -27,6 +27,7 @@
 #define _objmem_h
 
 #include "objectdef.h"
+#include "base.h"
 
 //the died flag for a droid is set to this when it gets added to the non-current list
 #define     NOT_CURRENT_LIST        1
@@ -117,5 +118,25 @@
 #ifdef DEBUG
 extern void checkFactoryFlags(void);
 #endif
+
+#define incrRefCount(x, file, line) _incrRefCount(x, file, line, __FUNCTION__)
+#define decrRefCount(x, file, line) _decrRefCount(x, file, line, __FUNCTION__)
+
+// using void to silence warnings
+static inline void _incrRefCount(void *psObj, char *file, int line, const char *function)
+{
+	((BASE_OBJECT *)psObj)->refCount++;
+	debug(LOG_MEMORY, "refCount %s from %s:%d %p ++ for a total of %hd", 
+	      function, file, line, psObj, ((BASE_OBJECT *)psObj)->refCount);
+}
+
+static inline void _decrRefCount(void *psObj, char *file, int line, const char *function)
+{
+	assert(((BASE_OBJECT *)psObj)->refCount > 0);
+	((BASE_OBJECT *)psObj)->refCount--;
+	debug(LOG_MEMORY, "refCount %s from %s:%d %p -- for a total of %hd", 
+	      function, file, line, psObj, ((BASE_OBJECT *)psObj)->refCount);
+}
+
 #endif
 
Index: src/order.h
===================================================================
--- src/order.h	(revision 1637)
+++ src/order.h	(working copy)
@@ -128,6 +128,13 @@
 	DSS_VTOLPROD_END		= 0x10000000,
 } SECONDARY_STATE;
 
+/* different types of order target object in order list */
+typedef enum _order_target_type {
+	OT_BASE_OBJECT,	//BASE_OBJECT target
+	OT_STATS,		//STATS target
+	OT_MAX_TYPES,	//number of target types
+} ORDER_TARGET_TYPE;
+
 // masks for the secondary order state
 #define DSS_ARANGE_MASK		0x000003
 #define DSS_REPLEV_MASK		0x00000c
@@ -251,16 +258,34 @@
 // clear all targets (but not action targets)
 void clearDroidTargets(DROID *psDroid);
 
-static inline void setDroidOrderTarget(DROID *psDroid, void *psNewObject, SDWORD idx)
+#define setDroidOrderTarget(x,y,z,a) _setDroidOrderTarget(x,y,z,a, __FILE__, __LINE__)
+#define removeDroidOrderTarget(x,y) _removeDroidOrderTarget(x,y, __FILE__, __LINE__)
+
+static inline void _setDroidOrderTarget(DROID *psDroid, void *psNewObject, SDWORD idx, ORDER_TARGET_TYPE type, char *file, int line)
 {
-	assert(idx >= 0 && idx < ORDER_LIST_MAX);
-	psDroid->asOrderList[idx].psOrderTarget = psNewObject;
+	assert(idx >= 0 && idx < ORDER_LIST_MAX && type < OT_MAX_TYPES);
+	if (psNewObject != NULL)
+	{
+		psDroid->asOrderList[idx].psOrderTarget = psNewObject;
+		psDroid->asOrderList[idx].type = type;
+		if (type == OT_BASE_OBJECT)
+		{
+			incrRefCount((BASE_OBJECT*)psDroid->asOrderList[idx].psOrderTarget, file, line);
+		}		
+	}
 }
 
-static inline void removeDroidOrderTarget(DROID *psDroid, SDWORD idx)
+static inline void _removeDroidOrderTarget(DROID *psDroid, SDWORD idx, char *file, int line)
 {
 	assert(idx >= 0 && idx < ORDER_LIST_MAX);
-	psDroid->asOrderList[idx].psOrderTarget = NULL;
+	if (psDroid->asOrderList[idx].psOrderTarget != NULL)
+	{
+		if (psDroid->asOrderList[idx].type == OT_BASE_OBJECT)
+		{
+			decrRefCount((BASE_OBJECT*)psDroid->asOrderList[idx].psOrderTarget, file, line);
+		}
+		psDroid->asOrderList[idx].psOrderTarget = NULL;
+	}
 }
 
 #endif
Index: src/droid.h
===================================================================
--- src/droid.h	(revision 1637)
+++ src/droid.h	(working copy)
@@ -27,6 +27,7 @@
 #define _droid_h
 
 #include "objectdef.h"
+#include "objmem.h"
 #include "lib/gamelib/gtime.h"
 
 #define OFF_SCREEN 9999		// world->screen check - alex
@@ -386,36 +387,97 @@
 /*returns TRUE if droid type is one of the Cyborg types*/
 extern BOOL cyborgDroid(DROID *psDroid);
 
-/** helper functions for future refcount patch **/
+#define setDroidTarget(x,y,z) _setDroidTarget(x,y,z, __FILE__, __LINE__)
+#define setDroidActionTarget(x,y,z) _setDroidActionTarget(x,y,z, __FILE__, __LINE__)
+#define setDroidBase(x,y) _setDroidBase(x,y, __FILE__, __LINE__)
+#define setSaveDroidTarget(x,y,z) _setSaveDroidTarget(x,y,z, __FILE__, __LINE__)
+#define setSaveDroidActionTarget(x,y,z) _setSaveDroidActionTarget(x,y,z, __FILE__, __LINE__)
+#define setSaveDroidBase(x,y) _setSaveDroidBase(x,y, __FILE__, __LINE__)
 
-static inline void setDroidTarget(DROID *psDroid, BASE_OBJECT *psNewTarget, UWORD idx)
+static inline void _setDroidTarget(DROID *psDroid, BASE_OBJECT *psNewTarget, UWORD idx, char *file, int line)
 {
-	psDroid->psTarget[idx] = psNewTarget;
+	assert(idx < DROID_MAXWEAPS);
+	if (psDroid->psTarget[idx] != NULL)
+	{
+		decrRefCount(psDroid->psTarget[idx], file, line);
+		psDroid->psTarget[idx] = NULL;
+	}
+	if (psNewTarget != NULL)
+	{
+		psDroid->psTarget[idx] = psNewTarget;
+		incrRefCount(psNewTarget, file, line);
+	}
 }
 
-static inline void setDroidActionTarget(DROID *psDroid, BASE_OBJECT *psNewTarget, UWORD idx)
+static inline void _setDroidActionTarget(DROID *psDroid, BASE_OBJECT *psNewTarget, UWORD idx, char *file, int line)
 {
-	psDroid->psActionTarget[idx] = psNewTarget;
+	assert(idx < DROID_MAXWEAPS);
+	if (psDroid->psActionTarget[idx] != NULL)
+	{
+		decrRefCount(psDroid->psActionTarget[idx], file, line);
+		psDroid->psActionTarget[idx] = NULL;
+	}
+	if (psNewTarget != NULL)
+	{
+		psDroid->psActionTarget[idx] = psNewTarget;
+		incrRefCount(psNewTarget, file, line);
+	}
 }
 
-static inline void setDroidBase(DROID *psDroid, STRUCTURE *psNewBase)
+static inline void _setDroidBase(DROID *psDroid, STRUCTURE *psNewBase, char *file, int line)
 {
-	psDroid->psBaseStruct = psNewBase;
+	if (psDroid->psBaseStruct != NULL)
+	{
+		decrRefCount(psDroid->psBaseStruct, file, line);
+		psDroid->psBaseStruct = NULL;
+	}
+	if (psNewBase != NULL)
+	{
+		psDroid->psBaseStruct = psNewBase;
+		incrRefCount(psNewBase, file, line);
+	}
 }
 
-static inline void setSaveDroidTarget(DROID *psSaveDroid, BASE_OBJECT *psNewTarget, UWORD idx)
+//save equivalent of setDroid* functions
+static inline void _setSaveDroidTarget(DROID *psSaveDroid, BASE_OBJECT *psNewTarget, UWORD idx, char *file, int line)
 {
-	psSaveDroid->psTarget[idx] = psNewTarget;
+	assert(idx < DROID_MAXWEAPS);
+	if (psNewTarget != NULL)
+	{
+		psSaveDroid->psTarget[idx] = psNewTarget;
+		incrRefCount(psNewTarget, file, line);
+	}
+	else
+	{
+		psSaveDroid->psTarget[idx] = NULL;
+	}
 }
 
-static inline void setSaveDroidActionTarget(DROID *psSaveDroid, BASE_OBJECT *psNewTarget, UWORD idx)
+static inline void _setSaveDroidActionTarget(DROID *psSaveDroid, BASE_OBJECT *psNewTarget, UWORD idx, char *file, int line)
 {
-	psSaveDroid->psActionTarget[idx] = psNewTarget;
+	assert(idx < DROID_MAXWEAPS);
+	if (psNewTarget != NULL)
+	{
+		psSaveDroid->psActionTarget[idx] = psNewTarget;
+		incrRefCount(psNewTarget, file, line);
+	}
+	else
+	{
+		psSaveDroid->psActionTarget[idx] = NULL;
+	}
 }
 
-static inline void setSaveDroidBase(DROID *psSaveDroid, STRUCTURE *psNewBase)
+static inline void _setSaveDroidBase(DROID *psSaveDroid, STRUCTURE *psNewBase, char *file, int line)
 {
-	psSaveDroid->psBaseStruct = psNewBase;
+	if (psNewBase != NULL)
+	{
+		psSaveDroid->psBaseStruct = psNewBase;
+		incrRefCount(psNewBase, file, line);
+	}
+	else
+	{
+		psSaveDroid->psBaseStruct = NULL;
+	}
 }
 
 /* assert if droid is bad */
@@ -429,19 +491,25 @@
 	assert(droid->type == OBJ_DROID); \
 \
 	assert(droid->direction <= 360.0f && droid->direction >= 0.0f); \
-	assert(droid->numWeaps < DROID_MAXWEAPS); \
+	assert(droid->numWeaps <= DROID_MAXWEAPS); \
 	assert(droid->listSize < ORDER_LIST_MAX); \
 	assert(droid->player < MAX_PLAYERS); \
 \
 	for (i = 0; i < DROID_MAXWEAPS; ++i) \
+	{ \
 		assert(droid->turretRotation[i] <= 360); \
-\
-	for (i = 0; i < DROID_MAXWEAPS; ++i) \
 		assert(droid->asWeaps[i].lastFired <= gameTime); \
-\
-	for (i = 0; i < DROID_MAXWEAPS; ++i) \
+		if (droid->psTarget[i]) \
+		{ \
+			assert(droid->psTarget[i]->refCount > 0); \
+			CHECK_OBJECT(droid->psTarget[i]); \
+		} \
 		if (droid->psActionTarget[i]) \
-			assert(droid->psActionTarget[i]->direction >= 0.0f); \
+		{ \
+			assert(droid->psActionTarget[i]->refCount > 0); \
+			CHECK_OBJECT(droid->psActionTarget[i]); \
+		} \
+	} \
 } while (0)
 
 #endif
Index: src/droiddef.h
===================================================================
--- src/droiddef.h	(revision 1637)
+++ src/droiddef.h	(working copy)
@@ -91,6 +91,7 @@
 typedef struct _order_list
 {
 	SDWORD order;
+	UBYTE type;	//type of order target object
     void *psOrderTarget; //this needs to cope with objects and stats
 	UWORD x, y, x2, y2;      //line build requires two sets of coords
 } ORDER_LIST;
_______________________________________________
Warzone-dev mailing list
[email protected]
https://mail.gna.org/listinfo/warzone-dev

Reply via email to