mirror of
git://xwords.git.sourceforge.net/gitroot/xwords/xwords
synced 2025-01-27 07:58:49 +01:00
enable rematch for 3- and 4-device games
Because only the host/inviter knows the addresses of all the devices in a game it's hard for guests to rematch (unless it's a 2-device game, as they know the host's address.) So now, as part of telling guests the game is ready to play, include the addresses of other guests. It's usually only 9 bytes per device, and only happens when more than two devices are in a game.
This commit is contained in:
parent
dcc9cd553c
commit
9ca291cf0d
17 changed files with 355 additions and 202 deletions
|
@ -857,7 +857,7 @@ public class BoardDelegate extends DelegateBase
|
|||
}
|
||||
}
|
||||
|
||||
enable = m_gameOver && rematchSupported( false );
|
||||
enable = null != m_gsi && m_gsi.canRematch;
|
||||
Utils.setItemVisible( menu, R.id.board_menu_rematch, enable );
|
||||
|
||||
enable = m_gameOver && !inArchiveGroup();
|
||||
|
@ -2879,53 +2879,6 @@ public class BoardDelegate extends DelegateBase
|
|||
}
|
||||
}
|
||||
|
||||
// For now, supported if standalone or either BT or SMS used for transport
|
||||
private boolean rematchSupported( boolean showMulti )
|
||||
{
|
||||
return null != m_summary
|
||||
&& rematchSupported( showMulti ? m_activity : null,
|
||||
m_summary );
|
||||
}
|
||||
|
||||
public static boolean rematchSupported( Context context, long rowID )
|
||||
{
|
||||
GameSummary summary = GameUtils.getSummary( context, rowID, 1 );
|
||||
return null != summary && rematchSupported( null, summary );
|
||||
}
|
||||
|
||||
private static boolean rematchSupported( Context context,
|
||||
GameSummary summary )
|
||||
|
||||
{
|
||||
return rematchSupported( context, false, summary );
|
||||
}
|
||||
|
||||
private static boolean rematchSupported( Context context, boolean supported,
|
||||
GameSummary summary )
|
||||
{
|
||||
// standalone games are easy to rematch
|
||||
supported = summary.serverRole == DeviceRole.SERVER_STANDALONE;
|
||||
|
||||
if ( !supported ) {
|
||||
if ( 2 == summary.nPlayers ) {
|
||||
if ( !summary.anyMissing() ) {
|
||||
CommsConnTypeSet connTypes = summary.conTypes;
|
||||
supported = connTypes.contains( CommsConnType.COMMS_CONN_MQTT )
|
||||
|| connTypes.contains( CommsConnType.COMMS_CONN_BT )
|
||||
|| connTypes.contains( CommsConnType.COMMS_CONN_SMS )
|
||||
|| connTypes.contains( CommsConnType.COMMS_CONN_P2P );
|
||||
}
|
||||
} else if ( null != context ) {
|
||||
// show the button if people haven't dismissed the hint yet
|
||||
supported = ! XWPrefs
|
||||
.getPrefsBoolean( context,
|
||||
R.string.key_na_rematch_two_only,
|
||||
false );
|
||||
}
|
||||
}
|
||||
return supported;
|
||||
}
|
||||
|
||||
private void doRematchIf( boolean deleteAfter )
|
||||
{
|
||||
doRematchIf( GROUPID_UNSPEC, deleteAfter );
|
||||
|
@ -2942,27 +2895,12 @@ public class BoardDelegate extends DelegateBase
|
|||
GameSummary summary, CurGameInfo gi,
|
||||
GamePtr jniGamePtr, boolean deleteAfter )
|
||||
{
|
||||
boolean doIt = true;
|
||||
if ( DeviceRole.SERVER_STANDALONE == gi.serverRole ) {
|
||||
// nothing to do??
|
||||
} else if ( 2 != gi.nPlayers ) {
|
||||
Assert.assertNotNull( dlgt );
|
||||
if ( null != dlgt ) {
|
||||
dlgt.makeNotAgainBuilder( R.string.key_na_rematch_two_only,
|
||||
R.string.not_again_rematch_two_only )
|
||||
.show();
|
||||
}
|
||||
doIt = false;
|
||||
}
|
||||
|
||||
if ( doIt ) {
|
||||
String newName = summary.getRematchName( activity );
|
||||
Intent intent = GamesListDelegate
|
||||
.makeRematchIntent( activity, rowid, groupID, gi,
|
||||
summary.conTypes, newName, deleteAfter );
|
||||
if ( null != intent ) {
|
||||
activity.startActivity( intent );
|
||||
}
|
||||
String newName = summary.getRematchName( activity );
|
||||
Intent intent = GamesListDelegate
|
||||
.makeRematchIntent( activity, rowid, groupID, gi,
|
||||
summary.conTypes, newName, deleteAfter );
|
||||
if ( null != intent ) {
|
||||
activity.startActivity( intent );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -589,8 +589,6 @@ public class GameUtils {
|
|||
if ( null != gamePtrNew ) {
|
||||
rowid = saveNewGame1( context, gamePtrNew,
|
||||
groupID, gameName );
|
||||
} else {
|
||||
Assert.failDbg();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -599,7 +597,6 @@ public class GameUtils {
|
|||
}
|
||||
|
||||
Log.d( TAG, "makeRematch() => %d", rowid );
|
||||
Assert.assertTrueNR( DBUtils.ROWID_NOTFOUND != rowid );
|
||||
return rowid;
|
||||
}
|
||||
|
||||
|
|
|
@ -1750,14 +1750,6 @@ public class GamesListDelegate extends ListDelegateBase
|
|||
.contains( XWPrefs.getDefaultNewGameGroup( m_activity ) );
|
||||
Utils.setItemVisible( menu, R.id.games_group_default, enable );
|
||||
|
||||
// Rematch supported if there's one game selected
|
||||
enable = 1 == nGamesSelected;
|
||||
if ( enable ) {
|
||||
enable = BoardDelegate.rematchSupported( m_activity,
|
||||
getSelRowIDs()[0] );
|
||||
}
|
||||
Utils.setItemVisible( menu, R.id.games_game_rematch, enable );
|
||||
|
||||
// Move up/down enabled for groups if not the top-most or bottommost
|
||||
// selected
|
||||
enable = 1 == nGroupsSelected;
|
||||
|
@ -1991,8 +1983,6 @@ public class GamesListDelegate extends ListDelegateBase
|
|||
|
||||
if ( null != gameItem ) {
|
||||
long rowID = gameItem.getRowID();
|
||||
enable = BoardDelegate.rematchSupported( m_activity, rowID );
|
||||
Utils.setItemVisible( menu, R.id.games_game_rematch, enable );
|
||||
|
||||
// Deal with possibility summary's temporarily null....
|
||||
GameSummary summary = gameItem.getSummary();
|
||||
|
|
|
@ -129,11 +129,14 @@ public class JNIThread extends Thread implements AutoCloseable {
|
|||
public boolean canTrade;
|
||||
public boolean canPause;
|
||||
public boolean canUnpause;
|
||||
public boolean canRematch;
|
||||
@Override
|
||||
public GameStateInfo clone() {
|
||||
GameStateInfo obj = null;
|
||||
GameStateInfo obj;
|
||||
try {
|
||||
obj = (GameStateInfo)super.clone();
|
||||
} catch ( CloneNotSupportedException cnse ) {
|
||||
obj = null;
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
|
|
@ -346,7 +346,10 @@ public class XwJNI {
|
|||
CommonPrefs cp, String gameName )
|
||||
{
|
||||
GamePtr gamePtrNew = initGameJNI( 0 );
|
||||
game_makeRematch( gamePtr, gamePtrNew, util, cp, gameName );
|
||||
if ( !game_makeRematch( gamePtr, gamePtrNew, util, cp, gameName ) ) {
|
||||
gamePtrNew.release();
|
||||
gamePtrNew = null;
|
||||
}
|
||||
return gamePtrNew;
|
||||
}
|
||||
|
||||
|
@ -384,10 +387,10 @@ public class XwJNI {
|
|||
CommonPrefs cp,
|
||||
TransportProcs procs );
|
||||
|
||||
private static native void game_makeRematch( GamePtr gamePtr,
|
||||
GamePtr gamePtrNew,
|
||||
UtilCtxt util, CommonPrefs cp,
|
||||
String gameName );
|
||||
private static native boolean game_makeRematch( GamePtr gamePtr,
|
||||
GamePtr gamePtrNew,
|
||||
UtilCtxt util, CommonPrefs cp,
|
||||
String gameName );
|
||||
|
||||
private static native boolean game_makeFromInvite( GamePtr gamePtr, NetLaunchInfo nli,
|
||||
UtilCtxt util,
|
||||
|
|
|
@ -1495,11 +1495,12 @@ initGameGlobals( JNIEnv* env, JNIState* state, jobject jutil, jobject jprocs )
|
|||
globals->jniutil = state->globalJNI->jniutil;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_org_eehouse_android_xw4_jni_XwJNI_game_1makeRematch
|
||||
( JNIEnv* env, jclass C, GamePtrType gamePtr, GamePtrType gamePtrNew,
|
||||
jobject jutil, jobject jcp, jstring jGameName )
|
||||
{
|
||||
jboolean success = false;
|
||||
XWJNI_START_GLOBALS(gamePtr);
|
||||
|
||||
JNIState* oldState = state; /* state about to go out-of-scope */
|
||||
|
@ -1511,12 +1512,13 @@ Java_org_eehouse_android_xw4_jni_XwJNI_game_1makeRematch
|
|||
loadCommonPrefs( env, &cp, jcp );
|
||||
|
||||
const char* gameName = (*env)->GetStringUTFChars( env, jGameName, NULL );
|
||||
game_makeRematch( &oldState->game, env, globals->util, &cp,
|
||||
&state->game, gameName, XP_FALSE );
|
||||
success = game_makeRematch( &oldState->game, env, globals->util, &cp,
|
||||
(TransportProcs*)NULL, &state->game, gameName );
|
||||
(*env)->ReleaseStringUTFChars( env, jGameName, gameName );
|
||||
|
||||
XWJNI_END(); /* matches second XWJNI_START_GLOBALS! */
|
||||
XWJNI_END();
|
||||
return success;
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
|
@ -2540,6 +2542,7 @@ static const SetInfo gsi_bools[] = {
|
|||
ARR_MEMBER( GameStateInfo, canTrade ),
|
||||
ARR_MEMBER( GameStateInfo, canPause ),
|
||||
ARR_MEMBER( GameStateInfo, canUnpause ),
|
||||
ARR_MEMBER( GameStateInfo, canRematch ),
|
||||
};
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
|
|
|
@ -329,8 +329,8 @@ static void assertQueueOk( const CommsCtxt* comms );
|
|||
static const char* relayCmdToStr( XWRELAY_Cmd cmd );
|
||||
# endif
|
||||
static void printQueue( const CommsCtxt* comms );
|
||||
static void logAddr( const CommsCtxt* comms, const CommsAddrRec* addr,
|
||||
const char* caller );
|
||||
static void logAddrComms( const CommsCtxt* comms, const CommsAddrRec* addr,
|
||||
const char* caller );
|
||||
#else
|
||||
# define ASSERT_ADDR_OK(addr)
|
||||
# define assertQueueOk(comms)
|
||||
|
@ -556,13 +556,13 @@ comms_make( MPFORMAL XWEnv xwe, XW_UtilCtxt* util, XP_Bool isServer,
|
|||
|
||||
if ( !!selfAddr ) {
|
||||
ASSERT_ADDR_OK(selfAddr);
|
||||
logAddr( comms, &comms->selfAddr, "before selfAddr" );
|
||||
logAddrComms( comms, &comms->selfAddr, "before selfAddr" );
|
||||
comms->selfAddr = *selfAddr;
|
||||
logAddr( comms, &comms->selfAddr, "after selfAddr" );
|
||||
logAddrComms( comms, &comms->selfAddr, "after selfAddr" );
|
||||
}
|
||||
if ( !!hostAddr ) {
|
||||
XP_ASSERT( !isServer );
|
||||
logAddr( comms, hostAddr, __func__ );
|
||||
logAddrComms( comms, hostAddr, __func__ );
|
||||
XP_PlayerAddr channelNo = comms_getChannelSeed( comms );
|
||||
#ifdef DEBUG
|
||||
AddressRecord* rec =
|
||||
|
@ -772,8 +772,9 @@ void
|
|||
addrFromStream( CommsAddrRec* addrP, XWStreamCtxt* stream )
|
||||
{
|
||||
XP_U8 tmp = stream_getU8( stream );
|
||||
if ( (STREAM_VERS_MULTIADDR > stream_getVersion( stream ))
|
||||
&& (COMMS_CONN_NONE != tmp) ) {
|
||||
XP_U16 version = stream_getVersion( stream );
|
||||
XP_ASSERT( 0 < version );
|
||||
if ( STREAM_VERS_MULTIADDR > version && (COMMS_CONN_NONE != tmp) ) {
|
||||
tmp = 1 << (tmp - 1);
|
||||
}
|
||||
addrP->_conTypes = tmp;
|
||||
|
@ -879,7 +880,7 @@ comms_makeFromStream( MPFORMAL XWEnv xwe, XWStreamCtxt* stream,
|
|||
XP_USE( nPlayersTotal );
|
||||
#endif
|
||||
XP_MEMCPY( &comms->selfAddr, &selfAddr, sizeof(comms->selfAddr) );
|
||||
logAddr( comms, &selfAddr, __func__ );
|
||||
logAddrComms( comms, &selfAddr, __func__ );
|
||||
comms->flags = flags;
|
||||
|
||||
comms->connID = stream_getU32( stream );
|
||||
|
@ -914,7 +915,7 @@ comms_makeFromStream( MPFORMAL XWEnv xwe, XWStreamCtxt* stream,
|
|||
AddressRecord* rec = (AddressRecord*)XP_CALLOC( mpool, sizeof(*rec));
|
||||
|
||||
addrFromStream( &rec->addr, stream );
|
||||
logAddr( comms, &rec->addr, __func__ );
|
||||
logAddrComms( comms, &rec->addr, __func__ );
|
||||
|
||||
if ( STREAM_VERS_SMALLCOMMS <= version ) {
|
||||
rec->nextMsgID = stream_getU32VL( stream );
|
||||
|
@ -1155,8 +1156,7 @@ addrToStreamOne( XWStreamCtxt* stream, CommsConnType typ,
|
|||
void
|
||||
addrToStream( XWStreamCtxt* stream, const CommsAddrRec* addrP )
|
||||
{
|
||||
stream_setVersion( stream, CUR_STREAM_VERS );
|
||||
XP_ASSERT( CUR_STREAM_VERS >= STREAM_VERS_NORELAY );
|
||||
XP_ASSERT( 0 < stream_getVersion(stream) ); /* must be set already */
|
||||
XP_U16 conTypes = addrP->_conTypes;
|
||||
types_rmType( &conTypes, COMMS_CONN_RELAY );
|
||||
stream_putU8( stream, conTypes );
|
||||
|
@ -1209,7 +1209,7 @@ comms_writeToStream( CommsCtxt* comms, XWStreamCtxt* stream, XP_U16 saveToken )
|
|||
stream_setVersion( stream, CUR_STREAM_VERS );
|
||||
|
||||
stream_putU8( stream, comms->flags );
|
||||
logAddr( comms, &comms->selfAddr, __func__ );
|
||||
logAddrComms( comms, &comms->selfAddr, __func__ );
|
||||
addrToStream( stream, &comms->selfAddr );
|
||||
stream_putBits( stream, 4, comms->rr.nPlayersHere );
|
||||
stream_putBits( stream, 4, comms->rr.nPlayersTotal );
|
||||
|
@ -1239,7 +1239,7 @@ comms_writeToStream( CommsCtxt* comms, XWStreamCtxt* stream, XP_U16 saveToken )
|
|||
for ( rec = comms->recs; !!rec; rec = rec->next ) {
|
||||
|
||||
const CommsAddrRec* addr = &rec->addr;
|
||||
logAddr( comms, addr, __func__ );
|
||||
logAddrComms( comms, addr, __func__ );
|
||||
addrToStream( stream, addr );
|
||||
|
||||
stream_putU32VL( stream, rec->nextMsgID );
|
||||
|
@ -1364,18 +1364,36 @@ comms_addMQTTDevID( CommsCtxt* comms, XP_PlayerAddr channelNo,
|
|||
}
|
||||
|
||||
void
|
||||
comms_getAddrs( const CommsCtxt* comms, CommsAddrRec addr[],
|
||||
XP_U16* nRecs )
|
||||
comms_getAddrs( const CommsCtxt* comms, CommsAddrRec addrs[],
|
||||
XP_U16* nAddrs )
|
||||
{
|
||||
AddressRecord* recs;
|
||||
XP_U16 count;
|
||||
for ( count = 0, recs = comms->recs;
|
||||
count < *nRecs && !!recs;
|
||||
++count, recs = recs->next ) {
|
||||
XP_MEMCPY( &addr[count], &recs->addr, sizeof(addr[count]) );
|
||||
logAddr( comms, &addr[count], __func__ );
|
||||
XP_U16 count = 0;
|
||||
for ( AddressRecord* recs = comms->recs; !!recs; recs = recs->next ) {
|
||||
if ( count < *nAddrs ) {
|
||||
XP_MEMCPY( &addrs[count], &recs->addr, sizeof(addrs[count]) );
|
||||
logAddrComms( comms, &addrs[count], __func__ );
|
||||
}
|
||||
++count;
|
||||
}
|
||||
*nRecs = count;
|
||||
*nAddrs = count;
|
||||
}
|
||||
|
||||
void
|
||||
comms_getChannelAddr( const CommsCtxt* comms, XP_PlayerAddr channelNo,
|
||||
CommsAddrRec* addr )
|
||||
{
|
||||
XP_U16 masked = channelNo & CHANNEL_MASK;
|
||||
XP_Bool found = XP_FALSE;
|
||||
for ( const AddressRecord* rec = comms->recs;
|
||||
!found && !!rec; rec = rec->next ) {
|
||||
found = (rec->channelNo & CHANNEL_MASK) == masked;
|
||||
if ( found ) {
|
||||
XP_LOGFF( "writing addr for channel %X", channelNo );
|
||||
*addr = rec->addr;
|
||||
logAddrComms( comms, addr, __func__ );
|
||||
}
|
||||
}
|
||||
XP_ASSERT( found );
|
||||
}
|
||||
|
||||
XP_U16
|
||||
|
@ -1683,7 +1701,7 @@ comms_invite( CommsCtxt* comms, XWEnv xwe, const NetLaunchInfo* nli,
|
|||
followed by opening the game, which results in comms_resendAll()
|
||||
getting called leading to a second send immediately after this. So
|
||||
let Android drop it. Linux, though, needs it for now. */
|
||||
if ( sendNow ) {
|
||||
if ( sendNow && !!comms->procs.sendInvt ) {
|
||||
sendMsg( comms, xwe, elem, COMMS_CONN_NONE );
|
||||
}
|
||||
}
|
||||
|
@ -2101,7 +2119,7 @@ sendMsg( const CommsCtxt* comms, XWEnv xwe, MsgQueueElem* elem,
|
|||
} else {
|
||||
XP_ASSERT( !!comms->procs.sendMsg );
|
||||
XP_U32 gameid = gameID( comms );
|
||||
logAddr( comms, &addr, __func__ );
|
||||
logAddrComms( comms, &addr, __func__ );
|
||||
XP_UCHAR msgNo[16];
|
||||
formatMsgNo( comms, elem, msgNo, sizeof(msgNo) );
|
||||
XP_ASSERT( 0 != elem->createdStamp );
|
||||
|
@ -2643,7 +2661,15 @@ getRecordFor( const CommsCtxt* comms, const XP_PlayerAddr channelNo )
|
|||
XP_LOGFF( "comparing rec channel %s with addr channel %s",
|
||||
cbuf1, cbuf );
|
||||
|
||||
if ( (rec->channelNo & ~CHANNEL_MASK) == (channelNo & ~CHANNEL_MASK) ) {
|
||||
/* Invite case: base on channelNo bits if the rest is 0 */
|
||||
if ( (0 == (rec->channelNo & ~CHANNEL_MASK)) && (0 == (channelNo & ~CHANNEL_MASK)) ) {
|
||||
if ( rec->channelNo == channelNo ) {
|
||||
break;
|
||||
}
|
||||
} else if ( (rec->channelNo & ~CHANNEL_MASK) == (channelNo & ~CHANNEL_MASK) ) {
|
||||
XP_LOGFF( "match based on channels!!!" );
|
||||
/* This is so wrong for addresses coming from invites. Why works
|
||||
with GTK? */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -3449,7 +3475,7 @@ rememberChannelAddress( CommsCtxt* comms, XP_PlayerAddr channelNo,
|
|||
XP_LOGFF( "(%s)", cbuf );
|
||||
listRecs( comms, "entering rememberChannelAddress" );
|
||||
|
||||
logAddr( comms, addr, __func__ );
|
||||
logAddrComms( comms, addr, __func__ );
|
||||
rec = getRecordFor( comms, channelNo );
|
||||
if ( !rec ) {
|
||||
/* not found; add a new entry */
|
||||
|
@ -3487,17 +3513,27 @@ rememberChannelAddress( CommsCtxt* comms, XP_PlayerAddr channelNo,
|
|||
} /* rememberChannelAddress */
|
||||
|
||||
#ifdef DEBUG
|
||||
static void
|
||||
logAddr( const CommsCtxt* comms, const CommsAddrRec* addr,
|
||||
|
||||
static void
|
||||
logAddrComms( const CommsCtxt* comms, const CommsAddrRec* addr,
|
||||
const char* caller )
|
||||
{
|
||||
logAddr( MPPARM(comms->mpool) comms->dutil, addr, caller );
|
||||
}
|
||||
|
||||
void
|
||||
logAddr( MPFORMAL XW_DUtilCtxt* dutil, const CommsAddrRec* addr,
|
||||
const char* caller )
|
||||
{
|
||||
if ( !!addr ) {
|
||||
char buf[128];
|
||||
XWStreamCtxt* stream = mem_stream_make_raw( MPPARM(comms->mpool)
|
||||
dutil_getVTManager(comms->dutil));
|
||||
snprintf( buf, sizeof(buf), TAGFMT() "called on %p from %s:\n", TAGPRMS,
|
||||
addr, caller );
|
||||
stream_catString( stream, buf );
|
||||
XWStreamCtxt* stream = mem_stream_make_raw( MPPARM(mpool)
|
||||
dutil_getVTManager(dutil));
|
||||
if ( !!caller ) {
|
||||
snprintf( buf, sizeof(buf), "called on %p from %s:\n",
|
||||
addr, caller );
|
||||
stream_catString( stream, buf );
|
||||
}
|
||||
|
||||
CommsConnType typ;
|
||||
XP_Bool first = XP_TRUE;
|
||||
|
|
|
@ -214,6 +214,8 @@ XP_S16 comms_resendAll( CommsCtxt* comms, XWEnv xwe, CommsConnType filter,
|
|||
XP_Bool force );
|
||||
|
||||
XP_U16 comms_getChannelSeed( CommsCtxt* comms );
|
||||
void comms_getChannelAddr( const CommsCtxt* comms, XP_PlayerAddr channelNo,
|
||||
CommsAddrRec* addr );
|
||||
|
||||
#ifdef XWFEATURE_COMMSACK
|
||||
void comms_ackAny( CommsCtxt* comms, XWEnv xwe );
|
||||
|
@ -277,6 +279,8 @@ void comms_setAddrDisabled( CommsCtxt* comms, CommsConnType typ,
|
|||
XP_Bool send, XP_Bool enabled );
|
||||
XP_Bool comms_getAddrDisabled( const CommsCtxt* comms, CommsConnType typ,
|
||||
XP_Bool send );
|
||||
void logAddr( MPFORMAL XW_DUtilCtxt* dutil, const CommsAddrRec* addr,
|
||||
const char* caller );
|
||||
|
||||
# else
|
||||
# define comms_setAddrDisabled( comms, typ, send, enabled )
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
#define MAX_COLS MAX_ROWS
|
||||
#define MIN_COLS 11
|
||||
|
||||
#define STREAM_VERS_REMATCHADDRS 0x24
|
||||
#define STREAM_VERS_MSGSTREAMVERS 0x23
|
||||
#define STREAM_VERS_NORELAY 0x22
|
||||
#define STREAM_VERS_MSGTIMESTAMP 0x21
|
||||
|
@ -98,7 +99,7 @@
|
|||
#define STREAM_VERS_405 0x01
|
||||
|
||||
/* search for FIX_NEXT_VERSION_CHANGE next time this is changed */
|
||||
#define CUR_STREAM_VERS STREAM_VERS_MSGSTREAMVERS
|
||||
#define CUR_STREAM_VERS STREAM_VERS_REMATCHADDRS
|
||||
|
||||
typedef struct XP_Rect {
|
||||
XP_S16 left;
|
||||
|
|
|
@ -165,6 +165,7 @@ game_makeNewGame( MPFORMAL XWEnv xwe, XWGame* game, CurGameInfo* gi,
|
|||
#endif
|
||||
)
|
||||
{
|
||||
XP_ASSERT( gi == util->gameInfo ); /* if holds, remove gi param */
|
||||
#ifndef XWFEATURE_STANDALONE_ONLY
|
||||
XP_U16 nPlayersHere = 0;
|
||||
XP_U16 nPlayersTotal = 0;
|
||||
|
@ -231,58 +232,44 @@ game_makeNewGame( MPFORMAL XWEnv xwe, XWGame* game, CurGameInfo* gi,
|
|||
return success;
|
||||
} /* game_makeNewGame */
|
||||
|
||||
void
|
||||
XP_Bool
|
||||
game_makeRematch( const XWGame* oldGame, XWEnv xwe, XW_UtilCtxt* newUtil,
|
||||
const CommonPrefs* newCp, XWGame* newGame,
|
||||
const XP_UCHAR* newName, XP_Bool sendNow )
|
||||
const CommonPrefs* newCp, const TransportProcs* procs,
|
||||
XWGame* newGame, const XP_UCHAR* newName )
|
||||
{
|
||||
LOG_FUNC();
|
||||
CurGameInfo* newGI = newUtil->gameInfo;
|
||||
XP_ASSERT( !!newGI );
|
||||
XP_ASSERT( newGI != oldGame->util->gameInfo );
|
||||
const CurGameInfo* gi = oldGame->util->gameInfo;
|
||||
XP_ASSERT( 0 < gi->nPlayers );
|
||||
gi_copy( MPPARM(newUtil->mpool) newGI, gi );
|
||||
newGI->gameID = makeGameID( newUtil );
|
||||
if ( SERVER_ISCLIENT == newGI->serverRole ) {
|
||||
newGI->serverRole = SERVER_ISSERVER; /* we'll be inviting */
|
||||
newGI->forceChannel = 0;
|
||||
}
|
||||
XP_Bool success = XP_FALSE;
|
||||
XP_LOGFF( "(newName=%s)", newName );
|
||||
|
||||
CommsAddrRec* selfAddrP = NULL;
|
||||
CommsAddrRec selfAddr;
|
||||
if ( !!oldGame->comms ) {
|
||||
comms_getSelfAddr( oldGame->comms, &selfAddr );
|
||||
selfAddrP = &selfAddr;
|
||||
}
|
||||
RematchAddrs ra;
|
||||
if ( server_getRematchInfo( oldGame->server, newUtil,
|
||||
makeGameID( newUtil ), &ra ) ) {
|
||||
CommsAddrRec* selfAddrP = NULL;
|
||||
CommsAddrRec selfAddr;
|
||||
if ( !!oldGame->comms ) {
|
||||
comms_getSelfAddr( oldGame->comms, &selfAddr );
|
||||
selfAddrP = &selfAddr;
|
||||
}
|
||||
|
||||
CommsAddrRec hostAddr;
|
||||
XP_Bool haveRemote = !oldGame->comms
|
||||
|| comms_getHostAddr( oldGame->comms, &hostAddr );
|
||||
if ( !haveRemote ) {
|
||||
XP_U16 nRecs = 1;
|
||||
comms_getAddrs( oldGame->comms, &hostAddr, &nRecs );
|
||||
haveRemote = 0 < nRecs;
|
||||
}
|
||||
XP_ASSERT( haveRemote );
|
||||
if ( game_makeNewGame( MPPARM(newUtil->mpool) xwe, newGame, newUtil->gameInfo,
|
||||
selfAddrP, (CommsAddrRec*)NULL, newUtil,
|
||||
(DrawCtx*)NULL, newCp, procs ) ) {
|
||||
|
||||
if ( haveRemote &&
|
||||
game_makeNewGame( MPPARM(newUtil->mpool) xwe, newGame, newGI,
|
||||
selfAddrP, (CommsAddrRec*)NULL, newUtil,
|
||||
(DrawCtx*)NULL, newCp, (TransportProcs*)NULL ) ) {
|
||||
LOGGI(newGI, "made game" );
|
||||
XP_ASSERT( 0 < newGI->nPlayers );
|
||||
if ( !!newGame->comms ) {
|
||||
NetLaunchInfo nli;
|
||||
nli_init( &nli, newGI, selfAddrP, 1, 1 );
|
||||
if ( !!newName ) {
|
||||
nli_setGameName( &nli, newName );
|
||||
const CurGameInfo* newGI = newUtil->gameInfo;
|
||||
for ( int ii = 0; ii < ra.nAddrs; ++ii ) {
|
||||
NetLaunchInfo nli;
|
||||
/* hard-code one player per device -- for now */
|
||||
nli_init( &nli, newGI, selfAddrP, 1, ii + 1 );
|
||||
if ( !!newName ) {
|
||||
nli_setGameName( &nli, newName );
|
||||
}
|
||||
LOGNLI( &nli );
|
||||
comms_invite( newGame->comms, xwe, &nli, &ra.addrs[ii], XP_TRUE );
|
||||
}
|
||||
LOGNLI( &nli );
|
||||
comms_invite( newGame->comms, xwe, &nli, &hostAddr, sendNow );
|
||||
success = XP_TRUE;
|
||||
}
|
||||
}
|
||||
LOG_RETURN_VOID();
|
||||
LOG_RETURNF( "%s", boolToStr(success) );
|
||||
return success;
|
||||
}
|
||||
|
||||
#ifdef XWFEATURE_CHANGEDICT
|
||||
|
@ -526,6 +513,7 @@ game_getState( const XWGame* game, XWEnv xwe, GameStateInfo* gsi )
|
|||
gsi->nPendingMessages = !!game->comms ?
|
||||
comms_countPendingPackets(game->comms) : 0;
|
||||
|
||||
gsi->canRematch = server_canRematch( server );
|
||||
gsi->canPause = server_canPause( server );
|
||||
gsi->canUnpause = server_canUnpause( server );
|
||||
}
|
||||
|
|
|
@ -47,6 +47,7 @@ typedef struct _GameStateInfo {
|
|||
XP_Bool curTurnSelected;
|
||||
XP_Bool canHideRack;
|
||||
XP_Bool canTrade;
|
||||
XP_Bool canRematch;
|
||||
XP_Bool canPause; /* duplicate-mode only */
|
||||
XP_Bool canUnpause; /* duplicate-mode only */
|
||||
} GameStateInfo;
|
||||
|
@ -84,9 +85,9 @@ XP_Bool game_makeNewGame( MPFORMAL XWEnv xwe, XWGame* game, CurGameInfo* gi,
|
|||
,XP_U16 gameSeed
|
||||
#endif
|
||||
);
|
||||
void game_makeRematch( const XWGame* game, XWEnv xwe, XW_UtilCtxt* util,
|
||||
const CommonPrefs* cp, XWGame* newGame,
|
||||
const XP_UCHAR* newName, XP_Bool sendNow );
|
||||
XP_Bool game_makeRematch( const XWGame* game, XWEnv xwe, XW_UtilCtxt* util,
|
||||
const CommonPrefs* cp, const TransportProcs* procs,
|
||||
XWGame* newGame, const XP_UCHAR* newName );
|
||||
|
||||
void game_changeDict( MPFORMAL XWGame* game, XWEnv xwe, CurGameInfo* gi,
|
||||
DictionaryCtxt* dict );
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
#ifndef _GAMEINFO_H_
|
||||
#define _GAMEINFO_H_
|
||||
|
||||
#include "server.h"
|
||||
#include "nlityp.h"
|
||||
|
||||
#ifdef CPLUS
|
||||
extern "C" {
|
||||
|
|
|
@ -92,6 +92,7 @@ saveState( XW_DUtilCtxt* dutil, XWEnv xwe, KPState* state )
|
|||
if ( state->dirty ) {
|
||||
XWStreamCtxt* stream = mem_stream_make_raw( MPPARM(dutil->mpool)
|
||||
dutil_getVTManager(dutil) );
|
||||
stream_setVersion( stream, CUR_STREAM_VERS );
|
||||
stream_putU8( stream, CUR_STREAM_VERS );
|
||||
for ( KnownPlayer* kp = state->players; !!kp; kp = kp->next ) {
|
||||
stream_putU32( stream, kp->newestMod );
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* -*- compile-command: "cd ../linux && make -j3 MEMDEBUG=TRUE"; -*- */
|
||||
/*
|
||||
* Copyright 1997 - 2021 by Eric House (xwords@eehouse.org). All rights
|
||||
* Copyright 1997 - 2023 by Eric House (xwords@eehouse.org). All rights
|
||||
* reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
|
@ -86,12 +86,12 @@ typedef enum {
|
|||
#define UNKNOWN_DEVICE -1
|
||||
#define SERVER_DEVICE 0
|
||||
|
||||
typedef struct ServerPlayer {
|
||||
typedef struct _ServerPlayer {
|
||||
EngineCtxt* engine; /* each needs his own so don't interfere each other */
|
||||
XP_S8 deviceIndex; /* 0 means local, -1 means unknown */
|
||||
} ServerPlayer;
|
||||
|
||||
typedef struct RemoteAddress {
|
||||
typedef struct _RemoteAddress {
|
||||
XP_PlayerAddr channelNo;
|
||||
#ifdef STREAM_VERS_BIGBOARD
|
||||
XP_U8 streamVersion;
|
||||
|
@ -143,9 +143,15 @@ typedef struct ServerNonvolatiles {
|
|||
RemoteAddress addresses[MAX_NUM_PLAYERS];
|
||||
XWStreamCtxt* prevMoveStream; /* save it to print later */
|
||||
XWStreamCtxt* prevWordsStream;
|
||||
|
||||
/* On guests only, stores addresses of other clients for rematch use*/
|
||||
XP_U16 rematchAddrsLen;
|
||||
XP_U8* rematchAddrs;
|
||||
|
||||
XP_Bool dupTurnsMade[MAX_NUM_PLAYERS];
|
||||
XP_Bool dupTurnsForced[MAX_NUM_PLAYERS];
|
||||
XP_Bool dupTurnsSent; /* used on client only */
|
||||
XP_Bool dupTurnsSent; /* used on guest only */
|
||||
|
||||
} ServerNonvolatiles;
|
||||
|
||||
struct ServerCtxt {
|
||||
|
@ -157,7 +163,7 @@ struct ServerCtxt {
|
|||
BadWordInfo illegalWordInfo;
|
||||
XP_U16 lastMoveSource;
|
||||
|
||||
ServerPlayer players[MAX_NUM_PLAYERS];
|
||||
ServerPlayer srvPlyrs[MAX_NUM_PLAYERS];
|
||||
XP_Bool serverDoing;
|
||||
#ifdef XWFEATURE_SLOW_ROBOT
|
||||
XP_Bool robotWaiting;
|
||||
|
@ -194,7 +200,7 @@ static void badWordMoveUndoAndTellUser( ServerCtxt* server, XWEnv xwe,
|
|||
BadWordInfo* bwi );
|
||||
static XP_Bool tileCountsOk( const ServerCtxt* server );
|
||||
static void setTurn( ServerCtxt* server, XWEnv xwe, XP_S16 turn );
|
||||
static XWStreamCtxt* mkServerStream( ServerCtxt* server );
|
||||
static XWStreamCtxt* mkServerStream( const ServerCtxt* server );
|
||||
static void fetchTiles( ServerCtxt* server, XWEnv xwe, XP_U16 playerNum,
|
||||
XP_U16 nToFetch, const TrayTileSet* tradedTiles,
|
||||
TrayTileSet* resultTiles, XP_Bool forceCanPlay );
|
||||
|
@ -232,6 +238,8 @@ static XP_Bool handleIllegalWord( ServerCtxt* server, XWEnv xwe,
|
|||
static void tellMoveWasLegal( ServerCtxt* server, XWEnv xwe );
|
||||
static void writeProto( const ServerCtxt* server, XWStreamCtxt* stream,
|
||||
XW_Proto proto );
|
||||
static void readGuestAddrs( ServerCtxt* server, XWStreamCtxt* stream );
|
||||
|
||||
#endif
|
||||
|
||||
#define PICK_NEXT -1
|
||||
|
@ -301,7 +309,7 @@ syncPlayers( ServerCtxt* server )
|
|||
XP_U16 ii;
|
||||
CurGameInfo* gi = server->vol.gi;
|
||||
LocalPlayer* lp = gi->players;
|
||||
ServerPlayer* player = server->players;
|
||||
ServerPlayer* player = server->srvPlyrs;
|
||||
for ( ii = 0; ii < gi->nPlayers; ++ii, ++lp, ++player ) {
|
||||
if ( !lp->isLocal/* && !lp->name */ ) {
|
||||
++server->nv.pendingRegistrations;
|
||||
|
@ -553,7 +561,7 @@ server_makeFromStream( MPFORMAL XWEnv xwe, XWStreamCtxt* stream, ModelCtxt* mode
|
|||
}
|
||||
|
||||
for ( ii = 0; ii < nPlayers; ++ii ) {
|
||||
ServerPlayer* player = &server->players[ii];
|
||||
ServerPlayer* player = &server->srvPlyrs[ii];
|
||||
|
||||
player->deviceIndex = stream_getU8( stream );
|
||||
|
||||
|
@ -578,12 +586,17 @@ server_makeFromStream( MPFORMAL XWEnv xwe, XWStreamCtxt* stream, ModelCtxt* mode
|
|||
server->nv.prevWordsStream = readStreamIf( server, stream );
|
||||
}
|
||||
|
||||
if ( server->vol.gi->serverRole == SERVER_ISCLIENT
|
||||
&& 2 < nPlayers ) {
|
||||
readGuestAddrs( server, stream );
|
||||
}
|
||||
|
||||
/* Hack alert: recovering from an apparent bug that leaves the game
|
||||
thinking it's a client but being in the host-only XWSTATE_BEGIN
|
||||
state. */
|
||||
if ( server->nv.gameState == XWSTATE_BEGIN &&
|
||||
server->vol.gi->serverRole == SERVER_ISCLIENT ) {
|
||||
XP_LOGFF( "server_makeFromStream(): fixing state" );
|
||||
XP_LOGFF( "fixing state" );
|
||||
SETSTATE( server, XWSTATE_NONE );
|
||||
}
|
||||
|
||||
|
@ -594,7 +607,7 @@ server_makeFromStream( MPFORMAL XWEnv xwe, XWStreamCtxt* stream, ModelCtxt* mode
|
|||
void
|
||||
server_writeToStream( const ServerCtxt* server, XWStreamCtxt* stream )
|
||||
{
|
||||
XP_U16 nPlayers = server->vol.gi->nPlayers;
|
||||
const XP_U16 nPlayers = server->vol.gi->nPlayers;
|
||||
|
||||
putNV( stream, &server->nv, nPlayers );
|
||||
|
||||
|
@ -604,7 +617,7 @@ server_writeToStream( const ServerCtxt* server, XWStreamCtxt* stream )
|
|||
}
|
||||
|
||||
for ( int ii = 0; ii < nPlayers; ++ii ) {
|
||||
const ServerPlayer* player = &server->players[ii];
|
||||
const ServerPlayer* player = &server->srvPlyrs[ii];
|
||||
|
||||
stream_putU8( stream, player->deviceIndex );
|
||||
|
||||
|
@ -618,6 +631,13 @@ server_writeToStream( const ServerCtxt* server, XWStreamCtxt* stream )
|
|||
|
||||
writeStreamIf( stream, server->nv.prevMoveStream );
|
||||
writeStreamIf( stream, server->nv.prevWordsStream );
|
||||
|
||||
if ( server->vol.gi->serverRole == SERVER_ISCLIENT
|
||||
&& 2 < nPlayers ) {
|
||||
XP_U16 len = server->nv.rematchAddrsLen;
|
||||
stream_putU32VL( stream, len );
|
||||
stream_putBytes( stream, server->nv.rematchAddrs, len );
|
||||
}
|
||||
} /* server_writeToStream */
|
||||
|
||||
void
|
||||
|
@ -638,14 +658,13 @@ server_onRoleChanged( ServerCtxt* server, XWEnv xwe, XP_Bool amNowGuest )
|
|||
static void
|
||||
cleanupServer( ServerCtxt* server )
|
||||
{
|
||||
XP_U16 ii;
|
||||
for ( ii = 0; ii < VSIZE(server->players); ++ii ){
|
||||
ServerPlayer* player = &server->players[ii];
|
||||
for ( XP_U16 ii = 0; ii < VSIZE(server->srvPlyrs); ++ii ){
|
||||
ServerPlayer* player = &server->srvPlyrs[ii];
|
||||
if ( player->engine != NULL ) {
|
||||
engine_destroy( player->engine );
|
||||
}
|
||||
}
|
||||
XP_MEMSET( server->players, 0, sizeof(server->players) );
|
||||
XP_MEMSET( server->srvPlyrs, 0, sizeof(server->srvPlyrs) );
|
||||
|
||||
if ( server->pool != NULL ) {
|
||||
pool_destroy( server->pool );
|
||||
|
@ -659,6 +678,8 @@ cleanupServer( ServerCtxt* server )
|
|||
stream_destroy( server->nv.prevWordsStream );
|
||||
}
|
||||
|
||||
XP_FREEP( server->mpool, &server->nv.rematchAddrs );
|
||||
|
||||
XP_MEMSET( &server->nv, 0, sizeof(server->nv) );
|
||||
} /* cleanupServer */
|
||||
|
||||
|
@ -778,6 +799,66 @@ readMQTTDevID( ServerCtxt* server, XWStreamCtxt* stream )
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
addGuestAddrsIf( const ServerCtxt* server, XP_U16 sendee, XWStreamCtxt* stream )
|
||||
{
|
||||
XP_LOGFF("(sendee: %d)", sendee );
|
||||
if ( amServer( server )
|
||||
/* Not needed for two-device games */
|
||||
&& 2 < server->nv.nDevices
|
||||
/* no two-player devices? */
|
||||
&& server->nv.nDevices == server->vol.gi->nPlayers
|
||||
&& STREAM_VERS_REMATCHADDRS <= stream_getVersion(stream) ) {
|
||||
XWStreamCtxt* tmpStream = mkServerStream( server );
|
||||
stream_setVersion( tmpStream, stream_getVersion( stream ) );
|
||||
|
||||
for ( XP_U16 devIndex = 1; devIndex < server->nv.nDevices; ++devIndex ) {
|
||||
if ( devIndex == sendee ) {
|
||||
continue;
|
||||
}
|
||||
XP_PlayerAddr channelNo
|
||||
= server->nv.addresses[devIndex].channelNo;
|
||||
CommsAddrRec addr;
|
||||
comms_getChannelAddr( server->vol.comms, channelNo, &addr );
|
||||
addrToStream( tmpStream, &addr );
|
||||
}
|
||||
XP_U16 len = stream_getSize( tmpStream );
|
||||
stream_putU32VL( stream, len );
|
||||
stream_putBytes( stream, stream_getPtr(tmpStream), len );
|
||||
stream_destroy( tmpStream );
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
readGuestAddrs( ServerCtxt* server, XWStreamCtxt* stream )
|
||||
{
|
||||
XP_U16 version = stream_getVersion( stream );
|
||||
XP_LOGFF( "version: %X", version );
|
||||
if ( STREAM_VERS_REMATCHADDRS <= version && 0 < stream_getSize(stream) ) {
|
||||
XP_U16 len = server->nv.rematchAddrsLen = stream_getU32VL( stream );
|
||||
XP_LOGFF( "rematchAddrsLen: %d", server->nv.rematchAddrsLen );
|
||||
if ( 0 < len ) {
|
||||
XP_ASSERT( !server->nv.rematchAddrs );
|
||||
server->nv.rematchAddrs = XP_MALLOC( server->mpool, len );
|
||||
stream_getBytes( stream, server->nv.rematchAddrs, len );
|
||||
XP_LOGFF( "loaded %d bytes of rematchAddrs", len );
|
||||
}
|
||||
#ifdef DEBUG
|
||||
XWStreamCtxt* tmpStream = mkServerStream( server );
|
||||
stream_setVersion( tmpStream, stream_getVersion( stream ) );
|
||||
stream_putBytes( tmpStream, server->nv.rematchAddrs, server->nv.rematchAddrsLen );
|
||||
while ( 0 < stream_getSize(tmpStream) ) {
|
||||
CommsAddrRec addr = {0};
|
||||
addrFromStream( &addr, tmpStream );
|
||||
XP_LOGFF( "got an address" );
|
||||
logAddr( MPPARM(server->mpool) server->vol.dutil, &addr, __func__ );
|
||||
}
|
||||
stream_destroy( tmpStream );
|
||||
#endif
|
||||
}
|
||||
LOG_RETURN_VOID();
|
||||
}
|
||||
|
||||
XP_Bool
|
||||
server_initClientConnection( ServerCtxt* server, XWEnv xwe )
|
||||
{
|
||||
|
@ -1401,11 +1482,11 @@ robotTradeTiles( ServerCtxt* server, MoveInfo* newMove )
|
|||
#endif
|
||||
|
||||
static XWStreamCtxt*
|
||||
mkServerStream( ServerCtxt* server )
|
||||
mkServerStream( const ServerCtxt* server )
|
||||
{
|
||||
XWStreamCtxt* stream;
|
||||
stream = mem_stream_make_raw( MPPARM(server->mpool)
|
||||
dutil_getVTManager(server->vol.dutil) );
|
||||
XWStreamCtxt* stream =
|
||||
mem_stream_make_raw( MPPARM(server->mpool)
|
||||
dutil_getVTManager(server->vol.dutil) );
|
||||
XP_ASSERT( !!stream );
|
||||
return stream;
|
||||
} /* mkServerStream */
|
||||
|
@ -1847,7 +1928,7 @@ findFirstPending( ServerCtxt* server, ServerPlayer** playerP )
|
|||
XP_LOGFF( "no slot found for player; duplicate packet?" );
|
||||
lp = NULL;
|
||||
} else {
|
||||
*playerP = server->players + nPlayers;
|
||||
*playerP = server->srvPlyrs + nPlayers;
|
||||
}
|
||||
return lp;
|
||||
} /* findFirstPending */
|
||||
|
@ -2042,6 +2123,7 @@ client_readInitialMessage( ServerCtxt* server, XWEnv xwe, XWStreamCtxt* stream )
|
|||
}
|
||||
|
||||
readMQTTDevID( server, stream );
|
||||
readGuestAddrs( server, stream );
|
||||
|
||||
syncPlayers( server );
|
||||
|
||||
|
@ -2078,7 +2160,7 @@ makeSendableGICopy( ServerCtxt* server, CurGameInfo* giCopy,
|
|||
for ( clientPl = giCopy->players, ii = 0;
|
||||
ii < nPlayers; ++clientPl, ++ii ) {
|
||||
/* adjust isLocal to client's perspective */
|
||||
clientPl->isLocal = server->players[ii].deviceIndex == deviceIndex;
|
||||
clientPl->isLocal = server->srvPlyrs[ii].deviceIndex == deviceIndex;
|
||||
}
|
||||
|
||||
giCopy->forceChannel = deviceIndex;
|
||||
|
@ -2139,6 +2221,7 @@ sendInitialMessage( ServerCtxt* server, XWEnv xwe )
|
|||
}
|
||||
|
||||
addMQTTDevIDIf( server, xwe, stream );
|
||||
addGuestAddrsIf( server, deviceIndex, stream );
|
||||
|
||||
stream_destroy( stream );
|
||||
}
|
||||
|
@ -2288,7 +2371,7 @@ server_getEngineFor( ServerCtxt* server, XP_U16 playerNum )
|
|||
const CurGameInfo* gi = server->vol.gi;
|
||||
XP_ASSERT( playerNum < gi->nPlayers );
|
||||
|
||||
ServerPlayer* player = &server->players[playerNum];
|
||||
ServerPlayer* player = &server->srvPlyrs[playerNum];
|
||||
EngineCtxt* engine = player->engine;
|
||||
if ( !engine &&
|
||||
(inDuplicateMode(server) || gi->players[playerNum].isLocal) ) {
|
||||
|
@ -2303,7 +2386,7 @@ server_getEngineFor( ServerCtxt* server, XP_U16 playerNum )
|
|||
void
|
||||
server_resetEngine( ServerCtxt* server, XP_U16 playerNum )
|
||||
{
|
||||
ServerPlayer* player = &server->players[playerNum];
|
||||
ServerPlayer* player = &server->srvPlyrs[playerNum];
|
||||
if ( !!player->engine ) {
|
||||
XP_ASSERT( player->deviceIndex == 0 || inDuplicateMode(server) );
|
||||
engine_reset( player->engine );
|
||||
|
@ -3816,6 +3899,7 @@ server_getGameIsOver( const ServerCtxt* server )
|
|||
return server->nv.gameState == XWSTATE_GAMEOVER;
|
||||
} /* server_getGameIsOver */
|
||||
|
||||
/* This is completely wrong */
|
||||
XP_Bool
|
||||
server_getGameIsConnected( const ServerCtxt* server )
|
||||
{
|
||||
|
@ -3849,7 +3933,7 @@ server_getMissingPlayers( const ServerCtxt* server )
|
|||
case SERVER_ISSERVER:
|
||||
if ( 0 < server->nv.pendingRegistrations ) {
|
||||
XP_U16 nPlayers = server->vol.gi->nPlayers;
|
||||
const ServerPlayer* players = server->players;
|
||||
const ServerPlayer* players = server->srvPlyrs;
|
||||
for ( ii = 0; ii < nPlayers; ++ii ) {
|
||||
if ( players->deviceIndex == UNKNOWN_DEVICE ) {
|
||||
result |= 1 << ii;
|
||||
|
@ -3870,7 +3954,7 @@ server_getOpenChannel( const ServerCtxt* server, XP_U16* channel )
|
|||
XP_ASSERT( amServer( server ) );
|
||||
if ( amServer( server ) && 0 < server->nv.pendingRegistrations ) {
|
||||
const XP_U16 nPlayers = server->vol.gi->nPlayers;
|
||||
const ServerPlayer* players = server->players;
|
||||
const ServerPlayer* players = server->srvPlyrs;
|
||||
for ( int ii = 0; ii < nPlayers && !result; ++ii ) {
|
||||
result = UNKNOWN_DEVICE == players->deviceIndex;
|
||||
if ( result ) {
|
||||
|
@ -3883,6 +3967,91 @@ server_getOpenChannel( const ServerCtxt* server, XP_U16* channel )
|
|||
return result;
|
||||
}
|
||||
|
||||
XP_Bool
|
||||
server_canRematch( const ServerCtxt* server )
|
||||
{
|
||||
/* XP_LOGFF( "nDevices: %d; nPlayers: %d", */
|
||||
/* server->nv.nDevices, server->vol.gi->nPlayers ); */
|
||||
const CurGameInfo* gi = server->vol.gi;
|
||||
XP_Bool result;
|
||||
switch ( gi->serverRole ) {
|
||||
case SERVER_STANDALONE:
|
||||
result = XP_TRUE; /* can always rematch a local game */
|
||||
break;
|
||||
case SERVER_ISSERVER:
|
||||
/* have all expected clients connected? */
|
||||
result = XWSTATE_RECEIVED_ALL_REG <= server->nv.gameState;
|
||||
break;
|
||||
case SERVER_ISCLIENT:
|
||||
result = 2 == gi->nPlayers
|
||||
? XP_TRUE /* We always have server address */
|
||||
: 0 < server->nv.rematchAddrsLen;
|
||||
break;
|
||||
}
|
||||
LOG_RETURNF( "%s", boolToStr(result) );
|
||||
return result;
|
||||
}
|
||||
|
||||
XP_Bool
|
||||
server_getRematchInfo( const ServerCtxt* server, XW_UtilCtxt* newUtil,
|
||||
XP_U32 gameID, RematchAddrs* ra )
|
||||
{
|
||||
LOG_FUNC();
|
||||
XP_Bool success = server_canRematch( server );
|
||||
if ( success ) {
|
||||
XP_MEMSET( ra, 0, sizeof(*ra) );
|
||||
CurGameInfo* newGI = newUtil->gameInfo;
|
||||
gi_disposePlayerInfo( MPPARM(newUtil->mpool) newGI );
|
||||
|
||||
gi_copy( MPPARM(newUtil->mpool) newGI, server->vol.gi );
|
||||
newGI->gameID = gameID;
|
||||
if ( SERVER_ISCLIENT == newGI->serverRole ) {
|
||||
newGI->serverRole = SERVER_ISSERVER; /* we'll be inviting */
|
||||
newGI->forceChannel = 0;
|
||||
}
|
||||
LOGGI( newUtil->gameInfo, "ready to invite" );
|
||||
|
||||
/* Now build the address list */
|
||||
const CommsCtxt* comms = server->vol.comms;
|
||||
if ( amServer( server ) ) {
|
||||
/* skip 0; it's me */
|
||||
for ( int ii = 1; ii < server->nv.nDevices; ++ii ) {
|
||||
XP_PlayerAddr channelNo = server->nv.addresses[ii].channelNo;
|
||||
comms_getChannelAddr( comms, channelNo, &ra->addrs[ra->nAddrs] );
|
||||
++ra->nAddrs;
|
||||
}
|
||||
} else {
|
||||
/* first, server's address */
|
||||
comms_getHostAddr( comms, &ra->addrs[ra->nAddrs++] );
|
||||
/* then, any other guests we've been told about */
|
||||
if ( !!server->nv.rematchAddrs ) {
|
||||
XWStreamCtxt* stream = mkServerStream( server );
|
||||
stream_setVersion( stream, server->nv.streamVersion );
|
||||
stream_putBytes( stream, server->nv.rematchAddrs,
|
||||
server->nv.rematchAddrsLen );
|
||||
while ( 0 < stream_getSize( stream )
|
||||
&& ra->nAddrs < VSIZE(ra->addrs) ) {
|
||||
addrFromStream( &ra->addrs[ra->nAddrs++], stream );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
if ( success ) {
|
||||
for ( int ii = 0; ii < ra->nAddrs; ++ii ) {
|
||||
XP_LOGFF( "addr %d of %d: ", ii, ra->nAddrs );
|
||||
logAddr( MPPARM(server->mpool) server->vol.dutil,
|
||||
&ra->addrs[ii], NULL );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
XP_ASSERT( !success || server->vol.gi->nPlayers == ra->nAddrs + 1 );
|
||||
LOG_RETURNF( "%s", boolToStr(success) );
|
||||
return success;
|
||||
}
|
||||
|
||||
XP_U32
|
||||
server_getLastMoveTime( const ServerCtxt* server )
|
||||
{
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */
|
||||
/*
|
||||
* Copyright 1997 - 2000 by Eric House (xwords@eehouse.org). All rights reserved.
|
||||
* Copyright 1997 - 2023 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
|
||||
|
@ -25,6 +25,7 @@
|
|||
|
||||
#include "commmgr.h"
|
||||
#include "model.h"
|
||||
#include "gameinfo.h"
|
||||
|
||||
#ifdef CPLUS
|
||||
extern "C" {
|
||||
|
@ -85,6 +86,7 @@ XP_S16 server_getTimerSeconds( const ServerCtxt* server, XWEnv xwe, XP_U16 turn
|
|||
XP_Bool server_dupTurnDone( const ServerCtxt* server, XP_U16 turn );
|
||||
XP_Bool server_canPause( const ServerCtxt* server );
|
||||
XP_Bool server_canUnpause( const ServerCtxt* server );
|
||||
XP_Bool server_canRematch( const ServerCtxt* server );
|
||||
void server_pause( ServerCtxt* server, XWEnv xwe, XP_S16 turn, const XP_UCHAR* msg );
|
||||
void server_unpause( ServerCtxt* server, XWEnv xwe, XP_S16 turn, const XP_UCHAR* msg );
|
||||
|
||||
|
@ -142,6 +144,19 @@ XP_U16 server_figureFinishBonus( const ServerCtxt* server, XP_U16 turn );
|
|||
XP_Bool server_getIsServer( const ServerCtxt* server );
|
||||
#endif
|
||||
|
||||
typedef struct _RematchAddrs {
|
||||
CommsAddrRec addrs[MAX_NUM_PLAYERS];
|
||||
XP_U16 nAddrs;
|
||||
} RematchAddrs;
|
||||
|
||||
/* Sets up newUtil->gameInfo correctly, and returns with a set of
|
||||
addresses to which invitation should be sent. But: meant to be called
|
||||
only from game.c anyway.
|
||||
*/
|
||||
XP_Bool server_getRematchInfo( const ServerCtxt* server, XW_UtilCtxt* newUtil,
|
||||
XP_U32 gameID, RematchAddrs* ra );
|
||||
|
||||
|
||||
#ifdef CPLUS
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -1259,7 +1259,8 @@ inviteList( CommonGlobals* cGlobals, CommsAddrRec* myAddr, GSList* invitees,
|
|||
XP_ASSERT(0);
|
||||
}
|
||||
#ifdef XWFEATURE_COMMS_INVITE
|
||||
comms_invite( cGlobals->game.comms, NULL_XWE, &nli, &destAddr, XP_TRUE );
|
||||
comms_invite( cGlobals->game.comms, NULL_XWE, &nli,
|
||||
&destAddr, XP_TRUE );
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
|
@ -366,8 +366,11 @@ make_rematch( GtkAppGlobals* apg, const CommonGlobals* cGlobals )
|
|||
|
||||
XW_UtilCtxt* util = newGlobals->cGlobals.util;
|
||||
const CommonPrefs* cp = &newGlobals->cGlobals.cp;
|
||||
XP_UCHAR buf[64];
|
||||
snprintf( buf, VSIZE(buf), "Game %lX", XP_RANDOM() % 256 );
|
||||
game_makeRematch( &cGlobals->game, NULL_XWE, util, cp,
|
||||
&newGlobals->cGlobals.game, NULL, XP_TRUE );
|
||||
&newGlobals->cGlobals.procs,
|
||||
&newGlobals->cGlobals.game, buf );
|
||||
|
||||
linuxSaveGame( &newGlobals->cGlobals );
|
||||
sqlite3_int64 rowid = newGlobals->cGlobals.rowid;
|
||||
|
|
Loading…
Add table
Reference in a new issue