mirror of
git://xwords.git.sourceforge.net/gitroot/xwords/xwords
synced 2025-01-15 15:41:24 +01:00
When a game's consumated and guest discovers it isn't using the same
dict, give chance to switch, and to download if required. Because of the way the JNI thread works, and JNI's requirement in general that env instances match up (e.g. dicts must be destroyed in the same thread that creates them), substituting into a live game is too hard. So the game's saved with its new dict and then reloaded.
This commit is contained in:
parent
13c74cfbd5
commit
aec03fc572
12 changed files with 140 additions and 22 deletions
|
@ -263,13 +263,14 @@ and_util_informUndo( XW_UtilCtxt* uc )
|
|||
}
|
||||
|
||||
static void
|
||||
and_util_informNetDict( XW_UtilCtxt* uc, const XP_UCHAR* oldName,
|
||||
and_util_informNetDict( XW_UtilCtxt* uc, XP_LangCode lang,
|
||||
const XP_UCHAR* oldName,
|
||||
const XP_UCHAR* newName, const XP_UCHAR* newSum,
|
||||
XWPhoniesChoice phoniesAction )
|
||||
{
|
||||
LOG_FUNC();
|
||||
UTIL_CBK_HEADER( "informNetDict",
|
||||
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;L"
|
||||
"(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;L"
|
||||
PKG_PATH("jni/CurGameInfo$XWPhoniesChoice") ";)V" );
|
||||
jstring jnew = (*env)->NewStringUTF( env, newName );
|
||||
jstring jsum = (*env)->NewStringUTF( env, newSum );
|
||||
|
@ -277,7 +278,8 @@ and_util_informNetDict( XW_UtilCtxt* uc, const XP_UCHAR* oldName,
|
|||
jobject jphon = intToJEnum( env, phoniesAction,
|
||||
PKG_PATH("jni/CurGameInfo$XWPhoniesChoice") );
|
||||
|
||||
(*env)->CallVoidMethod( env, util->jutil, mid, jold, jnew, jsum, jphon );
|
||||
(*env)->CallVoidMethod( env, util->jutil, mid, lang, jold, jnew, jsum,
|
||||
jphon );
|
||||
deleteLocalRefs( env, jnew, jold, jsum, jphon, DELETE_NO_REF );
|
||||
|
||||
UTIL_CBK_TAIL();
|
||||
|
|
|
@ -1287,6 +1287,22 @@ Java_org_eehouse_android_xw4_jni_XwJNI_game_1hasComms
|
|||
return result;
|
||||
}
|
||||
|
||||
#ifdef XWFEATURE_CHANGEDICT
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_org_eehouse_android_xw4_jni_XwJNI_game_1changeDict
|
||||
( JNIEnv* env, jclass C, jint gamePtr, jobject jgi, jstring jname,
|
||||
jbyteArray jDictBytes, jstring jpath )
|
||||
{
|
||||
XWJNI_START_GLOBALS();
|
||||
DictionaryCtxt* dict = makeDict( MPPARM(mpool) env, globals->jniutil,
|
||||
jname, jDictBytes, jpath, NULL, false );
|
||||
game_changeDict( MPPARM(mpool) &state->game, globals->gi, dict );
|
||||
setJGI( env, jgi, globals->gi );
|
||||
XWJNI_END();
|
||||
return XP_FALSE; /* no need to redraw */
|
||||
}
|
||||
#endif
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_org_eehouse_android_xw4_jni_XwJNI_comms_1resendAll
|
||||
( JNIEnv* env, jclass C, jint gamePtr, jboolean thenAck )
|
||||
|
|
|
@ -2110,9 +2110,16 @@
|
|||
<!-- -->
|
||||
<string name="inform_dict_diffversionf">You and the host of this
|
||||
game are using different versions of the wordlist %1$s.</string>
|
||||
<string name="inform_dict_title">Wordlist mismatch</string>
|
||||
<!-- -->
|
||||
<string name="inform_dict_diffdictf">You are using the wordlist
|
||||
%1$s but the game host is using %2$s.</string>
|
||||
%1$s but the game host is using %2$s. Would you like to use %3$s
|
||||
too?</string>
|
||||
<string name="inform_dict_download">\u0020(You will have to download it
|
||||
first.)</string>
|
||||
<!-- Shown in toast when relaunching after switching dicts -->
|
||||
<string name="reload_new_dict">Reloading game with %1$s</string>
|
||||
|
||||
<!-- -->
|
||||
<string name="inform_dict_phonies">\u0020(Remember that phonies
|
||||
will be discarded based on the host\'s wordlist.)</string>
|
||||
|
|
|
@ -56,7 +56,8 @@ import org.eehouse.android.xw4.jni.CurGameInfo.DeviceRole;
|
|||
|
||||
|
||||
public class BoardActivity extends XWActivity
|
||||
implements TransportProcs.TPMsgHandler, View.OnClickListener {
|
||||
implements TransportProcs.TPMsgHandler, View.OnClickListener,
|
||||
NetUtils.DownloadFinishedListener {
|
||||
|
||||
public static final String INTENT_KEY_CHAT = "chat";
|
||||
|
||||
|
@ -72,6 +73,9 @@ public class BoardActivity extends XWActivity
|
|||
private static final int DLG_INVITE = DLG_OKONLY + 9;
|
||||
private static final int DLG_SCORES_BLK = DLG_OKONLY + 10;
|
||||
private static final int PICK_TILE_REQUESTTRAY_BLK = DLG_OKONLY + 11;
|
||||
private static final int DLG_USEDICT = DLG_OKONLY + 12;
|
||||
private static final int DLG_GETDICT = DLG_OKONLY + 13;
|
||||
|
||||
|
||||
private static final int CHAT_REQUEST = 1;
|
||||
private static final int BT_INVITE_RESULT = 2;
|
||||
|
@ -105,6 +109,7 @@ public class BoardActivity extends XWActivity
|
|||
private static final String PWDNAME = "PWDNAME";
|
||||
private static final String TOASTSTR = "TOASTSTR";
|
||||
private static final String WORDS = "WORDS";
|
||||
private static final String GETDICT = "GETDICT";
|
||||
|
||||
private BoardView m_view;
|
||||
private int m_jniGamePtr;
|
||||
|
@ -155,6 +160,7 @@ public class BoardActivity extends XWActivity
|
|||
private String m_toastStr;
|
||||
private String[] m_words;
|
||||
private String m_pwdName;
|
||||
private String m_getDict;
|
||||
|
||||
private int m_missing;
|
||||
private boolean m_haveInvited = false;
|
||||
|
@ -244,6 +250,30 @@ public class BoardActivity extends XWActivity
|
|||
Utils.setRemoveOnDismiss( this, dialog, id );
|
||||
break;
|
||||
|
||||
case DLG_USEDICT:
|
||||
case DLG_GETDICT:
|
||||
lstnr = new DialogInterface.OnClickListener() {
|
||||
public void onClick( DialogInterface dlg,
|
||||
int whichButton ) {
|
||||
if ( DLG_USEDICT == id ) {
|
||||
setGotGameDict();
|
||||
} else {
|
||||
NetUtils.launchAndDownload( BoardActivity.this,
|
||||
m_gi.dictLang,
|
||||
m_getDict,
|
||||
BoardActivity.this );
|
||||
}
|
||||
}
|
||||
};
|
||||
dialog = new AlertDialog.Builder( this )
|
||||
.setTitle( m_dlgTitle )
|
||||
.setMessage( m_dlgBytes )
|
||||
.setPositiveButton( R.string.button_yes, lstnr )
|
||||
.setNegativeButton( R.string.button_no, null )
|
||||
.create();
|
||||
Utils.setRemoveOnDismiss( this, dialog, id );
|
||||
break;
|
||||
|
||||
case DLG_DELETED:
|
||||
ab = new AlertDialog.Builder( BoardActivity.this )
|
||||
.setTitle( R.string.query_title )
|
||||
|
@ -512,6 +542,7 @@ public class BoardActivity extends XWActivity
|
|||
outState.putString( TOASTSTR, m_toastStr );
|
||||
outState.putStringArray( WORDS, m_words );
|
||||
outState.putString( PWDNAME, m_pwdName );
|
||||
outState.putString( GETDICT, m_getDict );
|
||||
}
|
||||
|
||||
private void getBundledData( Bundle bundle )
|
||||
|
@ -524,6 +555,7 @@ public class BoardActivity extends XWActivity
|
|||
m_toastStr = bundle.getString( TOASTSTR );
|
||||
m_words = bundle.getStringArray( WORDS );
|
||||
m_pwdName = bundle.getString( PWDNAME );
|
||||
m_getDict = bundle.getString( GETDICT );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1014,6 +1046,31 @@ public class BoardActivity extends XWActivity
|
|||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
// NetUtils.DownloadFinishedListener interface
|
||||
//////////////////////////////////////////////////
|
||||
public void downloadFinished( final boolean success )
|
||||
{
|
||||
if ( success ) {
|
||||
post( new Runnable() {
|
||||
public void run() {
|
||||
setGotGameDict();
|
||||
}
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
private void setGotGameDict()
|
||||
{
|
||||
Assert.assertNotNull( m_getDict );
|
||||
m_jniThread.setSaveDict( m_getDict );
|
||||
|
||||
String msg = getString( R.string.reload_new_dict, m_getDict );
|
||||
Utils.showToast( this, msg );
|
||||
finish();
|
||||
GameUtils.launchGame( this, m_rowid, false );
|
||||
}
|
||||
|
||||
private XwJNI.XP_Key keyCodeToXPKey( int keyCode )
|
||||
{
|
||||
XwJNI.XP_Key xpKey = XwJNI.XP_Key.XP_KEY_NONE;
|
||||
|
@ -1473,7 +1530,8 @@ public class BoardActivity extends XWActivity
|
|||
}
|
||||
|
||||
@Override
|
||||
public void informNetDict( String oldName, String newName, String newSum,
|
||||
public void informNetDict( int code, String oldName,
|
||||
String newName, String newSum,
|
||||
CurGameInfo.XWPhoniesChoice phonies )
|
||||
{
|
||||
// If it's same dict and same sum, we're good. That
|
||||
|
@ -1492,14 +1550,18 @@ public class BoardActivity extends XWActivity
|
|||
} else {
|
||||
// Different dict! If we have the other one, switch
|
||||
// to it. Otherwise offer to download
|
||||
int dlgID;
|
||||
msg = getString( R.string.inform_dict_diffdictf,
|
||||
oldName, newName );
|
||||
}
|
||||
if ( null != msg ) {
|
||||
if ( CurGameInfo.XWPhoniesChoice.PHONIES_DISALLOW == phonies ) {
|
||||
msg += getString( R.string.inform_dict_phonies );
|
||||
oldName, newName, newName );
|
||||
if ( DictLangCache.haveDict( BoardActivity.this, code,
|
||||
newName ) ) {
|
||||
dlgID = DLG_USEDICT;
|
||||
} else {
|
||||
dlgID = DLG_GETDICT;
|
||||
msg += getString( R.string.inform_dict_download );
|
||||
}
|
||||
nonBlockingDialog( DLG_OKONLY, msg );
|
||||
m_getDict = newName;
|
||||
nonBlockingDialog( dlgID, msg );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1779,6 +1841,11 @@ public class BoardActivity extends XWActivity
|
|||
case DLG_BADWORDS:
|
||||
m_dlgTitle = R.string.badwords_title;
|
||||
break;
|
||||
case DLG_USEDICT:
|
||||
case DLG_GETDICT:
|
||||
m_dlgTitle = R.string.inform_dict_title;
|
||||
break;
|
||||
|
||||
default:
|
||||
Assert.fail();
|
||||
}
|
||||
|
|
|
@ -127,6 +127,7 @@ public class JNIThread extends Thread {
|
|||
private SyncedDraw m_drawer;
|
||||
private static final int kMinDivWidth = 10;
|
||||
private int m_connsIconID = 0;
|
||||
private String m_newDict = null;
|
||||
|
||||
LinkedBlockingQueue<QueueElem> m_queue;
|
||||
|
||||
|
@ -199,6 +200,14 @@ public class JNIThread extends Thread {
|
|||
}
|
||||
}
|
||||
|
||||
// Gross hack. This is the easiest way to set the dict without
|
||||
// rewriting game loading code or running into cross-threading
|
||||
// issues.
|
||||
public void setSaveDict( String newDict )
|
||||
{
|
||||
m_newDict = newDict;
|
||||
}
|
||||
|
||||
private boolean toggleTray() {
|
||||
boolean draw;
|
||||
int state = XwJNI.board_getTrayVisState( m_jniGamePtr );
|
||||
|
@ -272,9 +281,12 @@ public class JNIThread extends Thread {
|
|||
XwJNI.server_do( m_jniGamePtr );
|
||||
|
||||
XwJNI.game_getGi( m_jniGamePtr, m_gi );
|
||||
if ( null != m_newDict ) {
|
||||
m_gi.dictName = m_newDict;
|
||||
}
|
||||
GameSummary summary = new GameSummary( m_context, m_gi );
|
||||
XwJNI.game_summarize( m_jniGamePtr, summary );
|
||||
byte[] state = XwJNI.game_saveToStream( m_jniGamePtr, null );
|
||||
byte[] state = XwJNI.game_saveToStream( m_jniGamePtr, m_gi );
|
||||
GameUtils.saveGame( m_context, state, m_lock, false );
|
||||
DBUtils.saveSummary( m_context, m_lock, summary );
|
||||
// There'd better be no way for saveGame above to fail!
|
||||
|
|
|
@ -118,8 +118,8 @@ public interface UtilCtxt {
|
|||
void informMove( String expl, String words );
|
||||
void informUndo();
|
||||
|
||||
void informNetDict( String oldName, String newName, String newSum,
|
||||
CurGameInfo.XWPhoniesChoice phonies );
|
||||
void informNetDict( int lang, String oldName, String newName,
|
||||
String newSum, CurGameInfo.XWPhoniesChoice phonies );
|
||||
|
||||
void informMissing( boolean isServer, CommsAddrRec.CommsConnType connType,
|
||||
int nMissingPlayers );
|
||||
|
|
|
@ -228,7 +228,8 @@ public class UtilCtxtImpl implements UtilCtxt {
|
|||
subclassOverride( "informUndo" );
|
||||
}
|
||||
|
||||
public void informNetDict( String oldName, String newName, String newSum,
|
||||
public void informNetDict( int lang, String oldName,
|
||||
String newName, String newSum,
|
||||
CurGameInfo.XWPhoniesChoice phonies )
|
||||
{
|
||||
subclassOverride( "informNetDict" );
|
||||
|
|
|
@ -132,6 +132,13 @@ public class XwJNI {
|
|||
public static native void game_getState( int gamePtr,
|
||||
JNIThread.GameStateInfo gsi );
|
||||
public static native boolean game_hasComms( int gamePtr );
|
||||
|
||||
// Keep for historical purposes. But threading issues make it
|
||||
// impossible to implement this without a ton of work.
|
||||
// public static native boolean game_changeDict( int gamePtr, CurGameInfo gi,
|
||||
// String dictName,
|
||||
// byte[] dictBytes,
|
||||
// String dictPath );
|
||||
public static native void game_dispose( int gamePtr );
|
||||
|
||||
// Board methods
|
||||
|
|
|
@ -1295,7 +1295,9 @@ client_readInitialMessage( ServerCtxt* server, XWStreamCtxt* stream )
|
|||
#ifdef STREAM_VERS_BIGBOARD
|
||||
if ( '\0' != rmtDictName[0] ) {
|
||||
const XP_UCHAR* ourName = dict_getShortName( curDict );
|
||||
util_informNetDict( server->vol.util, ourName, rmtDictName,
|
||||
util_informNetDict( server->vol.util,
|
||||
dict_getLangCode( curDict ),
|
||||
ourName, rmtDictName,
|
||||
rmtDictSum, localGI.phoniesAction );
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -130,7 +130,8 @@ typedef struct UtilVtable {
|
|||
void (*m_util_informMove)( XW_UtilCtxt* uc, XWStreamCtxt* expl,
|
||||
XWStreamCtxt* words );
|
||||
void (*m_util_informUndo)( XW_UtilCtxt* uc );
|
||||
void (*m_util_informNetDict)( XW_UtilCtxt* uc, const XP_UCHAR* oldName,
|
||||
void (*m_util_informNetDict)( XW_UtilCtxt* uc, XP_LangCode lang,
|
||||
const XP_UCHAR* oldName,
|
||||
const XP_UCHAR* newName,
|
||||
const XP_UCHAR* newSum,
|
||||
XWPhoniesChoice phoniesAction );
|
||||
|
@ -251,8 +252,9 @@ struct XW_UtilCtxt {
|
|||
(uc)->vtable->m_util_informMove( (uc),(e),(w))
|
||||
#define util_informUndo(uc) \
|
||||
(uc)->vtable->m_util_informUndo( (uc))
|
||||
#define util_informNetDict(uc, on, nn, ns, pa ) \
|
||||
(uc)->vtable->m_util_informNetDict( (uc), (on), (nn), (ns), (pa) )
|
||||
#define util_informNetDict(uc, cd, on, nn, ns, pa ) \
|
||||
(uc)->vtable->m_util_informNetDict( (uc), (cd), (on), (nn), (ns), \
|
||||
(pa) )
|
||||
#define util_notifyGameOver( uc, q ) \
|
||||
(uc)->vtable->m_util_notifyGameOver((uc), (q))
|
||||
|
||||
|
|
|
@ -395,7 +395,8 @@ curses_util_notifyGameOver( XW_UtilCtxt* uc, XP_S16 quitter )
|
|||
} /* curses_util_notifyGameOver */
|
||||
|
||||
static void
|
||||
curses_util_informNetDict( XW_UtilCtxt* uc, const XP_UCHAR* XP_UNUSED_DBG(oldName),
|
||||
curses_util_informNetDict( XW_UtilCtxt* uc, XP_LangCode XP_UNUSED(lang),
|
||||
const XP_UCHAR* XP_UNUSED_DBG(oldName),
|
||||
const XP_UCHAR* XP_UNUSED_DBG(newName),
|
||||
const XP_UCHAR* XP_UNUSED_DBG(newSum),
|
||||
XWPhoniesChoice phoniesAction )
|
||||
|
|
|
@ -1475,7 +1475,8 @@ gtk_util_notifyGameOver( XW_UtilCtxt* uc, XP_S16 quitter )
|
|||
} /* gtk_util_notifyGameOver */
|
||||
|
||||
static void
|
||||
gtk_util_informNetDict( XW_UtilCtxt* uc, const XP_UCHAR* oldName,
|
||||
gtk_util_informNetDict( XW_UtilCtxt* uc, XP_LangCode XP_UNUSED(lang),
|
||||
const XP_UCHAR* oldName,
|
||||
const XP_UCHAR* newName, const XP_UCHAR* newSum,
|
||||
XWPhoniesChoice phoniesAction )
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue