CMRPFull g_MRF;
extern DPSESSIONDESC2 CurrentSession;
extern DWORD MyDirectPlayID;
extern bool IAmTheServer;
extern bool InNetworkGame;
extern char GameNameBuffer[];
extern char PasswordBuffer[];
extern DWORD gInSecureGame;
extern ListOfNames* CurrentPlayers;
extern char *LocalIPAddress; // extern SCRIPTVAR_STR(LocalIPAddress);

extern int ConnectionIndex;

DWORD g_dwMR_Meta = 0xab9a655f;
DWORD g_dwMR_MetaOldA = 0xab9a654f;

bool g_bMRTest = false;
const char* g_pcszGameDataExtMR = ".mr";

#if !defined(SCRIPTCALLBACK)
#define SCRIPTCALLBACK(func) int __stdcall func( void * instance, int args, void * arg[])
#endif // !defined(SCRIPTCALLBACK)

#if !defined(FREE_PTR)
#define FREE_PTR(ptr) if ((void *)ptr) { gos_Free((void *)ptr); (ptr)=NULL; }
#endif // !defined(FREE_PTR)

extern bool g_bCOOP; // COin OPeration

extern void RegisterData(void);
extern void UnRegisterData(void);
extern SCRIPTCALLBACK(CancelDialup);
extern SCRIPTCALLBACK(PreConnect);
extern SCRIPTCALLBACK(LoadMPConnectionSettings);
extern SCRIPTCALLBACK(InitConnectionWizard);

extern void _stdcall gos_RealRemovePlayerFromGame( ListOfNames** pListOfPlayers, char* Name, DPID dpId );
extern void _stdcall gos_RealAddPlayerToGame( ListOfNames** pListOfPlayers, char* Name, DPID dpId );

extern void _stdcall CTCL_SetMissionParamsBy(void* pNMP, int nSize);

void __stdcall MRP_OnGameOpen(const char* pcszGameName, DWORD dwMyID, const char* pcszPlayer, const char* pcszPassword);
void __stdcall NET_AddPlayerToGame(void/*ListOfNames*/** pListOfPlayers, char* Name, DPID dpId);
void __stdcall NET_RemovePlayerFromGame(void/*ListOfNames*/** pListOfPlayers, char* Name, DPID dpId);
void __stdcall NET_AddRemoveConnection(bool bAdd, void* pConnection);
void __stdcall NET_SessionLost();

void* __stdcall MRP_NetInformation(gosNetInfo Info, DWORD Parameter, char* Name);
void __stdcall MRP_NetServerCommands(gos_NetCommands Command, DWORD Data1);
NetPacket* __stdcall MRP_NETGETMESSAGE();
bool _stdcall MRP_LOCALSENDNETMESSAGE(int message_type, void/*Stuff::MemoryStream*/* message);
void __stdcall MRP_BACKGROUNDTACK();
bool __stdcall MRP_NETSENDMESSAGE(NetPacket* Message);

#define STRING_SIZE						256

void _inline AllocString(char * &sptr)
{
	sptr = (char *)gos_Malloc(STRING_SIZE);
	sptr[0] = 0;
}

void _inline FreeString(char * &sptr)
{
	FREE_PTR(sptr);
}

void __stdcall MRP_OnGameOpen(const char* pcszGameName, DWORD dwMyID, const char* pcszPlayer, const char* pcszPassword)
{
    g_MRF.OnGameOpen(pcszGameName, dwMyID, pcszPlayer, pcszPassword);
}

void __stdcall NET_AddPlayerToGame(void/*ListOfNames*/** pListOfPlayers, char* Name, DPID dpId)
{
    g_MRF.AddRemovePlayerToGame(MRP_ADD_PLAYER_NAME, Name, dpId);
}

void __stdcall NET_RemovePlayerFromGame(void/*ListOfNames*/** pListOfPlayers, char* Name, DPID dpId)
{
    g_MRF.AddRemovePlayerToGame(MRP_REMOVE_PLAYER_NAME, Name, dpId);
}

void __stdcall NET_AddRemoveConnection(bool bAdd, void* pConnection)
{
    g_MRF.AddRemoveConnection(bAdd, (Connection*)pConnection);
}

void __stdcall NET_SessionLost()
{
    g_MRF.SessionLost();
}

void* __stdcall MRP_NetInformation(gosNetInfo Info, DWORD Parameter, char* Name)
{
    return g_MRF.NetInformation(Info, Parameter, Name);
}

void __stdcall MRP_NetServerCommands(gos_NetCommands Command, DWORD Data1)
{
    g_MRF.NetServerCommands(Command, Data1);
}

NetPacket* __stdcall MRP_NETGETMESSAGE()
{
    return g_MRF.NetGetMessage();
}

bool _stdcall MRP_LOCALSENDNETMESSAGE(int message_type, void/*Stuff::MemoryStream*/* message)
{
    return g_MRF.LocalSendNetMessage(message_type, *(Stuff::MemoryStream*)message);
}

void __stdcall MRP_BACKGROUNDTACK()
{
    g_MRF.BackgroundTack();
}

bool __stdcall MRP_NETSENDMESSAGE(NetPacket* Message)
{
    return true;
}

int SMRP::GetMemSize() const
{
    return sizeof(SMRP) + m_nLen;
}

CMRPPack* AllocMRPPack(int nCount, PMRP* ppMRP)
{
    CMRPPack* pMRPPack = (CMRPPack*)malloc(sizeof(CMRPPack) + sizeof(PMRP) * nCount);
    pMRPPack->Construct(nCount, ppMRP);

    return pMRPPack;
}

void FreeMRPPack(CMRPPack* pMRPPack)
{
    if (pMRPPack) {
        pMRPPack->Destruct();
        free(pMRPPack);
    }
}

void CMRPPack::Construct(int nCount, PMRP* ppMRP)
{
    m_pPrev = NULL;
    m_pNext = NULL;
    m_fFrameTime = 0.0f;
    m_nCount = nCount;
    if (ppMRP)
    memcpy(&m_pa[0], ppMRP, sizeof(PMRP) * nCount);
}

void CMRPPack::Destruct()
{
    PMRP* ppStart = &m_pa[0];
    PMRP* ppEnd = &m_pa[m_nCount];
    while(ppEnd-- > ppStart) {
        free(*ppEnd);
    }
}

int CMRPPack::GetMemSize() const
{
    int nSize = sizeof(CMRPPack);
    for(int i = 0; i < m_nCount; i++) {
        nSize += m_pa[i]->GetMemSize();
    }

    return nSize;
}

void CMRPPack::Save(Stuff::DynamicMemoryStream& mf)
{
    mf.WriteBytes(&m_fFrameTime, sizeof(m_fFrameTime));
    for(int i = 0; i < m_nCount; i++) {
        PMRP pMRP = m_pa[i];
        mf.WriteBytes(&pMRP->m_nCommand, sizeof(pMRP->m_nCommand));
        mf.WriteBytes(&pMRP->m_nType, sizeof(pMRP->m_nType));
        mf.WriteBytes(&pMRP->m_nLen, sizeof(pMRP->m_nLen));
        mf.WriteBytes(pMRP->m_ba, pMRP->m_nLen);
    }
}

void CMRPPack::Load(Stuff::MemoryStream& mf, DWORD dwMeta)
{
    if (dwMeta != g_dwMR_MetaOldA) {
        mf.ReadBytes(&m_fFrameTime, sizeof(m_fFrameTime));
    }
    for(int i = 0; i < m_nCount; i++) {
        int nCommand;
        int nType;
        int nLen;
        mf.ReadBytes(&nCommand, sizeof(nCommand));
        mf.ReadBytes(&nType, sizeof(nType));
        mf.ReadBytes(&nLen, sizeof(nLen));
        PMRP pMRP = (PMRP)malloc(sizeof(SMRP) + nLen);
        pMRP->m_nCommand = nCommand;
        pMRP->m_nType = nType;
        pMRP->m_nLen = nLen;
        mf.ReadBytes(pMRP->m_ba, nLen);
        m_pa[i] = pMRP;
    }
}

CMRPPlayer::CMRPPlayer()
    : m_pPrev(NULL), m_pNext(NULL), m_bBOT(false), m_strName(""), m_strClan(""), m_strScript(""), m_connection_id(0), m_pilotTeam(0), m_pilotDecals(0), m_teamDecals(0), m_mechChasisID(0), m_pilotSkins(0), m_tonnage(0), m_pBufVCM(NULL), m_vehicleCreateMessage(NULL)
{
}

