Merge tag 'android_beta_100' into android_branch

ready for release
This commit is contained in:
Eric House 2016-01-03 11:36:37 -08:00
commit 22dde029c8
26 changed files with 319 additions and 197 deletions

View file

@ -22,7 +22,7 @@
to come from a domain that you own or have control over. --> to come from a domain that you own or have control over. -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.eehouse.android.xw4dbg" package="org.eehouse.android.xw4dbg"
android:versionCode="93" android:versionCode="94"
android:versionName="@string/app_version" android:versionName="@string/app_version"
> >

View file

@ -55,7 +55,7 @@
<!-- extension targets. Uncomment the ones where you want to do custom work <!-- extension targets. Uncomment the ones where you want to do custom work
in between standard targets --> in between standard targets -->
<property name="INITIAL_CLIENT_VERS" value="4"/> <property name="INITIAL_CLIENT_VERS" value="7"/>
<property name="VARIANT_NAME" value="xw4dbg"/> <property name="VARIANT_NAME" value="xw4dbg"/>
<property name="APP_NAME" value="CrossDbg"/> <property name="APP_NAME" value="CrossDbg"/>

View file

@ -22,7 +22,7 @@
to come from a domain that you own or have control over. --> to come from a domain that you own or have control over. -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.eehouse.android.xw4" package="org.eehouse.android.xw4"
android:versionCode="93" android:versionCode="94"
android:versionName="@string/app_version" android:versionName="@string/app_version"
> >

View file

