rough implementation of creating and inviting a known player

Followed the way rematch works. Which is gross. Eventually the two
paths (invitee and rematch) should be unified with rematch getting a lot
simpler.)
This commit is contained in:
Eric House 2020-09-21 20:27:03 -07:00
parent b8c588e02c
commit fc05612b74
9 changed files with 315 additions and 48 deletions

View file

@ -530,6 +530,8 @@ public class BoardDelegate extends DelegateBase
Assert.assertTrue( 0 < state.nMissing ); Assert.assertTrue( 0 < state.nMissing );
if ( state.summary.hasRematchInfo() ) { if ( state.summary.hasRematchInfo() ) {
tryRematchInvites( true ); tryRematchInvites( true );
} else if ( state.summary.hasInviteInfo() ) {
tryOtherInvites( true );
} else { } else {
callInviteChoices( sentInfo[0] ); callInviteChoices( sentInfo[0] );
} }
@ -1770,6 +1772,8 @@ public class BoardDelegate extends DelegateBase
} else if ( nMissing > 0 ) { } else if ( nMissing > 0 ) {
if ( m_summary.hasRematchInfo() ) { if ( m_summary.hasRematchInfo() ) {
skipDismiss = !tryRematchInvites( false ); skipDismiss = !tryRematchInvites( false );
} else if ( m_summary.hasInviteInfo() ) {
skipDismiss = !tryOtherInvites( false );
} else if ( !m_haveInvited ) { } else if ( !m_haveInvited ) {
m_haveInvited = true; m_haveInvited = true;
showInviteAlertIf(); showInviteAlertIf();
@ -2770,6 +2774,8 @@ public class BoardDelegate extends DelegateBase
{ {
if ( 0 < m_mySIS.nMissing && m_summary.hasRematchInfo() ) { if ( 0 < m_mySIS.nMissing && m_summary.hasRematchInfo() ) {
tryRematchInvites( false ); tryRematchInvites( false );
} else if ( 0 < m_mySIS.nMissing && m_summary.hasInviteInfo() ) {
tryOtherInvites( false );
} else if ( null != m_missingDevs ) { } else if ( null != m_missingDevs ) {
Assert.assertNotNull( m_missingMeans ); Assert.assertNotNull( m_missingMeans );
String gameName = GameUtils.getName( m_activity, m_rowid ); String gameName = GameUtils.getName( m_activity, m_rowid );
@ -3136,6 +3142,15 @@ public class BoardDelegate extends DelegateBase
} }
} }
private NetLaunchInfo nliForMe()
{
int numHere = 1;
int forceChannel = 1;
NetLaunchInfo nli = new NetLaunchInfo( m_activity, m_summary, m_gi,
numHere, forceChannel );
return nli;
}
// Return true if anything sent // Return true if anything sent
private boolean tryRematchInvites( boolean force ) private boolean tryRematchInvites( boolean force )
{ {
@ -3148,10 +3163,7 @@ public class BoardDelegate extends DelegateBase
Assert.assertNotNull( m_summary ); Assert.assertNotNull( m_summary );
Assert.assertNotNull( m_gi ); Assert.assertNotNull( m_gi );
// only supports a single invite for now! // only supports a single invite for now!
int numHere = 1; NetLaunchInfo nli = nliForMe();
int forceChannel = 1;
NetLaunchInfo nli = new NetLaunchInfo( m_activity, m_summary, m_gi,
numHere, forceChannel );
String value; String value;
value = m_summary.getStringExtra( GameSummary.EXTRA_REMATCH_PHONE ); value = m_summary.getStringExtra( GameSummary.EXTRA_REMATCH_PHONE );
@ -3184,6 +3196,47 @@ public class BoardDelegate extends DelegateBase
return force; return force;
} }
private boolean tryOtherInvites( boolean force )
{
boolean result = true;
Assert.assertNotNull( m_summary );
Assert.assertNotNull( m_gi );
String str64 = m_summary.getStringExtra( GameSummary.EXTRA_REMATCH_ADDR );
try {
CommsAddrRec addr = (CommsAddrRec)Utils.string64ToSerializable( str64 );
NetLaunchInfo nli = nliForMe();
CommsConnTypeSet conTypes = addr.conTypes;
for ( CommsConnType typ : conTypes ) {
switch ( typ ) {
case COMMS_CONN_MQTT:
MQTTUtils.inviteRemote( m_activity, addr.mqtt_devID, nli );
recordInviteSent( InviteMeans.MQTT, addr.mqtt_devID );
break;
case COMMS_CONN_BT:
BTService.inviteRemote( m_activity, addr.bt_btAddr, nli );
recordInviteSent( InviteMeans.BLUETOOTH, addr.bt_btAddr );
break;
// case COMMS_CONN_RELAY:
// RelayService.inviteRemote( m_activity, m_jniGamePtr, 0, value, nli );
// recordInviteSent( InviteMeans.RELAY );
// break;
case COMMS_CONN_SMS:
sendNBSInviteIf( addr.sms_phone, nli, true );
recordInviteSent( InviteMeans.SMS_DATA, addr.sms_phone );
break;
default:
Log.d( TAG, "not inviting using addr type %s", typ );
}
}
} catch ( Exception ex ) {
Log.ex( TAG, ex );
Assert.failDbg();
result = false;
}
return result;
}
private void sendNBSInviteIf( String phone, NetLaunchInfo nli, private void sendNBSInviteIf( String phone, NetLaunchInfo nli,
boolean askOk ) boolean askOk )
{ {

View file

@ -38,6 +38,7 @@ import android.text.TextUtils;
import org.eehouse.android.xw4.DBHelper.TABLE_NAMES; import org.eehouse.android.xw4.DBHelper.TABLE_NAMES;
import org.eehouse.android.xw4.DictUtils.DictLoc; import org.eehouse.android.xw4.DictUtils.DictLoc;
import org.eehouse.android.xw4.DlgDelegate.DlgClickNotify.InviteMeans; import org.eehouse.android.xw4.DlgDelegate.DlgClickNotify.InviteMeans;
import org.eehouse.android.xw4.jni.CommsAddrRec;
import org.eehouse.android.xw4.jni.CommsAddrRec.CommsConnType; import org.eehouse.android.xw4.jni.CommsAddrRec.CommsConnType;
import org.eehouse.android.xw4.jni.CommsAddrRec.CommsConnTypeSet; import org.eehouse.android.xw4.jni.CommsAddrRec.CommsConnTypeSet;
import org.eehouse.android.xw4.jni.CurGameInfo; import org.eehouse.android.xw4.jni.CurGameInfo;
@ -369,6 +370,22 @@ public class DBUtils {
} }
} // saveSummary } // saveSummary
public static void addRematchInfo( Context context, long rowid, CommsAddrRec addr )
{
try ( GameLock lock = GameLock.tryLock(rowid) ) {
if ( null != lock ) {
String as64 = Utils.serializableToString64( addr );
GameSummary summary = getSummary( context, lock )
.putStringExtra( GameSummary.EXTRA_REMATCH_ADDR, as64 )
;
saveSummary( context, lock, summary );
} else {
Assert.failDbg();
Log.e( TAG, "addRematchInfo(%d): unable to lock game" );
}
}
}
public static void addRematchInfo( Context context, long rowid, String btAddr, public static void addRematchInfo( Context context, long rowid, String btAddr,
String phone, String relayID, String p2pAddr, String phone, String relayID, String p2pAddr,
String mqttDevID ) String mqttDevID )

View file

@ -62,6 +62,7 @@ import org.eehouse.android.xw4.jni.CommsAddrRec;
import org.eehouse.android.xw4.jni.CurGameInfo; import org.eehouse.android.xw4.jni.CurGameInfo;
import org.eehouse.android.xw4.jni.GameSummary; import org.eehouse.android.xw4.jni.GameSummary;
import org.eehouse.android.xw4.jni.LastMoveInfo; import org.eehouse.android.xw4.jni.LastMoveInfo;
import org.eehouse.android.xw4.jni.XwJNI;
import org.eehouse.android.xw4.loc.LocUtils; import org.eehouse.android.xw4.loc.LocUtils;
import java.io.File; import java.io.File;
@ -89,6 +90,7 @@ public class GamesListDelegate extends ListDelegateBase
private static final String RELAYIDS_EXTRA = "relayids"; private static final String RELAYIDS_EXTRA = "relayids";
private static final String ROWID_EXTRA = "rowid"; private static final String ROWID_EXTRA = "rowid";
private static final String GAMEID_EXTRA = "gameid"; private static final String GAMEID_EXTRA = "gameid";
private static final String INVITEE_REC_EXTRA = "invitee_rec";
private static final String REMATCH_ROWID_EXTRA = "rm_rowid"; private static final String REMATCH_ROWID_EXTRA = "rm_rowid";
private static final String REMATCH_GROUPID_EXTRA = "rm_groupid"; private static final String REMATCH_GROUPID_EXTRA = "rm_groupid";
private static final String REMATCH_DICT_EXTRA = "rm_dict"; private static final String REMATCH_DICT_EXTRA = "rm_dict";
@ -864,49 +866,14 @@ public class GamesListDelegate extends ListDelegateBase
} }
break; break;
case GAMES_LIST_NEWGAME: { case GAMES_LIST_NEWGAME:
boolean solo = (Boolean)params[0]; boolean solo = (Boolean)params[0];
final LinearLayout view = (LinearLayout) boolean forceConfig = 2 <= params.length && (Boolean)params[1];
LocUtils.inflate( m_activity, R.layout.msg_label_and_edit ); if ( !solo && !forceConfig && XwJNI.hasKnownPlayers() ) {
final EditWClear edit = (EditWClear)view.findViewById( R.id.edit ); dialog = mkNewWithKnowns();
edit.setText( GameUtils.makeDefaultName( m_activity ) ); } else {
dialog = mkNewGameDialog( solo );
boolean canDoDefaults = solo ||
0 < XWPrefs.getAddrTypes( m_activity ).size();
int iconResID = solo ? R.drawable.ic_sologame : R.drawable.ic_multigame;
int titleID = solo ? R.string.new_game : R.string.new_game_networked;
String msg = getString( canDoDefaults ? R.string.new_game_message
: R.string.new_game_message_nodflt );
if ( !solo ) {
msg += "\n\n" + getString( R.string.new_game_message_net );
} }
TextView tmpEdit = (TextView)view.findViewById( R.id.msg );
tmpEdit.setText( msg );
lstnr = new OnClickListener() {
public void onClick( DialogInterface dlg, int item ) {
String name = edit.getText().toString();
curThis().makeThenLaunchOrConfigure( name, true, false );
}
};
ab = makeAlertBuilder()
.setView( view )
.setTitle( titleID )
.setIcon( iconResID )
.setPositiveButton( R.string.newgame_configure_first, lstnr );
if ( canDoDefaults ) {
lstnr2 = new OnClickListener() {
public void onClick( DialogInterface dlg, int item ) {
String name = edit.getText().toString();
curThis().makeThenLaunchOrConfigure( name, false, false );
}
};
ab.setNegativeButton( R.string.use_defaults, lstnr2 );
}
dialog = ab.create();
}
break; break;
case GAMES_LIST_NAME_REMATCH: { case GAMES_LIST_NAME_REMATCH: {
@ -916,7 +883,7 @@ public class GamesListDelegate extends ListDelegateBase
if ( null != m_rematchExtras ) { if ( null != m_rematchExtras ) {
EditWClear edit = (EditWClear)view.findViewById( R.id.edit ); EditWClear edit = (EditWClear)view.findViewById( R.id.edit );
edit.setText( m_rematchExtras.getString( REMATCH_NEWNAME_EXTRA )); edit.setText( m_rematchExtras.getString( REMATCH_NEWNAME_EXTRA ));
boolean solo = m_rematchExtras.getBoolean( REMATCH_IS_SOLO, true ); solo = m_rematchExtras.getBoolean( REMATCH_IS_SOLO, true );
if ( !solo ) { if ( !solo ) {
iconResID = R.drawable.ic_multigame; iconResID = R.drawable.ic_multigame;
} }
@ -947,6 +914,81 @@ public class GamesListDelegate extends ListDelegateBase
return dialog; return dialog;
} // makeDialog } // makeDialog
private Dialog mkNewGameDialog( boolean solo )
{
final LinearLayout view = (LinearLayout)
LocUtils.inflate( m_activity, R.layout.msg_label_and_edit );
final EditWClear edit = (EditWClear)view.findViewById( R.id.edit );
edit.setText( GameUtils.makeDefaultName( m_activity ) );
boolean canDoDefaults = solo ||
0 < XWPrefs.getAddrTypes( m_activity ).size();
int iconResID = solo ? R.drawable.ic_sologame : R.drawable.ic_multigame;
int titleID = solo ? R.string.new_game : R.string.new_game_networked;
String msg = getString( canDoDefaults ? R.string.new_game_message
: R.string.new_game_message_nodflt );
if ( !solo ) {
msg += "\n\n" + getString( R.string.new_game_message_net );
}
TextView tmpEdit = (TextView)view.findViewById( R.id.msg );
tmpEdit.setText( msg );
OnClickListener lstnr = new OnClickListener() {
public void onClick( DialogInterface dlg, int item ) {
String name = edit.getText().toString();
curThis().makeThenLaunchOrConfigure( name, true, false );
}
};
AlertDialog.Builder ab = makeAlertBuilder()
.setView( view )
.setTitle( titleID )
.setIcon( iconResID )
.setPositiveButton( R.string.newgame_configure_first, lstnr );
if ( canDoDefaults ) {
OnClickListener lstnr2 = new OnClickListener() {
public void onClick( DialogInterface dlg, int item ) {
String name = edit.getText().toString();
curThis().makeThenLaunchOrConfigure( name, false, false );
}
};
ab.setNegativeButton( R.string.use_defaults, lstnr2 );
}
return ab.create();
}
private Dialog mkNewWithKnowns()
{
String[] names = XwJNI.kplr_getPlayers();
final NewWithKnowns view = (NewWithKnowns)
LocUtils.inflate( m_activity, R.layout.new_game_with_knowns );
view.setNames( names, GameUtils.makeDefaultName( m_activity ) );
AlertDialog.Builder ab = makeAlertBuilder()
.setView( view )
.setTitle( R.string.new_game_networked )
.setIcon( R.drawable.ic_multigame )
.setPositiveButton( "Play Now", new OnClickListener() {
@Override
public void onClick( DialogInterface dlg, int item ) {
String player = view.getSelPlayer();
CommsAddrRec rec = XwJNI.kplr_getAddr( player );
String gameName = view.gameName();
launchLikeRematch( rec, gameName );
}
} )
.setNegativeButton( "Configure First", new OnClickListener() {
@Override
public void onClick( DialogInterface dlg, int item ) {
String name = view.gameName();
curThis().makeThenLaunchOrConfigure( name, true, false );
}
} )
;
return ab.create();
}
private void enableMoveGroupButton( DialogInterface dlgi ) private void enableMoveGroupButton( DialogInterface dlgi )
{ {
((AlertDialog)dlgi) ((AlertDialog)dlgi)
@ -2332,6 +2374,22 @@ public class GamesListDelegate extends ListDelegateBase
return result; return result;
} }
private boolean startWithInvitee( Intent intent )
{
boolean result = false;
try {
CommsAddrRec rec = (CommsAddrRec)intent.getSerializableExtra( INVITEE_REC_EXTRA );
if ( null != rec ) {
String name = intent.getStringExtra( REMATCH_NEWNAME_EXTRA );
makeThenLaunchOrConfigure( name, false, false, rec );
}
} catch ( Exception ex ) {
Log.ex( TAG, ex );
}
return result;
}
private boolean startNewNetGame( NetLaunchInfo nli ) private boolean startNewNetGame( NetLaunchInfo nli )
{ {
boolean handled = false; boolean handled = false;
@ -2749,6 +2807,7 @@ public class GamesListDelegate extends ListDelegateBase
{ {
Log.d( TAG, "tryStartsFromIntent(extras={%s})", DbgUtils.extrasToString( intent ) ); Log.d( TAG, "tryStartsFromIntent(extras={%s})", DbgUtils.extrasToString( intent ) );
boolean handled = startFirstHasDict( intent ) boolean handled = startFirstHasDict( intent )
|| startWithInvitee( intent )
|| startNewNetGame( intent ) || startNewNetGame( intent )
|| startHasGameID( intent ) || startHasGameID( intent )
|| startRematch( intent ) || startRematch( intent )
@ -2890,6 +2949,12 @@ public class GamesListDelegate extends ListDelegateBase
private void makeThenLaunchOrConfigure( String name, boolean doConfigure, private void makeThenLaunchOrConfigure( String name, boolean doConfigure,
boolean skipAsk ) boolean skipAsk )
{
makeThenLaunchOrConfigure( name, doConfigure, skipAsk, null );
}
private void makeThenLaunchOrConfigure( String name, boolean doConfigure,
boolean skipAsk, CommsAddrRec rec )
{ {
if ( skipAsk || !askingChangeName( name, doConfigure ) ) { if ( skipAsk || !askingChangeName( name, doConfigure ) ) {
long rowID; long rowID;
@ -2906,6 +2971,10 @@ public class GamesListDelegate extends ListDelegateBase
rowID = GameUtils.makeNewMultiGame( m_activity, groupID, name ); rowID = GameUtils.makeNewMultiGame( m_activity, groupID, name );
} }
if ( null != rec ) {
DBUtils.addRematchInfo( m_activity, rowID, rec );
}
if ( doConfigure ) { if ( doConfigure ) {
// configure it // configure it
GameConfigDelegate.editForResult( getDelegator(), GameConfigDelegate.editForResult( getDelegator(),
@ -2963,6 +3032,15 @@ public class GamesListDelegate extends ListDelegateBase
return intent; return intent;
} }
private void launchLikeRematch( CommsAddrRec rec, String name )
{
Intent intent = makeSelfIntent( m_activity )
.putExtra( INVITEE_REC_EXTRA, (Serializable)rec )
.putExtra( REMATCH_NEWNAME_EXTRA, name )
;
startActivity( intent );
}
public static Intent makeRematchIntent( Context context, long rowid, public static Intent makeRematchIntent( Context context, long rowid,
long groupID, CurGameInfo gi, long groupID, CurGameInfo gi,
CommsConnTypeSet addrTypes, CommsConnTypeSet addrTypes,

View file

@ -0,0 +1,61 @@
/* -*- compile-command: "find-and-gradle.sh inXw4dDeb"; -*- */
/*
* Copyright 2020 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.
*/
package org.eehouse.android.xw4;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.Spinner;
public class NewWithKnowns extends LinearLayout {
public NewWithKnowns( Context cx, AttributeSet as )
{
super( cx, as );
}
void setNames( String[] knowns, String gameName )
{
final ArrayAdapter<String> adapter =
new ArrayAdapter<>( getContext(), android.R.layout.simple_spinner_item );
for ( String msg : knowns ) {
adapter.add( msg );
}
Spinner spinner = (Spinner)findViewById( R.id.names );
spinner.setAdapter( adapter );
EditText et = (EditText)findViewById( R.id.name_edit );
et.setText( gameName );
}
String getSelPlayer()
{
Spinner spinner = (Spinner)findViewById( R.id.names );
return spinner.getSelectedItem().toString();
}
String gameName()
{
EditText et = (EditText)findViewById( R.id.name_edit );
return et.getText().toString();
}
}

View file

@ -43,7 +43,7 @@ import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
public class CommsAddrRec { public class CommsAddrRec implements java.io.Serializable {
private static final String TAG = CommsAddrRec.class.getSimpleName(); private static final String TAG = CommsAddrRec.class.getSimpleName();
public enum CommsConnType { public enum CommsConnType {

View file

@ -51,6 +51,7 @@ public class GameSummary implements Serializable {
public static final String EXTRA_REMATCH_RELAY = "rm_relay"; public static final String EXTRA_REMATCH_RELAY = "rm_relay";
public static final String EXTRA_REMATCH_P2P = "rm_p2p"; public static final String EXTRA_REMATCH_P2P = "rm_p2p";
public static final String EXTRA_REMATCH_MQTT = "rm_mqtt"; public static final String EXTRA_REMATCH_MQTT = "rm_mqtt";
public static final String EXTRA_REMATCH_ADDR = "rm_addr";
public static final int MSG_FLAGS_NONE = 0; public static final int MSG_FLAGS_NONE = 0;
public static final int MSG_FLAGS_TURN = 1; public static final int MSG_FLAGS_TURN = 1;
@ -538,6 +539,12 @@ public class GameSummary implements Serializable {
return found; return found;
} }
public boolean hasInviteInfo()
{
boolean found = null != getStringExtra( EXTRA_REMATCH_ADDR );
return found;
}
private static boolean localTurnNextImpl( int flags, int turn ) private static boolean localTurnNextImpl( int flags, int turn )
{ {
int flag = 2 << (turn * 2); int flag = 2 << (turn * 2);

View file

@ -165,6 +165,12 @@ public class XwJNI {
dvc_parseMQTTPacket( getJNI().m_ptrGlobals, buf ); dvc_parseMQTTPacket( getJNI().m_ptrGlobals, buf );
} }
public static boolean hasKnownPlayers()
{
String[] players = kplr_getPlayers();
return null != players && 0 < players.length;
}
public static String[] kplr_getPlayers() public static String[] kplr_getPlayers()
{ {
return kplr_getPlayers( getJNI().m_ptrGlobals ); return kplr_getPlayers( getJNI().m_ptrGlobals );

View file

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<org.eehouse.android.xw4.NewWithKnowns
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="8dp"
>
<TextView android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Choose your opponent"
/>
<Spinner android:id="@+id/names"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
<TextView android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Name your game"
/>
<EditText android:id="@+id/name_edit"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
</org.eehouse.android.xw4.NewWithKnowns>

View file

@ -33,6 +33,7 @@ typedef struct _KPState {
KnownPlayer* players; KnownPlayer* players;
XP_U16 nPlayers; XP_U16 nPlayers;
XP_Bool dirty; XP_Bool dirty;
XP_Bool inUse;
} KPState; } KPState;
/* enum { STREAM_VERSION_KP_1, /\* initial *\/ */ /* enum { STREAM_VERSION_KP_1, /\* initial *\/ */
@ -75,6 +76,8 @@ loadState( XW_DUtilCtxt* dutil, XWEnv xwe )
stream_destroy( stream, xwe ); stream_destroy( stream, xwe );
} }
XP_ASSERT( !state->inUse );
state->inUse = XP_TRUE;
return state; return state;
} }
@ -95,6 +98,14 @@ saveState( XW_DUtilCtxt* dutil, XWEnv xwe, KPState* state )
} }
} }
static void
releaseState( XW_DUtilCtxt* dutil, XWEnv xwe, KPState* state )
{
XP_ASSERT( state->inUse );
saveState( dutil, xwe, state );
state->inUse = XP_FALSE;
}
static const XP_UCHAR* static const XP_UCHAR*
figureNameFor( XP_U16 posn, const CurGameInfo* gi ) figureNameFor( XP_U16 posn, const CurGameInfo* gi )
{ {
@ -158,7 +169,7 @@ kplr_addAddrs( XW_DUtilCtxt* dutil, XWEnv xwe, const CurGameInfo* gi,
XP_LOGFF( "unable to find %dth name", ii ); XP_LOGFF( "unable to find %dth name", ii );
} }
} }
saveState( dutil, xwe, state ); releaseState( dutil, xwe, state );
} }
return canUse; return canUse;
@ -169,6 +180,7 @@ kplr_havePlayers( XW_DUtilCtxt* dutil, XWEnv xwe )
{ {
KPState* state = loadState( dutil, xwe ); KPState* state = loadState( dutil, xwe );
XP_Bool result = 0 < state->nPlayers; XP_Bool result = 0 < state->nPlayers;
releaseState( dutil, xwe, state );
LOG_RETURNF( "%s", boolToStr(result) ); LOG_RETURNF( "%s", boolToStr(result) );
return result; return result;
} }
@ -185,6 +197,7 @@ kplr_getPlayers( XW_DUtilCtxt* dutil, XWEnv xwe,
} }
} }
*nFound = state->nPlayers; *nFound = state->nPlayers;
releaseState( dutil, xwe, state );
} }
XP_Bool XP_Bool
@ -199,6 +212,7 @@ kplr_getAddr( XW_DUtilCtxt* dutil, XWEnv xwe, const XP_UCHAR* name,
*addr = kp->addr; *addr = kp->addr;
} }
} }
releaseState( dutil, xwe, state );
LOG_RETURNF( "%s", boolToStr(found) ); LOG_RETURNF( "%s", boolToStr(found) );
return found; return found;
} }
@ -208,6 +222,7 @@ kplr_cleanup( XW_DUtilCtxt* dutil )
{ {
KPState** state = (KPState**)&dutil->kpCtxt; KPState** state = (KPState**)&dutil->kpCtxt;
if ( !!*state ) { if ( !!*state ) {
XP_ASSERT( !(*state)->inUse );
for ( KnownPlayer* kp = (*state)->players; !!kp; kp = kp->next ) { for ( KnownPlayer* kp = (*state)->players; !!kp; kp = kp->next ) {
XP_FREEP( dutil->mpool, &kp->name ); XP_FREEP( dutil->mpool, &kp->name );
XP_FREE( dutil->mpool, kp ); XP_FREE( dutil->mpool, kp );