send command to visible players
by Fyodor -bank- Osokin · 04/03/2007 (11:24 am) · 2 comments
-------------------- Intro --------------------
If you want to modify the chat, so only players who in visible range will get the messages what do you do?
Of course you can go similar to this (starter.fps/common/server/commands.cs):
1. it's scripted, and if you have lots of clients it can hit on performance.
2. if the target player is in interior and not visible but is in range - he will get the message
-------------------- The "code" --------------------
My proposal is to use benefits of C++ (speed). So, here what I have done:
in file engine/game/gameConnection.h, and after
in file engine/game/net/net.cc, BEFORE
at the end of the same file paste the following:
I've also put there how you can get the distance from the current SKY object if needed.
The example usage is simple:
You can perform any commands like this.
For example if you do something that only players in range should see/hear/whatever, just execute:
Have fun and good luck with Torquing!
If you want to modify the chat, so only players who in visible range will get the messages what do you do?
Of course you can go similar to this (starter.fps/common/server/commands.cs):
function chatMessageAll( %sender, %msgString, %a1, %a2, %a3, %a4, %a5, %a6, %a7, %a8, %a9, %a10 )
{
if ( ( %msgString $= "" ) || spamAlert( %sender ) || !isObject( %sender.getControlObject() ) )
return;
[b]%senderPosition = %sender.getControlObject().getPosition();[/b]
%count = ClientGroup.getCount();
for ( %i = 0; %i < %count; %i++ )
{
%obj = ClientGroup.getObject( %i );
[b]if ( !isObject(%obj.getControlObjecT()) ) continue;
%targetPosition = %obj.getControlObjecT().getPosition();
%distance = VectorDist(%senderPosition, %targetPosition);
if (%distance > $chatDistance) continue;[/b]
if(%sender.team != 0)
chatMessageClient( %obj, %sender, %sender.voiceTag, %sender.voicePitch, %msgString, %a1, %a2, %a3, %a4, %a5, %a6, %a7, %a8, %a9, %a10 );
else
{
// message sender is an observer -- only send message to other observers
if(%obj.team == %sender.team)
chatMessageClient( %obj, %sender, %sender.voiceTag, %sender.voicePitch, %msgString, %a1, %a2, %a3, %a4, %a5, %a6, %a7, %a8, %a9, %a10 );
}
}
}But code lacks on:1. it's scripted, and if you have lots of clients it can hit on performance.
2. if the target player is in interior and not visible but is in range - he will get the message
-------------------- The "code" --------------------
My proposal is to use benefits of C++ (speed). So, here what I have done:
in file engine/game/gameConnection.h, and after
U32 getMissionCRC() { return(mMissionCRC); }add:// Post RemoteCommandEvent only to "visible" clients bool commandToVisibleClients(S32 argc, const char **argv, bool selfExcept = false);
in file engine/game/net/net.cc, BEFORE
ConsoleFunctionGroupEnd( Net );add:
// Script commandToVisibleClients implementation
ConsoleFunction( commandToVisibleClients, bool, 3, RemoteCommandEvent::MaxRemoteCommandArgs + 2, "(GameConnection sourceClient, tagstring func, ...)")
{
GameConnection *conn;
if(!Sim::findObject(argv[1], conn)) {
Con::errorf(ConsoleLogEntry::Script, "Remote Client Command Error - Can't find client connection. No command were issued.");
return false;
}
return conn->commandToVisibleClients(argc - 2, argv + 2);
}
ConsoleFunction( commandToVisibleClientsSE, bool, 3, RemoteCommandEvent::MaxRemoteCommandArgs + 2, "(GameConnection sourceClient, tagstring func, ...) Self-except")
{
GameConnection *conn;
if(!Sim::findObject(argv[1], conn)) {
Con::errorf(ConsoleLogEntry::Script, "Remote CClient Command Error - Can't find client connection. No command were issued.");
return false;
}
return conn->commandToVisibleClients(argc - 2, argv + 2, true);
}at the end of the same file paste the following:
//Engine commandToVisibleClients implementation
bool GameConnection::commandToVisibleClients(S32 argc, const char **argv, bool selfExcept)
{
if (!this->getControlObject())
{
Con::errorf(ConsoleLogEntry::Script, "Remote Client Command Error - Can't find controlObject of client. No command were issued.");
return false;
}
//re-implementation of sendRemoteCommand
if(U8(argv[0][0]) != StringTagPrefixByte)
{
Con::errorf(ConsoleLogEntry::Script, "Remote Client Command Error - command must be a tag.");
return false;
}
S32 i;
for(i = argc - 1; i >= 0; i--)
{
if(argv[i][0] != 0)
break;
argc = i;
}
SimGroup *g = Sim::getClientGroup();
SimGroup::iterator t;
for (t = g->begin(); t != g->end(); t++)
{
GameConnection *pClient = static_cast<GameConnection*>(*t);
// if we need to except ourselfs - next one please!
if (selfExcept && pClient == this)
continue;
// check if the source client have control object and get the position
ShapeBase *pShape = NULL;
if (! pClient->getControlObject())
continue;
VectorF v1(0,0,0), v2(0,0,0);
v1 = this->getControlObject()->getPosition();
pShape = dynamic_cast<ShapeBase*>(pClient->getControlObject());
if (!pShape)
continue;
// checking if we scoped found object
if (this->getGhostIndex(pShape) == -1)
continue;
// Checking the distance
v2 = pShape->getTransform().getPosition();
VectorF v = v2 - v1;
F32 dist = mSqrt((v.x * v.x) + (v.y * v.y) + (v.z * v.z));
// using custom variable setting
F32 visDist = Con::getFloatVariable("$Game::visibleDistance",150.0);
/*
// Using sky
F32 visDist;
Sky * sky = gServerSceneGraph->getCurrentSky();
if(sky)
visDist = sky->getVisibleDistance();
else
visDist = 150.0f;
*/
if ( dist < visDist )
{
for(i = 0; i < argc; i++)
pClient->validateSendString(argv[i]);
RemoteCommandEvent *cevt = new RemoteCommandEvent(argc, argv, pClient);
pClient->postNetEvent(cevt);
}
}
return true;
}Using this technique the command (including chat messages if you do needed changes in script) will be issued only on currently scoped client AND in needed range. You can play with - remove check for scoped existence or the range check - to suit your needs.I've also put there how you can get the distance from the current SKY object if needed.
The example usage is simple:
function chatMessageAll( %sender, %msgString, %a1, %a2, %a3, %a4, %a5, %a6, %a7, %a8, %a9, %a10 )
{
if ( ( %msgString $= "" ) || spamAlert( %sender ) )
return;
if (%sender.player) {
commandToVisibleClients(%sender, 'ChatMessage', %sender, %sender.voiceTag, %sender.voicePitch, %msgString, %a1, %a2, %a3, %a4, %a5, %a6, %a7, %a8, %a9, %a10 );
return;
}Of course you can play with it how you want.You can perform any commands like this.
For example if you do something that only players in range should see/hear/whatever, just execute:
commandToVisibleClients( %sourceClient, 'commandTag', %argument1[, %argumentN ....]);If you need to issue commands without checking the source object (from where the location is taken), you can change/add the function so it will take position as a first parameter, e.g.:
commandToVisibleClients( "x y z", 'tag', %args[, ...] );You have sources and have this example - what you will do - is up to you!
Have fun and good luck with Torquing!
About the author
Game developer.

Torque Owner Suryadiputra Liawatimena
wew, cool i'll try this tonight...
thx for the resource.