CMRPPlayer::~CMRPPlayer()
{
    if (m_vehicleCreateMessage) {
        delete m_vehicleCreateMessage;
        m_vehicleCreateMessage = NULL;
    }
    if (m_pBufVCM) {
        free(m_pBufVCM);
        m_pBufVCM = NULL;
    }
}

int CMRPPlayer::GetMemSize() const
{
    int nSize = sizeof(CMRPPlayer);
    
    nSize += m_strName.GetLength() + 1;
    nSize += m_strClan.GetLength() + 1;
    nSize += m_strScript.GetLength() + 1;
    nSize += m_vehicleCreateMessage->GetSize();

    return nSize;
}

void CMRPPlayer::Save(Stuff::DynamicMemoryStream& mf)
{
    mf.WriteBit(m_bBOT);
    mf.WriteByteAlign();
    mf << m_strName;
    mf << m_strClan;
    mf << m_strScript;
    mf.WriteBytes(&m_connection_id, sizeof(m_connection_id));
	mf.WriteBytes(&m_pilotTeam, sizeof(m_pilotTeam));
	mf.WriteBytes(&m_pilotDecals, sizeof(m_pilotDecals));
	mf.WriteBytes(&m_teamDecals, sizeof(m_teamDecals));
	mf.WriteBytes(&m_mechChasisID, sizeof(m_mechChasisID));
	mf.WriteBytes(&m_pilotSkins, sizeof(m_pilotSkins));
    mf.WriteBytes(&m_tonnage, sizeof(m_tonnage));
    // for bot only - start
    mf << m_aiModel;
    int n = m_vehicleCreateMessage->GetSize();
    mf.WriteBytes(&n, sizeof(n));
    mf.WriteBytes(m_pBufVCM, n);
}

void CMRPPlayer::Load(Stuff::MemoryStream& mf)
{
    mf.ReadBit(m_bBOT);
    mf.ReadByteAlign();
    mf >> m_strName;
    mf >> m_strClan;
    mf >> m_strScript;
    mf.ReadBytes(&m_connection_id, sizeof(m_connection_id));
	mf.ReadBytes(&m_pilotTeam, sizeof(m_pilotTeam));
	mf.ReadBytes(&m_pilotDecals, sizeof(m_pilotDecals));
	mf.ReadBytes(&m_teamDecals, sizeof(m_teamDecals));
	mf.ReadBytes(&m_mechChasisID, sizeof(m_mechChasisID));
	mf.ReadBytes(&m_pilotSkins, sizeof(m_pilotSkins));
    mf.ReadBytes(&m_tonnage, sizeof(m_tonnage));
    // for bot only - start
    mf >> m_aiModel;
    int n;
    mf.ReadBytes(&n, sizeof(n));
    m_pBufVCM = (BYTE*)malloc(n);
    mf.ReadBytes(m_pBufVCM, n);
    m_vehicleCreateMessage = new MemoryStream(m_pBufVCM, n);
}

CMRPFull::CMRPFull()
    : m_strGameName(""), m_dwMyDirectPlayID(0), m_strPlayer(""), m_strPassword(""),
    m_bStarting(false), m_bStarted(false), m_bStopping(false), m_bStopped(false),
    m_nMissionParamSize(0), m_pMissionParam(NULL), m_bTeamGame(false), m_pMRPPlayers(NULL), m_nCount(-1), m_fFrameTime(0.0), m_pMRPPackStart(NULL),
    m_pCurMRPPack(NULL)
{
    m_nBOTPlayers = 0;
    m_nLoadingPlayers = 0;
    m_nBroadCastPlayers = 0;
}

CMRPFull::~CMRPFull()
{
    Reset();
}

MWApplication* CMRPFull::Check()
{
    MWApplication* app = MWApplication::GetInstance();
    if (app) {
        if (app->networkingFlag) {
            if (app->serverFlag)
                return app;
        }
    }

    return NULL;
}

bool CMRPFull::IsValidData() const
{
    if (m_pMissionParam) {
        if (m_pMRPPlayers) {
            if (m_pMRPPackStart) {
                return true;
            }
        }
    }

    return false;
}

void CMRPFull::Reset()
{
    FreeString(LocalIPAddress);
    m_bStarting = false;
    m_bStarted = false;
    m_bStopping = false;
    m_bStopped = false;
    while(m_pMRPPackStart) {
        CMRPPack* pNext = m_pMRPPackStart->m_pNext;

        FreeMRPPack(m_pMRPPackStart);
        m_pMRPPackStart = pNext;
    }
    while(m_pMRPPlayers) {
        CMRPPlayer* pNext = m_pMRPPlayers->m_pNext;

        delete m_pMRPPlayers;
        m_pMRPPlayers = pNext;
    }
    if (m_pMissionParam) {
        delete [] m_pMissionParam;
        m_pMissionParam = NULL;
    }

    m_strGameName = (const char*)NULL;
    m_strPlayer = (const char*)NULL;
    m_strPassword = (const char*)NULL;

    m_nMissionParamSize = 0;
    m_nBOTPlayers = 0;
    m_nLoadingPlayers = 0;
    m_nBroadCastPlayers = 0;

    int i;
    for(i = 0; i < m_nCount; i++) {
        free(m_pa[i]);
    }
    m_nCount = -1;
    m_fFrameTime = 0.0;

    m_pCurMRPPack = NULL;
    m_pLastDictionary = m_pLastDictionaryToBeSent = NULL;
}

bool CMRPFull::IsValid() const
{
    if (m_bStarted && (m_nLoadingPlayers > 0) && m_pMRPPackStart) {
        return true;
    }

    return false;
}

void CMRPFull::Loading()
{
}

void CMRPFull::Loaded()
{
}

void CMRPFull::PreRendering()
{
}

void CMRPFull::PreRendered()
{
}

void CMRPFull::Starting()
{
    if (Check()) {
        if (g_nMR == 1)
            m_bStarting = true;
    }
}

void CMRPFull::Started()
{
    MWApplication* app = Check();
    if (app) {
        if (g_nMR == 1) {
            NetMissionParameters::MWNetMissionParameters* params = app->GetLocalNetParams();

            DynamicMemoryStream stream;
            params->SaveParameters(&stream);
	        stream.WriteByteAlign();
	        stream.Rewind();

            m_pMissionParam = new BYTE[stream.GetBufferBytesUsed()];
            memcpy(m_pMissionParam, stream.GetPointer(), stream.GetBufferBytesUsed());
            m_nMissionParamSize = stream.GetBufferBytesUsed();
            m_bTeamGame = !!params->m_teamAllowed;

            m_bStarted = true;
        } else {
        }
    }
}

void CMRPFull::StartFrame()
{
    MWApplication* app = Check();
    if (app) {
        if (g_nMR == 1) {
            if (m_bStarted) {
                MWMission* mission = Cast_Object(MWMission*, MWMission::GetInstance());
                if (mission && (m_nCount == -1)) {
                    m_nCount++;
                    m_fFrameTime = mission->GetMissionTime();
                }
            }
        } else {
        }
    }
}

void CMRPFull::StopFrame()
{
    if (m_nCount != -1) {
        MWApplication* app = Check();
        if (app && (m_nCount > 0)) {
            CMRPPack* pMRPPack = AllocMRPPack(m_nCount, &m_pa[0]);
            if (m_pMRPPackStart) {
                CMRPPack* p = m_pMRPPackStart;
                while(p->m_pNext) {
                    p = p->m_pNext;
                }
                p->m_pNext = pMRPPack;
                pMRPPack->m_pPrev = p;
            } else {
                m_pMRPPackStart = pMRPPack;
            }
            pMRPPack->m_fFrameTime = m_fFrameTime;
        }
        m_nCount = -1;
    }
}

void CMRPFull::ReduceFrame()
{
}

void CMRPFull::Stopping()
{
    if (g_nMR == 1) {
        m_bStopping = true;
    }
}

void CMRPFull::Stopped()
{
    OnGameClose();
}

