Correctly detecting when skin has changed
by Faraz Ahmed · in Torque Game Engine · 06/19/2006 (7:50 am) · 2 replies
Hi,
I'm using the ShapeBase::setSkinName("newSkin") method to apply skin changes across a bunch of aiplayers in the game. There seems to be a significant delay between the the method call and the actual appearance of the new texture on the player bodies. The ShapeBase::getSkinName() method also prematurely responds with the new skin name as if it has visibly changed for a client.
My requirement is to flash different skins across the player bodies, so I need to set a new skin only when the previously set skin has been shown successfully to the client. So far I am able to get results if I add a scheduled delay between reskinning (which is basically an unreliable hack). I've tried adding a class level variable to keep track of the *actual* skinning thats happening inside of the method TSShapeInstance::reSkin(StringHandle& newBaseHandle).
Now I'm not sure how can I can set this method up so that it can be called from the console when I use it with one of the aiPlayers in the world. So for example, I would like to be able to make a script call that looks like:
I'm struggling to understand the networked nature of TSShapeInstance objects (and skinning) so I can correctly expose this method to the console. Im also afraid that this might turn out to be a dirty infinite loop creating solution to this problem. Any guidance here would be appreciated... i know that i'm missing something fundamental here about how the engine works and why that above mentiond delay is happening!
thanks.
I'm using the ShapeBase::setSkinName("newSkin") method to apply skin changes across a bunch of aiplayers in the game. There seems to be a significant delay between the the method call and the actual appearance of the new texture on the player bodies. The ShapeBase::getSkinName() method also prematurely responds with the new skin name as if it has visibly changed for a client.
inline const char* ShapeBase::getSkinName()
{
return mSkinNameHandle.getString();
}My requirement is to flash different skins across the player bodies, so I need to set a new skin only when the previously set skin has been shown successfully to the client. So far I am able to get results if I add a scheduled delay between reskinning (which is basically an unreliable hack). I've tried adding a class level variable to keep track of the *actual* skinning thats happening inside of the method TSShapeInstance::reSkin(StringHandle& newBaseHandle).
[b]const char* recentSkinName;[/b]
void TSShapeInstance::reSkin(StringHandle& newBaseHandle)
{
#define NAME_BUFFER_LENGTH 256
static char pathName[NAME_BUFFER_LENGTH];
const char* defaultBaseName = "base";
const char* newBaseName;
if (newBaseHandle.isValidString()) {
newBaseName = newBaseHandle.getString();
if (newBaseName == NULL) {
return;
}
}
else {
newBaseName = defaultBaseName;
}
[b]recentSkinName = newBaseName;[/b]
.
.
.
}
[b]
const char* TSShapeInstance::getRecentSkinName()
{
return recentSkinName;
}
[/b]Now I'm not sure how can I can set this method up so that it can be called from the console when I use it with one of the aiPlayers in the world. So for example, I would like to be able to make a script call that looks like:
[b]
while( aiPlayerObj.getRecentSkinName() !$= "red" )
{
// wait
}
// wait a little more to show the red and then ...
aiPlayerObj.setSkinName("blue");
// and so on...
[/b]I'm struggling to understand the networked nature of TSShapeInstance objects (and skinning) so I can correctly expose this method to the console. Im also afraid that this might turn out to be a dirty infinite loop creating solution to this problem. Any guidance here would be appreciated... i know that i'm missing something fundamental here about how the engine works and why that above mentiond delay is happening!
thanks.
#2
but one option would be to do the setSkinName() stuff locally on each client.
eg,
on the server:
on the clients:
locally, setSkinName() and getRecentSkinName() should be synchronized.
of course, this assumes you don't need the clients to be synced with the server as far as which skin texture is currently active.
if that's the case, then it hink you'll need something like what Manoel described.
.. actually i see that setSkinName doesn't in fact work on the client in stock TGE.
i've modified my version to look like this:
06/19/2006 (9:28 am)
Folks will probably jump on me for saying this,but one option would be to do the setSkinName() stuff locally on each client.
eg,
on the server:
for all clients: commandToClient(%client, 'flashThoseSkins', %theAIPlayer)
on the clients:
ClientCommandFlashThoseSkins(%theAIPlayer)
{
// start a sequence of local setSkinName()'s on the AIPlayer.
}locally, setSkinName() and getRecentSkinName() should be synchronized.
of course, this assumes you don't need the clients to be synced with the server as far as which skin texture is currently active.
if that's the case, then it hink you'll need something like what Manoel described.
.. actually i see that setSkinName doesn't in fact work on the client in stock TGE.
i've modified my version to look like this:
void ShapeBase::setSkinName(const char* name)
{
StringHandle skinNameHandle;
if (isGhost() && mShapeInstance) {
StringHandle sh = StringHandle(name);
mShapeInstance->reSkin(sh);
return;
}
// rest of method...
}
Associate Manoel Neto
Default Studio Name
You could use a series of commandToClient() and commandToServer() checks to verify each skin change. Try calling a command on the client(s) for every skin change, then send a command back to the server comfirming it, and do some console spamming to see if there is any delay there.
Also, there could be a delay involved in actually loading the texture, depending on how large it is. Does the game freeze before the new skins show up? If so, there is a way to prevent time from passing while the game is "frozen": set $timeAdvance to a non-zero value.
When $timeAdvance is zero, the game runs at framerate-independant rate, and calculates the amount of time passed between each frame dynamically. So if your game freezes for a whole second, the whole simulation (and this includes schedules) will jump a whole second forward when it unfreezes.
When you set $timeAdvance to any other value, the game uses it's value to increment the timer at every frame. So if you set $timeAdvance to 32, every frame will advance the simulation by 32 milliseconds. If the game freezes for a whole minute, only 32 milliseconds will be advanced when it unfreezes.
This is very usefull when you are doing something with can potentially cause a freeze, like loading a large texture into memory, or creating lots of objects at once.