T3D 1.1 Beta 3 - Player doesn't reset from set action thread when unmounting - RESOLVED
by David Wyand · in Torque 3D Professional · 01/14/2011 (6:57 pm) · 9 replies
Build: 1.1 Beta 3 Pro
Platform: Windows XP, Vista, 7
Target: Client game connected to a stand alone game server
Issues: When the Player has been given an action thread when mounted, unmounting the Player does not reset the action animation to the standard, such as 'root'. For example, have the Player switch to a 'sit' action thread when mounted to a chair. Then when the Player unmounts, they will still be in a sitting sequence until the Player does something to change this, such as moving forwards.
Steps to Repeat:
1. In your Player datablock's onMount() script callback, have the player switch their action thread's animation sequences, such as with:
2. Provide some shape for the Player to mount in the mission.
3. Start up a game Client and connected to a game Server. Note: This bug does not show up in single player.
4. In game, have the Player mount the shape (often by colliding with the shape).
5. Dismount the Player from the shape (often by press SPACE).
6. Player will remain in the same animation sequence as if they were mounted. Performing some other action, such as moving forwards, will force the Player to the correct sequence.
Suggested Fix: The problem is that the server resets the action thread in Player::onUnmount() to PlayerData::RootAnim, but due to how the Player's packUpdate() determines when to send the action thread change, it never reaches the client. The server is correct and the client is out of sync.
... Fix continued below due to forum text size limits...
Platform: Windows XP, Vista, 7
Target: Client game connected to a stand alone game server
Issues: When the Player has been given an action thread when mounted, unmounting the Player does not reset the action animation to the standard, such as 'root'. For example, have the Player switch to a 'sit' action thread when mounted to a chair. Then when the Player unmounts, they will still be in a sitting sequence until the Player does something to change this, such as moving forwards.
Steps to Repeat:
1. In your Player datablock's onMount() script callback, have the player switch their action thread's animation sequences, such as with:
%obj.setActionThread("sitting", true, true);2. Provide some shape for the Player to mount in the mission.
3. Start up a game Client and connected to a game Server. Note: This bug does not show up in single player.
4. In game, have the Player mount the shape (often by colliding with the shape).
5. Dismount the Player from the shape (often by press SPACE).
6. Player will remain in the same animation sequence as if they were mounted. Performing some other action, such as moving forwards, will force the Player to the correct sequence.
Suggested Fix: The problem is that the server resets the action thread in Player::onUnmount() to PlayerData::RootAnim, but due to how the Player's packUpdate() determines when to send the action thread change, it never reaches the client. The server is correct and the client is out of sync.
... Fix continued below due to forum text size limits...
About the author
A long time Associate of the GarageGames' community and author of the Torque 3D Game Development Cookbook. Buy it today from Packt Publishing!
#2
Another one decision is:
1. to set the ActionMask in onUnmount()
2. to change how packUpdate() works when the player is unmounted,may be setting a flag on the server.
01/14/2011 (7:29 pm)
This is a good fix,Dave.Another one decision is:
1. to set the ActionMask in onUnmount()
2. to change how packUpdate() works when the player is unmounted,may be setting a flag on the server.
#3
I originally started down the path of modifying Player::packUpdate(), but it started to get complicated. IIRC you would have to work around the mActionAnimation.action >= PlayerData::NumTableActionAnims check without affecting how the Player animates in general. I went down a number of rabbit holes on this one.
So I ended up going with this much simpler fix. I've had it in place for months now in my Zworldo.com Greenwood Faire game where the bug caused issues with my stools and chairs. So far I've not had any issues with it.
If you or someone else comes up with a more elegant solution, I'd be willing to try it out. :)
- Dave
01/14/2011 (10:25 pm)
Hey Ivan,I originally started down the path of modifying Player::packUpdate(), but it started to get complicated. IIRC you would have to work around the mActionAnimation.action >= PlayerData::NumTableActionAnims check without affecting how the Player animates in general. I went down a number of rabbit holes on this one.
So I ended up going with this much simpler fix. I've had it in place for months now in my Zworldo.com Greenwood Faire game where the bug caused issues with my stools and chairs. So far I've not had any issues with it.
If you or someone else comes up with a more elegant solution, I'd be willing to try it out. :)
- Dave
#4
In onUnmount() call setMaskBits(UnmountMask);
In packUpdate() use:
In unpackUpdate():
Well currently this is a different solution,but one extra mask is used.This may be not suitable if you use many masks in your game.
01/15/2011 (5:04 pm)
You could eventually use an additional mask, let's say UnmountMaskenum MaskBits {
ActionMask = Parent::NextFreeMask << 0,
MoveMask = Parent::NextFreeMask << 1,
ImpactMask = Parent::NextFreeMask << 2,
UnmountMask = Parent::NextFreeMask << 3,
NextFreeMask = Parent::NextFreeMask << 4
};In onUnmount() call setMaskBits(UnmountMask);
In packUpdate() use:
if (bstream->writeFlag(mask & UnmountMask)) { /*Do nothing*/}In unpackUpdate():
if (bstream->readFlag()) setActionThread(PlayerData::RootAnim,true,false,false);
Well currently this is a different solution,but one extra mask is used.This may be not suitable if you use many masks in your game.
#5
01/18/2011 (8:22 pm)
Logged as THREED-1344.
#7
thanks for this, I have been having this exact issue,
but
why could this be?
%obj.setActionThread("run",true,true);
is in my
function doPlayerDismount(%player, %obj, %forced)
ideas?
01/19/2011 (6:08 pm)
@David,thanks for this, I have been having this exact issue,
but
Quote:3. Start up a game Client and connected to a game Server. Note: This bug does not show up in single player.I am strictly single player...and I am getting this.
why could this be?
%obj.setActionThread("run",true,true);
is in my
function doPlayerDismount(%player, %obj, %forced)
ideas?
#8
It is possible that I'm simply having a memory failure and this bug is indeed in single player as well. But I don't recall having this issue when I was originally setting up my game and the initial testing was under single player. However, when I was first setting things up I was under 1.1 Alpha, and a lot has changed since then...
But regardless, by doPlayerDismount() do you mean the doDismount() callback that is fired against the Player's Datablock, such as from scripts/server/player.cs in the Full Template:
If so, then I don't believe a setActionThread() will do what you want so long as you reference one of the special NumTableActionAnims as defined in player.h. The server side will be set to your action sequence, but it will never be passed to the client side.
IIRC it is the logic in Player::packUpdate() that causes this to occur. The second IF statement is the culprit:
The "root" and "run" animation sequences are defined as indices 0 and 1 respectively, and are less than NumTableActionAnims. So any change to these sequences is ignored -- they are normally chosen in pickActionAnimation() I believe.
If you take a look at Player::onUnmount() it was intended that the root sequence should have always been chosen, and you don't need to actually set it manually in your doDismount() callback. But due to the packUpdate() logic above, it too wasn't making it through to the client.
When I attempted to work around this myself I tried a number of different tactics, including making changes to packUpdate(). Unfortunately, I ended up breaking the logic for the normal animation selection process.
After declaring that I had already spent too much time on the issue and just needed to get my game working, I came up with the solution I provided above. It mirrors the change on the server and already makes use of the MountedMask network mask check in SceneObject::unpackUpdate() (which calls the unmount() virtual method on the client).
But I've been posting my bugs here in the hopes that someone in the community may have a better, tested solution. Especially if there are cases where my proposed fix doesn't entirely work out. Hearing that this has solved your own issues helps out.
Thanks!
- Dave
01/19/2011 (7:41 pm)
Hey Deepscratch,It is possible that I'm simply having a memory failure and this bug is indeed in single player as well. But I don't recall having this issue when I was originally setting up my game and the initial testing was under single player. However, when I was first setting things up I was under 1.1 Alpha, and a lot has changed since then...
But regardless, by doPlayerDismount() do you mean the doDismount() callback that is fired against the Player's Datablock, such as from scripts/server/player.cs in the Full Template:
function Armor::doDismount(%this, %obj, %forced)
If so, then I don't believe a setActionThread() will do what you want so long as you reference one of the special NumTableActionAnims as defined in player.h. The server side will be set to your action sequence, but it will never be passed to the client side.
IIRC it is the logic in Player::packUpdate() that causes this to occur. The second IF statement is the culprit:
if (stream->writeFlag(mask & ActionMask &&
mActionAnimation.action != PlayerData::NullAnimation &&
mActionAnimation.action >= PlayerData::NumTableActionAnims)) {
...
}The "root" and "run" animation sequences are defined as indices 0 and 1 respectively, and are less than NumTableActionAnims. So any change to these sequences is ignored -- they are normally chosen in pickActionAnimation() I believe.
If you take a look at Player::onUnmount() it was intended that the root sequence should have always been chosen, and you don't need to actually set it manually in your doDismount() callback. But due to the packUpdate() logic above, it too wasn't making it through to the client.
When I attempted to work around this myself I tried a number of different tactics, including making changes to packUpdate(). Unfortunately, I ended up breaking the logic for the normal animation selection process.
After declaring that I had already spent too much time on the issue and just needed to get my game working, I came up with the solution I provided above. It mirrors the change on the server and already makes use of the MountedMask network mask check in SceneObject::unpackUpdate() (which calls the unmount() virtual method on the client).
But I've been posting my bugs here in the hopes that someone in the community may have a better, tested solution. Especially if there are cases where my proposed fix doesn't entirely work out. Hearing that this has solved your own issues helps out.
Thanks!
- Dave
#9
04/18/2011 (4:02 pm)
Fixed in 1.1 Final and Preview.
Associate David Wyand
Gnometech Inc.
To fix this we can just mirror on the client the same action thread change and not need to worry about getting into the network code. In player.h, make the following change by adding a new unmount() method:
/// @name Mounted objects /// @{ virtual void onUnmount( ShapeBase *obj, S32 node ); virtual void unmount(); // DAW: Added for client side /// @}Now in player.cpp, add the following method:
void Player::unmount() { // Reset back to root position during dismount. This copies what is // done on the server and corrects the fact that the RootAnim change // is not sent across to the client using the standard ActionMask. setActionThread(PlayerData::RootAnim,true,false,false); Parent::unmount(); }And that should be it!
- Dave