xwords/xwords4/common/knownplyr.c
Eric House 736c9f3503 harvest players on open; save and make available
Got as far as having gtk client display list of previously harvested
known players to be invited. Their addresses, or at least mqtt ids are
saved. Next is to actually invite one.
2020-09-26 09:48:35 -07:00

201 lines
6 KiB
C

/* -*- compile-command: "cd ../linux && make MEMDEBUG=TRUE -j3"; -*- */
/*
* Copyright 2001 - 2020 by Eric House (xwords@eehouse.org). All rights
* reserved.
*
* This program 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; either version 2
* of the License, or (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "knownplyr.h"
#include "strutils.h"
#include "comms.h"
#include "dbgutil.h"
typedef struct _KnownPlayer {
struct _KnownPlayer* next;
XP_UCHAR* name;
CommsAddrRec addr;
} KnownPlayer;
typedef struct _KPState {
KnownPlayer* players;
XP_U16 nPlayers;
XP_Bool dirty;
} KPState;
/* enum { STREAM_VERSION_KP_1, /\* initial *\/ */
/* }; */
static void
addPlayer( XW_DUtilCtxt* dutil, KPState* state,
const XP_UCHAR* name, const CommsAddrRec* addr );
static void
loadFromStream( XW_DUtilCtxt* dutil, KPState* state, XWStreamCtxt* stream )
{
LOG_FUNC();
while ( 0 < stream_getSize( stream ) ) {
XP_UCHAR buf[64];
stringFromStreamHere( stream, buf, VSIZE(buf) );
CommsAddrRec addr = {0};
addrFromStream( &addr, stream );
addPlayer( dutil, state, buf, &addr );
}
}
static KPState*
loadState( XW_DUtilCtxt* dutil, XWEnv xwe )
{
LOG_FUNC();
KPState* state = (KPState*)dutil->kpCtxt;
if ( NULL == state ) {
dutil->kpCtxt = state = XP_CALLOC( dutil->mpool, sizeof(*state) );
XWStreamCtxt* stream = mem_stream_make_raw( MPPARM(dutil->mpool)
dutil_getVTManager(dutil) );
dutil_loadStream( dutil, xwe, KNOWN_PLAYERS_KEY, NULL, stream );
if ( 0 < stream_getSize( stream ) ) {
XP_U8 vers = stream_getU8( stream );
stream_setVersion( stream, vers );
loadFromStream( dutil, state, stream );
}
stream_destroy( stream, xwe );
}
return state;
}
static void
saveState( XW_DUtilCtxt* dutil, XWEnv xwe, KPState* state )
{
if ( state->dirty ) {
XWStreamCtxt* stream = mem_stream_make_raw( MPPARM(dutil->mpool)
dutil_getVTManager(dutil) );
stream_putU8( stream, CUR_STREAM_VERS );
for ( KnownPlayer* kp = state->players; !!kp; kp = kp->next ) {
stringToStream( stream, kp->name );
addrToStream( stream, &kp->addr );
}
dutil_storeStream( dutil, xwe, KNOWN_PLAYERS_KEY, stream );
stream_destroy( stream, xwe );
state->dirty = XP_FALSE;
}
}
static const XP_UCHAR*
figureNameFor( XP_U16 posn, const CurGameInfo* gi )
{
const XP_UCHAR* result = NULL;
// int nthRemote = 0;
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
addPlayer( XW_DUtilCtxt* dutil, KPState* state,
const XP_UCHAR* name, const CommsAddrRec* addr )
{
XP_LOGFF( "(name=%s)", name );
XP_Bool exists = XP_FALSE;
for ( KnownPlayer* kp = state->players; !!kp && !exists; kp = kp->next ) {
exists = 0 == XP_STRCMP( kp->name, name );
}
if ( !exists ) {
XP_LOGFF( "adding new player!" );
KnownPlayer* newPlayer = XP_CALLOC( dutil->mpool, sizeof(*newPlayer) );
newPlayer->name = copyString( dutil->mpool, name );
newPlayer->addr = *addr;
newPlayer->next = state->players;
state->players = newPlayer;
state->dirty = XP_TRUE;
++state->nPlayers;
}
XP_LOGFF( "nPlayers now: %d", state->nPlayers );
}
XP_Bool
kplr_addAddrs( XW_DUtilCtxt* dutil, XWEnv xwe, const CurGameInfo* gi,
CommsAddrRec addrs[], XP_U16 nAddrs )
{
LOG_FUNC();
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 );
}
}
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] );
} else {
XP_LOGFF( "unable to find %dth name", ii );
}
}
saveState( dutil, xwe, state );
}
return canUse;
}
XP_Bool
kplr_havePlayers( XW_DUtilCtxt* dutil, XWEnv xwe )
{
KPState* state = loadState( dutil, xwe );
XP_Bool result = 0 < state->nPlayers;
LOG_RETURNF( "%s", boolToStr(result) );
return result;
}
void
kplr_getPlayers( XW_DUtilCtxt* dutil, XWEnv xwe,
const XP_UCHAR** players, XP_U16* nFound )
{
KPState* state = loadState( dutil, xwe );
if ( state->nPlayers <= *nFound && !!players ) {
XP_U16 ii = 0;
for ( KnownPlayer* kp = state->players; !!kp; kp = kp->next ) {
players[ii++] = kp->name;
}
}
*nFound = state->nPlayers;
}
void
kplr_cleanup( XW_DUtilCtxt* dutil )
{
KPState** state = (KPState**)&dutil->kpCtxt;
if ( !!*state ) {
for ( KnownPlayer* kp = (*state)->players; !!kp; kp = kp->next ) {
XP_FREEP( dutil->mpool, &kp->name );
XP_FREE( dutil->mpool, kp );
}
XP_FREEP( dutil->mpool, state );
}
}