RoundManager component that controls round lifecycle. It starts rounds, tracks remaining time and round state, resets the arena, respawns players, detects eliminations to end rounds, and advances the round counter.
using Sandbox;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
public sealed class RoundManager : Component
{
public static RoundManager Instance { get; private set; }
[Property] public float RoundTime { get; set; } = 120f;
[Sync] public float TimeLeft { get; set; }
[Sync] public bool IsInRound { get; set; }
[Sync] public int CurrentRound { get; set; } = 1;
protected override void OnAwake()
{
Instance = this;
}
protected override void OnStart()
{
StartNewRound();
}
public void StartNewRound()
{
TimeLeft = RoundTime;
IsInRound = true;
ResetArena();
RespawnAllPlayers();
var shrinker = Scene.GetAllComponents<ArenaShrinker>().FirstOrDefault();
if ( shrinker.IsValid() )
{
shrinker.StartRound();
}
Log.Info( $"[RoundManager] Раунд {CurrentRound} начат!" );
}
public void OnPlayerEliminated( GameObject player )
{
if ( !IsInRound ) return;
if ( player.IsValid() )
{
player.Enabled = false;
}
var activePlayers = Scene.GetAllComponents<PushAbility>()
.Where( p => p.GameObject.IsValid() && p.GameObject.Enabled );
if ( activePlayers.Count() <= 1 )
{
_ = EndRound();
}
}
public async Task EndRound()
{
if ( !IsInRound ) return;
var winner = Scene.GetAllComponents<PushAbility>()
.FirstOrDefault( p => p.GameObject.IsValid() && p.GameObject.Enabled );
if ( winner.IsValid() && !winner.IsProxy )
{
GameServices.RecordRoundWin();
}
_ = GameServices.SaveStatsAsync();
IsInRound = false;
CurrentRound++;
Log.Info( $"Раунд {CurrentRound - 1} завершен! Перезапуск через 3 секунды..." );
await Task.DelaySeconds( 3f );
StartNewRound();
}
private void ResetArena()
{
var tiles = Scene.GetAllComponents<ArenaTile>();
foreach ( var tile in tiles )
{
if ( tile.IsValid() )
{
tile.ResetTile();
}
}
}
private void RespawnAllPlayers()
{
var spawn = Scene.GetAllComponents<SpawnPoint>().FirstOrDefault();
Vector3 spawnPos = spawn.IsValid() ? spawn.WorldPosition : new Vector3( 0, 0, 250 );
var players = Scene.GetAllComponents<PushAbility>();
foreach ( var player in players )
{
if ( !player.IsValid() ) continue;
var root = player.GameObject.Root;
root.Enabled = true;
root.WorldPosition = spawnPos;
var cc = root.Components.Get<CharacterController>( true );
if ( cc.IsValid() )
{
cc.Velocity = Vector3.Zero;
}
var rb = root.Components.Get<Rigidbody>( true );
if ( rb.IsValid() )
{
rb.Velocity = Vector3.Zero;
rb.AngularVelocity = Vector3.Zero;
}
}
}
}