From 2f91ff1f78d81e0d4ae0dd93b3ed5c3d81e6e176 Mon Sep 17 00:00:00 2001 From: Eric House Date: Sun, 28 Jul 2024 08:46:01 -0700 Subject: [PATCH] display known player names for pending invites When an invitation is pending for a player in GameSummary or scoreboard, show " invited" instead of "remote missing." --- .../org/eehouse/android/xw4/BoardDelegate.kt | 8 +-- .../java/org/eehouse/android/xw4/GameUtils.kt | 11 ++++ .../java/org/eehouse/android/xw4/MQTTUtils.kt | 6 +-- .../eehouse/android/xw4/jni/GameSummary.kt | 20 ++++---- .../java/org/eehouse/android/xw4/jni/XwJNI.kt | 3 ++ xwords4/android/jni/xwjni.c | 18 +++++++ xwords4/common/comms.c | 51 +++++++++++++++++-- xwords4/common/comms.h | 6 +++ xwords4/common/knownplyr.c | 14 +++++ xwords4/common/knownplyr.h | 2 + xwords4/common/server.c | 42 +++++++++++++-- xwords4/common/server.h | 4 ++ xwords4/common/strutils.c | 8 +++ xwords4/common/strutils.h | 3 ++ 14 files changed, 168 insertions(+), 28 deletions(-) diff --git a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/BoardDelegate.kt b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/BoardDelegate.kt index 1a686ca3d..d96a8e8f4 100644 --- a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/BoardDelegate.kt +++ b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/BoardDelegate.kt @@ -1483,12 +1483,8 @@ class BoardDelegate(delegator: Delegator) : } } - override fun getInviteeName(plyrNum: Int): String? { - return if (null == mSummary) null else mSummary!!.summarizePlayer( - mActivity, - mRowid, - plyrNum - ) + override fun getInviteeName(index: Int): String? { + return mSummary?.summarizePlayer( mActivity, mRowid, index) } override fun playerScoreHeld(player: Int) { diff --git a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/GameUtils.kt b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/GameUtils.kt index 4de42d55c..d23e0e91b 100644 --- a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/GameUtils.kt +++ b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/GameUtils.kt @@ -580,6 +580,17 @@ object GameUtils { return rowid } + fun inviteeName(context: Context, rowid: Long, playerPosn: Int): String? { + var result = + GameWrapper.make(context, rowid).use { gw -> + gw?.let { + val name = XwJNI.server_inviteeName(it.gamePtr(), playerPosn) + name + } + } + return result + } + fun handleInvitation( context: Context, nli: NetLaunchInfo, procs: TransportProcs? diff --git a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/MQTTUtils.kt b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/MQTTUtils.kt index 0f2c6b26a..c40eff025 100644 --- a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/MQTTUtils.kt +++ b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/MQTTUtils.kt @@ -468,8 +468,8 @@ object MQTTUtils { .callback(this@Conn) .send() .whenComplete{ ack, throwable -> - Log.d( TAG, "$this.whenComplete(); topic=$mTopic, " - + "ack=$ack, err=$throwable") + // Log.d( TAG, "$this.whenComplete(); topic=$mTopic, " + // + "ack=$ack, err=$throwable") } } } @@ -486,7 +486,7 @@ object MQTTUtils { .retain(true) .send() .whenComplete { mqtt3Publish, throwable -> - Log.d(TAG, "whenComplete(): $mqtt3Publish") + // Log.d(TAG, "whenComplete(): $mqtt3Publish") mStats.addSend(throwable == null) if (throwable != null) { // Handle failure to publish diff --git a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/jni/GameSummary.kt b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/jni/GameSummary.kt index 68897d5d3..24b219df7 100644 --- a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/jni/GameSummary.kt +++ b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/jni/GameSummary.kt @@ -29,6 +29,7 @@ import java.io.Serializable import org.eehouse.android.xw4.Assert import org.eehouse.android.xw4.BuildConfig import org.eehouse.android.xw4.DBUtils +import org.eehouse.android.xw4.GameUtils import org.eehouse.android.xw4.Log import org.eehouse.android.xw4.R import org.eehouse.android.xw4.Utils @@ -199,7 +200,8 @@ class GameSummary : Serializable { val prev = nxt nxt = playersStr.indexOf(sep, nxt) val name = - if (-1 == nxt) playersStr.substring(prev) else playersStr.substring(prev, nxt) + if (-1 == nxt) playersStr.substring(prev) + else playersStr.substring(prev, nxt) m_players!![ii] = name if (-1 == nxt) { break @@ -372,16 +374,12 @@ class GameSummary : Serializable { if (!isLocal(indx)) { val isMissing = 0 != ((1 shl indx) and missingPlayers) if (isMissing) { - val si = DBUtils.getInvitesFor(context, rowid) - var kp: String? = null - if (null != si) { - kp = si.getKPName(context) - } - player = if (null == kp) { - LocUtils.getString(context, R.string.missing_player) - } else { - LocUtils.getString(context, R.string.invitee_fmt, kp) - } + val kp = GameUtils.inviteeName(context, rowid, indx) + player = + if (TextUtils.isEmpty(kp)) + LocUtils.getString(context, R.string.missing_player) + else + LocUtils.getString(context, R.string.invitee_fmt, kp) } else { formatID = R.string.str_nonlocal_name_fmt } diff --git a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/jni/XwJNI.kt b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/jni/XwJNI.kt index 5ceeede6f..960d7c481 100644 --- a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/jni/XwJNI.kt +++ b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/jni/XwJNI.kt @@ -786,6 +786,9 @@ class XwJNI private constructor() { @JvmStatic external fun server_endGame(gamePtr: GamePtr?) + @JvmStatic + external fun server_inviteeName(gamePtr: GamePtr?, channelNo: Int): String? + // hybrid to save work @JvmStatic external fun board_server_prefsChanged( diff --git a/xwords4/android/jni/xwjni.c b/xwords4/android/jni/xwjni.c index 0e7d3bc21..71810c3b1 100644 --- a/xwords4/android/jni/xwjni.c +++ b/xwords4/android/jni/xwjni.c @@ -2835,6 +2835,24 @@ Java_org_eehouse_android_xw4_jni_XwJNI_server_1endGame XWJNI_END(); } +JNIEXPORT jstring JNICALL +Java_org_eehouse_android_xw4_jni_XwJNI_server_1inviteeName +( JNIEnv* env, jclass C, GamePtrType gamePtr, jint channel ) +{ + jstring result = NULL; + XWJNI_START(gamePtr); + XP_ASSERT( !!state->game.server ); + XP_UCHAR buf[32] = {0}; + XP_U16 len = VSIZE(buf); + server_inviteeName( state->game.server, env, channel, buf, &len ); + if ( !!buf[0] ) { + result = (*env)->NewStringUTF( env, buf ); + } + XWJNI_END(); + return result; +} + + JNIEXPORT void JNICALL Java_org_eehouse_android_xw4_jni_XwJNI_board_1pause ( JNIEnv* env, jclass C, GamePtrType gamePtr, jstring jmsg ) { diff --git a/xwords4/common/comms.c b/xwords4/common/comms.c index b21db3db1..c3a5736b7 100644 --- a/xwords4/common/comms.c +++ b/xwords4/common/comms.c @@ -1836,7 +1836,7 @@ getInvitedProc( MsgQueueElem* elem, void* closure ) if ( IS_INVITE( elem ) ) { GetInvitedData* gidp = (GetInvitedData*)closure; XP_PlayerAddr channelNo = elem->channelNo & CHANNEL_MASK; - XP_LOGFF( "got invite on channel %d", channelNo ); + XP_LOGFF( "found invite on channel %d", channelNo ); XP_U16 thisBit = 1 << channelNo; XP_ASSERT( 0 == (thisBit & gidp->allBits) ); /* should be no dupes */ if ( 0 == (thisBit & gidp->allBits) ) { @@ -1857,6 +1857,51 @@ comms_getInvited( RELCONST CommsCtxt* comms, XP_U16* nInvites ) // LOG_RETURNF( "%d", *nInvites ); COMMS_MUTEX_UNLOCK(); } + +typedef struct _GetNamesData { + const CommsCtxt* comms; + XWEnv xwe; + InviteeNames* names; +} GetNamesData; + +static ForEachAct +getNamesProc( MsgQueueElem* elem, void* closure ) +{ + LOG_FUNC(); + if ( IS_INVITE( elem ) ) { + GetNamesData* gndp = (GetNamesData*)closure; + XP_PlayerAddr channelNo = elem->channelNo & CHANNEL_MASK; + XP_LOGFF( "channelNo: %d", channelNo ); + + const AddressRecord* rec = getRecordFor( gndp->comms, channelNo ); + XP_ASSERT( !!rec ); + const CommsAddrRec* addr = &rec->addr; + const XP_UCHAR* name = + kplr_nameForAddress( gndp->comms->dutil, gndp->xwe, addr ); + InviteeNames* names = gndp->names; + if ( !!name ) { + XP_STRCAT( names->name[names->count], name ); + XP_LOGFF( "copied name %s to pos %d (pos %d)", name, + channelNo, names->count ); + } + ++names->count; + } + return FEA_OK; +} + +void +comms_inviteeNames( CommsCtxt* comms, XWEnv xwe, + InviteeNames* names ) +{ + COMMS_MUTEX_LOCK(comms); + GetNamesData gnd = { + .comms = comms, + .xwe = xwe, + .names = names, + }; + forEachElem( (CommsCtxt*)comms, getNamesProc, &gnd ); + COMMS_MUTEX_UNLOCK(); +} #endif /* Send a message using the sequentially next MsgID. Save the message so @@ -3079,7 +3124,7 @@ parseBeefHeader( CommsCtxt* comms, XWStreamCtxt* stream, HeaderStuff* stuff ) && stream_gotU32( stream, &stuff->msgID ) && stream_gotU32( stream, &stuff->lastMsgRcd ); - LOG_RETURNF( "%s", boolToStr(messageValid) ); + // LOG_RETURNF( "%s", boolToStr(messageValid) ); return messageValid; } @@ -3111,7 +3156,7 @@ parseSmallHeader( CommsCtxt* comms, XWStreamCtxt* msgStream, stream_destroy( hdrStream ); } - LOG_RETURNF( "%s", boolToStr(messageValid) ); + // LOG_RETURNF( "%s", boolToStr(messageValid) ); COMMS_MUTEX_UNLOCK(); return messageValid; } diff --git a/xwords4/common/comms.h b/xwords4/common/comms.h index c96865f44..70574cfaf 100644 --- a/xwords4/common/comms.h +++ b/xwords4/common/comms.h @@ -207,6 +207,12 @@ void addrToStream( XWStreamCtxt* stream, const CommsAddrRec* addr ); void comms_invite( CommsCtxt* comms, XWEnv xwe, const NetLaunchInfo* nli, const CommsAddrRec* destAddr, XP_Bool sendNow ); void comms_getInvited( RELCONST CommsCtxt* comms, XP_U16* nInvites ); +typedef struct _InviteeNames { + XP_UCHAR name[4][32]; + XP_U16 count; +} InviteeNames; +void comms_inviteeNames( CommsCtxt* comms, XWEnv xwe, InviteeNames* names ); + #endif XP_S16 comms_send( CommsCtxt* comms, XWEnv xwe, XWStreamCtxt* stream ); XP_S16 comms_resendAll( CommsCtxt* comms, XWEnv xwe, CommsConnType filter, diff --git a/xwords4/common/knownplyr.c b/xwords4/common/knownplyr.c index 11b065564..cb863e6c0 100644 --- a/xwords4/common/knownplyr.c +++ b/xwords4/common/knownplyr.c @@ -434,6 +434,20 @@ kplr_nameForMqttDev( XW_DUtilCtxt* dutil, XWEnv xwe, return ms.name; } +const XP_UCHAR* +kplr_nameForAddress( XW_DUtilCtxt* dutil, XWEnv xwe, + const CommsAddrRec* addr ) +{ + const XP_UCHAR* result = NULL; + if ( addr_hasType( addr, COMMS_CONN_MQTT ) ) { + result = kplr_nameForMqttDev( dutil, xwe, + &addr->u.mqtt.devID ); + } else { + XP_ASSERT(0); /* FIXME */ + } + return result; +} + static void freeKP( XW_DUtilCtxt* XP_UNUSED_DBG(dutil), KnownPlayer* kp ) { diff --git a/xwords4/common/knownplyr.h b/xwords4/common/knownplyr.h index 4aa71f9c0..4ab246375 100644 --- a/xwords4/common/knownplyr.h +++ b/xwords4/common/knownplyr.h @@ -45,6 +45,8 @@ XP_Bool kplr_getAddr( XW_DUtilCtxt* dutil, XWEnv xwe, const XP_UCHAR* name, CommsAddrRec* addr, XP_U32* lastMod ); const XP_UCHAR* kplr_nameForMqttDev( XW_DUtilCtxt* dutil, XWEnv xwe, const MQTTDevID* devID ); +const XP_UCHAR* kplr_nameForAddress( XW_DUtilCtxt* dutil, XWEnv xwe, + const CommsAddrRec* addr ); KP_Rslt kplr_renamePlayer( XW_DUtilCtxt* dutil, XWEnv xwe, const XP_UCHAR* oldName, const XP_UCHAR* newName ); diff --git a/xwords4/common/server.c b/xwords4/common/server.c index a75f43e05..872e01b92 100644 --- a/xwords4/common/server.c +++ b/xwords4/common/server.c @@ -486,7 +486,7 @@ getNV( XWStreamCtxt* stream, ServerNonvolatiles* nv, XP_U16 nPlayers ) if ( STREAM_SAVE_PREVWORDS < version ) { nv->streamVersion = stream_getU8 ( stream ); } - /* XP_LOGF( "%s: read streamVersion: 0x%x", __func__, nv->streamVersion ); */ + /* XP_LOGFF( "read streamVersion: 0x%x", nv->streamVersion ); */ #endif if ( version >= STREAM_VERS_DUPLICATE ) { @@ -527,7 +527,7 @@ putNV( XWStreamCtxt* stream, const ServerNonvolatiles* nv, XP_U16 nPlayers ) } #ifdef STREAM_VERS_BIGBOARD stream_putU8( stream, nv->streamVersion ); - /* XP_LOGF( "%s: wrote streamVersion: 0x%x", __func__, nv->streamVersion ); */ + /* XP_LOGFF( "wrote streamVersion: 0x%x", nv->streamVersion ); */ #endif for ( int ii = 0; ii < nPlayers; ++ii ) { @@ -2723,7 +2723,7 @@ trayAllowsMoves( ServerCtxt* server, XWEnv xwe, XP_U16 turn, XP_MEMCPY( tmpTiles, &tray->tiles[0], nInTray * sizeof(tmpTiles[0]) ); XP_MEMCPY( &tmpTiles[nInTray], &tiles[0], nTiles * sizeof(tmpTiles[0]) ); - /* XP_LOGF( "%s(nTiles=%d)", __func__, nTiles ); */ + /* XP_LOGFF( "%s(nTiles=%d)", __func__, nTiles ); */ EngineCtxt* tmpEngine = NULL; EngineCtxt* engine = server_getEngineFor( server, turn ); if ( !engine ) { @@ -3702,7 +3702,7 @@ dupe_checkWhatsDone( const ServerCtxt* server, XP_Bool amHost, } } - // XP_LOGF( "%s(): allDone: %d; allLocalsDone: %d", __func__, allDone, allLocalsDone ); + // XP_LOGFF( "allDone: %d; allLocalsDone: %d", allDone, allLocalsDone ); *allDoneP = allDone; *allLocalsDoneP = allLocalsDone; } @@ -4018,7 +4018,7 @@ server_isPlayersTurn( const ServerCtxt* server, XP_U16 turn ) result = turn == server_getCurrentTurn( server, NULL ); } - // XP_LOGF( "%s(%d) => %d", __func__, turn, result ); + // XP_LOGFF( "(%d) => %d", turn, result ); return result; } @@ -4686,6 +4686,38 @@ server_endGame( ServerCtxt* server, XWEnv xwe ) } } /* server_endGame */ +void +server_inviteeName( const ServerCtxt* server, + XWEnv xwe, XP_U16 playerPosn, + XP_UCHAR* buf, XP_U16* bufLen ) +{ + int nameIndx = 0; + for ( int ii = 0; ii <= playerPosn; ++ii ) { + const ServerPlayer* sp = &server->srvPlyrs[ii]; + if ( -1 == sp->deviceIndex ) { /* not yet claimed */ + if ( playerPosn == ii ) { + + CommsCtxt* comms = server->vol.comms; + InviteeNames names = {0}; + comms_inviteeNames( comms, xwe, &names ); + + if ( nameIndx < names.count ) { + XP_LOGFF( "got a match: player %d for channel %d; name: \"%s\"", + playerPosn, nameIndx, names.name[nameIndx] ); + *bufLen = XP_SNPRINTF( buf, *bufLen, names.name[nameIndx], playerPosn ); + } else { + XP_LOGFF( "expected %dth name but found only %d", + nameIndx, names.count ); + } + break; + } + ++nameIndx; + } + } + + XP_LOGFF( "(%d) => %s", playerPosn, buf ); +} + /* If game is about to end because one player's out of tiles, we don't want to * keep trying to move. Note that in duplicate mode if ANY player has tiles * the answer's yes. */ diff --git a/xwords4/common/server.h b/xwords4/common/server.h index b0d43af64..46171cbe8 100644 --- a/xwords4/common/server.h +++ b/xwords4/common/server.h @@ -117,6 +117,10 @@ XP_Bool server_commitTrade( ServerCtxt* server, XWEnv xwe, /* call this when user wants to end the game */ void server_endGame( ServerCtxt* server, XWEnv xwe ); +void server_inviteeName( const ServerCtxt* server, + XWEnv xwe, XP_U16 channelNo, + XP_UCHAR* buf, XP_U16* bufLen ); + /* called when running as either client or server */ XP_Bool server_receiveMessage( ServerCtxt* server, XWEnv xwe, XWStreamCtxt* incoming ); diff --git a/xwords4/common/strutils.c b/xwords4/common/strutils.c index 045ac0ee9..533092163 100644 --- a/xwords4/common/strutils.c +++ b/xwords4/common/strutils.c @@ -748,6 +748,14 @@ log_hex( const XP_U8* memp, XP_U16 len, const char* tag ) XP_LOGF( "%s", buf ); } } + +void +log_devid( const MQTTDevID* devID, const XP_UCHAR* tag ) +{ + XP_UCHAR buf[32]; + XP_SNPRINTF( buf, VSIZE(buf), MQTTDevID_FMT, *devID ); + XP_LOGFF( "%s: id: %s", tag, buf ); +} #endif #ifdef CPLUS diff --git a/xwords4/common/strutils.h b/xwords4/common/strutils.h index 4e74b2f07..19e167969 100644 --- a/xwords4/common/strutils.h +++ b/xwords4/common/strutils.h @@ -140,10 +140,13 @@ XP_Bool strToMQTTCDevID( const XP_UCHAR* str, MQTTDevID* result ); #ifdef DEBUG void assertSorted( const MoveInfo* mi ); void log_hex( const XP_U8* memp, XP_U16 len, const char* tag ); +void log_devid( const MQTTDevID* devID, const XP_UCHAR* tag ); # define LOG_HEX(m,l,t) log_hex((const XP_U8*)(m),(l),(t)) +# define LOG_DEVID(ID, TAG) log_devid((ID), (TAG)) #else # define assertSorted(mi) # define LOG_HEX(m,l,t) +# define LOG_DEVID(id, tag) #endif #ifdef CPLUS