📄 bloodservershell.cpp
字号:
// ----------------------------------------------------------------------- //
//
// MODULE : BloodServerShell.cpp
//
// PURPOSE : Blood's server shell - Implementation
//
// CREATED : 9/17/97
//
// ----------------------------------------------------------------------- //
#include "BloodServerShell.h"
#include "PlayerObj.h"
#include "cpp_server_de.h"
#include "PathMgr.h"
#include "ClientServerShared.h"
#include "FileCaching.h"
#include "ai_mgr.h"
#include "sparam.h"
#include "CameraObj.h"
#include "CVarTrack.h"
#include "CultistAI.h"
#include <windows.h> // For DebugBreak
#include <winbase.h>
#include <stdio.h>
#include <io.h>
#include <fcntl.h>
#define MAX_CLIENT_NAME_LENGTH 100
#define CLIENT_PING_UPDATE_RATE 7.5f
#define WAIT_TIME_FOR_LEVEL_SWITCH 7.5f
char g_szVarDoAutosave[] = "GAME_DOAUTOSAVE";
char g_szVarRevisiting[] = "GAME_REVISITING";
char g_szVarRestoring[] = "GAME_RESTORING";
char g_szVarGotoStartpoint[] = "GAME_GOTOSTARTPOINT";
char g_szVarWorldName[] = "GAME_WORLDNAME";
char g_szVarDifficulty[] = "GAME_DIFFICULTY";
char g_szVarGameType[] = "GAME_GAMETYPE";
char g_szSavePath[] = "Save\\Current\\";
char g_szAutoSaveFile[] = "Auto.sav";
char g_szCurrentSaveFile[] = "Current.sav";
DBOOL g_bNextLevel = DFALSE;
DBOOL g_bWaitToStartNextLevel = DFALSE;
DFLOAT g_fWaitTimeForNextLevel = 0.0f;
CVarTrack g_SayTrack;
extern BOOL g_bLevelChangeCharacter;
extern int g_nLevelChangeCharacter;
SETUP_SERVERSHELL()
DEFINE_CLASSES()
CBloodServerShell* g_pBloodServerShell = DNULL;
ServerShellDE* CreateServerShell(ServerDE *pServerDE)
{
g_pServerDE = pServerDE;
CBloodServerShell *pShell = new CBloodServerShell;
g_pBloodServerShell = pShell;
return (ServerShellDE*)pShell;
}
void DeleteServerShell(ServerShellDE *pInputShell)
{
CBloodServerShell *pShell = (CBloodServerShell*)pInputShell;
// Only set to NULL if we are deleting what we think is the current server shell..
// gk
// if (g_pBloodServerShell == pShell)
// g_pBloodServerShell = DNULL;
delete pShell;
}
// ----------------------------------------------------------------------- //
//
// ROUTINE: CBloodServerShell::CBloodServerShell()
//
// PURPOSE: Initialize
//
// ----------------------------------------------------------------------- //
CBloodServerShell::CBloodServerShell()
{
memset(&m_GameInfo, 0, sizeof(NetGame));
m_hstrStartPointName = DNULL;
#ifdef _ADD_ON
m_bAddonLevel = DFALSE;
#endif
SetUpdateBlood2Serv();
ClearClientList();
SetupGameInfo();
m_bBlood2ServHosted = DFALSE;
m_nCurLevel = 0;
if (!m_VoiceMgr.IsInited())
{
m_VoiceMgr.Init(g_pServerDE);
}
g_SayTrack.Term();
// Reset the goto-start-point game con var...
g_pServerDE->SetGameConVar(g_szVarGotoStartpoint, "1");
}
// ----------------------------------------------------------------------- //
//
// ROUTINE: CBloodServerShell::~CBloodServerShell()
//
// PURPOSE: Deallocate
//
// ----------------------------------------------------------------------- //
CBloodServerShell::~CBloodServerShell()
{
if (!g_pServerDE) return;
// Tell all clients that we are shutting down
//HMESSAGEWRITE hMessage = g_pServerDE->StartMessage(NULL, SMSG_SERVERSHUTDOWN);
//g_pServerDE->EndMessage(hMessage);
if (m_hstrStartPointName)
g_pServerDE->FreeString(m_hstrStartPointName);
m_VoiceMgr.Term();
g_SayTrack.Term();
}
/*
// ----------------------------------------------------------------------- //
//
// ROUTINE: CBloodServerShell::OnAddClient()
//
// PURPOSE: Add a client
//
// ----------------------------------------------------------------------- //
void CBloodServerShell::OnAddClient(HCLIENT hClient)
{
}
*/
// ----------------------------------------------------------------------- //
//
// ROUTINE: CBloodServerShell::OnRemoveClient()
//
// PURPOSE: Remove a client
//
// ----------------------------------------------------------------------- //
void CBloodServerShell::OnRemoveClient(HCLIENT hClient)
{
CPlayerObj *pPlayer;
ServerDE *pServerDE = GetServerDE();
if(pPlayer = (CPlayerObj*)pServerDE->GetClientUserData(hClient))
{
pPlayer->SetClient(DNULL);
}
}
// ----------------------------------------------------------------------- //
//
// ROUTINE: CBloodServerShell::OnClientEnterWorld()
//
// PURPOSE: Handle client entering the world
//
// ----------------------------------------------------------------------- //
BaseClass* CBloodServerShell::OnClientEnterWorld(HCLIENT hClient, void* pClientData, DDWORD dwClientDataLen)
{
if (!g_pServerDE || !hClient) return DNULL;
BaseClass* pObject = DNULL;
DBOOL bFoundClient = DFALSE;
char szClientName[MAX_CLIENT_NAME_LENGTH];
char szClientRefName[MAX_CLIENT_NAME_LENGTH];
szClientName[0] = szClientRefName[0] = '\0';
g_pServerDE->GetClientName(hClient, szClientName, MAX_CLIENT_NAME_LENGTH-1);
// Search through the client refs to see if any of them match..
HCLIENTREF hClientRef = g_pServerDE->GetNextClientRef(DNULL);
while (hClientRef)
{
// See if this client reference is local or not...
if (g_pServerDE->GetClientRefInfoFlags(hClientRef) & CIF_LOCAL)
{
bFoundClient = DTRUE;
}
// Determine if there is a reference to a client with the same name...
if (!bFoundClient && g_pServerDE->GetClientRefName(hClientRef, szClientRefName, MAX_CLIENT_NAME_LENGTH-1))
{
if (szClientName[0] && szClientRefName[0])
{
if (_mbsicmp((const unsigned char*)szClientName, (const unsigned char*)szClientRefName) == 0)
{
bFoundClient = DTRUE;
}
}
}
// See if we found the right client...
if (bFoundClient)
{
HOBJECT hObject = g_pServerDE->GetClientRefObject(hClientRef);
pObject = g_pServerDE->HandleToObject(hObject);
if (pObject)
RespawnPlayer(pObject, hClient);
break;
}
hClientRef = g_pServerDE->GetNextClientRef(hClientRef);
}
// Add this client to the appropriate team...
DWORD dwTeamID = TEAM_1;
if (IsMultiplayerTeamBasedGame())
{
if (pClientData && dwClientDataLen == sizeof(NetClientData))
{
NetClientData* pNcd = (NetClientData*)pClientData;
dwTeamID = pNcd->m_dwTeam;
}
if (dwTeamID == TEAM_AUTO)
{
CTeam* pTeam = m_TeamMgr.GetTeamWithLeastPlayers(TRUE);
if (pTeam)
{
dwTeamID = pTeam->GetID();
}
else
{
if (IsRandomChance(50)) dwTeamID = TEAM_2;
else dwTeamID = TEAM_1;
}
}
DDWORD dwTransTeamID = m_TeamMgr.GetTeamTransID(g_pServerDE->GetClientID(hClient));
CTeam* pTeam = m_TeamMgr.GetTeam(dwTransTeamID);
if (dwTransTeamID != TM_ID_NULL && pTeam)
{
dwTeamID = dwTransTeamID;
}
}
m_TeamMgr.AddPlayer(dwTeamID, g_pServerDE->GetClientID(hClient));
// See if we need to create a player (no matches found)...
if (!pObject)
{
pObject = CreatePlayer(hClient);
RespawnPlayer(pObject, hClient);
}
// Add this client to our local list...
AddClientToList(hClient);
// All done...
return pObject;
}
// ----------------------------------------------------------------------- //
//
// ROUTINE: CBloodServerShell::OnClientExitWorld()
//
// PURPOSE: Remove a client
//
// ----------------------------------------------------------------------- //
void CBloodServerShell::OnClientExitWorld(HCLIENT hClient)
{
// Tell all clients..
RemovePlayerMessage(hClient);
// Remove this client from the team...
m_TeamMgr.RemovePlayer(g_pServerDE->GetClientID(hClient));
// Remove this client from our local list...
RemoveClientFromList(hClient);
SetUpdateBlood2Serv();
// Remove the player object...
CPlayerObj* pPlayer = (CPlayerObj*)g_pServerDE->GetClientUserData(hClient);
if (pPlayer)
{
pPlayer->DropFlag(DFALSE);
g_pServerDE->RemoveObject(pPlayer->m_hObject);
}
g_pServerDE->SetClientUserData(hClient, DNULL);
}
// ----------------------------------------------------------------------- //
//
// ROUTINE: CBloodServerShell::OnMessage()
//
// PURPOSE: Handle messages
//
// ----------------------------------------------------------------------- //
void CBloodServerShell::OnMessage(HCLIENT hSender, DBYTE messageID, HMESSAGEREAD hMessage)
{
if (!g_pServerDE) return;
switch(messageID)
{
case CMSG_NEXTLEVEL:
{
g_bNextLevel = DTRUE;
break;
}
case CMSG_WEAPON_FIRE:
{
void *pData = g_pServerDE->GetClientUserData(hSender);
CPlayerObj* pPlayer = (CPlayerObj*)pData;
if (pPlayer)
{
pPlayer->HandleWeaponFireMessage(hMessage);
}
}
break;
case CMSG_WEAPON_SOUND:
{
void *pData = g_pServerDE->GetClientUserData(hSender);
CPlayerObj* pPlayer = (CPlayerObj*)pData;
if (pPlayer)
{
pPlayer->HandleWeaponSoundMessage(hMessage);
}
}
break;
case CMSG_WEAPON_STATE:
{
void *pData = g_pServerDE->GetClientUserData(hSender);
CPlayerObj* pPlayer = (CPlayerObj*)pData;
if (pPlayer)
{
pPlayer->HandleWeaponStateMessage(hMessage);
}
}
break;
case CMSG_WEAPON_CHANGE:
{
void *pData = g_pServerDE->GetClientUserData(hSender);
CPlayerObj* pPlayer = (CPlayerObj*)pData;
if (pPlayer)
{
DBYTE nWeaponId = g_pServerDE->ReadFromMessageByte(hMessage);
pPlayer->DoWeaponChange(nWeaponId);
}
}
break;
// Got a load world message
case CMSG_LOADWORLD:
{
DBOOL bResult;
bResult = LoadWorld(hMessage);
// Acknowledge the load, good or bad
HMESSAGEWRITE hMessage = g_pServerDE->StartMessage(NULL, SMSG_LOADWORLD_ACK);
g_pServerDE->WriteToMessageByte(hMessage, (DBYTE)bResult);
g_pServerDE->EndMessage(hMessage);
}
break;
case CMSG_SAVEGAME:
{
HMESSAGEREAD hClientSaveData;
CPlayerObj *pPlayerObj;
char *pFilename = g_pServerDE->ReadFromMessageString(hMessage);
DBOOL bSaveType = g_pServerDE->ReadFromMessageByte( hMessage );
hClientSaveData = g_pServerDE->ReadFromMessageHMessageRead( hMessage );
pPlayerObj = ( CPlayerObj * )g_pServerDE->GetClientUserData(hSender);
if( pPlayerObj )
pPlayerObj->SetClientSaveData( hClientSaveData );
if (bSaveType == SAVETYPE_CURRENT)
{
if (SaveGame(SAVETYPE_CURRENT, DTRUE, DTRUE))
{ // Acknowledge a successful save
HMESSAGEWRITE hMessage = g_pServerDE->StartMessage(NULL, SMSG_SAVEGAME_ACK);
g_pServerDE->EndMessage(hMessage);
}
}
else // Do autosave
{
if (SaveGame(SAVETYPE_AUTO, DTRUE, DTRUE))
{
HMESSAGEWRITE hMessage = g_pServerDE->StartMessage(NULL, SMSG_SAVEGAME_ACK);
g_pServerDE->EndMessage(hMessage);
}
}
}
break;
case CMSG_DETACH_AI:
{
HOBJECT hObj = g_pServerDE->ReadFromMessageObject(hMessage);
if(g_pServerDE->IsKindOf(g_pServerDE->GetObjectClass(hObj), g_pServerDE->GetClass("AI_Mgr")))
{
AI_Mgr* pAI = (AI_Mgr*)g_pServerDE->HandleToObject(hObj);
pAI->DetachFromEnemy();
}
break;
}
case CMSG_ATTACH_ACK:
{
HOBJECT hObj = g_pServerDE->ReadFromMessageObject(hMessage);
if(g_pServerDE->IsKindOf(g_pServerDE->GetObjectClass(hObj), g_pServerDE->GetClass("AI_Mgr")))
{
AI_Mgr* pAI = (AI_Mgr*)g_pServerDE->HandleToObject(hObj);
pAI->ProceedToAttach();
}
break;
}
case CMSG_GAME_PAUSE:
{
DBOOL bPause = (DBOOL)g_pServerDE->ReadFromMessageByte(hMessage);
DDWORD nFlags = g_pServerDE->GetServerFlags();
if (bPause)
nFlags |= SS_PAUSED;
else
nFlags &= ~SS_PAUSED;
g_pServerDE->SetServerFlags(nFlags);
}
break;
case CMSG_MULTIPLAYER_INIT:
{
CPlayerObj *pObj = (CPlayerObj*)g_pServerDE->GetClientUserData(hSender);
if (pObj)
{
pObj->OnMessage(messageID, hMessage);
// Tell other players that he's here
AddPlayerMessage(DNULL, hSender);
// tell new player about all current players (excluding himself)
AddPlayersMessage(hSender);
SetUpdateBlood2Serv();
}
}
break;
case CMSG_SINGLEPLAYER_INIT:
{
CPlayerObj *pObj = (CPlayerObj*)g_pServerDE->GetClientUserData(hSender);
if (pObj)
{
pObj->OnMessage(messageID, hMessage);
}
}
break;
case CMSG_AUTOSAVE:
{
#ifndef _DEMO
// Autosave current situation, to be able to restart the world
if (GetGameConVarValueFloat(g_szVarDoAutosave))
{
HMESSAGEWRITE hMessage = g_pServerDE->StartMessage(hSender, SMSG_DOAUTOSAVE);
g_pServerDE->EndMessage(hMessage);
/* if (SaveGame(SAVETYPE_AUTO, DTRUE, DTRUE))
{
HMESSAGEWRITE hMessage = g_pServerDE->StartMessage(NULL, SMSG_SAVEGAME_ACK);
g_pServerDE->EndMessage(hMessage);
}
*/
}
#endif
}
break;
default: // Let the player handle it
{
CPlayerObj *pObj = (CPlayerObj*)g_pServerDE->GetClientUserData(hSender);
if (pObj)
pObj->OnMessage(messageID, hMessage);
}
}
}
// ----------------------------------------------------------------------- //
//
// ROUTINE: CBloodServerShell::OnCommandOn()
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -