ProcessList - how to expose a secondary control object
by Ivan Mandzhukov · 06/18/2009 (6:25 am) · 15 comments
Tested on TGEA 1.7.1 (and T3D 1.0)
It exposes a secondary control object to act on the input.
Very wide usage - it can be used for new camera systems,controlling an additional players in the world,AIs....
gameProcess.cpp
It exposes a secondary control object to act on the input.
Very wide usage - it can be used for new camera systems,controlling an additional players in the world,AIs....
gameProcess.cpp
void ClientProcessList::clientCatchup(GameConnection * connection)
{
SimObjectPtr<GameBase> control = connection->getControlObject();
SimObjectPtr<GameBase> camera = connection->getCameraObject();
if (control)
{
Move * movePtr;
U32 numMoves;
connection->mMoveList.getMoveList(&movePtr,&numMoves);
#ifdef TORQUE_DEBUG_NET_MOVES
Con::printf("client catching up... (%i)", numMoves);
#endif
preTickSignal().trigger(); // T3D 1.0
if( control->mProcessTick )
for (U32 m=0; m<numMoves && control; m++)
{ control->processTick(movePtr++);}
}
else if (camera && (camera != control))
{
Move * movePtr;
U32 numMoves;
connection->mMoveList.getMoveList(&movePtr,&numMoves);
preTickSignal().trigger(); // T3D 1.0
if( camera->mProcessTick )
for (U32 m=0; m<numMoves && camera; m++){
camera->processTick(movePtr++);
connection->mMoveList.clearMoves(m);
}
}
#ifdef TORQUE_DEBUG_NET_MOVES
Con::printf("---------");
#endif
}void ClientProcessList::onTickObject(ProcessObject * pobj)
{
SimObjectPtr<GameBase> obj = getGameBase(pobj);
// Each object is either advanced a single tick, or if it's
// being controlled by a client, ticked once for each pending move.
Move* movePtr;
U32 numMoves;
GameConnection* con = obj->getControllingClient();
if (con && con->getControlObject() == obj)
{
con->mMoveList.getMoveList(&movePtr, &numMoves);
if (numMoves)
{
// Note: this line is removed,it notifies for a new control object,so this is not a bug
//AssertFatal(numMoves==1,"ClientProccessList::onTickObject: more than one move in queue");
if( obj->mProcessTick )
obj->processTick(movePtr);
if (bool(obj) && obj->getControllingClient())
{
U32 newsum = Move::ChecksumMask & obj->getPacketDataChecksum(obj->getControllingClient());
// set checksum if not set or check against stored value if set
movePtr->checksum = newsum;
#ifdef TORQUE_DEBUG_NET_MOVES
U32 sum = Move::ChecksumMask & obj->getPacketDataChecksum(obj->getControllingClient());
Con::printf("move checksum: %i, (start %i), (move %f %f %f)",
movePtr->checksum,sum,movePtr->yaw,movePtr->y,movePtr->z);
#endif
}
con->mMoveList.clearMoves(0);
}
}
else if (con && con->getCameraObject() == obj)
{
con->mMoveList.getMoveList(&movePtr, &numMoves);
if (numMoves)
{ if( obj->mProcessTick ) obj->processTick(movePtr);
con->mMoveList.clearMoves(1);
}
}
else if (obj->mProcessTick)
obj->processTick(0);
}void ServerProcessList::onTickObject(ProcessObject * pobj)
{
SimObjectPtr<GameBase> obj = getGameBase(pobj);
GameConnection * con = obj->getControllingClient();
if (con && con->getControlObject() == obj)
{
Move* movePtr;
U32 m, numMoves;
con->mMoveList.getMoveList(&movePtr, &numMoves);
for (m=0; m<numMoves && con && con->getControlObject() == obj; m++, movePtr++)
{
obj->processTick(movePtr);
if (con && con->getControlObject() == obj)
{
U32 newsum = Move::ChecksumMask & obj->getPacketDataChecksum(obj->getControllingClient());
// check move checksum
if (movePtr->checksum != newsum)
{
#ifdef TORQUE_DEBUG_NET_MOVES
if (!obj->mIsAiControlled)
Con::printf("move %i checksum disagree: %i != %i, (start %i), (move %f %f %f)",
movePtr->id, movePtr->checksum,newsum,sum,movePtr->yaw,movePtr->y,movePtr->z);
#endif
movePtr->checksum = Move::ChecksumMismatch;
}
else
{
#ifdef TORQUE_DEBUG_NET_MOVES
Con::printf("move %i checksum agree: %i == %i, (start %i), (move %f %f %f)",
movePtr->id, movePtr->checksum,newsum,sum,movePtr->yaw,movePtr->y,movePtr->z);
#endif
}
}
}
con->mMoveList.clearMoves(m);
}
else if (con && con->getCameraObject() == obj)
{
Move* movePtr;
U32 numMoves;
con->mMoveList.getMoveList(&movePtr, &numMoves);
if( obj->mProcessTick ) obj->processTick(movePtr);
}
else if (obj->mProcessTick) obj->processTick(0);
}
#2
It can handle with everything,which uses an input.
Right now i am using it for my camera system,that reads the move data.
You can do it in your object's processTick(),even it is mounted.
Actually you do not need a new control object,because the player is already a control object.
You only need to register in MoveManager a new input for your control and use it.
There is a way to read input data using the control object and send that data to a secondary non-control object,using a casted smart pointer.This way the second object can act as a control object.
I may provide a resource for it.
06/18/2009 (7:46 am)
Yes.It can handle with everything,which uses an input.
Right now i am using it for my camera system,that reads the move data.
con->getCameraObject() == objBut this object can be every one object in the game world.
You can do it in your object's processTick(),even it is mounted.
Actually you do not need a new control object,because the player is already a control object.
You only need to register in MoveManager a new input for your control and use it.
There is a way to read input data using the control object and send that data to a secondary non-control object,using a casted smart pointer.This way the second object can act as a control object.
I may provide a resource for it.
#3
06/18/2009 (8:48 am)
so in turn this could be used to control a second player on the same client eg. metal slug?
#4
06/18/2009 (8:49 am)
That's the idea.
#5
06/18/2009 (9:17 am)
yes this is great..especially for tgb users who want to have say 2 xbox 360 controllers connected..i will definitely be using this thank you
#6
I only ask because I'm not quite sure how I would use your resource in the actual script and bindings.
This would be much appreciated as I read in the other vehicle camera resource you mentioned that there were some un-needed server/client functions being passed.
Btw: I'm using TGE 1.5.2 and I would love to see if this works!
07/08/2009 (12:34 am)
Is there any way you could explain further how to use the default keyboard controls for vehicle steering and use the mouse for a vehicle freelook function?I only ask because I'm not quite sure how I would use your resource in the actual script and bindings.
This would be much appreciated as I read in the other vehicle camera resource you mentioned that there were some un-needed server/client functions being passed.
Btw: I'm using TGE 1.5.2 and I would love to see if this works!
#7
1. register new input variables in the moveManager.
2. add a new control object to gameConnection or use the already registered camera object.
2. write their control in moveList
3. add the changes to the processList
4. set the new control object via the gameConnection
5. adjust the input control(yaw/pitch) in the processTick() of your object(camera).
now you act on the input.
you use a separate control for the vehicle and another control for the second object(the camera)
the code works beautifully (if you are enough capable to use it),i can assure you.
07/09/2009 (12:31 pm)
The rest is:1. register new input variables in the moveManager.
2. add a new control object to gameConnection or use the already registered camera object.
2. write their control in moveList
3. add the changes to the processList
4. set the new control object via the gameConnection
5. adjust the input control(yaw/pitch) in the processTick() of your object(camera).
now you act on the input.
you use a separate control for the vehicle and another control for the second object(the camera)
the code works beautifully (if you are enough capable to use it),i can assure you.
#8
07/09/2009 (1:16 pm)
Edit: Your actual resource code added to the bottom of a TGE1.5.2 gameprocess.cc file does not compile with the following errors:gameProcess.cc
..enginegamegameProcess.cc(255) : error C2653: 'ClientProcessList' : is not a class or namespace name
..enginegamegameProcess.cc(263) : error C2248: 'GameConnection::mMoveList' : cannot access protected member declared in class 'GameConnection'
../enginegame/gameConnection.h(169) : see declaration of 'GameConnection::mMoveList'
../enginegame/gameConnection.h(41) : see declaration of 'GameConnection'
..enginegamegameProcess.cc(263) : error C2039: 'getMoveList' : is not a member of 'Vector<T>'
with
[
T=Move
]
..enginegamegameProcess.cc(272) : error C2248: 'GameConnection::mMoveList' : cannot access protected member declared in class 'GameConnection'
../enginegame/gameConnection.h(169) : see declaration of 'GameConnection::mMoveList'
../enginegame/gameConnection.h(41) : see declaration of 'GameConnection'
..enginegamegameProcess.cc(272) : error C2039: 'getMoveList' : is not a member of 'Vector<T>'
with
[
T=Move
]
..enginegamegameProcess.cc(276) : error C2248: 'GameConnection::mMoveList' : cannot access protected member declared in class 'GameConnection'
../enginegame/gameConnection.h(169) : see declaration of 'GameConnection::mMoveList'
../enginegame/gameConnection.h(41) : see declaration of 'GameConnection'
..enginegamegameProcess.cc(276) : error C2039: 'clearMoves' : is not a member of 'Vector<T>'
with
[
T=Move
]
..enginegamegameProcess.cc(284) : error C2653: 'ClientProcessList' : is not a class or namespace name
..enginegamegameProcess.cc(284) : error C2065: 'ProcessObject' : undeclared identifier
..enginegamegameProcess.cc(284) : error C2065: 'pobj' : undeclared identifier
..enginegamegameProcess.cc(285) : error C2448: 'onTickObject' : function-style initializer appears to be a function definition
..enginegamegameProcess.cc(336) : error C2653: 'ServerProcessList' : is not a class or namespace name
..enginegamegameProcess.cc(336) : error C2065: 'ProcessObject' : undeclared identifier
..enginegamegameProcess.cc(336) : error C2065: 'pobj' : undeclared identifier
..enginegamegameProcess.cc(337) : error C2448: 'onTickObject' : function-style initializer appears to be a function definition
#9
07/09/2009 (1:30 pm)
So I'm guessing this is not compatible with TGE1.5.2, Oh well, would have been nice.
#10
Eventually TGE uses the old style process list,so i think you should ask Michael Bacon about it.
07/18/2009 (10:34 am)
I've never worked with TGE,i don't know what the problem is.Eventually TGE uses the old style process list,so i think you should ask Michael Bacon about it.
#11
TORQUE_DEBUG_NET_MOVES and TORQUE_DEBUG_NET console spam removed!
Tested on T3D 1.0
11/05/2009 (7:13 am)
Small updates from me on this code.TORQUE_DEBUG_NET_MOVES and TORQUE_DEBUG_NET console spam removed!
Tested on T3D 1.0
#12
I'm trying to do somethieng similar as you but I'm struggling a bit and was hoping you can point me in the right direction :). What I'm looking for is a Camera independent from player, so for instance you can use keyboard to move player around and at the same time use ..say mouse buttons to rotate/zoom camera around. So I believe I need two control objects - player and a camera. I've registered a new control variable but I don't know how to use it. I don't know how to write control in movelist, set new control object etc.... I would appreciate if you could put some light on that matter, hope thats not a problem. Thanks :)
12/02/2009 (5:42 pm)
Hi Picasso,I'm trying to do somethieng similar as you but I'm struggling a bit and was hoping you can point me in the right direction :). What I'm looking for is a Camera independent from player, so for instance you can use keyboard to move player around and at the same time use ..say mouse buttons to rotate/zoom camera around. So I believe I need two control objects - player and a camera. I've registered a new control variable but I don't know how to use it. I don't know how to write control in movelist, set new control object etc.... I would appreciate if you could put some light on that matter, hope thats not a problem. Thanks :)
#13
You can try with move->y for example.
If you see the prints in the console,then it works for you.
Then you can register your new move.
You'll need only to pack unpack the data.
You have a very little work in movelist and movemanager.
movemanager is responsible for pack/unpack the data across the network,also it will register the torquescript variables with the c++ ones.
movelist is responsible to sum the input into a desirable format(a unit force or just a key press).
processlist is the key where all the control happens.
it is responsible for the object dependencies.
processlist will call advancetime() on the client each frame, processtick() on server/client each tick.
I think this information is enough for assembling the new input.
There are two types of control objects.
The first ones come from shapebase,they are non direct control objects,they act through something.
For example the stock camera,it acts through the control object - the player.
It is not a real control object, its input is passed from the player connection at the begining of player's updatemove().
The second type are the real control objects - gameconnection ones.
In stock T3D only the player is an axample of this.
This resource will register a new real control object.
The real control objects in T3D use a special (very secure) delivery mechanism - readpacketdata/writepacketdata.
At end don't forget to test the ACK system with TORQUE_DEBUG_NET_MOVES,defined in torqueconfig.h
12/14/2009 (1:41 pm)
The camera moves process the same as the player moves.You can try with move->y for example.
void YourCamera::processTick(const Move* move) {
..
if(move && move->y) Con::printf("you pressed up");
..
}If you see the prints in the console,then it works for you.
Then you can register your new move.
You'll need only to pack unpack the data.
You have a very little work in movelist and movemanager.
movemanager is responsible for pack/unpack the data across the network,also it will register the torquescript variables with the c++ ones.
movelist is responsible to sum the input into a desirable format(a unit force or just a key press).
processlist is the key where all the control happens.
it is responsible for the object dependencies.
processlist will call advancetime() on the client each frame, processtick() on server/client each tick.
I think this information is enough for assembling the new input.
There are two types of control objects.
The first ones come from shapebase,they are non direct control objects,they act through something.
For example the stock camera,it acts through the control object - the player.
It is not a real control object, its input is passed from the player connection at the begining of player's updatemove().
The second type are the real control objects - gameconnection ones.
In stock T3D only the player is an axample of this.
This resource will register a new real control object.
The real control objects in T3D use a special (very secure) delivery mechanism - readpacketdata/writepacketdata.
At end don't forget to test the ACK system with TORQUE_DEBUG_NET_MOVES,defined in torqueconfig.h
#14
02/11/2010 (12:25 pm)
While trying to implement this resource to move a second player, I created a second movemanager and second movelist that are basically clones of the default movemanager and movelist. I already add them to the project files and rebuilt the project and got no errors. The problem is that it appears that Torque is not recognizing the new movemanager and movelist. I already tested assigning the new movemanager and new movelist to the default control object but it doesn’t move. Anyone has an idea of why the new movemanager and movelist are not working like they should?
#15
Yes,it is possible.
But I found it's useless since you can close the input into a single connection/list.
02/12/2010 (3:50 pm)
If you wish to implement a second copy of movelist/movemanager, then you have a lot of work in gameconnection.Yes,it is possible.
But I found it's useless since you can close the input into a single connection/list.
Torque Owner deepscratch
DeepScratchStudios
this looks very interesting,
do you think it could be used to control a mounted players head/eye movement if the steering is handled by the keyboard?