fix harvesting of known player names to not mismatch name/address

The buggy code assumed two arrays were in sync that weren't guaranteed
to be so. So now I'm leveraging rematch code that already put
addresses in player order.
This commit is contained in:
Eric House 2024-07-30 11:12:08 -07:00
parent daacc66ffe
commit 696c47ace4
12 changed files with 233 additions and 166 deletions

View file

@ -237,7 +237,7 @@ mutex_init(CommsCtxt* comms)
#define COMMS_MUTEX_UNLOCK COMMS_MUTEX_UNLOCK_RELEASE
#endif
#define FLAG_HARVEST_DONE 1
#define _FLAG_HARVEST_DONE 1 /* no longer used */
#define FLAG_QUASHED 2
#define QUASHED(COMMS) (0 != ((COMMS)->flags & FLAG_QUASHED))
@ -3397,31 +3397,6 @@ comms_setQuashed( CommsCtxt* comms, XWEnv xwe, XP_Bool quashed )
return changed;
}
#ifdef XWFEATURE_KNOWNPLAYERS
void
comms_gatherPlayers( CommsCtxt* comms, XWEnv xwe, XP_U32 created )
{
COMMS_MUTEX_LOCK(comms);
if ( 0 == (comms->flags & FLAG_HARVEST_DONE) ) {
CommsAddrRec addrs[4] = {{0}};
XP_U16 nRecs = VSIZE(addrs);
comms_getAddrs( comms, addrs, &nRecs );
const CurGameInfo* gi = comms->util->gameInfo;
XP_ASSERT( 0 < gi->nPlayers );
if ( kplr_addAddrs( comms->dutil, xwe, gi, addrs, nRecs, created ) ) {
/* if ( 1 ) { */
/* COMMS_LOGFF( "not setting flag :-)" ); */
/* } else { */
/* /\* Need a way to force/override this manually? *\/ */
/* comms->flags |= FLAG_HARVEST_DONE; */
/* } */
}
}
COMMS_MUTEX_UNLOCK();
}
#endif
#ifdef RELAY_VIA_HTTP
void
comms_gameJoined( CommsCtxt* comms, XWEnv xwe, const XP_UCHAR* connname, XWHostID hid )

View file

@ -271,10 +271,6 @@ void types_rmType( XP_U16* conTypes, CommsConnType type );
XP_Bool types_hasType( XP_U16 conTypes, CommsConnType type );
XP_Bool types_iter( XP_U32 conTypes, CommsConnType* typp, XP_U32* state );
#ifdef XWFEATURE_KNOWNPLAYERS
void comms_gatherPlayers( CommsCtxt* comms, XWEnv xwe, XP_U32 created );
#endif
const char* ConnType2Str( CommsConnType typ );
# ifdef DEBUG

View file

