Game Development Community

dev|Pro Game Development Curriculum

Setting an ImageState manualy

by Josh Moore · 11/15/2005 (2:53 pm) · 28 comments

NOTE: If you've used this resource before 5-5-06, remove it and add this updated version!

This snippet will show you how to modify the ShapeBaseImage system to allow the manual setting of an ImageState. It works over a networked connection, unlike some other resources I've seen. Many people have wanted this functionality, so finaly, here it is!

Make sure to back up your files before using this resource!


We begin in shapeBase.h, after all of the includes, put:

#ifndef _NETCONNECTION_H_
#include "sim/netConnection.h"
#endif

Then right before the ShapeBase class declaration, add:

class ManualImageSetEvent;

Now stick this after the rest of the ShapeBase friends:
friend class ManualImageSetEvent;

Further down, find:
void getMuzzlePoint(U32 imageSlot,Point3F* pos);

And add this after it:
bool setManualImageState(U32 imageSlot, const char* state);

Now add this somewhere after the ShapeBase inline methods:
//------------------------------------------------------------------------------
// Manual shapeBaseImage state change NetEvent
//------------------------------------------------------------------------------

class ManualImageSetEvent : public NetEvent
{
	typedef NetEvent Parent;

	void pack(NetConnection*, BitStream*);
	void write(NetConnection*, BitStream*){}
	void unpack(NetConnection*, BitStream*);
	void process(NetConnection*);

public:
	ManualImageSetEvent() {
		mBadPacket = false;
		mShapeBase = NULL;
		mImageSlot = -1;
		mState = -1;
	};
	~ManualImageSetEvent() {};

	bool mBadPacket;
	SimObjectPtr<ShapeBase> mShapeBase;
	U32 mImageSlot;
	S32 mState;

	DECLARE_CONOBJECT(ManualImageSetEvent);
};

Save & close.

Then, in shapeBase.cc, put this along with the other ShapeBase ConsoleMethods:
ConsoleMethod( ShapeBase, setManualImageState, void, 4, 4, "(int slot, string state)")
{
	int imageSlot = dAtoi(argv[2]);
	const char* state = argv[3];
	if (imageSlot >= 0 && imageSlot < ShapeBase::MaxMountedImages)
		object->setManualImageState(imageSlot, state); 
}

Save & close.

Now, in shapeBaseImage.cc, add this to the end of the file:
bool ShapeBase::setManualImageState(U32 imageSlot, const char* state)
{
	if(!isServerObject()) return false;

	MountedImage& image = mMountedImageList[imageSlot];
	S32 stateNum = image.dataBlock->lookupState(state);
	if (image.dataBlock && stateNum > 0) {

		// Set the server-side image state
		setImageState(imageSlot, stateNum, true);

		// Send the state change over the network
		SimGroup* pClientGroup = Sim::getClientGroup();
		for (SimGroup::iterator itr = pClientGroup->begin(); itr != pClientGroup->end(); itr++) {
			NetConnection* nc = static_cast<NetConnection*>(*itr);
			if(nc->getGhostIndex(this) == -1)
				continue;

			ManualImageSetEvent* imgEvnt = new ManualImageSetEvent;

			imgEvnt->mShapeBase = this;
			imgEvnt->mImageSlot = imageSlot;
			imgEvnt->mState = stateNum;

			nc->postNetEvent(imgEvnt);
		}
		return true;
	}
	return false;
}

//------------------------------------------------------------------------------
// Manual shapeBaseImage state change NetEvent
//------------------------------------------------------------------------------
IMPLEMENT_CO_CLIENTEVENT_V1(ManualImageSetEvent);

void ManualImageSetEvent::pack(NetConnection* conn, BitStream* stream)
{
	if(stream->writeFlag(mShapeBase.isNull() || mImageSlot < 0 || mState < 0))
		return;

	S32 shapeId = conn->getGhostIndex(mShapeBase);
	if(stream->writeFlag(shapeId != -1))
		stream->writeInt(shapeId, NetConnection::GhostIdBitSize);

	stream->writeRangedU32(mImageSlot, 0, ShapeBase::MaxMountedImages);
	stream->writeInt(mState, 5);
}

