add more info to game "buttons"

Toward a games-list substitute. New game_summarize method will get
fleshed out and eventually replace what's in jni?
This commit is contained in:
Eric House 2021-03-08 18:38:02 -08:00
parent 8c920d6537
commit f3b76da8e1
5 changed files with 124 additions and 35 deletions

View file

@ -545,6 +545,30 @@ game_getState( const XWGame* game, XWEnv xwe, GameStateInfo* gsi )
gsi->canUnpause = server_canUnpause( server );
}
void
game_summarize( XWGame* game, CurGameInfo* gi, GameSummary* summary )
{
XP_MEMSET( summary, 0, sizeof(*summary) );
ServerCtxt* server = game->server;
summary->turn = server_getCurrentTurn( server, &summary->turnIsLocal );
summary->lastMoveTime = server_getLastMoveTime(server);
summary->lang = gi->dictLang;
for ( int ii = 0; ii < gi->nPlayers; ++ii ) {
LocalPlayer* lp = &gi->players[ii];
if ( LP_IS_ROBOT(lp) || !LP_IS_LOCAL(lp) ) {
if ( '\0' != summary->opponents[0] ) {
XP_STRCAT( summary->opponents, ", " );
}
XP_STRCAT( summary->opponents, lp->name );
}
}
if ( !!game->comms ) {
CommsCtxt* comms = game->comms;
summary->missingPlayers = server_getMissingPlayers( server );
summary->nPacketsPending = comms_countPendingPackets( comms );
}
}
XP_Bool
game_getIsServer( const XWGame* game )
{

View file

@ -51,6 +51,17 @@ typedef struct _GameStateInfo {
XP_Bool canUnpause; /* duplicate-mode only */
} GameStateInfo;
typedef struct _GameSummary {
XP_Bool turnIsLocal;
XP_Bool inPlay;
XP_S8 turn;
XP_U32 lastMoveTime;
XP_U8 missingPlayers;
XP_U8 nPacketsPending;
XP_LangCode lang;
XP_UCHAR opponents[64];
} GameSummary;
typedef struct _XWGame {
XW_UtilCtxt* util;
BoardCtxt* board;
@ -97,6 +108,7 @@ XP_Bool game_receiveMessage( XWGame* game, XWEnv xwe, XWStreamCtxt* stream,
void game_dispose( XWGame* game, XWEnv xwe );
void game_summarize( XWGame* game, CurGameInfo* gi, GameSummary* summary );
void game_getState( const XWGame* game, XWEnv xwe, GameStateInfo* gsi );
XP_Bool game_getIsServer( const XWGame* game );

View file

@ -62,6 +62,7 @@
#define KEY_LAST_GID "cur_game"
#define KEY_PLAYER_NAME "player_name"
#define KEY_GAMES "games"
#define KEY_SUMMARY "summary"
#define KEY_GAME "game_data"
#define KEY_NAME "game_name"
#define KEY_NEXT_GAME "next_game"
@ -84,7 +85,7 @@
#define BUTTON_INVITE "Invite"
#define BUTTON_GAME_NEW "New Game"
#define BUTTON_GAME_OPEN "Open Game"
#define BUTTON_GAME_OPEN "Games"
#define BUTTON_GAME_RENAME "Rename Game"
#define BUTTON_GAME_DELETE "Delete Game"
#define BUTTON_NAME "My Name"
@ -144,8 +145,10 @@ EM_JS(void, show_name, (const char* name), {
});
EM_JS(void, show_pool, (int cur, int max), {
let msg = 'cur: ' + cur + 'b; max: ' + max + 'b';
document.getElementById('mempool').textContent = msg;
const msg = 'cur: ' + cur + 'b; max: ' + max + 'b';
const div = document.getElementById('mempool');
div.textContent = msg;
div.parentNode.hidden = 0;
});
EM_JS(void, call_dialog, (const char* str, const char** but_strs,
@ -497,6 +500,16 @@ updateGameButtons( Globals* globals )
setButtons( BUTTONS_ID_GAME, buttons, onGameButton, gs );
}
static bool
langNameFor( Globals* globals, XP_LangCode code, char buf[], size_t buflen )
{
const char* lc = lcToLocale( code );
const XP_UCHAR* keys[] = { KEY_DICTS, lc, KEY_LANG_NAME, NULL };
XP_U32 len = buflen;
dutil_loadPtr( globals->dutil, NULL, keys, buf, &len );
return 0 < len;
}
static void
showName( GameState* gs )
{
@ -507,14 +520,10 @@ showName( GameState* gs )
char buf[64];
if ( true || 1 < countDicts( globals ) ) {
char langName[32];
const char* lc = lcToLocale(gs->gi.dictLang);
const XP_UCHAR* keys[] = {KEY_DICTS, lc, KEY_LANG_NAME, NULL };
XP_U32 len = sizeof(langName);
dutil_loadPtr( globals->dutil, NULL, keys, langName, &len );
if ( 0 != len ) {
lc = langName;
if ( !langNameFor( globals, gs->gi.dictLang, langName, sizeof(langName) ) ) {
strcpy( langName, "??" );
}
sprintf( buf, "%s (%s)", title, lc );
sprintf( buf, "%s (%s)", title, langName );
title = buf;
}
}
@ -541,8 +550,7 @@ typedef struct _NameIterState {
static void
onGameChosen( void* closure, const char* key )
{
NameIterState* nis = (NameIterState*)closure;
Globals* globals = nis->globals;
CAST_GLOB(Globals*, globals, closure);
/* To be safe, let's make sure the game exists. We don't want to create
* another if somehow it doesn't */
@ -552,13 +560,41 @@ onGameChosen( void* closure, const char* key )
loadAndDraw( globals, NULL, gameID, NULL );
}
XP_FREE( globals->mpool, nis->names );
XP_FREE( globals->mpool, nis->ids );
XP_FREE( globals->mpool, nis );
updateDeviceButtons( globals );
}
static char*
formatForGame(Globals* globals, bool multiLangs, const XP_UCHAR* gameKey )
{
const XP_UCHAR* keys[] = {KEY_GAMES, gameKey, KEY_NAME, NULL};
char gameName[32];
XP_U32 len = sizeof(gameName);
dutil_loadPtr( globals->dutil, NULL, keys, gameName, &len );
char buf[256];
int offset = snprintf( buf, sizeof(buf), "%s", gameName );
GameSummary summary;
len = sizeof(summary);
keys[2] = KEY_SUMMARY;
dutil_loadPtr( globals->dutil, NULL, keys, &summary, &len );
if ( len == sizeof(summary) ) {
if ( multiLangs ) {
char langName[32];
if ( langNameFor( globals, summary.lang, langName, sizeof(langName) ) ) {
offset += snprintf( buf+offset, sizeof(buf)-offset, " (in %s)", langName );
}
}
offset += snprintf( buf+offset, sizeof(buf)-offset, " My turn: %s",
summary.turnIsLocal ? "YES" : "NO" );
offset += snprintf( buf+offset, sizeof(buf)-offset, " Opponent: %s",
summary.opponents );
}
char* result = NULL;
replaceStringIfDifferent( globals->mpool, &result, buf );
return result;
}
static XP_Bool
onOneGameName( void* closure, const XP_UCHAR* keys[] )
{
@ -566,6 +602,7 @@ onOneGameName( void* closure, const XP_UCHAR* keys[] )
if ( 0 != strcmp( gameIDStr, "0" ) ) { /* temporary */
NameIterState* nis = (NameIterState*)closure;
Globals* globals = nis->globals;
bool multiLangs = 1 < countDicts(globals);
/* Make sure game exists. This may be unnecessary later */
const XP_UCHAR* dataKeys[] = { keys[0], keys[1], KEY_GAME, NULL };
@ -575,12 +612,7 @@ onOneGameName( void* closure, const XP_UCHAR* keys[] )
int cur = nis->count++;
nis->names = XP_REALLOC( globals->mpool, nis->names,
nis->count * sizeof(nis->names[0]) );
XP_U32 valLen;
dutil_loadPtr( globals->dutil, NULL, keys, NULL, &valLen );
nis->names[cur] = XP_MALLOC( globals->mpool, valLen );
dutil_loadPtr( globals->dutil, NULL, keys, nis->names[cur], &valLen );
nis->names[cur] = formatForGame( globals, multiLangs, keys[1] );
nis->ids = XP_REALLOC( globals->mpool, nis->ids,
nis->count * sizeof(nis->ids[0]) );
nis->ids[cur] = XP_MALLOC( globals->mpool, 1 + strlen(gameIDStr) );
@ -594,14 +626,16 @@ static void
pickGame( Globals* globals )
{
XW_DUtilCtxt* dutil = globals->dutil;
NameIterState* nis = XP_CALLOC( globals->mpool, sizeof(*nis) );
nis->globals = globals;
NameIterState nis = { .globals = globals, };
const XP_UCHAR* keys[] = {KEY_GAMES, KEY_WILDCARD, KEY_NAME, NULL};
dutil_forEach( dutil, NULL, keys, onOneGameName, nis );
dutil_forEach( dutil, NULL, keys, onOneGameName, &nis );
const char* msg = "Choose game to open:";
call_pickGame(msg, nis->ids, nis->names, nis->count, onGameChosen, nis);
call_pickGame(msg, nis.ids, nis.names, nis.count, onGameChosen, globals);
XP_FREE( globals->mpool, nis.names );
XP_FREE( globals->mpool, nis.ids );
}
static void
@ -1066,6 +1100,7 @@ getSavedGame( Globals* globals, int gameID )
{
GameState* gs;
/* Is it already open? */
for ( gs = globals->games; !!gs; gs = gs->next ) {
if ( gameID == gs->gi.gameID ) {
break;
@ -1100,6 +1135,7 @@ getSavedGame( Globals* globals, int gameID )
updateScreen( gs, false );
} else {
removeGameState( gs );
gs = NULL;
}
} else {
XP_LOGFF( "ERROR: no saved data for game %s", gameIDStr );
@ -1672,12 +1708,18 @@ updateScreen( GameState* gs, bool doSave )
game_saveToStream( &gs->game, NULL, &gs->gi,
stream, ++gs->saveToken );
GameSummary summary;
game_summarize( &gs->game, &gs->gi, &summary );
char gameIDStr[32];
formatGameID( gameIDStr, sizeof(gameIDStr), gs->gi.gameID );
const XP_UCHAR* keys[] = { KEY_GAMES, gameIDStr, KEY_GAME, NULL };
dutil_storeStream( globals->dutil, NULL, keys, stream );
stream_destroy( stream, NULL );
game_saveSucceeded( &gs->game, NULL, gs->saveToken );
keys[2] = KEY_SUMMARY;
dutil_storePtr( globals->dutil, NULL, keys, &summary, sizeof(summary) );
}
}

View file

@ -97,7 +97,7 @@
<table class='centered'>
<tr><td>MQTT Dev ID:</td><td id="mqtt_span"></td></tr>
<tr><td>MQTT Status:</td><td id="mqtt_status">Unconnected</td></tr>
<tr><td>MemPool used:</td><td id="mempool">0</td></tr>
<tr hidden=1><td>MemPool used:</td><td id="mempool">0</td></tr>
</table>
<hr/>
<!-- Remove until I figure out how this works

View file

@ -218,7 +218,7 @@ function newDlgWMsg(msg) {
return dlg;
}
function newButtonDiv(buttons, proc) {
function newButtonDiv(buttons, proc, asDivs) {
let div = document.createElement('div');
div.classList.add('buttonRow');
for ( let ii = 0; ii < buttons.length; ++ii ) {
@ -226,6 +226,11 @@ function newButtonDiv(buttons, proc) {
let button = document.createElement('button');
button.textContent = buttonTxt;
button.onclick = function() { proc(ii); };
if ( asDivs ) {
let bdiv = document.createElement('div');
bdiv.appendChild(button);
button = bdiv;
}
div.appendChild(button);
}
@ -239,7 +244,7 @@ function nbDialog(msg, buttons, proc, closure) {
dlg.parentNode.removeChild(dlg);
ccallString(proc, closure, buttons[indx]);
}
dlg.appendChild( newButtonDiv( buttons, butProc ) );
dlg.appendChild( newButtonDiv( buttons, butProc, false ) );
addDepthNote(dlg);
}
@ -251,7 +256,7 @@ function nbBlankPick(title, buttons, proc, closure) {
ccallString(proc, closure, indx.toString());
}
dlg.appendChild( newButtonDiv( buttons, butProc ) );
dlg.appendChild( newButtonDiv( buttons, butProc, false ) );
addDepthNote(dlg);
}
@ -281,8 +286,14 @@ function nbGamePick(title, gameMap, proc, closure) {
dlg.parentNode.removeChild(dlg);
ccallString(proc, closure, pairs[indx].id);
}
dlg.appendChild( newButtonDiv( buttons, butProc, true ) );
cancelProc = function() {
dlg.parentNode.removeChild(dlg);
ccallString(proc, closure, null);
};
dlg.appendChild( newButtonDiv( ['Cancel'], cancelProc, false ) );
dlg.appendChild( newButtonDiv( buttons, butProc ) );
addDepthNote(dlg);
}
@ -296,7 +307,7 @@ function setDivButtons(divid, buttons, proc, closure) {
ccallString(proc, closure, buttons[indx]);
}
parent.appendChild( newButtonDiv( buttons, butProc ) );
parent.appendChild( newButtonDiv( buttons, butProc, false ) );
}
function nbGetString(msg, dflt, proc, closure) {
@ -320,7 +331,7 @@ function nbGetString(msg, dflt, proc, closure) {
dismissed(tarea.value);
}
}
dlg.appendChild( newButtonDiv( buttons, butProc ) );
dlg.appendChild( newButtonDiv( buttons, butProc, false ) );
addDepthNote(dlg);
}
@ -383,7 +394,7 @@ function nbGetNewGame(closure, msg, langs) {
dlg.parentNode.removeChild(dlg);
}
dlg.appendChild( newButtonDiv( ['Cancel', 'OK'], butProc ) );
dlg.appendChild( newButtonDiv( ['Cancel', 'OK'], butProc, false ) );
addDepthNote(dlg);
}