PMRPPlayer CMRPFull::AddMRPPlayer(bool bBOT)
{
    PMRPPlayer p = NULL;
    if (g_nMR == 1) {
        MWApplication* app = Check();
        if (app) {
            if (g_nMR == 1) {
                p = new CMRPPlayer();
                PMRPPlayer pList = m_pMRPPlayers;

                if (pList) {
                    while(pList->m_pNext) {
                        pList = pList->m_pNext;
                    }
                    pList->m_pNext = p;
                    p->m_pPrev = pList;
                } else {
                    m_pMRPPlayers = p;
                }
                p->m_bBOT = bBOT;
                if (bBOT) {
                    m_nBOTPlayers++;
                } else {
                    if (!m_bStarted) {
                        if (m_bStarting) {
                            m_nBroadCastPlayers++;
                        } else {
                            m_nLoadingPlayers++;
                        }
                    }
                }
            }
        }
    }

    return p;
}

PMRP CMRPFull::AddMRP(int nCommand, int nType, int nLen)
{
    gosASSERT(g_nMR == 1);
    if (m_nCount < 0) {
        // should be frame started...
        StartFrame();
    }

    PMRP pRet = (PMRP)malloc(sizeof(SMRP) + nLen);
    pRet->m_nCommand = nCommand;
    pRet->m_nType = nType;
    pRet->m_nLen = nLen;

    m_pa[m_nCount++] = pRet;

    return pRet;
}

void CMRPFull::OnGameOpen(const char* pcszGameName, DWORD dwMyID, const char* pcszPlayer, const char* pcszPassword)
{
    Reset();
    g_nMR = 0;
    if (!CTCL_IsConsole()) {
        if (!g_bCOOP && CTCL_IsConsoleX()) {
            gosASSERT(g_bIsServer);
            if (g_nMissionReview)
                g_nMR = 1;
        } else {
            if (g_bMRTest)
                g_nMR = 1;
        }
    }
    m_CurrentSession = CurrentSession;
    m_strGameName = pcszGameName;
    m_dwMyDirectPlayID = dwMyID;
    m_strPlayer = pcszPlayer;
    m_strPassword = pcszPassword;
}

void CMRPFull::OnGameClose()
{
    if (g_nMR == 1) {
        StopFrame();
        m_bStopped = true;
        DbgReport();
        if (IsValidData()) {
            char szFile[256];
            if (!g_bCOOP && CTCL_IsConsoleX()) {
                GetFileName4GUID(szFile, "c:", g_pcszGameDataSavePath, g_pcszGameDataExtMR, g_guidGameDatas);
                if (SaveMR(szFile)) {
                    CTCL_SendFile(g_SysTime, g_guidGameDatas, 1);
                }
            } else {
                if (g_bMRTest) {
                    GetFileName4GUID(szFile, "c:", g_pcszGameDataSavePath, g_pcszGameDataExtMR);
                    SaveMR(szFile);
                }
            }
        }
    } else if (g_nMR == 2) {
        QuitReplay();
    }
    g_nMR = 0;
}

void CMRPFull::AddRemovePlayerToGame(int nCommand, char* Name, DPID dpId)
{
    if (!Name)
        Name = "";
#if defined(_DEBUG) && 0 // jcem - for MR test
  {
	char Buffer[128];
    sprintf(Buffer, "Network::RoutePacket() Player(\"%s\") %s\n", Name, (nCommand == MRP_ADD_PLAYER_NAME) ? "Added": "Deleted");
	OutputDebugString(Buffer);
  }
#endif // _DEBUG && ...
/*
    PMRP pMRP = AddMRP(nCommand, 0, strlen(Name) + 1);

    SMRP_PLAYER_NAME& PN = pMRP->m_PlayerName[0];
    PN.m_dpId = dpId;
    strcpy(PN.m_szName, Name);
*/
}

void CMRPFull::AddRemoveConnection(bool bAdd, Connection* pConnection)
{
    gosASSERT(pConnection);
#if defined(_DEBUG) && 0 // jcem - for MR test
  {
	char Buffer[128];
    sprintf(Buffer, "Network::RoutePacket() Connection %s\n", bAdd ? "Added": "Deleted");
	OutputDebugString(Buffer);
  }
#endif // _DEBUG && ...
/*
    PMRP pMRP = AddMRP(bAdd ? gosNet_PlayerAdded: gosNet_PlayerDeleted, 0, sizeof(DWORD));
    pMRP->m_dpID = pConnection->GetNetworkAddress();
*/
}

void CMRPFull::SessionLost()
{
#if defined(_DEBUG) && 0 // jcem - for MR test
  {
	char Buffer[128];
    sprintf(Buffer, "Network::RoutePacket() SessionLost\n");
	OutputDebugString(Buffer);
  }
#endif // _DEBUG && ...
/*
    AddMRP(gosNet_GameEnded, 0, 0);
*/
}

