123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557 |
- /****************************************************************************
- * Copyright (C) 1995-1996 Microsoft Corporation. All Rights Reserved.
- *
- * File: NetworkGame.cpp
- *
- * Author: Curt Carpenter
- *
- * Description: DPlay interface for networking stuff
- *
- ******************************************************************************/
- #include "pch.h"
- #include <dplobby.h>
- #define CURRENT_DPLAY_VER 318
- //
- // Variables global to this module.
- //
- DPlayWrapper mDPlayWrap;
- BOOL mfMultiplex = FALSE;
- //
- // NetworkGame
- //
- // Basic constructor for a network game.
- NetworkGame::NetworkGame()
- {
- mpDirectPlay = NULL;
- mhPlayerEvent = NULL;
- mdpId = 0;
- mcMessagesSent = 0;
- mcMessagesReceived = 0;
- mcPlayers = 0;
- #ifdef RECEIVETHREAD
- mhReceiveThread = NULL;
- mhKillReceiveEvent = NULL;
- #endif
- }
- // ~NetworkGame
- //
- // Destructor. Releases all DirectPlay state.
- //
- NetworkGame::~NetworkGame()
- {
- debugf("NWG:~NetworkGame()\n");
- this->ShutdownConnection();
- }
- /****************************************************************************\
- *
- * FUNCTION: EnumSessionsCallback2
- *
- * PURPOSE: Called by IDirectPlay#::EnumSessions
- *
- *\***************************************************************************/
- BOOL FAR PASCAL EnumSessionsCallback2(LPCDPSESSIONDESC2 lpThisSD,
- LPDWORD lpdwTimeOut,
- DWORD dwFlags,
- LPVOID lpContext)
- {
- // lpContext is a pointer for where to stick the instance guid, which is all we want
- if (lpThisSD) // will be null if we timed out
- *(GUID*)lpContext = lpThisSD->guidInstance;
- return FALSE;
- }
- /****************************************************************************\
- *
- * FUNCTION: SetupConnection
- *
- * PURPOSE: sets up all the dplay stuff and puts us in a listen state
- *
- *\***************************************************************************/
- HRESULT NetworkGame::SetupConnection(const char * szFedServer,
- const char * szCharName,
- const char * szCharPW,
- bool fCreateNew,
- FILETIME * pftLastArtUpdate)
- {
- HRESULT hr = S_OK;
- char szPlayerName[30] = "/"; // we're going to start copying past the slash
- DWORD dwcbPlayerName = sizeof(szPlayerName) - 1;
- DWORD dwAddressSize = 0;
- #ifdef RECEIVETHREAD
- DWORD idReceiveThread = 0; // id of receive thread
- #endif
- //
- // Create an IDirectPlay3 session to the server.
- //
- hr = mDPlayWrap.AllocDirectPlaySession(szFedServer, &mpDirectPlay);
- if (SUCCEEDED(hr))
- {
- // Use character name / user name for player name
- GetUserName(szPlayerName + 1, &dwcbPlayerName);
- //
- // Create a player
- //
- DPNAME dpName;
- dpName.dwSize = sizeof(dpName);
- dpName.dwFlags = 0;
- dpName.lpszShortNameA = *(char**)&szCharName; // make compiler happy about const-ness
- dpName.lpszLongNameA = szPlayerName;
- hr = mpDirectPlay->CreatePlayer(&mdpId,
- &dpName,
- mhPlayerEvent,
- NULL,
- 0,
- 0);
- if (SUCCEEDED(hr))
- {
- //
- // Player on this machine always in first slot
- //
- mPlayers[0].dpid = mdpId;
- mPlayers[0].FormalName[0] = 0;
- strcpy(mPlayers[0].FriendlyName, szPlayerName);
- mcPlayers++;
- DPCAPS dpcaps;
- dpcaps.dwSize = sizeof(dpcaps);
- hr = mpDirectPlay->GetCaps(&dpcaps, 0);
- FM.Init(mpDirectPlay, mdpId);
- {
- }
- } else
- debugf("NWG: Failed to create user\n");
- } else
- debugf("NWG: Failed to obtain dplay session\n");
- if (FAILED(hr))
- this->ShutdownConnection();
- return(hr);
- }
- LPSTR NetworkGame::GetPlayerName(int i)
- {
- if ((i < 0) || (i >= mcPlayers))
- return NULL;
- return(&mPlayers[i].FriendlyName[0]);
- }
- HRESULT NetworkGame::SendMessages(DPID dpidTo, bool fGuaranteed)
- {
- FM.SendMessages(dpidTo, fGuaranteed, NULL);
- return S_OK;
- }
- DPID NetworkGame::DpId()
- {
- return(mdpId);
- }
-
- #ifdef RECEIVETHREAD
- /****************************************************************************\
- *
- * FUNCTION: ReceiveThread
- *
- * PURPOSE: Waits for messages in its own thread
- *
- *\***************************************************************************/
- DWORD WINAPI ReceiveThread(LPVOID pNWG_This)
- {
- //
- // BUGBUG: This won't work any more. If we want to implement this, we
- // need access to the BasePlayerData so that we can call the callback.
- // If we decide to implement this, it should probably be in the
- // BasePlayerData class instead of here.
- //
- NetworkGame * pNetworkGame = (NetworkGame * ) pNWG_This;
- HANDLE eventHandles[2];
- BOOL fSysMsg;
- eventHandles[0] = pNetworkGame->mhPlayerEvent;
- eventHandles[1] = pNetworkGame->mhKillReceiveEvent;
- // loop waiting for player events. If the kill event is signaled
- // the thread will exit
- while (WaitForMultipleObjects(2, eventHandles, FALSE, INFINITE) == WAIT_OBJECT_0)
- {
- // receive any messages in the queue
- pNetworkGame->ReceiveMessages(&fSysMsg);
- }
- ExitThread(0);
- return (0);
- }
- #endif // RECEIVETHREAD
- /****************************************************************************\
- *
- * FUNCTION: ReceiveMessages
- *
- * PURPOSE: Reads messages queued by DPlay
- *
- * Returns: S_OK if message needs processing,
- * S_FALSE message doesn't need processing,
- * or failure code (including no more messages)
- *
- *\***************************************************************************/
- HRESULT NetworkGame::ReceiveMessages(BOOL * pfSystemMsg)
- {
- DPID idFrom;
- HRESULT hr;
- *pfSystemMsg = FALSE;
- hr = S_FALSE;
- if (0 != mdpId)
- {
- idFrom = 0;
- hr = FM.ReceiveMessages(mdpId, &idFrom);
- if (SUCCEEDED(hr))
- {
- if (FM.PacketSize() >= sizeof(DPMSG_GENERIC))
- {
- mcMessagesReceived++;
- if (idFrom == DPID_SYSMSG)
- *pfSystemMsg = TRUE;
- } else
- hr = S_FALSE;
- }
- }
- return (hr);
- }
- /****************************************************************************\
- *
- * FUNCTION: ShutdownConnection
- *
- * PURPOSE: Shut everything down and go home
- *
- *\***************************************************************************/
- void NetworkGame::ShutdownConnection()
- {
- #ifdef RECEIVETHREAD
- if (mhReceiveThread)
- {
- // wake up receive thread and wait for it to quit
- SetEvent(mhKillReceiveEvent);
- WaitForSingleObject(mhReceiveThread, INFINITE);
- CloseHandle(mhReceiveThread);
- mhReceiveThread = NULL;
- }
- if (mhKillReceiveEvent)
- {
- CloseHandle(mhKillReceiveEvent);
- mhKillReceiveEvent = NULL;
- }
- #endif // RECEIVETHREAD
- mDPlayWrap.FreeDirectPlaySession(mpDirectPlay);
- mpDirectPlay = NULL;
- #ifdef RECEIVETHREAD
- if (mhPlayerEvent)
- {
- CloseHandle(mhPlayerEvent);
- mhPlayerEvent = NULL;
- }
- #endif // RECEIVETHREAD
- }
- /****************************************************************************\
- *
- * FUNCTION: HandleSysMsg
- *
- * PURPOSE: Handle system message
- *
- *\***************************************************************************/
- void NetworkGame::HandleSysMsg(DPID idTo, DPID idFrom)
- {
- // The body of each case is there so you can set a breakpoint and examine
- // the contents of the message received.
- LPDPMSG_GENERIC pMsg = (LPDPMSG_GENERIC) FM.BuffIn();
- debugf("NWG: HandleSysMsg from %lu to %lu, dwType %lu\n", idFrom, idTo, pMsg->dwType);
- switch (pMsg->dwType)
- {
- case DPSYS_CREATEPLAYERORGROUP:
- {
- // should never get this
- }
- break;
- case DPSYS_DESTROYPLAYERORGROUP:
- {
- LPDPMSG_DESTROYPLAYERORGROUP lp = (LPDPMSG_DESTROYPLAYERORGROUP) pMsg;
- }
- break;
- case DPSYS_ADDPLAYERTOGROUP:
- {
- LPDPMSG_ADDPLAYERTOGROUP lp = (LPDPMSG_ADDPLAYERTOGROUP) pMsg;
- }
- break;
- case DPSYS_DELETEPLAYERFROMGROUP:
- {
- LPDPMSG_DELETEPLAYERFROMGROUP lp = (LPDPMSG_DELETEPLAYERFROMGROUP) pMsg;
- }
- break;
- case DPSYS_SESSIONLOST:
- {
- LPDPMSG_SESSIONLOST lp = (LPDPMSG_SESSIONLOST) pMsg;
- }
- break;
- case DPSYS_HOST:
- {
- LPDPMSG_HOST lp = (LPDPMSG_HOST) pMsg;
- }
- break;
- case DPSYS_SETPLAYERORGROUPDATA:
- {
- LPDPMSG_SETPLAYERORGROUPDATA lp = (LPDPMSG_SETPLAYERORGROUPDATA) pMsg;
- assert(false);
- }
- break;
- case DPSYS_SETPLAYERORGROUPNAME:
- {
- LPDPMSG_SETPLAYERORGROUPNAME lp = (LPDPMSG_SETPLAYERORGROUPNAME) pMsg;
- assert(false);
- }
- break;
- case DPSYS_SECUREMESSAGE:
- {
- LPDPMSG_SECUREMESSAGE lp = (LPDPMSG_SECUREMESSAGE) pMsg;
- assert(false);
- }
- break;
- }
- }
- //
- // We really want to use the same IDirectPlay pointer in all of
- // our network game code (DPlay creates 3 threads per IDirectPlay).
- // To do this, I've created these static functions to handle the
- // initialization and termination of the one DPlay pointer.
- //
- DPlayWrapper::DPlayWrapper()
- {
- mpDirectPlay = NULL;
- mpDirectPlayLobbyA = NULL;
- }
- DPlayWrapper::~DPlayWrapper()
- {
- ZAssert(NULL == mpDirectPlay);
- if (NULL != mpDirectPlayLobbyA)
- mpDirectPlayLobbyA->Release();
- }
- HRESULT DPlayWrapper::AllocDirectPlaySession(const CHAR * szServer,
- IDirectPlayX ** ppDirectPlay)
- {
- BOOL fCreateSession;
- VOID * pvAddress;
- DWORD cbAddress;
- HRESULT hr;
- hr = S_OK;
- fCreateSession = FALSE;
- if (!CheckDPlayVersion())
- hr = E_FAIL;
-
- //
- // Create a lobby if we don't already have one.
- //
- if (SUCCEEDED(hr) && NULL == mpDirectPlayLobbyA)
- {
- hr = DirectPlayLobbyCreate(NULL,
- &mpDirectPlayLobbyA,
- NULL,
- NULL,
- 0);
- }
- //
- // Create a directplay session if need be.
- //
- if (SUCCEEDED(hr) && (NULL == mpDirectPlay))
- {
- hr = CoCreateInstance(CLSID_DirectPlay,
- NULL,
- CLSCTX_INPROC_SERVER,
- IID_IDirectPlayX,
- (VOID **) &mpDirectPlay);
- if (SUCCEEDED(hr))
- fCreateSession = TRUE;
- }
- if (TRUE == fCreateSession)
- {
- //
- // At this point I have a new directplay pointer and lobby pointer.
- //
- //
- // Need to find out how big of an address buffer we need, so
- // we intentionally fail the first time.
- //
- pvAddress = NULL;
- cbAddress = 0;
- hr = mpDirectPlayLobbyA->CreateAddress(DPSPGUID_TCPIP,
- DPAID_INet,
- szServer,
- strlen(szServer) + 1,
- pvAddress,
- &cbAddress);
- if (DPERR_BUFFERTOOSMALL == hr)
- {
- pvAddress = new BYTE[cbAddress];
- if (NULL != pvAddress)
- {
- hr = mpDirectPlayLobbyA->CreateAddress(DPSPGUID_TCPIP,
- DPAID_INet,
- szServer,
- strlen(szServer) + 1,
- pvAddress,
- &cbAddress);
- } else
- hr = E_OUTOFMEMORY;
- }
- if (SUCCEEDED(hr))
- {
- hr = mpDirectPlay->InitializeConnection(pvAddress, 0);
- if (SUCCEEDED(hr))
- {
- //
- // Find the session.
- //
- DPSESSIONDESC2 sessionDesc;
- GUID guidDPInstance, guidZero;
- ZeroMemory(&sessionDesc, sizeof(sessionDesc));
- sessionDesc.dwSize = sizeof(sessionDesc);
- sessionDesc.guidApplication = FEDSRV_GUID;
- ZeroMemory(&guidDPInstance, sizeof(guidDPInstance));
- ZeroMemory(&guidZero, sizeof(guidZero));
- hr = mpDirectPlay->EnumSessions(&sessionDesc,
- 5000,
- EnumSessionsCallback2,
- &guidDPInstance,
- 0);
- if (FAILED(hr) || (guidZero == guidDPInstance))
- {
- //
- // Maybe we hit a burp. Try again.
- //
- hr = mpDirectPlay->EnumSessions(&sessionDesc,
- 5000,
- EnumSessionsCallback2,
- &guidDPInstance,
- 0);
- }
- if (guidZero != guidDPInstance)
- {
- //
- // Join the session.
- //
- sessionDesc.guidInstance = guidDPInstance;
- hr = mpDirectPlay->SecureOpen(&sessionDesc,
- DPOPEN_JOIN,
- NULL,
- NULL);
- } else
- hr = E_FAIL;
- }
- }
- if (NULL != pvAddress)
- delete[] pvAddress;
- if (FAILED(hr))
- {
- mpDirectPlay->Release();
- mpDirectPlay = NULL;
- }
- }
- if (SUCCEEDED(hr))
- {
- *ppDirectPlay = mpDirectPlay;
- if (FALSE == mfMultiplex)
- mpDirectPlay = NULL;
- else
- mpDirectPlay->AddRef();
- } else
- *ppDirectPlay = NULL;
- return(hr);
- }
- VOID DPlayWrapper::FreeDirectPlaySession(IDirectPlayX * pDirectPlay)
- {
- if (NULL != pDirectPlay)
- {
- if (FALSE == mfMultiplex)
- {
- //
- // Not multiplexing. Shut the whole thing down.
- //
- pDirectPlay->Close();
- pDirectPlay->Release();
- } else if (1 == pDirectPlay->Release())
- {
- //
- // We own the last reference. Shut down.
- //
- mpDirectPlay->Close();
- mpDirectPlay->Release();
- mpDirectPlay = NULL;
- }
- }
- }
|