void CGameServer::ClientEnterGame(int iClient) { TMsg(sprintf(tstring("Client %d (") + GameNetwork()->GetClientNickname(iClient) + ") entering game.\n", iClient)); if (GetGame()) GetGame()->OnClientEnterGame(iClient); for (size_t i = 0; i < GameServer()->GetMaxEntities(); i++) { CBaseEntity* pEntity = CBaseEntity::GetEntity(i); if (!pEntity) continue; ::CreateEntity.RunCommand(sprintf(tstring("%s %d %d"), pEntity->GetClassName(), pEntity->GetHandle(), pEntity->GetSpawnSeed()), iClient); } CGameServerNetwork::UpdateNetworkVariables(iClient, true); // Update entities after all creations have been run, so we don't refer to entities that haven't been created yet. for (size_t i = 0; i < GameServer()->GetMaxEntities(); i++) { CBaseEntity* pEntity = CBaseEntity::GetEntity(i); if (!pEntity) continue; pEntity->ClientUpdate(iClient); } GameNetwork()->CallFunction(iClient, "EnterGame"); GameNetwork()->CallFunction(iClient, "LoadingDone"); }
void CGameServer::DestroyAllEntities(const tvector<tstring>& asSpare, bool bRemakeGame) { if (!GameNetwork()->IsHost() && !IsLoading()) return; if (m_pWorkListener) m_pWorkListener->SetAction("Locating dead nodes", GameServer()->GetMaxEntities()); for (size_t i = 0; i < GameServer()->GetMaxEntities(); i++) { CBaseEntity* pEntity = CBaseEntity::GetEntity(i); if (!pEntity) continue; bool bSpare = false; for (size_t j = 0; j < asSpare.size(); j++) { if (asSpare[j] == pEntity->GetClassName()) { bSpare = true; break; } } if (bSpare) continue; pEntity->Delete(); if (m_pWorkListener) m_pWorkListener->WorkProgress(i); } if (m_pWorkListener) m_pWorkListener->SetAction("Clearing buffers", GameServer()->m_ahDeletedEntities.size()); for (size_t i = 0; i < GameServer()->m_ahDeletedEntities.size(); i++) { delete GameServer()->m_ahDeletedEntities[i]; if (m_pWorkListener) m_pWorkListener->WorkProgress(i); } GameServer()->m_ahDeletedEntities.clear(); if (CBaseEntity::GetNumEntities() == 0) CBaseEntity::s_iNextEntityListIndex = 0; if (bRemakeGame && GameNetwork()->IsHost()) m_hGame = CreateGame(); }
void CInstructor::CallOutput(const tstring& sOutput) { if (!GetCurrentLesson()) return; for (size_t i = 0; i < GetCurrentLesson()->m_aOutputs.size(); i++) { CLessonOutput* pOutput = &GetCurrentLesson()->m_aOutputs[i]; if (pOutput->m_sOutput == sOutput) { for (size_t i = 0; i < GameServer()->GetMaxEntities(); i++) { CBaseEntity* pEntity = CBaseEntity::GetEntity(i); if (!pEntity) continue; if (pEntity->IsDeleted()) continue; if (pOutput->m_sTarget.length() == 0) continue; if (pOutput->m_sTarget.length() == 0) continue; if (pOutput->m_sTarget[0] == '*') { if (tstring(pEntity->GetClassName()) != pOutput->m_sTarget.c_str()+1) continue; } else { if (pEntity->GetName() != pOutput->m_sTarget) continue; } pEntity->CallInput(pOutput->m_sInput, convertstring<char, tchar>(pOutput->m_sArgs)); } } } }
void FireInput(class CCommand* pCommand, tvector<tstring>& asTokens, const tstring& sCommand) { if (!CVar::GetCVarBool("cheats")) return; if (asTokens.size() < 3) { TMsg("Format: ent_input entityname input [optional args]\n"); return; } tvector<CBaseEntity*> apEntities; CBaseEntity::FindEntitiesByName(asTokens[1], apEntities); if (!apEntities.size()) { if (CVar::GetCVarBool("debug_entity_outputs")) TMsg("Console -> none\n"); else TError("No entities found that match name \"" + asTokens[1] + "\".\n"); return; } tstring sArgs; for (size_t i = 3; i < asTokens.size(); i++) sArgs += asTokens[i] + " "; for (size_t i = 0; i < apEntities.size(); i++) { CBaseEntity* pTargetEntity = apEntities[i]; if (CVar::GetCVarBool("debug_entity_outputs")) TMsg("Console -> " + tstring(pTargetEntity->GetClassName()) + "(\"" + pTargetEntity->GetName() + "\")." + asTokens[2] + "(\"" + sArgs + "\")\n"); pTargetEntity->CallInput(asTokens[2], sArgs); } }
void CGameServer::LoadLevel(const CHandle<CLevel>& pLevel) { // Create and name the entities first and add them to this array. This way we avoid a problem where // one entity needs to connect to another entity which has not yet been created. tmap<size_t, CBaseEntity*> apEntities; // Do a quick precache now to load default models and such. Another precache will come later. const auto& aEntities = pLevel->GetEntityData(); for (size_t i = 0; i < aEntities.size(); i++) AddToPrecacheList("C" + aEntities[i].GetClass()); PrecacheList(); m_bAllowPrecaches = true; for (size_t i = 0; i < aEntities.size(); i++) { const CLevelEntity* pLevelEntity = &aEntities[i]; tstring sClass = "C" + pLevelEntity->GetClass(); auto it = CBaseEntity::GetEntityRegistration().find(sClass); TAssert(it != CBaseEntity::GetEntityRegistration().end()); if (it == CBaseEntity::GetEntityRegistration().end()) { TError("Unregistered entity '" + sClass + "'\n"); continue; } AddToPrecacheList("C" + aEntities[i].GetClass()); CBaseEntity* pEntity = Create<CBaseEntity>(sClass.c_str()); apEntities[i] = pEntity; pEntity->SetName(pLevelEntity->GetName()); // Process outputs here so that they exist when handle callbacks run. for (size_t k = 0; k < pLevelEntity->GetOutputs().size(); k++) { auto pOutput = &pLevelEntity->GetOutputs()[k]; tstring sValue = pOutput->m_sOutput; CSaveData* pSaveData = CBaseEntity::FindOutput(pEntity->GetClassName(), sValue); TAssert(pSaveData); if (!pSaveData) { TError("Unknown output '" + sValue + "'\n"); continue; } tstring sTarget = pOutput->m_sTargetName; tstring sInput = pOutput->m_sInput; tstring sArgs = pOutput->m_sArgs; bool bKill = pOutput->m_bKill; if (!sTarget.length()) { TUnimplemented(); TError("Output '" + sValue + "' of entity '" + pEntity->GetName() + "' (" + pEntity->GetClassName() + ") is missing a target.\n"); continue; } if (!sInput.length()) { TUnimplemented(); TError("Output '" + sValue + "' of entity '" + pEntity->GetName() + "' (" + pEntity->GetClassName() + ") is missing an input.\n"); continue; } pEntity->AddOutputTarget(sValue, sTarget, sInput, sArgs, bKill); } } for (auto it = apEntities.begin(); it != apEntities.end(); it++) { auto pLevelEntity = &aEntities[it->first]; CBaseEntity* pEntity = it->second; // Force physics related stuff first so it's available if there's a physics model. auto itScale = pLevelEntity->GetParameters().find("Scale"); if (itScale != pLevelEntity->GetParameters().end()) UnserializeParameter("Scale", itScale->second, pEntity); auto itOrigin = pLevelEntity->GetParameters().find("Origin"); if (itOrigin != pLevelEntity->GetParameters().end()) UnserializeParameter("Origin", itOrigin->second, pEntity); for (auto it = pLevelEntity->GetParameters().begin(); it != pLevelEntity->GetParameters().end(); it++) { tstring sHandle = it->first; tstring sValue = it->second; if (sHandle == "MoveParent") continue; if (sHandle == "Scale") continue; if (sHandle == "Origin") continue; UnserializeParameter(sHandle, sValue, pEntity); } } for (auto it = apEntities.begin(); it != apEntities.end(); it++) { auto pLevelEntity = &aEntities[it->first]; CBaseEntity* pEntity = it->second; // Force MoveParent last so that global -> local conversion is performed. auto itMoveParent = pLevelEntity->GetParameters().find("MoveParent"); if (itMoveParent != pLevelEntity->GetParameters().end()) UnserializeParameter("MoveParent", itMoveParent->second, pEntity); } for (size_t i = 0; i < apEntities.size(); i++) apEntities[i]->PostLoad(); if (CWorkbench::IsActive()) CWorkbench::LoadLevel(pLevel); }
void CGameServerNetwork::UpdateNetworkVariables(int iClient, bool bForceAll) { if (!GameNetwork()->IsConnected()) return; double flTime = GameServer()->GetGameTime(); size_t iMaxEnts = GameServer()->GetMaxEntities(); for (size_t i = 0; i < iMaxEnts; i++) { CBaseEntity* pEntity = CBaseEntity::GetEntity(i); if (!pEntity) continue; const tchar* pszClassName = pEntity->GetClassName(); CEntityRegistration* pRegistration = NULL; do { pRegistration = pEntity->GetRegisteredEntity(pszClassName); TAssert(pRegistration); if (!pRegistration) break; size_t iNetVarsSize = pRegistration->m_aNetworkVariables.size(); for (size_t j = 0; j < iNetVarsSize; j++) { CNetworkedVariableData* pVarData = &pRegistration->m_aNetworkVariables[j]; CNetworkedVariableBase* pVariable = pVarData->GetNetworkedVariableBase(pEntity); if (!bForceAll) { if (!pVariable->IsDirty()) continue; if (flTime - pVariable->m_flLastUpdate < pVarData->m_flUpdateInterval) continue; } // For one, m_flLastUpdate needs to be a double pVariable->m_flLastUpdate = (float)flTime; // For two, it's shit. TUnimplemented(); // Try some testing or something. CNetworkParameters p; p.ui1 = pEntity->GetHandle(); size_t iDataSize; void* pValue = pVariable->Serialize(iDataSize); if (net_replication_debug.GetBool()) { if (iDataSize >= 4) TMsg(tstring("Updating ") + pVarData->GetName() + sprintf(tstring(" (%x) (%f) (%d)\n"), *(unsigned int*)pValue, *(float*)pValue, *(int*)pValue)); else TMsg(tstring("Updating ") + pVarData->GetName() + "\n"); } p.CreateExtraData(iDataSize + strlen(pVarData->GetName())+1); strcpy((char*)p.m_pExtraData, pVarData->GetName()); memcpy((unsigned char*)(p.m_pExtraData) + strlen(pVarData->GetName())+1, pValue, iDataSize); // UV stands for UpdateValue GameNetwork()->CallFunctionParameters(iClient, "UV", &p); // Only reset the dirty flag if all clients got the message. if (iClient == NETWORK_TOCLIENTS) pVariable->SetDirty(false); } pszClassName = pRegistration->m_pszParentClass; } while (pszClassName); } }