Bug Fixes

This commit is contained in:
2026-07-03 17:44:41 +03:00
parent 3d423974eb
commit 26b896c39d
8 changed files with 2006 additions and 119 deletions
@@ -38,6 +38,10 @@ public class RoundManager : NetworkBehaviour
private List<PlayerHealth> alivePlayers = new List<PlayerHealth>();
// Точки спавна, назначенные игрокам в этом раунде (параллельно alivePlayers).
// Нужны, чтобы дождаться, пока серверная позиция догонит телепорт, перед стартом записи.
private List<Vector3> spawnAssignments = new List<Vector3>();
private NetworkList<PlayerScore> playerScores = new NetworkList<PlayerScore>();
// pitDefenders[i] = ClientId игрока, которому принадлежит яма с pitIndex == i
@@ -97,8 +101,13 @@ public class RoundManager : NetworkBehaviour
// Своя яма — не считается, побеждают только за попадание в ЧУЖУЮ яму.
// Для клона сюда приходит ClientId его ОРИГИНАЛА (см. PitZone) — правило работает так же.
if (_enteringClientId == pitDefenders[_pitIndex]) return;
if (_enteringClientId == pitDefenders[_pitIndex])
{
Debug.Log($"[ROUND] pit{_pitIndex} own pit by {_enteringClientId} — no score");
return;
}
Debug.Log($"[ROUND] WIN pit{_pitIndex} by client={_enteringClientId} (defender={pitDefenders[_pitIndex]}) round={currentRound.Value} timeLeft={roundTimeRemaining.Value:F1}");
AddScore(_enteringClientId);
StartCoroutine(EndRound(_enteringClientId));
}
@@ -177,6 +186,7 @@ public class RoundManager : NetworkBehaviour
private IEnumerator EndRound(ulong _winnerClientId)
{
Debug.Log($"[ROUND] EndRound round={currentRound.Value} winner={_winnerClientId} timeLeft={roundTimeRemaining.Value:F1}");
isRoundActive.Value = false;
// Сразу: стоп клонов + запись раунда в архив.
@@ -219,6 +229,7 @@ public class RoundManager : NetworkBehaviour
_players.Sort((_a, _b) => _a.OwnerClientId.CompareTo(_b.OwnerClientId));
alivePlayers.Clear();
spawnAssignments.Clear();
// Одна яма на игрока: игрок с индексом _q защищает яму pitIndex == _q
pitDefenders = new ulong[_players.Count];
@@ -231,12 +242,59 @@ public class RoundManager : NetworkBehaviour
pitDefenders[_q] = _clientId;
Vector3 _spawnPosition = spawnPoints[_q % spawnPoints.Length].position;
// Диагностика: спавн-поинт не должен быть внутри триггера ямы,
// иначе клон заспавнится в яме и мгновенно "победит".
Collider[] _overlaps = Physics.OverlapSphere(_spawnPosition, 0.5f, ~0, QueryTriggerInteraction.Collide);
foreach (Collider _c in _overlaps)
if (_c.GetComponentInParent<PitZone>() != null)
Debug.LogError($"[ROUND] SPAWN {_q} at {_spawnPosition} INSIDE PIT '{_c.name}' для client={_clientId} — это причина мгновенной победы клона!");
_players[_q].Respawn(_spawnPosition);
alivePlayers.Add(_players[_q]);
spawnAssignments.Add(_spawnPosition);
}
}
// Ждём, пока серверная позиция каждого игрока догонит телепорт на спавн.
// Иначе первый сэмпл записи (positions[0]) окажется там, где игрок умер (в яме),
// и клон следующего раунда заспавнится прямо в яме → мгновенная ложная победа.
private IEnumerator WaitForPlayersAtSpawn()
{
float _timeout = Time.time + 3f;
float _start = Time.time;
while (Time.time < _timeout)
{
bool _allAtSpawn = true;
for (int _i = 0; _i < alivePlayers.Count; _i++)
{
if (alivePlayers[_i] == null) continue;
float _dist = Vector3.Distance(alivePlayers[_i].transform.position, spawnAssignments[_i]);
if (_dist > 1.5f)
{
_allAtSpawn = false;
break;
}
}
if (_allAtSpawn)
{
Debug.Log($"[ROUND] players at spawn after {Time.time - _start:F2}s");
yield break;
}
yield return null;
}
Debug.LogWarning($"[ROUND] WaitForPlayersAtSpawn TIMEOUT after 3s — positions may still be stale:");
for (int _i = 0; _i < alivePlayers.Count; _i++)
if (alivePlayers[_i] != null)
Debug.LogWarning($"[ROUND] player {alivePlayers[_i].OwnerClientId} pos={alivePlayers[_i].transform.position} target={spawnAssignments[_i]} dist={Vector3.Distance(alivePlayers[_i].transform.position, spawnAssignments[_i]):F2}");
}
private IEnumerator StartRoundWithDelay()
{
yield return new WaitForSeconds(1f);
@@ -245,6 +303,10 @@ public class RoundManager : NetworkBehaviour
RespawnAllPlayers();
// КРИТИЧНО: ждём, пока серверная позиция игроков реально станет спавном,
// прежде чем начинать запись — иначе клоны будут спавниться в яме (см. WaitForPlayersAtSpawn).
yield return WaitForPlayersAtSpawn();
// Спавним клонов прошлых раундов и включаем запись у живых игроков
if (GhostRoundManager.Current != null)
GhostRoundManager.Current.ServerStartRound();
@@ -252,6 +314,7 @@ public class RoundManager : NetworkBehaviour
roundTimeRemaining.Value = roundDuration.Value;
isRoundActive.Value = true;
Debug.Log($"[ROUND] START round={currentRound.Value} players={alivePlayers.Count}");
RoundStartedClientRPC(currentRound.Value);
}