@ -380,9 +380,9 @@ game_makeFromStream( MPFORMAL XWEnv xwe, XWStreamCtxt* stream,
#ifdef XWFEATURE_KNOWNPLAYERS
const XP_U32 created = game->created;
if ( 0 != created
if ( !!game->comms && 0 != created
&& server_getGameIsConnected( game->server ) ) {
comms_gatherPlayers( game->comms, xwe, created );
server_gatherPlayers( game->server, xwe, created );
}
#endif
}
@ -564,7 +564,7 @@ game_dispose( XWGame* game, XWEnv xwe )
const XP_U32 created = game->created;
if ( !!game->comms && 0 != created
&& server_getGameIsConnected( game->server ) ) {
comms_gatherPlayers( game->comms, xwe, created );
server_gatherPlayers( game->server, xwe, created );
}
#endif
@ -1072,6 +1072,7 @@ game_logGI( const CurGameInfo* gi, const char* msg, const char* func, int line )
XP_LOGFF( "msg: %s from %s() line %d; gameID: %X", msg, func, line,
!!gi ? gi->gameID:0 );
if ( !!gi ) {
XP_LOGF( " serverRole: %d", gi->serverRole );
XP_LOGF( " nPlayers: %d", gi->nPlayers );
for ( XP_U16 ii = 0; ii < gi->nPlayers; ++ii ) {
const LocalPlayer* lp = &gi->players[ii];
@ -1079,7 +1080,6 @@ game_logGI( const CurGameInfo* gi, const char* msg, const char* func, int line )
boolToStr(lp->isLocal), lp->robotIQ, lp->name, lp->dictName, lp->password );
}
XP_LOGF( " forceChannel: %d", gi->forceChannel );
XP_LOGF( " serverRole: %d", gi->serverRole );
XP_LOGF( " dictName: %s", gi->dictName );
XP_LOGF( " isoCode: %s", gi->isoCodeStr );
XP_LOGF( " tradeSub7: %s", boolToStr(gi->tradeSub7) );

View file

@ -18,7 +18,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// #define ENABLE_LOGFFV 1
#ifdef XWFEATURE_KNOWNPLAYERS
#include "knownplyr.h"
#include "strutils.h"
@ -26,8 +26,6 @@
#include "dbgutil.h"
#include "dllist.h"
#ifdef XWFEATURE_KNOWNPLAYERS
typedef struct _KnownPlayer {
DLHead links;
XP_U32 newestMod;
@ -127,23 +125,6 @@ releaseState( XW_DUtilCtxt* dutil, XWEnv xwe, KPState* state )
pthread_mutex_unlock( &dutil->kpMutex );
}
static const XP_UCHAR*
figureNameFor( XP_U16 posn, const CurGameInfo* gi )
{
const XP_UCHAR* result = NULL;
for ( int ii = 0, nthRemote = 0;
NULL == result && ii < gi->nPlayers;
++ii ) {
const LocalPlayer* lp = &gi->players[ii];
if ( lp->isLocal ) {
continue;
} else if ( nthRemote++ == posn ) {
result = lp->name;
}
}
return result;
}
static void
makeUniqueName( const KPState* state, const XP_UCHAR* name,
XP_UCHAR newName[], XP_U16 len )
@ -261,29 +242,15 @@ addPlayer( XW_DUtilCtxt* XP_UNUSED_DBG(dutil), KPState* state,
}
XP_Bool
kplr_addAddrs( XW_DUtilCtxt* dutil, XWEnv xwe, const CurGameInfo* gi,
CommsAddrRec addrs[], XP_U16 nAddrs, XP_U32 modTime )
kplr_addAddr( XW_DUtilCtxt* dutil, XWEnv xwe, const CommsAddrRec* addr,
const XP_UCHAR* name, XP_U32 modTime )
{
XP_LOGFFV( "(nAddrs=%d)", nAddrs );
XP_ASSERT( modTime );
XP_Bool canUse = XP_TRUE;
for ( int ii = 0; ii < nAddrs && canUse; ++ii ) {
canUse = addr_hasType( &addrs[ii], COMMS_CONN_MQTT );
if ( !canUse ) {
XP_LOGFF( "addr %d has no mqqt id", ii );
}
}
XP_ASSERT( !!name );
XP_Bool canUse = addr_hasType( addr, COMMS_CONN_MQTT );
if ( canUse ) {
KPState* state = loadState( dutil, xwe );
for ( int ii = 0; ii < nAddrs && canUse; ++ii ) {
const XP_UCHAR* name = figureNameFor( ii, gi );
if ( !!name ) {
addPlayer( dutil, state, name, &addrs[ii], modTime );
} else {
XP_LOGFF( "unable to find %dth name", ii );
}
}
addPlayer( dutil, state, name, addr, modTime );
releaseState( dutil, xwe, state );
}

View file

@ -52,8 +52,8 @@ KP_Rslt kplr_renamePlayer( XW_DUtilCtxt* dutil, XWEnv xwe, const XP_UCHAR* oldNa
const XP_UCHAR* newName );
KP_Rslt kplr_deletePlayer( XW_DUtilCtxt* dutil, XWEnv xwe, const XP_UCHAR* name );
XP_Bool kplr_addAddrs( XW_DUtilCtxt* dutil, XWEnv xwe, const CurGameInfo* gi,
CommsAddrRec addrs[], XP_U16 nAddrs, XP_U32 modTime );
XP_Bool kplr_addAddr( XW_DUtilCtxt* dutil, XWEnv xwe, const CommsAddrRec* addr,
const XP_UCHAR* name, XP_U32 modTime );
# else
# define kplr_cleanup( dutil )
# endif

View file

@ -32,6 +32,7 @@
#include "device.h"
#include "strutils.h"
#include "dbgutil.h"
#include "knownplyr.h"
#include "LocalizedStrIncludes.h"
@ -119,6 +120,7 @@ typedef struct ServerVolatiles {
#define MASK_IS_FROM_REMATCH (1<<0)
#define MASK_HAVE_RIP_INFO (1<<1)
#define FLAG_HARVEST_READY (1<<2)
typedef struct _ServerNonvolatiles {
XP_U32 flags; /* */
@ -287,6 +289,9 @@ static void writeProto( const ServerCtxt* server, XWStreamCtxt* stream,
XW_Proto proto );
static void readGuestAddrs( ServerCtxt* server, XWStreamCtxt* stream,
XP_U8 streamVersion );
static XP_Bool getRematchInfoImpl( const ServerCtxt* server,
CurGameInfo* newGI, const NewOrder* nop,
RematchInfo** ripp );
static void ri_fromStream( RematchInfo* rip, XWStreamCtxt* stream,
const ServerCtxt* server );
@ -2017,6 +2022,7 @@ server_do( ServerCtxt* server, XWEnv xwe )
SETSTATE( server, XWSTATE_INTURN );
setTurn( server, xwe, 0 );
moreToDo = XP_TRUE;
server->nv.flags |= FLAG_HARVEST_READY;
break;
case XWSTATE_MOVE_CONFIRM_MUSTSEND:
@ -2269,6 +2275,7 @@ client_readInitialMessage( ServerCtxt* server, XWEnv xwe, XWStreamCtxt* stream )
XP_ASSERT( !localGI.dictName );
localGI.dictName = copyString( server->mpool, gi->dictName );
gi_copy( MPPARM(server->mpool) gi, &localGI );
server->nv.flags |= FLAG_HARVEST_READY;
if ( streamVersion < STREAM_VERS_NOEMPTYDICT ) {
SRVR_LOGFF( "loading and dropping empty dict" );
@ -4266,9 +4273,7 @@ server_getRematchInfo( const ServerCtxt* server, XW_UtilCtxt* newUtil,
XP_U32 gameID, const NewOrder* nop, RematchInfo** ripp )
{
XP_Bool success = server_canRematch( server, NULL );
const CommsCtxt* comms = server->vol.comms;
if ( success ) {
RematchInfo ri = {0};
CurGameInfo* newGI = newUtil->gameInfo;
gi_disposePlayerInfo( MPPARM(newUtil->mpool) newGI );
@ -4280,102 +4285,114 @@ server_getRematchInfo( const ServerCtxt* server, XW_UtilCtxt* newUtil,
}
LOGGI( newUtil->gameInfo, "ready to invite" );
/* Now build the address list. Simple cases are STANDALONE, when I'm
the host, or when there are only two devices/players. If I'm guest
and there is another guest, I count on the host having sent rematch
info, and *that* info has an old and a new format. Sheesh. */
XP_Bool canOrder = XP_TRUE;
if ( !comms ) {
/* no addressing to do!! */
} else if ( amHost( server ) || 2 == newGI->nPlayers ) {
for ( int ii = 0; ii < newGI->nPlayers; ++ii ) {
success = getRematchInfoImpl( server, newGI, nop, ripp );
}
return success;
}
static XP_Bool
getRematchInfoImpl( const ServerCtxt* server, CurGameInfo* newGI,
const NewOrder* nop, RematchInfo** ripp )
{
XP_Bool success = XP_TRUE;
RematchInfo ri = {0};
const CommsCtxt* comms = server->vol.comms;
/* Now build the address list. Simple cases are STANDALONE, when I'm
the host, or when there are only two devices/players. If I'm guest
and there is another guest, I count on the host having sent rematch
info, and *that* info has an old and a new format. Sheesh. */
XP_Bool canOrder = XP_TRUE;
if ( !comms ) {
/* no addressing to do!! */
} else if ( amHost( server ) || 2 == newGI->nPlayers ) {
for ( int ii = 0; ii < newGI->nPlayers; ++ii ) {
if ( newGI->players[ii].isLocal ) {
ri_addLocal( &ri );
} else {
CommsAddrRec addr;
if ( amHost(server) ) {
XP_S8 deviceIndex = server->srvPlyrs[ii].deviceIndex;
XP_ASSERT( deviceIndex != RIP_LOCAL_INDX );
XP_PlayerAddr channelNo =
server->nv.addresses[deviceIndex].channelNo;
comms_getChannelAddr( comms, channelNo, &addr );
} else {
comms_getHostAddr( comms, &addr );
}
ri_addAddrAt( &ri, server, &addr, ii );
}
}
} else if ( !!server->nv.rematch.addrs ) {
XP_U16 streamVersion = server->nv.streamVersion;
if ( STREAM_VERS_REMATCHORDER <= streamVersion ) {
loadRemoteRI( server, newGI, &ri );
} else {
/* I don't have complete info yet. So let's go through the gi,
assigning an address to all non-local players. We'll use
the host address first, then the rest we have. If we don't
have the right number of everything, we fail. Note: we
should not have given the user a choice in rematch ordering
here!!!*/
canOrder = newGI->nPlayers <= 2;
XP_ASSERT( !canOrder );
canOrder = XP_FALSE;
CommsAddrRec addrs[MAX_NUM_PLAYERS];
int nAddrs = 0;
comms_getHostAddr( comms, &addrs[nAddrs++] );
XWStreamCtxt* stream = mkServerStream( server,
server->nv.streamVersion );
stream_putBytes( stream, server->nv.rematch.addrs,
server->nv.rematch.addrsLen );
while ( 0 < stream_getSize( stream ) ) {
XP_ASSERT( nAddrs < VSIZE(addrs) );
addrFromStream( &addrs[nAddrs++], stream );
}
stream_destroy( stream );
int nextRemote = 0;
for ( int ii = 0; success && ii < newGI->nPlayers; ++ii ) {
if ( newGI->players[ii].isLocal ) {
ri_addLocal( &ri );
} else if ( nextRemote < nAddrs ) {
ri_addAddrAt( &ri, server, &addrs[nextRemote++], ii );
} else {
CommsAddrRec addr;
if ( amHost(server) ) {
XP_S8 deviceIndex = server->srvPlyrs[ii].deviceIndex;
XP_ASSERT( deviceIndex != RIP_LOCAL_INDX );
XP_PlayerAddr channelNo =
server->nv.addresses[deviceIndex].channelNo;
comms_getChannelAddr( comms, channelNo, &addr );
} else {
comms_getHostAddr( comms, &addr );
}
ri_addAddrAt( &ri, server, &addr, ii );
SRVR_LOGFF( "ERROR: not enough addresses for all"
" remote players" );
success = XP_FALSE;
}
}
} else if ( !!server->nv.rematch.addrs ) {
XP_U16 streamVersion = server->nv.streamVersion;
if ( STREAM_VERS_REMATCHORDER <= streamVersion ) {
loadRemoteRI( server, newGI, &ri );
} else {
/* I don't have complete info yet. So let's go through the gi,
assigning an address to all non-local players. We'll use
the host address first, then the rest we have. If we don't
have the right number of everything, we fail. Note: we
should not have given the user a choice in rematch ordering
here!!!*/
canOrder = newGI->nPlayers <= 2;
XP_ASSERT( !canOrder );
canOrder = XP_FALSE;
CommsAddrRec addrs[MAX_NUM_PLAYERS];
int nAddrs = 0;
comms_getHostAddr( comms, &addrs[nAddrs++] );
XWStreamCtxt* stream = mkServerStream( server, server->nv.streamVersion );
stream_putBytes( stream, server->nv.rematch.addrs,
server->nv.rematch.addrsLen );
while ( 0 < stream_getSize( stream ) ) {
XP_ASSERT( nAddrs < VSIZE(addrs) );
addrFromStream( &addrs[nAddrs++], stream );
}
stream_destroy( stream );
int nextRemote = 0;
for ( int ii = 0; success && ii < newGI->nPlayers; ++ii ) {
if ( newGI->players[ii].isLocal ) {
ri_addLocal( &ri );
} else if ( nextRemote < nAddrs ) {
ri_addAddrAt( &ri, server, &addrs[nextRemote++], ii );
} else {
SRVR_LOGFF( "ERROR: not enough addresses for all remote players" );
success = XP_FALSE;
}
}
if ( success ) {
success = nextRemote == nAddrs;
}
if ( success ) {
success = nextRemote == nAddrs;
}
} else {
XP_ASSERT( 0 ); /* should not have returned TRUE from server_canRematch(); */
success = XP_FALSE;
}
if ( success && canOrder ) {
if ( !!comms ) {
assertRI( &ri, newGI );
}
success = setPlayerOrder( server, nop, newGI, !!comms ? &ri : NULL );
}
if ( success && !!comms ) {
LOG_RI( &ri );
assertRI( &ri, newGI );
XP_ASSERT( success );
*ripp = XP_MALLOC(server->mpool, sizeof(**ripp));
**ripp = ri;
} else {
*ripp = NULL;
}
XP_ASSERT( success );
} else {
success = XP_FALSE;
}
if ( success && canOrder ) {
if ( !!comms ) {
assertRI( &ri, newGI );
}
success = setPlayerOrder( server, nop, newGI, !!comms ? &ri : NULL );
}
if ( success && !!comms ) {
LOG_RI( &ri );
assertRI( &ri, newGI );
XP_ASSERT( success );
*ripp = XP_MALLOC(server->mpool, sizeof(**ripp));
**ripp = ri;
} else {
*ripp = NULL;
}
XP_ASSERT( success );
LOG_RETURNF( "%s", boolToStr(success) );
return success;
} /* server_getRematchInfo */
} /* getRematchInfoImpl */
void
server_disposeRematchInfo( ServerCtxt* XP_UNUSED_DBG(server), RematchInfo** ripp )
@ -4464,6 +4481,42 @@ server_isFromRematch( const ServerCtxt* server )
return 0 != (server->nv.flags & MASK_IS_FROM_REMATCH);
}
#ifdef XWFEATURE_KNOWNPLAYERS
void
server_gatherPlayers( ServerCtxt* server, XWEnv xwe, XP_U32 created )
{
XP_Bool flagSet = 0 != (server->nv.flags & FLAG_HARVEST_READY);
if ( flagSet ) {
const CurGameInfo* gi = server->vol.gi;
XW_DUtilCtxt* dutil = server->vol.dutil;
NewOrder no;
server_figureOrder( server, RO_SAME, &no );
CurGameInfo tmpGi = *gi;
RematchInfo* ripp;
if ( getRematchInfoImpl( server, &tmpGi, &no, &ripp ) ) {
for ( int ii = 0, nRemotes = 0; ii < gi->nPlayers; ++ii ) {
const LocalPlayer* lp = &gi->players[ii];
/* order unchanged? */
XP_ASSERT( lp->name == gi->players[ii].name );
if ( !lp->isLocal ) {
CommsAddrRec addr;
XP_U16 nPlayersH;
if ( !server_ri_getAddr( ripp, nRemotes++, &addr, &nPlayersH ) ) {
break;
}
XP_ASSERT( 1 == nPlayersH ); /* else fixme... */
kplr_addAddr( dutil, xwe, &addr, lp->name, created );
}
}
server_disposeRematchInfo( server, &ripp );
}
}
}
#endif
#ifdef DEBUG
static void
log_ri( const ServerCtxt* server, const RematchInfo* rip,
@ -4482,7 +4535,8 @@ log_ri( const ServerCtxt* server, const RematchInfo* rip,
maxIndx = indx;
}
}
SRVR_LOGFFV( "%d players (and %d addrs): [%s]", rip->nPlayers, rip->nAddrs, buf );
SRVR_LOGFFV( "%d players (and %d addrs): [%s]", rip->nPlayers,
rip->nAddrs, buf );
for ( int ii = 0; ii < rip->nAddrs; ++ii ) {
XP_SNPRINTF( buf, VSIZE(buf), "[%d of %d]: %s from %s",

View file

@ -199,6 +199,10 @@ void server_setRematchOrder( ServerCtxt* server, const RematchInfo* ri );
XP_Bool server_isFromRematch( const ServerCtxt* server );
#ifdef XWFEATURE_KNOWNPLAYERS
void server_gatherPlayers( ServerCtxt* server, XWEnv xwe, XP_U32 created );
#endif
#ifdef CPLUS
}
#endif

View file

@ -447,8 +447,8 @@ disposeBoard( CursesBoardGlobals* bGlobals, XP_Bool rmFromList )
cmenu_pop( bGlobals->cbState->menuState );
}
gi_disposePlayerInfo( MPPARM(cGlobals->util->mpool) cGlobals->gi );
game_dispose( &cGlobals->game, NULL_XWE );
gi_disposePlayerInfo( MPPARM(cGlobals->util->mpool) cGlobals->gi );
disposeUtil( cGlobals );

View file

@ -75,6 +75,7 @@
#include "curgamlistwin.h"
#include "gsrcwrap.h"
#include "extcmds.h"
#include "knownplyr.h"
#ifndef CURSES_CELL_HT
# define CURSES_CELL_HT 1
@ -1516,6 +1517,37 @@ resignWrapper( void* closure, XP_U32 gameID )
return cb_resign( aGlobals->cbState, gameID );
}
static cJSON*
getKPsWrapper( void* closure )
{
CursesAppGlobals* aGlobals = (CursesAppGlobals*)closure;
XW_DUtilCtxt* dutil = aGlobals->cag.params->dutil;
XP_U16 nFound = 0;
kplr_getNames( dutil, NULL_XWE, XP_FALSE, NULL, &nFound );
const XP_UCHAR* players[nFound];
kplr_getNames( dutil, NULL_XWE, XP_FALSE, players, &nFound );
cJSON* result = cJSON_CreateArray();
for ( int ii = 0; ii < nFound; ++ii ) {
cJSON* entry = cJSON_CreateObject();
cJSON_AddStringToObject( entry, "name", players[ii]);
CommsAddrRec addr;
if ( kplr_getAddr( dutil, NULL_XWE, players[ii],
&addr, NULL ) ) {
XP_UCHAR buf[17];
formatMQTTDevID( &addr.u.mqtt.devID, buf, VSIZE(buf) );
cJSON_AddStringToObject( entry, "devID", buf );
}
cJSON_AddItemToArray( result, entry );
}
return result;
}
void
cursesmain( XP_Bool XP_UNUSED(isServer), LaunchParams* params )
{
@ -1552,6 +1584,7 @@ cursesmain( XP_Bool XP_UNUSED(isServer), LaunchParams* params )
.sendChat = sendChatWrapper,
.undoMove = undoMoveWrapper,
.resign = resignWrapper,
.getKPs = getKPsWrapper,
},
};
GSocketService* cmdService = cmds_addCmdListener( &wr );

View file

@ -153,6 +153,11 @@ resignFromArgs( CmdWrapper* wr, cJSON* args )
XP_U32 gameID = gidFromObject( args );
return (*wr->procs.resign)( wr->closure, gameID );
}
static cJSON*
knwnPlyrs( CmdWrapper* wr )
{
return (*wr->procs.getKPs)( wr->closure );
}
/* Return 'gid' of new game */
static XP_U32
@ -430,6 +435,12 @@ on_incoming_signal( GSocketService* XP_UNUSED(service),
success = undoFromArgs( wr, args );
} else if ( 0 == strcmp( cmdStr, "resign" ) ) {
success = resignFromArgs( wr, args );
} else if ( 0 == strcmp( cmdStr, "getKPs" ) ) {
cJSON* result = knwnPlyrs( wr );
success = !!result;
if ( success ) {
addObjectToObject( &response, "kps", result );
}
} else {
success = XP_FALSE;
XP_ASSERT(0);

View file

@ -37,6 +37,7 @@ typedef struct _CmdWrapper {
XP_Bool (*sendChat)( void* closure, XP_U32 gameID, const char* msg );
XP_Bool (*undoMove)( void* closure, XP_U32 gameID );
XP_Bool (*resign)( void* closure, XP_U32 gameID );
cJSON* (*getKPs)( void* closure );
} procs;
LaunchParams* params;
void* closure;

View file

@ -198,6 +198,7 @@ class Device():
_logdir = None
_nSteps = 0
_nextChatID = 0
_kps = {}
@staticmethod
def setup(logdir):
@ -272,7 +273,10 @@ class Device():
tryTrade = random.randint(0, 99) < self.args.TRADE_PCT
response = self._sendWaitReply('moveIf', gid=gid, tryTrade=tryTrade)
moved = response.get('success', False)
if moved: break
if moved:
response = self._sendWaitReply('getKPs', gid=gid)
self.checkKPs(response.get('kps'))
break
return moved
def sendChat(self):
@ -280,7 +284,8 @@ class Device():
if random.randint(0, 99) < self.args.CHAT_PCT:
gid = self._pickGid()
if gid:
response = self._sendWaitReply('sendChat', gid=gid, msg=Device.nextChatMsg(self.host))
response = self._sendWaitReply('sendChat', gid=gid,
msg=Device.nextChatMsg(self.host))
success = response.get('success', False)
return success
@ -302,6 +307,19 @@ class Device():
success = response.get('success', False)
return success
def checkKPs(self, kps):
if kps:
for kp in kps:
devID = kp.get('devID')
if not devID in Device._kps: Device._kps[devID] = set()
names = Device._kps[devID]
name = kp.get('name')
if name not in names and len(names):
print('adding {} to {} for {}' \
.format(name, names, Device._kps.get(devID)))
names.add(name)
def _pickGid(self):
result = None
gids = [game.gid for game in self._allGames()]
@ -687,6 +705,12 @@ def countCores(args):
count = len( glob.glob(args.CORE_PAT) )
return count
def printKPs():
kps = Device._kps
for names in kps.values():
assert 1 == len(names)
print('Known players: {}'.format(kps))
def mainLoop(args, devs):
startCount = len(devs)
nCores = countCores(args)
@ -936,6 +960,8 @@ def main():
dev.quit()
mainLoop(args, devs)
printKPs()
elapsed = datetime.datetime.now() - startTime
print('played {} games in {}'.format(gGamesMade, elapsed))