void* CMRPFull::NetInformation(gosNetInfo Info, DWORD Parameter, char* Name)
{
    gosASSERT(g_nMR == 2);
    gosASSERT(InNetworkGame);
    gosASSERT(IAmTheServer);

	static char Buffer[256];
	void* result=0;

	switch( Info )
	{
//
// Returns TRUE if in a networked game
//
		case gos_Networking:
		{
			result=(void*)1;
			return result;
		}
//
// Returns TRUE if you created the game (FALSE=Joined)
//
		case gos_GameSecure:
		{
			result=(void*)(CurrentSession.dwFlags&DPSESSION_SECURESERVER);
			return result;
		}
//
// Returns NULL or pointer to password string
//
		case gos_GamePassword:
		{
			if( PasswordBuffer[0] )
				result=PasswordBuffer;

			return result;
		}
//
// Returns TRUE if the host created the game as a secure game
//
		case gos_AmITheServer:
		{
			result=(void*)1;
			return result;
		}
//
// Returns the number of player in the current game
//
		case gos_NumberOfPlayers:
		{
			DWORD NumPlayers=0;
			ListOfNames* pThis=CurrentPlayers;
			while( pThis )
			{
				NumPlayers++;
				pThis=pThis->pNext;
			}
			result=(void*)NumPlayers;

			return result;
		}
	
//
// Returns a char* for the ip address
//
		case gos_MyIPAddress:
		{
			result=(void*)MyIPAddress;	
			return result;
		}

//
// Returns a DWORD for this machines player NUMBER
//
		case gos_MyID:
		{
			result=(void*)MyDirectPlayID;
			return result;
		}
//
// Returns a DWORD for the servers player NUMBER
//
		case gos_ServerID:
		{
			if( Environment.NetworkGame && Connected )
				result=(void*)DPID_SERVERPLAYER;

			return result;
		}
//
// Returns a DWORD for ALL players (broadcast)
//
		case gos_AllID:
		{
			if( Environment.NetworkGame && Connected )
				result=(void*)DPID_ALLPLAYERS;

			return result;
		}
//
// Returns a player ID for the player NUMBER passed in the parameter
//
		case gos_PlayerID:
		{
			DWORD NumPlayers=0;
			ListOfNames* pThis=CurrentPlayers;
			while( pThis )
			{
				if( NumPlayers==Parameter )
				{
					result=(void*)pThis->Data;
					break;
				}
				NumPlayers++;
				pThis=pThis->pNext;
			}

			return result;
		}
//
// Returns a NUMBER for the player ID passed in the parameter (or 0xffffffff if not found)
//
		case gos_PlayerNumber:
		{
			result=(void*)0xffffffff;
			DWORD NumPlayers=0;
			ListOfNames* pThis=CurrentPlayers;
			while( pThis )
			{
				if( pThis->Data==Parameter )
				{
					result=(void*)NumPlayers;
					break;
				}
				NumPlayers++;
				pThis=pThis->pNext;
			}

			return result;
		}
//
// Returns a char* for the player NUMBER passed in the parameter
//
		case gos_PlayerName:
		{
			result=(void*)"";
			DWORD NumPlayers=0;
			ListOfNames* pThis=CurrentPlayers;
			while( pThis )
			{
				if( NumPlayers==Parameter )
				{
					result=(void*)pThis->Name;
				}
				NumPlayers++;
				pThis=pThis->pNext;
			}

			return result;
		}
//
// Returns if the game is currently locked
//
		case gos_LockedStatus:
		{
			result=(void*)(CurrentSession.dwFlags&DPSESSION_JOINDISABLED ? 1 : 0);

			return result;
		}
//
// Returns number of packets sent in the past frame to the player NUMBER passed
//
		case gos_PacketsSentLastFrame:
		{
			PacketLogging* pThis=pDebugPacketLog;
			DWORD PlayerID=(DWORD)gos_NetInformation(gos_PlayerID);
			DWORD Counter=0;
			/*while( pThis )
			{
				if( CurrentFrameNumber-1==pThis->FrameNumber && PlayerID==pThis->ToID )
					Counter++;
				pThis=pThis->pNext;
			}*/
			result=(void*)Counter;

			return result;
		}
//
// Returns number of packets recieved in the past Frame from the player NUMBER passed
//
		case gos_PacketsFromLastFrame:
		{
			PacketLogging* pThis=pDebugPacketLog;
			DWORD PlayerID=(DWORD)gos_NetInformation(gos_PlayerID);
			DWORD Counter=0;
			/*while( pThis )
			{
				if( CurrentFrameNumber-1==pThis->FrameNumber && PlayerID==pThis->FromID )
					Counter++;
				pThis=pThis->pNext;
			}*/
			result=(void*)Counter;

			return result;
		}
//
// Returns number of bytes sent in the past Frame to the player NUMBER passed
//
		case gos_BytesSentLastFrame:
		{
			PacketLogging* pThis=pDebugPacketLog;
			DWORD PlayerID=(DWORD)gos_NetInformation(gos_PlayerID);
			DWORD Counter=0;
			/*while( pThis )
			{
				if( CurrentFrameNumber-1==pThis->FrameNumber && PlayerID==pThis->ToID )
					Counter+=pThis->Size;
				pThis=pThis->pNext;
			}*/
			result=(void*)Counter;

			return result;
		}
//
// Returns number of bytes recieved in the past Frame from the player NUMBER passed
//
		case gos_BytesFromLastFrame:
		{
			PacketLogging* pThis=pDebugPacketLog;
			DWORD PlayerID=(DWORD)gos_NetInformation(gos_PlayerID);
			DWORD Counter=0;
			/*while( pThis )
			{
				if( CurrentFrameNumber-1==pThis->FrameNumber && PlayerID==pThis->FromID )
					Counter+=pThis->Size;
				pThis=pThis->pNext;
			}*/
			result=(void*)Counter;

			return result;
		}
//
// Returns total number of bytes sent in the past Frame to the player NUMBER passed (including packet overhead)
//
		case gos_BandwithSentLastFrame:
		{
			PacketLogging* pThis=pDebugPacketLog;
			DWORD PlayerID=(DWORD)gos_NetInformation(gos_PlayerID);
			DWORD Counter=0;
			/*while( pThis )
			{
				if( CurrentFrameNumber-1==pThis->FrameNumber && PlayerID==pThis->ToID )
					Counter+=pThis->Size+PACKET_OVERHEAD;
				pThis=pThis->pNext;
			}*/
			result=(void*)Counter;

			return result;
		}
//
// Returns total number of bytes recieved in the past Frame from the player NUMBER passed (including packet overhead)
//
		case gos_BandwithFromLastFrame:
		{
			PacketLogging* pThis=pDebugPacketLog;
			DWORD PlayerID=(DWORD)gos_NetInformation(gos_PlayerID);
			DWORD Counter=0;
			/*while( pThis )
			{
				if( CurrentFrameNumber-1==pThis->FrameNumber && PlayerID==pThis->FromID )
					Counter+=pThis->Size+PACKET_OVERHEAD;
				pThis=pThis->pNext;
			}*/
			result=(void*)Counter;

			return result;
		}
//
// Returns number of packets lost from the player NUMBER passed (based on packet numbers and retries)
//
		case gos_PacketsLostLastFrame:
		{
			return (void*)0;
		}
//
// Returns the average ping time for any guaranteed packets sent in the last frame to the player NUMBER
//
		case gos_LatencyLastFrame:
		{
			return (void*)0;
		}
//
// Returns the number of packets still in the send queue
//
		case gos_GetMessageSendQueue:
		{
			result=(void*)0;

			return result;
		}
//
// Returns the number of Games found on network (or 1 if in a network game)
//
		case gos_NumberOfGames:
		{
			result=(void*)1;

			return result;
		}
//
// Returns the name of the Game with the parameter passed   (If in a game, returns this games name)
//
		case gos_NameOfGame:
		{
			result=(void*)"";
			
			if( 0==Parameter )
				result=(void*)CurrentSession.lpszSessionNameA;

			return result;
		}
//
// Returns true if the game name passed is passworded, Name=Game Name
//
		case gos_IsGamePassworded:
		{
			result=(void*)((CurrentSession.dwFlags&DPSESSION_PASSWORDREQUIRED) ? 1 : 0);

			return result;
		}
//
// Returns true if the game name passed is secure, Name=Game Name
//
		case gos_IsGameSecure:
		{
			result=(void*)((CurrentSession.dwFlags&DPSESSION_SECURESERVER) ? 1 : 0);
			return result;
		}
//
// Returns true if the game name passed is locked so no more players can enter, Name=Game Name
//
		case gos_IsGameLocked:
		{
			result=(void*)((CurrentSession.dwFlags&DPSESSION_JOINDISABLED) ? 1 : 0);

			return result;
		}
//
// Returns maximum number of players in a game, Name=Game Name
//
		case gos_MaxPlayersInGame:
		{
			result=(void*)CurrentSession.dwMaxPlayers;

			return result;
		}
//
// Returns a pointer to 16 bytes of information from the game, Name=Game Name  (Games set this in Environment.NetGameInfo)
//
		case gos_InformationAboutGame:
		{
			result=(void*)&CurrentSession.dwUser1;
			return result;
		}
//
// Returns number of players in a game, Name=Game Name   (If in a game, returns player in this game)
//
		case gos_NumberOfPlayersInGame:
		{
			result=gos_NetInformation(gos_NumberOfPlayers);
			return result;
		}
//
// Return players name - Parameter=Player #, Name=Game Name.   (If in a game, returns players name in this game)
//
		case gos_NameOfPlayersInGame:
		{
			result=gos_NetInformation(gos_PlayerName,Parameter);

			return result;
		}
//
// Returns the number of modems installed
//
		case gos_NumberOfModems:
		{
			DWORD ModemNumber=0;
			result=(void*)ModemNumber;

			return result;
		}
//
// Returns the name of the modem number passed
//
		case gos_NameOfModem:
		{
			result=(void*)"";

			return result;
		}
//
// Returns the number of serial ports installed
//
		case gos_NumberOfSerialPorts:
		{
			DWORD PortNumber=0;
			result=(void*)PortNumber;

			return result;
		}
//
// Returns the name of the serial port number passed
//
		case gos_NameOfSerialPort:
		{
			result=(void*)"";

			return result;
		}
/* To be added once UI queries required decided
//
// Returns the status of the ZoneTech matchmaking connect attempt for game server
// 0 is success, 1 not yet tried, 2 pending, 3 failed, 4 lost connection
//
		case gos_GameRegistrationStatus:
		{
			DWORD status = 1;
			
			IZoneAsync::STATUS actual =IZoneAsync::STATUS_FAILED;
			
			if (g_pZMAsync)
			{
				g_pZMAsync->GetStatus(&actual);
				switch (actual)
				{
				case IZoneAsync::STATUS_COMPLETED:
					status =0;	
					break;
				case IZoneAsync::STATUS_STARTING:
					status = 2;
					break;
				default:
					status = 3;
					break;
				}
			}
			
			return (void*) status;
			
		}
//
// Returns the status of the ZoneTech matchmaking connect attempt for game joiner
// 0 is success, 1 not yet tried, 2 pending, 3 failed, 4 lost connection
//
		case gos_GameBrowseStatus:
		{
			DWORD status = 1;
			
			IZoneAsync::STATUS actual =IZoneAsync::STATUS_FAILED;
			
			if (g_pZMAsync)
			{
				g_pZMAsync->GetStatus(&actual);
				switch (actual)
				{
				case IZoneAsync::STATUS_COMPLETED:
					status =0;	
					break;
				case IZoneAsync::STATUS_STARTING:
					status = 2;
					break;
				default:
					status = 3;
					break;
				}
			}
			
			return (void*) status;
			
		}
//
//
//
*/
#ifdef OUTBOUND_WINDOW
		case gos_GetNumOutboudWindows:
			OutboundWindow * pOW;
			pOW = OutboundWindow::m_pHead;
			int i;
			i=0;
			while (pOW)
			{
				i++;
				pOW = pOW->m_pNext;
			}
			return (void *)i;
			break;

		case gos_GetOutboundWindowSize:
			pOW = OutboundWindow::m_pHead;
			while (pOW)
			{
				if (Parameter==0)
					break;
				Parameter--;
				pOW = pOW->m_pNext;
			}
			if (Parameter != 0)
				return (void *)-1;
			return (void *)(pOW->m_NextPacketNumberToSend - pOW->m_LastPacketTheyReceived);
			break;

		case gos_GetOutboundWindowSizeDpid:
			pOW=OutboundWindow::Find(Parameter);
			if (pOW)
			{
				return (void *)(pOW->m_NextPacketNumberToSend - pOW->m_LastPacketTheyReceived);
			}
			
			return (void *)-10000;
		
			break;

		case gos_GetOB_NxtPkt2Send:
			pOW = OutboundWindow::m_pHead;
			while (pOW)
			{
				if (Parameter==0)
					break;
				Parameter--;
				pOW = pOW->m_pNext;
			}
			if (Parameter != 0)
				return (void *)-1;
			return (void *)(pOW->m_NextPacketNumberToSend);
			break;

		case gos_GetOB_LstPktRcvd:
			pOW = OutboundWindow::m_pHead;
			while (pOW)
			{
				if (Parameter==0)
					break;
				Parameter--;
				pOW = pOW->m_pNext;
			}
			if (Parameter != 0)
				return (void *)-1;
			return (void *)(pOW->m_LastPacketWeReceived);
			break;

		case gos_GetOB_LstPktTheyRcvd:
			pOW = OutboundWindow::m_pHead;
			while (pOW)
			{
				if (Parameter==0)
					break;
				Parameter--;
				pOW = pOW->m_pNext;
			}
			if (Parameter != 0)
				return (void *)-1;
			return (void *)(pOW->m_LastPacketTheyReceived);
			break;

#else
		case gos_GetNumOutboudWindows:
		case gos_GetOutboundWindowSize:
		case gos_GetOB_NxtPkt2Send:
		case gos_GetOB_LstPktRcvd:
		case gos_GetOB_LstPktTheyRcvd:
			return 0;
			break;
#endif

		default:
			STOP(( "Unknown info %d",Info ));
	}
	return 0;
}