@ -13,10 +13,10 @@
</style> </style>
</head> </head>
<body> <body>
<h2>Crosswords 4.4 beta 99 release</h2> <h2>Crosswords 4.4 beta 100 release</h2>
<p>This is a quick-fix release for Bluetooth on Android <p>This is the first of two releases that together fix stalling
Marshmallow.</p> issues in network games.</p>
<div id="survey"> <div id="survey">
<p>Please <a href="https://www.surveymonkey.com/s/GX3XLHR">take <p>Please <a href="https://www.surveymonkey.com/s/GX3XLHR">take
@ -26,10 +26,9 @@
<h3>New with this release</h3> <h3>New with this release</h3>
<ul> <ul>
<li>Work around "security" change that broke Bluetooth <li>Fix to recognize (but not yet send) correct identifier for
invitations and gameplay on the latest Android release game state. (Once this upgrade is out I'll do a new release that
("Marshmallow").</li> also sends the correct identifier.)</li>
<li>Fix crash choosing menu at the wrong time</li>
</ul> </ul>
<p>(The full changelog <p>(The full changelog

View file

@ -55,7 +55,7 @@
<!-- extension targets. Uncomment the ones where you want to do custom work <!-- extension targets. Uncomment the ones where you want to do custom work
in between standard targets --> in between standard targets -->
<property name="INITIAL_CLIENT_VERS" value="6"/> <property name="INITIAL_CLIENT_VERS" value="7"/>
<property name="VARIANT_NAME" value="xw4"/> <property name="VARIANT_NAME" value="xw4"/>
<property name="APP_NAME" value="Crosswords"/> <property name="APP_NAME" value="Crosswords"/>

View file

@ -1,6 +1,6 @@
/* -*- compile-command: "cd ..; ../scripts/ndkbuild.sh -j3"; -*- */ /* -*- compile-command: "find-and-ant.sh debug install"; -*- */
/* /*
* Copyright © 2009 - 2011 by Eric House (xwords@eehouse.org). All rights * Copyright © 2009 - 2016 by Eric House (xwords@eehouse.org). All rights
* reserved. * reserved.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
@ -648,7 +648,7 @@ makeDict( MPFORMAL JNIEnv *env, DictMgrCtxt* dictMgr, JNIUtilCtxt* jniutil, jstr
anddict->super.langName = getStringCopy( MPPARM(mpool) anddict->super.langName = getStringCopy( MPPARM(mpool)
env, jlangname ); env, jlangname );
XP_U32 numEdges; XP_U32 numEdges = 0;
XP_Bool parses = parseDict( anddict, (XP_U8*)anddict->bytes, XP_Bool parses = parseDict( anddict, (XP_U8*)anddict->bytes,
bytesSize, &numEdges ); bytesSize, &numEdges );
if ( !parses || (check && !checkSanity( &anddict->super, if ( !parses || (check && !checkSanity( &anddict->super,

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<string name="app_version">4.4 beta 99</string> <string name="app_version">4.4 beta 100</string>
</resources> </resources>

View file

@ -1738,7 +1738,7 @@
<string name="about_vers_fmt">Crosswords for Android, Version %1$s, <string name="about_vers_fmt">Crosswords for Android, Version %1$s,
rev %2$s, built on %3$s.</string> rev %2$s, built on %3$s.</string>
<!-- copyright info --> <!-- copyright info -->
<string name="about_copyright">Copyright (C) 1998-2015 by Eric <string name="about_copyright">Copyright (C) 1998-2016 by Eric
House. This free/open source software is released under the GNU Public House. This free/open source software is released under the GNU Public
License.</string> License.</string>

View file

@ -1495,7 +1495,7 @@
<string name="about_vers_fmt">Sdrowssorc rof ,diordna Noisrev %1$s, <string name="about_vers_fmt">Sdrowssorc rof ,diordna Noisrev %1$s,
ver %2$s, tliub no %3$s.</string> ver %2$s, tliub no %3$s.</string>
<!-- copyright info --> <!-- copyright info -->
<string name="about_copyright">Thgirypoc )C( 5102-8991 yb Cire <string name="about_copyright">Thgirypoc )C( 6102-8991 yb Cire
Esuoh. Siht nepo/eerf ecruos erawtfos si desaeler rednu eht UNG Cilbup Esuoh. Siht nepo/eerf ecruos erawtfos si desaeler rednu eht UNG Cilbup
Esnecil.</string> Esnecil.</string>
<!-- Another paragraph in the about dialog --> <!-- Another paragraph in the about dialog -->

View file

@ -1495,7 +1495,7 @@
<string name="about_vers_fmt">CROSSWORDS FOR ANDROID, VERSION %1$s, <string name="about_vers_fmt">CROSSWORDS FOR ANDROID, VERSION %1$s,
REV %2$s, BUILT ON %3$s.</string> REV %2$s, BUILT ON %3$s.</string>
<!-- copyright info --> <!-- copyright info -->
<string name="about_copyright">COPYRIGHT (C) 1998-2015 BY ERIC <string name="about_copyright">COPYRIGHT (C) 1998-2016 BY ERIC
HOUSE. THIS FREE/OPEN SOURCE SOFTWARE IS RELEASED UNDER THE GNU PUBLIC HOUSE. THIS FREE/OPEN SOURCE SOFTWARE IS RELEASED UNDER THE GNU PUBLIC
LICENSE.</string> LICENSE.</string>
<!-- Another paragraph in the about dialog --> <!-- Another paragraph in the about dialog -->

View file

@ -48,7 +48,7 @@ public class NetStateCache {
private static boolean s_netAvail = false; private static boolean s_netAvail = false;
private static boolean s_isWifi; private static boolean s_isWifi;
private static PvtBroadcastReceiver s_receiver; private static PvtBroadcastReceiver s_receiver;
private static final boolean s_onSim = XWApp.onEmulator(); private static final boolean s_onSDKSim = Build.PRODUCT.contains("sdk"); // not genymotion
public static void register( Context context, StateChangedIf proc ) public static void register( Context context, StateChangedIf proc )
{ {
@ -69,11 +69,23 @@ public class NetStateCache {
public static boolean netAvail( Context context ) public static boolean netAvail( Context context )
{ {
initIfNot( context ); initIfNot( context );
boolean result = s_netAvail || s_onSim;
if ( BuildConfig.DEBUG ) { // Cache is returning false negatives. Don't trust it.
checkSame( context, result ); if ( !s_netAvail ) {
boolean netAvail = getIsConnected( context );
if ( netAvail ) {
String msg = "netAvail(): second-guessing successful!!!";
DbgUtils.logf( msg );
Utils.showToast( context, msg );
s_netAvail = true;
if ( null != s_receiver ) {
s_receiver.notifyStateChanged( context );
}
}
} }
DbgUtils.logf( "NetStateCache.netAvail() => %b", result );
boolean result = s_netAvail || s_onSDKSim;
DbgUtils.logf( "netAvail() => %b", result );
return result; return result;
} }
@ -94,6 +106,19 @@ public class NetStateCache {
} }
} }
private static boolean getIsConnected( Context context )
{
boolean result = false;
NetworkInfo ni = ((ConnectivityManager)
context.getSystemService( Context.CONNECTIVITY_SERVICE ))
.getActiveNetworkInfo();
if ( null != ni && ni.isConnectedOrConnecting() ) {
result = true;
}
DbgUtils.logf( "NetStateCache.getConnected() => %b", result );
return result;
}
private static void initIfNot( Context context ) private static void initIfNot( Context context )
{ {
synchronized( s_haveReceiver ) { synchronized( s_haveReceiver ) {
@ -150,7 +175,7 @@ public class NetStateCache {
} }
@Override @Override
public void onReceive( final Context context, Intent intent ) public void onReceive( Context context, Intent intent )
{ {
DbgUtils.assertOnUIThread(); DbgUtils.assertOnUIThread();
@ -180,41 +205,7 @@ public class NetStateCache {
if ( s_netAvail != netAvail ) { if ( s_netAvail != netAvail ) {
s_netAvail = netAvail; // keep current in case we're asked s_netAvail = netAvail; // keep current in case we're asked
notifyStateChanged( context );
// We want to wait for WAIT_STABLE_MILLIS of inactivity
// before informing listeners. So each time there's a
// change, kill any existing timer then set another, which
// will only fire if we go that long without coming
// through here again.
if ( null != mNotifyLater ) {
mHandler.removeCallbacks( mNotifyLater );
mNotifyLater = null;
}
if ( mLastStateSent != s_netAvail ) {
mNotifyLater = new Runnable() {
@Override
public void run() {
Assert.assertTrue( mLastStateSent != s_netAvail );
mLastStateSent = s_netAvail;
synchronized( s_ifs ) {
Iterator<StateChangedIf> iter = s_ifs.iterator();
while ( iter.hasNext() ) {
iter.next().netAvail( s_netAvail );
}
}
if ( s_netAvail ) {
CommsConnType typ = CommsConnType
.COMMS_CONN_RELAY;
GameUtils.resendAllIf( context, typ,
false );
}
}
};
mHandler.postDelayed( mNotifyLater, WAIT_STABLE_MILLIS );
}
} else { } else {
DbgUtils.logdf( "NetStateCache.PvtBroadcastReceiver.onReceive:" DbgUtils.logdf( "NetStateCache.PvtBroadcastReceiver.onReceive:"
+ " no change; doing nothing; s_netAvail=%b", + " no change; doing nothing; s_netAvail=%b",
@ -222,6 +213,46 @@ public class NetStateCache {
} }
} }
} }
public void notifyStateChanged( final Context context )
{
// We want to wait for WAIT_STABLE_MILLIS of inactivity
// before informing listeners. So each time there's a
// change, kill any existing timer then set another, which
// will only fire if we go that long without coming
// through here again.
if ( null != mNotifyLater ) {
mHandler.removeCallbacks( mNotifyLater );
mNotifyLater = null;
}
if ( mLastStateSent != s_netAvail ) {
mNotifyLater = new Runnable() {
@Override
public void run() {
Assert.assertTrue( mLastStateSent != s_netAvail );
mLastStateSent = s_netAvail;
DbgUtils.logf( "NetStateCache.notifyStateChanged(%b)",
s_netAvail );
synchronized( s_ifs ) {
Iterator<StateChangedIf> iter = s_ifs.iterator();
while ( iter.hasNext() ) {
iter.next().netAvail( s_netAvail );
}
}
if ( s_netAvail ) {
CommsConnType typ = CommsConnType
.COMMS_CONN_RELAY;
GameUtils.resendAllIf( context, typ, false );
}
}
};
mHandler.postDelayed( mNotifyLater, WAIT_STABLE_MILLIS );
}
}
} // class PvtBroadcastReceiver } // class PvtBroadcastReceiver
} }

View file

@ -6,6 +6,9 @@ $(DEST_PATH)/%.java : $(SRC_PATH)/%.java
-e "s,\(import org.eehouse.android.\)xw4\(.*\);,\1$(VARIANT)\2;," \ -e "s,\(import org.eehouse.android.\)xw4\(.*\);,\1$(VARIANT)\2;," \
< $< > $@ < $< > $@
$(DEST_PATH)/icon48x48.png : $(SRC_PATH)/icon48x48.png
convert $< -fill red -gravity Center -annotate +0+5 ' Dbg ' $@
$(DEST_PATH)/%.png : $(SRC_PATH)/%.png $(DEST_PATH)/%.png : $(SRC_PATH)/%.png
@cp $< $@ @cp $< $@

View file

@ -94,9 +94,9 @@ dbg_logstream( const XWStreamCtxt* stream, const char* func, int line )
if ( !!stream ) { if ( !!stream ) {
XP_U16 len = 0; XP_U16 len = 0;
XWStreamPos end = stream_getPos( stream, POS_WRITE ); XWStreamPos end = stream_getPos( stream, POS_WRITE );
stream_copyBits( stream, 0, end, NULL, &len ); stream_copyBits( stream, end, NULL, &len );
XP_U8 buf[len]; XP_U8 buf[len];
stream_copyBits( stream, 0, end, buf, &len ); stream_copyBits( stream, end, buf, &len );
char comment[128]; char comment[128];
XP_SNPRINTF( comment, VSIZE(comment), "%s line %d", func, line ); XP_SNPRINTF( comment, VSIZE(comment), "%s line %d", func, line );
LOG_HEX( buf, len, comment ); LOG_HEX( buf, len, comment );

View file

@ -25,6 +25,7 @@
#include "comtypes.h" #include "comtypes.h"
#include "memstream.h" #include "memstream.h"
#include "vtabmgr.h" #include "vtabmgr.h"
#include "strutils.h"
#ifdef CPLUS #ifdef CPLUS
extern "C" { extern "C" {
@ -184,10 +185,10 @@ mem_stream_getBits( XWStreamCtxt* p_sctx, XP_U16 nBits )
return result; return result;
} /* stream_getBits */ } /* stream_getBits */
#if defined HASH_STREAM || defined DEBUG #if defined DEBUG
static void static void
mem_stream_copyBits( const XWStreamCtxt* p_sctx, XWStreamPos XP_UNUSED(startPos), mem_stream_copyBits( const XWStreamCtxt* p_sctx, XWStreamPos endPos,
XWStreamPos endPos, XP_U8* buf, XP_U16* lenp ) XP_U8* buf, XP_U16* lenp )
{ {
MemStreamCtxt* stream = (MemStreamCtxt*)p_sctx; MemStreamCtxt* stream = (MemStreamCtxt*)p_sctx;
XP_U16 len = BYTE_PART(endPos); XP_U16 len = BYTE_PART(endPos);
@ -195,7 +196,7 @@ mem_stream_copyBits( const XWStreamCtxt* p_sctx, XWStreamPos XP_UNUSED(startPos)
XP_ASSERT( len <= stream->nBytesAllocated ); XP_ASSERT( len <= stream->nBytesAllocated );
XP_MEMCPY( buf, stream->buf, len ); XP_MEMCPY( buf, stream->buf, len );
if ( 0 != BIT_PART(endPos) ) { if ( 0 != BIT_PART(endPos) ) {
buf[len-1] &= 1 << BIT_PART(endPos); buf[len-1] &= ~(0xFF << BIT_PART(endPos));
} }
} }
*lenp = len; *lenp = len;
@ -371,6 +372,36 @@ mem_stream_getSize( const XWStreamCtxt* p_sctx )
return size; return size;
} /* mem_stream_getSize */ } /* mem_stream_getSize */
static XP_U32
mem_stream_getHash( const XWStreamCtxt* p_sctx, XWStreamPos pos,
XP_Bool correct )
{
XP_U32 hash = 0;
const MemStreamCtxt* stream = (const MemStreamCtxt*)p_sctx;
const XP_U8* ptr = stream->buf;
XP_U16 len = BYTE_PART(pos);
XP_U16 bits = BIT_PART(pos);
if ( 0 != bits ) {
XP_ASSERT( 0 < len );
--len;
}
hash = augmentHash( 0, ptr, len );
if ( 0 != bits ) {
XP_U8 byt = ptr[len];
if ( correct ) {
byt &= ~(0xFF << bits);
} else {
byt &= 1 << bits;
}
hash = augmentHash( hash, &byt, 1 );
}
hash = finishHash( hash );
LOG_RETURNF( "%X(%d:%d)", hash, len, bits );
return hash;
} /* mem_stream_getHash */
static const XP_U8* static const XP_U8*
mem_stream_getPtr( const XWStreamCtxt* p_sctx ) mem_stream_getPtr( const XWStreamCtxt* p_sctx )
{ {
@ -476,7 +507,7 @@ make_vtable( MemStreamCtxt* stream )
SET_VTABLE_ENTRY( vtable, stream_getU16, mem ); SET_VTABLE_ENTRY( vtable, stream_getU16, mem );
SET_VTABLE_ENTRY( vtable, stream_getU32, mem ); SET_VTABLE_ENTRY( vtable, stream_getU32, mem );
SET_VTABLE_ENTRY( vtable, stream_getBits, mem ); SET_VTABLE_ENTRY( vtable, stream_getBits, mem );
#if defined HASH_STREAM || defined DEBUG #if defined DEBUG
SET_VTABLE_ENTRY( vtable, stream_copyBits, mem ); SET_VTABLE_ENTRY( vtable, stream_copyBits, mem );
#endif #endif
@ -497,6 +528,7 @@ make_vtable( MemStreamCtxt* stream )
SET_VTABLE_ENTRY( vtable, stream_close, mem ); SET_VTABLE_ENTRY( vtable, stream_close, mem );
SET_VTABLE_ENTRY( vtable, stream_getSize, mem ); SET_VTABLE_ENTRY( vtable, stream_getSize, mem );
SET_VTABLE_ENTRY( vtable, stream_getHash, mem );
SET_VTABLE_ENTRY( vtable, stream_getPtr, mem ); SET_VTABLE_ENTRY( vtable, stream_getPtr, mem );
SET_VTABLE_ENTRY( vtable, stream_getAddress, mem ); SET_VTABLE_ENTRY( vtable, stream_getAddress, mem );
SET_VTABLE_ENTRY( vtable, stream_setAddress, mem ); SET_VTABLE_ENTRY( vtable, stream_setAddress, mem );

View file

@ -1,6 +1,6 @@
/* -*- compile-command: "cd ../linux && make -j3 MEMDEBUG=TRUE"; -*- */ /* -*- compile-command: "cd ../linux && make -j3 MEMDEBUG=TRUE"; -*- */
/* /*
* Copyright 2000-2011 by Eric House (xwords@eehouse.org). All rights * Copyright 2000-2015 by Eric House (xwords@eehouse.org). All rights
* reserved. * reserved.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
@ -312,36 +312,67 @@ model_destroy( ModelCtxt* model )
} /* model_destroy */ } /* model_destroy */
XP_U32 XP_U32
model_getHash( const ModelCtxt* model, XP_U16 version ) model_getHash( const ModelCtxt* model )
{ {
#ifndef STREAM_VERS_HASHSTREAM #ifndef STREAM_VERS_HASHSTREAM
XP_USE(version); XP_USE(version);
#endif #endif
StackCtxt* stack = model->vol.stack; StackCtxt* stack = model->vol.stack;
XP_ASSERT( !!stack ); XP_ASSERT( !!stack );
XP_U32 hash = return stack_getHash( stack, XP_FALSE );
#ifdef STREAM_VERS_HASHSTREAM
STREAM_VERS_HASHSTREAM <= version ?
stack_getHash( stack ) :
#endif
stack_getHashOld( stack );
/* XP_LOGF( "%s(version=%x)=>%.8X", __func__, version, */
/* (unsigned int)hash ); */
return hash;
} }
XP_Bool XP_Bool
model_hashMatches( const ModelCtxt* model, const XP_U32 hash ) model_hashMatches( const ModelCtxt* model, const XP_U32 hash )
{ {
StackCtxt* stack = model->vol.stack; StackCtxt* stack = model->vol.stack;
XP_Bool matches = XP_Bool matches = hash == stack_getHash( stack, XP_TRUE )
#ifdef STREAM_VERS_HASHSTREAM || hash == stack_getHash( stack, XP_FALSE );
(hash == stack_getHash( stack )) ||
#endif
(hash == stack_getHashOld( stack ));
return matches; return matches;
} }
XP_Bool
model_popToHash( ModelCtxt* model, const XP_U32 hash, PoolContext* pool )
{
XP_U16 nPopped = 0;
StackCtxt* stack = model->vol.stack;
const XP_U16 nEntries = stack_getNEntries( stack );
StackEntry entries[nEntries];
XP_S16 foundAt = -1;
for ( XP_U16 ii = 0; ii < nEntries; ++ii ) {
if ( hash == stack_getHash( stack, XP_TRUE )
|| hash == stack_getHash( stack, XP_FALSE ) ) {
foundAt = ii;
break;
}
if ( ! stack_popEntry( stack, &entries[ii] ) ) {
break;
}
++nPopped;
}
for ( XP_S16 ii = nPopped - 1; ii >= 0; --ii ) {
stack_redo( stack, &entries[ii] );
}
XP_Bool found = -1 != foundAt;
if ( found ) {
XP_LOGF( "%s: undoing %d turns to match hash %X", __func__,
foundAt, hash );
#ifdef DEBUG
XP_Bool success =
#endif
model_undoLatestMoves( model, pool, foundAt, NULL, NULL );
XP_ASSERT( success );
/* Assert not needed for long */
XP_ASSERT( hash == stack_getHash( model->vol.stack, XP_TRUE )
|| hash == stack_getHash( model->vol.stack, XP_FALSE ) );
}
return found;
}
#ifdef STREAM_VERS_BIGBOARD #ifdef STREAM_VERS_BIGBOARD
void void
model_setSquareBonuses( ModelCtxt* model, XWBonusType* bonuses, XP_U16 nBonuses ) model_setSquareBonuses( ModelCtxt* model, XWBonusType* bonuses, XP_U16 nBonuses )

View file

@ -122,8 +122,11 @@ void model_writeToTextStream( const ModelCtxt* model, XWStreamCtxt* stream );
void model_setSize( ModelCtxt* model, XP_U16 boardSize ); void model_setSize( ModelCtxt* model, XP_U16 boardSize );
void model_destroy( ModelCtxt* model ); void model_destroy( ModelCtxt* model );
XP_U32 model_getHash( const ModelCtxt* model, XP_U16 version ); XP_U32 model_getHash( const ModelCtxt* model );
XP_Bool model_hashMatches( const ModelCtxt* model, XP_U32 hash ); XP_Bool model_hashMatches( const ModelCtxt* model, XP_U32 hash );
XP_Bool model_popToHash( ModelCtxt* model, const XP_U32 hash,
PoolContext* pool );
void model_setNPlayers( ModelCtxt* model, XP_U16 numPlayers ); void model_setNPlayers( ModelCtxt* model, XP_U16 numPlayers );
XP_U16 model_getNPlayers( const ModelCtxt* model ); XP_U16 model_getNPlayers( const ModelCtxt* model );

View file

@ -1,6 +1,6 @@
/* -*- compile-command: "cd ../linux && make -j3 MEMDEBUG=TRUE"; -*- */ /* -*- compile-command: "cd ../linux && make -j5 MEMDEBUG=TRUE"; -*- */
/* /*
* Copyright 2001, 2006-2012 by Eric House (xwords@eehouse.org). All rights * Copyright 2001-2015 by Eric House (xwords@eehouse.org). All rights
* reserved. * reserved.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
@ -67,88 +67,14 @@ stack_init( StackCtxt* stack )
shrunk to fit as soon as we serialize/deserialize anyway. */ shrunk to fit as soon as we serialize/deserialize anyway. */
} /* stack_init */ } /* stack_init */
static XP_U32
augmentHash( XP_U32 hash, const XP_U8* ptr, XP_U16 len )
{
XP_ASSERT( 0 < len );
// see http://en.wikipedia.org/wiki/Jenkins_hash_function
XP_U16 ii;
for ( ii = 0; ii < len; ++ii ) {
hash += *ptr++;
hash += (hash << 10);
hash ^= (hash >> 6);
}
// XP_LOGF( "%s: hashed %d bytes -> %X", __func__, len, (unsigned int)hash );
return hash;
}
static XP_U32
finishHash( XP_U32 hash )
{
hash += (hash << 3);
hash ^= (hash >> 11);
hash += (hash << 15);
return hash;
}
static XP_U32
augmentFor( XP_U32 hash, const StackEntry* entry )
{
switch( entry->moveType ) {
case ASSIGN_TYPE: {
TrayTileSet tiles;
sortTiles( &tiles, &entry->u.assign.tiles, 0 );
hash = augmentHash( hash, (XP_U8*)&tiles, sizeof(tiles) );
}
break;
case MOVE_TYPE:
hash = augmentHash( hash, (XP_U8*)&entry->u.move,
sizeof(entry->u.move) );
break;
case TRADE_TYPE:
hash = augmentHash( hash, (XP_U8*)&entry->u.trade,
sizeof(entry->u.trade) );
break;
case PHONY_TYPE:
hash = augmentHash( hash, (XP_U8*)&entry->u.phony,
sizeof(entry->u.phony) );
break;
}
return hash;
}
XP_U32
stack_getHashOld( StackCtxt* stack )
{
XP_U16 nn, nEntries = stack->nEntries;
XP_U32 hash = 0L;
for ( nn = 0; nn < nEntries; ++nn ) {
StackEntry entry;
XP_MEMSET( &entry, 0, sizeof(entry) );
if ( !stack_getNthEntry( stack, nn, &entry ) ) {
XP_ASSERT( 0 );
}
hash = augmentFor( hash, &entry );
// XP_LOGF( "hash after %d: %.8X", nn, (unsigned int)hash );
}
XP_ASSERT( 0 != hash );
hash = finishHash( hash );
LOG_RETURNF( "%.8X", (unsigned int)hash );
return hash;
} /* stack_getHashOld */
#ifdef STREAM_VERS_HASHSTREAM #ifdef STREAM_VERS_HASHSTREAM
XP_U32 XP_U32
stack_getHash( const StackCtxt* stack ) stack_getHash( const StackCtxt* stack, XP_Bool correct )
{ {
XP_U32 hash; XP_U32 hash = 0;
XP_U16 len = 0; if ( !!stack->data ) {
stream_copyBits( stack->data, 0, stack->top, NULL, &len ); hash = stream_getHash( stack->data, stack->top, correct );
XP_U8 buf[len]; }
stream_copyBits( stack->data, 0, stack->top, buf, &len );
// LOG_HEX( buf, len, __func__ );
hash = finishHash( augmentHash( 0L, buf, len ) );
// LOG_RETURNF( "%.8X", (unsigned int)hash );
return hash; return hash;
} /* stack_getHash */ } /* stack_getHash */
#endif #endif
@ -250,7 +176,7 @@ stack_copy( const StackCtxt* stack )
} }
static void static void
pushEntry( StackCtxt* stack, const StackEntry* entry ) pushEntryImpl( StackCtxt* stack, const StackEntry* entry )
{ {
XP_U16 ii, bitsPerTile; XP_U16 ii, bitsPerTile;
XWStreamPos oldLoc; XWStreamPos oldLoc;
@ -308,9 +234,33 @@ pushEntry( StackCtxt* stack, const StackEntry* entry )
++stack->nEntries; ++stack->nEntries;
stack->highWaterMark = stack->nEntries; stack->highWaterMark = stack->nEntries;
stack->top = stream_setPos( stream, POS_WRITE, oldLoc ); stack->top = stream_setPos( stream, POS_WRITE, oldLoc );
// XP_LOGSTREAM( stack->data ); #ifdef DEBUG_HASHING
XP_LOGSTREAM( stack->data );
#endif
SET_DIRTY( stack ); SET_DIRTY( stack );
} /* pushEntry */ } /* pushEntryImpl */
static void
pushEntry( StackCtxt* stack, const StackEntry* entry )
{
#ifdef DEBUG_HASHING
XP_Bool correct = XP_TRUE;
XP_U32 origHash = stack_getHash( stack, correct );
#endif
pushEntryImpl( stack, entry );
#ifdef DEBUG_HASHING
XP_U32 newHash = stack_getHash( stack, XP_TRUE );
StackEntry lastEntry;
if ( stack_popEntry( stack, &lastEntry ) ) {
XP_ASSERT( origHash == stack_getHash( stack, correct ) );
pushEntryImpl( stack, &lastEntry );
XP_ASSERT( newHash == stack_getHash( stack, correct ) );
XP_LOGF( "%s: all ok", __func__ );
}
#endif
}
static void static void
readEntry( const StackCtxt* stack, StackEntry* entry ) readEntry( const StackCtxt* stack, StackEntry* entry )
@ -482,7 +432,9 @@ stack_popEntry( StackCtxt* stack, StackEntry* entry )
setCacheReadyFor( stack, nn ); /* set cachedPos by side-effect */ setCacheReadyFor( stack, nn ); /* set cachedPos by side-effect */
stack->top = stack->cachedPos; stack->top = stack->cachedPos;
} }
// XP_LOGSTREAM( stack->data ); #ifdef DEBUG_HASHING
XP_LOGSTREAM( stack->data );
#endif
return found; return found;
} /* stack_popEntry */ } /* stack_popEntry */

