mirror of
git://xwords.git.sourceforge.net/gitroot/xwords/xwords
synced 2025-01-04 23:02:02 +01:00
3069 lines
93 KiB
C
3069 lines
93 KiB
C
/* -*- compile-command: "find-and-gradle.sh inXw4dDeb"; -*- */
|
|
/*
|
|
* Copyright © 2009 - 2022 by Eric House (xwords@eehouse.org). All rights
|
|
* reserved.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License as
|
|
* published by the Free Software Foundation; either version 2 of the
|
|
* License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*/
|
|
#include <string.h>
|
|
#include <sys/time.h>
|
|
#include <pthread.h>
|
|
|
|
#include <jni.h>
|
|
#include <android/log.h>
|
|
|
|
#include "comtypes.h"
|
|
#include "game.h"
|
|
#include "board.h"
|
|
#include "mempool.h"
|
|
#include "strutils.h"
|
|
#include "dbgutil.h"
|
|
#include "dictnry.h"
|
|
#include "dictiter.h"
|
|
#include "dictmgr.h"
|
|
#include "nli.h"
|
|
#include "smsproto.h"
|
|
#include "device.h"
|
|
#include "knownplyr.h"
|
|
|
|
#include "utilwrapper.h"
|
|
#include "drawwrapper.h"
|
|
#include "xportwrapper.h"
|
|
#include "anddict.h"
|
|
#include "andutils.h"
|
|
#include "andglobals.h"
|
|
#include "jniutlswrapper.h"
|
|
#include "paths.h"
|
|
|
|
#ifdef MAP_THREAD_TO_ENV
|
|
# define LOG_MAPPING
|
|
#endif
|
|
// #define LOG_MAPPING_ALL
|
|
|
|
#ifdef MAP_THREAD_TO_ENV
|
|
typedef struct _EnvThreadEntry {
|
|
JNIEnv* env;
|
|
pthread_t owner;
|
|
XP_U16 refcount;
|
|
#ifdef LOG_MAPPING
|
|
const char* ownerFunc;
|
|
#endif
|
|
} EnvThreadEntry;
|
|
|
|
struct _EnvThreadInfo {
|
|
pthread_mutex_t mtxThreads;
|
|
int nEntries;
|
|
EnvThreadEntry* entries;
|
|
MPSLOT
|
|
};
|
|
|
|
#endif
|
|
|
|
/* Globals for the whole game */
|
|
typedef struct _JNIGlobalState {
|
|
#ifdef MAP_THREAD_TO_ENV
|
|
EnvThreadInfo ti;
|
|
#endif
|
|
DictMgrCtxt* dictMgr;
|
|
SMSProto* smsProto;
|
|
VTableMgr* vtMgr;
|
|
XW_DUtilCtxt* dutil;
|
|
JNIUtilCtxt* jniutil;
|
|
XP_Bool mpoolInUse;
|
|
const char* mpoolUser;
|
|
MPSLOT
|
|
} JNIGlobalState;
|
|
|
|
#ifdef MEM_DEBUG
|
|
static MemPoolCtx*
|
|
getMPoolImpl( JNIGlobalState* globalState, const char* user )
|
|
{
|
|
if ( globalState->mpoolInUse ) {
|
|
XP_LOGFF( "mpoolInUse ALREADY SET!!!! (by %s)",
|
|
globalState->mpoolUser );
|
|
}
|
|
globalState->mpoolInUse = XP_TRUE;
|
|
globalState->mpoolUser = user;
|
|
return globalState->mpool;
|
|
}
|
|
|
|
#define GETMPOOL(gs) getMPoolImpl( (gs), __func__ )
|
|
|
|
static void
|
|
releaseMPool( JNIGlobalState* globalState )
|
|
{
|
|
// XP_ASSERT( globalState->mpoolInUse ); /* fired again!!! */
|
|
if ( !globalState->mpoolInUse ) {
|
|
XP_LOGFF( "line %d; ERROR ERROR ERROR mpoolInUse not set", __LINE__ );
|
|
}
|
|
globalState->mpoolInUse = XP_FALSE;
|
|
}
|
|
#else
|
|
# define releaseMPool(s)
|
|
#endif
|
|
|
|
|
|
#define GAMEPTR_IS_OBJECT
|
|
#ifdef GAMEPTR_IS_OBJECT
|
|
typedef jobject GamePtrType;
|
|
#else
|
|
typedef long GamePtrType;
|
|
#endif
|
|
|
|
#ifdef LOG_MAPPING
|
|
# ifdef DEBUG
|
|
static int
|
|
countUsed( const EnvThreadInfo* ti )
|
|
{
|
|
int count = 0;
|
|
for ( int ii = 0; ii < ti->nEntries; ++ii ) {
|
|
EnvThreadEntry* entry = &ti->entries[ii];
|
|
if ( 0 != entry->owner ) {
|
|
# ifdef LOG_MAPPING_ALL
|
|
XP_LOGFF( "ii=%d; owner: %x", ii, (unsigned int)entry->owner );
|
|
# endif
|
|
++count;
|
|
}
|
|
}
|
|
return count;
|
|
}
|
|
# endif
|
|
#endif
|
|
|
|
#ifdef MAP_THREAD_TO_ENV
|
|
# define MAP_THREAD( ti, env ) map_thread_prv( (ti), (env), __func__ )
|
|
|
|
static void
|
|
map_thread_prv( EnvThreadInfo* ti, JNIEnv* env, const char* caller )
|
|
{
|
|
pthread_t self = pthread_self();
|
|
|
|
pthread_mutex_lock( &ti->mtxThreads );
|
|
|
|
XP_Bool found = false;
|
|
int nEntries = ti->nEntries;
|
|
EnvThreadEntry* firstEmpty = NULL;
|
|
for ( int ii = 0; !found && ii < nEntries; ++ii ) {
|
|
EnvThreadEntry* entry = &ti->entries[ii];
|
|
if ( 0 == entry->owner ) {
|
|
if ( NULL == firstEmpty ) {
|
|
firstEmpty = entry;
|
|
}
|
|
} else if ( self == entry->owner ) {
|
|
found = true;
|
|
if ( env != entry->env ) {
|
|
/* this DOES happen!!! */
|
|
RAW_LOG( "(ti=%p): replacing env %p with env %p for thread %x",
|
|
ti, entry->env, env, (int)self );
|
|
entry->env = env;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( !found ) {
|
|
if ( !firstEmpty ) { /* out of slots */
|
|
if ( 0 == nEntries ) { /* first time */
|
|
nEntries = 2;
|
|
XP_ASSERT( !ti->entries );
|
|
} else {
|
|
nEntries *= 2;
|
|
}
|
|
EnvThreadEntry* entries = XP_CALLOC( ti->mpool, nEntries * sizeof(*entries) );
|
|
if ( !!ti->entries ) {
|
|
XP_MEMCPY( entries, ti->entries, ti->nEntries * sizeof(*ti->entries) );
|
|
}
|
|
firstEmpty = &entries[ti->nEntries]; /* first new entry */
|
|
ti->entries = entries;
|
|
ti->nEntries = nEntries;
|
|
#ifdef LOG_MAPPING
|
|
RAW_LOG( "num env entries now %d", nEntries );
|
|
#endif
|
|
}
|
|
|
|
XP_ASSERT( !!firstEmpty );
|
|
firstEmpty->owner = self;
|
|
firstEmpty->env = env;
|
|
XP_ASSERT( 0 == firstEmpty->refcount );
|
|
++firstEmpty->refcount;
|
|
#ifdef LOG_MAPPING
|
|
firstEmpty->ownerFunc = caller;
|
|
RAW_LOG( "entry %zu: mapped env %p to thread %x",
|
|
firstEmpty - ti->entries, env, (int)self );
|
|
RAW_LOG( "num entries USED now %d", countUsed(ti) );
|
|
#endif
|
|
}
|
|
|
|
pthread_mutex_unlock( &ti->mtxThreads );
|
|
} /* map_thread_prv */
|
|
|
|
static void
|
|
map_init( MPFORMAL EnvThreadInfo* ti, JNIEnv* env )
|
|
{
|
|
pthread_mutex_init( &ti->mtxThreads, NULL );
|
|
MPASSIGN( ti->mpool, mpool );
|
|
MAP_THREAD( ti, env );
|
|
}
|
|
|
|
#define MAP_REMOVE( ti, env ) map_remove_prv((ti), (env), __func__)
|
|
static void
|
|
map_remove_prv( EnvThreadInfo* ti, JNIEnv* env, const char* func )
|
|
{
|
|
XP_Bool found = false;
|
|
|
|
pthread_mutex_lock( &ti->mtxThreads );
|
|
for ( int ii = 0; !found && ii < ti->nEntries; ++ii ) {
|
|
EnvThreadEntry* entry = &ti->entries[ii];
|
|
found = env == entry->env;
|
|
if ( found ) {
|
|
XP_ASSERT( pthread_self() == entry->owner );
|
|
#ifdef LOG_MAPPING
|
|
RAW_LOG( "UNMAPPED env %p to thread %x (from %s; mapped by %s)",
|
|
entry->env, (int)entry->owner, func, entry->ownerFunc );
|
|
RAW_LOG( "%d entries left", countUsed( ti ) );
|
|
entry->ownerFunc = NULL;
|
|
#endif
|
|
XP_ASSERT( 1 == entry->refcount );
|
|
--entry->refcount;
|
|
entry->env = NULL;
|
|
entry->owner = 0;
|
|
}
|
|
}
|
|
pthread_mutex_unlock( &ti->mtxThreads );
|
|
|
|
XP_ASSERT( found );
|
|
}
|
|
|
|
static void
|
|
map_destroy( EnvThreadInfo* ti )
|
|
{
|
|
pthread_mutex_destroy( &ti->mtxThreads );
|
|
}
|
|
|
|
static JNIEnv*
|
|
prvEnvForMe( EnvThreadInfo* ti )
|
|
{
|
|
JNIEnv* result = NULL;
|
|
pthread_t self = pthread_self();
|
|
pthread_mutex_lock( &ti->mtxThreads );
|
|
for ( int ii = 0; !result && ii < ti->nEntries; ++ii ) {
|
|
if ( self == ti->entries[ii].owner ) {
|
|
result = ti->entries[ii].env;
|
|
}
|
|
}
|
|
pthread_mutex_unlock( &ti->mtxThreads );
|
|
return result;
|
|
}
|
|
|
|
#else
|
|
# define MAP_THREAD( ti, env )
|
|
# define MAP_REMOVE( ti, env )
|
|
# define map_init( ... )
|
|
# define map_destroy( ti )
|
|
#endif // MAP_THREAD_TO_ENV
|
|
|
|
#ifdef MAP_THREAD_TO_ENV
|
|
static pthread_mutex_t g_globalStateLock = PTHREAD_MUTEX_INITIALIZER;
|
|
static JNIGlobalState* g_globalState = NULL;
|
|
|
|
void setGlobalState( JNIGlobalState* state )
|
|
{
|
|
pthread_mutex_lock( &g_globalStateLock );
|
|
g_globalState = state;
|
|
pthread_mutex_unlock( &g_globalStateLock );
|
|
}
|
|
|
|
JNIEnv*
|
|
envForMe( EnvThreadInfo* ti, const char* caller )
|
|
{
|
|
JNIEnv* result = prvEnvForMe( ti );
|
|
#ifdef DEBUG
|
|
if( !result ) {
|
|
pthread_t self = pthread_self();
|
|
XP_LOGFF( "no env for %s (thread %x)", caller, (int)self );
|
|
XP_ASSERT(0);
|
|
}
|
|
#endif
|
|
return result;
|
|
}
|
|
|
|
#else
|
|
# define setGlobalState(s)
|
|
#endif
|
|
|
|
JNIEnv*
|
|
waitEnvFromGlobals() /* hanging */
|
|
{
|
|
JNIEnv* result = NULL;
|
|
#ifdef MAP_THREAD_TO_ENV
|
|
pthread_mutex_lock( &g_globalStateLock );
|
|
JNIGlobalState* state = g_globalState;
|
|
if ( !!state ) {
|
|
result = prvEnvForMe( &state->ti );
|
|
}
|
|
if ( !result ) {
|
|
pthread_mutex_unlock( &g_globalStateLock );
|
|
}
|
|
#endif
|
|
return result;
|
|
}
|
|
|
|
void
|
|
releaseEnvFromGlobals( JNIEnv* env )
|
|
{
|
|
#ifdef MAP_THREAD_TO_ENV
|
|
XP_ASSERT( !!env );
|
|
JNIGlobalState* state = g_globalState;
|
|
XP_ASSERT( !!state );
|
|
XP_ASSERT( env == prvEnvForMe( &state->ti ) );
|
|
pthread_mutex_unlock( &g_globalStateLock );
|
|
#endif
|
|
}
|
|
|
|
static void
|
|
tilesArrayToTileSet( JNIEnv* env, jintArray jtiles, TrayTileSet* tset )
|
|
{
|
|
if ( jtiles != NULL ) {
|
|
XP_ASSERT( !!jtiles );
|
|
jsize nTiles = (*env)->GetArrayLength( env, jtiles );
|
|
int tmp[MAX_TRAY_TILES];
|
|
getIntsFromArray( env, tmp, jtiles, nTiles, XP_FALSE );
|
|
|
|
tset->nTiles = nTiles;
|
|
for ( int ii = 0; ii < nTiles; ++ii ) {
|
|
tset->tiles[ii] = tmp[ii];
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef GAMEPTR_IS_OBJECT
|
|
static JNIState*
|
|
getState( JNIEnv* env, GamePtrType gamePtr, const char* func )
|
|
{
|
|
#ifdef DEBUG
|
|
if ( NULL == gamePtr ) {
|
|
XP_LOGFF( "ERROR: getState() called from %s() with null gamePtr",
|
|
func );
|
|
}
|
|
#endif
|
|
XP_ASSERT( NULL != gamePtr ); /* fired */
|
|
jmethodID mid = getMethodID( env, gamePtr, "ptr", "()J" );
|
|
XP_ASSERT( !!mid );
|
|
return (JNIState*)(*env)->CallLongMethod( env, gamePtr, mid );
|
|
}
|
|
#else
|
|
# define getState( env, gamePtr, func ) ((JNIState*)(gamePtr))
|
|
#endif
|
|
|
|
JNIEXPORT jlong JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_globalsInit
|
|
( JNIEnv* env, jclass C, jobject jdutil, jobject jniu, jlong jseed )
|
|
{
|
|
#ifdef MEM_DEBUG
|
|
MemPoolCtx* mpool = mpool_make( NULL );
|
|
XP_LOGFF( "ptr size: %zu", sizeof(mpool) );
|
|
#endif
|
|
int seed = (int)jseed;
|
|
XP_LOGFF( "calling srandom(seed %d)", seed );
|
|
srandom( seed );
|
|
|
|
JNIGlobalState* globalState = (JNIGlobalState*)XP_CALLOC( mpool,
|
|
sizeof(*globalState) );
|
|
map_init( MPPARM(mpool) &globalState->ti, env );
|
|
globalState->jniutil = makeJNIUtil( MPPARM(mpool) env, TI_IF(&globalState->ti) jniu );
|
|
globalState->vtMgr = make_vtablemgr( MPPARM_NOCOMMA(mpool) );
|
|
globalState->dictMgr = dmgr_make( MPPARM_NOCOMMA( mpool ) );
|
|
globalState->dutil = makeDUtil( MPPARM(mpool) env, TI_IF(&globalState->ti)
|
|
jdutil, globalState->vtMgr, globalState->dictMgr,
|
|
globalState->jniutil, NULL );
|
|
globalState->smsProto = smsproto_init( MPPARM( mpool ) env, globalState->dutil );
|
|
MPASSIGN( globalState->mpool, mpool );
|
|
setGlobalState( globalState );
|
|
// LOG_RETURNF( "%p", globalState );
|
|
return (jlong)globalState;
|
|
}
|
|
|
|
JNIEXPORT void JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_cleanGlobals
|
|
( JNIEnv* env, jclass C, jlong jniGlobalPtr )
|
|
{
|
|
// LOG_FUNC();
|
|
if ( 0 != jniGlobalPtr ) {
|
|
setGlobalState( NULL );
|
|
JNIGlobalState* globalState = (JNIGlobalState*)jniGlobalPtr;
|
|
#ifdef MEM_DEBUG
|
|
MemPoolCtx* mpool = GETMPOOL( globalState );
|
|
#endif
|
|
ASSERT_ENV( &globalState->ti, env );
|
|
smsproto_free( globalState->smsProto );
|
|
vtmgr_destroy( MPPARM(mpool) globalState->vtMgr );
|
|
dmgr_destroy( globalState->dictMgr, env );
|
|
destroyDUtil( &globalState->dutil, env );
|
|
destroyJNIUtil( env, &globalState->jniutil );
|
|
map_destroy( &globalState->ti );
|
|
XP_FREE( mpool, globalState );
|
|
mpool_destroy( mpool );
|
|
}
|
|
}
|
|
|
|
static const SetInfo gi_ints[] = {
|
|
ARR_MEMBER( CurGameInfo, nPlayers )
|
|
,ARR_MEMBER( CurGameInfo, gameSeconds )
|
|
,ARR_MEMBER( CurGameInfo, boardSize )
|
|
,ARR_MEMBER( CurGameInfo, traySize )
|
|
,ARR_MEMBER( CurGameInfo, bingoMin )
|
|
,ARR_MEMBER( CurGameInfo, gameID )
|
|
,ARR_MEMBER( CurGameInfo, forceChannel )
|
|
};
|
|
|
|
static const SetInfo gi_bools[] = {
|
|
ARR_MEMBER( CurGameInfo, hintsNotAllowed )
|
|
,ARR_MEMBER( CurGameInfo, timerEnabled )
|
|
,ARR_MEMBER( CurGameInfo, allowPickTiles )
|
|
,ARR_MEMBER( CurGameInfo, allowHintRect )
|
|
,ARR_MEMBER( CurGameInfo, inDuplicateMode )
|
|
};
|
|
|
|
static const SetInfo pl_ints[] = {
|
|
ARR_MEMBER( LocalPlayer, robotIQ )
|
|
,ARR_MEMBER( LocalPlayer, secondsUsed )
|
|
};
|
|
|
|
static CurGameInfo*
|
|
makeGI( MPFORMAL JNIEnv* env, jobject jgi )
|
|
{
|
|
CurGameInfo* gi = (CurGameInfo*)XP_CALLOC( mpool, sizeof(*gi) );
|
|
XP_UCHAR buf[256]; /* in case needs whole path */
|
|
|
|
getInts( env, (void*)gi, jgi, AANDS(gi_ints) );
|
|
getBools( env, (void*)gi, jgi, AANDS(gi_bools) );
|
|
|
|
/* Unlike on other platforms, gi is created without a call to
|
|
game_makeNewGame, which sets gameID. So check here if it's still unset
|
|
and if necessary set it -- including back in the java world. */
|
|
if ( 0 == gi->gameID ) {
|
|
while ( 0 == gi->gameID ) {
|
|
gi->gameID = getCurSeconds( env );
|
|
}
|
|
setInt( env, jgi, "gameID", gi->gameID );
|
|
}
|
|
|
|
gi->phoniesAction =
|
|
jenumFieldToInt( env, jgi, "phoniesAction",
|
|
PKG_PATH("jni/CurGameInfo$XWPhoniesChoice") );
|
|
gi->serverRole =
|
|
jenumFieldToInt( env, jgi, "serverRole",
|
|
PKG_PATH("jni/CurGameInfo$DeviceRole"));
|
|
|
|
getString( env, jgi, "dictName", AANDS(buf) );
|
|
gi->dictName = copyString( mpool, buf );
|
|
getString( env, jgi, "isoCodeStr", AANDS(buf) );
|
|
XP_STRNCPY( gi->isoCodeStr, buf, VSIZE(gi->isoCodeStr) );
|
|
|
|
XP_ASSERT( gi->nPlayers <= MAX_NUM_PLAYERS );
|
|
|
|
jobject jplayers
|
|
= getObjectField( env, jgi, "players", "[L" PKG_PATH("jni/LocalPlayer") ";" );
|
|
XP_ASSERT( !!jplayers );
|
|
for ( int ii = 0; !!jplayers && ii < gi->nPlayers; ++ii ) {
|
|
LocalPlayer* lp = &gi->players[ii];
|
|
|
|
jobject jlp = (*env)->GetObjectArrayElement( env, jplayers, ii );
|
|
XP_ASSERT( !!jlp );
|
|
|
|
getInts( env, (void*)lp, jlp, AANDS(pl_ints) );
|
|
|
|
lp->isLocal = getBool( env, jlp, "isLocal" );
|
|
|
|
getString( env, jlp, "name", AANDS(buf) );
|
|
lp->name = copyString( mpool, buf );
|
|
getString( env, jlp, "password", AANDS(buf) );
|
|
lp->password = copyString( mpool, buf );
|
|
getString( env, jlp, "dictName", AANDS(buf) );
|
|
lp->dictName = copyString( mpool, buf );
|
|
|
|
deleteLocalRef( env, jlp );
|
|
}
|
|
deleteLocalRef( env, jplayers );
|
|
return gi;
|
|
} /* makeGI */
|
|
|
|
static void
|
|
setJGI( JNIEnv* env, jobject jgi, const CurGameInfo* gi )
|
|
{
|
|
// set fields
|
|
|
|
setInts( env, jgi, (void*)gi, AANDS(gi_ints) );
|
|
setBools( env, jgi, (void*)gi, AANDS(gi_bools) );
|
|
|
|
setString( env, jgi, "dictName", gi->dictName );
|
|
setString( env, jgi, "isoCodeStr", gi->isoCodeStr );
|
|
|
|
intToJenumField( env, jgi, gi->phoniesAction, "phoniesAction",
|
|
PKG_PATH("jni/CurGameInfo$XWPhoniesChoice") );
|
|
intToJenumField( env, jgi, gi->serverRole, "serverRole",
|
|
PKG_PATH("jni/CurGameInfo$DeviceRole") );
|
|
|
|
jobject jplayers = getObjectField( env, jgi, "players",
|
|
"[L" PKG_PATH("jni/LocalPlayer") ";" );
|
|
if ( !!jplayers ) {
|
|
for ( int ii = 0; ii < gi->nPlayers; ++ii ) {
|
|
const LocalPlayer* lp = &gi->players[ii];
|
|
|
|
jobject jlp = (*env)->GetObjectArrayElement( env, jplayers, ii );
|
|
XP_ASSERT( !!jlp );
|
|
|
|
setInts( env, jlp, (void*)lp, AANDS(pl_ints) );
|
|
|
|
setBool( env, jlp, "isLocal", lp->isLocal );
|
|
setString( env, jlp, "name", lp->name );
|
|
setString( env, jlp, "password", lp->password );
|
|
setString( env, jlp, "dictName", lp->dictName );
|
|
|
|
deleteLocalRef( env, jlp );
|
|
}
|
|
deleteLocalRef( env, jplayers );
|
|
} else {
|
|
XP_ASSERT(0);
|
|
}
|
|
} /* setJGI */
|
|
|
|
#ifdef COMMON_LAYOUT
|
|
static const SetInfo bd_ints[] = { ARR_MEMBER( BoardDims, left ),
|
|
ARR_MEMBER( BoardDims, top ),
|
|
ARR_MEMBER( BoardDims, width ),
|
|
ARR_MEMBER( BoardDims, height ),
|
|
ARR_MEMBER( BoardDims, scoreLeft ),
|
|
ARR_MEMBER( BoardDims, scoreHt ),
|
|
ARR_MEMBER( BoardDims, scoreWidth ),
|
|
ARR_MEMBER( BoardDims, boardWidth ),
|
|
ARR_MEMBER( BoardDims, boardHt ),
|
|
ARR_MEMBER( BoardDims, trayLeft ),
|
|
ARR_MEMBER( BoardDims, trayTop ),
|
|
ARR_MEMBER( BoardDims, trayWidth ),
|
|
ARR_MEMBER( BoardDims, trayHt ),
|
|
ARR_MEMBER( BoardDims, traySize ),
|
|
ARR_MEMBER( BoardDims, cellSize ),
|
|
ARR_MEMBER( BoardDims, maxCellSize ),
|
|
ARR_MEMBER( BoardDims, timerWidth ),
|
|
};
|
|
|
|
static void
|
|
dimsJToC( JNIEnv* env, BoardDims* out, jobject jdims )
|
|
{
|
|
getInts( env, (void*)out, jdims, AANDS(bd_ints) );
|
|
}
|
|
|
|
static void
|
|
dimsCtoJ( JNIEnv* env, jobject jdims, const BoardDims* in )
|
|
{
|
|
setInts( env, jdims, (void*)in, AANDS(bd_ints) );
|
|
}
|
|
#endif
|
|
|
|
static void
|
|
destroyGI( MPFORMAL CurGameInfo** gip )
|
|
{
|
|
CurGameInfo* gi = *gip;
|
|
if ( !!gi ) {
|
|
gi_disposePlayerInfo( MPPARM(mpool) gi );
|
|
XP_FREE( mpool, gi );
|
|
*gip = NULL;
|
|
}
|
|
}
|
|
|
|
static void
|
|
loadCommonPrefs( JNIEnv* env, CommonPrefs* cp, jobject j_cp )
|
|
{
|
|
XP_ASSERT( !!j_cp );
|
|
cp->showBoardArrow = getBool( env, j_cp, "showBoardArrow" );
|
|
cp->showRobotScores = getBool( env, j_cp, "showRobotScores" );
|
|
cp->hideTileValues = getBool( env, j_cp, "hideTileValues" );
|
|
cp->skipCommitConfirm = getBool( env, j_cp, "skipCommitConfirm" );
|
|
cp->showColors = getBool( env, j_cp, "showColors" );
|
|
cp->sortNewTiles = getBool( env, j_cp, "sortNewTiles" );
|
|
cp->allowPeek = getBool( env, j_cp, "allowPeek" );
|
|
cp->skipMQTTAdd = getBool( env, j_cp, "skipMQTTAdd" );
|
|
#ifdef XWFEATURE_CROSSHAIRS
|
|
cp->hideCrosshairs = getBool( env, j_cp, "hideCrosshairs" );
|
|
#endif
|
|
cp->tvType = jenumFieldToInt( env, j_cp, "tvType",
|
|
PKG_PATH("jni/CommonPrefs$TileValueType"));
|
|
}
|
|
|
|
static XWStreamCtxt*
|
|
streamFromJStream( MPFORMAL JNIEnv* env, VTableMgr* vtMgr, jbyteArray jstream )
|
|
{
|
|
XP_ASSERT( !!jstream );
|
|
int len = (*env)->GetArrayLength( env, jstream );
|
|
XWStreamCtxt* stream = mem_stream_make_sized( MPPARM(mpool) vtMgr,
|
|
len, NULL, 0, NULL );
|
|
jbyte* jelems = (*env)->GetByteArrayElements( env, jstream, NULL );
|
|
stream_putBytes( stream, jelems, len );
|
|
(*env)->ReleaseByteArrayElements( env, jstream, jelems, 0 );
|
|
return stream;
|
|
} /* streamFromJStream */
|
|
|
|
/****************************************************
|
|
* These methods are stateless: no gamePtr
|
|
****************************************************/
|
|
|
|
#define DVC_HEADER(PTR) { \
|
|
JNIGlobalState* globalState = (JNIGlobalState*)(PTR); \
|
|
|
|
#define DVC_HEADER_END() } \
|
|
|
|
|
|
JNIEXPORT jstring JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_dvc_1getMQTTDevID
|
|
( JNIEnv* env, jclass C, jlong jniGlobalPtr )
|
|
{
|
|
jstring result;
|
|
DVC_HEADER(jniGlobalPtr);
|
|
MQTTDevID devID;
|
|
dvc_getMQTTDevID( globalState->dutil, env, &devID );
|
|
|
|
XP_UCHAR buf[64];
|
|
formatMQTTDevID( &devID, buf, VSIZE(buf) );
|
|
result = (*env)->NewStringUTF( env, buf );
|
|
|
|
DVC_HEADER_END();
|
|
return result;
|
|
}
|
|
|
|
JNIEXPORT void JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_dvc_1resetMQTTDevID
|
|
( JNIEnv* env, jclass C, jlong jniGlobalPtr )
|
|
{
|
|
DVC_HEADER(jniGlobalPtr);
|
|
dvc_resetMQTTDevID( globalState->dutil, env );
|
|
DVC_HEADER_END();
|
|
}
|
|
|
|
static void
|
|
jstrToDevID( JNIEnv* env, jstring jstr, MQTTDevID* outDevID )
|
|
{
|
|
const char* str = (*env)->GetStringUTFChars( env, jstr, NULL );
|
|
#ifdef DEBUG
|
|
XP_Bool success =
|
|
#endif
|
|
strToMQTTCDevID( str, outDevID );
|
|
XP_ASSERT( success );
|
|
(*env)->ReleaseStringUTFChars( env, jstr, str );
|
|
}
|
|
|
|
JNIEXPORT jobjectArray JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_dvc_1getMQTTSubTopics
|
|
( JNIEnv* env, jclass C, jlong jniGlobalPtr )
|
|
{
|
|
jobjectArray result = NULL;
|
|
DVC_HEADER(jniGlobalPtr);
|
|
|
|
|
|
XP_UCHAR storage[256];
|
|
XP_UCHAR* topics[4];
|
|
XP_U16 nTopics = VSIZE(topics);
|
|
dvc_getMQTTSubTopics( globalState->dutil, env,
|
|
storage, VSIZE(storage),
|
|
&nTopics, topics );
|
|
|
|
result = makeStringArray( env, nTopics, (const XP_UCHAR* const*)topics );
|
|
|
|
DVC_HEADER_END();
|
|
return result;
|
|
}
|
|
|
|
typedef struct _MTPData {
|
|
JNIEnv* env;
|
|
int count;
|
|
const XP_UCHAR* topics[4];
|
|
jbyteArray jPackets[4];
|
|
XP_UCHAR storage[256];
|
|
int offset;
|
|
} MTPData;
|
|
|
|
static void
|
|
msgAndTopicProc( void* closure, const XP_UCHAR* topic,
|
|
const XP_U8* msgBuf, XP_U16 msgLen )
|
|
{
|
|
MTPData* mtp = (MTPData*)closure;
|
|
JNIEnv* env = mtp->env;
|
|
|
|
const XP_UCHAR* ptr = mtp->topics[mtp->count] = &mtp->storage[mtp->offset];
|
|
size_t siz = XP_SNPRINTF( (char*)ptr, VSIZE(mtp->storage) - mtp->offset,
|
|
"%s", topic );
|
|
XP_ASSERT( siz < VSIZE(mtp->storage) - mtp->offset );
|
|
XP_USE( siz );
|
|
mtp->offset += 1 + XP_STRLEN(ptr);
|
|
|
|
mtp->jPackets[mtp->count] = makeByteArray( env, msgLen, (const jbyte*)msgBuf );
|
|
|
|
++mtp->count;
|
|
XP_ASSERT( mtp->count < VSIZE(mtp->topics) );
|
|
}
|
|
|
|
static jobject
|
|
wrapResults( MTPData* mtp )
|
|
{
|
|
JNIEnv* env = mtp->env;
|
|
jobject result =
|
|
makeObjectEmptyConst( env, PKG_PATH("jni/XwJNI$TopicsAndPackets"));
|
|
|
|
jobjectArray jTopics = makeStringArray( env, mtp->count, mtp->topics );
|
|
setObjectField( env, result, "topics", "[Ljava/lang/String;", jTopics );
|
|
|
|
jobjectArray jPackets = makeByteArrayArray( env, mtp->count );
|
|
for ( int ii = 0; ii < mtp->count; ++ii ) {
|
|
(*env)->SetObjectArrayElement( env, jPackets, ii, mtp->jPackets[ii] );
|
|
deleteLocalRef( env, mtp->jPackets[ii] );
|
|
}
|
|
setObjectField( env, result, "packets", "[[B", jPackets );
|
|
|
|
return result;
|
|
}
|
|
|
|
JNIEXPORT jobject JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_dvc_1makeMQTTInvites
|
|
( JNIEnv* env, jclass C, jlong jniGlobalPtr, jstring jAddressee,
|
|
jobject jnli )
|
|
{
|
|
jobject result;
|
|
DVC_HEADER(jniGlobalPtr);
|
|
|
|
NetLaunchInfo nli;
|
|
loadNLI( env, &nli, jnli );
|
|
LOGNLI( &nli );
|
|
|
|
MTPData mtp = { .env = env, };
|
|
|
|
MQTTDevID addressee;
|
|
jstrToDevID( env, jAddressee, &addressee );
|
|
|
|
dvc_makeMQTTInvites( globalState->dutil, env, msgAndTopicProc, &mtp,
|
|
&addressee, &nli );
|
|
result = wrapResults( &mtp );
|
|
|
|
DVC_HEADER_END();
|
|
return result;
|
|
}
|
|
|
|
JNIEXPORT jobject JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_dvc_1makeMQTTMessages
|
|
( JNIEnv* env, jclass C, jlong jniGlobalPtr, jstring jAddressee,
|
|
jint jGameID, jbyteArray jmsg )
|
|
{
|
|
jobject result;
|
|
LOG_FUNC();
|
|
DVC_HEADER(jniGlobalPtr);
|
|
|
|
MTPData mtp = { .env = env, };
|
|
|
|
MQTTDevID addressee;
|
|
jstrToDevID( env, jAddressee, &addressee );
|
|
|
|
XP_U16 len = (*env)->GetArrayLength( env, jmsg );
|
|
jbyte* buf = (*env)->GetByteArrayElements( env, jmsg, NULL );
|
|
dvc_makeMQTTMessages( globalState->dutil, env, msgAndTopicProc, &mtp,
|
|
&addressee, jGameID, (const XP_U8*)buf, len );
|
|
(*env)->ReleaseByteArrayElements( env, jmsg, buf, 0 );
|
|
|
|
result = wrapResults( &mtp );
|
|
|
|
DVC_HEADER_END();
|
|
LOG_RETURN_VOID();
|
|
return result;
|
|
}
|
|
|
|
JNIEXPORT jobject JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_dvc_1makeMQTTNoSuchGames
|
|
( JNIEnv* env, jclass C, jlong jniGlobalPtr, jstring jAddressee,
|
|
jint jgameid )
|
|
{
|
|
jobject result;
|
|
DVC_HEADER(jniGlobalPtr);
|
|
|
|
MTPData mtp = { .env = env, };
|
|
MQTTDevID addressee;
|
|
jstrToDevID( env, jAddressee, &addressee );
|
|
|
|
dvc_makeMQTTNoSuchGames( globalState->dutil, env, msgAndTopicProc, &mtp,
|
|
&addressee, jgameid );
|
|
|
|
result = wrapResults( &mtp );
|
|
|
|
DVC_HEADER_END();
|
|
return result;
|
|
}
|
|
|
|
JNIEXPORT void JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_dvc_1parseMQTTPacket
|
|
( JNIEnv* env, jclass C, jlong jniGlobalPtr, jstring jtopic, jbyteArray jmsg )
|
|
{
|
|
DVC_HEADER(jniGlobalPtr);
|
|
|
|
XP_U16 len = (*env)->GetArrayLength( env, jmsg );
|
|
jbyte* buf = (*env)->GetByteArrayElements( env, jmsg, NULL );
|
|
const char* topic = (*env)->GetStringUTFChars( env, jtopic, NULL );
|
|
|
|
dvc_parseMQTTPacket( globalState->dutil, env, topic, (XP_U8*)buf, len );
|
|
|
|
(*env)->ReleaseStringUTFChars( env, jtopic, topic );
|
|
(*env)->ReleaseByteArrayElements( env, jmsg, buf, 0 );
|
|
DVC_HEADER_END();
|
|
}
|
|
|
|
# ifdef XWFEATURE_KNOWNPLAYERS
|
|
JNIEXPORT jobjectArray JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_kplr_1getPlayers
|
|
( JNIEnv* env, jclass C, jlong jniGlobalPtr )
|
|
{
|
|
jobjectArray jnames = NULL;
|
|
DVC_HEADER(jniGlobalPtr);
|
|
|
|
XP_U16 nFound = 0;
|
|
kplr_getNames( globalState->dutil, env, NULL, &nFound );
|
|
if ( 0 < nFound ) {
|
|
const XP_UCHAR* names[nFound];
|
|
kplr_getNames( globalState->dutil, env, names, &nFound );
|
|
jnames = makeStringArray( env, nFound, names );
|
|
}
|
|
DVC_HEADER_END();
|
|
return jnames;
|
|
}
|
|
|
|
JNIEXPORT jboolean JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_kplr_1renamePlayer
|
|
( JNIEnv* env, jclass C, jlong jniGlobalPtr, jstring jOldName, jstring jNewName )
|
|
{
|
|
jboolean result;
|
|
DVC_HEADER(jniGlobalPtr);
|
|
const char* oldName = (*env)->GetStringUTFChars( env, jOldName, NULL );
|
|
const char* newName = (*env)->GetStringUTFChars( env, jNewName, NULL );
|
|
result = KP_OK == kplr_renamePlayer( globalState->dutil, env, oldName, newName );
|
|
(*env)->ReleaseStringUTFChars( env, jOldName, oldName );
|
|
(*env)->ReleaseStringUTFChars( env, jNewName, newName );
|
|
DVC_HEADER_END();
|
|
return result;
|
|
}
|
|
|
|
JNIEXPORT void JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_kplr_1deletePlayer
|
|
( JNIEnv* env, jclass C, jlong jniGlobalPtr, jstring jName )
|
|
{
|
|
DVC_HEADER(jniGlobalPtr);
|
|
const char* name = (*env)->GetStringUTFChars( env, jName, NULL );
|
|
kplr_deletePlayer( globalState->dutil, env, name );
|
|
(*env)->ReleaseStringUTFChars( env, jName, name );
|
|
DVC_HEADER_END();
|
|
}
|
|
|
|
JNIEXPORT jobject JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_kplr_1getAddr
|
|
( JNIEnv* env, jclass C, jlong jniGlobalPtr, jstring jName, jintArray jLastMod )
|
|
{
|
|
jobject jaddr = NULL;
|
|
DVC_HEADER(jniGlobalPtr);
|
|
|
|
CommsAddrRec addr;
|
|
const char* name = (*env)->GetStringUTFChars( env, jName, NULL );
|
|
XP_U32 lastMod;
|
|
kplr_getAddr( globalState->dutil, env, name, &addr, &lastMod );
|
|
(*env)->ReleaseStringUTFChars( env, jName, name );
|
|
jaddr = makeObjectEmptyConst( env, PKG_PATH("jni/CommsAddrRec") );
|
|
setJAddrRec( env, jaddr, &addr );
|
|
|
|
if ( !!jLastMod ) {
|
|
setIntInArray( env, jLastMod, 0, lastMod );
|
|
}
|
|
|
|
DVC_HEADER_END();
|
|
return jaddr;
|
|
}
|
|
|
|
JNIEXPORT jstring JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_kplr_1nameForMqttDev
|
|
( JNIEnv* env, jclass C, jlong jniGlobalPtr, jstring jDevID )
|
|
{
|
|
jstring result = NULL;
|
|
DVC_HEADER(jniGlobalPtr);
|
|
const char* devid = (*env)->GetStringUTFChars( env, jDevID, NULL );
|
|
const XP_UCHAR* name = kplr_nameForMqttDev( globalState->dutil, env, devid );
|
|
result = (*env)->NewStringUTF( env, name );
|
|
(*env)->ReleaseStringUTFChars( env, jDevID, devid );
|
|
DVC_HEADER_END();
|
|
return result;
|
|
}
|
|
#endif
|
|
|
|
JNIEXPORT void JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_gi_1from_1stream
|
|
( JNIEnv* env, jclass C, jlong jniGlobalPtr, jobject jgi, jbyteArray jstream )
|
|
{
|
|
JNIGlobalState* globalState = (JNIGlobalState*)jniGlobalPtr;
|
|
#ifdef MEM_DEBUG
|
|
MemPoolCtx* mpool = GETMPOOL( globalState );
|
|
#endif
|
|
XWStreamCtxt* stream = streamFromJStream( MPPARM(mpool) env,
|
|
globalState->vtMgr, jstream );
|
|
|
|
CurGameInfo gi = {0};
|
|
// XP_MEMSET( &gi, 0, sizeof(gi) );
|
|
if ( game_makeFromStream( MPPARM(mpool) env, stream, NULL,
|
|
&gi, NULL, NULL, NULL, NULL ) ) {
|
|
setJGI( env, jgi, &gi );
|
|
} else {
|
|
XP_LOGFF( "game_makeFromStream failed" );
|
|
}
|
|
|
|
gi_disposePlayerInfo( MPPARM(mpool) &gi );
|
|
|
|
stream_destroy( stream, env );
|
|
releaseMPool( globalState );
|
|
}
|
|
|
|
JNIEXPORT jbyteArray JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_nli_1to_1stream
|
|
( JNIEnv* env, jclass C, jlong jniGlobalPtr, jobject jnli )
|
|
{
|
|
LOG_FUNC();
|
|
JNIGlobalState* globalState = (JNIGlobalState*)jniGlobalPtr;
|
|
#ifdef MEM_DEBUG
|
|
MemPoolCtx* mpool = GETMPOOL( globalState );
|
|
#endif
|
|
|
|
jbyteArray result;
|
|
NetLaunchInfo nli;
|
|
loadNLI( env, &nli, jnli );
|
|
XWStreamCtxt* stream = mem_stream_make( MPPARM(mpool) globalState->vtMgr,
|
|
NULL, 0, NULL );
|
|
|
|
nli_saveToStream( &nli, stream );
|
|
|
|
result = streamToBArray( env, stream );
|
|
stream_destroy( stream, env );
|
|
releaseMPool( globalState );
|
|
return result;
|
|
}
|
|
|
|
JNIEXPORT jobject JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_nli_1from_1stream
|
|
( JNIEnv* env, jclass C, jlong jniGlobalPtr, jbyteArray jstream )
|
|
{
|
|
jobject jnli = NULL;
|
|
LOG_FUNC();
|
|
JNIGlobalState* globalState = (JNIGlobalState*)jniGlobalPtr;
|
|
#ifdef MEM_DEBUG
|
|
MemPoolCtx* mpool = GETMPOOL( globalState );
|
|
#endif
|
|
XWStreamCtxt* stream = streamFromJStream( MPPARM(mpool) env,
|
|
globalState->vtMgr, jstream );
|
|
|
|
NetLaunchInfo nli = {0};
|
|
if ( nli_makeFromStream( &nli, stream ) ) {
|
|
jnli = makeObjectEmptyConst( env, PKG_PATH("NetLaunchInfo") );
|
|
setNLI( env, jnli, &nli );
|
|
} else {
|
|
XP_LOGFF( "nli_makeFromStream failed" );
|
|
}
|
|
|
|
stream_destroy( stream, env );
|
|
releaseMPool( globalState );
|
|
return jnli;
|
|
}
|
|
|
|
JNIEXPORT jstring JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_comms_1getUUID
|
|
( JNIEnv* env, jclass C )
|
|
{
|
|
jstring jstr =
|
|
#ifdef XWFEATURE_BLUETOOTH
|
|
(*env)->NewStringUTF( env, XW_BT_UUID )
|
|
#else
|
|
NULL
|
|
#endif
|
|
;
|
|
return jstr;
|
|
}
|
|
|
|
JNIEXPORT jstring JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_lcToLocale
|
|
( JNIEnv* env, jclass C, jint lc )
|
|
{
|
|
jstring result = NULL;
|
|
const XP_UCHAR* locale = lcToLocale( lc );
|
|
if ( !!locale ) {
|
|
result = (*env)->NewStringUTF( env, locale );
|
|
}
|
|
return result;
|
|
}
|
|
|
|
JNIEXPORT jboolean JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_haveLocaleToLc
|
|
( JNIEnv* env, jclass C, jstring jIsoCode, jintArray jOutArray )
|
|
{
|
|
XP_ASSERT( !!jIsoCode );
|
|
XP_LangCode lc;
|
|
const char* isoCode = (*env)->GetStringUTFChars( env, jIsoCode, NULL );
|
|
jboolean result = haveLocaleToLc( isoCode, &lc );
|
|
if ( result ) {
|
|
setIntInArray( env, jOutArray, 0, lc );
|
|
}
|
|
(*env)->ReleaseStringUTFChars( env, jIsoCode, isoCode );
|
|
return result;
|
|
}
|
|
|
|
JNIEXPORT jlong JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_dict_1make
|
|
( JNIEnv* env, jclass C, jlong jniGlobalPtr, jbyteArray jDictBytes,
|
|
jstring jname, jstring jpath )
|
|
{
|
|
JNIGlobalState* globalState = (JNIGlobalState*)jniGlobalPtr;
|
|
#ifdef MEM_DEBUG
|
|
MemPoolCtx* mpool = GETMPOOL( globalState );
|
|
#endif
|
|
|
|
/* makeDict calls dict_ref() */
|
|
DictionaryCtxt* dictPtr = makeDict( MPPARM(mpool) env, TI_IF(&globalState->ti)
|
|
globalState->dictMgr,globalState->jniutil,
|
|
jname, jDictBytes, jpath, NULL, false );
|
|
return (jlong)dictPtr;
|
|
}
|
|
|
|
JNIEXPORT void JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_dict_1ref
|
|
( JNIEnv* env, jclass C, jlong dictPtr )
|
|
{
|
|
if ( 0 != dictPtr ) {
|
|
DictionaryCtxt* dict = (DictionaryCtxt*)dictPtr;
|
|
dict_ref( dict, env );
|
|
}
|
|
}
|
|
|
|
JNIEXPORT void JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_dict_1unref
|
|
( JNIEnv* env, jclass C, jlong dictPtr )
|
|
{
|
|
if ( 0 != dictPtr ) {
|
|
DictionaryCtxt* dict = (DictionaryCtxt*)dictPtr;
|
|
dict_unref( dict, env );
|
|
}
|
|
}
|
|
|
|
typedef struct _FTData {
|
|
JNIEnv* env;
|
|
jbyteArray arrays[16];
|
|
int nArrays;
|
|
} FTData;
|
|
|
|
static XP_Bool
|
|
onFoundTiles( void* closure, const Tile* tiles, int nTiles )
|
|
{
|
|
FTData* ftd = (FTData*)closure;
|
|
ftd->arrays[ftd->nArrays++] = makeByteArray( ftd->env, nTiles,
|
|
(const jbyte*)tiles );
|
|
return ftd->nArrays < VSIZE(ftd->arrays); /* still have room? */
|
|
}
|
|
|
|
JNIEXPORT jobjectArray JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_dict_1strToTiles
|
|
( JNIEnv* env, jclass C, jlong dictPtr, jstring jstr )
|
|
{
|
|
jobjectArray result = NULL;
|
|
DictionaryCtxt* dict = (DictionaryCtxt*)dictPtr;
|
|
const char* str = (*env)->GetStringUTFChars( env, jstr, NULL );
|
|
|
|
FTData ftd = { .env = env, };
|
|
dict_tilesForString( dict, str, 0, onFoundTiles, &ftd );
|
|
|
|
if ( ftd.nArrays > 0 ) {
|
|
result = makeByteArrayArray( env, ftd.nArrays );
|
|
for ( int ii = 0; ii < ftd.nArrays; ++ii ) {
|
|
(*env)->SetObjectArrayElement( env, result, ii, ftd.arrays[ii] );
|
|
deleteLocalRef( env, ftd.arrays[ii] );
|
|
}
|
|
}
|
|
|
|
(*env)->ReleaseStringUTFChars( env, jstr, str );
|
|
return result;
|
|
}
|
|
|
|
JNIEXPORT jboolean JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_dict_1hasDuplicates
|
|
( JNIEnv* env, jclass C, jlong dictPtr )
|
|
{
|
|
jboolean result;
|
|
DictionaryCtxt* dict = (DictionaryCtxt*)dictPtr;
|
|
result = dict_hasDuplicates( dict );
|
|
return result;
|
|
}
|
|
|
|
JNIEXPORT jstring JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_dict_1getTilesInfo
|
|
( JNIEnv* env, jclass C, jlong jniGlobalPtr, jlong dictPtr )
|
|
{
|
|
jstring result = NULL;
|
|
JNIGlobalState* globalState = (JNIGlobalState*)jniGlobalPtr;
|
|
#ifdef MEM_DEBUG
|
|
MemPoolCtx* mpool = GETMPOOL( globalState );
|
|
#endif
|
|
DictionaryCtxt* dict = (DictionaryCtxt*)dictPtr;
|
|
XWStreamCtxt* stream = mem_stream_make( MPPARM(mpool) globalState->vtMgr,
|
|
NULL, 0, NULL );
|
|
dict_writeTilesInfo( dict, 15, stream );
|
|
result = streamToJString( env, stream );
|
|
stream_destroy( stream, env );
|
|
|
|
return result;
|
|
}
|
|
|
|
JNIEXPORT jstring JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_dict_1tilesToStr
|
|
( JNIEnv* env, jclass C, jlong dictPtr, jbyteArray jtiles, jstring jdelim )
|
|
{
|
|
jstring result = NULL;
|
|
DictionaryCtxt* dict = (DictionaryCtxt*)dictPtr;
|
|
if ( !!jtiles && !!dict ) {
|
|
XP_UCHAR buf[64];
|
|
const XP_UCHAR* delim = NULL;
|
|
if ( !!jdelim ) {
|
|
delim = (*env)->GetStringUTFChars( env, jdelim, NULL );
|
|
}
|
|
|
|
XP_U16 nTiles = (*env)->GetArrayLength( env, jtiles );
|
|
jbyte* tiles = (*env)->GetByteArrayElements( env, jtiles, NULL );
|
|
|
|
XP_U16 strLen = dict_tilesToString( dict, (Tile*)tiles, nTiles,
|
|
buf, VSIZE(buf), delim );
|
|
if ( 0 < strLen ) {
|
|
buf[strLen] = '\0';
|
|
result = (*env)->NewStringUTF( env, buf );
|
|
}
|
|
|
|
if ( !!jdelim ) {
|
|
(*env)->ReleaseStringUTFChars( env, jdelim, delim );
|
|
}
|
|
(*env)->ReleaseByteArrayElements( env, jtiles, tiles, 0 );
|
|
} else {
|
|
XP_LOGFF( "null jtiles array" );
|
|
}
|
|
return result;
|
|
}
|
|
|
|
JNIEXPORT jobject JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_dict_1getInfo
|
|
( JNIEnv* env, jclass C, jlong jniGlobalPtr, jlong dictPtr,
|
|
jboolean check )
|
|
{
|
|
jobject jinfo = NULL;
|
|
#ifdef MAP_THREAD_TO_ENV
|
|
JNIGlobalState* globalState = (JNIGlobalState*)jniGlobalPtr;
|
|
MAP_THREAD( &globalState->ti, env );
|
|
#endif
|
|
DictionaryCtxt* dict = (DictionaryCtxt*)dictPtr;
|
|
if ( NULL != dict ) {
|
|
jinfo = makeObjectEmptyConst( env, PKG_PATH("jni/DictInfo") );
|
|
setInt( env, jinfo, "wordCount", dict_getWordCount( dict, env ) );
|
|
setString( env, jinfo, "md5Sum", dict_getMd5Sum( dict ) );
|
|
setString( env, jinfo, "isoCodeStr", dict_getISOCode( dict ) );
|
|
setString( env, jinfo, "langName", dict_getLangName( dict ) );
|
|
}
|
|
|
|
return jinfo;
|
|
}
|
|
|
|
JNIEXPORT jstring JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_dict_1getDesc
|
|
( JNIEnv* env, jclass C, jlong dictPtr )
|
|
{
|
|
jstring result = NULL;
|
|
DictionaryCtxt* dict = (DictionaryCtxt*)dictPtr;
|
|
const XP_UCHAR* disc = dict_getDesc( dict );
|
|
if ( NULL != disc && '\0' != disc[0] ) {
|
|
result = (*env)->NewStringUTF( env, disc );
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/* Dictionary methods: don't use gamePtr */
|
|
JNIEXPORT jboolean JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_dict_1tilesAreSame
|
|
( JNIEnv* env, jclass C, jlong dictPtr1, jlong dictPtr2 )
|
|
{
|
|
jboolean result;
|
|
const DictionaryCtxt* dict1 = (DictionaryCtxt*)dictPtr1;
|
|
XP_ASSERT( !!dict1 );
|
|
const DictionaryCtxt* dict2 = (DictionaryCtxt*)dictPtr2;
|
|
XP_ASSERT( !!dict2 );
|
|
result = dict_tilesAreSame( dict1, dict2 );
|
|
return result;
|
|
}
|
|
|
|
JNIEXPORT jobjectArray JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_dict_1getChars
|
|
( JNIEnv* env, jclass C, jlong dictPtr )
|
|
{
|
|
jobject result = NULL;
|
|
result = and_dictionary_getChars( env, (DictionaryCtxt*)dictPtr );
|
|
return result;
|
|
}
|
|
|
|
JNIEXPORT jint JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_dict_1getTileValue
|
|
( JNIEnv* env, jclass C, jlong dictPtr, jint tile )
|
|
{
|
|
return dict_getTileValue( (DictionaryCtxt*)dictPtr, tile );
|
|
}
|
|
|
|
static jobjectArray
|
|
msgArrayToByteArrays( JNIEnv* env, const SMSMsgArray* arr )
|
|
{
|
|
XP_ASSERT( arr->format == FORMAT_NET );
|
|
|
|
jobjectArray result = makeByteArrayArray( env, arr->nMsgs );
|
|
for ( int ii = 0; ii < arr->nMsgs; ++ii ) {
|
|
SMSMsgNet* msg = &arr->u.msgsNet[ii];
|
|
jbyteArray arr = makeByteArray( env, msg->len, (const jbyte*)msg->data );
|
|
(*env)->SetObjectArrayElement( env, result, ii, arr );
|
|
deleteLocalRef( env, arr );
|
|
}
|
|
return result;
|
|
}
|
|
|
|
static jobjectArray
|
|
msgArrayToJMsgArray( JNIEnv* env, const SMSMsgArray* arr )
|
|
{
|
|
XP_ASSERT( arr->format == FORMAT_LOC );
|
|
jclass clas = (*env)->FindClass( env, PKG_PATH("jni/XwJNI$SMSProtoMsg") );
|
|
jobjectArray result = (*env)->NewObjectArray( env, arr->nMsgs, clas, NULL );
|
|
|
|
jmethodID initId = (*env)->GetMethodID( env, clas, "<init>", "()V" );
|
|
for ( int ii = 0; ii < arr->nMsgs; ++ii ) {
|
|
jobject jmsg = (*env)->NewObject( env, clas, initId );
|
|
|
|
const SMSMsgLoc* msgsLoc = &arr->u.msgsLoc[ii];
|
|
intToJenumField( env, jmsg, msgsLoc->cmd, "cmd", PKG_PATH("jni/XwJNI$SMS_CMD") );
|
|
setInt( env, jmsg, "gameID", msgsLoc->gameID );
|
|
|
|
jbyteArray arr = makeByteArray( env, msgsLoc->len,
|
|
(const jbyte*)msgsLoc->data );
|
|
setObjectField( env, jmsg, "data", "[B", arr );
|
|
|
|
(*env)->SetObjectArrayElement( env, result, ii, jmsg );
|
|
deleteLocalRef( env, jmsg );
|
|
}
|
|
deleteLocalRef( env, clas );
|
|
return result;
|
|
}
|
|
|
|
JNIEXPORT jobjectArray JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_smsproto_1prepOutbound
|
|
( JNIEnv* env, jclass C, jlong jniGlobalPtr, jobject jCmd, jint jGameID,
|
|
jbyteArray jData, jstring jToPhone, jint jPort, jintArray jWaitSecsArr )
|
|
{
|
|
jobjectArray result = NULL;
|
|
JNIGlobalState* globalState = (JNIGlobalState*)jniGlobalPtr;
|
|
MAP_THREAD( &globalState->ti, env );
|
|
|
|
SMS_CMD cmd = jEnumToInt( env, jCmd );
|
|
jbyte* data = NULL;
|
|
int len = 0;
|
|
if ( NULL != jData ) {
|
|
len = (*env)->GetArrayLength( env, jData );
|
|
data = (*env)->GetByteArrayElements( env, jData, NULL );
|
|
}
|
|
const char* toPhone = (*env)->GetStringUTFChars( env, jToPhone, NULL );
|
|
|
|
XP_U16 waitSecs;
|
|
SMSMsgArray* arr = smsproto_prepOutbound( globalState->smsProto, env, cmd,
|
|
jGameID, (const XP_U8*)data, len,
|
|
toPhone, jPort, XP_FALSE,
|
|
&waitSecs );
|
|
if ( !!arr ) {
|
|
result = msgArrayToByteArrays( env, arr );
|
|
smsproto_freeMsgArray( globalState->smsProto, arr );
|
|
}
|
|
|
|
setIntInArray( env, jWaitSecsArr, 0, waitSecs );
|
|
|
|
(*env)->ReleaseStringUTFChars( env, jToPhone, toPhone );
|
|
if ( NULL != jData ) {
|
|
(*env)->ReleaseByteArrayElements( env, jData, data, 0 );
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
JNIEXPORT jobjectArray JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_smsproto_1prepInbound
|
|
( JNIEnv* env, jclass C, jlong jniGlobalPtr, jbyteArray jData,
|
|
jstring jFromPhone, jint jWantPort )
|
|
{
|
|
jobjectArray result = NULL;
|
|
|
|
if ( !!jData ) {
|
|
JNIGlobalState* globalState = (JNIGlobalState*)jniGlobalPtr;
|
|
MAP_THREAD( &globalState->ti, env );
|
|
|
|
int len = (*env)->GetArrayLength( env, jData );
|
|
jbyte* data = (*env)->GetByteArrayElements( env, jData, NULL );
|
|
const char* fromPhone = (*env)->GetStringUTFChars( env, jFromPhone, NULL );
|
|
|
|
SMSMsgArray* arr = smsproto_prepInbound( globalState->smsProto, env, fromPhone,
|
|
jWantPort, (XP_U8*)data, len );
|
|
if ( !!arr ) {
|
|
result = msgArrayToJMsgArray( env, arr );
|
|
smsproto_freeMsgArray( globalState->smsProto, arr );
|
|
}
|
|
|
|
(*env)->ReleaseStringUTFChars( env, jFromPhone, fromPhone );
|
|
(*env)->ReleaseByteArrayElements( env, jData, data, 0 );
|
|
} else {
|
|
XP_LOGFF( " => null (null input)" );
|
|
}
|
|
return result;
|
|
}
|
|
|
|
struct _JNIState {
|
|
XWGame game;
|
|
JNIGlobalState* globalJNI;
|
|
AndGameGlobals globals;
|
|
XP_U16 curSaveCount;
|
|
XP_U16 lastSavedSize;
|
|
#ifdef DEBUG
|
|
const char* envSetterFunc;
|
|
XP_U32 guard;
|
|
#endif
|
|
MPSLOT
|
|
};
|
|
|
|
#define GAME_GUARD 0x453627
|
|
#if 0
|
|
# define LOG_FUNC_IF() LOG_FUNC()
|
|
# define LOG_RETURN_VOID_IF() LOG_RETURN_VOID()
|
|
#else
|
|
# define LOG_FUNC_IF()
|
|
# define LOG_RETURN_VOID_IF()
|
|
#endif
|
|
|
|
#define XWJNI_START(GP) { \
|
|
JNIState* state = getState( env, (GP), __func__ ); \
|
|
LOG_FUNC_IF(); \
|
|
XP_ASSERT( state->guard == GAME_GUARD ); \
|
|
MPSLOT; \
|
|
MPASSIGN( mpool, state->mpool ); \
|
|
XP_ASSERT( !!state->globalJNI ); \
|
|
MAP_THREAD( &state->globalJNI->ti, env ); \
|
|
|
|
#define XWJNI_START_GLOBALS(GP) \
|
|
XWJNI_START(GP); \
|
|
AndGameGlobals* globals = &state->globals; \
|
|
XP_USE(globals); /*no warnings */ \
|
|
|
|
#define XWJNI_END() \
|
|
LOG_RETURN_VOID_IF(); \
|
|
} \
|
|
|
|
JNIEXPORT jlong JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_gameJNIInit
|
|
( JNIEnv* env, jclass C, jlong jniGlobalPtr )
|
|
{
|
|
#ifdef MEM_DEBUG
|
|
MemPoolCtx* mpool = ((JNIGlobalState*)jniGlobalPtr)->mpool;
|
|
#endif
|
|
JNIState* state = (JNIState*)XP_CALLOC( mpool, sizeof(*state) );
|
|
#ifdef DEBUG
|
|
state->guard = GAME_GUARD;
|
|
#endif
|
|
state->globalJNI = (JNIGlobalState*)jniGlobalPtr;
|
|
MAP_THREAD( &state->globalJNI->ti, env );
|
|
AndGameGlobals* globals = &state->globals;
|
|
globals->dutil = state->globalJNI->dutil;
|
|
globals->state = (JNIState*)state;
|
|
MPASSIGN( state->mpool, mpool );
|
|
globals->vtMgr = make_vtablemgr(MPPARM_NOCOMMA(mpool));
|
|
|
|
/* LOG_RETURNF( "%p", state ); */
|
|
return (jlong) state;
|
|
}
|
|
|
|
JNIEXPORT void JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_envDone
|
|
( JNIEnv* env, jclass C, jlong jniGlobalPtr )
|
|
{
|
|
#ifdef MAP_THREAD_TO_ENV
|
|
JNIGlobalState* globalJNI = (JNIGlobalState*)jniGlobalPtr;
|
|
MAP_REMOVE( &globalJNI->ti, env );
|
|
#endif
|
|
}
|
|
|
|
JNIEXPORT void JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_game_1makeNewGame
|
|
( JNIEnv* env, jclass C, GamePtrType gamePtr, jobject j_gi,
|
|
jobject j_selfAddr, jobject j_hostAddr, jobject j_util, jobject j_draw,
|
|
jobject j_cp, jobject j_procs )
|
|
{
|
|
XWJNI_START_GLOBALS(gamePtr);
|
|
CurGameInfo* gi = makeGI( MPPARM(mpool) env, j_gi );
|
|
globals->gi = gi;
|
|
globals->util = makeUtil( MPPARM(mpool) env,
|
|
TI_IF(&state->globalJNI->ti)
|
|
j_util, gi, globals );
|
|
globals->jniutil = state->globalJNI->jniutil;
|
|
DrawCtx* dctx = NULL;
|
|
if ( !!j_draw ) {
|
|
dctx = makeDraw( MPPARM(mpool) env,
|
|
TI_IF(&state->globalJNI->ti) j_draw );
|
|
}
|
|
globals->dctx = dctx;
|
|
if ( !!j_procs ) {
|
|
globals->xportProcs = makeXportProcs( MPPARM(mpool) env,
|
|
TI_IF(&state->globalJNI->ti)
|
|
j_procs );
|
|
}
|
|
CommonPrefs cp = {0};
|
|
loadCommonPrefs( env, &cp, j_cp );
|
|
|
|
CommsAddrRec selfAddr;
|
|
CommsAddrRec* selfAddrP = NULL;
|
|
if ( !!j_selfAddr ) {
|
|
getJAddrRec( env, &selfAddr, j_selfAddr );
|
|
selfAddrP = &selfAddr;
|
|
}
|
|
|
|
CommsAddrRec hostAddr;
|
|
CommsAddrRec* hostAddrP = NULL;
|
|
if ( !!j_hostAddr ) {
|
|
XP_ASSERT( gi->serverRole == SERVER_ISCLIENT );
|
|
getJAddrRec( env, &hostAddr, j_hostAddr );
|
|
hostAddrP = &hostAddr;
|
|
} else {
|
|
XP_ASSERT( gi->serverRole != SERVER_ISCLIENT );
|
|
}
|
|
|
|
game_makeNewGame( MPPARM(mpool) env, &state->game, gi, selfAddrP,
|
|
hostAddrP, globals->util, dctx, &cp, globals->xportProcs );
|
|
XWJNI_END();
|
|
} /* makeNewGame */
|
|
|
|
static void
|
|
initGameGlobals( JNIEnv* env, JNIState* state, jobject jutil, jobject jprocs )
|
|
{
|
|
AndGameGlobals* globals = &state->globals;
|
|
globals->gi = (CurGameInfo*)XP_CALLOC( state->mpool, sizeof(*globals->gi) );
|
|
if ( !!jutil ) {
|
|
XP_ASSERT( !globals->util );
|
|
globals->util = makeUtil( MPPARM(state->mpool) env,
|
|
TI_IF(&state->globalJNI->ti)
|
|
jutil, globals->gi, globals );
|
|
}
|
|
if ( !!jprocs ) {
|
|
globals->xportProcs = makeXportProcs( MPPARM(state->mpool) env,
|
|
TI_IF(&state->globalJNI->ti)
|
|
jprocs );
|
|
}
|
|
globals->jniutil = state->globalJNI->jniutil;
|
|
}
|
|
|
|
JNIEXPORT void JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_game_1makeRematch
|
|
( JNIEnv* env, jclass C, GamePtrType gamePtr, GamePtrType gamePtrNew,
|
|
jobject jutil, jobject jcp, jstring jGameName )
|
|
{
|
|
XWJNI_START_GLOBALS(gamePtr);
|
|
|
|
JNIState* oldState = state; /* state about to go out-of-scope */
|
|
XWJNI_START_GLOBALS(gamePtrNew);
|
|
|
|
initGameGlobals( env, state, jutil, NULL );
|
|
|
|
CommonPrefs cp;
|
|
loadCommonPrefs( env, &cp, jcp );
|
|
|
|
const char* gameName = (*env)->GetStringUTFChars( env, jGameName, NULL );
|
|
game_makeRematch( &oldState->game, env, globals->util, &cp,
|
|
&state->game, gameName );
|
|
(*env)->ReleaseStringUTFChars( env, jGameName, gameName );
|
|
|
|
XWJNI_END(); /* matches second XWJNI_START_GLOBALS! */
|
|
XWJNI_END();
|
|
}
|
|
|
|
JNIEXPORT jboolean JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_game_1makeFromInvite
|
|
( JNIEnv* env, jclass C, GamePtrType gamePtr, jobject jnli, jobject jutil,
|
|
jobject jSelfAddr, jobject jcp, jobject jprocs )
|
|
{
|
|
jboolean result;
|
|
XWJNI_START_GLOBALS(gamePtr);
|
|
|
|
initGameGlobals( env, state, jutil, jprocs );
|
|
|
|
NetLaunchInfo nli;
|
|
loadNLI( env, &nli, jnli );
|
|
LOGNLI( &nli );
|
|
|
|
XP_ASSERT( !!jSelfAddr );
|
|
CommsAddrRec* selfAddrP = NULL;
|
|
CommsAddrRec selfAddr;
|
|
if ( !!jSelfAddr ) {
|
|
selfAddrP = &selfAddr;
|
|
getJAddrRec( env, selfAddrP, jSelfAddr );
|
|
}
|
|
CommonPrefs cp;
|
|
loadCommonPrefs( env, &cp, jcp );
|
|
|
|
result = game_makeFromInvite( &state->game, env, &nli, selfAddrP, globals->util,
|
|
globals->dctx, &cp, globals->xportProcs );
|
|
XWJNI_END();
|
|
return result;
|
|
}
|
|
|
|
JNIEXPORT void JNICALL Java_org_eehouse_android_xw4_jni_XwJNI_game_1dispose
|
|
( JNIEnv* env, jclass claz, GamePtrType gamePtr )
|
|
{
|
|
JNIState* state = getState( env, gamePtr, __func__ );
|
|
XP_ASSERT( state->guard == GAME_GUARD );
|
|
|
|
#ifdef MEM_DEBUG
|
|
MemPoolCtx* mpool = state->mpool;
|
|
#endif
|
|
AndGameGlobals* globals = &state->globals;
|
|
|
|
game_dispose( &state->game, env );
|
|
/* Must happen after game_dispose, which uses it */
|
|
destroyGI( MPPARM(mpool) &globals->gi );
|
|
|
|
destroyDraw( &globals->dctx, env );
|
|
destroyXportProcs( &globals->xportProcs, env );
|
|
destroyUtil( &globals->util, env );
|
|
vtmgr_destroy( MPPARM(mpool) globals->vtMgr );
|
|
|
|
MAP_REMOVE( &state->globalJNI->ti, env );
|
|
|
|
#ifdef DEBUG
|
|
XP_MEMSET( state, -1, sizeof(*state) );
|
|
#endif
|
|
XP_FREE( mpool, state );
|
|
} /* game_dispose */
|
|
|
|
JNIEXPORT jboolean JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_game_1makeFromStream
|
|
( JNIEnv* env, jclass C, GamePtrType gamePtr, jbyteArray jstream, jobject /*out*/jgi,
|
|
jobject jutil, jobject jdraw, jobject jcp, jobject jprocs )
|
|
{
|
|
jboolean result;
|
|
XWJNI_START_GLOBALS(gamePtr);
|
|
|
|
globals->gi = (CurGameInfo*)XP_CALLOC( mpool, sizeof(*globals->gi) );
|
|
globals->util = makeUtil( MPPARM(mpool) env,
|
|
TI_IF(&state->globalJNI->ti)
|
|
jutil, globals->gi, globals);
|
|
globals->jniutil = state->globalJNI->jniutil;
|
|
if ( !!jdraw ) {
|
|
globals->dctx = makeDraw( MPPARM(mpool) env,
|
|
TI_IF(&state->globalJNI->ti)
|
|
jdraw );
|
|
}
|
|
globals->xportProcs = makeXportProcs( MPPARM(mpool) env,
|
|
TI_IF(&state->globalJNI->ti)
|
|
jprocs );
|
|
|
|
XWStreamCtxt* stream = streamFromJStream( MPPARM(mpool) env,
|
|
globals->vtMgr, jstream );
|
|
|
|
CommonPrefs cp;
|
|
loadCommonPrefs( env, &cp, jcp );
|
|
result = game_makeFromStream( MPPARM(mpool) env, stream, &state->game,
|
|
globals->gi, globals->util, globals->dctx,
|
|
&cp, globals->xportProcs );
|
|
stream_destroy( stream, env );
|
|
|
|
if ( result ) {
|
|
XP_ASSERT( 0 != globals->gi->gameID );
|
|
if ( !!jgi ) {
|
|
setJGI( env, jgi, globals->gi );
|
|
}
|
|
}
|
|
|
|
XWJNI_END();
|
|
return result;
|
|
} /* makeFromStream */
|
|
|
|
JNIEXPORT jbyteArray JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_game_1saveToStream
|
|
( JNIEnv* env, jclass C, GamePtrType gamePtr, jobject jgi )
|
|
{
|
|
jbyteArray result;
|
|
XWJNI_START_GLOBALS(gamePtr);
|
|
|
|
/* Use our copy of gi if none's provided. That's because only the caller
|
|
knows if its gi should win -- user has changed game config -- or if
|
|
ours should -- changes like remote players being added. */
|
|
CurGameInfo* gi =
|
|
(NULL == jgi) ? globals->gi : makeGI( MPPARM(mpool) env, jgi );
|
|
XWStreamCtxt* stream = mem_stream_make_sized( MPPARM(mpool) globals->vtMgr,
|
|
state->lastSavedSize,
|
|
NULL, 0, NULL );
|
|
XP_ASSERT( gi_equal( gi, globals->util->gameInfo ) );
|
|
game_saveToStream( &state->game, env, gi, stream, ++state->curSaveCount );
|
|
|
|
if ( NULL != jgi ) {
|
|
destroyGI( MPPARM(mpool) &gi );
|
|
}
|
|
|
|
state->lastSavedSize = stream_getSize( stream );
|
|
result = streamToBArray( env, stream );
|
|
stream_destroy( stream, env );
|
|
|
|
XWJNI_END();
|
|
return result;
|
|
}
|
|
|
|
JNIEXPORT void JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_game_1saveSucceeded
|
|
( JNIEnv* env, jclass C, GamePtrType gamePtr )
|
|
{
|
|
XWJNI_START(gamePtr);
|
|
game_saveSucceeded( &state->game, env, state->curSaveCount );
|
|
XWJNI_END();
|
|
}
|
|
|
|
JNIEXPORT void JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_board_1setDraw
|
|
( JNIEnv* env, jclass C, GamePtrType gamePtr, jobject jdraw )
|
|
{
|
|
XWJNI_START_GLOBALS(gamePtr);
|
|
|
|
DrawCtx* newDraw = makeDraw( MPPARM(mpool) env, TI_IF(&state->globalJNI->ti) jdraw );
|
|
board_setDraw( state->game.board, env, newDraw );
|
|
|
|
destroyDraw( &globals->dctx, env );
|
|
globals->dctx = newDraw;
|
|
|
|
XWJNI_END();
|
|
}
|
|
|
|
JNIEXPORT void JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_board_1invalAll
|
|
( JNIEnv* env, jclass C, GamePtrType gamePtr )
|
|
{
|
|
XWJNI_START(gamePtr);
|
|
board_invalAll( state->game.board );
|
|
XWJNI_END();
|
|
}
|
|
|
|
JNIEXPORT jboolean JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_board_1draw
|
|
( JNIEnv* env, jclass C, GamePtrType gamePtr )
|
|
{
|
|
jboolean result;
|
|
XWJNI_START(gamePtr);
|
|
result = board_draw( state->game.board, env );
|
|
XWJNI_END();
|
|
return result;
|
|
}
|
|
|
|
JNIEXPORT void JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_board_1drawSnapshot
|
|
( JNIEnv* env, jclass C, GamePtrType gamePtr, jobject jdraw, jint width,
|
|
jint height )
|
|
{
|
|
XWJNI_START(gamePtr);
|
|
DrawCtx* newDraw = makeDraw( MPPARM(mpool) env, TI_IF(&state->globalJNI->ti) jdraw );
|
|
board_drawSnapshot( state->game.board, env, newDraw, width, height );
|
|
destroyDraw( &newDraw, env );
|
|
XWJNI_END();
|
|
}
|
|
|
|
#ifdef COMMON_LAYOUT
|
|
JNIEXPORT void JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_board_1figureLayout
|
|
( JNIEnv* env, jclass C, GamePtrType gamePtr, jobject jgi, jint left, jint top,
|
|
jint width, jint height, jint scorePct, jint trayPct, jint scoreWidth,
|
|
jint fontWidth, jint fontHt, jboolean squareTiles, jobject jdims )
|
|
{
|
|
XWJNI_START(gamePtr);
|
|
CurGameInfo* gi = makeGI( MPPARM(mpool) env, jgi );
|
|
|
|
BoardDims dims;
|
|
board_figureLayout( state->game.board, env, gi, left, top, width, height,
|
|
115, scorePct, trayPct, scoreWidth,
|
|
fontWidth, fontHt, squareTiles,
|
|
((!!jdims) ? &dims : NULL) );
|
|
|
|
destroyGI( MPPARM(mpool) &gi );
|
|
|
|
if ( !!jdims ) {
|
|
dimsCtoJ( env, jdims, &dims );
|
|
}
|
|
XWJNI_END();
|
|
}
|
|
|
|
JNIEXPORT void JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_board_1applyLayout
|
|
( JNIEnv* env, jclass C, GamePtrType gamePtr, jobject jdims )
|
|
{
|
|
XWJNI_START(gamePtr);
|
|
BoardDims dims;
|
|
dimsJToC( env, &dims, jdims );
|
|
board_applyLayout( state->game.board, env, &dims );
|
|
XWJNI_END();
|
|
}
|
|
|
|
#else
|
|
|
|
JNIEXPORT void JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_board_1setPos
|
|
(JNIEnv* env, jclass C, GamePtrType gamePtr, jint left, jint top, jint width,
|
|
jint height, jint maxCellSize, jboolean lefty )
|
|
{
|
|
XWJNI_START(gamePtr);
|
|
board_setPos( state->game.board, left, top, width, height, maxCellSize,
|
|
lefty );
|
|
XWJNI_END();
|
|
}
|
|
|
|
JNIEXPORT void JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_board_1setScoreboardLoc
|
|
( JNIEnv* env, jclass C, GamePtrType gamePtr, jint left, jint top,
|
|
jint width, jint height, jboolean divideHorizontally )
|
|
{
|
|
XWJNI_START(gamePtr);
|
|
board_setScoreboardLoc( state->game.board, left, top, width,
|
|
height, divideHorizontally );
|
|
XWJNI_END();
|
|
}
|
|
|
|
JNIEXPORT void JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_board_1setTrayLoc
|
|
( JNIEnv* env, jclass C, GamePtrType gamePtr, jint left, jint top,
|
|
jint width, jint height, jint minDividerWidth )
|
|
{
|
|
XWJNI_START(gamePtr);
|
|
board_setTrayLoc( state->game.board, left, top, width, height,
|
|
minDividerWidth );
|
|
XWJNI_END();
|
|
}
|
|
#endif
|
|
|
|
JNIEXPORT jboolean JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_board_1zoom
|
|
( JNIEnv* env, jclass C, GamePtrType gamePtr, jint zoomBy, jbooleanArray jCanZoom )
|
|
{
|
|
jboolean result;
|
|
XWJNI_START(gamePtr);
|
|
XP_Bool canInOut[2];
|
|
result = board_zoom( state->game.board, env, zoomBy, canInOut );
|
|
jboolean canZoom[2] = { canInOut[0], canInOut[1] };
|
|
setBoolArray( env, jCanZoom, VSIZE(canZoom), canZoom );
|
|
XWJNI_END();
|
|
return result;
|
|
}
|
|
|
|
#ifdef XWFEATURE_ACTIVERECT
|
|
JNIEXPORT jboolean JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_board_1getActiveRect
|
|
( JNIEnv* env, jclass C, GamePtrType gamePtr, jobject jrect, jintArray dims )
|
|
{
|
|
jboolean result;
|
|
XWJNI_START(gamePtr);
|
|
XP_Rect rect;
|
|
XP_U16 nCols, nRows;
|
|
result = board_getActiveRect( state->game.board, &rect, &nCols, &nRows );
|
|
if ( result ) {
|
|
setInt( env, jrect, "left", rect.left );
|
|
setInt( env, jrect, "top", rect.top );
|
|
setInt( env, jrect, "right", rect.left + rect.width );
|
|
setInt( env, jrect, "bottom", rect.top + rect.height );
|
|
if ( !!dims ) {
|
|
setIntInArray( env, dims, 0, nCols );
|
|
setIntInArray( env, dims, 1, nRows );
|
|
}
|
|
}
|
|
XWJNI_END();
|
|
return result;
|
|
}
|
|
#endif
|
|
|
|
#ifdef POINTER_SUPPORT
|
|
JNIEXPORT jboolean JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_board_1handlePenDown
|
|
( JNIEnv* env, jclass C, GamePtrType gamePtr, jint xx, jint yy, jbooleanArray barray )
|
|
{
|
|
jboolean result;
|
|
XWJNI_START(gamePtr);
|
|
XP_Bool bb; /* drop this for now */
|
|
result = board_handlePenDown( state->game.board, env, xx, yy, &bb );
|
|
XWJNI_END();
|
|
return result;
|
|
}
|
|
|
|
JNIEXPORT jboolean JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_board_1handlePenMove
|
|
( JNIEnv* env, jclass C, GamePtrType gamePtr, jint xx, jint yy )
|
|
{
|
|
jboolean result;
|
|
XWJNI_START(gamePtr);
|
|
result = board_handlePenMove( state->game.board, env, xx, yy );
|
|
XWJNI_END();
|
|
return result;
|
|
}
|
|
|
|
JNIEXPORT jboolean JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_board_1handlePenUp
|
|
( JNIEnv* env, jclass C, GamePtrType gamePtr, jint xx, jint yy )
|
|
{
|
|
jboolean result;
|
|
XWJNI_START(gamePtr);
|
|
result = board_handlePenUp( state->game.board, env, xx, yy );
|
|
XWJNI_END();
|
|
return result;
|
|
}
|
|
|
|
JNIEXPORT jboolean JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_board_1containsPt
|
|
( JNIEnv* env, jclass C, GamePtrType gamePtr, jint xx, jint yy )
|
|
{
|
|
jboolean result;
|
|
XWJNI_START(gamePtr);
|
|
result = board_containsPt( state->game.board, xx, yy );
|
|
XWJNI_END();
|
|
return result;
|
|
}
|
|
#endif
|
|
|
|
JNIEXPORT jboolean JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_board_1juggleTray
|
|
(JNIEnv* env, jclass C, GamePtrType gamePtr )
|
|
{
|
|
jboolean result;
|
|
XWJNI_START(gamePtr);
|
|
result = board_juggleTray( state->game.board, env );
|
|
XWJNI_END();
|
|
return result;
|
|
}
|
|
|
|
JNIEXPORT jint JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_board_1getTrayVisState
|
|
(JNIEnv* env, jclass C, GamePtrType gamePtr)
|
|
{
|
|
jboolean result;
|
|
XWJNI_START(gamePtr);
|
|
result = board_getTrayVisState( state->game.board );
|
|
XWJNI_END();
|
|
return result;
|
|
}
|
|
|
|
JNIEXPORT jint JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_board_1getSelPlayer
|
|
(JNIEnv* env, jclass C, GamePtrType gamePtr)
|
|
{
|
|
jint result;
|
|
XWJNI_START(gamePtr);
|
|
result = board_getSelPlayer( state->game.board );
|
|
XWJNI_END();
|
|
return result;
|
|
}
|
|
|
|
JNIEXPORT jboolean JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_board_1passwordProvided
|
|
(JNIEnv* env, jclass C, GamePtrType gamePtr, jint player, jstring jpasswd )
|
|
{
|
|
jboolean result;
|
|
XWJNI_START(gamePtr);
|
|
const char* passwd = (*env)->GetStringUTFChars( env, jpasswd, NULL );
|
|
result = board_passwordProvided( state->game.board, env, player, passwd );
|
|
(*env)->ReleaseStringUTFChars( env, jpasswd, passwd );
|
|
XWJNI_END();
|
|
return result;
|
|
}
|
|
|
|
JNIEXPORT jboolean JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_board_1hideTray
|
|
(JNIEnv* env, jclass C, GamePtrType gamePtr)
|
|
{
|
|
jboolean result;
|
|
XWJNI_START(gamePtr);
|
|
result = board_hideTray( state->game.board, env);
|
|
XWJNI_END();
|
|
return result;
|
|
}
|
|
|
|
JNIEXPORT jboolean JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_board_1showTray
|
|
(JNIEnv* env, jclass C, GamePtrType gamePtr)
|
|
{
|
|
jboolean result;
|
|
XWJNI_START(gamePtr);
|
|
result = board_showTray( state->game.board, env );
|
|
XWJNI_END();
|
|
return result;
|
|
}
|
|
|
|
JNIEXPORT jboolean JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_board_1beginTrade
|
|
( JNIEnv* env, jclass C, GamePtrType gamePtr )
|
|
{
|
|
jboolean result;
|
|
XWJNI_START(gamePtr);
|
|
result = board_beginTrade( state->game.board, env );
|
|
XWJNI_END();
|
|
return result;
|
|
}
|
|
|
|
JNIEXPORT jboolean JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_board_1endTrade
|
|
( JNIEnv* env, jclass C, GamePtrType gamePtr )
|
|
{
|
|
jboolean result;
|
|
XWJNI_START(gamePtr);
|
|
result = board_endTrade( state->game.board );
|
|
XWJNI_END();
|
|
return result;
|
|
}
|
|
|
|
JNIEXPORT jboolean JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_board_1setBlankValue
|
|
( JNIEnv* env, jclass C, GamePtrType gamePtr, jint player,
|
|
jint col, jint row, jint tile )
|
|
{
|
|
jboolean result;
|
|
XWJNI_START(gamePtr);
|
|
result = board_setBlankValue( state->game.board, player, col, row, tile );
|
|
XWJNI_END();
|
|
return result;
|
|
}
|
|
|
|
JNIEXPORT jboolean JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_board_1commitTurn
|
|
( JNIEnv* env, jclass C, GamePtrType gamePtr, jboolean phoniesConfirmed,
|
|
jboolean turnConfirmed, jintArray jNewTiles )
|
|
{
|
|
jboolean result;
|
|
XWJNI_START(gamePtr);
|
|
TrayTileSet* newTilesP = NULL;
|
|
TrayTileSet newTiles;
|
|
|
|
if ( jNewTiles != NULL ) {
|
|
tilesArrayToTileSet( env, jNewTiles, &newTiles );
|
|
newTilesP = &newTiles;
|
|
}
|
|
|
|
result = board_commitTurn( state->game.board, env, phoniesConfirmed,
|
|
turnConfirmed, newTilesP );
|
|
XWJNI_END();
|
|
return result;
|
|
}
|
|
|
|
JNIEXPORT jboolean JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_board_1flip
|
|
(JNIEnv* env, jclass C, GamePtrType gamePtr)
|
|
{
|
|
jboolean result;
|
|
XWJNI_START(gamePtr);
|
|
result = board_flip( state->game.board );
|
|
XWJNI_END();
|
|
return result;
|
|
}
|
|
|
|
JNIEXPORT jboolean JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_board_1replaceTiles
|
|
(JNIEnv* env, jclass C, GamePtrType gamePtr)
|
|
{
|
|
jboolean result;
|
|
XWJNI_START(gamePtr);
|
|
result = board_replaceTiles( state->game.board, env );
|
|
XWJNI_END();
|
|
return result;
|
|
}
|
|
|
|
JNIEXPORT jboolean JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_board_1redoReplacedTiles
|
|
( JNIEnv* env, jclass C, GamePtrType gamePtr )
|
|
{
|
|
jboolean result;
|
|
XWJNI_START(gamePtr);
|
|
result = board_redoReplacedTiles( state->game.board, env );
|
|
XWJNI_END();
|
|
return result;
|
|
}
|
|
|
|
JNIEXPORT void JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_server_1reset
|
|
(JNIEnv* env, jclass C, GamePtrType gamePtr )
|
|
{
|
|
XWJNI_START(gamePtr);
|
|
server_reset( state->game.server, env, state->game.comms );
|
|
XWJNI_END();
|
|
}
|
|
|
|
JNIEXPORT void JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_server_1handleUndo
|
|
(JNIEnv* env, jclass C, GamePtrType gamePtr)
|
|
{
|
|
XWJNI_START(gamePtr);
|
|
server_handleUndo( state->game.server, env, 0 );
|
|
XWJNI_END();
|
|
}
|
|
|
|
JNIEXPORT jboolean JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_server_1do
|
|
(JNIEnv* env, jclass C, GamePtrType gamePtr )
|
|
{
|
|
jboolean result;
|
|
XWJNI_START(gamePtr);
|
|
XP_ASSERT( !!state->game.server );
|
|
result = server_do( state->game.server, env );
|
|
XWJNI_END();
|
|
return result;
|
|
}
|
|
|
|
JNIEXPORT void JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_server_1tilesPicked
|
|
( JNIEnv* env, jclass C, GamePtrType gamePtr, jint player, jintArray jNewTiles )
|
|
{
|
|
XWJNI_START(gamePtr);
|
|
TrayTileSet newTiles;
|
|
tilesArrayToTileSet( env, jNewTiles, &newTiles );
|
|
server_tilesPicked( state->game.server, env, player, &newTiles );
|
|
XWJNI_END();
|
|
}
|
|
|
|
JNIEXPORT jint JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_server_1countTilesInPool
|
|
( JNIEnv* env, jclass C, GamePtrType gamePtr )
|
|
{
|
|
jint result;
|
|
XWJNI_START(gamePtr);
|
|
result = server_countTilesInPool( state->game.server );
|
|
XWJNI_END();
|
|
return result;
|
|
}
|
|
|
|
JNIEXPORT void JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_board_1resetEngine
|
|
(JNIEnv* env, jclass C, GamePtrType gamePtr )
|
|
{
|
|
XWJNI_START(gamePtr);
|
|
board_resetEngine( state->game.board );
|
|
XWJNI_END();
|
|
}
|
|
|
|
JNIEXPORT jboolean JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_board_1requestHint
|
|
( JNIEnv* env, jclass C, GamePtrType gamePtr, jboolean useLimits,
|
|
jboolean goBack, jbooleanArray workRemains )
|
|
{
|
|
jboolean result;
|
|
XWJNI_START(gamePtr);
|
|
XP_Bool tmpbool;
|
|
result = board_requestHint( state->game.board, env,
|
|
#ifdef XWFEATURE_SEARCHLIMIT
|
|
useLimits,
|
|
#endif
|
|
goBack, &tmpbool );
|
|
/* If passed need to do workRemains[0] = tmpbool */
|
|
if ( workRemains ) {
|
|
jboolean jbool = tmpbool;
|
|
setBoolArray( env, workRemains, 1, &jbool );
|
|
}
|
|
XWJNI_END();
|
|
return result;
|
|
}
|
|
|
|
JNIEXPORT jboolean JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_timerFired
|
|
( JNIEnv* env, jclass C, GamePtrType gamePtr, jint why, jint when, jint handle )
|
|
{
|
|
jboolean result;
|
|
XWJNI_START_GLOBALS(gamePtr);
|
|
XW_UtilCtxt* util = globals->util;
|
|
result = utilTimerFired( util, env, why, handle );
|
|
XWJNI_END();
|
|
return result;
|
|
}
|
|
|
|
JNIEXPORT jstring JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_board_1formatRemainingTiles
|
|
(JNIEnv* env, jclass C, GamePtrType gamePtr )
|
|
{
|
|
jstring result;
|
|
XWJNI_START_GLOBALS(gamePtr);
|
|
XWStreamCtxt* stream = mem_stream_make( MPPARM(mpool) globals->vtMgr,
|
|
NULL, 0, NULL );
|
|
board_formatRemainingTiles( state->game.board, env, stream );
|
|
result = streamToJString( env, stream );
|
|
stream_destroy( stream, env );
|
|
|
|
XWJNI_END();
|
|
return result;
|
|
}
|
|
|
|
JNIEXPORT jstring JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_server_1formatDictCounts
|
|
( JNIEnv* env, jclass C, GamePtrType gamePtr, jint nCols )
|
|
{
|
|
jstring result;
|
|
XWJNI_START_GLOBALS(gamePtr);
|
|
XWStreamCtxt* stream = and_empty_stream( MPPARM(mpool) globals );
|
|
server_formatDictCounts( state->game.server, env, stream, nCols, XP_FALSE );
|
|
result = streamToJString( env, stream );
|
|
stream_destroy( stream, env );
|
|
XWJNI_END();
|
|
return result;
|
|
}
|
|
|
|
JNIEXPORT jboolean JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_server_1getGameIsOver
|
|
( JNIEnv* env, jclass C, GamePtrType gamePtr )
|
|
{
|
|
jboolean result;
|
|
XWJNI_START(gamePtr);
|
|
result = server_getGameIsOver( state->game.server );
|
|
XWJNI_END();
|
|
return result;
|
|
}
|
|
|
|
JNIEXPORT jstring JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_model_1writeGameHistory
|
|
( JNIEnv* env, jclass C, GamePtrType gamePtr, jboolean gameOver )
|
|
{
|
|
jstring result;
|
|
XWJNI_START_GLOBALS(gamePtr);
|
|
XWStreamCtxt* stream = and_empty_stream( MPPARM(mpool) globals );
|
|
model_writeGameHistory( state->game.model, env, stream,
|
|
state->game.server, gameOver );
|
|
result = streamToJString( env, stream );
|
|
stream_destroy( stream, env );
|
|
XWJNI_END();
|
|
return result;
|
|
}
|
|
|
|
JNIEXPORT jint JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_model_1getNMoves
|
|
( JNIEnv* env, jclass C, GamePtrType gamePtr )
|
|
{
|
|
jint result;
|
|
XWJNI_START(gamePtr);
|
|
XP_ASSERT( !!state->game.model );
|
|
result = model_getNMoves( state->game.model );
|
|
XWJNI_END();
|
|
return result;
|
|
}
|
|
|
|
|
|
JNIEXPORT jint JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_model_1getNumTilesInTray
|
|
( JNIEnv* env, jclass C, GamePtrType gamePtr, jint player )
|
|
{
|
|
jint result;
|
|
XWJNI_START(gamePtr);
|
|
XP_ASSERT( !!state->game.model );
|
|
result = model_getNumTilesInTray( state->game.model, player );
|
|
XWJNI_END();
|
|
return result;
|
|
}
|
|
|
|
JNIEXPORT jobject JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_model_1getPlayersLastScore
|
|
( JNIEnv* env, jclass C, GamePtrType gamePtr, jint player )
|
|
{
|
|
jobject jlmi;
|
|
XWJNI_START(gamePtr);
|
|
XP_ASSERT( !!state->game.model );
|
|
LastMoveInfo lmi;
|
|
XP_Bool valid = model_getPlayersLastScore( state->game.model, env,
|
|
player, &lmi );
|
|
|
|
jlmi = makeObjectEmptyConst( env, PKG_PATH("jni/LastMoveInfo") );
|
|
setBool( env, jlmi, "isValid", valid );
|
|
if ( valid ) {
|
|
setBool( env, jlmi, "inDuplicateMode", lmi.inDuplicateMode );
|
|
setInt( env, jlmi, "score", lmi.score );
|
|
setInt( env, jlmi, "nTiles", lmi.nTiles );
|
|
setInt( env, jlmi, "moveType", lmi.moveType );
|
|
setStringArray( env, jlmi, "names", lmi.nWinners, lmi.names );
|
|
setString( env, jlmi, "word", lmi.word );
|
|
}
|
|
XWJNI_END();
|
|
return jlmi;
|
|
}
|
|
|
|
JNIEXPORT jstring JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_server_1writeFinalScores
|
|
( JNIEnv* env, jclass C, GamePtrType gamePtr )
|
|
{
|
|
jstring result;
|
|
XWJNI_START_GLOBALS(gamePtr);
|
|
XWStreamCtxt* stream = and_empty_stream( MPPARM(mpool) globals );
|
|
server_writeFinalScores( state->game.server, env, stream );
|
|
result = streamToJString( env, stream );
|
|
stream_destroy( stream, env );
|
|
XWJNI_END();
|
|
return result;
|
|
}
|
|
|
|
void
|
|
and_send_on_close( XWStreamCtxt* stream, XWEnv xwe, void* closure )
|
|
{
|
|
AndGameGlobals* globals = (AndGameGlobals*)closure;
|
|
JNIState* state = (JNIState*)globals->state;
|
|
|
|
XP_ASSERT( !!state->game.comms );
|
|
comms_send( state->game.comms, xwe, stream );
|
|
}
|
|
|
|
JNIEXPORT jboolean JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_server_1initClientConnection
|
|
( JNIEnv* env, jclass C, GamePtrType gamePtr )
|
|
{
|
|
jboolean result;
|
|
LOG_FUNC();
|
|
XWJNI_START_GLOBALS(gamePtr);
|
|
result = server_initClientConnection( state->game.server, env );
|
|
XWJNI_END();
|
|
LOG_RETURNF( "%s", boolToStr(result) );
|
|
return result;
|
|
}
|
|
|
|
JNIEXPORT void JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_comms_1start
|
|
( JNIEnv* env, jclass C, GamePtrType gamePtr )
|
|
{
|
|
XWJNI_START(gamePtr);
|
|
CommsCtxt* comms = state->game.comms;
|
|
if ( !!comms ) {
|
|
comms_start( comms, env );
|
|
}
|
|
XWJNI_END();
|
|
}
|
|
|
|
JNIEXPORT void JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_comms_1stop
|
|
( JNIEnv* env, jclass C, GamePtrType gamePtr )
|
|
{
|
|
XWJNI_START(gamePtr);
|
|
CommsCtxt* comms = state->game.comms;
|
|
if ( !!comms ) {
|
|
comms_stop( comms
|
|
#ifdef XWFEATURE_RELAY
|
|
, env
|
|
#endif
|
|
);
|
|
}
|
|
XWJNI_END();
|
|
}
|
|
|
|
JNIEXPORT jobject JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_comms_1getSelfAddr
|
|
(JNIEnv* env, jclass C, GamePtrType gamePtr )
|
|
{
|
|
jobject jaddr;
|
|
XWJNI_START(gamePtr);
|
|
XP_ASSERT( state->game.comms );
|
|
CommsAddrRec addr;
|
|
comms_getSelfAddr( state->game.comms, &addr );
|
|
jaddr = makeObjectEmptyConst( env, PKG_PATH("jni/CommsAddrRec") );
|
|
setJAddrRec( env, jaddr, &addr );
|
|
XWJNI_END();
|
|
return jaddr;
|
|
}
|
|
|
|
JNIEXPORT jobject JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_comms_1getHostAddr
|
|
(JNIEnv* env, jclass C, GamePtrType gamePtr )
|
|
{
|
|
jobject jaddr = NULL;
|
|
XWJNI_START(gamePtr);
|
|
XP_ASSERT( state->game.comms );
|
|
CommsAddrRec addr;
|
|
if ( comms_getHostAddr( state->game.comms, &addr ) ) {
|
|
jaddr = makeObjectEmptyConst( env, PKG_PATH("jni/CommsAddrRec") );
|
|
setJAddrRec( env, jaddr, &addr );
|
|
}
|
|
XWJNI_END();
|
|
return jaddr;
|
|
}
|
|
|
|
JNIEXPORT jobjectArray JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_comms_1getAddrs
|
|
( JNIEnv* env, jclass C, GamePtrType gamePtr )
|
|
{
|
|
jobjectArray result = NULL;
|
|
XWJNI_START(gamePtr);
|
|
XP_ASSERT( state->game.comms );
|
|
if ( !!state->game.comms ) {
|
|
CommsAddrRec addrs[MAX_NUM_PLAYERS];
|
|
XP_U16 count = VSIZE(addrs);
|
|
comms_getAddrs( state->game.comms, env, addrs, &count );
|
|
result = makeAddrArray( env, count, addrs );
|
|
}
|
|
XWJNI_END();
|
|
return result;
|
|
}
|
|
|
|
JNIEXPORT jboolean JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_game_1receiveMessage
|
|
( JNIEnv* env, jclass C, GamePtrType gamePtr, jbyteArray jstream, jobject jaddr )
|
|
{
|
|
jboolean result;
|
|
XWJNI_START_GLOBALS(gamePtr);
|
|
|
|
XWStreamCtxt* stream = streamFromJStream( MPPARM(mpool) env, globals->vtMgr,
|
|
jstream );
|
|
CommsAddrRec* addrp = NULL;
|
|
CommsAddrRec addr = {0};
|
|
XP_ASSERT( !!jaddr );
|
|
if ( NULL != jaddr ) {
|
|
getJAddrRec( env, &addr, jaddr );
|
|
addrp = &addr;
|
|
}
|
|
|
|
result = game_receiveMessage( &state->game, env, stream, addrp );
|
|
|
|
stream_destroy( stream, env );
|
|
|
|
XWJNI_END();
|
|
return result;
|
|
}
|
|
|
|
JNIEXPORT void JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_game_1summarize
|
|
( JNIEnv* env, jclass C, GamePtrType gamePtr, jobject jsummary )
|
|
{
|
|
XWJNI_START_GLOBALS(gamePtr);
|
|
GameSummary summary = {0};
|
|
game_summarize( &state->game, globals->gi, &summary );
|
|
|
|
setInt( env, jsummary, "nMoves", summary.nMoves );
|
|
setBool( env, jsummary, "gameOver", summary.gameOver );
|
|
setInt( env, jsummary, "turn", summary.turn );
|
|
setBool( env, jsummary, "turnIsLocal", summary.turnIsLocal );
|
|
setInt( env, jsummary, "lastMoveTime", summary.lastMoveTime );
|
|
setInt( env, jsummary, "dupTimerExpires", summary.dupTimerExpires );
|
|
|
|
if ( !!state->game.comms ) {
|
|
CommsCtxt* comms = state->game.comms;
|
|
setInt( env, jsummary, "seed", comms_getChannelSeed( comms ) );
|
|
setInt( env, jsummary, "missingPlayers", summary.missingPlayers );
|
|
setInt( env, jsummary, "nPacketsPending", summary.nPacketsPending );
|
|
|
|
CommsAddrRec addr;
|
|
comms_getSelfAddr( comms, &addr );
|
|
setTypeSetFieldIn( env, &addr, jsummary, "conTypes" );
|
|
|
|
CommsConnType typ;
|
|
for ( XP_U32 st = 0; addr_iter( &addr, &typ, &st ); ) {
|
|
switch( typ ) {
|
|
case COMMS_CONN_RELAY: {
|
|
#ifdef XWFEATURE_RELAY
|
|
XP_UCHAR buf[128];
|
|
XP_U16 len = VSIZE(buf);
|
|
if ( comms_getRelayID( comms, buf, &len ) ) {
|
|
XP_ASSERT( '\0' == buf[len-1] ); /* failed! */
|
|
setString( env, jsummary, "relayID", buf );
|
|
}
|
|
setString( env, jsummary, "roomName", addr.u.ip_relay.invite );
|
|
#endif
|
|
}
|
|
break;
|
|
case COMMS_CONN_NFC:
|
|
case COMMS_CONN_MQTT:
|
|
break;
|
|
#if defined XWFEATURE_BLUETOOTH || defined XWFEATURE_SMS || defined XWFEATURE_P2P
|
|
case COMMS_CONN_BT:
|
|
case COMMS_CONN_P2P:
|
|
case COMMS_CONN_SMS: {
|
|
CommsAddrRec addrs[MAX_NUM_PLAYERS];
|
|
XP_U16 count = VSIZE(addrs);
|
|
comms_getAddrs( comms, env, addrs, &count );
|
|
|
|
const XP_UCHAR* addrps[count];
|
|
for ( int ii = 0; ii < count; ++ii ) {
|
|
switch ( typ ) {
|
|
case COMMS_CONN_BT: addrps[ii] = (XP_UCHAR*)&addrs[ii].u.bt.btAddr; break;
|
|
case COMMS_CONN_P2P: addrps[ii] = (XP_UCHAR*)&addrs[ii].u.p2p.mac_addr; break;
|
|
case COMMS_CONN_SMS: addrps[ii] = (XP_UCHAR*)&addrs[ii].u.sms.phone; break;
|
|
default: XP_ASSERT(0); break;
|
|
}
|
|
XP_LOGFF( "adding btaddr/phone/mac %s", addrps[ii] );
|
|
}
|
|
setStringArray( env, jsummary, "remoteDevs", count, addrps );
|
|
}
|
|
break;
|
|
#endif
|
|
default:
|
|
XP_ASSERT(0);
|
|
}
|
|
}
|
|
}
|
|
|
|
ModelCtxt* model = state->game.model;
|
|
XP_U16 nPlayers = model_getNPlayers( model );
|
|
jint jvals[nPlayers];
|
|
if ( summary.gameOver ) {
|
|
ScoresArray scores;
|
|
model_figureFinalScores( model, &scores, NULL );
|
|
for ( int ii = 0; ii < nPlayers; ++ii ) {
|
|
jvals[ii] = scores.arr[ii];
|
|
}
|
|
} else {
|
|
for ( int ii = 0; ii < nPlayers; ++ii ) {
|
|
jvals[ii] = model_getPlayerScore( model, ii );
|
|
}
|
|
}
|
|
|
|
setIntArray( env, jsummary, "scores", nPlayers, jvals, sizeof(jvals[0]) );
|
|
|
|
XWJNI_END();
|
|
}
|
|
|
|
JNIEXPORT jboolean JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_board_1server_1prefsChanged
|
|
( JNIEnv* env, jclass C, GamePtrType gamePtr, jobject jcp )
|
|
{
|
|
jboolean result;
|
|
XWJNI_START(gamePtr);
|
|
|
|
CommonPrefs cp;
|
|
loadCommonPrefs( env, &cp, jcp );
|
|
|
|
result = board_prefsChanged( state->game.board, &cp );
|
|
server_prefsChanged( state->game.server, &cp );
|
|
|
|
XWJNI_END();
|
|
return result;
|
|
}
|
|
|
|
#ifdef KEYBOARD_NAV
|
|
JNIEXPORT jint JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_board_1getFocusOwner
|
|
( JNIEnv* env, jclass C, GamePtrType gamePtr )
|
|
{
|
|
jint result;
|
|
XWJNI_START(gamePtr);
|
|
result = board_getFocusOwner( state->game.board );
|
|
XWJNI_END();
|
|
return result;
|
|
}
|
|
|
|
JNIEXPORT jboolean JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_board_1focusChanged
|
|
( JNIEnv* env, jclass C, GamePtrType gamePtr, jint typ )
|
|
{
|
|
jboolean result;
|
|
XWJNI_START(gamePtr);
|
|
result = board_focusChanged( state->game.board, typ, XP_TRUE );
|
|
XWJNI_END();
|
|
return result;
|
|
}
|
|
#endif
|
|
|
|
#ifdef KEYBOARD_NAV
|
|
JNIEXPORT jboolean JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_board_1handleKey
|
|
( JNIEnv* env, jclass C, GamePtrType gamePtr, jobject jkey, jboolean jup,
|
|
jbooleanArray jhandled )
|
|
{
|
|
jboolean result;
|
|
XWJNI_START(gamePtr);
|
|
|
|
XP_Bool tmpbool;
|
|
XP_Key key = jEnumToInt( env, jkey );
|
|
if ( jup ) {
|
|
result = board_handleKeyUp( state->game.board, key, &tmpbool );
|
|
} else {
|
|
result = board_handleKeyDown( state->game.board, key, &tmpbool );
|
|
}
|
|
jboolean jbool = tmpbool;
|
|
setBoolArray( env, jhandled, 1, &jbool );
|
|
XWJNI_END();
|
|
return result;
|
|
}
|
|
#endif
|
|
|
|
JNIEXPORT void JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_game_1getGi
|
|
( JNIEnv* env, jclass C, GamePtrType gamePtr, jobject jgi )
|
|
{
|
|
XWJNI_START_GLOBALS(gamePtr);
|
|
setJGI( env, jgi, globals->gi );
|
|
XWJNI_END();
|
|
}
|
|
|
|
static const SetInfo gsi_ints[] = {
|
|
ARR_MEMBER( GameStateInfo, visTileCount ),
|
|
ARR_MEMBER( GameStateInfo, nPendingMessages ),
|
|
ARR_MEMBER( GameStateInfo, trayVisState ),
|
|
};
|
|
static const SetInfo gsi_bools[] = {
|
|
ARR_MEMBER( GameStateInfo,canHint ),
|
|
ARR_MEMBER( GameStateInfo, canUndo ),
|
|
ARR_MEMBER( GameStateInfo, canRedo ),
|
|
ARR_MEMBER( GameStateInfo, inTrade ),
|
|
ARR_MEMBER( GameStateInfo, tradeTilesSelected ),
|
|
ARR_MEMBER( GameStateInfo, canChat ),
|
|
ARR_MEMBER( GameStateInfo, canShuffle ),
|
|
ARR_MEMBER( GameStateInfo, curTurnSelected ),
|
|
ARR_MEMBER( GameStateInfo, canHideRack ),
|
|
ARR_MEMBER( GameStateInfo, canTrade ),
|
|
ARR_MEMBER( GameStateInfo, canPause ),
|
|
ARR_MEMBER( GameStateInfo, canUnpause ),
|
|
};
|
|
|
|
JNIEXPORT void JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_game_1getState
|
|
( JNIEnv* env, jclass C, GamePtrType gamePtr, jobject jgsi )
|
|
{
|
|
XWJNI_START(gamePtr);
|
|
GameStateInfo info;
|
|
game_getState( &state->game, env, &info );
|
|
|
|
setInts( env, jgsi, (void*)&info, AANDS(gsi_ints) );
|
|
setBools( env, jgsi, (void*)&info, AANDS(gsi_bools) );
|
|
|
|
XWJNI_END();
|
|
}
|
|
|
|
JNIEXPORT jboolean JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_game_1hasComms
|
|
( JNIEnv* env, jclass C, GamePtrType gamePtr )
|
|
{
|
|
jboolean result;
|
|
XWJNI_START(gamePtr);
|
|
result = NULL != state->game.comms;
|
|
XWJNI_END();
|
|
return result;
|
|
}
|
|
|
|
#ifdef XWFEATURE_CHANGEDICT
|
|
JNIEXPORT jboolean JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_game_1changeDict
|
|
( JNIEnv* env, jclass C, GamePtrType gamePtr, jobject jgi, jstring jname,
|
|
jbyteArray jDictBytes, jstring jpath )
|
|
{
|
|
XWJNI_START_GLOBALS(gamePtr);
|
|
DictionaryCtxt* dict = makeDict( MPPARM(state->globalJNI->mpool) env,
|
|
TI_IF(&globalState->ti)
|
|
state->globalJNI->dictMgr,
|
|
globals->jniutil, jname, jDictBytes,
|
|
jpath, NULL, false );
|
|
game_changeDict( MPPARM(mpool) &state->game, globals->gi, dict );
|
|
dict_unref( dict );
|
|
setJGI( env, jgi, globals->gi );
|
|
XWJNI_END();
|
|
return XP_FALSE; /* no need to redraw */
|
|
}
|
|
#endif
|
|
|
|
JNIEXPORT jint JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_comms_1resendAll
|
|
( JNIEnv* env, jclass C, GamePtrType gamePtr, jboolean force, jobject jFilter,
|
|
jboolean thenAck )
|
|
{
|
|
jint result = 0;
|
|
XWJNI_START(gamePtr);
|
|
CommsCtxt* comms = state->game.comms;
|
|
XP_ASSERT( !!comms );
|
|
if ( !!comms ) {
|
|
CommsConnType filter =
|
|
NULL == jFilter ? COMMS_CONN_NONE : jEnumToInt( env, jFilter );
|
|
result = comms_resendAll( comms, env, filter, force );
|
|
if ( thenAck ) {
|
|
#ifdef XWFEATURE_COMMSACK
|
|
comms_ackAny( comms, env );
|
|
#endif
|
|
}
|
|
} else {
|
|
/* I've seen this once, but wasn't reproducible */
|
|
XP_LOGFF( "ERROR: called with null comms" );
|
|
}
|
|
XWJNI_END();
|
|
return result;
|
|
}
|
|
|
|
JNIEXPORT jint JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_comms_1countPendingPackets
|
|
( JNIEnv* env, jclass C, GamePtrType gamePtr )
|
|
{
|
|
jint result = 0;
|
|
XWJNI_START(gamePtr);
|
|
const CommsCtxt* comms = state->game.comms;
|
|
if ( !!comms ) {
|
|
result = comms_countPendingPackets( comms );
|
|
}
|
|
XWJNI_END();
|
|
return result;
|
|
}
|
|
|
|
#ifdef XWFEATURE_COMMSACK
|
|
JNIEXPORT void JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_comms_1ackAny
|
|
( JNIEnv* env, jclass C, GamePtrType gamePtr )
|
|
{
|
|
XWJNI_START(gamePtr);
|
|
XP_ASSERT( !!state->game.comms );
|
|
(void)comms_ackAny( state->game.comms, env );
|
|
XWJNI_END();
|
|
}
|
|
#endif
|
|
|
|
JNIEXPORT jboolean JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_comms_1isConnected
|
|
( JNIEnv* env, jclass C, GamePtrType gamePtr )
|
|
{
|
|
jboolean result;
|
|
XWJNI_START(gamePtr);
|
|
result = NULL != state->game.comms && comms_isConnected( state->game.comms );
|
|
XWJNI_END();
|
|
return result;
|
|
}
|
|
|
|
JNIEXPORT jstring JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_comms_1getStats
|
|
( JNIEnv* env, jclass C, GamePtrType gamePtr )
|
|
{
|
|
jstring result = NULL;
|
|
#ifdef DEBUG
|
|
XWJNI_START_GLOBALS(gamePtr);
|
|
if ( NULL != state->game.comms ) {
|
|
XWStreamCtxt* stream = mem_stream_make( MPPARM(mpool) globals->vtMgr,
|
|
NULL, 0, NULL );
|
|
comms_getStats( state->game.comms, stream );
|
|
result = streamToJString( env, stream );
|
|
stream_destroy( stream, env );
|
|
}
|
|
XWJNI_END();
|
|
#endif
|
|
return result;
|
|
}
|
|
|
|
JNIEXPORT void JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_comms_1addMQTTDevID
|
|
( JNIEnv* env, jclass C, GamePtrType gamePtr, jint channel, jstring jdevid )
|
|
{
|
|
XWJNI_START_GLOBALS(gamePtr);
|
|
if ( NULL != state->game.comms ) {
|
|
const char* str = (*env)->GetStringUTFChars( env, jdevid, NULL );
|
|
MQTTDevID devID;
|
|
if ( strToMQTTCDevID( str, &devID ) ) {
|
|
comms_addMQTTDevID( state->game.comms, channel, &devID );
|
|
}
|
|
(*env)->ReleaseStringUTFChars( env, jdevid, str );
|
|
}
|
|
XWJNI_END();
|
|
}
|
|
|
|
#ifdef XWFEATURE_COMMS_INVITE
|
|
JNIEXPORT void JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_comms_1invite
|
|
( JNIEnv* env, jclass C, GamePtrType gamePtr, jobject jnli, jobject jaddr )
|
|
{
|
|
XWJNI_START_GLOBALS(gamePtr);
|
|
CommsCtxt* comms = state->game.comms;
|
|
XP_ASSERT( NULL != comms );
|
|
if ( NULL != comms ) {
|
|
CommsAddrRec destAddr;
|
|
getJAddrRec( env, &destAddr, jaddr );
|
|
NetLaunchInfo nli;
|
|
loadNLI( env, &nli, jnli );
|
|
|
|
comms_invite( comms, env, &nli, &destAddr );
|
|
}
|
|
XWJNI_END();
|
|
}
|
|
#endif
|
|
|
|
JNIEXPORT void JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_comms_1dropHostAddr
|
|
( JNIEnv* env, jclass C, GamePtrType gamePtr, jobject jConnTyp )
|
|
{
|
|
LOG_FUNC();
|
|
XWJNI_START(gamePtr);
|
|
if ( NULL != state->game.comms ) {
|
|
CommsConnType connType = jEnumToInt( env, jConnTyp );
|
|
comms_dropHostAddr( state->game.comms, connType );
|
|
}
|
|
XWJNI_END();
|
|
LOG_RETURN_VOID();
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
JNIEXPORT void JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_comms_1setAddrDisabled
|
|
( JNIEnv* env, jclass C, GamePtrType gamePtr, jobject jConnTyp,
|
|
jboolean forSend, jboolean val )
|
|
{
|
|
XWJNI_START(gamePtr);
|
|
if ( NULL != state->game.comms ) {
|
|
CommsConnType connType = jEnumToInt( env, jConnTyp );
|
|
comms_setAddrDisabled( state->game.comms, connType, forSend, val );
|
|
}
|
|
XWJNI_END();
|
|
}
|
|
#endif
|
|
|
|
JNIEXPORT jboolean JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_comms_1getAddrDisabled
|
|
( JNIEnv* env, jclass C, GamePtrType gamePtr, jobject jConnTyp,
|
|
jboolean forSend )
|
|
{
|
|
jboolean result = XP_FALSE;
|
|
#ifdef DEBUG
|
|
XWJNI_START(gamePtr);
|
|
if ( NULL != state->game.comms ) {
|
|
CommsConnType connType = jEnumToInt( env, jConnTyp );
|
|
result = comms_getAddrDisabled( state->game.comms, connType, forSend );
|
|
}
|
|
XWJNI_END();
|
|
#endif
|
|
return result;
|
|
}
|
|
|
|
JNIEXPORT jboolean JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_haveEnv
|
|
( JNIEnv* env, jclass C, jlong jniGlobalPtr )
|
|
{
|
|
jboolean result = XP_TRUE;
|
|
#ifdef MAP_THREAD_TO_ENV
|
|
JNIGlobalState* globalState = (JNIGlobalState*)jniGlobalPtr;
|
|
result = NULL != prvEnvForMe(&globalState->ti);
|
|
#endif
|
|
return result;
|
|
}
|
|
|
|
JNIEXPORT void JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_server_1endGame
|
|
( JNIEnv* env, jclass C, GamePtrType gamePtr )
|
|
{
|
|
XWJNI_START(gamePtr);
|
|
XP_ASSERT( !!state->game.server );
|
|
server_endGame( state->game.server, env );
|
|
XWJNI_END();
|
|
}
|
|
|
|
JNIEXPORT void JNICALL Java_org_eehouse_android_xw4_jni_XwJNI_board_1pause
|
|
( JNIEnv* env, jclass C, GamePtrType gamePtr, jstring jmsg )
|
|
{
|
|
XWJNI_START(gamePtr);
|
|
XP_ASSERT( !!state->game.board );
|
|
|
|
const char* msg = (*env)->GetStringUTFChars( env, jmsg, NULL );
|
|
board_pause( state->game.board, env, msg );
|
|
(*env)->ReleaseStringUTFChars( env, jmsg, msg );
|
|
|
|
XWJNI_END();
|
|
}
|
|
|
|
JNIEXPORT void JNICALL Java_org_eehouse_android_xw4_jni_XwJNI_board_1unpause
|
|
( JNIEnv* env, jclass C, GamePtrType gamePtr, jstring jmsg )
|
|
{
|
|
XWJNI_START(gamePtr);
|
|
XP_ASSERT( !!state->game.board );
|
|
const char* msg = (*env)->GetStringUTFChars( env, jmsg, NULL );
|
|
board_unpause( state->game.board, env, msg );
|
|
(*env)->ReleaseStringUTFChars( env, jmsg, msg );
|
|
XWJNI_END();
|
|
}
|
|
|
|
#ifdef XWFEATURE_CHAT
|
|
JNIEXPORT void JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_board_1sendChat
|
|
( JNIEnv* env, jclass C, GamePtrType gamePtr, jstring jmsg )
|
|
{
|
|
XWJNI_START(gamePtr);
|
|
XP_ASSERT( !!state->game.server );
|
|
const char* msg = (*env)->GetStringUTFChars( env, jmsg, NULL );
|
|
board_sendChat( state->game.board, env, msg );
|
|
(*env)->ReleaseStringUTFChars( env, jmsg, msg );
|
|
XWJNI_END();
|
|
}
|
|
#endif
|
|
|
|
#ifdef XWFEATURE_WALKDICT
|
|
////////////////////////////////////////////////////////////
|
|
// Dict iterator
|
|
////////////////////////////////////////////////////////////
|
|
|
|
typedef struct _DictIterData {
|
|
JNIGlobalState* globalState;
|
|
const DictionaryCtxt* dict;
|
|
DictIter* iter;
|
|
IndexData idata;
|
|
XP_U16 depth;
|
|
#ifdef DEBUG
|
|
pthread_t lastUser;
|
|
XP_U32 guard;
|
|
#endif
|
|
} DictIterData;
|
|
|
|
static void makeIndex( DictIterData* data );
|
|
static void freeIndices( DictIterData* data );
|
|
#define GI_GUARD 0x89ab72
|
|
|
|
JNIEXPORT jlong JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_di_1init
|
|
( JNIEnv* env, jclass C, jlong jniGlobalPtr, jlong dictPtr,
|
|
jobjectArray jPatsArr, jint minLen, jint maxLen )
|
|
{
|
|
jlong closure = 0;
|
|
JNIGlobalState* globalState = (JNIGlobalState*)jniGlobalPtr;
|
|
MAP_THREAD( &globalState->ti, env );
|
|
|
|
DictionaryCtxt* dict = (DictionaryCtxt*)dictPtr;
|
|
if ( !!dict ) {
|
|
PatDesc patDescs[3];
|
|
XP_MEMSET( patDescs, 0, VSIZE(patDescs) * sizeof(patDescs[0]) );
|
|
|
|
int len = 0;
|
|
bool formatOK = true;
|
|
if ( !!jPatsArr ) {
|
|
len = (*env)->GetArrayLength( env, jPatsArr );
|
|
XP_ASSERT( len == 3 );
|
|
for ( int ii = 0; formatOK && ii < len ; ++ii ) {
|
|
jobject jdesc = (*env)->GetObjectArrayElement( env, jPatsArr, ii );
|
|
if ( !!jdesc ) {
|
|
jbyteArray jtiles = getObjectField( env, jdesc, "tilePat", "[B" );
|
|
if ( !!jtiles ) {
|
|
int nTiles = (*env)->GetArrayLength( env, jtiles );
|
|
if ( 0 < nTiles ) {
|
|
PatDesc* pd = &patDescs[ii];
|
|
/* If user adds too many tiles, we'll see it here */
|
|
if ( nTiles <= VSIZE(pd->tiles) ) {
|
|
pd->nTiles = nTiles;
|
|
jbyte* tiles = (*env)->GetByteArrayElements( env, jtiles, NULL );
|
|
XP_MEMCPY( &pd->tiles[0], tiles, nTiles * sizeof(pd->tiles[0]) );
|
|
(*env)->ReleaseByteArrayElements( env, jtiles, tiles, 0 );
|
|
pd->anyOrderOk = getBool( env, jdesc, "anyOrderOk" );
|
|
} else {
|
|
formatOK = false;
|
|
}
|
|
}
|
|
}
|
|
deleteLocalRefs( env, jtiles, jdesc, DELETE_NO_REF );
|
|
}
|
|
}
|
|
}
|
|
|
|
DictIter* iter = NULL;
|
|
if ( formatOK ) {
|
|
DIMinMax mm = { .min = minLen, .max = maxLen };
|
|
iter = di_makeIter( dict, env, &mm, NULL, 0,
|
|
!!jPatsArr ? patDescs : NULL, VSIZE(patDescs) );
|
|
}
|
|
|
|
if ( !!iter ) {
|
|
DictIterData* data = XP_CALLOC( globalState->mpool, sizeof(*data) );
|
|
data->iter = iter;
|
|
data->globalState = globalState;
|
|
data->dict = dict_ref( dict, env );
|
|
data->depth = 2;
|
|
#ifdef DEBUG
|
|
data->guard = GI_GUARD;
|
|
#endif
|
|
makeIndex( data );
|
|
(void)di_firstWord( data->iter );
|
|
|
|
closure = (jlong)data;
|
|
}
|
|
}
|
|
return closure;
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
# define DI_HEADER(THREAD_CHECK) { \
|
|
DictIterData* data = (DictIterData*)closure; \
|
|
XP_ASSERT( NULL == data || data->guard == GI_GUARD ); \
|
|
if ( THREAD_CHECK && !!data ) { \
|
|
if ( 0 == data->lastUser ) { \
|
|
data->lastUser = pthread_self(); \
|
|
} else { \
|
|
XP_ASSERT( data->lastUser == pthread_self() ); \
|
|
} \
|
|
} \
|
|
|
|
#else
|
|
# define DI_HEADER(THREAD_CHECK) { \
|
|
DictIterData* data = (DictIterData*)closure; \
|
|
|
|
#endif
|
|
|
|
#define DI_HEADER_END() \
|
|
}
|
|
|
|
JNIEXPORT void JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_di_1destroy
|
|
( JNIEnv* env, jclass C, jlong closure )
|
|
{
|
|
DI_HEADER(XP_FALSE);
|
|
if ( NULL != data ) {
|
|
#ifdef MEM_DEBUG
|
|
MemPoolCtx* mpool = data->globalState->mpool;
|
|
#endif
|
|
|
|
freeIndices( data );
|
|
|
|
MAP_REMOVE( &data->globalState->ti, env );
|
|
|
|
di_freeIter( data->iter, env);
|
|
dict_unref( data->dict, env );
|
|
XP_FREE( mpool, data );
|
|
}
|
|
DI_HEADER_END();
|
|
}
|
|
|
|
JNIEXPORT jint JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_di_1wordCount
|
|
(JNIEnv* env, jclass C, jlong closure )
|
|
{
|
|
jint result = 0;
|
|
DI_HEADER(XP_TRUE);
|
|
if ( NULL != data ) {
|
|
result = di_getNWords( data->iter );
|
|
}
|
|
DI_HEADER_END();
|
|
return result;
|
|
}
|
|
|
|
JNIEXPORT jintArray JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_di_1getMinMax
|
|
( JNIEnv* env, jclass C, jlong closure )
|
|
{
|
|
jintArray result = NULL;
|
|
DI_HEADER(XP_TRUE);
|
|
XP_U16 vals[2];
|
|
di_getMinMax( data->iter, &vals[0], &vals[1] );
|
|
|
|
result = makeIntArray( env, VSIZE(vals), vals, sizeof(vals[0]) );
|
|
|
|
DI_HEADER_END();
|
|
return result;
|
|
}
|
|
|
|
JNIEXPORT jobjectArray JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_di_1getPrefixes
|
|
( JNIEnv* env, jclass C, jlong closure )
|
|
{
|
|
jobjectArray result = NULL;
|
|
DI_HEADER(XP_TRUE);
|
|
if ( NULL != data && NULL != data->idata.prefixes ) {
|
|
result = makeStringArray( env, data->idata.count, NULL );
|
|
|
|
XP_U16 depth = data->depth;
|
|
for ( int ii = 0; ii < data->idata.count; ++ii ) {
|
|
XP_UCHAR buf[16];
|
|
(void)dict_tilesToString( data->dict,
|
|
&data->idata.prefixes[depth*ii],
|
|
depth, buf, VSIZE(buf), NULL );
|
|
jstring jstr = (*env)->NewStringUTF( env, buf );
|
|
(*env)->SetObjectArrayElement( env, result, ii, jstr );
|
|
deleteLocalRef( env, jstr );
|
|
}
|
|
}
|
|
DI_HEADER_END();
|
|
return result;
|
|
}
|
|
|
|
JNIEXPORT jintArray JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_di_1getIndices
|
|
( JNIEnv* env, jclass C, jlong closure )
|
|
{
|
|
jintArray jindices = NULL;
|
|
DI_HEADER(XP_TRUE);
|
|
if ( NULL != data ) {
|
|
if ( !!data->idata.indices ) { /* filters-block-all case */
|
|
XP_ASSERT( sizeof(jint) == sizeof(data->idata.indices[0]) );
|
|
jindices = makeIntArray( env, data->idata.count,
|
|
(jint*)data->idata.indices,
|
|
sizeof(data->idata.indices[0]) );
|
|
}
|
|
}
|
|
DI_HEADER_END();
|
|
return jindices;
|
|
}
|
|
|
|
JNIEXPORT jstring JNICALL
|
|
Java_org_eehouse_android_xw4_jni_XwJNI_di_1nthWord
|
|
( JNIEnv* env, jclass C, jlong closure, jint jposn, jstring jdelim )
|
|
{
|
|
jstring result = NULL;
|
|
DI_HEADER(XP_TRUE);
|
|
if ( NULL != data ) {
|
|
if ( di_getNthWord( data->iter, env, jposn, data->depth, &data->idata ) ) {
|
|
XP_UCHAR buf[64];
|
|
const XP_UCHAR* delim = NULL == jdelim ? NULL
|
|
: (*env)->GetStringUTFChars( env, jdelim, NULL );
|
|
di_wordToString( data->iter, buf, VSIZE(buf), delim );
|
|
result = (*env)->NewStringUTF( env, buf );
|
|
if ( !!delim ) {
|
|
(*env)->ReleaseStringUTFChars( env, jdelim, delim );
|
|
}
|
|
} else {
|
|
XP_LOGFF( "failed to get %dth word", jposn );
|
|
}
|
|
}
|
|
DI_HEADER_END();
|
|
return result;
|
|
}
|
|
|
|
static void
|
|
freeIndices( DictIterData* data )
|
|
{
|
|
if ( !!data ) {
|
|
IndexData* idata = &data->idata;
|
|
if ( !!idata->prefixes ) {
|
|
XP_FREE( data->globalState->mpool, idata->prefixes );
|
|
idata->prefixes = NULL;
|
|
}
|
|
if( !!idata->indices ) {
|
|
XP_FREE( data->globalState->mpool, idata->indices );
|
|
idata->indices = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
makeIndex( DictIterData* data )
|
|
{
|
|
XP_U16 nFaces = dict_numTileFaces( data->dict );
|
|
XP_U16 ii;
|
|
XP_U16 count;
|
|
for ( count = 1, ii = 0; ii < data->depth; ++ii ) {
|
|
count *= nFaces;
|
|
}
|
|
|
|
freeIndices( data );
|
|
|
|
IndexData* idata = &data->idata;
|
|
#ifdef MEM_DEBUG
|
|
MemPoolCtx* mpool = data->globalState->mpool;
|
|
#endif
|
|
idata->prefixes = XP_MALLOC( mpool, count * data->depth
|
|
* sizeof(*idata->prefixes) );
|
|
idata->indices = XP_MALLOC( mpool, count * sizeof(*idata->indices) );
|
|
idata->count = count;
|
|
|
|
di_makeIndex( data->iter, data->depth, idata );
|
|
if ( 0 < idata->count ) {
|
|
idata->prefixes = XP_REALLOC( mpool, idata->prefixes,
|
|
idata->count * data->depth *
|
|
sizeof(*idata->prefixes) );
|
|
idata->indices = XP_REALLOC( mpool, idata->indices,
|
|
idata->count * sizeof(*idata->indices) );
|
|
} else {
|
|
freeIndices( data );
|
|
}
|
|
} /* makeIndex */
|
|
|
|
#endif /* XWFEATURE_BOARDWORDS */
|