LAN Query Gui
by Xavier "eXoDuS" Amado · 12/03/2002 (8:26 am) · 6 comments
You might have noticed that when you are offline the query Master Server button won't work and that you aren't able to see LAN servers. You might have also noted that the connect() function no longer works, thus making it even harder to connect to a LAN server. Finally you might have noted that the query Master Server button works for LAN servers too... but only if you are online.
The purpose of this resource is to show you how to add a new button to your joinServerGui to query LAN servers and to modify the existing query code to actually work.
NOTE: I wrote this resource very quickly, so excuse me if there are many typos, or bad expressions in my English here. I just wanted to put this thing online and keep working.
Ok, let's first edit your joinServerGui. Open the file joinServerGui.gui and replace the existing "new GuiButtonCtrl(JS_queryMaster) { ... }" with the following two gui controls:
You will see that we added a new guiButtonCtrl that will call the gui's method queryLan(). Let's define this new method now, go to the end of the joinServerGui.gui file and add this function:
First open game/net/serverquery.cc and search for the queryLanServers function and replace it with this one:
Ok almost done, now open the serverQuery.h file and replace the existing declarations of the above functions with these new ones:
Good Luck and enjoy.
The purpose of this resource is to show you how to add a new button to your joinServerGui to query LAN servers and to modify the existing query code to actually work.
NOTE: I wrote this resource very quickly, so excuse me if there are many typos, or bad expressions in my English here. I just wanted to put this thing online and keep working.
Ok, let's first edit your joinServerGui. Open the file joinServerGui.gui and replace the existing "new GuiButtonCtrl(JS_queryMaster) { ... }" with the following two gui controls:
new GuiButtonCtrl(JS_queryMaster) {
profile = "GuiButtonProfile";
horizSizing = "right";
vertSizing = "bottom";
position = "164 282";
extent = "127 23";
minExtent = "8 8";
visible = "1";
command = "Canvas.getContent().query();";
helpTag = "0";
text = "Query Master";
groupNum = "-1";
buttonType = "PushButton";
};
new GuiButtonCtrl(JS_queryLan) {
profile = "GuiButtonProfile";
horizSizing = "right";
vertSizing = "bottom";
position = "164 262";
extent = "127 23";
minExtent = "8 8";
visible = "1";
command = "Canvas.getContent().queryLan();";
helpTag = "0";
text = "Query LAN";
groupNum = "-1";
buttonType = "PushButton";
};Note: This two gui Controls where made using the default joinServerGui and their positions will work correctly on it.You will see that we added a new guiButtonCtrl that will call the gui's method queryLan(). Let's define this new method now, go to the end of the joinServerGui.gui file and add this function:
function JoinServerGui::queryLan(%this)
{
queryLANServers(
28000, // lanPort for local queries
0, // Query flags
$Client::GameTypeQuery, // gameTypes
$Client::MissionTypeQuery, // missionType
0, // minPlayers
100, // maxPlayers
0, // maxBots
2, // regionMask
0, // maxPing
100, // minCPU
0 // filterFlags
);
}We will also modify the existing JoinServerGui::query (%this) with this new version of it:function JoinServerGui::query(%this)
{
queryMasterServer(
0, // Query flags
$Client::GameTypeQuery, // gameTypes
$Client::MissionTypeQuery, // missionType
0, // minPlayers
100, // maxPlayers
0, // maxBots
2, // regionMask
0, // maxPing
100, // minCPU
0 // filterFlags
);
}Now we got a gui, with two buttons which call two different methods that call two functions with some parameters on them. Since we are in the joinServerGui, I'll use this moment to fix something else on your joinServerGui. Look for the cancel function that is called by the cancel button in the gui and replace it with the following one. This will fix the bug that appeared when you cancelled a query while offline but the dialog wouldn't go away.function JoinServerGui::cancel(%this)
{
cancelServerQuery();
JS_queryStatus.setVisible(false);
}Ok, let's continue with our query code. Now we have to modify the engine code to expose queryLanServers to the script code, and we will also modify this and queryMasterServer functions to actually work. I won't go into much detail here so just replace the code, if you have trouble understanding some parts email me and I'll try to answer.First open game/net/serverquery.cc and search for the queryLanServers function and replace it with this one:
void queryLanServers(U32 port, U8 flags, const char* gameType, const char* missionType,
U8 minPlayers, U8 maxPlayers, U8 maxBots, U32 regionMask, U32 maxPing, U16 minCPU,
U8 filterFlags)
{
sgServerQueryActive = true;
clearServerList();
pushServerFavorites();
sActiveFilter.type = ServerFilter::Offline;
// Clear the filter:
if ( !sActiveFilter.gameType || dStricmp( sActiveFilter.gameType, "Any" ) != 0 )
{
sActiveFilter.gameType = (char*) dRealloc( sActiveFilter.gameType, 4 );
dStrcpy( sActiveFilter.gameType, "Any" );
}
if ( !sActiveFilter.missionType || dStricmp( sActiveFilter.missionType, "Any" ) != 0 )
{
sActiveFilter.missionType = (char*) dRealloc( sActiveFilter.missionType, 4 );
dStrcpy( sActiveFilter.missionType, "Any" );
}
sActiveFilter.queryFlags = 0;
sActiveFilter.minPlayers = minPlayers;
sActiveFilter.maxPlayers = maxPlayers;
sActiveFilter.maxBots = maxBots;
sActiveFilter.regionMask = regionMask;
sActiveFilter.maxPing = maxPing;
sActiveFilter.minCPU = minCPU;
sActiveFilter.filterFlags = filterFlags;
NetAddress addr;
char addrText[256];
dSprintf( addrText, sizeof( addrText ), "IP:BROADCAST:%d", port );
Net::stringToAddress( addrText, &addr );
pushPingBroadcast( &addr );
#if !defined(TORQUE_COMPILER_MINGW)
dSprintf( addrText, sizeof( addrText ), "IPX:BROADCAST:%d", port );
Net::stringToAddress( addrText, &addr );
pushPingBroadcast( &addr );
#endif
Con::executef( 4, "onServerQueryStatus", "start", "Querying LAN servers", "0");
processPingsAndQueries( gPingSession );
}Just after this queryLanServers function add this new consoleMethod that will enable the queryLanServers function to be called from scripts:ConsoleFunction( queryLanServers, void, 12, 12, "queryLanServers(...);" )
{
argc;
U32 lanPort = dAtoi(argv[1]);
U8 flags = dAtoi(argv[2]);
// It's not a good idea to hold onto args, recursive calls to
// console exec will trash them.
char* gameType = dStrdup(argv[3]);
char* missionType = dStrdup(argv[4]);
U8 minPlayers = dAtoi(argv[5]);
U8 maxPlayers = dAtoi(argv[6]);
U8 maxBots = dAtoi(argv[7]);
U32 regionMask = dAtoi(argv[8]);
U32 maxPing = dAtoi(argv[9]);
U16 minCPU = dAtoi(argv[10]);
U8 filterFlags = dAtoi(argv[11]);
queryLanServers(lanPort, flags, gameType, missionType, minPlayers, maxPlayers, maxBots,
regionMask, maxPing, minCPU, filterFlags);
dFree(gameType);
dFree(missionType);
}Now we are almost done, let's just replace the existing queryMasterServer function and it's consoleMethod with this new version of both:void queryMasterServer(U8 flags, const char* gameType, const char* missionType,
U8 minPlayers, U8 maxPlayers, U8 maxBots, U32 regionMask, U32 maxPing,
U16 minCPU, U8 filterFlags, U8 buddyCount, U32* buddyList )
{
// Reset the list packet flag:
gGotFirstListPacket = false;
sgServerQueryActive = true;
Con::executef( 4, "onServerQueryStatus", "start", "Querying master server", "0");
if ( buddyCount == 0 )
{
sActiveFilter.type = ServerFilter::Normal;
// Update the active filter:
if ( !sActiveFilter.gameType || dStrcmp( sActiveFilter.gameType, gameType ) != 0 )
{
sActiveFilter.gameType = (char*) dRealloc( sActiveFilter.gameType, dStrlen( gameType ) + 1 );
dStrcpy( sActiveFilter.gameType, gameType );
}
if ( !sActiveFilter.missionType || dStrcmp( sActiveFilter.missionType, missionType ) != 0 )
{
sActiveFilter.missionType = (char*) dRealloc( sActiveFilter.missionType, dStrlen( missionType ) + 1 );
dStrcpy( sActiveFilter.missionType, missionType );
}
sActiveFilter.queryFlags = flags;
sActiveFilter.minPlayers = minPlayers;
sActiveFilter.maxPlayers = maxPlayers;
sActiveFilter.maxBots = maxBots;
sActiveFilter.regionMask = regionMask;
sActiveFilter.maxPing = maxPing;
sActiveFilter.minCPU = minCPU;
sActiveFilter.filterFlags = filterFlags;
sActiveFilter.buddyCount = buddyCount;
dFree( sActiveFilter.buddyList );
sActiveFilter.buddyList = NULL;
}
else
{
sActiveFilter.type = ServerFilter::Buddy;
sActiveFilter.buddyCount = buddyCount;
sActiveFilter.buddyList = (U32*) dRealloc( sActiveFilter.buddyList, buddyCount * 4 );
dMemcpy( sActiveFilter.buddyList, buddyList, buddyCount * 4 );
clearServerList();
}
// Pick a random master server from the list:
gMasterServerList.clear();
Vector<MasterInfo> *masterList = getMasterServerList();
for ( U32 i = 0; i < masterList->size(); i++ )
gMasterServerList.push_back( (*masterList)[i] );
// Clear the master server ping:
gMasterServerPing.time = 0;
gMasterServerPing.tryCount = gMasterServerRetryCount;
if ( !pickMasterServer() )
Con::errorf( "No master servers found!" );
else
processMasterServerQuery( gPingSession );
}
ConsoleFunction( queryMasterServer, void, 11, 11, "queryMasterServer(...);" )
{
argc;
U8 flags = dAtoi(argv[1]);
// It's not a good idea to hold onto args, recursive calls to
// console exec will trash them.
char* gameType = dStrdup(argv[2]);
char* missionType = dStrdup(argv[3]);
U8 minPlayers = dAtoi(argv[4]);
U8 maxPlayers = dAtoi(argv[5]);
U8 maxBots = dAtoi(argv[6]);
U32 regionMask = dAtoi(argv[7]);
U32 maxPing = dAtoi(argv[8]);
U16 minCPU = dAtoi(argv[9]);
U8 filterFlags = dAtoi(argv[10]);
U8 buddyCount = 0;
U32 buddyList = 0;
queryMasterServer(flags,gameType,missionType,minPlayers,maxPlayers,
maxBots,regionMask,maxPing,minCPU,filterFlags,0,&buddyList);
dFree(gameType);
dFree(missionType);
}Ok almost done, now open the serverQuery.h file and replace the existing declarations of the above functions with these new ones:
extern void queryLanServers(U32 port, U8 flags, const char* gameType, const char* missionType,
U8 minPlayers, U8 maxPlayers, U8 maxBots, U32 regionMask, U32 maxPing, U16 minCPU,
U8 filterFlags);
extern void queryMasterServer(U8 flags, const char* gameType, const char* missionType,
U8 minPlayers, U8 maxPlayers, U8 maxBots, U32 regionMask, U32 maxPing, U16 minCPU,
U8 filterFlags, U8 buddyCount, U32* buddyList );Ok, you are done, recompile and enjoy. What you will have now is a couple of buttons for individually querying LAN or Internet servers. The query master server button will no longer query LAN servers, and the query LAN servers will no longer need you to be online to work. Note that I also removed some buddyList code, etc. that I thought that wasn't being used, maybe some left overs from Tribes 2. Since I didn't need it I just went ahead and removed it from my new LAN function, but you will notice it's still there in the queryMasterServer function, but it's of no use, since it's initialized to 0 and NULL. So feel free to go ahead and remove that code, I just left it there because that was not the point of this resource.Good Luck and enjoy.

Torque Owner Josef Jahn
Thanks!