This commit is contained in:
Eric House 2023-11-30 11:03:27 -08:00
parent d021bb4029
commit c726477878
4 changed files with 106 additions and 78 deletions

View file

@ -135,7 +135,7 @@ static void relay_requestJoin_curses( void* closure, const XP_UCHAR* devID,
XP_U16 nPlayersTotal, XP_U16 seed, XP_U16 lang ); XP_U16 nPlayersTotal, XP_U16 seed, XP_U16 lang );
#endif #endif
static XP_Bool rematch_and_save( CursesBoardGlobals* bGlobals, XP_U32* newGameID ); static XP_Bool rematch_and_save( CursesBoardGlobals* bGlobals, XP_U32* newGameIDP );
static void disposeBoard( CursesBoardGlobals* bGlobals ); static void disposeBoard( CursesBoardGlobals* bGlobals );
static void initCP( CommonGlobals* cGlobals ); static void initCP( CommonGlobals* cGlobals );
static CursesBoardGlobals* commonInit( CursesBoardState* cbState, static CursesBoardGlobals* commonInit( CursesBoardState* cbState,
@ -198,7 +198,8 @@ cb_open( CursesBoardState* cbState, sqlite3_int64 rowid, const cb_dims* dims )
} }
bool bool
cb_new( CursesBoardState* cbState, const cb_dims* dims, const CurGameInfo* gi ) cb_new( CursesBoardState* cbState, const cb_dims* dims, const CurGameInfo* gi,
XP_U32* newGameIDP )
{ {
CursesBoardGlobals* bGlobals = findOrOpen( cbState, -1, gi, NULL ); CursesBoardGlobals* bGlobals = findOrOpen( cbState, -1, gi, NULL );
if ( !!bGlobals ) { if ( !!bGlobals ) {
@ -206,7 +207,13 @@ cb_new( CursesBoardState* cbState, const cb_dims* dims, const CurGameInfo* gi )
enableDraw( bGlobals, dims ); enableDraw( bGlobals, dims );
setupBoard( bGlobals ); setupBoard( bGlobals );
} }
return NULL != bGlobals; XP_Bool success = NULL != bGlobals;
if ( success && !!newGameIDP ) {
*newGameIDP = bGlobals->cGlobals.gi->gameID;
}
return success;
} }
void void
@ -687,10 +694,10 @@ cb_addInvite( CursesBoardState* cbState, XP_U32 gameID, XP_U16 forceChannel,
} }
XP_Bool XP_Bool
cb_makeRematch( CursesBoardState* cbState, XP_U32 gameID, XP_U32* newGameID ) cb_makeRematch( CursesBoardState* cbState, XP_U32 gameID, XP_U32* newGameIDP )
{ {
CursesBoardGlobals* bGlobals = findOrOpenForGameID( cbState, gameID, NULL, NULL ); CursesBoardGlobals* bGlobals = findOrOpenForGameID( cbState, gameID, NULL, NULL );
XP_Bool success = rematch_and_save( bGlobals, newGameID ); XP_Bool success = rematch_and_save( bGlobals, newGameIDP );
return success; return success;
} }
@ -998,7 +1005,7 @@ rematch_and_save_once( CursesBoardGlobals* bGlobals )
} }
static XP_Bool static XP_Bool
rematch_and_save( CursesBoardGlobals* bGlobals, XP_U32* newGameID ) rematch_and_save( CursesBoardGlobals* bGlobals, XP_U32* newGameIDP )
{ {
LOG_FUNC(); LOG_FUNC();
CommonGlobals* cGlobals = &bGlobals->cGlobals; CommonGlobals* cGlobals = &bGlobals->cGlobals;
@ -1011,8 +1018,8 @@ rematch_and_save( CursesBoardGlobals* bGlobals, XP_U32* newGameID )
&cGlobals->cp, &bGlobalsNew->cGlobals.procs, &cGlobals->cp, &bGlobalsNew->cGlobals.procs,
&bGlobalsNew->cGlobals.game, "newName" ); &bGlobalsNew->cGlobals.game, "newName" );
if ( success ) { if ( success ) {
if ( !!newGameID ) { if ( !!newGameIDP ) {
*newGameID = bGlobalsNew->cGlobals.gi->gameID; *newGameIDP = bGlobalsNew->cGlobals.gi->gameID;
} }
linuxSaveGame( &bGlobalsNew->cGlobals ); linuxSaveGame( &bGlobalsNew->cGlobals );
} }