void ManualImageSetEvent::unpack(NetConnection* conn, BitStream* stream)
{
	if(mBadPacket = stream->readFlag())
		return;

	if(stream->readFlag()) {
		S32 shapeId = stream->readInt(NetConnection::GhostIdBitSize);
		mShapeBase = dynamic_cast<ShapeBase*>(conn->resolveGhost(shapeId));
	}
	else {
		mShapeBase = NULL;
		mBadPacket = true;
	}

	mImageSlot = stream->readRangedU32(0, ShapeBase::MaxMountedImages);
	mState = stream->readInt(5);


void ManualImageSetEvent::process(NetConnection* conn)
{
	if(mBadPacket)
		return;
	mShapeBase->setImageState(mImageSlot, mState, true);
}

That's all of it.

Save, close, & compile.

To set the image state manualy in script, use this:
%shape.setManualImageState(%slot, %imageState);
When:
%shape = the ShapeBase that's holding the weapon you want to change States on
%slot = the image slot that you want to be changing States on
%imageState = the name of the image state you want to switch to

If you're using this for weapon reloading, here's an example state for you.
The trick here is not having this state be activated by any others.
stateName[7]                     = "ReloadClip"; // State name to use in setManualImageState
   stateTimeoutValue[7]             = 1.4; // State time
   stateTransitionOnTimeout[7]      = "Ready"; // Reset back to the ready state and normal weapon operation
   stateSequence[7]                 = "WeaponReload"; // Animation to play on the Image
   stateAllowImageChange[7]         = false; // Do not allow image change while reload animation is playing

This has also been submitted as a TDN article, it can be found here.
Page«First 1 2 Next»
#21
09/21/2006 (2:02 pm)
I know it's been a while and this is a completely useless post, but it finally hit me as I am putting this into MS4 now, why it didn't compile a long while back when I "added" that line as a friend to ShapeBase. I didn't, I added it to "ShapeBaseConvex". :) Silly me.
#22
10/02/2006 (11:57 am)
This works great! Thanks!

Just tried it on 1.5 ... went straight in.
#23
06/04/2007 (2:02 pm)
Very nice! Thank you
#24
09/11/2007 (5:52 pm)
Hello. I had some troubles using this resource in my project (see here for details).
I uploaded a patch to apply on a clean 1.4.2 TGE install on my website here, and I left this resource's code commented out.
Can you give me some hints on what I done wrong? Thanks in advance for anything.

Bye, Berserk.
.
#25
02/20/2008 (10:52 am)
I get this installed into my code, but every time I run it IN the game I get an error that says unknown command setManualImageState player-> ShabeBase -> GameBase -> SceneObject -> NetObject -> SimObject.

What we have done is this:
function serverCmdReloadWeapon(%client)
{
   %shape = %client.player;
   %slot = %shape.getMountSlot($WeaponSlot);
   %imageState = "myReload";
   echo("Shape:", %shape);
   echo("Slot:", %slot);
   echo("State:", %imageState);
   %shape.setManualImageState(%slot, "myReload");
}

%shape is the object (aka player character), the slot is the weapon slot (usually -1) and the %imageState is my reload sequence call (just look at crossbow.cs for the reload state, its the same). Does anyone have this error and/or know how to fix it? We are using 1.5.1 and 1.5.2 for the engine. Same issue in both
#26
03/02/2008 (4:19 pm)
Im also with exactly the same problem, as Austin Whitlatch .. TGEA 102. not compilation errors.

-> I've solved it, i've not setted good the code in shapebase.cpp, i've pasted it with the "shapebasedata" methods.
#27
04/22/2008 (9:39 pm)
Has anyone gotten this resource to work on TGEA 1.7.0? I am having some difficulties.
#28
08/19/2009 (9:27 am)
Nice resource but it is impossible to set the state (sometimes),because of network problems.
For example try to set it onAdd() and you will see what i am talking about...
It only works when it is set in console,or eventually further in time.
I believe it should be fixed,so far there is no real functionality.
Tested on TGEA 1.7.1
Page«First 1 2 Next»