diff --git a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/BoardDelegate.java b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/BoardDelegate.java index 518a59967..3db623e09 100644 --- a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/BoardDelegate.java +++ b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/BoardDelegate.java @@ -1828,22 +1828,6 @@ public class BoardDelegate extends DelegateBase } } - @Override - public void setIsServer( boolean isServer ) - { - Log.d( TAG, "setIsServer(isServer=%b)", isServer ); - DeviceRole newRole = isServer? DeviceRole.SERVER_ISSERVER - : DeviceRole.SERVER_ISCLIENT; - if ( newRole != m_gi.serverRole ) { - m_gi.serverRole = newRole; - if ( !isServer ) { - handleViaThread( JNICmd.CMD_SWITCHCLIENT ); - } - } else { - Log.d( TAG, "setIsServer(): no change" ); - } - } - @Override public void bonusSquareHeld( int bonus ) { diff --git a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/jni/JNIThread.java b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/jni/JNIThread.java index b0dbb5163..2d4094301 100644 --- a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/jni/JNIThread.java +++ b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/jni/JNIThread.java @@ -60,7 +60,6 @@ public class JNIThread extends Thread implements AutoCloseable { CMD_INVALALL, CMD_LAYOUT, CMD_START, - CMD_SWITCHCLIENT, CMD_RESET, CMD_SAVE, CMD_DO, @@ -524,12 +523,6 @@ public class JNIThread extends Thread implements AutoCloseable { draw = tryConnect( m_jniGamePtr, m_gi ); break; - case CMD_SWITCHCLIENT: - XwJNI.server_reset( m_jniGamePtr ); - XwJNI.server_initClientConnection( m_jniGamePtr ); - draw = XwJNI.server_do( m_jniGamePtr ); - break; - case CMD_DO: if ( nextSame( JNICmd.CMD_DO ) ) { continue; diff --git a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/jni/UtilCtxt.java b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/jni/UtilCtxt.java index ef8784c2e..44bf206d7 100644 --- a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/jni/UtilCtxt.java +++ b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/jni/UtilCtxt.java @@ -61,7 +61,6 @@ public interface UtilCtxt { void requestTime(); void remSelected(); void timerSelected( boolean inDuplicateMode, boolean canPause ); - void setIsServer( boolean isServer ); void informWordsBlocked( int nWords, String words, String dict ); void bonusSquareHeld( int bonus ); diff --git a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/jni/UtilCtxtImpl.java b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/jni/UtilCtxtImpl.java index 60d055d7b..e8104120c 100644 --- a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/jni/UtilCtxtImpl.java +++ b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/jni/UtilCtxtImpl.java @@ -79,12 +79,14 @@ public class UtilCtxtImpl implements UtilCtxt { @Override public void setTimer( int why, int when, int handle ) { + Log.e( TAG, "setTimer(%d) not doing anything...", why ); subclassOverride( "setTimer" ); } @Override public void clearTimer( int why ) { + Log.e( TAG, "setTimer(%d) not doing anything...", why ); subclassOverride( "clearTimer" ); } @@ -100,13 +102,6 @@ public class UtilCtxtImpl implements UtilCtxt { subclassOverride( "timerSelected" ); } - @Override - public void setIsServer( boolean isServer ) - { - subclassOverride( "setIsServer" ); - Assert.failDbg(); - } - @Override public void informWordsBlocked( int nWords, String words, String dict ) { diff --git a/xwords4/android/jni/utilwrapper.c b/xwords4/android/jni/utilwrapper.c index f5ec4293f..2515d9f94 100644 --- a/xwords4/android/jni/utilwrapper.c +++ b/xwords4/android/jni/utilwrapper.c @@ -703,16 +703,6 @@ and_util_addrChange( XW_UtilCtxt* uc, XWEnv xwe, // LOG_FUNC(); } -static void -and_util_setIsServer( XW_UtilCtxt* uc, XWEnv xwe, XP_Bool isServer ) -{ - /* Change both the C and Java structs, which need to stay in sync */ - uc->gameInfo->serverRole = isServer? SERVER_ISSERVER : SERVER_ISCLIENT; - UTIL_CBK_HEADER( "setIsServer", "(Z)V" ); - (*env)->CallVoidMethod( env, util->jutil, mid, isServer ); - UTIL_CBK_TAIL(); -} - static void and_util_informWordsBlocked( XW_UtilCtxt* uc, XWEnv xwe, XP_U16 nBadWords, XWStreamCtxt* words, const XP_UCHAR* dict ) @@ -975,7 +965,6 @@ makeUtil( MPFORMAL JNIEnv* env, #ifndef XWFEATURE_STANDALONE_ONLY SET_PROC(informMissing); SET_PROC(addrChange); - SET_PROC(setIsServer); #endif #ifdef XWFEATURE_SEARCHLIMIT SET_PROC(getTraySearchLimits); diff --git a/xwords4/android/jni/xwjni.c b/xwords4/android/jni/xwjni.c index 727671a88..d10c84eb2 100644 --- a/xwords4/android/jni/xwjni.c +++ b/xwords4/android/jni/xwjni.c @@ -1221,6 +1221,7 @@ struct _JNIState { #define XWJNI_START_GLOBALS() \ XWJNI_START() \ AndGameGlobals* globals = &state->globals; \ + XP_USE(globals); /*no warnings */ \ #define XWJNI_END() \ } \ diff --git a/xwords4/common/comms.c b/xwords4/common/comms.c index f07f1639b..234849529 100644 --- a/xwords4/common/comms.c +++ b/xwords4/common/comms.c @@ -110,6 +110,10 @@ struct CommsCtxt { AddressRecord* recs; /* return addresses */ TransportProcs procs; + + RoleChangeProc rcProc; + void* rcClosure; + XP_U32 xportFlags; #ifdef COMMS_HEARTBEAT XP_U32 lastMsgRcd; @@ -355,7 +359,9 @@ CommsCtxt* comms_make( MPFORMAL XWEnv xwe, XW_UtilCtxt* util, XP_Bool isServer, XP_U16 XP_UNUSED_RELAY(nPlayersHere), XP_U16 XP_UNUSED_RELAY(nPlayersTotal), - const TransportProcs* procs, XP_U16 forceChannel + const TransportProcs* procs, + RoleChangeProc rcp, void* rcClosure, + XP_U16 forceChannel #ifdef SET_GAMESEED , XP_U16 gameSeed #endif @@ -379,6 +385,10 @@ comms_make( MPFORMAL XWEnv xwe, XW_UtilCtxt* util, XP_Bool isServer, comms->xportFlags = comms->procs.flags; #endif } + XP_ASSERT( rcp ); + comms->rcProc = rcp; + comms->rcClosure = rcClosure; + comms->dutil = util_getDevUtilCtxt( util, xwe ); comms->util = util; comms->dutil = util_getDevUtilCtxt( util, xwe ); @@ -648,8 +658,11 @@ addrFromStream( CommsAddrRec* addrP, XWStreamCtxt* stream ) } CommsCtxt* -comms_makeFromStream( MPFORMAL XWEnv xwe, XWStreamCtxt* stream, XW_UtilCtxt* util, - const TransportProcs* procs, XP_U16 forceChannel ) +comms_makeFromStream( MPFORMAL XWEnv xwe, XWStreamCtxt* stream, + XW_UtilCtxt* util, + const TransportProcs* procs, + RoleChangeProc rcp, void* rcClosure, + XP_U16 forceChannel ) { XP_U16 nPlayersHere, nPlayersTotal; AddressRecord** prevsAddrNext; @@ -670,8 +683,8 @@ comms_makeFromStream( MPFORMAL XWEnv xwe, XWStreamCtxt* stream, XW_UtilCtxt* uti nPlayersTotal = 0; } CommsCtxt* comms = comms_make( MPPARM(mpool) xwe, util, isServer, - nPlayersHere, nPlayersTotal, procs, - forceChannel + nPlayersHere, nPlayersTotal, procs, + rcp, rcClosure, forceChannel #ifdef SET_GAMESEED , 0 #endif @@ -1768,8 +1781,11 @@ got_connect_cmd( CommsCtxt* comms, XWEnv xwe, XWStreamCtxt* stream, if ( isServer != comms->isServer ) { XP_LOGFF( "becoming%s a server", isServer ? "" : " NOT" ); comms->isServer = isServer; - util_setIsServer( comms->util, xwe, comms->isServer ); - +#ifdef DEBUG + XP_U16 queueLen = comms->queueLen; +#endif + (*comms->rcProc)( xwe, comms->rcClosure, !isServer ); + XP_ASSERT( queueLen == comms->queueLen ); /* callback should not send!!! */ reset_internal( comms, xwe, isServer, comms->rr.nPlayersHere, comms->rr.nPlayersTotal, XP_FALSE ); } @@ -2732,7 +2748,8 @@ comms_getStats( CommsCtxt* comms, XWStreamCtxt* stream ) } XP_SNPRINTF( (XP_UCHAR*)buf, sizeof(buf), - (XP_UCHAR*)"msg queue len: %d; have %d channels\n", + (XP_UCHAR*)"role: %s; msg queue len: %d; have %d channels\n", + comms->isServer ? "host" : "guest", comms->queueLen, nChannels ); stream_catString( stream, buf ); diff --git a/xwords4/common/comms.h b/xwords4/common/comms.h index b95fe125f..21ff0f638 100644 --- a/xwords4/common/comms.h +++ b/xwords4/common/comms.h @@ -102,6 +102,7 @@ typedef void (*RelayRequestJoinProc)( XWEnv xwe, void* closure, const XP_UCHAR* #endif typedef void (*MsgCountChange)( XWEnv xwe, void* closure, XP_U16 msgCount ); +typedef void (*RoleChangeProc)( XWEnv xwe, void* closure, XP_Bool amNowGuest ); typedef enum { COMMS_XPORT_FLAGS_NONE = 0 @@ -138,7 +139,9 @@ typedef struct _TransportProcs { CommsCtxt* comms_make( MPFORMAL XWEnv xwe, XW_UtilCtxt* util, XP_Bool isServer, XP_U16 nPlayersHere, XP_U16 nPlayersTotal, - const TransportProcs* procs, XP_U16 forceChannel + const TransportProcs* procs, + RoleChangeProc rcp, void* rcClosure, + XP_U16 forceChannel #ifdef SET_GAMESEED ,XP_U16 gameSeed #endif @@ -187,6 +190,7 @@ XP_Bool comms_getIsServer( const CommsCtxt* comms ); CommsCtxt* comms_makeFromStream( MPFORMAL XWEnv xwe, XWStreamCtxt* stream, XW_UtilCtxt* util, const TransportProcs* procs, + RoleChangeProc rcp, void* rcClosure, XP_U16 forceChannel ); void comms_start( CommsCtxt* comms, XWEnv xwe ); void comms_stop( CommsCtxt* comms, XWEnv xwe ); diff --git a/xwords4/common/game.c b/xwords4/common/game.c index b6da2c7aa..32c511768 100644 --- a/xwords4/common/game.c +++ b/xwords4/common/game.c @@ -98,6 +98,14 @@ timerChangeListener( XWEnv xwe, void* data, const XP_U32 gameID, gameID, oldVal, newVal ); } +static void +onRoleChanged( XWEnv xwe, void* closure, XP_Bool amNowGuest ) +{ + XP_ASSERT( amNowGuest ); + XWGame* game = (XWGame*)closure; + server_onRoleChanged( game->server, xwe, amNowGuest ); +} + static void setListeners( XWGame* game, const CommonPrefs* cp ) { @@ -136,7 +144,8 @@ game_makeNewGame( MPFORMAL XWEnv xwe, XWGame* game, CurGameInfo* gi, game->comms = comms_make( MPPARM(mpool) xwe, util, gi->serverRole != SERVER_ISCLIENT, nPlayersHere, nPlayersTotal, - procs, gi->forceChannel + procs, onRoleChanged, game, + gi->forceChannel #ifdef SET_GAMESEED , gameSeed #endif @@ -191,6 +200,7 @@ game_reset( MPFORMAL XWGame* game, XWEnv xwe, CurGameInfo* gi, XW_UtilCtxt* util game->comms = comms_make( MPPARM(mpool) xwe, util, gi->serverRole != SERVER_ISCLIENT, nPlayersHere, nPlayersTotal, procs, + onRoleChanged, game, gi->forceChannel #ifdef SET_GAMESEED , 0 @@ -281,7 +291,8 @@ game_makeFromStream( MPFORMAL XWEnv xwe, XWStreamCtxt* stream, XWGame* game, if ( hasComms ) { game->comms = comms_makeFromStream( MPPARM(mpool) xwe, stream, util, - procs, gi->forceChannel ); + procs, onRoleChanged, game, + gi->forceChannel ); } else { game->comms = NULL; } @@ -301,6 +312,11 @@ game_makeFromStream( MPFORMAL XWEnv xwe, XWStreamCtxt* stream, XWGame* game, success = XP_TRUE; } while( XP_FALSE ); } + + if ( success && !!game && !!game->comms ) { + XP_ASSERT( comms_getIsServer(game->comms) == server_getIsServer(game->server) ); + } + return success; } /* game_makeFromStream */ diff --git a/xwords4/common/server.c b/xwords4/common/server.c index fc597d1b1..72fe79a79 100644 --- a/xwords4/common/server.c +++ b/xwords4/common/server.c @@ -217,6 +217,7 @@ getStateStr( XW_State st ) switch( st ) { CASESTR(XWSTATE_NONE); CASESTR(XWSTATE_BEGIN); + CASESTR(XWSTATE_NEWCLIENT); CASESTR(XWSTATE_NEED_SHOWSCORE); CASESTR(XWSTATE_RECEIVED_ALL_REG); CASESTR(XWSTATE_NEEDSEND_BADWORD_INFO); @@ -226,6 +227,7 @@ getStateStr( XW_State st ) CASESTR(XWSTATE_INTURN); CASESTR(XWSTATE_GAMEOVER); default: + XP_ASSERT(0); return "unknown"; } # undef CASESTR @@ -289,6 +291,10 @@ amServer( const ServerCtxt* server ) return result; } +#ifdef DEBUG +XP_Bool server_getIsServer( const ServerCtxt* server ) { return amServer(server); } +#endif + static void initServer( ServerCtxt* server, XWEnv xwe ) { @@ -558,6 +564,21 @@ server_writeToStream( const ServerCtxt* server, XWStreamCtxt* stream ) writeStreamIf( stream, server->nv.prevWordsStream ); } /* server_writeToStream */ +void +server_onRoleChanged( ServerCtxt* server, XWEnv xwe, XP_Bool amNowGuest ) +{ + if ( amNowGuest == amServer(server) ) { /* do I need to change */ + XP_ASSERT ( amNowGuest ); + if ( amNowGuest ) { + server->vol.gi->serverRole = SERVER_ISCLIENT; + server_reset( server, xwe, server->vol.comms ); + + SETSTATE( server, XWSTATE_NEWCLIENT ); + util_requestTime( server->vol.util, xwe ); + } + } +} + static void cleanupServer( ServerCtxt* server, XWEnv xwe ) { @@ -1630,6 +1651,12 @@ server_do( ServerCtxt* server, XWEnv xwe ) } break; + case XWSTATE_NEWCLIENT: + XP_ASSERT( !amServer( server ) ); + SETSTATE( server, XWSTATE_NONE ); /* server_initClientConnection expects this */ + server_initClientConnection( server, xwe ); + break; + case XWSTATE_NEEDSEND_BADWORD_INFO: XP_ASSERT( server->vol.gi->serverRole == SERVER_ISSERVER ); badWordMoveUndoAndTellUser( server, xwe, &server->illegalWordInfo ); diff --git a/xwords4/common/server.h b/xwords4/common/server.h index 058c679d8..8346b3b17 100644 --- a/xwords4/common/server.h +++ b/xwords4/common/server.h @@ -43,6 +43,7 @@ void server_reset( ServerCtxt* server, XWEnv xwe, CommsCtxt* comms ); void server_destroy( ServerCtxt* server, XWEnv xwe ); void server_prefsChanged( ServerCtxt* server, const CommonPrefs* cp ); +void server_onRoleChanged( ServerCtxt* server, XWEnv xwe, XP_Bool amNowGuest ); typedef void (*TurnChangeListener)( XWEnv xwe, void* data ); void server_setTurnChangeListener( ServerCtxt* server, TurnChangeListener tl, @@ -134,6 +135,10 @@ void server_writeFinalScores( ServerCtxt* server, XWEnv xwe, XWStreamCtxt* strea XP_U16 server_figureFinishBonus( const ServerCtxt* server, XP_U16 turn ); #endif +#ifdef DEBUG +XP_Bool server_getIsServer( const ServerCtxt* server ); +#endif + #ifdef CPLUS } #endif diff --git a/xwords4/common/states.h b/xwords4/common/states.h index 3adc1778e..05cebf819 100644 --- a/xwords4/common/states.h +++ b/xwords4/common/states.h @@ -23,7 +23,7 @@ enum { XWSTATE_NONE, /* 0 */ XWSTATE_BEGIN, /* 1 */ - __UNUSED1, /* was XWSTATE_POOL_INITED */ + XWSTATE_NEWCLIENT, /* was a host, now a reset client */ XWSTATE_NEED_SHOWSCORE, /* client-only */ __XWSTATE_WAITING_ALL_REG, /* 4 (unused) */ XWSTATE_RECEIVED_ALL_REG, /* includes waiting for dict from server */ @@ -34,7 +34,7 @@ enum { XWSTATE_INTURN, /* 10 */ XWSTATE_GAMEOVER, /* 11 */ - XWSTATE_LAST /* for asserts only :-) */ + XWSTATE_LAST, /* for asserts only :-) */ }; typedef XP_U8 XW_State; #define XWSTATE_NBITS 4 diff --git a/xwords4/common/util.h b/xwords4/common/util.h index 538c3de70..e04d855c8 100644 --- a/xwords4/common/util.h +++ b/xwords4/common/util.h @@ -171,7 +171,6 @@ typedef struct UtilVtable { XP_U16 nMissing ); void (*m_util_addrChange)( XW_UtilCtxt* uc, XWEnv xwe, const CommsAddrRec* oldAddr, const CommsAddrRec* newAddr ); - void (*m_util_setIsServer)(XW_UtilCtxt* uc, XWEnv xwe, XP_Bool isServer ); #endif void (*m_util_informWordsBlocked)( XW_UtilCtxt* uc, XWEnv xwe, XP_U16 nBadWords, @@ -306,8 +305,6 @@ struct XW_UtilCtxt { (uc)->vtable->m_util_informMissing((uc), (e), (is), (ct), (nd), (nm) ) # define util_addrChange( uc,e, addro, addrn ) \ (uc)->vtable->m_util_addrChange((uc), (e), (addro), (addrn)) -# define util_setIsServer( uc,e, is ) \ - (uc)->vtable->m_util_setIsServer((uc), (e), (is)) # else # define util_addrChange( uc,e, addro, addrn ) #endif diff --git a/xwords4/linux/linuxmain.c b/xwords4/linux/linuxmain.c index f65f6596b..59335a60d 100644 --- a/xwords4/linux/linuxmain.c +++ b/xwords4/linux/linuxmain.c @@ -1865,36 +1865,6 @@ linux_util_addrChange( XW_UtilCtxt* uc, XWEnv XP_UNUSED(xwe), } } -static gint -changeRolesIdle( gpointer data ) -{ - CommonGlobals* cGlobals = (CommonGlobals*)data; - ServerCtxt* server = cGlobals->game.server; - server_reset( server, NULL_XWE, cGlobals->game.comms ); - if ( SERVER_ISCLIENT == cGlobals->gi->serverRole ) { - XWStreamCtxt* stream = - mem_stream_make( MPPARM(cGlobals->util->mpool) cGlobals->params->vtMgr, - cGlobals, CHANNEL_NONE, sendOnClose ); - (void)server_initClientConnection( server, NULL_XWE, stream ); - } - (void)server_do( server, NULL_XWE ); - return 0; -} - -static void -linux_util_setIsServer( XW_UtilCtxt* uc, XWEnv XP_UNUSED(xwe),XP_Bool isServer ) -{ - XP_LOGF( "%s(isServer=%d)", __func__, isServer ); - CommonGlobals* cGlobals = (CommonGlobals*)uc->closure; - - DeviceRole newRole = isServer? SERVER_ISSERVER : SERVER_ISCLIENT; - cGlobals->params->serverRole = newRole; - cGlobals->gi->serverRole = newRole; - - (void)ADD_ONETIME_IDLE( changeRolesIdle, cGlobals ); - XP_ASSERT( isServer == game_getIsServer( &cGlobals->game ) ); -} - #endif unsigned int @@ -2552,7 +2522,6 @@ setupLinuxUtilCallbacks( XW_UtilCtxt* util ) #ifndef XWFEATURE_STANDALONE_ONLY SET_PROC(informMissing); SET_PROC(addrChange); - SET_PROC(setIsServer); #endif SET_PROC(formatPauseHistory); SET_PROC(setTimer);