void CMRPFull::NetServerCommands(gos_NetCommands Command, DWORD Data1)
{
    gosASSERT(g_nMR == 2);

	switch( Command )
	{
//
// Remove the player with PlayerID == Data1 from the game
//
		case gos_Command_KillPlayer:
		{
			gosASSERT( InNetworkGame && IAmTheServer && Data1!=MyDirectPlayID );			// Not allowed to delete yourself like this
			//wDestroyPlayer( dplay4, Data1 );				// Allow any ID - so players already dead / dieing don't cause an error
			return;
		}
//
// Datat1=1 to lock the game, 0=to unlock the game - no more players can join when a game is locked
//
		case gos_Command_LockGame:
		{
			gosASSERT( InNetworkGame && IAmTheServer );

			CurrentSession.dwFlags&=~(DPSESSION_JOINDISABLED|DPSESSION_NEWPLAYERSDISABLED);
			if( Data1 )
			    CurrentSession.dwFlags|=DPSESSION_JOINDISABLED|DPSESSION_NEWPLAYERSDISABLED;
			break;
		}
//
// Updates the 'game data' from Environment.NetGameInfo - so players enumerating games can see the changes
//
		case gos_Command_UpdateGameData:
		{
			gosASSERT( InNetworkGame && IAmTheServer );
			break;
		}
//
// Updates the number of maximum players allowed in a game from Environment.NetworkMaxPlayers
//
		case gos_Commend_UpdateMaxPlayers:
		{
			gosASSERT( InNetworkGame && IAmTheServer );
			
			CurrentSession.dwMaxPlayers=Environment.NetworkMaxPlayers;
			break;
		}

		default:
			STOP(( "Bad command" ));
	}
}

NetPacket* CMRPFull::NetGetMessage()
{
    gosASSERT(g_nMR == 2);
    MWApplication* app = Check();
    if (app && app->GetApplicationState() == ApplicationStateEngine::RunningGameState) {
    }
    return (NetPacket*)NULL;
}

bool CMRPFull::LocalSendNetMessage(int message_type, Stuff::MemoryStream& message)
{
    if (g_nMR == 1) {
        switch(message_type) {
        case MWEntityManager::DictionaryIndexMessageID:
        case MWEntityManager::WeaponBundleMessageID:
        case MWApplication::ScoreFormatMessageID:
        case MWApplication::ScoreMessageID:
            SendMessage(message_type, &message);
            return false;
        default:
            if ((MWEntityManager::DictionaryPage0MessageID <= message_type) && (message_type < MWEntityManager::DictionaryPageMaxMessageID)) {
                SendMessage(message_type, &message);
                return false;
            }
            break;
        }
    } else if (g_nMR == 2) {
        switch(message_type) {
        case MWApplication::RequestNewDictionaryMessageID:
            if (m_pLastDictionary) {
                m_pLastDictionaryToBeSent = m_pLastDictionary;
            }
            return false;
        }
    }

    return true;
}

