| 434 | } |
| 435 | |
| 436 | void CGameContext::SnapSwitchers(int SnappingClient) |
| 437 | { |
| 438 | if(Switchers().empty()) |
| 439 | return; |
| 440 | |
| 441 | CPlayer *pPlayer = SnappingClient != SERVER_DEMO_CLIENT ? m_apPlayers[SnappingClient] : nullptr; |
| 442 | int Team = pPlayer && pPlayer->GetCharacter() ? pPlayer->GetCharacter()->Team() : 0; |
| 443 | |
| 444 | if(pPlayer && (pPlayer->GetTeam() == TEAM_SPECTATORS || pPlayer->IsPaused()) && pPlayer->SpectatorId() != SPEC_FREEVIEW && m_apPlayers[pPlayer->SpectatorId()] && m_apPlayers[pPlayer->SpectatorId()]->GetCharacter()) |
| 445 | Team = m_apPlayers[pPlayer->SpectatorId()]->GetCharacter()->Team(); |
| 446 | |
| 447 | if(Team == TEAM_SUPER) |
| 448 | return; |
| 449 | |
| 450 | int SentTeam = Team; |
| 451 | if(g_Config.m_SvTeam == SV_TEAM_FORCED_SOLO) |
| 452 | SentTeam = 0; |
| 453 | |
| 454 | CNetObj_SwitchState *pSwitchState = Server()->SnapNewItem<CNetObj_SwitchState>(SentTeam); |
| 455 | if(!pSwitchState) |
| 456 | return; |
| 457 | |
| 458 | pSwitchState->m_HighestSwitchNumber = std::clamp((int)Switchers().size() - 1, 0, 255); |
| 459 | std::fill(std::begin(pSwitchState->m_aStatus), std::end(pSwitchState->m_aStatus), 0); |
| 460 | |
| 461 | std::vector<std::pair<int, int>> vEndTicks; // <EndTick, SwitchNumber> |
| 462 | |
| 463 | for(int i = 0; i <= pSwitchState->m_HighestSwitchNumber; i++) |
| 464 | { |
| 465 | int Status = (int)Switchers()[i].m_aStatus[Team]; |
| 466 | pSwitchState->m_aStatus[i / 32] |= (Status << (i % 32)); |
| 467 | |
| 468 | int EndTick = Switchers()[i].m_aEndTick[Team]; |
| 469 | if(EndTick > 0 && EndTick < Server()->Tick() + 3 * Server()->TickSpeed() && Switchers()[i].m_aLastUpdateTick[Team] < Server()->Tick()) |
| 470 | { |
| 471 | // only keep track of EndTicks that have less than three second left and are not currently being updated by a player being present on a switch tile, to limit how often these are sent |
| 472 | vEndTicks.emplace_back(Switchers()[i].m_aEndTick[Team], i); |
| 473 | } |
| 474 | } |
| 475 | |
| 476 | // send the endtick of switchers that are about to toggle back (up to four, prioritizing those with the earliest endticks) |
| 477 | std::fill(std::begin(pSwitchState->m_aSwitchNumbers), std::end(pSwitchState->m_aSwitchNumbers), 0); |
| 478 | std::fill(std::begin(pSwitchState->m_aEndTicks), std::end(pSwitchState->m_aEndTicks), 0); |
| 479 | |
| 480 | std::sort(vEndTicks.begin(), vEndTicks.end()); |
| 481 | const int NumTimedSwitchers = minimum((int)vEndTicks.size(), (int)std::size(pSwitchState->m_aEndTicks)); |
| 482 | |
| 483 | for(int i = 0; i < NumTimedSwitchers; i++) |
| 484 | { |
| 485 | pSwitchState->m_aSwitchNumbers[i] = vEndTicks[i].second; |
| 486 | pSwitchState->m_aEndTicks[i] = vEndTicks[i].first; |
| 487 | } |
| 488 | } |
| 489 | |
| 490 | bool CGameContext::SnapLaserObject(const CSnapContext &Context, int SnapId, const vec2 &To, const vec2 &From, int StartTick, int Owner, int LaserType, int Subtype, int SwitchNumber) const |
| 491 | { |