Jump to content

FIXED: Proximity Mine Cannot Assign mOwner


Steve_Yorkshire

Recommended Posts

FIXED: SEE BELOW


Whilst looking through the stock code, I noticed that ProximityMine.cpp/h checks for mOwner and triggerOnOwner(bool) to set whether you want it to explode on the original owner of the mine or not ---- except mOwner can never be set.

 

// Detect movement in the trigger area
               if ( ( sql.mList == mOwner && !mDataBlock->triggerOnOwner ) ||
                    sql.mList->getVelocity().len() < mDataBlock->triggerSpeed )
                  continue;

mOwner and triggerOnOwner called when it decides if it should explode (line ~444) but as mOwner is always null it always explodes. Note: when in scripts/server/proximityMine.cs onThrow functionthe object has a "sourceObject" defined like projectiles, but unlike projectiles there is nothing to refer to this in C++.


So, thoughts on best fix?

1: Add a setOwner engineDefine and do it manually from script (feels a bit of a faff)

2: Add the script definition of sourceObject into C++ to be the mOwner variable, like projectile.cpp does and pack/unpack it.

eg: inside initPersistFields and change mSourceObjectId to mOwner:

addGroup("Source");
 
   addField("sourceObject",     TypeS32,     Offset(mSourceObjectId, Projectile),
      "@brief ID number of the object that fired the projectile.\n\n"
      "@note If the projectile was fired by a WeaponImage, sourceObject will be "
      "the object that owns the WeaponImage. This is usually the player.");


I expect #2 is the better option but thought I'd ask for opinions.


//edit 24 Jan 2016

Fixed this. Also killed 2 birds with 1 stone by making "sourceObject" in the ProximityMineData::onThrow function in scripts/server/proximityMine.cs used for setting and checking the mine's owner. If someone else triggers the mine, the owner can still be damaged if they are close to the blast.


The only downside which I have found is that the player collides with the mine as it has no "step" function for it's collision. Owner has to jump on/over the mine to move through it.


Stock code from scripts/server/proximityMine.cs, sourceObject now referenced in C++

function ProximityMineData::onThrow( %this, %user, %amount )
{
   // Remove the object from the inventory
   %user.decInventory( %this, 1 );
 
   // Construct the actual object in the world, and add it to
   // the mission group so its cleaned up when the mission is
   // done.  The object is given a random z rotation.
   %obj = new ProximityMine()
   {
      datablock = %this;
      sourceObject = %user;
      rotation = "0 0 1 "@ (getRandom() * 360);
      static = false;
      client = %user.client;
   };
   MissionCleanup.add(%obj);
   return %obj;
}


===============================================================================


TorqueScript Changes:


art/datablocks/weapons/proxMine.cs

 

//...
 