void CMRPFull::BackgroundTack()
{
    gosASSERT(g_nMR == 2);
    MWApplication* app = Check();
    if (app) {
        if (app->GetApplicationState() == ApplicationStateEngine::RunningGameState) {
            MWEntityManager* pMWENTMGR = MWEntityManager::GetInstance();
            if (m_pLastDictionaryToBeSent) {
                PMRP pMRP = m_pLastDictionaryToBeSent;
                m_pLastDictionaryToBeSent = NULL;
                Stuff::MemoryStream message(&pMRP->m_ba[0], pMRP->m_nLen);
                pMWENTMGR->UpdateClientEntites(1, pMRP->m_nType, &message);
                return;
            }
            if (m_pCurMRPPack) {
                MWMission* mission = Cast_Object(MWMission*, MWMission::GetInstance());
                Scalar fFrameTime = mission->GetMissionTime();
                if (m_pCurMRPPack->m_fFrameTime <= fFrameTime) {
                    int i;

		            for(i = 0; i < Maximum_Players; ++i)
		            {
                        if (app->servedConnectionData[i].clientLoaded) {
                            if (pMWENTMGR->serverController->waitingForRespawn[i]) {
                                Mech *vehicle = (Mech *)app->servedConnectionData[i].clientPlayer->vehicle; // pMWENTMGR->playerVehicle[i];
                                if (vehicle) {
                                    pMWENTMGR->serverController->waitingForRespawn[i] = false;
					                Point3D trans;
					                YawPitchRoll rot;
					                vehicle->GetDeadReckonedNetworkPosition(trans, rot);
					                vehicle->ClearNetworkPosition();
					                LinearMatrix4D drop_position;
					                drop_position.BuildTranslation(trans);
					                drop_position.BuildRotation(rot);

					                vehicle->SetNewLocalToParent(drop_position);
					                vehicle->SyncMatrices(true);
					                Map::GetInstance()->UpdateZone(vehicle);
                                }
                            }
                        }
				    }

                    int nCount = m_pCurMRPPack->m_nCount;
                    for(i = 0; i < nCount; i++) {
                        PMRP pMRP = m_pCurMRPPack->m_pa[i];
                        switch(pMRP->m_nCommand) {
                        case 0:
                          {
                            Stuff::MemoryStream message(&pMRP->m_ba[0], pMRP->m_nLen);
                            switch(pMRP->m_nType)
                            {
                            case MWApplication::ScoreFormatMessageID:
                            case MWApplication::ScoreMessageID:
                                app->ReceiveDirectMessage(1, pMRP->m_nType, &message);
                                break;
                            default:
                                pMWENTMGR->UpdateClientEntites(1, pMRP->m_nType, &message);
                                if (pMRP->m_nType == MWEntityManager::DictionaryIndexMessageID) {
                                    m_pLastDictionary = pMRP;
                                }
                            }
                            break;
                          }
                        case MRP_RESPAWNMESSAGEID:
                          {
                            Stuff::MemoryStream message(&pMRP->m_ba[0], pMRP->m_nLen);

                            int nIdx = pMRP->m_nType;
                            if (nIdx < 0) {
                                nIdx++;
                                nIdx = -nIdx; // lancemate...
                                app->lancemateConnectionData[nIdx].lancemateMech->respawnCount+=1;
                                app->RespawnLancemateMessageHandler(1, &message);
                            } else {
                                app->servedConnectionData[nIdx].clientPlayer->GetVehicle()->respawnCount += 1;
                                EntityManager::GetInstance()->SetPlayerReady(app->servedConnectionData[nIdx].clientPlayer->vehicle);
                                app->RespawnMessageHandler(1, &message);
                            }
                            break;
                          }
                        case MRP_FULLCONFIRM:
                          {
                            int nWritten = pMRP->m_nType;
                            Stuff::MemoryStream message(&pMRP->m_ba[0], pMRP->m_nLen);
		                    int version = 0;
		                    message.ReadBits(&version,8);

		                    Dictionary *dictionary = pMWENTMGR->GetDictionaryManager(1)->GetDictionary(version);

		                    if (dictionary != NULL)
		                    {
			                    int rate_type = pMWENTMGR->bitManager->GetUpdateRate(UpdateManager::MechPositionUpdateID, dictionary->dictionaryBandwidth).m_ActiveRate;
			                    Scalar rate = DictionaryPage::CalculateSeconds(rate_type);

                                while(nWritten-- > 0) {
		                            BYTE connectionID;
		                            WORD localID;
                                    message.ReadBits(&connectionID, 8);
                                    message.ReadBits(&localID, 16);

                                    ReplicatorID id(connectionID, localID);

                                    Entity* pEntity = NULL;
			                        Connection* con2 = Network::GetInstance()->GetConnection(id.connectionID);
			                        if (con2 != NULL) {
				                        Check_Object(con2);
				                        pEntity = (Entity*)con2->FindReplicator(id);
                                        if (pEntity && !pEntity->IsDerivedFrom(MechWarrior4::Mech::DefaultData)) {
                                            pEntity = NULL;
                                        }
                                    }
                                    if (pEntity) {
			                            MechPositionUpdate::Decode(pEntity, &message, 0.0, 0.0f, 1, dictionary->debugDictionaryLevel, dictionary->dictionaryBandwidth, rate);
			                            ExternalJumpJetUpdate::Decode(pEntity, &message, 0.0, 0.0f, 1, dictionary->debugDictionaryLevel, dictionary->dictionaryBandwidth, rate);
                                        MechInternalDamageUpdate::Decode(pEntity, &message, 0.0, 0.0f, 1, dictionary->debugDictionaryLevel, dictionary->dictionaryBandwidth, rate);
                                    } else {
                                        MechPositionUpdate::Skip(&message, 0, 0.0, 1, dictionary->debugDictionaryLevel, dictionary->dictionaryBandwidth);
                                        ExternalJumpJetUpdate::Skip(&message, 0, 0.0, 1, dictionary->debugDictionaryLevel, dictionary->dictionaryBandwidth);
                                        MechInternalDamageUpdate::Skip(&message, 0, 0.0, 1, dictionary->debugDictionaryLevel, dictionary->dictionaryBandwidth);
                                    }

                                    message.ReadByteAlign();
                                }
		                    }
                            break;
                          }
                        case MRP_MECHDAMAGETAKEN:
                          {
                            const SMRP_MECH_DAMAGETAKEN& t = pMRP->m_MDT[0];
	                        ReplicatorID victim(t.m_bCon1, t.m_wLID1);
	                        Connection *vicConn = Network::GetInstance()->GetConnection(victim.connectionID);
	                        if (vicConn != 0)
	                        {
		                        Check_Object(vicConn);
		                        Replicator* repVict = vicConn->FindReplicator(victim);

		                        if (repVict)
		                        {
			                        ReplicatorID inflicting(t.m_bCon2, t.m_wLID2);
			                        Connection *inflConn = Network::GetInstance()->GetConnection(inflicting.connectionID);
			                        if (inflConn != 0)
			                        {
				                        Check_Object(inflConn);
				                        Replicator* repInfl = inflConn->FindReplicator(inflicting);

				                        if (repInfl)
				                        {
					                        // pass attacker and victim to spectator state engine
                                            if ((t.m_damageType == BeamDamageType) || (t.m_damageType == MissileDamageType) || (t.m_damageType == ProjectileDamageType)) {
                                                Mech_CheckDamage(repVict, repInfl);
                                            }
				                        }
			                        }
		                        }
	                        }
                          }
                        }
                    }
                    m_pCurMRPPack = m_pCurMRPPack->m_pNext;
                }
            } else {
                app->QueStopGame();
            }
        }
    }
}

PMRP CMRPFull::SendMessage(int message_type, Stuff::MemoryStream *message, int nCommand/* = 0*/)
{
    gosASSERT(g_nMR == 1);
    PMRP pMRP;
    if (message) {
		message->WriteByteAlign();
		message->Rewind();
        int nLen = message->GetBufferBytesUsed();
        const unsigned char* pSrc = (const unsigned char*)message->GetPointer();

        pMRP = AddMRP(nCommand, message_type, nLen);
        if (nLen > 0) {
            memcpy(&pMRP->m_ba[0], pSrc, nLen);
        }
    } else {
        pMRP = AddMRP(nCommand, message_type, 0);
    }

    return pMRP;
}

void g_MRF_MechDamageTaken(ReplicatorID id1, ReplicatorID id2, Stuff::Scalar damage_taken, int weaponID, int damageType)
{
    g_MRF.MechDamageTaken(id1, id2, damage_taken, weaponID, damageType);
}

void CMRPFull::MechDamageTaken(ReplicatorID mech1, ReplicatorID mech2, Stuff::Scalar damage_taken, int weaponID, int damageType)
{
    PMRP pMRP = AddMRP(MRP_MECHDAMAGETAKEN, 0, sizeof(SMRP_MECH_DAMAGETAKEN));
    SMRP_MECH_DAMAGETAKEN& t = pMRP->m_MDT[0];
    t.m_fDamage = damage_taken;
    t.m_bCon1 = mech1.connectionID;
    t.m_weaponID = weaponID;
    t.m_wLID1 = mech1.localID;
    t.m_bCon2 = mech2.connectionID;
    t.m_damageType = damageType;
    t.m_wLID2 = mech2.localID;
}

void _cdecl CMRPFull::SendCommand(int nCommand, ...)
{
}

void CMRPFull::DoReplay()
{
    g_nMR = 2;
    CTCL_SetGameState(_EGS_Preparing);

    MWApplication* app = MWApplication::GetInstance();

    g_pfn_NETINFORMATION = MRP_NetInformation;
    g_pfn_NETSERVERCOMMANDS = MRP_NetServerCommands;
    g_pfn_NETGETMESSAGE = MRP_NETGETMESSAGE;
    g_pfn_BACKGROUNDTACK = MRP_BACKGROUNDTACK;
    m_pCurMRPPack = m_pMRPPackStart;
    m_pLastDictionary = NULL;
    m_pLastDictionaryToBeSent = NULL;
    g_pfn_NETSENDMESSAGE = MRP_NETSENDMESSAGE;
  // see - CTCL_DoCreateGame() for full processing

  // see - gos_NetStartGame
	// store secure state
	gInSecureGame=MWApplication::SecureNetGame; // true;

	// initialize GameOS variables
	gos_InitializeNetworking();

	// get the ip address
	//
    UnRegisterData();
    RegisterData();
	AllocString(LocalIPAddress);

	CancelDialup(NULL, 0, NULL);
	LoadMPConnectionSettings(NULL, 0, NULL);
	InitConnectionWizard(NULL, 0, NULL);

    ConnectionIndex = 0;
    PreConnect(NULL, 0, NULL);

  // Mech4CreateGame -> gos_CreateGame -> InternalCreateGame
#ifdef OUTBOUND_WINDOW
	OutboundWindow::CleanAll();
#endif
    CurrentSession = m_CurrentSession;
    MyDirectPlayID = m_dwMyDirectPlayID;
    gosASSERT(m_strGameName.GetLength() > 0);

    GUID guid = gos_GenerateUniqueGUID();
    sprintf(GameNameBuffer, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
            guid.Data1, guid.Data2, guid.Data3,
            guid.Data4[0], guid.Data4[1],
            guid.Data4[2], guid.Data4[3], guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]);
    // strcpy(GameNameBuffer, m_strGameName);

    if ((const char*)m_strPassword)
        strcpy(PasswordBuffer, m_strPassword);
    else
        PasswordBuffer[0] = '\0';
	InNetworkGame=1;
	IAmTheServer=1;

    // GetCurrentPlayers();
    CMRPPlayer* pPlayer;
    
    // find server
    pPlayer = m_pMRPPlayers;
    while(pPlayer->m_bBOT || (pPlayer->m_connection_id != 1)) {
        pPlayer = pPlayer->m_pNext;
        gosASSERT(pPlayer);
    }

    // add server...
    gos_RealAddPlayerToGame(&CurrentPlayers, pPlayer->m_strName, MyDirectPlayID);

  // see - CTCL_DoGame1st()
    g_bIsServer = true;
    app->networkingFlag = true;
    app->serverFlag = true;

	if (Network::GetInstance() == NULL)
	{
		gos_PushCurrentHeap(MechWarrior4::Heap);
		Verify(!Network::GetInstance());
		GlobalPointers::AddGlobalPointer(new Network, NetworkGlobalPointerIndex);
		Register_Object(Network::GetInstance());
		gos_PopCurrentHeap();
	}

	app->SaveServerOptions();
	