View file

@ -41,7 +41,8 @@ void cb_resized( CursesBoardState* cbState, const cb_dims* dims );
void cb_open( CursesBoardState* cbState, sqlite3_int64 rowid, const cb_dims* dims ); void cb_open( CursesBoardState* cbState, sqlite3_int64 rowid, const cb_dims* dims );
bool cb_new( CursesBoardState* cbState, const cb_dims* dims, bool cb_new( CursesBoardState* cbState, const cb_dims* dims,
const CurGameInfo* gi /* optional: use from globals if unset */ ); const CurGameInfo* gi /* optional: use from globals if unset */,
XP_U32* newGameIDP );
void cb_newFor( CursesBoardState* cbState, const NetLaunchInfo* nli, void cb_newFor( CursesBoardState* cbState, const NetLaunchInfo* nli,
const cb_dims* dims ); const cb_dims* dims );

View file

@ -315,7 +315,7 @@ handleNewGame( void* closure, int XP_UNUSED(key) )
const CurGameInfo* gi = &aGlobals->cag.params->pgi; const CurGameInfo* gi = &aGlobals->cag.params->pgi;
if ( !canMakeFromGI(gi) ) { if ( !canMakeFromGI(gi) ) {
ca_inform( aGlobals->mainWin, "Unable to create game (check params?)" ); ca_inform( aGlobals->mainWin, "Unable to create game (check params?)" );
} else if ( !cb_new( aGlobals->cbState, &dims, NULL ) ) { } else if ( !cb_new( aGlobals->cbState, &dims, NULL, NULL ) ) {
XP_ASSERT(0); XP_ASSERT(0);
} }
return XP_TRUE; return XP_TRUE;
@ -1456,7 +1456,7 @@ castGid( cJSON* obj )
} }
static XP_U32 static XP_U32
gidFromObject( cJSON* obj ) gidFromObject( const cJSON* obj )
{ {
cJSON* tmp = cJSON_GetObjectItem( obj, "gid" ); cJSON* tmp = cJSON_GetObjectItem( obj, "gid" );
XP_ASSERT( !!tmp ); XP_ASSERT( !!tmp );
@ -1464,14 +1464,38 @@ gidFromObject( cJSON* obj )
} }
static void static void
addGIDToObject( cJSON* obj, XP_U32 gid, const char* key ) makeObjIfNot( cJSON** objp )
{ {
char buf[16]; if ( NULL == *objp ) {
sprintf( buf, "%08X", gid ); *objp = cJSON_CreateObject();
cJSON_AddStringToObject( obj, key, buf ); }
} }
static XP_Bool static void
addGIDToObject( cJSON** objp, XP_U32 gid, const char* key )
{
makeObjIfNot( objp );
char buf[16];
sprintf( buf, "%08X", gid );
cJSON_AddStringToObject( *objp, key, buf );
}
static void
addObjectToObject( cJSON** objp, const char* key, cJSON* value )
{
makeObjIfNot( objp );
cJSON_AddItemToObject( *objp, key, value );
}
static void
addSuccessToObject( cJSON** objp, XP_Bool success )
{
makeObjIfNot( objp );
cJSON_AddBoolToObject( *objp, "success", success );
}
static XP_U32
makeGameFromArgs( CursesAppGlobals* aGlobals, cJSON* args ) makeGameFromArgs( CursesAppGlobals* aGlobals, cJSON* args )
{ {
LaunchParams* params = aGlobals->cag.params; LaunchParams* params = aGlobals->cag.params;
@ -1481,8 +1505,6 @@ makeGameFromArgs( CursesAppGlobals* aGlobals, cJSON* args )
gi.boardSize = 15; gi.boardSize = 15;
gi.traySize = 7; gi.traySize = 7;
gi.gameID = gidFromObject( args );
cJSON* tmp = cJSON_GetObjectItem( args, "nPlayers" ); cJSON* tmp = cJSON_GetObjectItem( args, "nPlayers" );
XP_ASSERT( !!tmp ); XP_ASSERT( !!tmp );
gi.nPlayers = tmp->valueint; gi.nPlayers = tmp->valueint;
@ -1512,12 +1534,13 @@ makeGameFromArgs( CursesAppGlobals* aGlobals, cJSON* args )
cb_dims dims; cb_dims dims;
figureDims( aGlobals, &dims ); figureDims( aGlobals, &dims );
LOGGI( &gi, "prior to cb_new call" );
bool success = cb_new( aGlobals->cbState, &dims, &gi ); XP_U32 newGameID;
bool success = cb_new( aGlobals->cbState, &dims, &gi, &newGameID );
XP_ASSERT( success ); XP_ASSERT( success );
gi_disposePlayerInfo( MPPARM(params->mpool) &gi ); gi_disposePlayerInfo( MPPARM(params->mpool) &gi );
return success; return newGameID;
} }
static XP_Bool static XP_Bool
@ -1592,8 +1615,8 @@ getGamesStateForArgs( CursesAppGlobals* aGlobals, cJSON* args )
GameInfo gib; GameInfo gib;
if ( gdb_getGameInfoForGID( params->pDb, gameID, &gib ) ) { if ( gdb_getGameInfoForGID( params->pDb, gameID, &gib ) ) {
cJSON* item = cJSON_CreateObject(); cJSON* item = NULL;
addGIDToObject( item, gameID, "gid" ); addGIDToObject( &item, gameID, "gid" );
cJSON_AddBoolToObject( item, "gameOver", gib.gameOver ); cJSON_AddBoolToObject( item, "gameOver", gib.gameOver );
cJSON_AddNumberToObject( item, "nPending", gib.nPending ); cJSON_AddNumberToObject( item, "nPending", gib.nPending );
cJSON_AddNumberToObject( item, "nMoves", gib.nMoves ); cJSON_AddNumberToObject( item, "nMoves", gib.nMoves );
@ -1605,18 +1628,6 @@ getGamesStateForArgs( CursesAppGlobals* aGlobals, cJSON* args )
return result; return result;
} }
static cJSON*
makeBoolObj( const char* key, XP_Bool value )
{
cJSON* result = cJSON_CreateObject();
cJSON_AddBoolToObject( result, key, value );
/* char buf[1000]; */
/* if ( cJSON_PrintPreallocated( result, buf, sizeof(buf), 0 ) ) { */
/* XP_LOGFF( "(%s=>%s)=>%s", key, boolToStr(value), buf ); */
/* } */
return result;
}
static gboolean static gboolean
on_incoming_signal( GSocketService* XP_UNUSED(service), on_incoming_signal( GSocketService* XP_UNUSED(service),
GSocketConnection* connection, GSocketConnection* connection,
@ -1652,46 +1663,48 @@ on_incoming_signal( GSocketService* XP_UNUSED(service),
const char* cmdStr = cmd->valuestring; const char* cmdStr = cmd->valuestring;
cJSON* response = NULL; cJSON* response = NULL;
XP_Bool success = XP_TRUE;
if ( 0 == strcmp( cmdStr, "quit" ) ) { if ( 0 == strcmp( cmdStr, "quit" ) ) {
response = getGamesStateForArgs( aGlobals, args ); cJSON* gids = getGamesStateForArgs( aGlobals, args );
addObjectToObject( &response, "states", gids );
handleQuit( aGlobals, 0 ); handleQuit( aGlobals, 0 );
} else if ( 0 == strcmp( cmdStr, "getMQTTDevID" ) ) { } else if ( 0 == strcmp( cmdStr, "getMQTTDevID" ) ) {
MQTTDevID devID; MQTTDevID devID;
dvc_getMQTTDevID( params->dutil, NULL_XWE, &devID ); dvc_getMQTTDevID( params->dutil, NULL_XWE, &devID );
char buf[64]; char buf[64];
formatMQTTDevID( &devID, buf, sizeof(buf) ); formatMQTTDevID( &devID, buf, sizeof(buf) );
response = cJSON_CreateString( buf ); cJSON* devid = cJSON_CreateString( buf );
addObjectToObject( &response, "mqtt", devid );
} else if ( 0 == strcmp( cmdStr, "makeGame" ) ) { } else if ( 0 == strcmp( cmdStr, "makeGame" ) ) {
XP_Bool success = makeGameFromArgs( aGlobals, args ); XP_U32 newGameID = makeGameFromArgs( aGlobals, args );
response = makeBoolObj( "success", success ); success = 0 != newGameID;
if ( success ) {
addGIDToObject( &response, newGameID, "newGid" );
}
} else if ( 0 == strcmp( cmdStr, "invite" ) ) { } else if ( 0 == strcmp( cmdStr, "invite" ) ) {
XP_Bool success = inviteFromArgs( aGlobals, args ); success = inviteFromArgs( aGlobals, args );
response = makeBoolObj( "success", success );
} else if ( 0 == strcmp( cmdStr, "moveIf" ) ) { } else if ( 0 == strcmp( cmdStr, "moveIf" ) ) {
XP_Bool success = moveifFromArgs( aGlobals, args ); success = moveifFromArgs( aGlobals, args );
response = makeBoolObj( "success", success );
} else if ( 0 == strcmp( cmdStr, "rematch" ) ) { } else if ( 0 == strcmp( cmdStr, "rematch" ) ) {
XP_U32 newGameID = rematchFromArgs( aGlobals, args ); XP_U32 newGameID = rematchFromArgs( aGlobals, args );
if ( 0 != newGameID ) { success = 0 != newGameID;
response = cJSON_CreateObject(); if ( success ) {
addGIDToObject( response, newGameID, "newGid" ); addGIDToObject( &response, newGameID, "newGid" );
} }
} else if ( 0 == strcmp( cmdStr, "gamesState" ) ) {
response = getGamesStateForArgs( aGlobals, args );
} else { } else {
success = XP_FALSE;
XP_ASSERT(0); XP_ASSERT(0);
} }
XP_ASSERT( !!response ); addSuccessToObject( &response, success );
if ( !!response ) {
cJSON* tmp = cJSON_CreateObject();
cJSON_AddStringToObject( tmp, "cmd", cmdStr );
cJSON_AddNumberToObject( tmp, "key", key->valueint );
cJSON_AddItemToObject( tmp, "response", response );
/*(void)*/cJSON_AddItemToArray( reply, tmp ); cJSON* tmp = cJSON_CreateObject();
} cJSON_AddStringToObject( tmp, "cmd", cmdStr );
cJSON_AddNumberToObject( tmp, "key", key->valueint );
cJSON_AddItemToObject( tmp, "response", response );
/*(void)*/cJSON_AddItemToArray( reply, tmp );
} }
cJSON_Delete( cmds ); /* this apparently takes care of all children */ cJSON_Delete( cmds ); /* this apparently takes care of all children */

View file

@ -37,11 +37,15 @@ class GuestGameInfo():
# Should be subclass of GuestGameInfo # Should be subclass of GuestGameInfo
class HostedInfo(): class HostedInfo():
def __init__(self, guests, gid=None, invitesSent=False): def __init__(self, guestNames, **kwargs):
self.guestNames = guests self.guestNames = guestNames
self.gid = gid and gid or '{:08X}'.format(random.randint(1, 0x7FFFFFFF)) self.gid = kwargs.get('gid')
assert len(self.gid) == 8 self.needsInvite = kwargs.get('needsInvite', True)
self.invitesSent = invitesSent
def setGid(self, gid):
# set only once!
assert 8 == len(gid) and not self.gid
self.gid = gid
def __str__(self): def __str__(self):
return 'gid: {}, guests: {}'.format(self.gid, self.guestNames) return 'gid: {}, guests: {}'.format(self.gid, self.guestNames)
@ -212,8 +216,11 @@ class Device():
def setDevID(self): def setDevID(self):
response = self._sendWaitReply('getMQTTDevID') response = self._sendWaitReply('getMQTTDevID')
if response: mqttDevID = response and response.get('mqtt')
self.mqttDevID = response if mqttDevID:
self.mqttDevID = mqttDevID
else:
printError('no mqtt or no response')
def makeGames(self): def makeGames(self):
args = self.args args = self.args
@ -222,9 +229,12 @@ class Device():
hostPosn = random.randint(0, nPlayers-1) hostPosn = random.randint(0, nPlayers-1)
traySize = 0 == args.TRAY_SIZE and random.randint(7, 9) or args.TRAY_SIZE traySize = 0 == args.TRAY_SIZE and random.randint(7, 9) or args.TRAY_SIZE
self._sendWaitReply('makeGame', nPlayers=nPlayers, hostPosn=hostPosn, response = self._sendWaitReply('makeGame', nPlayers=nPlayers, hostPosn=hostPosn,
gid=remote.gid, dict=args.DICTS[0], dict=args.DICTS[0], boardSize=args.BOARD_SIZE,
boardSize=args.BOARD_SIZE, traySize=traySize) traySize=traySize)
newGid = response.get('newGid')
if newGid:
remote.setGid(newGid)
# This is the heart of things. Do something as long as we have a # This is the heart of things. Do something as long as we have a
# game that needs to run. # game that needs to run.
@ -232,7 +242,7 @@ class Device():
# self._log('step() called for {}'.format(self)) # self._log('step() called for {}'.format(self))
stepped = False stepped = False
for game in self.hostedGames: for game in self.hostedGames:
if not game.invitesSent: if game.needsInvite:
self.invite(game) self.invite(game)
stepped = True stepped = True
break break
@ -258,29 +268,26 @@ class Device():
guests.remove(self.host) guests.remove(self.host)
self._log('rematch: new host: {}; new guest[s]: {}, gid: {}'.format(self.host, guests, newGid)) self._log('rematch: new host: {}; new guest[s]: {}, gid: {}'.format(self.host, guests, newGid))
self.hostedGames.append(HostedInfo(guests, newGid, True)) self.hostedGames.append(HostedInfo(guests, needsInvite=False, gid=newGid))
for guest in guests: for guest in guests:
Device.getFor(guest).expectInvite(newGid) Device.getFor(guest).expectInvite(newGid)
def invite(self, game): def invite(self, game):
failed = False failed = False
for ii in range(len(game.guestNames)): for ii in range(len(game.guestNames)):
guestName = game.guestNames[ii] guestDev = Device.getFor(game.guestNames[ii])
# self._log('inviting {}'.format(guestName))
guestDev = self._devs[guestName]
addr = {} addr = {}
if self.args.WITH_MQTT: addr['mqtt'] = guestDev.mqttDevID if self.args.WITH_MQTT: addr['mqtt'] = guestDev.mqttDevID
if self.args.WITH_SMS: addr['sms'] = guestDev.smsNumber if self.args.WITH_SMS: addr['sms'] = guestDev.smsNumber
response = self._sendWaitReply('invite', gid=game.gid, response = self._sendWaitReply('invite', gid=game.gid,
channel=ii+1, addr=addr, channel=ii+1, addr=addr)
name=guestName) # just for logging
if response['success']: if response['success']:
guestDev.expectInvite(game.gid) guestDev.expectInvite(game.gid)
else: else:
failed = True failed = True
if not failed: game.invitesSent = True if not failed: game.needsInvite = False
def expectInvite(self, gid): def expectInvite(self, gid):
self.guestGames.append(GuestGameInfo(gid)) self.guestGames.append(GuestGameInfo(gid))
@ -328,7 +335,7 @@ class Device():
gids = [game.gid for game in allGames if not self.gameOver(game.gid)] gids = [game.gid for game in allGames if not self.gameOver(game.gid)]
response = self._sendWaitReply('quit', gids=gids) response = self._sendWaitReply('quit', gids=gids)
for obj in response: for obj in response.get('states', []):
gid = obj.get('gid') gid = obj.get('gid')
self.gameStates[gid] = obj self.gameStates[gid] = obj
@ -415,9 +422,7 @@ class Device():
return result return result
def addGameWith(self, guests): def addGameWith(self, guests):
# self._log('addGameWith({})'.format(guests)) self.hostedGames.append(HostedInfo(guests, needsInvite=True))
hosted = HostedInfo(guests)
self.hostedGames.append(hosted)
for guest in guests: for guest in guests:
Device.deviceFor(self.args, guest) # in case this device never hosts Device.deviceFor(self.args, guest) # in case this device never hosts
@ -635,6 +640,8 @@ def termHandler(signum, frame):
print('termHandler() called') print('termHandler() called')
gDone = True gDone = True
def printError(msg): print( 'ERROR: {}'.format(msg))
def main(): def main():
startTime = datetime.datetime.now() startTime = datetime.datetime.now()
signal.signal(signal.SIGINT, termHandler) signal.signal(signal.SIGINT, termHandler)