reman3/Rayman_X/cpa/tempgrp/NET/NetSynch.c

331 lines
12 KiB
C

/********************************************************************************/
/* */
/* NetSynch.c */
/* */
/* This file defines the synchronisation API */
/* */
/********************************************************************************/
/* Author: David Fournier
*
* Creation Date: 10/04/97
*/
#include "warnings.h"
#include "NetMemCo.h"
#include <stdlib.h>
#include <stdio.h>
#include "Privnetser.h"
#include "PrivNetSynch.h"
typedef struct
{
NetLib_uxSynchroId uxSyncId; /* Synchro Id. */
unsigned long ulSizeMes; /* Size of message. */
}NetLib_tdstMesSynchro;
typedef struct _stRecSynchro
{
NetLib_tduxPlayerId PId; /* Player Id. */
struct _stRecSynchro *pNext; /* Next synchro message receipt. */
NetLib_uxSynchroId uxSyncId; /* Synchro Id. */
unsigned long ulSizeMes; /* Size of message. */
}NetLib_tdstRecSynchro;
typedef struct
{
NetLib_uxSynchroId uxSyncId; /* Synchro Id. */
NetLib_tduxPlayerId *pMarkPlayer; /* Array of players mark. */
NetLib_tduxPlayerId NbrPlayer; /* Number of remote player. */
NetLib_tdstRecSynchro *pRecSync; /* Array of synchro receipt. */
NetLib_tdulTimeInfo ulTimeEnd; /* Time of end process (begin + time out). */
NetLib_tdfnvSynchroCallback tdfnvCallback; /* CallBack for remote sync message. */
}NetLib_tdstInfoSynchro;
static NetLib_tdstInfoSynchro gs_tdstInfoSynchro; /* Informations of the current synchro. */
/*****************************************************************************
* Description: vNetLibInitSynchro
* Initialyze synchro module.
*****************************************************************************
* Input: none
* Output: none
*****************************************************************************/
void _NET_CALLING_CONV_ vNetLibInitSynchro(void)
{
gs_tdstInfoSynchro.uxSyncId=NetLib_C_InvalidSynchroId;
gs_tdstInfoSynchro.pMarkPlayer=NULL;
gs_tdstInfoSynchro.ulTimeEnd=0;
gs_tdstInfoSynchro.pRecSync=NULL;
gs_tdstInfoSynchro.tdfnvCallback=NULL;
}
/*****************************************************************************
* Description: eNetLibFreeSynchro
* Free synchro module.
*****************************************************************************
* Input: none
* Output: none
*****************************************************************************/
void _NET_CALLING_CONV_ vNetLibFreeSynchro(void)
{
NetLib_tdstRecSynchro *pRecSync,*pNext;
vFree(gs_tdstInfoSynchro.pMarkPlayer);
gs_tdstInfoSynchro.pMarkPlayer=NULL;
pRecSync=gs_tdstInfoSynchro.pRecSync;
while (pRecSync)
{
pNext=pRecSync->pNext;
vFree(pRecSync);
pRecSync=pNext;
}
gs_tdstInfoSynchro.pRecSync=NULL;
gs_tdstInfoSynchro.tdfnvCallback=NULL;
gs_tdstInfoSynchro.uxSyncId=NetLib_C_InvalidSynchroId;
}
/*****************************************************************************
* Description: eNetLibTestSynchro
* Return the synchro state.
*****************************************************************************/
NetLib_tdeErrorStatus eNetLibTestSynchro(int bWithoutAck,NetLib_tduxPlayerId ucMaster)
{
NetLib_tduxPlayerId i;
NetLib_tdstRecSynchro *pRecSync;
if (!bWithoutAck)
{
for (i=0;i<gs_tdstInfoSynchro.NbrPlayer;i++)
{
if (gs_tdstInfoSynchro.pMarkPlayer[i]==C_uxNetInvalidId)
{
return NetLib_E_es_SynchroNoAck;
}
}
}
if (ucMaster==C_uxNetInvalidId)
{
for (i=0;i<gs_tdstInfoSynchro.NbrPlayer;i++)
{
pRecSync=gs_tdstInfoSynchro.pRecSync;
while (pRecSync)
{
if ((pRecSync->uxSyncId==gs_tdstInfoSynchro.uxSyncId) &&
(pRecSync->PId==gs_tdstInfoSynchro.pMarkPlayer[i])) break;
pRecSync=pRecSync->pNext;
}
if (!pRecSync) return NetLib_E_es_SynchroNoSync;
}
}
else
{
pRecSync=gs_tdstInfoSynchro.pRecSync;
while (pRecSync)
{
if ((pRecSync->uxSyncId==gs_tdstInfoSynchro.uxSyncId) &&
(pRecSync->PId==ucMaster)) break;
pRecSync=pRecSync->pNext;
}
if (!pRecSync) return NetLib_E_es_SynchroNoSync;
}
return NetLib_E_es_SynchroOk;
}
/*****************************************************************************
* Description: vNetLib_AckSynchro
* Aknowledgment of a synchro message.
*****************************************************************************/
static void _NET_CALLING_CONV_ vNetLib_AckSynchro(NetLib_tduxPlayerId PId,
NetLib_uxReadReceiptId AId,NetLib_ucReadReceiptFlag Flag,long Param)
{
NetLib_tduxPlayerId i;
if ((Flag==NetLib_C_ucReadReceiptSuccess) && (AId==gs_tdstInfoSynchro.uxSyncId))
{
for (i=0;i<gs_tdstInfoSynchro.NbrPlayer;i++)
{
if (gs_tdstInfoSynchro.pMarkPlayer[i]==C_uxNetInvalidId)
{
gs_tdstInfoSynchro.pMarkPlayer[i]=PId;
break;
}
else if (gs_tdstInfoSynchro.pMarkPlayer[i]==PId) break;
}
}
}
/*****************************************************************************
* Description: MemSwap
* Swap memory.
*****************************************************************************/
static void MemSwap(void *p,unsigned long s)
{
char *p1,*p2,c;
p1=(char *)p;
p2=p1+s;
s/=2;
while (s--)
{
c=*p1;
*(p1++)=*(--p2);
*p2=c;
}
}
/*****************************************************************************
* Description: eSwapLittleBigEndianSysMsgSynchro
* Swap synchro message.
*****************************************************************************/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ eSwapLittleBigEndianSysMsgSynchro(tdstNetMessage *pstMes,tdeNetProtocol eProt,tduwNetChannel uwChannel)
{
NetLib_tdstMesSynchro *pMessage;
pMessage=(NetLib_tdstMesSynchro *)(pstMes+1);
MemSwap(&(pMessage->ulSizeMes),sizeof(unsigned long));
return NetLib_E_es_NoError;
}
/*****************************************************************************
* Description: eHandleNetSysMsgSynchro
* Receive a synchro message.
*****************************************************************************/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ eHandleNetSysMsgSynchro(tdstNetMessage *pstMes,tdeNetProtocol eProt,tduwNetChannel uwChannel)
{
NetLib_tdstMesSynchro *pMessage;
NetLib_tdstRecSynchro **ppRecSync,*pRecSync,*pF;
if(pstMes->m_uxReadReceiptId!=C_uxNetInvalidId)
eNetSendReadReceiptMessage(pstMes);
pMessage=(NetLib_tdstMesSynchro *)(pstMes+1);
ppRecSync=&(gs_tdstInfoSynchro.pRecSync);
while (*ppRecSync)
{
pRecSync=*ppRecSync;
if ((pRecSync->uxSyncId==pMessage->uxSyncId) && (pRecSync->PId==pstMes->uxSenderId))
{ /* If an old synchro with same Id and same player */
pF=*ppRecSync; /* is already in the file, delete it. */
*ppRecSync=(*ppRecSync)->pNext;
vFree(pF);
}
else ppRecSync=&((*ppRecSync)->pNext);
}
pRecSync=(NetLib_tdstRecSynchro *)pMalloc(sizeof(NetLib_tdstRecSynchro)+pMessage->ulSizeMes);
pRecSync->PId=pstMes->uxSenderId;
pRecSync->pNext=NULL;
pRecSync->uxSyncId=pMessage->uxSyncId;
pRecSync->ulSizeMes=pMessage->ulSizeMes;
memcpy(pRecSync+1,pMessage+1,pMessage->ulSizeMes);
*ppRecSync=pRecSync;
vFree(pstMes);
return NetLib_E_es_NoError;
}
/*****************************************************************************
* Description: eNetLibWaitSynchro
* Send a synchro message and wait synchro messages from all other players or from master.
*****************************************************************************
* Input: uxSyncId = Synchro id
* ulTimeOut = when time elapsed, function return NetLib_E_es_SynchroNoAck or NetLib_E_es_SynchroNoSync.
* pBufMes = Adress of the send message.
* ulSizeMes = Size of the send message.
* tdfnvCallback = CallBack for receipt remote player message.
* bWithoutAck = true (!=0) if send without acknoledment.
* ucMaster = Id of master if the synchro is master/slave.
* C_uxNetInvalidId if no master.
* Output: An error code.
* NetLib_E_es_SynchroWait : Synchro not finish.
* NetLib_E_es_SynchroOk : Synchro ok. All synchro messages players receipt
* and all player receive our message.
* NetLib_E_es_SynchroNoAck : Time out, acknoledgment missing for one or many players,
* NetLib_E_es_SynchroNoSync : or one or many synchro message missing.
* NetLib_E_es_NotEnoughMemory : Not enough memory for perform synchro.
*****************************************************************************/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ eNetLibWaitSynchro(NetLib_uxSynchroId uxSyncId,
NetLib_tdulTimeInfo ulTimeOut,void *pBufMes,unsigned long ulSizeMes,
NetLib_tdfnvSynchroCallback tdfnvCallback,int bWithoutAck,
NetLib_tduxPlayerId ucMaster)
{
NetLib_tduxPlayerId PId,OwnId;
NetLib_tdstSendDesc tdstSendDesc;
NetLib_tdstMesSynchro *pMessage;
NetLib_tdeErrorStatus eStatus;
NetLib_tdstRecSynchro *pRecSync;
if (gs_tdstInfoSynchro.uxSyncId!=uxSyncId)
{
gs_tdstInfoSynchro.uxSyncId=NetLib_C_InvalidSynchroId;
vFree(gs_tdstInfoSynchro.pMarkPlayer);
gs_tdstInfoSynchro.NbrPlayer=NetLib_uwGetTotalNumberPlayer()-1;
OwnId=NetLib_uxGetOwnPlayerId();
if (gs_tdstInfoSynchro.NbrPlayer==0) return NetLib_E_es_SynchroOk;
gs_tdstInfoSynchro.pMarkPlayer=pMalloc(sizeof(NetLib_tduxPlayerId)*gs_tdstInfoSynchro.NbrPlayer);
if (!gs_tdstInfoSynchro.pMarkPlayer) return NetLib_E_es_NotEnoughMemory;
pMessage=(NetLib_tdstMesSynchro *)pMalloc(ulSizeMes+sizeof(NetLib_tdstMesSynchro));
if (!pMessage)
{
vFree(gs_tdstInfoSynchro.pMarkPlayer);
gs_tdstInfoSynchro.pMarkPlayer=NULL;
return NetLib_E_es_NotEnoughMemory;
}
if (OwnId==ucMaster) ucMaster=C_uxNetInvalidId;
for (PId=0;PId<gs_tdstInfoSynchro.NbrPlayer;PId++)
{
gs_tdstInfoSynchro.pMarkPlayer[PId]=C_uxNetInvalidId;
}
pMessage->uxSyncId=uxSyncId;
pMessage->ulSizeMes=ulSizeMes;
memcpy(pMessage+1,pBufMes,ulSizeMes);
gs_tdstInfoSynchro.uxSyncId=uxSyncId;
gs_tdstInfoSynchro.ulTimeEnd=GetTickCount()+ulTimeOut;
gs_tdstInfoSynchro.tdfnvCallback=tdfnvCallback;
if (ucMaster==C_uxNetInvalidId) tdstSendDesc.m_tduxRecipientId=C_uxNetBroadcastId;
else tdstSendDesc.m_tduxRecipientId=ucMaster;
tdstSendDesc.m_ulMaxWaitingTime=0;
tdstSendDesc.m_pMessageData=(char*)pMessage;
tdstSendDesc.m_uwMessageLength=ulSizeMes+sizeof(NetLib_tdstMesSynchro);
tdstSendDesc.m_uxPriority=0;
tdstSendDesc.m_uxReplaceType=0;
tdstSendDesc.m_uxReplaceFlag=NetLib_C_uxNoReplace;
if (!bWithoutAck)
{
tdstSendDesc.m_ucReadReceiptFlag=NetLib_C_ucReadReceiptRequired;
tdstSendDesc.m_stReadReceiptDesc.m_ulMaxWaitingTime=ulTimeOut;
tdstSendDesc.m_stReadReceiptDesc.m_ulReemitFreq=250;
tdstSendDesc.m_stReadReceiptDesc.m_uxReadReceiptId=uxSyncId;
tdstSendDesc.m_stReadReceiptDesc.m_lCallbackParam=uxSyncId;
tdstSendDesc.m_stReadReceiptDesc.p_fnv_ReadReceiptCallback=vNetLib_AckSynchro;
}
else
{
tdstSendDesc.m_ucReadReceiptFlag=NetLib_C_ucNoReadReceipt;
}
eNetInternalSendMessage(&tdstSendDesc,E_Net_mt_SysSynchro);
vFree(pMessage);
}
NetLib_vEngine();
eStatus=eNetLibTestSynchro(bWithoutAck,ucMaster);
if ((eStatus!=NetLib_E_es_SynchroOk) && (GetTickCount()<gs_tdstInfoSynchro.ulTimeEnd))
{
eStatus=NetLib_E_es_SynchroWait;
}
if (eStatus!=NetLib_E_es_SynchroWait)
{
if (tdfnvCallback)
{
pRecSync=gs_tdstInfoSynchro.pRecSync;
while (pRecSync)
{
if (pRecSync->uxSyncId==uxSyncId)
{
tdfnvCallback(pRecSync->PId,pRecSync->uxSyncId,pRecSync+1,pRecSync->ulSizeMes);
}
pRecSync=pRecSync->pNext;
}
}
vNetLibFreeSynchro();
}
return eStatus;
}