#if defined(LAB_ONLY)
	MWGameInfo::g_lastGameType = MWGameInfo::g_currentGameType;
	MWGameInfo::g_currentGameType = MWGameInfo::MultiServer;
#endif

	//app->LoadServerOptions();
	//app->SendRequestConnectionMessage();

	for (int i = 0; i < Maximum_Lancemates; ++i)
	{
		app->lancemateConnectionData[i].Disconnect();
	}

	app->memoryDiffKiller.Init();

    gosASSERT(MW4Shell::NetConnectedToServer(NULL, 0, NULL));

    CTCL_InitMechDatas();

    MW4Shell::Instance->InitNetworkScenarios(NULL, 0, (void**)NULL);

  // see - CTCL_SetMissionParams();
    CTCL_SetMissionParamsBy(m_pMissionParam, m_nMissionParamSize);

	// MWApplication::AcceptConnectionMessageHandler(int connection, Stuff::MemoryStream *message)
    // add bot !players
    pPlayer = m_pMRPPlayers;
    while(pPlayer) {
        if (pPlayer->m_bBOT) {
            MechWarrior4::LancemateConnectionData& lcd = app->lancemateConnectionData[pPlayer->m_connection_id];
	        lcd.lancemateConnected = true;
	        lcd.lancemateVehicleAccepted = true;

	        strcpy(lcd.lancemateName, pPlayer->m_strName);
	        strcpy(lcd.lancemateClan, pPlayer->m_strClan);
		    strcpy(lcd.scriptName, pPlayer->m_strScript);
            lcd.aiModel = pPlayer->m_aiModel;

            lcd.pilotTeam = pPlayer->m_pilotTeam;
            //lcd.pilotDecals = pPlayer->m_pilotDecals;
            //lcd.teamDecals = pPlayer->m_teamDecals;
            lcd.mechChasisID = pPlayer->m_mechChasisID;
            //lcd.pilotSkins = pPlayer->m_pilotSkins;
            lcd.tonnage = pPlayer->m_tonnage;
            //lcd.clientKey = 1000;
            MemoryStream* pVCM = pPlayer->m_vehicleCreateMessage;
            BYTE* pData = new BYTE[pVCM->GetSize()];
            memcpy(pData, pVCM->GetPointer(), pVCM->GetSize());
            lcd.lancemateCreateMessage = new MemoryStream(pData, pVCM->GetSize());
        }
        pPlayer = pPlayer->m_pNext;
    }
    // add players !bot
    pPlayer = m_pMRPPlayers;
    while(pPlayer) {
        if (!pPlayer->m_bBOT) {
            MechWarrior4::ServedConnectionData& scd = app->servedConnectionData[pPlayer->m_connection_id];
            if (pPlayer->m_connection_id != 1) {
                gos_RealAddPlayerToGame(&CurrentPlayers, pPlayer->m_strName, 0);

                Network::GetInstance()->Set_nextConnectionID(pPlayer->m_connection_id);
                Network::GetInstance()->net_AddPlayer(pPlayer->m_strName, pPlayer->m_connection_id);
            }
            gosASSERT(scd.clientConnected);
		    if (scd.clanName)
		    {
			    delete scd.clanName;
			    scd.clanName = NULL;
		    }

		    int clan_size = strlen(pPlayer->m_strClan) + 1;

		    scd.clanName = new char[clan_size];
            strcpy(scd.clanName, pPlayer->m_strClan);

            scd.clientVehicleAccepted = true;

            scd.clientReady = true;
            scd.clientSentScoreFormat = false;
            scd.clientAllowTransfer = false;
            scd.clientQuedForLaunch = true;

            scd.pilotTeam = pPlayer->m_pilotTeam;
            scd.pilotDecals = pPlayer->m_pilotDecals;
            scd.teamDecals = pPlayer->m_teamDecals;
            scd.mechChasisID = pPlayer->m_mechChasisID;
            scd.pilotSkins = pPlayer->m_pilotSkins;
            scd.tonnage = pPlayer->m_tonnage;
            //scd.clientKey = 1000;
            MemoryStream* pVCM = pPlayer->m_vehicleCreateMessage;
            BYTE* pData = new BYTE[pVCM->GetSize()];
            memcpy(pData, pVCM->GetPointer(), pVCM->GetSize());
            scd.vehicleCreateMessage = new MemoryStream(pData, pVCM->GetSize());
        }
        pPlayer = pPlayer->m_pNext;
    }

  // see - CTCL_SetMechs();

  // see - CTCL_CheckClientReady();
	app->lastMapCRC = -1;
	app->haveNetworkMap = true;

  // see - CTCL_CheckServerReady()
    // app->VerifyAllPlayerVehicles();

    // void CTCL_StartGame(BOOL bRealLaunch -> false)
	MW4Shell::Instance->EndAllScripts();
	MW4Shell::Instance->currentShellRunning = MW4Shell::MainShellRunning; //MW4Shell::NoShellRunning;
	MW4Shell::Instance->shellCommand = MW4Shell::StartNetworkGameCommand;
	MW4Shell::Instance->shellStart = MW4Shell::MainShellStart;

    // app->CTCL_CheckRunningStart();
    // if (GetApplicationState() == ApplicationStateEngine::PreRenderState)
    // CTCL_StartGame(TRUE);
}

void CMRPFull::QuitReplay()
{
    gos_ShutdownNetwork();

    g_pfn_NETSENDMESSAGE = NULL;
    g_pfn_BACKGROUNDTACK = NULL;
    m_pLastDictionaryToBeSent = NULL;
    m_pLastDictionary = NULL;
    m_pCurMRPPack = NULL;
    g_pfn_NETGETMESSAGE = NULL;
    g_pfn_NETSERVERCOMMANDS = NULL;
    g_pfn_NETINFORMATION = NULL;
}

int CMRPFull::GetMemSize() const
{
    int nSize = sizeof(CMRPFull);

    nSize += m_strGameName.GetLength() + 1;
    nSize += m_strPlayer.GetLength() + 1;
    nSize += m_strPassword.GetLength() + 1;
    nSize += m_nMissionParamSize;

    CMRPPlayer* p1 = m_pMRPPlayers;
    while(p1) {
        nSize += p1->GetMemSize();
        nSize += sizeof(int);
        p1 = p1->m_pNext;
    }

    CMRPPack* p2 = m_pMRPPackStart;
    while(p2) {
        nSize += p2->GetMemSize();
        nSize += sizeof(int);
        nSize += p2->m_nCount;
        p2 = p2->m_pNext;
    }

    return nSize;
}

