From 41cd3d8f394c88d3fbe5e2544055ec79b6df1ea6 Mon Sep 17 00:00:00 2001 From: Eric House Date: Sat, 20 Feb 2021 09:04:57 -0800 Subject: [PATCH] open game to receive message --- xwords4/common/memstream.c | 43 ++++++++++++--- xwords4/common/xwstream.h | 7 +++ xwords4/wasm/Makefile | 1 + xwords4/wasm/main.c | 107 ++++++++++++++++++++++++++----------- 4 files changed, 118 insertions(+), 40 deletions(-) diff --git a/xwords4/common/memstream.c b/xwords4/common/memstream.c index fbce1923c..a6f07d04b 100644 --- a/xwords4/common/memstream.c +++ b/xwords4/common/memstream.c @@ -38,6 +38,12 @@ extern "C" { #define STREAM_INCR_SIZE 100 +#ifdef XWFEATURE_STREAMREF +# define REFCOUNT refCount +#else +# define REFCOUNT _unused_refCount +#endif + #define SOCKET_STREAM_SUPER_COMMON_SLOTS \ StreamCtxVTable* vtable; \ void* closure; \ @@ -51,6 +57,7 @@ extern "C" { XP_U16 version; \ XP_U8 nReadBits; \ XP_U8 nWriteBits; \ + XP_U8 REFCOUNT; \ XP_Bool isOpen; \ MPSLOT @@ -93,7 +100,9 @@ mem_stream_make( MPFORMAL VTableMgr* vtmgr, void* closure, result->onClose = onClose; result->isOpen = XP_TRUE; - +#ifdef XWFEATURE_STREAMREF + result->refCount = 1; +#endif return (XWStreamCtxt*)result; } /* make_mem_stream */ @@ -492,18 +501,34 @@ mem_stream_setPos( XWStreamCtxt* p_sctx, PosWhich which, XWStreamPos newpos ) return oldPos; } /* mem_stream_setPos */ +#ifdef XWFEATURE_STREAMREF +static XWStreamCtxt* +mem_stream_ref( XWStreamCtxt* p_sctx ) +{ + MemStreamCtxt* stream = (MemStreamCtxt*)p_sctx; + ++stream->refCount; + return p_sctx; +} +#endif + static void mem_stream_destroy( XWStreamCtxt* p_sctx, XWEnv xwe ) { MemStreamCtxt* stream = (MemStreamCtxt*)p_sctx; + if ( 0 ) { +#ifdef XWFEATURE_STREAMREF + } else if ( 0 == --stream->refCount ) { +#else + } else { +#endif + if ( stream->isOpen ) { + stream_close( p_sctx, xwe ); + } - if ( stream->isOpen ) { - stream_close( p_sctx, xwe ); - } - - XP_FREEP( stream->mpool, &stream->buf ); + XP_FREEP( stream->mpool, &stream->buf ); - XP_FREE( stream->mpool, stream ); + XP_FREE( stream->mpool, stream ); + } } /* mem_stream_destroy */ static StreamCtxVTable* @@ -535,7 +560,9 @@ make_vtable( MemStreamCtxt* stream ) SET_VTABLE_ENTRY( vtable, stream_setPos, mem ); SET_VTABLE_ENTRY( vtable, stream_getPos, mem ); - +#ifdef XWFEATURE_STREAMREF + SET_VTABLE_ENTRY( vtable, stream_ref, mem ); +#endif SET_VTABLE_ENTRY( vtable, stream_destroy, mem ); SET_VTABLE_ENTRY( vtable, stream_open, mem ); SET_VTABLE_ENTRY( vtable, stream_close, mem ); diff --git a/xwords4/common/xwstream.h b/xwords4/common/xwstream.h index ff881df78..be86cb954 100644 --- a/xwords4/common/xwstream.h +++ b/xwords4/common/xwstream.h @@ -55,6 +55,9 @@ typedef XP_U8 PosWhich; typedef struct StreamCtxVTable { +#ifdef XWFEATURE_STREAMREF + XWStreamCtxt* (*m_stream_ref)( XWStreamCtxt* dctx ); +#endif void (*m_stream_destroy)( XWStreamCtxt* dctx, XWEnv xwe ); XP_U8 (*m_stream_getU8)( DBG_PROC_FORMAL XWStreamCtxt* dctx ); @@ -110,6 +113,10 @@ struct XWStreamCtxt { StreamCtxVTable* vtable; }; +#ifdef XWFEATURE_STREAMREF +# define stream_ref(sc) \ + (sc)->vtable->m_stream_ref((sc)) +#endif #define stream_destroy(sc,e) \ (sc)->vtable->m_stream_destroy(sc,(e)) diff --git a/xwords4/wasm/Makefile b/xwords4/wasm/Makefile index 5e2481ad4..082a8a80e 100644 --- a/xwords4/wasm/Makefile +++ b/xwords4/wasm/Makefile @@ -42,6 +42,7 @@ DEFINES += -DXWFEATURE_DICTSANITY DEFINES += -DPOINTER_SUPPORT DEFINES += -DPLATFORM_WASM DEFINES += -DXWFEATURE_CROSSHAIRS +DEFINES += -DXWFEATURE_STREAMREF DEFINES += -DNATIVE_NLI DEFINES += -DDEBUG_REF DEFINES += -Wno-switch diff --git a/xwords4/wasm/main.c b/xwords4/wasm/main.c index 92beadc3a..98e68e38b 100644 --- a/xwords4/wasm/main.c +++ b/xwords4/wasm/main.c @@ -603,6 +603,34 @@ onPlayerNamed( void* closure, const char* name ) } } +static void +doReplace( Globals* globals, const NetLaunchInfo* invite ) +{ + cleanupGame( globals ); + + gi_disposePlayerInfo( MPPARM(globals->mpool) &globals->gs.gi ); + XP_MEMSET( &globals->gs.gi, 0, sizeof(globals->gs.gi) ); + + globals->gs.util = wasm_util_make( MPPARM(globals->mpool) &globals->gs.gi, + globals->dutil, globals ); + + game_makeFromInvite( MPPARM(globals->mpool) NULL, invite, + &globals->gs.game, &globals->gs.gi, + globals->dict, NULL, + globals->gs.util, globals->draw, + &globals->cp, &globals->procs ); + ensureName( globals ); + + const char* name = get_stored_value( KEY_PLAYER_NAME ); + if ( NULL != name ) { + startGame( globals, name ); + free( (void*)name ); + } else { + const char* msg = "Please enter your name so you opponent knows it's you"; + call_get_string( msg, "Player 1", onPlayerNamed, globals ); + } +} + static void onReplaceConfirmed( void* closure, bool confirmed ) { @@ -610,29 +638,7 @@ onReplaceConfirmed( void* closure, bool confirmed ) Globals* globals = ars->globals; if ( confirmed ) { - cleanupGame( globals ); - - gi_disposePlayerInfo( MPPARM(globals->mpool) &globals->gs.gi ); - XP_MEMSET( &globals->gs.gi, 0, sizeof(globals->gs.gi) ); - - globals->gs.util = wasm_util_make( MPPARM(globals->mpool) &globals->gs.gi, - globals->dutil, globals ); - - game_makeFromInvite( MPPARM(globals->mpool) NULL, &ars->invite, - &globals->gs.game, &globals->gs.gi, - globals->dict, NULL, - globals->gs.util, globals->draw, - &globals->cp, &globals->procs ); - ensureName( globals ); - - const char* name = get_stored_value( KEY_PLAYER_NAME ); - if ( NULL != name ) { - startGame( globals, name ); - free( (void*)name ); - } else { - const char* msg = "Please enter your name so you opponent knows it's you"; - call_get_string( msg, "Player 1", onPlayerNamed, globals ); - } + doReplace( globals, &ars->invite ); } XP_FREE( globals->mpool, ars ); @@ -652,7 +658,7 @@ gameFromInvite( Globals* globals, const NetLaunchInfo* invite ) } else { AskReplaceState* ars = XP_MALLOC( globals->mpool, sizeof(*ars) ); ars->globals = globals; - XP_MEMCPY( &ars->invite, invite, sizeof(ars->invite) ); + ars->invite = *invite; call_confirm( globals, "Invitation received; replace current game?", onReplaceConfirmed, ars ); needsLoad = false; @@ -660,6 +666,9 @@ gameFromInvite( Globals* globals, const NetLaunchInfo* invite ) } else if ( invite->lang != 1 ) { call_alert( "Invitations are only supported for play in English right now." ); needsLoad = false; + } else { + // No game open. Just do it + doReplace( globals, invite ); } bool loaded = !needsLoad; @@ -807,13 +816,39 @@ main_gameFromInvite( Globals* globals, const NetLaunchInfo* invite ) } } +typedef struct _OpenForMessageState { + Globals* globals; + int gameID; + CommsAddrRec from; + XWStreamCtxt* stream; +} OpenForMessageState; + +static void +onOpenForMsgConfirmed( void* closure, bool confirmed ) +{ + OpenForMessageState* ofm = (OpenForMessageState*)closure; + Globals* globals = ofm->globals; + if ( confirmed ) { + + char gameID[16]; + formatGameID( gameID, sizeof(gameID), ofm->gameID ); + loadAndDraw( globals, NULL, gameID, NULL ); + XP_ASSERT( globals->gs.gi.gameID == ofm->gameID ); + + if ( game_receiveMessage( &globals->gs.game, NULL, ofm->stream, &ofm->from ) ) { + updateScreen( globals, true ); + } + } + stream_destroy( ofm->stream, NULL ); + XP_FREE( globals->mpool, ofm ); +} + void main_onGameMessage( Globals* globals, XP_U32 gameID, const CommsAddrRec* from, XWStreamCtxt* stream ) { - if ( gameID == globals->gs.gi.gameID ) { - XP_Bool draw = game_receiveMessage( &globals->gs.game, NULL, stream, from ); - if ( draw ) { + if ( gameID == globals->gs.gi.gameID ) { /* current game open */ + if ( game_receiveMessage( &globals->gs.game, NULL, stream, from ) ) { updateScreen( globals, true ); } } else { @@ -822,20 +857,28 @@ main_onGameMessage( Globals* globals, XP_U32 gameID, if ( have_stored_value( key ) ) { formatNameKey( key, sizeof(key), gameID ); const char* name = get_stored_value( key ); - char buf[128]; - snprintf( buf, sizeof(buf), "Dropping packet for closed game \"%s\"", name ); + XP_ASSERT( !!name ); + char msg[128]; + snprintf( msg, sizeof(msg), "Move arrived for closed game \"%s\"; " + "Shall I open it?", name ); free( (void*)name); - call_alert( buf ); + + OpenForMessageState* ofm = XP_MALLOC( globals->mpool, sizeof(*ofm) ); + ofm->globals = globals; + ofm->gameID = gameID; + ofm->from = *from; + ofm->stream = stream_ref( stream ); + + call_confirm( globals, msg, onOpenForMsgConfirmed, ofm ); } else { XWStreamCtxt* stream = mem_stream_make_raw( MPPARM(globals->mpool) globals->vtMgr ); dvc_makeMQTTNoSuchGame( globals->dutil, NULL, stream, gameID ); sendStreamToDev( stream, &from->u.mqtt.devID ); - call_alert( "Dropping packet for non-existant game" ); + call_alert( "Dropping move for deleted game" ); } } - LOG_RETURN_VOID(); } void