datablock ProximityMineData( ProxMine )
{
   //...
 
   autoTriggerDelay = 0;
   triggerOnOwner = false;//stock = true; WHETHER THE OWNER TRIGGERS THE MINE
   triggerRadius = 3.0;
   //...


-----------------------------------------------

C++ Changes:


source/T3D/proximityMine.h


We get rid of "mOwner" and replace it with sourceObjectId and a pointer to the ghost, just like in projectile.cpp.

 

class ProximityMine: public Item
{
   typedef Item Parent;
 
protected:
//...
 
   TSThread*            mAnimThread;
   //SceneObject*         mOwner;//<----- yorks out, use sourceObjectId now
 
   State                mState;
//...
   void renderObject( ObjectRenderInst* ri, SceneRenderState* state, BaseMatInstance* overrideMat );
 
   //<-------- yorks in start
   S32      mSourceObjectId;
   SimObjectPtr mSourceObject; ///< Actual pointer to the source object, times out after SourceIdTimeoutTicks
   //<-------- yorks in end
 
public:
   DECLARE_CONOBJECT( ProximityMine );
//...
   bool onAdd();
   void onRemove();
   bool onNewDataBlock( GameBaseData* dptr, bool reload );
   static void initPersistFields();//<---------- yorks new in to get sourceObject set from script
 
   virtual void setTransform( const MatrixF& mat );
//...
   void unpackUpdate( NetConnection* conn, BitStream* stream );
 
   S32 getOwnerID() { return mSourceObjectId; }//<------- yorks new in
};
 
#endif // _PROXIMITYMINE_H_


source/T3D/proximityMine.cpp

 

//...
 
ProximityMine::ProximityMine()
{
   mTypeMask |= StaticShapeObjectType;
//...
 
   // For the Item class
   mSubclassItemHandlesScene = true;
 
   mSourceObjectId = -1;//<---------- yorks in
}
 
ProximityMine::~ProximityMine()
{
}
 
//<------ yorks in start
void ProximityMine::initPersistFields()
{
 
	addGroup("Source");
 
	addField("sourceObject", TypeS32, Offset(mSourceObjectId, ProximityMine),
		"@brief ID number of the object that fired the mine.\n\n"
		"@note This is usually the player.");
 
	endGroup("Source");
 
	Parent::initPersistFields();
}
//<------- yorks in end
 
//...
 
bool ProximityMine::onAdd()
{
   if ( !Parent::onAdd() || !mDataBlock )
      return false;
 
   addToScene();
 
   //<----- yorks out start
   //if (isServerObject())
      //scriptOnAdd();
   //<----- yorks out end
 
   //<-------- yorks in start
   if (isServerObject())
   {
	   ShapeBase* ptr;
	   if (Sim::findObject(mSourceObjectId, ptr))
	   {
		   mSourceObject = ptr;
 
		   // Since we later do processAfter( mSourceObject ) we must clearProcessAfter
		   // if it is deleted. SceneObject already handles this in onDeleteNotify so
		   // all we need to do is register for the notification.
		   deleteNotify(ptr);
	   }
	   else
	   {
		   if (mSourceObjectId != -1)
			   Con::errorf(ConsoleLogEntry::General, "ProximityMine::onAdd: mSourceObjectId is invalid");
		   mSourceObject = NULL;
	   }
   }
   else
   {
	   if (mSourceObject.isValid())
		   processAfter(mSourceObject);
   }
   //<------ yorks in end
 
   if ( mStatic )
   {
      // static mines are armed immediately
      mState = Deployed;
      mStateTimeout = 0;
   }
 
   return true;
}
 
//...
 
void ProximityMine::processTick( const Move* move )
{
   //...
               SimpleQueryList::insertionCallback, &sql );
            for ( S32 i = 0; i < sql.mList.size(); i++ )
            {
		//<---- yorks out start - not using mOwner now
		/*
               // Detect movement in the trigger area
               if ( ( sql.mList == mOwner && !mDataBlock->triggerOnOwner ) ||
                    sql.mList->getVelocity().len() < mDataBlock->triggerSpeed )
                  continue;
			 */
		//<---- yorks out end - not using mOwner now
		//<---- yorks in start - now using mSourceObject, and check it's valid
				if ((mSourceObject.isValid() && sql.mList == mSourceObject && !mDataBlock->triggerOnOwner) ||
					sql.mList->getVelocity().len() < mDataBlock->triggerSpeed)
					continue;
		//<---- yorks in end - now using mSourceObject, and check it's valid
 
               // Mine has been triggered
               mShapeInstance->destroyThread( mAnimThread );
               mAnimThread = NULL;
//...
 
U32 ProximityMine::packUpdate( NetConnection* connection, U32 mask, BitStream* stream )
{
//...
 
   stream->writeFlag( ( mask & ExplosionMask ) && ( mState == Exploded ) );
 
   //yorks in start
   if (mSourceObject.isValid())
   {
	   // Potentially have to write this to the client, let's make sure it has a
	   //  ghost on the other side... 
	   //yorks this is from projectile so not sure if this is true for proximityMine
	   S32 ghostIndex = connection->getGhostIndex(mSourceObject);
	   if (stream->writeFlag(ghostIndex != -1))
	   {
		   stream->writeRangedU32(U32(ghostIndex),
			   0,
			   NetConnection::MaxGhostCount);
	   }
	   else
		   // have not recieved the ghost for the source object yet, try again later
		   retMask |= GameBase::InitialUpdateMask;
   }
   else
	   stream->writeFlag(false);
   //yorks in end
 
   return retMask;
}
 
void ProximityMine::unpackUpdate( NetConnection* connection, BitStream* stream )
{
//...
 
   if ( mStatic && mState <= Deployed )
   {
      // static mines are armed immediately
      mState = Deployed;
      mStateTimeout = 0;
   }
 
   //<------------ yorks in start
	if (stream->readFlag())
   {
	   mSourceObjectId = stream->readRangedU32(0, NetConnection::MaxGhostCount);
 
	   NetObject* pObject = connection->resolveGhost(mSourceObjectId);
	   if (pObject != NULL)
		   mSourceObject = dynamic_cast(pObject);
	}
	else
	{
	   mSourceObjectId = -1;
	   mSourceObject = NULL;
	}
   //<------- yorks in end
}
 
//...
 
//right at the bottom add a TS function for debug testing the mine's sourceObject
 
DefineEngineMethod(ProximityMine, getOwner, S32, (), ,
	"@brief Get the owner of the proximity mine.\n\n"
	"@returns mSourceObjectId.")
{
	return object->getOwnerID();
}


And here's the source for download:

http://yorkshirerifles.com/downloads/proxMine_yorks.zip


As always, feedback and improvements welcome.

proxMine_yorks.zip

C++

Edited by Steve_Yorkshire
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...