void CMRPFull::DbgReport() const
{
#if 0
    MString str;
	char Buffer[128];

    str = "";
    sprintf(Buffer, "CMRPFull: %d, m_CurrentSession: %d, m_nMissionParamSize: %d\n", sizeof(CMRPFull), sizeof(m_CurrentSession), m_nMissionParamSize);
    str += Buffer;
	OutputDebugString(Buffer);

    int nPlayersSize = 0;
    CMRPPlayer* p1 = m_pMRPPlayers;
    while(p1) {
        nPlayersSize = p1->GetMemSize();
        p1 = p1->m_pNext;
    }
    sprintf(Buffer, "nPlayersSize: %d, %f, m_nBOTPlayers: %d, m_nLoadingPlayers: %d\n", nPlayersSize, (1.0 * nPlayersSize) / (1.0 * (m_nBOTPlayers + m_nLoadingPlayers + m_nBroadCastPlayers)), m_nBOTPlayers, m_nLoadingPlayers);
    str += Buffer;
	OutputDebugString(Buffer);

    int nMRPPacks = 0;
    int nMRPPackSize = 0;
    CMRPPack* p2 = m_pMRPPackStart;
    while(p2) {
        nMRPPackSize += p2->GetMemSize();
        nMRPPacks++;
        p2 = p2->m_pNext;
    }
    sprintf(Buffer, "nMRPPacks: %d, nMRPPackSize: %d, %f\n", nMRPPacks, nMRPPackSize, (1.0 * nMRPPackSize) / (1.0 * nMRPPacks));
    str += Buffer;
	OutputDebugString(Buffer);

    Scalar f;
    //(m_fFrameTime / 60): total = 1: f
    // f = total * 60 / m_fFrameTime;
    f = 60.0 * (nPlayersSize + nMRPPackSize) / m_fFrameTime;
    f /= 1024.0;
    sprintf(Buffer, "====\nTotalSize: %f kb, %f seconds(%f kb per minutes)\n", (1.0 * (nPlayersSize + nMRPPackSize)) / 1024.0, m_fFrameTime, f);
    str += Buffer;
	OutputDebugString(Buffer);

    FILE* file = fopen("c:\\mr-info.txt", "wb");
    if (file) {
        fputs(str, file);
        fclose(file);
    }
#endif
}

bool CMRPFull::SaveMR(const char* pcszFile)
{
    gosASSERT(pcszFile && pcszFile[0]);

    FILE* f = fopen(pcszFile, "wb");
    if (f) {
        Stuff::DynamicMemoryStream mf(GetMemSize());

        mf.WriteBytes(&g_dwMR_Meta, sizeof(g_dwMR_Meta));
        mf.WriteBytes(&m_CurrentSession, sizeof(m_CurrentSession));
        mf << m_strGameName;
        mf.WriteBytes(&m_dwMyDirectPlayID, sizeof(m_dwMyDirectPlayID));
        mf << m_strPlayer;
        mf << m_strPassword;
        mf.WriteBit(m_bStarting);
        mf.WriteBit(m_bStarted);
        mf.WriteBit(m_bStopping);
        mf.WriteBit(m_bStopped);
        mf.WriteBit(m_bTeamGame);
        mf.WriteByteAlign();
        mf.WriteBytes(&m_nMissionParamSize, sizeof(m_nMissionParamSize));
        mf.WriteBytes(m_pMissionParam, m_nMissionParamSize);
        mf.WriteBytes(&m_nBOTPlayers, sizeof(m_nBOTPlayers));
        mf.WriteBytes(&m_nLoadingPlayers, sizeof(m_nLoadingPlayers));
        mf.WriteBytes(&m_nBroadCastPlayers, sizeof(m_nBroadCastPlayers));
        int n = m_nBOTPlayers + m_nLoadingPlayers + m_nBroadCastPlayers;
        CMRPPlayer* p1 = m_pMRPPlayers;
        while(n-- > 0) {
            p1->Save(mf);
            p1 = p1->m_pNext;
        }
        mf.WriteBytes(&m_fFrameTime, sizeof(m_fFrameTime));

        CMRPPack* p2 = m_pMRPPackStart;
        n = 0;
        while(p2) {
            n++;
            p2 = p2->m_pNext;
        }
        mf.WriteBytes(&n, sizeof(n));

        p2 = m_pMRPPackStart;
        while(p2) {
            mf.WriteBytes(&p2->m_nCount, sizeof(p2->m_nCount));
            p2->Save(mf);
            p2 = p2->m_pNext;
        }
        mf.WriteByteAlign();
        fwrite(mf.GetStreamStart(), mf.GetBytesUsed(), 1, f);
        fclose(f);
        return true;
    }

    return false;
}

bool CMRPFull::LoadDefaultMR()
{
    char szFile[256];

    GetFileName4GUID(szFile, "c:", g_pcszGameDataSavePath, g_pcszGameDataExtMR);
    return LoadMR(szFile);
}

bool CMRPFull::LoadMR(const char* pcszFile)
{
    gosASSERT(pcszFile && pcszFile[0]);

    bool bRet = false;

    FILE* f = fopen(pcszFile, "rb");
    if (f) {
        Reset();

        long lSize = _filelength(fileno(f));
        BYTE* pBuf = (BYTE*)malloc(lSize);
        fread(pBuf, lSize, 1, f);
        MemoryStream mf(pBuf, lSize);

        DWORD dwMeta;
        mf.ReadBytes(&dwMeta, sizeof(dwMeta));
        if ((dwMeta == g_dwMR_Meta) || (dwMeta == g_dwMR_MetaOldA)) {
            mf.ReadBytes(&m_CurrentSession, sizeof(m_CurrentSession));
            mf >> m_strGameName;
            mf.ReadBytes(&m_dwMyDirectPlayID, sizeof(m_dwMyDirectPlayID));
            mf >> m_strPlayer;
            mf >> m_strPassword;
            mf.ReadBit(m_bStarting);
            mf.ReadBit(m_bStarted);
            mf.ReadBit(m_bStopping);
            mf.ReadBit(m_bStopped);
            mf.ReadBit(m_bTeamGame);
            mf.ReadByteAlign();
            mf.ReadBytes(&m_nMissionParamSize, sizeof(m_nMissionParamSize));
            m_pMissionParam = new BYTE[m_nMissionParamSize];
            mf.ReadBytes(m_pMissionParam, m_nMissionParamSize);
            mf.ReadBytes(&m_nBOTPlayers, sizeof(m_nBOTPlayers));
            mf.ReadBytes(&m_nLoadingPlayers, sizeof(m_nLoadingPlayers));
            mf.ReadBytes(&m_nBroadCastPlayers, sizeof(m_nBroadCastPlayers));

            int n;
            n = m_nBOTPlayers + m_nLoadingPlayers + m_nBroadCastPlayers;
            CMRPPlayer* p1Last = NULL;
            while(n-- > 0) {
                CMRPPlayer* p1 = new CMRPPlayer;
                if (p1Last) {
                    p1Last->m_pNext = p1;
                    p1->m_pPrev = p1Last;
                } else {
                    m_pMRPPlayers = p1;
                }
                p1Last = p1;
                p1->Load(mf);
            }
            mf.ReadBytes(&m_fFrameTime, sizeof(m_fFrameTime));

            mf.ReadBytes(&n, sizeof(n));
            CMRPPack* p2Last = NULL;
            while(n-- > 0) {
                int nCount;
                mf.ReadBytes(&nCount, sizeof(nCount));
                CMRPPack* p2 = AllocMRPPack(nCount, (PMRP*)NULL);
                if (p2Last) {
                    p2Last->m_pNext = p2;
                    p2->m_pPrev = p2Last;
                } else {
                    m_pMRPPackStart = p2;
                }
                p2Last = p2;
                p2->Load(mf, dwMeta);
            }
            mf.Rewind();

            bRet = true;
        }

        free(pBuf);
        fclose(f);
        //if (!bRet) {
        //  remove(pcszFile);
        //}

        return true;
    }

    return bRet;
}

Stuff::Scalar CMRPFull::EndMissionTime() const
{
    Stuff::Scalar fTime = 0.0f;
    CMRPPack* pMRPP = m_pMRPPackStart;
    while(pMRPP) {
        if (pMRPP->m_fFrameTime > fTime)
            fTime = pMRPP->m_fFrameTime;
        pMRPP = pMRPP->m_pNext;
    }

    if (fTime > m_fFrameTime)
        return fTime + 0.5;
    return m_fFrameTime + 0.5f;
}

void MRP_Setup()
{
    g_pfn_ONGAMEOPEN = MRP_OnGameOpen;
    g_pfn_ADDPLAYERTOGAME = NET_AddPlayerToGame;
    g_pfn_REMOVEPLAYERFROMGAME = NET_RemovePlayerFromGame;
    g_pfn_ADDREMOVE_CONNECTION = NET_AddRemoveConnection;
    g_pfn_LOCALSENDNETMESSAGE = MRP_LOCALSENDNETMESSAGE;

    g_nMR = 0;
}

void MRP_Cleanup()
{
    g_MRF.Reset();

    g_pfn_LOCALSENDNETMESSAGE = NULL;
    g_pfn_ADDREMOVE_CONNECTION = NULL;
    g_pfn_REMOVEPLAYERFROMGAME = NULL;
    g_pfn_ADDPLAYERTOGAME = NULL;
    g_pfn_ONGAMEOPEN = NULL;
}
