From 384542defeef228829069d83b8187f20c3c0f9e1 Mon Sep 17 00:00:00 2001 From: Daniel Collins Date: Fri, 21 Aug 2015 22:01:51 +0100 Subject: [PATCH] DirectPlay: Store addresses in shared player data. When there are more than two players in a session (including the host), the message that triggers SP_CreatePlayer() may not be from the host that actually has that player on it, copy the behaviour of the DX5 SP and make each player be responsible for sharing their own address via the shared data. --- src/directplay.c | 72 ++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 66 insertions(+), 6 deletions(-) diff --git a/src/directplay.c b/src/directplay.c index 2e04c19..aaf94f4 100644 --- a/src/directplay.c +++ b/src/directplay.c @@ -189,7 +189,7 @@ static HRESULT WINAPI IPX_Send(LPDPSP_SENDDATA data) { DWORD addr_size; HRESULT r = IDirectPlaySP_GetSPPlayerData( - data->lpISP, data->idPlayerTo, (void**)(&addr_p), &addr_size, DPGET_LOCAL); + data->lpISP, data->idPlayerTo, (void**)(&addr_p), &addr_size, 0); if(r != DP_OK) { log_printf(LOG_ERROR, "GetSPPlayerData: %x", (unsigned int)(r)); @@ -244,7 +244,7 @@ static HRESULT WINAPI IPX_Reply(LPDPSP_REPLYDATA data) { struct sockaddr_ipx *addr_p; DWORD size; - HRESULT r = IDirectPlaySP_GetSPPlayerData(data->lpISP, data->idNameServer, (void**)&addr_p, &size, DPGET_LOCAL); + HRESULT r = IDirectPlaySP_GetSPPlayerData(data->lpISP, data->idNameServer, (void**)&addr_p, &size, 0); if(r != DP_OK) { log_printf(LOG_ERROR, "GetSPPlayerData: %d", (int)r); }else if(addr_p) { @@ -266,14 +266,74 @@ static HRESULT WINAPI IPX_Reply(LPDPSP_REPLYDATA data) { return DP_OK; } +/* CreatePlayer dwFlags bits. Meanings guessed from examination of official + * implementation. +*/ +#define CREATEPLAYER_FIRST 1 /* The first player ID of a node */ +#define CREATEPLAYER_NS 2 /* This instance is becomming the name server */ +#define CREATEPLAYER_SELF 8 /* This is a local player ID */ + static HRESULT WINAPI IPX_CreatePlayer(LPDPSP_CREATEPLAYERDATA data) { CALL("SP_CreatePlayer"); - if(data->lpSPMessageHeader) { - HRESULT r = IDirectPlaySP_SetSPPlayerData(data->lpISP, data->idPlayer, data->lpSPMessageHeader, sizeof(struct sockaddr_ipx), DPSET_LOCAL); + if(data->lpSPMessageHeader) + { + struct sockaddr_ipx *addr = data->lpSPMessageHeader; + + IPX_STRING_ADDR(str_addr, addr32_in(addr->sa_netnum), addr48_in(addr->sa_nodenum), addr->sa_socket); + log_printf(LOG_DEBUG, "IPX_CreatePlayer: idPlayer = %u, addr = %s, dwFlags = %u", + (unsigned int)(data->idPlayer), str_addr, (unsigned int)(data->dwFlags)); + } + else{ + log_printf(LOG_DEBUG, "IPX_CreatePlayer: idPlayer = %u, dwFlags = %u", + (unsigned int)(data->idPlayer), (unsigned int)(data->dwFlags)); + } + + if(data->dwFlags & CREATEPLAYER_SELF) + { + /* This is a local player ID, initialise the shared player data + * with our socket address. + */ + + struct sp_data *sp_data = get_sp_data(data->lpISP); + struct sockaddr_ipx addr = sp_data->addr; + release_sp_data(sp_data); + + HRESULT r = IDirectPlaySP_SetSPPlayerData( + data->lpISP, data->idPlayer, &addr, sizeof(addr), 0); + if(r != DP_OK) + { + log_printf(LOG_ERROR, "IPX_CreatePlayer: SetSPPlayerData: %x", (unsigned int)(r)); + return r; + } + } + else{ + /* This is a remote player ID, verify the shared player data + * already contains an address. + */ + + struct sockaddr_ipx *addr; + DWORD addr_size; + + HRESULT r = IDirectPlaySP_GetSPPlayerData( + data->lpISP, data->idPlayer, (void**)(&addr), &addr_size, 0); if(r != DP_OK) { - log_printf(LOG_ERROR, "SetSPPlayerData: %d", (int)r); - return DPERR_GENERIC; + log_printf(LOG_ERROR, "IPX_CreatePlayer: GetSPPlayerData: %x", (unsigned int)(r)); + return r; + } + + if(addr == NULL) + { + log_printf(LOG_WARNING, + "IPX_CreatePlayer: Remote player %u has no shared data", + (unsigned int)(data->idPlayer)); + } + else if(addr_size != sizeof(*addr)) + { + log_printf(LOG_WARNING, + "IPX_CreatePlayer: Remote player %u shared data is %u bytes (expected %u)", + (unsigned int)(data->idPlayer), + (unsigned int)(addr_size), (unsigned int)(sizeof(*addr))); } }