2005-07-24 16:12:37 +02:00
/* $Id$ */
2009-08-21 22:21:05 +02:00
/*
* This file is part of OpenTTD .
* OpenTTD is free software ; you can redistribute it and / or modify it under the terms of the GNU General Public License as published by the Free Software Foundation , version 2.
* OpenTTD is distributed in the hope that it will be useful , but WITHOUT ANY WARRANTY ; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE .
* See the GNU General Public License for more details . You should have received a copy of the GNU General Public License along with OpenTTD . If not , see < http : //www.gnu.org/licenses/>.
*/
2007-02-23 09:37:33 +01:00
/**
* @ file network_gamelist . cpp This file handles the GameList
* Also , it handles the request to a server for data about the server
*/
2007-01-02 18:34:03 +01:00
# include "../stdafx.h"
# include "../debug.h"
2011-02-08 21:51:30 +01:00
# include "../window_func.h"
2008-05-30 20:20:26 +02:00
# include "network_internal.h"
2007-02-01 22:04:40 +01:00
# include "network_udp.h"
2007-02-02 22:32:58 +01:00
# include "network_gamelist.h"
2019-03-17 11:05:38 +01:00
# include <atomic>
2007-02-02 22:32:58 +01:00
2014-04-23 22:13:33 +02:00
# include "../safeguards.h"
2019-04-10 23:07:06 +02:00
NetworkGameList * _network_game_list = nullptr ;
2007-02-01 22:04:40 +01:00
2011-05-02 18:14:23 +02:00
/** The games to insert when the GUI thread has time for us. */
2019-04-10 23:07:06 +02:00
static std : : atomic < NetworkGameList * > _network_game_delayed_insertion_list ( nullptr ) ;
2009-01-20 04:44:43 +01:00
2010-08-01 21:22:34 +02:00
/**
* Add a new item to the linked gamelist , but do it delayed in the next tick
2009-01-20 04:44:43 +01:00
* or so to prevent race conditions .
* @ param item the item to add . Will be freed once added .
*/
void NetworkGameListAddItemDelayed ( NetworkGameList * item )
{
2019-03-17 11:05:38 +01:00
item - > next = _network_game_delayed_insertion_list . load ( std : : memory_order_relaxed ) ;
while ( ! _network_game_delayed_insertion_list . compare_exchange_weak ( item - > next , item , std : : memory_order_acq_rel ) ) { }
2009-01-20 04:44:43 +01:00
}
/** Perform the delayed (thread safe) insertion into the game list */
static void NetworkGameListHandleDelayedInsert ( )
{
2019-03-17 11:05:38 +01:00
while ( true ) {
NetworkGameList * ins_item = _network_game_delayed_insertion_list . load ( std : : memory_order_relaxed ) ;
2019-04-10 23:07:06 +02:00
while ( ins_item ! = nullptr & & ! _network_game_delayed_insertion_list . compare_exchange_weak ( ins_item , ins_item - > next , std : : memory_order_acq_rel ) ) { }
if ( ins_item = = nullptr ) break ; // No item left.
2009-01-20 04:44:43 +01:00
2009-04-02 22:17:46 +02:00
NetworkGameList * item = NetworkGameListAddItem ( ins_item - > address ) ;
2009-01-20 04:44:43 +01:00
2019-04-10 23:07:06 +02:00
if ( item ! = nullptr ) {
2009-01-20 04:44:43 +01:00
if ( StrEmpty ( item - > info . server_name ) ) {
2010-01-06 21:49:24 +01:00
ClearGRFConfigList ( & item - > info . grfconfig ) ;
2009-01-20 04:44:43 +01:00
memset ( & item - > info , 0 , sizeof ( item - > info ) ) ;
strecpy ( item - > info . server_name , ins_item - > info . server_name , lastof ( item - > info . server_name ) ) ;
strecpy ( item - > info . hostname , ins_item - > info . hostname , lastof ( item - > info . hostname ) ) ;
item - > online = false ;
}
2009-04-03 14:49:58 +02:00
item - > manually | = ins_item - > manually ;
2009-07-29 18:45:51 +02:00
if ( item - > manually ) NetworkRebuildHostList ( ) ;
2012-03-25 21:46:59 +02:00
UpdateNetworkGameWindow ( ) ;
2009-01-20 04:44:43 +01:00
}
free ( ins_item ) ;
}
}
2010-08-01 21:22:34 +02:00
/**
* Add a new item to the linked gamelist . If the IP and Port match
2006-01-26 14:01:53 +01:00
* return the existing item instead of adding it again
2009-04-03 13:02:41 +02:00
* @ param address the address of the to - be added item
2010-08-01 21:44:49 +02:00
* @ return a point to the newly added or already existing item
*/
2009-04-02 22:17:46 +02:00
NetworkGameList * NetworkGameListAddItem ( NetworkAddress address )
2004-12-04 18:54:56 +01:00
{
2009-04-08 23:16:24 +02:00
const char * hostname = address . GetHostname ( ) ;
/* Do not query the 'any' address. */
if ( StrEmpty ( hostname ) | |
strcmp ( hostname , " 0.0.0.0 " ) = = 0 | |
strcmp ( hostname , " :: " ) = = 0 ) {
2019-04-10 23:07:06 +02:00
return nullptr ;
2009-04-08 23:16:24 +02:00
}
2008-04-14 22:31:21 +02:00
2006-01-25 20:03:50 +01:00
NetworkGameList * item , * prev_item ;
2004-12-04 18:54:56 +01:00
2019-04-10 23:07:06 +02:00
prev_item = nullptr ;
for ( item = _network_game_list ; item ! = nullptr ; item = item - > next ) {
2009-04-02 22:17:46 +02:00
if ( item - > address = = address ) return item ;
2006-01-25 20:03:50 +01:00
prev_item = item ;
2004-12-04 18:54:56 +01:00
}
2009-01-20 04:44:43 +01:00
item = CallocT < NetworkGameList > ( 1 ) ;
2019-04-10 23:07:06 +02:00
item - > next = nullptr ;
2009-04-02 22:17:46 +02:00
item - > address = address ;
2006-01-25 20:03:50 +01:00
2019-04-10 23:07:06 +02:00
if ( prev_item = = nullptr ) {
2006-06-27 23:25:53 +02:00
_network_game_list = item ;
} else {
prev_item - > next = item ;
}
2006-12-26 18:36:18 +01:00
DEBUG ( net , 4 , " [gamelist] added server to list " ) ;
2004-12-04 18:54:56 +01:00
2012-03-25 21:46:59 +02:00
UpdateNetworkGameWindow ( ) ;
2004-12-04 18:54:56 +01:00
return item ;
}
2010-08-01 21:22:34 +02:00
/**
* Remove an item from the gamelist linked list
2010-08-01 21:44:49 +02:00
* @ param remove pointer to the item to be removed
*/
2004-12-20 23:14:39 +01:00
void NetworkGameListRemoveItem ( NetworkGameList * remove )
{
2019-04-10 23:07:06 +02:00
NetworkGameList * prev_item = nullptr ;
for ( NetworkGameList * item = _network_game_list ; item ! = nullptr ; item = item - > next ) {
2006-01-25 20:03:50 +01:00
if ( remove = = item ) {
2019-04-10 23:07:06 +02:00
if ( prev_item = = nullptr ) {
2006-06-27 23:25:53 +02:00
_network_game_list = remove - > next ;
} else {
prev_item - > next = remove - > next ;
}
2004-12-20 23:14:39 +01:00
2006-12-18 13:26:55 +01:00
/* Remove GRFConfig information */
2006-12-20 22:17:33 +01:00
ClearGRFConfigList ( & remove - > info . grfconfig ) ;
2004-12-20 23:14:39 +01:00
free ( remove ) ;
2019-04-10 23:07:06 +02:00
remove = nullptr ;
2006-12-20 22:17:33 +01:00
2006-12-26 18:36:18 +01:00
DEBUG ( net , 4 , " [gamelist] removed server from list " ) ;
2009-07-29 18:45:51 +02:00
NetworkRebuildHostList ( ) ;
2012-03-25 21:46:59 +02:00
UpdateNetworkGameWindow ( ) ;
2004-12-20 23:14:39 +01:00
return ;
}
2006-01-25 20:03:50 +01:00
prev_item = item ;
2004-12-20 23:14:39 +01:00
}
}
2010-05-13 12:14:29 +02:00
static const uint MAX_GAME_LIST_REQUERY_COUNT = 10 ; ///< How often do we requery in number of times per server?
static const uint REQUERY_EVERY_X_GAMELOOPS = 60 ; ///< How often do we requery in time?
static const uint REFRESH_GAMEINFO_X_REQUERIES = 50 ; ///< Refresh the game info itself after REFRESH_GAMEINFO_X_REQUERIES * REQUERY_EVERY_X_GAMELOOPS game loops
2007-02-01 22:04:40 +01:00
/** Requeries the (game) servers we have not gotten a reply from */
2007-03-07 12:47:46 +01:00
void NetworkGameListRequery ( )
2007-02-01 22:04:40 +01:00
{
2009-01-20 04:44:43 +01:00
NetworkGameListHandleDelayedInsert ( ) ;
2007-02-01 22:04:40 +01:00
static uint8 requery_cnt = 0 ;
2007-07-26 11:53:58 +02:00
if ( + + requery_cnt < REQUERY_EVERY_X_GAMELOOPS ) return ;
2007-02-01 22:04:40 +01:00
requery_cnt = 0 ;
2019-04-10 23:07:06 +02:00
for ( NetworkGameList * item = _network_game_list ; item ! = nullptr ; item = item - > next ) {
2007-07-26 11:53:58 +02:00
item - > retries + + ;
if ( item - > retries < REFRESH_GAMEINFO_X_REQUERIES & & ( item - > online | | item - > retries > = MAX_GAME_LIST_REQUERY_COUNT ) ) continue ;
2007-02-01 22:04:40 +01:00
/* item gets mostly zeroed by NetworkUDPQueryServer */
uint8 retries = item - > retries ;
2009-04-02 22:17:46 +02:00
NetworkUDPQueryServer ( NetworkAddress ( item - > address ) ) ;
2007-07-26 11:53:58 +02:00
item - > retries = ( retries > = REFRESH_GAMEINFO_X_REQUERIES ) ? 0 : retries ;
2007-02-01 22:04:40 +01:00
}
}
2009-09-17 23:14:16 +02:00
/**
* Rebuild the GRFConfig ' s of the servers in the game list as we did
* a rescan and might have found new NewGRFs .
*/
void NetworkAfterNewGRFScan ( )
{
2019-04-10 23:07:06 +02:00
for ( NetworkGameList * item = _network_game_list ; item ! = nullptr ; item = item - > next ) {
2012-12-01 14:12:39 +01:00
/* Reset compatibility state */
2009-09-17 23:14:16 +02:00
item - > info . compatible = item - > info . version_compatible ;
2019-04-10 23:07:06 +02:00
for ( GRFConfig * c = item - > info . grfconfig ; c ! = nullptr ; c = c - > next ) {
2009-09-17 23:14:16 +02:00
assert ( HasBit ( c - > flags , GCF_COPY ) ) ;
2010-10-17 14:12:13 +02:00
const GRFConfig * f = FindGRFConfig ( c - > ident . grfid , FGCM_EXACT , c - > ident . md5sum ) ;
2019-04-10 23:07:06 +02:00
if ( f = = nullptr ) {
2009-09-17 23:14:16 +02:00
/* Don't know the GRF, so mark game incompatible and the (possibly)
* already resolved name for this GRF ( another server has sent the
2012-12-01 14:12:39 +01:00
* name of the GRF already . */
2011-03-03 19:47:46 +01:00
c - > name - > Release ( ) ;
c - > name = FindUnknownGRFName ( c - > ident . grfid , c - > ident . md5sum , true ) ;
c - > name - > AddRef ( ) ;
2009-09-17 23:14:16 +02:00
c - > status = GCS_NOT_FOUND ;
2012-12-01 14:12:39 +01:00
/* If we miss a file, we're obviously incompatible. */
2009-09-17 23:14:16 +02:00
item - > info . compatible = false ;
} else {
2011-03-03 19:47:46 +01:00
c - > filename = f - > filename ;
c - > name - > Release ( ) ;
c - > name = f - > name ;
c - > name - > AddRef ( ) ;
c - > info - > Release ( ) ;
c - > info = f - > info ;
c - > info - > AddRef ( ) ;
c - > status = GCS_UNKNOWN ;
2009-09-17 23:14:16 +02:00
}
}
}
2011-02-08 21:51:30 +01:00
InvalidateWindowClassesData ( WC_NETWORK_WINDOW ) ;
2009-09-17 23:14:16 +02:00
}