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:
Then right before the ShapeBase class declaration, add:
Now stick this after the rest of the ShapeBase friends:
Further down, find:
And add this after it:
Now add this somewhere after the ShapeBase inline methods:
Save & close.
Then, in shapeBase.cc, put this along with the other ShapeBase ConsoleMethods:
Save & close.
Now, in shapeBaseImage.cc, add this to the end of the file:
That's all of it.
Save, close, & compile.
To set the image state manualy in script, use this:
%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.
This has also been submitted as a TDN article, it can be found here.
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.
About the author
#2
11/16/2005 (8:21 am)
It allows you to set an image state manualy, in script. For instance, you have a weapon(gun) with a reload state that is not called from the normal FSM(only triggered by script). The state maybe has an animation and a timer so when you call it, the animation plays and the "Ready" state won't be loaded untill the timer is up.
#4
11/22/2005 (9:58 pm)
It's very useful if you want to deal with things like clips or alternate fire IMO.
#5
11/26/2005 (7:47 pm)
Great resource Josh. Just got in reloading into my project and this will solve the problem I just found. :)
#6
01/25/2006 (5:36 am)
This is precisely what I needed for my game. Thanks for the great resource Josh, very easy to implement and use.
#7
What create a animation reload with this resource?
Help step by step plese....
And i create reload animation on my player or only my weapon?
Help THANKS =D
04/05/2006 (7:15 am)
Hi....I'm a stupid sorry....But i don't understand a uso to this resource...What create a animation reload with this resource?
Help step by step plese....
%shape.manualSetImageState(%slot, %imageState);This code put in?
And i create reload animation on my player or only my weapon?
Help THANKS =D
#8
05/02/2006 (10:16 pm)
If you're having trouble with this resource before 5-2-06, remove the changes and re-add the newer version.
#10
05/03/2006 (4:01 am)
Problem, compile errors, in ShapeImage.cc regarding the last huge code piece.c:\Torque\TGE\tseSDK\engine\game\shapeImage.cpp(2054): error C2039: 'writeCussedU32' : is not a member of 'BitStream' c:\Torque\TGE\tseSDK\engine\game\shapeImage.cpp(2072): error C2039: 'redCussedU32' : is not a member of 'BitStream'
#11
05/03/2006 (7:05 pm)
And I don't see "writeCussedU32" or "readCussedU32" anywhere else in the code besides the one last block. Maybe you left something out? From a non-programmer perspective it seems you need information in bitStream.h along with the other read/write types.
#12
C2: Those methods seem to be new to 1.4, and are actualy heavier on the network than the normal write/read RangedU32. I've changed the resource to use those instead.
05/03/2006 (9:01 pm)
Cimo: I switched the ConsoleMethod to 'setManualImageState' when I updated this because of some people in the forums complaining about my naming choices.C2: Those methods seem to be new to 1.4, and are actualy heavier on the network than the normal write/read RangedU32. I've changed the resource to use those instead.
#13
05/04/2006 (6:20 am)
Ah, yes, I'm on a late Milestone 2 version of TSE. Only MS3+ is based on TGE 1.4. Thanks for the change though, will compile later and test.
#14
I merged to TSE MS3 (1.4 based), and it compiled fine until I got an error about not being able to access a protected member of the class ShapeBase. Moved one line up into the public section:
..and it compiled. Tested and it works excellently with no problems, save one.
If you're reloading under a manual state and you hit the fire button, it says forget the manual state and lets you fire your weapon. Didn't do this before you fixed it.
05/04/2006 (2:27 pm)
c:\Torque\ms3\engine\game\shapeImage.cpp(2067): error C2248: 'ShapeBase::setImageState' : cannot access protected member declared in class 'ShapeBase'
I merged to TSE MS3 (1.4 based), and it compiled fine until I got an error about not being able to access a protected member of the class ShapeBase. Moved one line up into the public section:
void setImageState(U32 imageSlot, U32 state, bool force = false);
..and it compiled. Tested and it works excellently with no problems, save one.
If you're reloading under a manual state and you hit the fire button, it says forget the manual state and lets you fire your weapon. Didn't do this before you fixed it.
#15
The reason it's letting you fire is probably because in this new version, the image state on is only getting set on the client! I'm really glad you noticed that as it would of been a bug in my codebase for a long time. Big thanks for reporting this, I updated the resource with the fix. The changes were made to ShapeBase::setManualImageState(also added a server object check).
Edit: I'm very sorry to anybody that has used this resource in the past. It should actualy function how it's supposed to now, but if you have any problems or find a bug, please post here so I'll know.
And thanks again for finding all those little things I missed, Chris.
05/05/2006 (4:20 am)
C2: You need to add the ManualImageSetEvent class as a ShapeBase friend for this to work out of the box. You probably just missed that part of the tutorial or something.The reason it's letting you fire is probably because in this new version, the image state on is only getting set on the client! I'm really glad you noticed that as it would of been a bug in my codebase for a long time. Big thanks for reporting this, I updated the resource with the fix. The changes were made to ShapeBase::setManualImageState(also added a server object check).
Edit: I'm very sorry to anybody that has used this resource in the past. It should actualy function how it's supposed to now, but if you have any problems or find a bug, please post here so I'll know.
And thanks again for finding all those little things I missed, Chris.
#16
05/05/2006 (5:54 am)
Alright, will add in your changes and try later. I did add it as a friend along with the Vehicle and other friends in the shapeBase.h file, but as long as moving that one line up makes it work, no worries. Thanks again. :)
#17
05/05/2006 (6:28 am)
Well I guess having it work is the important thing, but adding it as a friend class should give the image change event class access to private/protected members and functions. Not sure why it wouldn't work. :/
#18
05/05/2006 (1:05 pm)
Tested, functions flawlessly.
#19
05/19/2006 (9:04 pm)
You're missing a bracket at the end of the unpack function in the code snippet >.>
#20
06/02/2006 (12:37 am)
Nevermind, I am rambling. 
Torque Owner Dreamer
Default Studio Name
Don't get me wrong it looks like a really, really nice mod, but I just can't see what it accomplishes, or how more succinctly what can be done with it.
Do you happen to have an example implemenation or scenario?