View file

@ -69,8 +69,7 @@ StackCtxt* stack_make( MPFORMAL VTableMgr* vtmgr );
void stack_destroy( StackCtxt* stack ); void stack_destroy( StackCtxt* stack );
void stack_init( StackCtxt* stack ); void stack_init( StackCtxt* stack );
XP_U32 stack_getHashOld( StackCtxt* stack ); XP_U32 stack_getHash( const StackCtxt* stack, XP_Bool correct );
XP_U32 stack_getHash( const StackCtxt* stack );
void stack_setBitsPerTile( StackCtxt* stack, XP_U16 bitsPerTile ); void stack_setBitsPerTile( StackCtxt* stack, XP_U16 bitsPerTile );
void stack_loadFromStream( StackCtxt* stack, XWStreamCtxt* stream ); void stack_loadFromStream( StackCtxt* stack, XWStreamCtxt* stream );

View file

@ -2032,8 +2032,10 @@ sendMoveTo( ServerCtxt* server, XP_U16 devIndex, XP_U16 turn,
XP_U16 version = stream_getVersion( stream ); XP_U16 version = stream_getVersion( stream );
if ( STREAM_VERS_BIGBOARD <= version ) { if ( STREAM_VERS_BIGBOARD <= version ) {
XP_ASSERT( version == server->nv.streamVersion ); XP_ASSERT( version == server->nv.streamVersion );
XP_U32 hash = model_getHash( server->vol.model, version ); XP_U32 hash = model_getHash( server->vol.model );
// XP_LOGF( "%s: adding hash %x", __func__, (unsigned int)hash ); #ifdef DEBUG_HASHING
XP_LOGF( "%s: adding hash %x", __func__, (unsigned int)hash );
#endif
stream_putU32( stream, hash ); stream_putU32( stream, hash );
} }
#endif #endif
@ -2084,10 +2086,16 @@ readMoveInfo( ServerCtxt* server, XWStreamCtxt* stream,
#ifdef STREAM_VERS_BIGBOARD #ifdef STREAM_VERS_BIGBOARD
if ( STREAM_VERS_BIGBOARD <= stream_getVersion( stream ) ) { if ( STREAM_VERS_BIGBOARD <= stream_getVersion( stream ) ) {
XP_U32 hashReceived = stream_getU32( stream ); XP_U32 hashReceived = stream_getU32( stream );
success = model_hashMatches( server->vol.model, hashReceived ); success = model_hashMatches( server->vol.model, hashReceived )
if ( !success ) { || model_popToHash( server->vol.model, hashReceived, server->pool );
XP_LOGF( "%s: hash mismatch",__func__); // XP_ASSERT( success ); /* I need to understand when this can fail */
#ifdef DEBUG_HASHING
if ( success ) {
XP_LOGF( "%s: hash match: %X",__func__, hashReceived );
} else {
XP_LOGF( "%s: hash mismatch: %X not found",__func__, hashReceived );
} }
#endif
} }
#endif #endif
if ( success ) { if ( success ) {

View file

@ -228,6 +228,30 @@ p_replaceStringIfDifferent( MPFORMAL XP_UCHAR** curLoc, const XP_UCHAR* newStr
*curLoc = curStr; *curLoc = curStr;
} /* replaceStringIfDifferent */ } /* replaceStringIfDifferent */
XP_U32
augmentHash( XP_U32 hash, const XP_U8* ptr, XP_U16 len )
{
// see http://en.wikipedia.org/wiki/Jenkins_hash_function
for ( XP_U16 ii = 0; ii < len; ++ii ) {
hash += *ptr++;
hash += (hash << 10);
hash ^= (hash >> 6);
}
#ifdef DEBUG_HASHING
XP_LOGF( "%s: hashed %d bytes -> %X", __func__, len, (unsigned int)hash );
#endif
return hash;
}
XP_U32
finishHash( XP_U32 hash )
{
hash += (hash << 3);
hash ^= (hash >> 11);
hash += (hash << 15);
return hash;
}
/* /*
* A wrapper for printing etc. potentially null strings. * A wrapper for printing etc. potentially null strings.
*/ */

View file

@ -68,6 +68,8 @@ XP_UCHAR* p_copyString( MPFORMAL const XP_UCHAR* instr
# define copyString( p, in ) p_copyString( in ) # define copyString( p, in ) p_copyString( in )
#endif #endif
XP_U32 augmentHash( XP_U32 hash, const XP_U8* ptr, XP_U16 len );
XP_U32 finishHash( XP_U32 hash );
void p_replaceStringIfDifferent( MPFORMAL XP_UCHAR** curLoc, void p_replaceStringIfDifferent( MPFORMAL XP_UCHAR** curLoc,
const XP_UCHAR* newStr const XP_UCHAR* newStr

View file

@ -1,6 +1,7 @@
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */ /* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */
/* /*
* Copyright 1997 - 2000 by Eric House (xwords@eehouse.org). All rights reserved. * Copyright 1997 - 2015 by Eric House (xwords@eehouse.org). All rights
* reserved.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -48,9 +49,9 @@ typedef struct StreamCtxVTable {
XP_U16 (*m_stream_getU16)( XWStreamCtxt* dctx ); XP_U16 (*m_stream_getU16)( XWStreamCtxt* dctx );
XP_U32 (*m_stream_getU32)( XWStreamCtxt* dctx ); XP_U32 (*m_stream_getU32)( XWStreamCtxt* dctx );
XP_U32 (*m_stream_getBits)( XWStreamCtxt* dctx, XP_U16 nBits ); XP_U32 (*m_stream_getBits)( XWStreamCtxt* dctx, XP_U16 nBits );
#if defined HASH_STREAM || defined DEBUG #if defined DEBUG
void (*m_stream_copyBits)( const XWStreamCtxt* dctx, XWStreamPos startPos, void (*m_stream_copyBits)( const XWStreamCtxt* dctx, XWStreamPos endPos,
XWStreamPos endPos, XP_U8* buf, XP_U16* len ); XP_U8* buf, XP_U16* len );
#endif #endif
void (*m_stream_putU8)( XWStreamCtxt* dctx, XP_U8 byt ); void (*m_stream_putU8)( XWStreamCtxt* dctx, XP_U8 byt );
@ -73,6 +74,8 @@ typedef struct StreamCtxVTable {
void (*m_stream_close)( XWStreamCtxt* dctx ); void (*m_stream_close)( XWStreamCtxt* dctx );
XP_U16 (*m_stream_getSize)( const XWStreamCtxt* dctx ); XP_U16 (*m_stream_getSize)( const XWStreamCtxt* dctx );
XP_U32 (*m_stream_getHash)( const XWStreamCtxt* dctx, XWStreamPos pos,
XP_Bool correct );
const XP_U8* (*m_stream_getPtr)( const XWStreamCtxt* dctx ); const XP_U8* (*m_stream_getPtr)( const XWStreamCtxt* dctx );
@ -113,9 +116,9 @@ struct XWStreamCtxt {
#define stream_getBits(sc, n) \ #define stream_getBits(sc, n) \
(sc)->vtable->m_stream_getBits((sc), (n)) (sc)->vtable->m_stream_getBits((sc), (n))
#if defined HASH_STREAM || defined DEBUG #if defined DEBUG
#define stream_copyBits(sc, s, e, b, l) \ #define stream_copyBits(sc, e, b, l) \
(sc)->vtable->m_stream_copyBits((sc), (s), (e), (b), (l)) (sc)->vtable->m_stream_copyBits((sc), (e), (b), (l))
#endif #endif
#define stream_putU8(sc, b) \ #define stream_putU8(sc, b) \
@ -154,6 +157,9 @@ struct XWStreamCtxt {
#define stream_getSize(sc) \ #define stream_getSize(sc) \
(sc)->vtable->m_stream_getSize((sc)) (sc)->vtable->m_stream_getSize((sc))
#define stream_getHash(sc, p, c) \
(sc)->vtable->m_stream_getHash((sc), (p), (c))
#define stream_getPtr(sc) \ #define stream_getPtr(sc) \
(sc)->vtable->m_stream_getPtr((sc)) (sc)->vtable->m_stream_getPtr((sc))

View file

@ -0,0 +1,32 @@
# -*-mode: Makefile -*-
# Copyright 2002 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.
XWLANG=ODS7
LANGCODE=fr_FR
TARGET_TYPE ?= WINCE
include ../Makefile.langcommon
$(XWLANG)Main.dict.gz: $(XWDICTPATH)/French/ods7.txt
cat $< | tr -d '\r' | tr a-z A-Z | grep '^[A-Z]*$$' | gzip >$@
# Everything but creating of the Main.dict file is inherited from the
# "parent" Makefile.langcommon in the parent directory.
clean: clean_common
rm -f $(XWLANG)Main.dict.gz *.bin $(XWLANG)*.pdb $(XWLANG)*.seb

View file

@ -22,6 +22,7 @@ ifeq ($(MEMDEBUG),TRUE)
DEFINES = -DMEM_DEBUG -DDEBUG -DENABLE_LOGGING -DNUMBER_KEY_AS_INDEX DEFINES = -DMEM_DEBUG -DDEBUG -DENABLE_LOGGING -DNUMBER_KEY_AS_INDEX
DEFINES += -DCOMMS_CHECKSUM DEFINES += -DCOMMS_CHECKSUM
CFLAGS += -g $(GPROFFLAG) -Wall -Wunused-parameter -Wcast-align -Werror -O0 CFLAGS += -g $(GPROFFLAG) -Wall -Wunused-parameter -Wcast-align -Werror -O0
# DEFINES += -DDEBUG_HASHING
CFLAGS += -DDEBUG_TS -rdynamic CFLAGS += -DDEBUG_TS -rdynamic
PLATFORM = obj_linux_memdbg PLATFORM = obj_linux_memdbg
else else
@ -119,7 +120,7 @@ DEFINES += -DXWFEATURE_DEVID
DEFINES += -DXWFEATURE_COMMSACK DEFINES += -DXWFEATURE_COMMSACK
#DEFINES += -DXWFEATURE_ACTIVERECT #DEFINES += -DXWFEATURE_ACTIVERECT
DEFINES += -DCOMMS_XPORT_FLAGSPROC DEFINES += -DCOMMS_XPORT_FLAGSPROC
DEFINES += -DINITIAL_CLIENT_VERS=2 DEFINES += -DINITIAL_CLIENT_VERS=3
DEFINES += -DCOMMON_LAYOUT DEFINES += -DCOMMON_LAYOUT
DEFINES += -DNATIVE_NLI DEFINES += -DNATIVE_NLI

View file

@ -554,7 +554,7 @@ secondTimerFired( gpointer data )
if ( !!game->server && !!game->board ) { if ( !!game->server && !!game->board ) {
XP_U16 undoRatio = cGlobals->params->undoRatio; XP_U16 undoRatio = cGlobals->params->undoRatio;
if ( 0 != undoRatio ) { if ( 0 != undoRatio ) {
if ( (XP_RANDOM() % 100) < undoRatio ) { if ( (XP_RANDOM() % 1000) < undoRatio ) {
XP_LOGF( "%s: calling server_handleUndo", __func__ ); XP_LOGF( "%s: calling server_handleUndo", __func__ );
if ( server_handleUndo( game->server, 1 ) ) { if ( server_handleUndo( game->server, 1 ) ) {
board_draw( game->board ); board_draw( game->board );
@ -2443,8 +2443,8 @@ main( int argc, char** argv )
#ifdef USE_GLIBLOOP #ifdef USE_GLIBLOOP
case CMD_UNDOPCT: case CMD_UNDOPCT:
mainParams.undoRatio = atoi( optarg ); mainParams.undoRatio = atoi( optarg );
if ( mainParams.undoRatio < 0 || mainParams.undoRatio > 100 ) { if ( mainParams.undoRatio < 0 || mainParams.undoRatio > 1000 ) {
usage(argv[0], "must be 0 <= n <= 100" ); usage(argv[0], "must be 0 <= n <= 1000" );
} }
break; break;
#endif #endif

View file

@ -6,7 +6,7 @@ APP_NEW=""
DO_CLEAN="" DO_CLEAN=""
APP_NEW_PARAMS="" APP_NEW_PARAMS=""
NGAMES="" NGAMES=""
UDP_PCT_START=5 UDP_PCT_START=100
UDP_PCT_INCR=10 UDP_PCT_INCR=10
UPGRADE_ODDS="" UPGRADE_ODDS=""
NROOMS="" NROOMS=""
@ -68,7 +68,7 @@ function cleanup() {
function connName() { function connName() {
LOG=$1 LOG=$1
grep 'got_connect_cmd: connName' $LOG | \ grep -a 'got_connect_cmd: connName' $LOG | \
tail -n 1 | \ tail -n 1 | \
sed 's,^.*connName: \"\(.*\)\" (reconnect=.)$,\1,' sed 's,^.*connName: \"\(.*\)\" (reconnect=.)$,\1,'
} }
@ -356,7 +356,7 @@ maybe_resign() {
if [ "$RESIGN_RATIO" -gt 0 ]; then if [ "$RESIGN_RATIO" -gt 0 ]; then
KEY=$1 KEY=$1
LOG=${LOGS[$KEY]} LOG=${LOGS[$KEY]}
if grep -q XWRELAY_ALLHERE $LOG; then if grep -aq XWRELAY_ALLHERE $LOG; then
if [ 0 -eq $(($RANDOM % $RESIGN_RATIO)) ]; then if [ 0 -eq $(($RANDOM % $RESIGN_RATIO)) ]; then
echo "making $LOG $(connName $LOG) resign..." echo "making $LOG $(connName $LOG) resign..."
kill_from_log $LOG && close_device $KEY $DEADDIR "resignation forced" || /bin/true kill_from_log $LOG && close_device $KEY $DEADDIR "resignation forced" || /bin/true
@ -397,14 +397,13 @@ check_game() {
CONNNAME="$(connName $LOG)" CONNNAME="$(connName $LOG)"
OTHERS="" OTHERS=""
if [ -n "$CONNNAME" ]; then if [ -n "$CONNNAME" ]; then
if grep -q '\[unused tiles\]' $LOG; then if grep -aq '\[unused tiles\]' $LOG ; then
ALL_DONE=TRUE
for INDX in ${!LOGS[*]}; do for INDX in ${!LOGS[*]}; do
[ $INDX -eq $KEY ] && continue [ $INDX -eq $KEY ] && continue
ALOG=${LOGS[$INDX]} ALOG=${LOGS[$INDX]}
CONNNAME2="$(connName $ALOG)" CONNNAME2="$(connName $ALOG)"
if [ "$CONNNAME2" = "$CONNNAME" ]; then if [ "$CONNNAME2" = "$CONNNAME" ]; then
if ! grep -q '\[unused tiles\]' $ALOG; then if ! grep -aq '\[unused tiles\]' $ALOG; then
OTHERS="" OTHERS=""
break break
fi fi
@ -424,11 +423,11 @@ check_game() {
done done
echo "" echo ""
# XWRELAY_ERROR_DELETED may be old # XWRELAY_ERROR_DELETED may be old
elif grep -q 'relay_error_curses(XWRELAY_ERROR_DELETED)' $LOG; then elif grep -aq 'relay_error_curses(XWRELAY_ERROR_DELETED)' $LOG; then
echo "deleting $LOG $(connName $LOG) b/c another resigned" echo "deleting $LOG $(connName $LOG) b/c another resigned"
kill_from_log $LOG || /bin/true kill_from_log $LOG || /bin/true
close_device $KEY $DEADDIR "other resigned" close_device $KEY $DEADDIR "other resigned"
elif grep -q 'relay_error_curses(XWRELAY_ERROR_DEADGAME)' $LOG; then elif grep -aq 'relay_error_curses(XWRELAY_ERROR_DEADGAME)' $LOG; then
echo "deleting $LOG $(connName $LOG) b/c another resigned" echo "deleting $LOG $(connName $LOG) b/c another resigned"
kill_from_log $LOG || /bin/true kill_from_log $LOG || /bin/true
close_device $KEY $DEADDIR "other resigned" close_device $KEY $DEADDIR "other resigned"
@ -474,7 +473,7 @@ summarizeTileCounts() {
for KEY in ${KEYS[@]}; do for KEY in ${KEYS[@]}; do
local LOG=${LOGS[$KEY]} local LOG=${LOGS[$KEY]}
local LINE=$(grep pool_removeTiles $LOG | tail -n 1) local LINE=$(grep -a pool_removeTiles $LOG | tail -n 1)
if [ -n "$LINE" ]; then if [ -n "$LINE" ]; then
local NUM=$(echo $LINE | sed 's,^.*removeTiles: \(.*\) tiles.*$,\1,') local NUM=$(echo $LINE | sed 's,^.*removeTiles: \(.*\) tiles.*$,\1,')
STR="${STR} ${KEY}:${NUM}" STR="${STR} ${KEY}:${NUM}"
@ -482,7 +481,7 @@ summarizeTileCounts() {
done done
if [ -n "${STR}" ]; then if [ -n "${STR}" ]; then
echo "$(date +%r) tiles left: $STR" echo "** $(date +%r) tiles left: $STR"
fi fi
} }
@ -613,7 +612,7 @@ function usage() {
echo " [--seed <int>] \\" >&2 echo " [--seed <int>] \\" >&2
echo " [--send-chat <interval-in-seconds> \\" >&2 echo " [--send-chat <interval-in-seconds> \\" >&2
echo " [--udp-incr <pct>] \\" >&2 echo " [--udp-incr <pct>] \\" >&2
echo " [--udp-start <pct>] \\" >&2 echo " [--udp-start <pct>] # default: $UDP_PCT_START \\" >&2
echo " [--undo-pct <int>] \\" >&2 echo " [--undo-pct <int>] \\" >&2
exit 1 exit 1