save and restore games (though there's a global game for now).

This commit is contained in:
ehouse 2010-01-09 17:19:25 +00:00
parent 5d9dc49bf0
commit a91f662327
3 changed files with 191 additions and 23 deletions

View file

@ -11,12 +11,16 @@ import android.view.MenuInflater;
import android.content.res.AssetManager;
import java.io.InputStream;
import android.os.Handler;
import java.io.FileOutputStream;
import java.io.FileInputStream;
import android.content.res.Configuration;
import org.eehouse.android.xw4.jni.*;
public class BoardActivity extends Activity implements XW_UtilCtxt, Runnable {
private static final String CUR_GAME = "cur_game";
private BoardView m_view;
private int m_jniGamePtr;
private CurGameInfo m_gi;
@ -73,12 +77,26 @@ public class BoardActivity extends Activity implements XW_UtilCtxt, Runnable {
}
// am.close(); don't close! won't work subsequently
Utils.logf( "calling game_makeNewGame; passing bytes: " + dictBytes.length );
m_jniGamePtr = XwJNI.game_makeNewGame( m_gi, this, m_view, 0,
m_jniGamePtr = XwJNI.initJNI();
byte[] stream = savedGame();
if ( null == stream ||
! XwJNI.game_makeFromStream( m_jniGamePtr, stream,
m_gi, dictBytes, this,
m_view, m_prefs,
null ) ) {
XwJNI.game_makeNewGame( m_jniGamePtr, m_gi, this, m_view, 0,
m_prefs, null, dictBytes );
}
m_view.startHandling( this, m_jniGamePtr, m_gi );
XwJNI.server_do( m_jniGamePtr );
} // onCreate
protected void onPause() {
// save state here
saveGame();
super.onPause();
}
protected void onDestroy()
@ -106,7 +124,6 @@ public class BoardActivity extends Activity implements XW_UtilCtxt, Runnable {
return draw;
}
public boolean onOptionsItemSelected(MenuItem item) {
boolean draw = false;
boolean handled = true;
@ -152,6 +169,39 @@ public class BoardActivity extends Activity implements XW_UtilCtxt, Runnable {
return handled;
}
private void saveGame()
{
byte[] state = XwJNI.game_saveToStream( m_jniGamePtr, m_gi );
try {
FileOutputStream out = openFileOutput( CUR_GAME, MODE_PRIVATE );
out.write( state );
out.close();
} catch ( java.io.IOException ex ) {
Utils.logf( "got IOException: " + ex.toString() );
}
}
private byte[] savedGame()
{
byte[] stream = null;
try {
FileInputStream in = openFileInput( CUR_GAME );
int len = in.available();
Utils.logf( "savedGame: got " + len + " bytes." );
stream = new byte[len];
in.read( stream, 0, len );
in.close();
} catch ( java.io.FileNotFoundException fnf ) {
Utils.logf( fnf.toString() );
stream = null;
} catch ( java.io.IOException io ) {
Utils.logf( io.toString() );
stream = null;
}
return stream;
}
// gets called for orientation changes only if
// android:configChanges="orientation" set in AndroidManifest.xml

View file

@ -19,9 +19,25 @@ public class XwJNI {
int when, int handle );
// Game methods
public static native int game_makeNewGame( CurGameInfo gi, XW_UtilCtxt util,
DrawCtx draw, int gameID, CommonPrefs cp,
TransportProcs procs, byte[] dict );
public static native int initJNI();
public static native void game_makeNewGame( int gamePtr,
CurGameInfo gi,
XW_UtilCtxt util,
DrawCtx draw, int gameID,
CommonPrefs cp,
TransportProcs procs,
byte[] dict );
public static native boolean game_makeFromStream( int gamePtr,
byte[] stream,
CurGameInfo gi,
byte[] dict,
XW_UtilCtxt util,
DrawCtx draw,
CommonPrefs cp,
TransportProcs procs );
public static native byte[] game_saveToStream( int gamePtr,
CurGameInfo gi );
public static native void game_dispose( int gamePtr );
// Board methods

View file

@ -21,7 +21,6 @@ makeGI( MPFORMAL JNIEnv* env, jobject j_gi )
{
CurGameInfo* gi = (CurGameInfo*)XP_CALLOC( mpool, sizeof(*gi) );
int nPlayers, robotSmartness, boardSize;
int ii;
XP_UCHAR buf[256]; /* in case needs whole path */
bool success = getInt( env, j_gi, "nPlayers", &nPlayers )
@ -49,6 +48,7 @@ makeGI( MPFORMAL JNIEnv* env, jobject j_gi )
if ( getObject( env, j_gi, "players",
"[Lorg/eehouse/android/xw4/jni/LocalPlayer;",
&jplayers ) ) {
int ii;
for ( ii = 0; ii < gi->nPlayers; ++ii ) {
LocalPlayer* lp = &gi->players[ii];
@ -74,6 +74,45 @@ makeGI( MPFORMAL JNIEnv* env, jobject j_gi )
return gi;
} /* makeGI */
static void
setJGI( JNIEnv* env, jobject jgi, const CurGameInfo* gi )
{
// set fields
bool success = setInt( env, jgi, "nPlayers", gi->nPlayers )
&& setInt( env, jgi, "boardSize", gi->boardSize )
&& setInt( env, jgi, "robotSmartness", gi->robotSmartness )
&& setBool( env, jgi, "hintsNotAllowed", gi->hintsNotAllowed )
&& setBool( env, jgi, "timerEnabled", gi->timerEnabled )
&& setBool( env, jgi, "allowPickTiles", gi->allowPickTiles )
&& setBool( env, jgi, "allowHintRect", gi->allowHintRect )
&& setString( env, jgi, "dictName", gi->dictName )
;
XP_ASSERT( success );
jobject jplayers;
if ( getObject( env, jgi, "players",
"[Lorg/eehouse/android/xw4/jni/LocalPlayer;",
&jplayers ) ) {
int ii;
for ( ii = 0; ii < gi->nPlayers; ++ii ) {
const LocalPlayer* lp = &gi->players[ii];
jobject jlp = (*env)->GetObjectArrayElement( env, jplayers, ii );
setBool( env, jlp, "isRobot", lp->isRobot );
setBool( env, jlp, "isLocal", lp->isLocal );
setString( env, jlp, "name", lp->name );
setString( env, jlp, "password", lp->password );
setInt( env, jlp, "secondsUsed", lp->secondsUsed );
(*env)->DeleteLocalRef( env, jlp );
}
(*env)->DeleteLocalRef( env, jplayers );
} else {
XP_ASSERT(0);
}
}
static void
destroyGI( MPFORMAL CurGameInfo* gi )
{
@ -92,11 +131,6 @@ loadCommonPrefs( JNIEnv* env, CommonPrefs* cp, jobject j_cp )
return success;
}
/*
generated by running:
(cd /home/andy/dev/XWORDS/android/XWords4/bin/classes; javah -o /tmp/foo.h org.eehouse.android.xw4.jni.XwJNI)
*/
typedef struct _GameAndMPool {
XWGame game;
AndGlobals* globals;
@ -104,19 +138,30 @@ typedef struct _GameAndMPool {
} GameAndMPool;
JNIEXPORT jint JNICALL
Java_org_eehouse_android_xw4_jni_XwJNI_game_1makeNewGame
( JNIEnv *env, jclass C, jobject j_gi, jobject j_util, jobject j_draw,
jint gameID, jobject j_cp, jobject j_procs, jbyteArray jDictBytes )
Java_org_eehouse_android_xw4_jni_XwJNI_initJNI
( JNIEnv* env, jclass C )
{
LOG_FUNC();
MemPoolCtx* mpool = mpool_make();
GameAndMPool* game = XP_MALLOC( mpool, sizeof(*game) );
GameAndMPool* game = (GameAndMPool*)XP_CALLOC( mpool, sizeof(*game) );
AndGlobals* globals = XP_MALLOC( mpool, sizeof( *globals ) );
game->mpool = mpool;
game->globals = globals;
globals->vtMgr = make_vtablemgr(MPPARM_NOCOMMA(mpool));
return (jint) game;
}
JNIEXPORT void JNICALL
Java_org_eehouse_android_xw4_jni_XwJNI_game_1makeNewGame
( JNIEnv* env, jclass C, jint gamePtr, jobject j_gi, jobject j_util,
jobject j_draw, jint gameID, jobject j_cp, jobject j_procs,
jbyteArray jDictBytes )
{
LOG_FUNC();
GameAndMPool* game = (GameAndMPool*)gamePtr;
MemPoolCtx* mpool = game->mpool;
AndGlobals* globals = game->globals;
CurGameInfo* gi = makeGI( MPPARM(mpool) env, j_gi );
globals->gi = gi;
XW_UtilCtxt* util = makeUtil( MPPARM(mpool) env, j_util, gi, globals );
@ -142,13 +187,70 @@ Java_org_eehouse_android_xw4_jni_XwJNI_game_1makeNewGame
}
#endif
XP_ASSERT( !!dict );
globals->dict = dict;
model_setDictionary( game->game.model, dict );
return (jint) game;
} /* makeNewGame */
JNIEXPORT jboolean JNICALL
Java_org_eehouse_android_xw4_jni_XwJNI_game_1makeFromStream
( JNIEnv* env, jclass C, jint gamePtr, jbyteArray jstream,
jobject /*out*/jgi, jbyteArray jdict, jobject jutil, jobject jdraw,
jobject jcp, jobject jprocs )
{
GameAndMPool* game = (GameAndMPool*)gamePtr;
MemPoolCtx* mpool = game->mpool;
AndGlobals* globals = game->globals;
globals->gi = (CurGameInfo*)XP_CALLOC( mpool, sizeof(*globals->gi) );
DictionaryCtxt* dict = makeDict( MPPARM(mpool) env, jdict );
globals->util = makeUtil( MPPARM(mpool) env, jutil, globals->gi, globals );
globals->dctx = makeDraw( MPPARM(mpool) env, jdraw );
jbyte* jelems = (*env)->GetByteArrayElements( env, jstream, NULL );
XWStreamCtxt* stream = mem_stream_make( game->mpool, globals->vtMgr,
NULL, 0, NULL );
int len = (*env)->GetArrayLength( env, jstream );
XP_LOGF( "putting %d bytes into stream", len );
stream_putBytes( stream, jelems, len );
(*env)->ReleaseByteArrayElements( env, jstream, jelems, 0 );
CommonPrefs cp;
(void)loadCommonPrefs( env, &cp, jcp );
XP_Bool result = game_makeFromStream( mpool, stream, &game->game,
globals->gi, dict,
globals->util, globals->dctx, &cp,
NULL );
stream_destroy( stream );
setJGI( env, jgi, globals->gi );
LOG_RETURNF( "%s", result?"success":"failure" );
return result;
} /* makeFromStream */
JNIEXPORT jbyteArray JNICALL
Java_org_eehouse_android_xw4_jni_XwJNI_game_1saveToStream
( JNIEnv* env, jclass C, jint gamePtr, jobject jgi )
{
GameAndMPool* game = (GameAndMPool*)gamePtr;
AndGlobals* globals = game->globals;
CurGameInfo* gi = makeGI( MPPARM(game->mpool) env, jgi );
XWStreamCtxt* stream = mem_stream_make( game->mpool, globals->vtMgr,
NULL, 0, NULL );
game_saveToStream( &game->game, gi, stream );
destroyGI( MPPARM(game->mpool) gi );
int nBytes = stream_getSize( stream );
jbyteArray jarr = (*env)->NewByteArray( env, nBytes );
jbyte* jelems = (*env)->GetByteArrayElements( env, jarr, NULL );
stream_getBytes( stream, jelems, nBytes );
(*env)->ReleaseByteArrayElements( env, jarr, jelems, 0 );
stream_destroy( stream );
(*env)->DeleteLocalRef( env, jarr );
return jarr;
}
JNIEXPORT void JNICALL Java_org_eehouse_android_xw4_jni_XwJNI_game_1dispose
( JNIEnv * env, jclass claz, jint gamePtr )
{