Merge branch 'android_branch' into android_translate

This commit is contained in:
Eric House 2018-03-14 19:32:25 -07:00
commit 36c9e8c93b
31 changed files with 385 additions and 443 deletions

View file

@ -1,6 +1,6 @@
def INITIAL_CLIENT_VERS = 8
def VERSION_CODE_BASE = 129
def VERSION_NAME = '4.4.133'
def VERSION_CODE_BASE = 130
def VERSION_NAME = '4.4.134'
def FABRIC_API_KEY = System.getenv("FABRIC_API_KEY")
def GCM_SENDER_ID = System.getenv("GCM_SENDER_ID")
def BUILD_INFO_NAME = "build-info.txt"

View file

@ -13,9 +13,9 @@
</style>
</head>
<body>
<h2>CrossWords 4.4.133 release</h2>
<h2>CrossWords 4.4.134 release</h2>
<p>This release fixes a crash closing the wordlist browser.</p>
<p>This release makes a few UI tweaks.</p>
<div id="survey">
<p>Please <a href="https://www.surveymonkey.com/s/GX3XLHR">take
@ -25,12 +25,12 @@
<h3>New with this release</h3>
<ul>
<li>Don't crash (even occasionally) when closing the wordlist
browser. (Reported via Google; thanks!)</li>
<li>Prevent setting wordlist browser min word length higher than
max</li>
<li>Don&apos;t include current player&apos;s tiles in remaining
tiles display</li>
<li>For better navigation with lots of saved games, make the
scrollbar thumb draggable (and move it to the left side
where it doesn't obscure anything)</li>
<li>When space is limited in Games List display, truncate player
name rather than score</li>
<li>Include latest Catalan translations (from Weblate)</li>
</ul>
<p>(The full changelog

View file

@ -1095,60 +1095,29 @@ public class BTService extends XWService {
m_sender = null;
}
@Override
void postNotification( String device, int gameID, long rowid )
{
String body = LocUtils.getString( this, R.string.new_bt_body_fmt,
device );
GameUtils.postInvitedNotification( this, gameID, body, rowid );
postEvent( MultiEvent.BT_GAME_CREATED, rowid );
}
private BTCmd makeOrNotify( NetLaunchInfo nli, String btName,
String btAddr )
{
BTCmd result;
if ( checkNotDupe( nli ) ) {
if ( DictLangCache.haveDict( this, nli.lang, nli.dict ) ) {
result = makeGame( nli, btName, btAddr );
} else {
Intent intent = MultiService
.makeMissingDictIntent( this, nli,
DictFetchOwner.OWNER_BT );
// NetLaunchInfo.putExtras( intent, gameID, btName, btAddr );
MultiService.postMissingDictNotification( this, intent,
nli.gameID() );
result = BTCmd.INVITE_ACCPT; // ???
}
if ( handleInvitation( nli, btName, DictFetchOwner.OWNER_BT ) ) {
result = BTCmd.INVITE_ACCPT;
} else {
result = BTCmd.INVITE_DUP_INVITE; // dupe of rematch
}
return result;
}
private BTCmd makeGame( NetLaunchInfo nli, String sender,
String senderAddress )
{
BTCmd result;
long[] rowids = DBUtils.getRowIDsFor( BTService.this, nli.gameID() );
if ( null == rowids || 0 == rowids.length ) {
CommsAddrRec addr = nli.makeAddrRec( BTService.this );
long rowid = GameUtils.makeNewMultiGame( BTService.this, nli,
m_btMsgSink,
getUtilCtxt() );
if ( DBUtils.ROWID_NOTFOUND == rowid ) {
result = BTCmd.INVITE_FAILED;
} else {
if ( null != nli.gameName && 0 < nli.gameName.length() ) {
DBUtils.setName( BTService.this, rowid, nli.gameName );
}
result = BTCmd.INVITE_ACCPT;
String body = LocUtils.getString( BTService.this,
R.string.new_bt_body_fmt,
sender );
GameUtils.postInvitedNotification( this, nli.gameID(), body,
rowid );
postEvent( MultiEvent.BT_GAME_CREATED, rowid );
}
} else {
result = BTCmd.INVITE_DUPID;
}
return result;
}
private DataOutputStream connect( BluetoothSocket socket, BTCmd cmd )
{
String name = socket.getRemoteDevice().getName();

View file

@ -510,7 +510,9 @@ public class BoardCanvas extends Canvas implements DrawCtx {
public void score_pendingScore( Rect rect, int score, int playerNum,
int curTurn, int flags )
{
String text = score >= 0? String.format( "%d", score ) : "??";
Log.d( TAG, "pendingScore(playerNum=%d, curTurn=%d)",
playerNum, curTurn );
int otherIndx = (0 == (flags & CELL_ISCURSOR))
? CommonPrefs.COLOR_BACKGRND : CommonPrefs.COLOR_FOCUS;
++rect.top;
@ -522,6 +524,7 @@ public class BoardCanvas extends Canvas implements DrawCtx {
}
m_fillPaint.setColor( playerColor );
String text = score >= 0? String.format( "%d", score ) : "??";
rect.bottom -= rect.height() / 2;
drawCentered( text, rect, null );

View file

@ -20,18 +20,24 @@
package org.eehouse.android.xw4;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.database.DatabaseUtils;
import android.os.Bundle;
import android.os.Looper;
import android.text.TextUtils;
import android.text.format.Time;
import java.util.ArrayList;
import java.util.Formatter;
import java.util.Iterator;
import java.util.Set;
import junit.framework.Assert;
import org.eehouse.android.xw4.loc.LocUtils;
import java.util.Formatter;
public class DbgUtils {
private static final String TAG = DbgUtils.class.getSimpleName();
@ -117,21 +123,17 @@ public class DbgUtils {
}
}
// public static void printIntent( Intent intent )
// {
// if ( s_doLog ) {
// Bundle bundle = intent.getExtras();
// ArrayList<String> al = new ArrayList<String>();
// if ( null != bundle ) {
// Set<String> keys = bundle.keySet();
// Iterator<String> iter = keys.iterator();
// while ( iter.hasNext() ) {
// al.add( iter.next() );
// }
// }
// DbgUtils.logf( "intent extras: %s", TextUtils.join( ", ", al ) );
// }
// }
static String extrasToString( Intent intent )
{
Bundle bundle = intent.getExtras();
ArrayList<String> al = new ArrayList<String>();
if ( null != bundle ) {
for ( String key : bundle.keySet() ) {
al.add( key + ":" + bundle.get(key) );
}
}
return TextUtils.join( ", ", al );
}
public static void dumpCursor( Cursor cursor )
{

View file

@ -1257,7 +1257,6 @@ public class GameUtils {
private static class ResendTask extends AsyncTask<Void, Void, Void> {
private Context m_context;
private HashMap<Long,CommsConnTypeSet> m_games;
private ResendDoneProc m_doneProc;
private CommsConnType m_filter;
private int m_nSent = 0;
@ -1273,15 +1272,16 @@ public class GameUtils {
@Override
protected Void doInBackground( Void... unused )
{
m_games = DBUtils.getGamesWithSendsPending( m_context );
HashMap<Long,CommsConnTypeSet> games
= DBUtils.getGamesWithSendsPending( m_context );
Iterator<Long> iter = m_games.keySet().iterator();
Iterator<Long> iter = games.keySet().iterator();
while ( iter.hasNext() ) {
long rowid = iter.next();
// If we're looking for a specific type, check
if ( null != m_filter ) {
CommsConnTypeSet gameSet = m_games.get( rowid );
CommsConnTypeSet gameSet = games.get( rowid );
if ( gameSet != null && ! gameSet.contains( m_filter ) ) {
continue;
}

View file

@ -2476,6 +2476,7 @@ public class GamesListDelegate extends ListDelegateBase
private void tryStartsFromIntent( Intent intent )
{
Log.d( TAG, "tryStartsFromIntent(extras={%s})", DbgUtils.extrasToString( intent ) );
startFirstHasDict( intent );
startNewNetGame( intent );
startHasGameID( intent );

View file

@ -23,7 +23,6 @@ package org.eehouse.android.xw4;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Handler;
import android.text.TextUtils;
@ -267,51 +266,16 @@ public class RelayService extends XWService
{
Log.d( TAG, "receiveInvitation: got nli from %d: %s", srcDevID,
nli.toString() );
if ( checkNotDupe( nli ) ) {
makeOrNotify( nli );
if ( !handleInvitation( nli, null, DictFetchOwner.OWNER_RELAY ) ) {
Log.d( TAG, "handleInvitation() failed" );
}
}
private void makeOrNotify( NetLaunchInfo nli )
@Override
void postNotification( String device, int gameID, long rowid )
{
if ( DictLangCache.haveDict( this, nli.lang, nli.dict ) ) {
makeGame( nli );
} else {
Intent intent = MultiService
.makeMissingDictIntent( this, nli,
DictFetchOwner.OWNER_RELAY );
MultiService.postMissingDictNotification( this, intent,
nli.gameID() );
}
}
private void makeGame( NetLaunchInfo nli )
{
long[] rowids = DBUtils.getRowIDsFor( this, nli.gameID() );
if ( (null == rowids || 0 == rowids.length)
|| XWPrefs.getRelayInviteToSelfEnabled( this )) {
if ( DictLangCache.haveDict( this, nli.lang, nli.dict ) ) {
long rowid = GameUtils.makeNewMultiGame( this, nli,
new RelayMsgSink(),
getUtilCtxt() );
if ( DBUtils.ROWID_NOTFOUND != rowid ) {
if ( null != nli.gameName && 0 < nli.gameName.length() ) {
DBUtils.setName( this, rowid, nli.gameName );
}
String body = LocUtils.getString( this,
R.string.new_relay_body );
GameUtils.postInvitedNotification( this, nli.gameID(), body,
rowid );
}
} else {
Intent intent = MultiService
.makeMissingDictIntent( this, nli,
DictFetchOwner.OWNER_RELAY );
MultiService.postMissingDictNotification( this, intent,
nli.gameID() );
}
}
String body = LocUtils.getString( this, R.string.new_relay_body );
GameUtils.postInvitedNotification( this, gameID, body, rowid );
}
// Exists to get incoming data onto the main thread
@ -1268,19 +1232,18 @@ public class RelayService extends XWService
}
private static class AsyncSender extends AsyncTask<Void, Void, Void> {
private static class AsyncSender extends Thread {
private Context m_context;
private HashMap<String,ArrayList<byte[]>> m_msgHash;
public AsyncSender( Context context,
HashMap<String,ArrayList<byte[]>> msgHash )
AsyncSender( Context context, HashMap<String, ArrayList<byte[]>> msgHash )
{
m_context = context;
m_msgHash = msgHash;
}
@Override
protected Void doInBackground( Void... ignored )
public void run()
{
// format: total msg lenth: 2
// number-of-relayIDs: 2
@ -1327,9 +1290,9 @@ public class RelayService extends XWService
}
msgLen += thisLen;
}
// Now open a real socket, write size and proto, and
// copy in the formatted buffer
Socket socket = NetUtils.makeProxySocket( m_context, 8000 );
if ( null != socket ) {
DataOutputStream outStream =
@ -1345,15 +1308,14 @@ public class RelayService extends XWService
} catch ( java.io.IOException ioe ) {
Log.ex( TAG, ioe );
}
return null;
} // doInBackground
} // run
}
private static void sendToRelay( Context context,
HashMap<String,ArrayList<byte[]>> msgHash )
{
if ( null != msgHash ) {
new AsyncSender( context, msgHash ).execute();
new AsyncSender( context, msgHash ).start();
} else {
Log.w( TAG, "sendToRelay: null msgs" );
}

View file

@ -504,20 +504,7 @@ public class SMSService extends XWService {
switch( cmd ) {
case INVITE:
String nliData = dis.readUTF();
NetLaunchInfo nli = new NetLaunchInfo( this, nliData );
if ( nli.isValid() && checkNotDupe( nli ) ) {
if ( DictLangCache.haveDict( this, nli.lang, nli.dict ) ) {
makeForInvite( phone, nli );
} else {
Intent intent = MultiService
.makeMissingDictIntent( this, nli,
DictFetchOwner.OWNER_SMS );
MultiService.postMissingDictNotification( this, intent,
nli.gameID() );
}
} else {
Log.w( TAG, "invalid nli from: %s", nliData );
}
makeForInvite( phone, new NetLaunchInfo( this, nliData ) );
break;
case DATA:
int gameID = dis.readInt();
@ -632,7 +619,8 @@ public class SMSService extends XWService {
return success;
}
private void postNotification( String phone, int gameID, long rowid )
@Override
protected void postNotification( String phone, int gameID, long rowid )
{
String owner = Utils.phoneToContact( this, phone, true );
String body = LocUtils.getString( this, R.string.new_name_body_fmt,
@ -642,11 +630,9 @@ public class SMSService extends XWService {
private void makeForInvite( String phone, NetLaunchInfo nli )
{
long rowid = GameUtils.makeNewMultiGame( this, nli,
new SMSMsgSink( this ),
getUtilCtxt() );
postNotification( phone, nli.gameID(), rowid );
ackInvite( phone, nli.gameID() );
if ( handleInvitation( nli, phone, DictFetchOwner.OWNER_SMS ) ) {
ackInvite( phone, nli.gameID() );
}
}
private PendingIntent makeStatusIntent( String msg )

View file

@ -762,19 +762,18 @@ public class WiDirService extends XWService {
String nliData = intent.getStringExtra( KEY_NLI );
NetLaunchInfo nli = new NetLaunchInfo( this, nliData );
String returnMac = intent.getStringExtra( KEY_SRC );
if ( checkNotDupe( nli ) ) {
if ( DictLangCache.haveDict( this, nli.lang, nli.dict ) ) {
makeGame( nli, returnMac );
} else {
Intent dictIntent = MultiService
.makeMissingDictIntent( this, nli,
DictFetchOwner.OWNER_P2P );
MultiService.postMissingDictNotification( this, dictIntent,
nli.gameID() );
}
if ( !handleInvitation( nli, returnMac, DictFetchOwner.OWNER_P2P ) ) {
Log.d( TAG, "handleInvitation() failed" );
}
}
@Override
void postNotification( String device, int gameID, long rowid )
{
Log.e( TAG, "postNotification() doing nothing" );
}
private void handleGameGone( Intent intent )
{
int gameID = intent.getIntExtra( KEY_GAMEID, 0 );

View file

@ -77,11 +77,6 @@ public class XWPrefs {
return getPrefsBoolean( context, R.string.key_show_gcm, false );
}
public static boolean getRelayInviteToSelfEnabled( Context context )
{
return getPrefsBoolean( context, R.string.key_enable_relay_toself, false );
}
public static boolean getSMSToSelfEnabled( Context context )
{
return getPrefsBoolean( context, R.string.key_enable_sms_toself, false );

View file

@ -27,6 +27,7 @@ import android.os.IBinder;
import junit.framework.Assert;
import org.eehouse.android.xw4.MultiService.DictFetchOwner;
import org.eehouse.android.xw4.MultiService.MultiEvent;
import org.eehouse.android.xw4.jni.CommsAddrRec;
import org.eehouse.android.xw4.jni.JNIThread;
@ -36,7 +37,7 @@ import org.eehouse.android.xw4.jni.UtilCtxtImpl;
import java.util.HashSet;
import java.util.Set;
class XWService extends Service {
abstract class XWService extends Service {
private static final String TAG = XWService.class.getSimpleName();
public static enum ReceiveResult { OK, GAME_GONE, UNCONSUMED };
@ -72,7 +73,7 @@ class XWService extends Service {
// Check that we aren't already processing an invitation with this
// inviteID.
protected boolean checkNotDupe( NetLaunchInfo nli )
private boolean checkNotDupe( NetLaunchInfo nli )
{
String inviteID = nli.inviteID();
boolean isDupe;
@ -86,6 +87,40 @@ class XWService extends Service {
return !isDupe;
}
abstract void postNotification( String device, int gameID, long rowid );
protected boolean handleInvitation( NetLaunchInfo nli, String device,
DictFetchOwner dfo )
{
boolean success = false;
long[] rowids = DBUtils.getRowIDsFor( this, nli.gameID() );
if ( 0 == rowids.length
|| ( rowids.length < nli.nPlayersT // will break for two-per-device game
&& XWPrefs.getSecondInviteAllowed( this ) ) ) {
if ( nli.isValid() && checkNotDupe( nli ) ) {
if ( DictLangCache.haveDict( this, nli.lang, nli.dict ) ) {
long rowid = GameUtils.makeNewMultiGame( this, nli,
getSink( 0 ),
getUtilCtxt() );
if ( null != nli.gameName && 0 < nli.gameName.length() ) {
DBUtils.setName( this, rowid, nli.gameName );
}
postNotification( device, nli.gameID(), rowid );
} else {
Intent intent = MultiService
.makeMissingDictIntent( this, nli, dfo );
MultiService.postMissingDictNotification( this, intent,
nli.gameID() );
}
}
}
return success;
}
protected UtilCtxt getUtilCtxt()
{
if ( null == m_utilCtxt ) {
@ -128,8 +163,7 @@ class XWService extends Service {
consumed = true;
jniThread.receive( msg, addr ).release();
} else {
GameUtils.BackMoveResult bmr =
new GameUtils.BackMoveResult();
GameUtils.BackMoveResult bmr = new GameUtils.BackMoveResult();
if ( null == sink ) {
sink = getSink( rowid );
}

View file

@ -125,7 +125,6 @@
<string name="key_enable_dup_invite">key_enable_dup_invite</string>
<string name="key_enable_nfc_toself">key_enable_nfc_toself</string>
<string name="key_enable_sms_toself">key_enable_sms_toself</string>
<string name="key_enable_relay_toself">key_enable_relay_toself</string>
<string name="key_ignore_gcm">key_ignore_gcm</string>
<string name="key_show_gcm">key_show_gcm</string>
<string name="key_nag_intervals">key_nag_intervals</string>

View file

@ -2600,9 +2600,6 @@
devices and I think it\'s rare that people play with more than
two. Let me know if I\'m wrong and I\'ll up the priority.</string>
<string name="enable_relay_toself_title">Enable relay invites to self</string>
<string name="enable_relay_toself_summary">(To aid testing and debugging)</string>
<string name="ignore_gcm_title">Ignore incoming GCM messages</string>
<string name="ignore_gcm_summary">Mimic life without a google account</string>

View file

@ -393,11 +393,6 @@
<PreferenceScreen android:title="@string/pref_group_relay_title"
android:summary="@string/pref_group_relay_summary"
>
<CheckBoxPreference android:key="@string/key_enable_relay_toself"
android:title="@string/enable_relay_toself_title"
android:summary="@string/enable_relay_toself_summary"
android:defaultValue="false"
/>
<CheckBoxPreference android:key="@string/key_ignore_gcm"
android:title="@string/ignore_gcm_title"
android:summary="@string/ignore_gcm_summary"

View file

@ -2177,6 +2177,7 @@ board_requestHint( BoardCtxt* board,
board_popTimerSave( board );
if ( searchComplete && canMove ) {
juggleMoveIfDebug( &newMove );
model_makeTurnFromMoveInfo( model, selPlayer, &newMove);
} else {
result = XP_FALSE;

View file

@ -2704,7 +2704,7 @@ logAddrs( const CommsCtxt* comms, const char* caller )
#endif
static void
augmentChannelAddr( CommsCtxt* comms, AddressRecord * const rec,
augmentChannelAddr( CommsCtxt* XP_UNUSED_DBG(comms), AddressRecord * const rec,
const CommsAddrRec* addr, XWHostID hostID )
{
if ( !!addr ) {

View file

@ -123,7 +123,6 @@ struct EngineCtxt {
static void findMovesOneRow( EngineCtxt* engine );
static Tile localGetBoardTile( EngineCtxt* engine, XP_U16 col,
XP_U16 row, XP_Bool substBlank );
static XP_Bool scoreQualifies( EngineCtxt* engine, XP_U16 score );
static void findMovesForAnchor( EngineCtxt* engine, XP_S16* prevAnchor,
XP_U16 col, XP_U16 row ) ;
static void figureCrosschecks( EngineCtxt* engine, XP_U16 col,
@ -1115,33 +1114,37 @@ considerScoreWordHasBlanks( EngineCtxt* engine, XP_U16 blanksLeft,
XP_U16 ii;
if ( blanksLeft == 0 ) {
XP_U16 score;
XP_U16 nTiles = posmove->moveInfo.nTiles;
/* Hack: When a single-tile move involves two words it'll be found by
both the horizontal and vertical passes. Since it's really the same
move both times we don't want both. It'd be better I think to
change the move comparison code to detect it as a duplicate, but
that's a lot of work. Instead, add a callback in the single-tile
vertical case to count words, and when the count it > 1 drop the
move.*/
WordNotifierInfo* wiip = NULL;
WordNotifierInfo wii;
XP_U16 wordCount = 0;
if ( 1 == nTiles ) {
XP_U16 singleTileWordCount = 0;
if ( !engine->searchHorizontal && 1 == posmove->moveInfo.nTiles ) {
wii.proc = countWords;
wii.closure = &wordCount;
wii.closure = &singleTileWordCount;
wiip = &wii;
}
score = figureMoveScore( engine->model, engine->turn,
&posmove->moveInfo,
engine, (XWStreamCtxt*)NULL, wiip );
#ifdef XWFEATURE_BONUSALL
if ( 0 != engine->allTilesBonus && 0 == engine->nTilesMax ) {
XP_LOGF( "%s: adding bonus: %d becoming %d", __func__, score ,
score + engine->allTilesBonus );
score += engine->allTilesBonus;
}
#endif
/* First, check that the score is even what we're interested in. If
it is, then go to the expense of filling in a PossibleMove to be
compared in full */
if ( 1 == nTiles && 1 < wordCount && !engine->searchHorizontal ) {
XP_U16 score = figureMoveScore( engine->model, engine->turn,
&posmove->moveInfo,
engine, (XWStreamCtxt*)NULL, wiip );
if ( singleTileWordCount > 1 ) { /* only set by special-case code above */
XP_ASSERT( singleTileWordCount == 2 ); /* I think this is the limit */
// XP_LOGF( "%s(): dropping", __func__ );
} else if ( scoreQualifies( engine, score ) ) {
} else {
#ifdef XWFEATURE_BONUSALL
if ( 0 != engine->allTilesBonus && 0 == engine->nTilesMax ) {
XP_LOGF( "%s: adding bonus: %d becoming %d", __func__, score ,
score + engine->allTilesBonus );
score += engine->allTilesBonus;
}
#endif
posmove->score = score;
XP_MEMSET( &posmove->blankVals, 0, sizeof(posmove->blankVals) );
for ( ii = 0; ii < usedBlanksCount; ++ii ) {
@ -1342,43 +1345,6 @@ move_cache_empty( const EngineCtxt* engine )
return empty;
}
static XP_Bool
scoreQualifies( EngineCtxt* engine, XP_U16 score )
{
XP_Bool qualifies = XP_FALSE;
XP_Bool usePrev = engine->usePrev;
MoveIterationData* miData = &engine->miData;
if ( usePrev && score < miData->lastSeenMove.score ) {
/* drop it */
} else if ( !usePrev && score > miData->lastSeenMove.score
/* || (score < miData->lowestSavedScore) */ ) {
/* drop it */
} else {
XP_S16 ii;
PossibleMove* savedMoves = miData->savedMoves;
/* Look at each saved score, and return true as soon as one's found
with a lower or equal score to this. <eeh> As an optimization,
consider remembering what the lowest score is *once there are
NUM_SAVED_ENGINE_MOVES moves in here* and doing a quick test on
that. Or better, keeping the list in sorted order. */
for ( ii = 0, savedMoves = miData->savedMoves;
ii < engine->nMovesToSave; ++ii, ++savedMoves ) {
if ( savedMoves->score == 0 ) { /* empty slot */
qualifies = XP_TRUE;
} else if ( usePrev && score <= savedMoves->score ) {
qualifies = XP_TRUE;
break;
} else if ( !usePrev && score >= savedMoves->score ) {
qualifies = XP_TRUE;
break;
}
}
}
//XP_LOGF( "%s(%d)->%d", __func__, score, qualifies );
return qualifies;
} /* scoreQualifies */
static array_edge*
edge_from_tile( const DictionaryCtxt* dict, array_edge* from, Tile tile )
{

View file

@ -1120,6 +1120,28 @@ model_makeTurnFromStream( ModelCtxt* model, XP_U16 playerNum,
return success;
} /* model_makeTurnFromStream */
#ifdef DEBUG
void
juggleMoveIfDebug( MoveInfo* move )
{
XP_U16 nTiles = move->nTiles;
// XP_LOGF( "%s(): move len: %d", __func__, nTiles );
MoveInfoTile tiles[MAX_TRAY_TILES];
XP_MEMCPY( tiles, move->tiles, sizeof(tiles) );
for ( int ii = 0; ii < nTiles; ++ii ) {
int last = nTiles - ii;
int choice = XP_RANDOM() % last;
move->tiles[ii] = tiles[choice];
// XP_LOGF( "%s(): setting %d to %d", __func__, ii, choice );
if ( choice != --last ) {
tiles[choice] = tiles[last];
// XP_LOGF( "%s(): replacing %d with %d", __func__, choice, last );
}
}
}
#endif
void
model_makeTurnFromMoveInfo( ModelCtxt* model, XP_U16 playerNum,
const MoveInfo* newMove )
@ -1127,11 +1149,8 @@ model_makeTurnFromMoveInfo( ModelCtxt* model, XP_U16 playerNum,
XP_U16 col, row, ii;
XP_U16* other;
const MoveInfoTile* tinfo;
Tile blank;
XP_U16 numTiles;
blank = dict_getBlankTile( model_getDictionary( model ) );
numTiles = newMove->nTiles;
Tile blank = dict_getBlankTile( model_getDictionary( model ) );
XP_U16 numTiles = newMove->nTiles;
col = row = newMove->commonCoord; /* just assign both */
other = newMove->isHorizontal? &col: &row;
@ -1667,15 +1686,7 @@ static XP_S16
commitTurn( ModelCtxt* model, XP_S16 turn, const TrayTileSet* newTiles,
XWStreamCtxt* stream, WordNotifierInfo* wni, XP_Bool useStack )
{
XP_U16 ii;
PlayerCtxt* player;
PendingTile* pt;
XP_S16 score = -1;
XP_Bool isHorizontal;
const Tile* newTilesP;
XP_U16 nTiles;
nTiles = newTiles->nTiles;
#ifdef DEBUG
XP_ASSERT( getCurrentMoveScoreIfLegal( model, turn, (XWStreamCtxt*)NULL,
@ -1687,10 +1698,11 @@ commitTurn( ModelCtxt* model, XP_S16 turn, const TrayTileSet* newTiles,
clearLastMoveInfo( model );
player = &model->players[turn];
PlayerCtxt* player = &model->players[turn];
if ( useStack ) {
MoveInfo moveInfo = {0};
XP_Bool isHorizontal;
#ifdef DEBUG
XP_Bool inLine =
#endif
@ -1701,19 +1713,16 @@ commitTurn( ModelCtxt* model, XP_S16 turn, const TrayTileSet* newTiles,
stack_addMove( model->vol.stack, turn, &moveInfo, newTiles );
}
for ( ii = 0, pt=player->pendingTiles; ii < player->nPending;
++ii, ++pt ) {
XP_U16 col, row;
CellTile tile;
XP_U16 val;
col = pt->col;
row = pt->row;
tile = getModelTileRaw( model, col, row );
/* Where's it removed from tray? Need to assert there! */
for ( int ii = 0; ii < player->nPending; ++ii ) {
const PendingTile* pt = &player->pendingTiles[ii];
XP_U16 col = pt->col;
XP_U16 row = pt->row;
CellTile tile = getModelTileRaw( model, col, row );
XP_ASSERT( (tile & TILE_PENDING_BIT) != 0 );
val = tile & TILE_VALUE_MASK;
XP_U16 val = tile & TILE_VALUE_MASK;
if ( val > 1 ) { /* somebody else is using this square too! */
putBackOtherPlayersTiles( model, turn, col, row );
}
@ -1734,17 +1743,18 @@ commitTurn( ModelCtxt* model, XP_S16 turn, const TrayTileSet* newTiles,
player->score += score;
/* Why is this next loop necessary? */
for ( ii = 0; ii < model->nPlayers; ++ii ) {
for ( int ii = 0; ii < model->nPlayers; ++ii ) {
invalidateScore( model, ii );
}
player->nPending = 0;
player->nUndone = 0;
newTilesP = newTiles->tiles;
while ( nTiles-- ) {
model_addPlayerTile( model, turn, -1, *newTilesP++ );
/* Move new tiles into tray */
for ( int ii = newTiles->nTiles - 1; ii >= 0; --ii ) {
model_addPlayerTile( model, turn, -1, newTiles->tiles[ii] );
}
return score;
} /* commitTurn */
@ -2045,72 +2055,67 @@ static void
printMovePre( ModelCtxt* model, XP_U16 XP_UNUSED(moveN), const StackEntry* entry,
void* p_closure )
{
XWStreamCtxt* stream;
const XP_UCHAR* format;
XP_UCHAR buf[64];
XP_UCHAR traybuf[MAX_TRAY_TILES+1];
MovePrintClosure* closure = (MovePrintClosure*)p_closure;
if ( entry->moveType != ASSIGN_TYPE ) {
const XP_UCHAR* format;
XP_UCHAR buf[64];
XP_UCHAR traybuf[MAX_TRAY_TILES+1];
MovePrintClosure* closure = (MovePrintClosure*)p_closure;
XWStreamCtxt* stream = closure->stream;
if ( entry->moveType == ASSIGN_TYPE ) {
return;
}
stream = closure->stream;
XP_SNPRINTF( buf, sizeof(buf), (XP_UCHAR*)"%d:%d ", ++closure->nPrinted,
entry->playerNum+1 );
printString( stream, (XP_UCHAR*)buf );
if ( entry->moveType == TRADE_TYPE ) {
} else {
XP_UCHAR letter[2] = {'\0','\0'};
XP_Bool isHorizontal = entry->u.move.moveInfo.isHorizontal;
XP_U16 col, row;
const MoveInfo* mi;
XP_Bool isPass = XP_FALSE;
if ( entry->moveType == PHONY_TYPE ) {
mi = &entry->u.phony.moveInfo;
} else {
mi = &entry->u.move.moveInfo;
if ( mi->nTiles == 0 ) {
isPass = XP_TRUE;
}
}
if ( isPass ) {
format = util_getUserString( model->vol.util, STR_PASS );
XP_SNPRINTF( buf, VSIZE(buf), "%s", format );
} else {
if ( isHorizontal ) {
format = util_getUserString( model->vol.util, STRS_MOVE_ACROSS );
} else {
format = util_getUserString( model->vol.util, STRS_MOVE_DOWN );
}
row = mi->commonCoord;
col = mi->tiles[0].varCoord;
if ( !isHorizontal ) {
XP_U16 tmp = col; col = row; row = tmp;
}
letter[0] = 'A' + col;
XP_SNPRINTF( traybuf, sizeof(traybuf), (XP_UCHAR *)"%s%d",
letter, row + 1 );
XP_SNPRINTF( buf, sizeof(buf), format, traybuf );
}
XP_SNPRINTF( buf, sizeof(buf), (XP_UCHAR*)"%d:%d ", ++closure->nPrinted,
entry->playerNum+1 );
printString( stream, (XP_UCHAR*)buf );
}
if ( !closure->keepHidden ) {
format = util_getUserString( model->vol.util, STRS_TRAY_AT_START );
formatTray( model_getPlayerTiles( model, entry->playerNum ),
closure->dict, (XP_UCHAR*)traybuf, sizeof(traybuf),
XP_FALSE );
XP_SNPRINTF( buf, sizeof(buf), format, traybuf );
printString( stream, buf );
}
if ( entry->moveType == TRADE_TYPE ) {
} else {
XP_UCHAR letter[2] = {'\0','\0'};
XP_Bool isHorizontal = entry->u.move.moveInfo.isHorizontal;
XP_U16 col, row;
const MoveInfo* mi;
XP_Bool isPass = XP_FALSE;
if ( entry->moveType == PHONY_TYPE ) {
mi = &entry->u.phony.moveInfo;
} else {
mi = &entry->u.move.moveInfo;
if ( mi->nTiles == 0 ) {
isPass = XP_TRUE;
}
}
if ( isPass ) {
format = util_getUserString( model->vol.util, STR_PASS );
XP_SNPRINTF( buf, VSIZE(buf), "%s", format );
} else {
if ( isHorizontal ) {
format = util_getUserString( model->vol.util, STRS_MOVE_ACROSS );
} else {
format = util_getUserString( model->vol.util, STRS_MOVE_DOWN );
}
row = mi->commonCoord;
col = mi->tiles[0].varCoord;
if ( !isHorizontal ) {
XP_U16 tmp = col; col = row; row = tmp;
}
letter[0] = 'A' + col;
XP_SNPRINTF( traybuf, sizeof(traybuf), (XP_UCHAR *)"%s%d",
letter, row + 1 );
XP_SNPRINTF( buf, sizeof(buf), format, traybuf );
}
printString( stream, (XP_UCHAR*)buf );
}
if ( !closure->keepHidden ) {
format = util_getUserString( model->vol.util, STRS_TRAY_AT_START );
formatTray( model_getPlayerTiles( model, entry->playerNum ),
closure->dict, (XP_UCHAR*)traybuf, sizeof(traybuf),
XP_FALSE );
XP_SNPRINTF( buf, sizeof(buf), format, traybuf );
printString( stream, buf );
}
}
} /* printMovePre */
static void
@ -2118,69 +2123,66 @@ printMovePost( ModelCtxt* model, XP_U16 XP_UNUSED(moveN),
const StackEntry* entry, XP_S16 XP_UNUSED(score),
void* p_closure )
{
MovePrintClosure* closure = (MovePrintClosure*)p_closure;
XWStreamCtxt* stream = closure->stream;
DictionaryCtxt* dict = closure->dict;
const XP_UCHAR* format;
XP_U16 nTiles;
XP_S16 totalScore;
XP_UCHAR buf[100];
XP_UCHAR traybuf1[MAX_TRAY_TILES+1];
XP_UCHAR traybuf2[MAX_TRAY_TILES+1];
const MoveInfo* mi;
if ( entry->moveType != ASSIGN_TYPE ) {
MovePrintClosure* closure = (MovePrintClosure*)p_closure;
XWStreamCtxt* stream = closure->stream;
DictionaryCtxt* dict = closure->dict;
const XP_UCHAR* format;
XP_U16 nTiles;
if ( entry->moveType == ASSIGN_TYPE ) {
return;
}
XP_UCHAR buf[100];
XP_UCHAR traybuf1[MAX_TRAY_TILES+1];
XP_UCHAR traybuf2[MAX_TRAY_TILES+1];
const MoveInfo* mi;
XP_S16 totalScore = model_getPlayerScore( model, entry->playerNum );
totalScore = model_getPlayerScore( model, entry->playerNum );
switch( entry->moveType ) {
case TRADE_TYPE:
formatTray( (const TrayTileSet*)&entry->u.trade.oldTiles,
dict, traybuf1, sizeof(traybuf1), closure->keepHidden );
formatTray( (const TrayTileSet*) &entry->u.trade.newTiles,
dict, traybuf2, sizeof(traybuf2), closure->keepHidden );
switch( entry->moveType ) {
case TRADE_TYPE:
formatTray( (const TrayTileSet*)&entry->u.trade.oldTiles,
dict, traybuf1, sizeof(traybuf1), closure->keepHidden );
formatTray( (const TrayTileSet*) &entry->u.trade.newTiles,
dict, traybuf2, sizeof(traybuf2), closure->keepHidden );
format = util_getUserString( model->vol.util, STRSS_TRADED_FOR );
XP_SNPRINTF( buf, sizeof(buf), format, traybuf1, traybuf2 );
printString( stream, buf );
printString( stream, (XP_UCHAR*)XP_CR );
break;
format = util_getUserString( model->vol.util, STRSS_TRADED_FOR );
XP_SNPRINTF( buf, sizeof(buf), format, traybuf1, traybuf2 );
printString( stream, buf );
printString( stream, (XP_UCHAR*)XP_CR );
break;
case PHONY_TYPE:
format = util_getUserString( model->vol.util, STR_PHONY_REJECTED );
printString( stream, format );
case MOVE_TYPE:
format = util_getUserString( model->vol.util, STRD_CUMULATIVE_SCORE );
XP_SNPRINTF( buf, sizeof(buf), format, totalScore );
printString( stream, buf );
if ( entry->moveType == PHONY_TYPE ) {
mi = &entry->u.phony.moveInfo;
} else {
mi = &entry->u.move.moveInfo;
}
nTiles = mi->nTiles;
if ( nTiles > 0 ) {
case PHONY_TYPE:
format = util_getUserString( model->vol.util, STR_PHONY_REJECTED );
printString( stream, format );
case MOVE_TYPE:
format = util_getUserString( model->vol.util, STRD_CUMULATIVE_SCORE );
XP_SNPRINTF( buf, sizeof(buf), format, totalScore );
printString( stream, buf );
if ( entry->moveType == PHONY_TYPE ) {
/* printString( stream, (XP_UCHAR*)"phony rejected " ); */
} else if ( !closure->keepHidden ) {
format = util_getUserString(model->vol.util, STRS_NEW_TILES);
XP_SNPRINTF( buf, sizeof(buf), format,
formatTray( &entry->u.move.newTiles, dict,
traybuf1, sizeof(traybuf1),
XP_FALSE ) );
printString( stream, buf );
stream_catString( stream, (XP_UCHAR*)XP_CR );
mi = &entry->u.phony.moveInfo;
} else {
mi = &entry->u.move.moveInfo;
}
nTiles = mi->nTiles;
if ( nTiles > 0 ) {
if ( entry->moveType == PHONY_TYPE ) {
/* printString( stream, (XP_UCHAR*)"phony rejected " ); */
} else if ( !closure->keepHidden ) {
format = util_getUserString(model->vol.util, STRS_NEW_TILES);
XP_SNPRINTF( buf, sizeof(buf), format,
formatTray( &entry->u.move.newTiles, dict,
traybuf1, sizeof(traybuf1),
XP_FALSE ) );
printString( stream, buf );
stream_catString( stream, (XP_UCHAR*)XP_CR );
}
}
break;
}
break;
printString( stream, (XP_UCHAR*)XP_CR );
}
printString( stream, (XP_UCHAR*)XP_CR );
} /* printMovePost */
static void

View file

@ -221,6 +221,12 @@ XP_Bool model_makeTurnFromStream( ModelCtxt* model, XP_U16 playerNum,
void model_makeTurnFromMoveInfo( ModelCtxt* model, XP_U16 playerNum,
const MoveInfo* newMove );
#ifdef DEBUG
void juggleMoveIfDebug( MoveInfo* move );
#else
# define juggleMoveIfDebug(newMove)
#endif
void model_resetCurrentTurn( ModelCtxt* model, XP_S16 turn );
XP_S16 model_getNMoves( const ModelCtxt* model );

View file

@ -316,10 +316,9 @@ void
stack_addMove( StackCtxt* stack, XP_U16 turn, const MoveInfo* moveInfo,
const TrayTileSet* newTiles )
{
StackEntry move;
move.playerNum = (XP_U8)turn;
move.moveType = MOVE_TYPE;
StackEntry move = {.playerNum = (XP_U8)turn,
.moveType = MOVE_TYPE,
};
XP_MEMCPY( &move.u.move.moveInfo, moveInfo, sizeof(move.u.move.moveInfo));
move.u.move.newTiles = *newTiles;
@ -330,10 +329,9 @@ stack_addMove( StackCtxt* stack, XP_U16 turn, const MoveInfo* moveInfo,
void
stack_addPhony( StackCtxt* stack, XP_U16 turn, const MoveInfo* moveInfo )
{
StackEntry move;
move.playerNum = (XP_U8)turn;
move.moveType = PHONY_TYPE;
StackEntry move = {.playerNum = (XP_U8)turn,
.moveType = PHONY_TYPE,
};
XP_MEMCPY( &move.u.phony.moveInfo, moveInfo,
sizeof(move.u.phony.moveInfo));
@ -345,10 +343,9 @@ void
stack_addTrade( StackCtxt* stack, XP_U16 turn,
const TrayTileSet* oldTiles, const TrayTileSet* newTiles )
{
StackEntry move;
move.playerNum = (XP_U8)turn;
move.moveType = TRADE_TYPE;
StackEntry move = { .playerNum = (XP_U8)turn,
.moveType = TRADE_TYPE,
};
move.u.trade.oldTiles = *oldTiles;
move.u.trade.newTiles = *newTiles;
@ -359,10 +356,9 @@ stack_addTrade( StackCtxt* stack, XP_U16 turn,
void
stack_addAssign( StackCtxt* stack, XP_U16 turn, const TrayTileSet* tiles )
{
StackEntry move;
move.playerNum = (XP_U8)turn;
move.moveType = ASSIGN_TYPE;
StackEntry move = { .playerNum = (XP_U8)turn,
.moveType = ASSIGN_TYPE,
};
move.u.assign.tiles = *tiles;

View file

@ -615,9 +615,13 @@ scoreWord( const ModelCtxt* model, XP_U16 turn,
* each time through in the debug case */
if ( 0 ) { /* makes keeping parens balanced easier */
#ifdef DEBUG
/* Always run in DEBUG case */
} else if ( 1 ) {
#else
} else if ( engine == NULL ) {
/* If notifyInfo is set, we're counting on the side-effect of its
proc getting called. So skip caching in that case even on
release builds. */
} else if ( engine == NULL || notifyInfo != NULL ) {
#endif
Tile checkWordBuf[MAX_ROWS];
Tile* curTile = checkWordBuf;
@ -688,7 +692,8 @@ scoreWord( const ModelCtxt* model, XP_U16 turn,
#else
} else { /* non-debug case we know it's non-null */
#endif
XP_ASSERT( nTiles==1 );
XP_ASSERT( nTiles == 1 );
XP_ASSERT( notifyInfo == NULL );
XP_ASSERT( engine_getScoreCache( engine, movei->commonCoord )
== restScore );
restScore = engine_getScoreCache( engine, movei->commonCoord );

View file

@ -929,6 +929,7 @@ makeRobotMove( ServerCtxt* server )
/* if canMove is false, this is a fake move, a pass */
if ( canMove || NPASSES_OK(server) ) {
juggleMoveIfDebug( &newMove );
model_makeTurnFromMoveInfo( model, turn, &newMove );
XP_LOGF( "%s: robot making %d tile move", __func__, newMove.nTiles );
@ -1832,10 +1833,7 @@ fetchTiles( ServerCtxt* server, XP_U16 playerNum, XP_U16 nToFetch,
{
XP_Bool ask;
XP_U16 nSoFar = resultTiles->nTiles;
XP_U16 nLeft;
PoolContext* pool = server->pool;
TrayTileSet oneTile;
PickInfo pi;
const XP_UCHAR* curTray[MAX_TRAY_TILES];
#ifdef FEATURE_TRAY_EDIT
DictionaryCtxt* dict = model_getDictionary( server->vol.model );
@ -1849,22 +1847,22 @@ fetchTiles( ServerCtxt* server, XP_U16 playerNum, XP_U16 nToFetch,
ask = XP_FALSE;
#endif
nLeft = pool_getNTilesLeft( pool );
XP_U16 nLeft = pool_getNTilesLeft( pool );
if ( nLeft < nToFetch ) {
nToFetch = nLeft;
}
oneTile.nTiles = 1;
pi.nTotal = nToFetch;
pi.thisPick = 0;
pi.curTiles = curTray;
TrayTileSet oneTile = {.nTiles = 1};
PickInfo pi = { .nTotal = nToFetch,
.thisPick = 0,
.curTiles = curTray,
};
curTrayAsTexts( server, playerNum, tradedTiles, &pi.nCurTiles, curTray );
#ifdef FEATURE_TRAY_EDIT /* good compiler would note ask==0, but... */
/* First ask until cancelled */
for ( ; ask && nSoFar < nToFetch; ) {
while ( ask && nSoFar < nToFetch ) {
const XP_UCHAR* texts[MAX_UNIQUE_TILES];
Tile tiles[MAX_UNIQUE_TILES];
XP_S16 chosen;
@ -1901,12 +1899,7 @@ fetchTiles( ServerCtxt* server, XP_U16 playerNum, XP_U16 nToFetch,
/* Then fetch the rest without asking */
if ( nSoFar < nToFetch ) {
XP_U8 nLeft = nToFetch - nSoFar;
Tile tiles[MAX_TRAY_TILES];
pool_requestTiles( pool, tiles, &nLeft );
XP_MEMCPY( &resultTiles->tiles[nSoFar], tiles,
nLeft * sizeof(resultTiles->tiles[0]) );
pool_requestTiles( pool, &resultTiles->tiles[nSoFar], &nLeft );
nSoFar += nLeft;
}
@ -2462,8 +2455,9 @@ server_commitMove( ServerCtxt* server, TrayTileSet* newTilesP )
if client, send to server. */
XP_ASSERT( turn >= 0 );
nTilesMoved = model_getCurrentMoveCount( model, turn );
pool_removeTiles( server->pool, &newTiles );
nTilesMoved = model_getCurrentMoveCount( model, turn );
fetchTiles( server, turn, nTilesMoved, NULL, &newTiles );
#ifndef XWFEATURE_STANDALONE_ONLY

View file

@ -1372,8 +1372,8 @@ curses_util_getVTManager(XW_UtilCtxt* uc)
static void
curses_util_informNeedPassword( XW_UtilCtxt* XP_UNUSED(uc),
XP_U16 playerNum,
const XP_UCHAR* name )
XP_U16 XP_UNUSED_DBG(playerNum),
const XP_UCHAR* XP_UNUSED_DBG(name) )
{
XP_WARNF( "curses_util_informNeedPassword(num=%d, name=%s", playerNum, name );
} /* curses_util_askPassword */
@ -1391,7 +1391,7 @@ curses_util_yOffsetChange( XW_UtilCtxt* XP_UNUSED(uc),
#ifdef XWFEATURE_TURNCHANGENOTIFY
static void
curses_util_turnChanged( XW_UtilCtxt* XP_UNUSED(uc), XP_S16 newTurn )
curses_util_turnChanged( XW_UtilCtxt* XP_UNUSED(uc), XP_S16 XP_UNUSED_DBG(newTurn) )
{
XP_LOGF( "%s(turn=%d)", __func__, newTurn );
}
@ -1725,7 +1725,7 @@ cursesGotBuf( void* closure, const CommsAddrRec* addr,
static void
cursesGotForRow( void* closure, const CommsAddrRec* from,
sqlite3_int64 rowid, const XP_U8* buf,
sqlite3_int64 XP_UNUSED_DBG(rowid), const XP_U8* buf,
XP_U16 len )
{
LOG_FUNC();

View file

@ -31,8 +31,8 @@ static void getColumnText( sqlite3_stmt *ppStmt, int iCol, XP_UCHAR* buf,
int len );
#ifdef DEBUG
static char* sqliteErr2str( int err );
static void assertPrintResult( sqlite3* pDb, int result, int expect );
#endif
static void assertPrintResult( sqlite3* pDb, int result, int expect );
sqlite3*
openGamesDB( const char* dbName )
@ -590,17 +590,15 @@ sqliteErr2str( int err )
}
return "<unknown>";
}
#endif
static void
assertPrintResult( sqlite3* pDb, int result, int expect )
assertPrintResult( sqlite3* pDb, int XP_UNUSED_DBG(result), int expect )
{
int code = sqlite3_errcode( pDb );
XP_ASSERT( code == result ); /* do I need to pass it? */
if ( code != expect ) {
const char* msg = sqlite3_errmsg( pDb );
XP_LOGF( "sqlite3 error: %s", msg );
XP_LOGF( "sqlite3 error: %s", sqlite3_errmsg( pDb ) );
XP_ASSERT(0);
}
}
#endif

View file

@ -435,7 +435,7 @@ tryConnectToServer(CommonGlobals* cGlobals)
{
LaunchParams* params = cGlobals->params;
XWStreamCtxt* stream =
mem_stream_make( cGlobals->util->mpool, params->vtMgr,
mem_stream_make( MPPARM(cGlobals->util->mpool) params->vtMgr,
cGlobals, CHANNEL_NONE,
sendOnClose );
(void)server_initClientConnection( cGlobals->game.server,

View file

@ -1460,8 +1460,7 @@ gtkDrawCtxtMake( GtkWidget* drawing_area, GtkGameGlobals* globals )
dctx->drawing_area = drawing_area;
dctx->globals = globals;
GdkWindow* window = gtk_widget_get_window(drawing_area);
XP_ASSERT( !!window );
XP_ASSERT( !!gtk_widget_get_window(drawing_area) );
#ifdef USE_CAIRO
/* dctx->cairo = gdk_cairo_create( window ); */
/* XP_LOGF( "dctx->cairo=%p", dctx->cairo ); */
@ -1514,6 +1513,7 @@ removeSurface( GtkDrawCtx* dctx )
dctx->surface = NULL;
}
#ifdef DEBUG
static cairo_status_t
write_func( void *closure, const unsigned char *data,
unsigned int length )
@ -1522,16 +1522,19 @@ write_func( void *closure, const unsigned char *data,
stream_putBytes( stream, data, length );
return CAIRO_STATUS_SUCCESS;
}
#endif
void
getImage( GtkDrawCtx* dctx, XWStreamCtxt* stream )
getImage( GtkDrawCtx* XP_UNUSED_DBG(dctx), XWStreamCtxt* XP_UNUSED_DBG(stream) )
{
LOG_FUNC();
XP_ASSERT( !!dctx->surface );
#ifdef DEBUG
cairo_status_t status =
cairo_surface_write_to_png_stream( dctx->surface,
write_func, stream );
XP_ASSERT( CAIRO_STATUS_SUCCESS == status );
#endif
}
void

View file

@ -1242,7 +1242,7 @@ linux_reset( void* closure )
#endif
XP_S16
linux_send( const XP_U8* buf, XP_U16 buflen, const XP_UCHAR* msgNo,
linux_send( const XP_U8* buf, XP_U16 buflen, const XP_UCHAR* XP_UNUSED_DBG(msgNo),
const CommsAddrRec* addrRec, CommsConnType conType, XP_U32 gameID,
void* closure )
{

View file

@ -480,8 +480,9 @@ relayThread( void* arg )
while ( !storage->relayTaskList ) {
pthread_cond_wait( &storage->relayCondVar, &storage->relayMutex );
}
#ifdef DEBUG
int len = g_slist_length( storage->relayTaskList );
#endif
gchar* strs = listTasks( storage->relayTaskList );
GSList* head = storage->relayTaskList;
storage->relayTaskList = g_slist_remove_link( storage->relayTaskList,
@ -740,12 +741,16 @@ relaycon_cleanup( LaunchParams* params )
RelayConStorage* storage = (RelayConStorage*)params->relayConStorage;
if ( storage->params->useHTTP ) {
pthread_mutex_lock( &storage->relayMutex );
#ifdef DEBUG
int nRelayTasks = g_slist_length( storage->relayTaskList );
#endif
gchar* taskStrs = listTasks( storage->relayTaskList );
pthread_mutex_unlock( &storage->relayMutex );
pthread_mutex_lock( &storage->gotDataMutex );
#ifdef DEBUG
int nDataTasks = g_slist_length( storage->gotDataTaskList );
#endif
gchar* gotStrs = listTasks( storage->gotDataTaskList );
pthread_mutex_unlock( &storage->gotDataMutex );
@ -905,17 +910,16 @@ onGotQueryData( RelayTask* task )
if ( !!reply ) {
CommsAddrRec addr = {0};
addr_addType( &addr, COMMS_CONN_RELAY );
#ifdef DEBUG
GList* ids = g_hash_table_get_keys( task->u.query.map );
const char* xxx = ids->data;
#endif
json_object* jMsgs;
if ( json_object_object_get_ex( reply, "msgs", &jMsgs ) ) {
/* Currently there's an array of arrays for each relayID (value) */
XP_LOGF( "%s: got result of len %d", __func__, json_object_object_length(jMsgs) );
XP_ASSERT( json_object_object_length(jMsgs) <= 1 );
json_object_object_foreach(jMsgs, relayID, arrOfArrOfMoves) {
XP_ASSERT( 0 == strcmp( relayID, xxx ) );
XP_ASSERT( 0 == strcmp( relayID, ids->data ) );
int len1 = json_object_array_length( arrOfArrOfMoves );
if ( len1 > 0 ) {
sqlite3_int64 rowid = *(sqlite3_int64*)g_hash_table_lookup( task->u.query.map, relayID );

View file

@ -220,7 +220,7 @@ CRefMgr::getMakeCookieRef( const char* cookie, int nPlayersH, int nPlayersT,
int langCode, int seed, int clientIndx,
bool wantsPublic, bool makePublic, bool* seenSeed )
{
CidInfo* cinfo;
CidInfo* cinfo = NULL;
/* We have a cookie from a new connection or from a reconnect. This may
be the first time it's been seen, or there may be a game currently in
@ -229,8 +229,8 @@ CRefMgr::getMakeCookieRef( const char* cookie, int nPlayersH, int nPlayersT,
a new one. Pass the connName which will be used if set, but if not set
we'll be generating another later when the game is complete.
*/
for ( ; ; ) {
/* What's this for loop thing. It's to fix a race condition. One
for ( int ii = 0; ; ++ii ) {
/* What's this for loop thing? It's to fix a race condition. One
thread has "claim" on cid <N>, which is in the DB. Another comes
into this function and looks it up in the DB, retrieving <N>, but
progress is blocked inside getCookieRef_impl which calls Claim().
@ -238,6 +238,13 @@ CRefMgr::getMakeCookieRef( const char* cookie, int nPlayersH, int nPlayersT,
cref before calling Relinquish so that when Claim() returns there's
no cref. So we test for that case and retry. */
/* I'm now seeing an infinte loop here. Until it's tracked down, let's
assert out. Note that I've seen it here, not at any of the other
places where I'm replacing FOREVER loops with this test*/
if ( ii > 5 ) {
assert(0);
break;
}
CookieID cid;
char connNameBuf[MAX_CONNNAME_LEN+1] = {0};
@ -295,7 +302,13 @@ CRefMgr::getMakeCookieRef( const char* connName, const char* cookie,
CookieRef* cref = NULL;
CidInfo* cinfo = NULL;
for ( ; ; ) { /* for: see comment above */
for ( int ii = 0; ; ++ii ) { /* for: see comment above */
if ( ii > 5 ) {
assert(0);
break;
}
/* fetch these from DB */
char curCookie[MAX_INVITE_LEN+1];
int curLangCode;
@ -346,7 +359,12 @@ CRefMgr::getMakeCookieRef( const char* const connName, HostID hid, bool* isDead
int nPlayersT = 0;
int nAlreadyHere = 0;
for ( ; ; ) { /* for: see comment above */
for ( int ii = 0; ; ++ii ) { /* for: see comment above */
if ( ii > 5 ) {
assert(0);
break;
}
CookieID cid = m_db->FindGame( connName, hid, curCookie, sizeof(curCookie),
&curLangCode, &nPlayersT, &nAlreadyHere,
isDead );
@ -385,7 +403,12 @@ CRefMgr::getMakeCookieRef( const AddrInfo::ClientToken clientToken, HostID srcID
int nPlayersT = 0;
int nAlreadyHere = 0;
for ( ; ; ) { /* for: see comment above */
for ( int ii = 0; ; ++ii ) { /* for: see comment above */
if ( ii > 5 ) {
assert(0);
break;
}
char connName[MAX_CONNNAME_LEN+1] = {0};
CookieID cid = m_db->FindGame( clientToken, srcID,
connName, sizeof(connName),

View file

@ -691,12 +691,14 @@ send_msg_via_udp( const AddrInfo* addr, AddrInfo::ClientToken clientToken,
uint32_t asNetTok = htonl(clientToken);
ssize_t nSent = send_via_udp( addr, packetIDP, XWPDEV_MSG, &asNetTok,
sizeof(asNetTok), buf, bufLen, NULL );
logf( XW_LOGINFO, "%s: sent %d bytes (plus header) on UDP socket, "
"token=%x(%d)", __func__, bufLen, clientToken,
clientToken );
result = 0 < nSent;
logf( XW_LOGINFO, "%s()=>%d", __func__, result );
if (result) {
logf( XW_LOGINFO, "%s: sent %d bytes (plus header) on UDP socket, "
"token=%x(%d)", __func__, bufLen, clientToken,
clientToken );
}
}
// logf( XW_LOGINFO, "%s()=>%d", __func__, result );
return result;
}
@ -1802,8 +1804,8 @@ handle_udp_packet( PacketThreadClosure* ptc )
handlePutMessage( scr, hid, &addr, end - ptr, &ptr, end );
assert( ptr == end ); // DON'T CHECK THIS IN!!!
} else {
logf( XW_LOGERROR, "%s: invalid scr for %s", __func__,
connName );
logf( XW_LOGERROR, "%s: invalid scr for %s/%d", __func__,
connName, hid );
}
} else {
logf( XW_LOGERROR, "no clientToken found!!!" );