void CHLTVDirector::StartInstantBroadcastShot() { m_nNextShotTick = m_nBroadcastTick + TIME_TO_TICKS( MAX_SHOT_LENGTH ); if ( m_iCameraManIndex > 0 ) { // camera man is still recording and live, resend camera man message IGameEvent *msg = gameeventmanager->CreateEvent( "hltv_cameraman", true ); if ( msg ) { msg->SetInt("index", m_iCameraManIndex ); m_pHLTVServer->BroadcastEvent( msg ); gameeventmanager->FreeEvent( msg ); m_iPVSEntity = m_iCameraManIndex; m_nNextShotTick = m_nBroadcastTick+TIME_TO_TICKS( MIN_SHOT_LENGTH ); } } else { RemoveEventsFromHistory(-1); // all AnalyzePlayers(); AnalyzeCameras(); StartRandomShot(); } }
void CHLTVDirector::UpdateSettings() { // set delay m_fDelay = tv_delay.GetFloat(); m_fDelay = clamp( m_fDelay, HLTV_MIN_DELAY, HLTV_MAX_DELAY ); // broadcast time is current time - delay time int newBroadcastTick = gpGlobals->tickcount - TIME_TO_TICKS( m_fDelay ); if( (m_nBroadcastTick == 0) && (newBroadcastTick > 0) ) { // we start broadcasting right now, reset NextShotTimer m_nNextShotTick = 0; } // check if camera man is still valid if ( m_iCameraManIndex > 0 ) { CBasePlayer *pPlayer = UTIL_PlayerByIndex( m_iCameraManIndex ); if ( !pPlayer || pPlayer->GetTeamNumber() != TEAM_SPECTATOR ) { SetCameraMan( 0 ); } } m_nBroadcastTick = MAX( 0, newBroadcastTick ); }
void CHLTVDirector::FrameUpdatePostEntityThink( void ) { if ( !m_pHLTVServer ) return; // don't do anything // This function is called each tick UpdateSettings(); // update settings from cvars if ( m_nNextAnalyzeTick < gpGlobals->tickcount ) { m_nNextAnalyzeTick = gpGlobals->tickcount + TIME_TO_TICKS( 0.5f ); AnalyzePlayers(); AnalyzeCameras(); } if ( m_nBroadcastTick <= 0 ) { // game start is still in delay loop StartDelayMessage(); } else if ( m_nNextShotTick <= m_nBroadcastTick ) { // game is being broadcasted, generate camera shots StartNewShot(); } }
void lagcompensation::create_move() { last_eye_positions.push_front(g_ctx.m_local->get_eye_pos()); if (last_eye_positions.size() > 128) last_eye_positions.pop_back(); auto nci = g_csgo.m_engine()->GetNetChannelInfo(); if (!nci) return; const int latency_ticks = TIME_TO_TICKS(nci->GetLatency(FLOW_OUTGOING)); const auto latency_based_eye_pos = last_eye_positions.size() <= latency_ticks ? last_eye_positions.back() : last_eye_positions[latency_ticks]; for (int i = 1; i <= g_csgo.m_globals()->m_maxclients; i++) { auto e = static_cast<player_t *>(g_csgo.m_entitylist()->GetClientEntity(i)); auto & player = players[i]; player.m_e = e; if (!e) { player.m_e = nullptr; continue; } if (!e->valid(true)) continue; player.m_resolver->m_e = e; player.m_resolver->create_move(latency_based_eye_pos); } }
void CHLTVDirector::CreateShotFromEvent( CHLTVGameEvent *event ) { // show event at least for 2 more seconds after it occured const char *name = event->m_Event->GetName(); bool bPlayerHurt = Q_strcmp( "player_hurt", name ) == 0; bool bPlayerKilled = Q_strcmp( "player_death", name ) == 0; bool bRoundStart = Q_strcmp( "round_start", name ) == 0; bool bRoundEnd = Q_strcmp( "round_end", name ) == 0; if ( bPlayerHurt || bPlayerKilled ) { CBaseEntity *victim = UTIL_PlayerByUserId( event->m_Event->GetInt("userid") ); CBaseEntity *attacker = UTIL_PlayerByUserId( event->m_Event->GetInt("attacker") ); if ( !victim ) return; if ( attacker == victim || attacker == NULL ) { // player killed self or by WORLD StartChaseCameraShot( victim->entindex(), 0, 96, 20, 0, false ); } else // attacker != NULL { // check if we would show it from ineye view bool bInEye = (bPlayerKilled && RandomFloat(0,1) > 0.33) || (bPlayerHurt && RandomFloat(0,1) > 0.66); // if we show ineye view, show it more likely from killer if ( RandomFloat(0,1) > (bInEye?0.3f:0.7f) ) { V_swap( attacker, victim ); } // hurting a victim is shown as chase more often // view from behind over head // lower view point, dramatic // view over shoulder, randomly left or right StartChaseCameraShot( victim->entindex(), attacker->entindex(), 96, -20, (RandomFloat()>0.5)?30:-30, bInEye ); } // shot 2 seconds after death/hurt m_nNextShotTick = MIN( m_nNextShotTick, (event->m_Tick+TIME_TO_TICKS(2.0)) ); } else if ( bRoundStart || bRoundEnd ) { StartBestFixedCameraShot( false ); } else { DevMsg( "No known TV shot for event %s\n", name ); } }
/*====================================== * receive a mail to mailbox * 接收邮件从邮箱 *======================================*/ void* acoral_mbox_recv(acoral_evt_t * event, acoral_time timeout) { void *msg; acoral_sr cpu_sr; acoral_thread_t *cur; if (acoral_intr_nesting > 0) return NULL; if(event->type!=ACORAL_EVENT_MBOX) return NULL; HAL_ENTER_CRITICAL(); acoral_spin_lock(&event->spin_lock); if( event->data == NULL) { cur = acoral_cur_thread; if (timeout > 0) { cur->delay = TIME_TO_TICKS(timeout); timeout_queue_add(cur); } acoral_unrdy_thread(cur); acoral_evt_queue_add(event, cur); acoral_spin_unlock(&event->spin_lock); HAL_EXIT_CRITICAL(); acoral_sched(); HAL_ENTER_CRITICAL(); acoral_spin_lock(&event->spin_lock); if (timeout > 0 && cur->delay <= 0) { acoral_evt_queue_del(cur); acoral_spin_unlock(&event->spin_lock); HAL_EXIT_CRITICAL(); return NULL; } msg = event->data; event->data = NULL; acoral_spin_unlock(&event->spin_lock); HAL_EXIT_CRITICAL(); return msg; } msg = event->data; event->data = NULL; acoral_spin_unlock(&event->spin_lock); HAL_EXIT_CRITICAL(); return msg; }
// when running in threaded host mode, the clock drifts by a predictable algorithm // because the client lags the server by one frame // so at each update from the network we have lastframeticks-1 pending ticks to execute // on the client. If the clock has drifted by exactly that amount, allow it to drift temporarily // NOTE: When the server gets paused the tick count is still incorrect for a frame // NOTE: It should be possible to fix this by applying pause before the tick is incremented // NOTE: or decrementing the client tick after receiving pause // NOTE: This is due to the fact that currently pause is applied at frame start on the server // NOTE: and frame end on the client void CClockDriftMgr::SetServerTick( int nTick ) { #if !defined( SWDS ) m_nServerTick = nTick; int nMaxDriftTicks = IsEngineThreaded() ? TIME_TO_TICKS( (cl_clockdrift_max_ms_threadmode.GetFloat() / 1000.0) ) : TIME_TO_TICKS( (cl_clockdrift_max_ms.GetFloat() / 1000.0) ); int clientTick = cl.GetClientTickCount() + g_ClientGlobalVariables.simTicksThisFrame - 1; if ( cl_clock_correction_force_server_tick.GetInt() == 999 ) { // If this is the first tick from the server, or if we get further than cl_clockdrift_max_ticks off, then // use the old behavior and slam the server's tick into the client tick. if ( !IsClockCorrectionEnabled() || clientTick == 0 || abs(nTick - clientTick) > nMaxDriftTicks ) { cl.SetClientTickCount( nTick - (g_ClientGlobalVariables.simTicksThisFrame - 1) ); if ( cl.GetClientTickCount() < cl.oldtickcount ) { cl.oldtickcount = cl.GetClientTickCount(); } memset( m_ClockOffsets, 0, sizeof( m_ClockOffsets ) ); } } else { // Used for testing.. cl.SetClientTickCount( nTick + cl_clock_correction_force_server_tick.GetInt() ); } // adjust the clock offset by the clock with thread mode compensation m_ClockOffsets[m_iCurClockOffset] = clientTick - m_nServerTick; m_iCurClockOffset = (m_iCurClockOffset + 1) % NUM_CLOCKDRIFT_SAMPLES; #endif // SWDS }
void CHLTVDirector::FinishCameraManShot() { Assert( m_iCameraMan == m_iPVSEntity ); int index = FindFirstEvent( m_nBroadcastTick ); if ( index == m_EventHistory.InvalidIndex() ) { // check next frame again if event history is empty m_nNextShotTick = m_nBroadcastTick+1; return; } m_nNextShotTick = m_nBroadcastTick + TIME_TO_TICKS( DEF_SHOT_LENGTH ); //check if camera turns camera off within broadcast time and game time while( index != m_EventHistory.InvalidIndex() ) { CGameEvent &dc = m_EventHistory[index]; if ( dc.m_Tick >= m_nNextShotTick ) break; if ( Q_strcmp( dc.m_Event->GetName(), "hltv_cameraman") == 0 ) { int iNewCameraMan = dc.m_Event->GetInt("index"); if ( iNewCameraMan == 0 ) { // camera man switched camera off m_nNextShotTick = dc.m_Tick+1; m_iCameraMan = 0; return; } } index = m_EventHistory.NextInorder( index ); } // camera man is still recording and live, resend camera man message IGameEvent *msg = gameeventmanager->CreateEvent( "hltv_cameraman", true ); if ( msg ) { msg->SetInt("index", m_iCameraMan ); m_pHLTVServer->BroadcastEvent( msg ); gameeventmanager->FreeEvent( msg ); } }
void CHLTVDirector::StartRandomShot() { int toTick = m_nBroadcastTick + TIME_TO_TICKS ( DEF_SHOT_LENGTH ); m_nNextShotTick = MIN( m_nNextShotTick, toTick ); if ( RandomFloat(0,1) < 0.25 && tv_allow_static_shots.GetBool() ) { // create a static shot from a level camera StartBestFixedCameraShot( false ); } else { // follow a player StartBestPlayerCameraShot(); } }
void CDemoActionSkipAhead::FireAction( void ) { // demo->StartSkippingAhead( m_bUsingSkipFrame, m_nSkipToFrame, m_flSkipToTime ); // demo->PushDemoAction( GetActionName() ); // Don't this this, instead wait for demo to notify us that it's finished skipping // SetFinishedAction( true ); if ( m_bUsingSkipTick ) { demoplayer->SkipToTick( m_nSkipToTick, false, false ); } else { demoplayer->SkipToTick( TIME_TO_TICKS(m_flSkipToTime), false, false ); } SetFinishedAction( true ); }
void CHLTVDirector::StartDelayMessage() { if ( m_nNextShotTick > gpGlobals->tickcount ) return; // check the next 8 seconds for interrupts/important events m_nNextShotTick = gpGlobals->tickcount + TIME_TO_TICKS( DEF_SHOT_LENGTH ); // game hasn't started yet, we are still in the broadcast delay hole IGameEvent *msg = gameeventmanager->CreateEvent( "hltv_message", true ); if ( msg ) { msg->SetString("text", "Please wait for broadcast to start ..." ); // send spectators the HLTV director command as a game event m_pHLTVServer->BroadcastEvent( msg ); gameeventmanager->FreeEvent( msg ); } StartBestFixedCameraShot( true ); }
// Called during player movement to set up/restore after lag compensation void CLagCompensationManager::StartLagCompensation( CBasePlayer *player, CUserCmd *cmd ) { //DONT LAG COMP AGAIN THIS FRAME IF THERES ALREADY ONE IN PROGRESS //IF YOU'RE HITTING THIS THEN IT MEANS THERES A CODE BUG if ( m_pCurrentPlayer ) { Assert( m_pCurrentPlayer == NULL ); Warning( "Trying to start a new lag compensation session while one is already active!\n" ); return; } // sort out any changes to the AI indexing if ( m_bNeedsAIUpdate ) // to be called once per frame... must happen BEFORE lag compensation - {// if that happens, that is. if not its called at the end of the frame m_bNeedsAIUpdate = false; UpdateAIIndexes(); } // Assume no players or entities need to be restored m_RestorePlayer.ClearAll(); m_RestoreEntity.ClearAll(); m_bNeedToRestore = false; m_pCurrentPlayer = player; if ( !player->m_bLagCompensation // Player not wanting lag compensation || (gpGlobals->maxClients <= 1) // no lag compensation in single player || !sv_unlag.GetBool() // disabled by server admin || player->IsBot() // not for bots || player->IsObserver() // not for spectators ) return; // NOTE: Put this here so that it won't show up in single player mode. VPROF_BUDGET( "StartLagCompensation", VPROF_BUDGETGROUP_OTHER_NETWORKING ); Q_memset( m_RestoreData, 0, sizeof( m_RestoreData ) ); Q_memset( m_ChangeData, 0, sizeof( m_ChangeData ) ); Q_memset( m_EntityRestoreData, 0, sizeof( m_EntityRestoreData ) ); Q_memset( m_EntityChangeData, 0, sizeof( m_EntityChangeData ) ); // Get true latency // correct is the amout of time we have to correct game time float correct = 0.0f; INetChannelInfo *nci = engine->GetPlayerNetInfo( player->entindex() ); if ( nci ) { // add network latency correct+= nci->GetLatency( FLOW_OUTGOING ); } // calc number of view interpolation ticks - 1 int lerpTicks = TIME_TO_TICKS( player->m_fLerpTime ); // add view interpolation latency see C_BaseEntity::GetInterpolationAmount() correct += TICKS_TO_TIME( lerpTicks ); // check bouns [0,sv_maxunlag] correct = clamp( correct, 0.0f, sv_maxunlag.GetFloat() ); // correct tick send by player int targettick = cmd->tick_count - lerpTicks; // calc difference between tick send by player and our latency based tick float deltaTime = correct - TICKS_TO_TIME(gpGlobals->tickcount - targettick); if ( fabs( deltaTime ) > 0.2f ) { // difference between cmd time and latency is too big > 200ms, use time correction based on latency // DevMsg("StartLagCompensation: delta too big (%.3f)\n", deltaTime ); targettick = gpGlobals->tickcount - TIME_TO_TICKS( correct ); } // Iterate all active players const CBitVec<MAX_EDICTS> *pEntityTransmitBits = engine->GetEntityTransmitBitsForClient( player->entindex() - 1 ); for ( int i = 1; i <= gpGlobals->maxClients; i++ ) { CBasePlayer *pPlayer = UTIL_PlayerByIndex( i ); if ( !pPlayer || player == pPlayer ) continue; // Custom checks for if things should lag compensate (based on things like what team the player is on). if ( !player->WantsLagCompensationOnEntity( pPlayer, cmd, pEntityTransmitBits ) ) continue; // Move other player back in time BacktrackPlayer( pPlayer, TICKS_TO_TIME( targettick ) ); } // also iterate all monsters CAI_BaseNPC **ppAIs = g_AI_Manager.AccessAIs(); int nAIs = g_AI_Manager.NumAIs(); for ( int i = 0; i < nAIs; i++ ) { CAI_BaseNPC *pNPC = ppAIs[i]; // Custom checks for if things should lag compensate if ( !pNPC || !player->WantsLagCompensationOnEntity( pNPC, cmd, pEntityTransmitBits ) ) continue; // Move NPC back in time BacktrackEntity( pNPC, TICKS_TO_TIME( targettick ) ); } }
void CTFHLTVDirector::CreateShotFromEvent( CHLTVGameEvent *event ) { // show event at least for 2 more seconds after it occured const char *name = event->m_Event->GetName(); int thera = RandomFloat()>0.5?20:-20; if ( !Q_strcmp( "teamplay_point_startcapture", name ) || !Q_strcmp( "teamplay_point_captured", name ) || !Q_strcmp( "teamplay_capture_blocked", name ) ) { CBaseEntity *pCapturePoint = GetCapturePointByIndex( event->m_Event->GetInt( "cp" ) ); int iCameraIndex = -1; float flClosest = 99999.9f; if ( pCapturePoint ) { // Does it have an associated viewpoint? for ( int i = 0; i<m_nNumFixedCameras; i++ ) { CBaseEntity *pCamera = m_pFixedCameras[ i ]; if ( pCamera ) { byte pvs[MAX_MAP_CLUSTERS/8]; int clusterIndex = engine->GetClusterForOrigin( pCamera->GetAbsOrigin() ); engine->GetPVSForCluster( clusterIndex, sizeof(pvs), pvs ); bool bCameraInPVS = engine->CheckOriginInPVS( pCapturePoint->GetAbsOrigin(), pvs, sizeof( pvs ) ); if ( bCameraInPVS == true ) { float flDistance = (pCapturePoint->GetAbsOrigin() - pCamera->GetAbsOrigin()).Length(); if ( flDistance <= flClosest ) { iCameraIndex = i; flClosest = flDistance; } } } } } CBasePlayer *pPlayer = NULL; if ( !Q_strcmp( "teamplay_point_captured", name ) ) { const char *pszCappers = event->m_Event->GetString("cappers"); int nLength = Q_strlen(pszCappers); if ( nLength > 0 ) { int iRandomCapper = pszCappers[ RandomInt(0,nLength-1) ]; pPlayer = UTIL_PlayerByIndex( iRandomCapper ); } } else if ( !Q_strcmp( "teamplay_capture_blocked", name ) ) { int iBlocker = event->m_Event->GetInt("blocker"); pPlayer = UTIL_PlayerByIndex( iBlocker ); } if ( pPlayer ) { if ( iCameraIndex >= 0 && RandomFloat() > 0.66f ) { StartFixedCameraShot( iCameraIndex, pPlayer->entindex() ); } else if ( pCapturePoint ) { StartChaseCameraShot( pPlayer->entindex(), pCapturePoint->entindex(), 96, 20, thera, false ); } else { StartChaseCameraShot( pPlayer->entindex(), 0, 96, 20, 0, false ); } } else if ( iCameraIndex >= 0 && pCapturePoint ) { // no player known for this event StartFixedCameraShot( iCameraIndex, pCapturePoint->entindex() ); } // shot 2 seconds after event m_nNextShotTick = min( m_nNextShotTick, (event->m_Tick+TIME_TO_TICKS(1.0)) ); } else if ( !Q_strcmp( "object_destroyed", name ) ) { CBasePlayer *attacker = UTIL_PlayerByUserId( event->m_Event->GetInt("attacker") ); if ( attacker ) { int iObjectIndex = event->m_Event->GetInt("index"); StartChaseCameraShot( attacker->entindex(), iObjectIndex, 96, 20, thera, false ); } } else if ( !Q_strcmp( "ctf_flag_captured", name ) ) { CBasePlayer *capper = UTIL_PlayerByUserId( event->m_Event->GetInt("capper") ); if ( capper ) { StartChaseCameraShot( capper->entindex(), 0, 96, 20, 0, false ); } } else if ( !Q_strcmp( "teamplay_flag_event", name ) ) { StartChaseCameraShot( event->m_Event->GetInt("player"), 0, 96, 20, 0, false ); } else { // let baseclass create a shot BaseClass::CreateShotFromEvent( event ); } }
inline int GetServerTickCount() { int nTick = TIME_TO_TICKS( engine->GetLastTimeStamp() ); return nTick; }
/*============================= * the appliation for mutex * 信号号申请操作 * 优先级继承的优先级反转解决 *=============================*/ acoral_u32 acoral_mutex_pend(acoral_evt_t *evt, acoral_time timeout) { acoral_sr cpu_sr; acoral_u8 highPrio; acoral_u8 ownerPrio; acoral_thread_t *thread; acoral_thread_t *cur; if(acoral_intr_nesting>0) return MUTEX_ERR_INTR; cur=acoral_cur_thread; HAL_ENTER_CRITICAL(); acoral_spin_lock(&evt->spin_lock); if (NULL== evt) { acoral_spin_unlock(&evt->spin_lock); HAL_EXIT_CRITICAL(); return MUTEX_ERR_NULL; } if ((acoral_u8)(evt->count & MUTEX_L_MASK) == MUTEX_AVAI) { /* 申请成功*/ evt->count &= MUTEX_U_MASK; evt->count |= cur->prio; evt->data = (void*)cur; acoral_spin_unlock(&evt->spin_lock); HAL_EXIT_CRITICAL(); return MUTEX_SUCCED; } /* 互斥量已被占有*/ /* 这里要看进程是否一个核上的*/ /* 是一个核上的任务才有可能发生优先级反转*/ highPrio = (acoral_u8)(evt->count >> 8); ownerPrio = (acoral_u8)(evt->count & MUTEX_L_MASK); thread = (acoral_thread_t*)evt->data; if (thread->prio != highPrio&&ownerPrio>cur->prio) { /*有可能优先级反转,提升拥有者优先级*/ if(highPrio==0) highPrio=cur->prio; acoral_thread_change_prio(thread,highPrio); } /*不需要或不能提高优先级*/ acoral_unrdy_thread(cur); acoral_evt_queue_add(evt,cur); if (timeout > 0) { /*加载到超时队列*/ cur->delay = TIME_TO_TICKS(timeout); timeout_queue_add(cur); } acoral_spin_unlock(&evt->spin_lock); HAL_EXIT_CRITICAL(); acoral_sched(); HAL_ENTER_CRITICAL(); acoral_spin_lock(&evt->spin_lock); if(evt->data!=cur&&timeout>0&&cur->delay<=0) { acoral_printk("Time Out Return\n"); acoral_evt_queue_del(cur); acoral_spin_unlock(&evt->spin_lock); HAL_EXIT_CRITICAL(); return MUTEX_ERR_TIMEOUT; } //--------------- // modify by pegasus 0804: timeout_queue_del [+] timeout_queue_del(cur); if(evt->data!=cur) { acoral_printk("Err Ready Return\n"); acoral_evt_queue_del(cur); acoral_spin_unlock(&evt->spin_lock); HAL_EXIT_CRITICAL(); return MUTEX_ERR_RDY; } return MUTEX_SUCCED; }
void Resolver::Resolve() { for (int i = 1; i <= g_GlobalVars->maxClients; i++) { auto &record = arr_infos[i]; if (!record.m_bActive) continue; C_BasePlayer *player = C_BasePlayer::GetPlayerByIndex(i); if (!player || !player->IsAlive() || player->IsDormant() || player == g_LocalPlayer) continue; if (record.m_flVelocity == 0.f && player->m_vecVelocity().Length2D() != 0.f) { Math::VectorAngles(player->m_vecVelocity(), record.m_angDirectionFirstMoving); record.m_nCorrectedFakewalkIdx = 0; } auto firedShots = g_LocalPlayer->m_iShotsFired(); if (g_Options.debug_fliponkey) { float_t new_yaw = player->m_flLowerBodyYawTarget(); if (g_InputSystem->IsButtonDown(g_Options.debug_flipkey)) new_yaw += 180.f; new_yaw = Math::ClampYaw(new_yaw); player->m_angEyeAngles().yaw = new_yaw; return; } if (g_Options.hvh_resolver_override && g_InputSystem->IsButtonDown(g_Options.hvh_resolver_override_key)) { Override(); //needs an improvement sometimes f****d up xD Global::resolverModes[player->EntIndex()] = "Overriding"; return; } AnimationLayer curBalanceLayer, prevBalanceLayer; ResolveInfo curtickrecord; curtickrecord.SaveRecord(player); if ((player->m_fFlags() & FL_ONGROUND) && (IsFakewalking(player, curtickrecord) || (player->m_vecVelocity().Length2D() > 0.1f && player->m_vecVelocity().Length2D() < 45.f && !(player->m_fFlags() & FL_DUCKING)))) //Fakewalk, shiftwalk check // We have to rework the fakewalk resolving, it sucks :D { float_t new_yaw = ResolveFakewalk(player, curtickrecord); new_yaw = Math::ClampYaw(new_yaw); player->m_angEyeAngles().yaw = new_yaw; Global::resolverModes[player->EntIndex()] = "Fakewalking"; continue; } if (IsEntityMoving(player)) { float_t new_yaw = player->m_flLowerBodyYawTarget(); new_yaw = Math::ClampYaw(new_yaw); player->m_angEyeAngles().yaw = new_yaw; record.m_flStandingTime = player->m_flSimulationTime(); record.m_flMovingLBY = player->m_flLowerBodyYawTarget(); record.m_bIsMoving = true; Global::resolverModes[player->EntIndex()] = "Moving"; continue; } if (IsAdjustingBalance(player, curtickrecord, &curBalanceLayer)) { if (fabsf(LBYDelta(curtickrecord)) > 35.f) { float_t new_yaw = player->m_flLowerBodyYawTarget() + record.m_flLbyDelta; new_yaw = Math::ClampYaw(new_yaw); player->m_angEyeAngles().yaw = new_yaw; Global::resolverModes[player->EntIndex()] = "Fakehead (delta > 35)"; } if (IsAdjustingBalance(player, record, &prevBalanceLayer)) { if ((prevBalanceLayer.m_flCycle != curBalanceLayer.m_flCycle) || curBalanceLayer.m_flWeight == 1.f) { float flAnimTime = curBalanceLayer.m_flCycle, flSimTime = player->m_flSimulationTime(); if (flAnimTime < 0.01f && prevBalanceLayer.m_flCycle > 0.01f && g_Options.rage_lagcompensation && CMBacktracking::Get().IsTickValid(TIME_TO_TICKS(flSimTime - flAnimTime))) { CMBacktracking::Get().SetOverwriteTick(player, QAngle(player->m_angEyeAngles().pitch, player->m_flLowerBodyYawTarget(), 0), (flSimTime - flAnimTime), 2); } float_t new_yaw = player->m_flLowerBodyYawTarget(); new_yaw = Math::ClampYaw(new_yaw); player->m_angEyeAngles().yaw = new_yaw; Global::resolverModes[player->EntIndex()] = "Breaking LBY"; continue; } else if (curBalanceLayer.m_flWeight == 0.f && (prevBalanceLayer.m_flCycle > 0.92f && curBalanceLayer.m_flCycle > 0.92f)) // breaking lby with delta < 120 { if (player->m_flSimulationTime() >= record.m_flStandingTime + 0.22f && record.m_bIsMoving) { record.m_flLbyDelta = record.m_flLowerBodyYawTarget - player->m_flLowerBodyYawTarget(); float_t new_yaw = player->m_flLowerBodyYawTarget() + record.m_flLbyDelta; new_yaw = Math::ClampYaw(new_yaw); player->m_angEyeAngles().yaw = new_yaw; record.m_bIsMoving = false; Global::resolverModes[player->EntIndex()] = "Breaking LBY (delta < 120)"; continue; } if (player->m_flSimulationTime() >= record.m_flStandingTime + 1.32f && std::fabsf(record.m_flLbyDelta) < 35.f) { record.m_flLbyDelta = record.m_flMovingLBY - player->m_flLowerBodyYawTarget(); float_t new_yaw = player->m_flLowerBodyYawTarget() + record.m_flLbyDelta; new_yaw = Math::ClampYaw(new_yaw); player->m_angEyeAngles().yaw = new_yaw; record.m_bIsMoving = false; Global::resolverModes[player->EntIndex()] = "LBY delta < 35"; continue; } } } else { float_t new_yaw = player->m_flLowerBodyYawTarget(); new_yaw = Math::ClampYaw(new_yaw); player->m_angEyeAngles().yaw = new_yaw; Global::resolverModes[player->EntIndex()] = "Other"; continue; } } if (player->m_flSimulationTime() >= record.m_flStandingTime + 0.22f && record.m_bIsMoving) { record.m_flLbyDelta = record.m_flLowerBodyYawTarget - player->m_flLowerBodyYawTarget(); float_t new_yaw = player->m_flLowerBodyYawTarget() + record.m_flLbyDelta; new_yaw = Math::ClampYaw(new_yaw); player->m_angEyeAngles().yaw = new_yaw; record.m_bIsMoving = false; Global::resolverModes[player->EntIndex()] = "Breaking LBY (delta < 120)"; continue; } if (player->m_flSimulationTime() >= record.m_flStandingTime + 1.32f && std::fabsf(record.m_flLbyDelta) < 35.f) { record.m_flLbyDelta = record.m_flMovingLBY - player->m_flLowerBodyYawTarget(); float_t new_yaw = player->m_flLowerBodyYawTarget() + record.m_flLbyDelta; new_yaw = Math::ClampYaw(new_yaw); player->m_angEyeAngles().yaw = new_yaw; record.m_bIsMoving = false; Global::resolverModes[player->EntIndex()] = "LBY delta < 35"; continue; } float_t new_yaw = player->m_flLowerBodyYawTarget() + record.m_flLbyDelta; new_yaw = Math::ClampYaw(new_yaw); player->m_angEyeAngles().yaw = new_yaw; } }
CGameEvent *CHLTVDirector::FindBestGameEvent() { int bestEvent[4]; int bestEventPrio[4]; Q_memset( bestEvent, 0, sizeof(bestEvent) ); Q_memset( bestEventPrio, 0, sizeof(bestEventPrio) ); int index = FindFirstEvent( m_nBroadcastTick ); // search for next 4 best events within next 8 seconds for (int i = 0; i<4; i ++) { bestEventPrio[i] = 0; bestEvent[i] = 0; int tillTick = m_nBroadcastTick + TIME_TO_TICKS( 2.0f*(1.0f+i) ); if ( tillTick > m_nNextShotTick ) break; // sum all action for the next time while ( index != m_EventHistory.InvalidIndex() ) { CGameEvent &event = m_EventHistory[index]; if ( event.m_Tick > tillTick ) break; int priority = event.m_Priority; if ( priority > bestEventPrio[i] ) { bestEvent[i] = index; bestEventPrio[i] = priority; } index = m_EventHistory.NextInorder( index ); } } if ( !( bestEventPrio[0] || bestEventPrio[1] || bestEventPrio[2] ) ) return NULL; // no event found at all, give generic algorithm a chance // camera cut rules : if ( bestEventPrio[1] >= bestEventPrio[0] && bestEventPrio[1] >= bestEventPrio[2] && bestEventPrio[1] >= bestEventPrio[3] ) { return &m_EventHistory[ bestEvent[1] ]; // best case } else if ( bestEventPrio[0] > bestEventPrio[1] && bestEventPrio[0] > bestEventPrio[2] ) { return &m_EventHistory[ bestEvent[0] ]; // event 0 is very important } else if ( bestEventPrio[2] > bestEventPrio[3] ) { return &m_EventHistory[ bestEvent[2] ]; } else { // event 4 is the best but too far away, so show event 1 if ( bestEvent[0] ) return &m_EventHistory[ bestEvent[0] ]; else return NULL; } }
void CHLTVDirector::StartNewShot() { // we can remove all events the int smallestTick = MAX(0, gpGlobals->tickcount - TIME_TO_TICKS(HLTV_MAX_DELAY) ); RemoveEventsFromHistory( smallestTick ); if ( m_iCameraMan > 0 ) { // we already have an active camera man, // wait until he releases the "record" lock FinishCameraManShot(); return; } if ( StartCameraManShot() ) { // now we have an active camera man return; } // ok, no camera man active, now check how much time // we have for the next shot, if the time diff to the next // important event we have to switch to is too short (<2sec) // just extent the current shot and don't start a new one // check the next 8 seconds for interrupts/important events m_nNextShotTick = m_nBroadcastTick + TIME_TO_TICKS( MAX_SHOT_LENGTH ); if ( m_nBroadcastTick <= 0 ) { // game hasn't started yet, we are still in the broadcast delay hole IGameEvent *msg = gameeventmanager->CreateEvent( "hltv_message", true ); if ( msg ) { msg->SetString("text", "Please wait for broadcast to start ..." ); // send spectators the HLTV director command as a game event m_pHLTVServer->BroadcastEvent( msg ); gameeventmanager->FreeEvent( msg ); } StartBestFixedCameraShot( true ); return; } int index = FindFirstEvent( m_nBroadcastTick ); while( index != m_EventHistory.InvalidIndex() ) { CGameEvent &dc = m_EventHistory[index]; if ( dc.m_Tick >= m_nNextShotTick ) break; // we have searched enough // a camera man is always interrupting auto director if ( Q_strcmp( dc.m_Event->GetName(), "hltv_cameraman") == 0 ) { if ( dc.m_Event->GetInt("index") > 0 ) { // stop the next cut when this cameraman starts recording m_nNextShotTick = dc.m_Tick; break; } } index = m_EventHistory.NextInorder( index ); } float flDuration = TICKS_TO_TIME(m_nNextShotTick - m_nBroadcastTick); if ( flDuration < MIN_SHOT_LENGTH ) return; // not enough time for a new shot // find the most intesting game event for next shot CGameEvent *dc = FindBestGameEvent(); if ( dc ) { // show the game event CreateShotFromEvent( dc ); } else { // no interesting events found, start random shot StartRandomShot(); } }
/*=================================== * * 消息接收 *===================================*/ void* acoral_msg_recv (acoral_msgctr_t* msgctr, acoral_u32 id, acoral_time timeout, acoral_u32 *err) { void *dat; acoral_sr cpu_sr; acoral_list_t *p, *q; acoral_msg_t *pmsg; acoral_thread_t *cur; if (acoral_intr_nesting > 0) { *err = MST_ERR_INTR; return NULL; } if (NULL == msgctr) { *err = MST_ERR_NULL; return NULL; } cur = acoral_cur_thread; HAL_ENTER_CRITICAL(); acoral_spin_lock(&msgctr->spin_lock); if(timeout>0){ cur->delay = TIME_TO_TICKS(timeout); timeout_queue_add( cur); } while(1) { p = &msgctr->msglist; q = p->next; for( ;p != q; q = q->next) { pmsg = list_entry( q, acoral_msg_t, msglist); if ( (pmsg->id == id) && (pmsg->n > 0)) { /*-----------------*/ /* 有接收消息*/ /*-----------------*/ pmsg->n--; /*-----------------*/ /* 延时列表删除*/ /*-----------------*/ timeout_queue_del(cur); dat = pmsg->data; acoral_list_del (q); acoral_release_res ((acoral_res_t *)pmsg); msgctr->count--; acoral_spin_unlock(&msgctr->spin_lock); HAL_EXIT_CRITICAL(); return dat; } } /*-----------------*/ /* 没有接收消息*/ /*-----------------*/ msgctr->wait_thread_num++; acoral_msgctr_queue_add(msgctr, cur); acoral_unrdy_thread(cur); acoral_spin_unlock(&msgctr->spin_lock); HAL_EXIT_CRITICAL(); acoral_sched(); /*-----------------*/ /* 看有没有超时*/ /*-----------------*/ HAL_ENTER_CRITICAL(); acoral_spin_lock(&msgctr->spin_lock); if (timeout>0&&(acoral_32)cur->delay <=0 ) break; } /*---------------*/ /* 超时退出*/ /*---------------*/ // timeout_queue_del(cur); if(msgctr->wait_thread_num>0) msgctr->wait_thread_num--; acoral_list_del(&cur->waiting); acoral_spin_unlock(&msgctr->spin_lock); HAL_EXIT_CRITICAL(); *err = MST_ERR_TIMEOUT; return NULL; }
void CHLTVDirector::CreateShotFromEvent( CGameEvent *event ) { // show event at least for 2 more seconds after it occured const char *name = event->m_Event->GetName(); IGameEvent *shot = NULL; bool bPlayerHurt = Q_strcmp( "player_hurt", name ) == 0; bool bPlayerKilled = Q_strcmp( "player_death", name ) == 0; bool bRoundStart = Q_strcmp( "round_start", name ) == 0; bool bRoundEnd = Q_strcmp( "round_end", name ) == 0; if ( bPlayerHurt || bPlayerKilled ) { CBaseEntity *victim = UTIL_PlayerByUserId( event->m_Event->GetInt("userid") ); CBaseEntity *attacker = UTIL_PlayerByUserId( event->m_Event->GetInt("attacker") ); if ( !victim ) return; if ( attacker == victim || attacker == NULL ) { // player killed self or by WORLD shot = gameeventmanager->CreateEvent( "hltv_chase", true ); shot->SetInt( "target1", victim->entindex() ); shot->SetInt( "target2", 0 ); shot->SetInt( "theta", 0 ); // view from behind over head shot->SetInt( "phi", 20 ); // from above shot->SetFloat( "distance", 96.0f ); } else // attacker != NULL { // check if we would show it from ineye view bool bInEye = (bPlayerKilled && RandomFloat(0,1) > 0.33) || (bPlayerHurt && RandomFloat(0,1) > 0.66); // if we show ineye view, show it more likely from killer if ( RandomFloat(0,1) > (bInEye?0.3f:0.7f) ) { swap( attacker, victim ); } // hurting a victim is shown as chase more often shot = gameeventmanager->CreateEvent( "hltv_chase", true ); shot->SetInt( "target1", victim->entindex() ); shot->SetInt( "target2", attacker->entindex() ); // view from behind over head shot->SetInt( "phi", -20 ); // lower view point, dramatic shot->SetFloat( "distance", 96.0f ); shot->SetInt( "ineye", bInEye?1:0 ); // view over shoulder, randomly left or right if ( RandomFloat(0,1) > 0.5 ) { shot->SetInt( "theta", 30 ); // swing left } else { shot->SetInt( "theta", -30 ); // swing right } } // shot 2 seconds after death/hurt m_nNextShotTick = MIN( m_nNextShotTick, (event->m_Tick+TIME_TO_TICKS(2.0)) ); m_iPVSEntity = victim->entindex(); } else if ( bRoundStart || bRoundEnd ) { StartBestFixedCameraShot( false ); } else { DevMsg( "No known TV shot for event %s\n", name ); } if ( shot ) { m_pHLTVServer->BroadcastEvent( shot ); gameeventmanager->FreeEvent( shot ); } }
void CCSHLTVDirector::CreateShotFromEvent( CHLTVGameEvent *event ) { // show event at least for 2 more seconds after it occured const char *name = event->m_Event->GetName(); IGameEvent *shot = NULL; if ( !Q_strcmp( "hostage_rescued", name ) || !Q_strcmp( "hostage_hurt", name ) || !Q_strcmp( "hostage_follows", name ) || !Q_strcmp( "hostage_killed", name ) ) { CBaseEntity *player = UTIL_PlayerByUserId( event->m_Event->GetInt("userid") ); if ( !player ) return; // shot player as primary, hostage as secondary target shot = gameeventmanager->CreateEvent( "hltv_chase", true ); shot->SetInt( "target1", player->entindex() ); shot->SetInt( "target2", event->m_Event->GetInt("hostage") ); shot->SetFloat( "distance", 96.0f ); shot->SetInt( "theta", 40 ); shot->SetInt( "phi", 20 ); // shot 2 seconds after event m_nNextShotTick = min( m_nNextShotTick, (event->m_Tick+TIME_TO_TICKS(2.0)) ); m_iPVSEntity = player->entindex(); } else if ( !Q_strcmp( "bomb_pickup", name ) || !Q_strcmp( "bomb_dropped", name ) || !Q_strcmp( "bomb_planted", name ) || !Q_strcmp( "bomb_defused", name ) ) { CBaseEntity *player = UTIL_PlayerByUserId( event->m_Event->GetInt("userid") ); if ( !player ) return; shot = gameeventmanager->CreateEvent( "hltv_chase", true ); shot->SetInt( "target1", player->entindex() ); shot->SetInt( "target2", 0 ); shot->SetFloat( "distance", 64.0f ); shot->SetInt( "theta", 200 ); shot->SetInt( "phi", 10 ); // shot 2 seconds after pickup m_nNextShotTick = min( m_nNextShotTick, (event->m_Tick+TIME_TO_TICKS(2.0)) ); m_iPVSEntity = player->entindex(); } else { // let baseclass create a shot BaseClass::CreateShotFromEvent( event ); return; } if ( shot ) { m_pHLTVServer->BroadcastEvent( shot ); gameeventmanager->FreeEvent( shot ); DevMsg("DrcCmd: %s\n", name ); } }