components/game.cs

Game component that manages lobby and round lifecycle for a simple SCP-style game. It creates a lobby on host start, tracks connections and scene objects tagged as humans, scps, and spectators, assigns one random player as SCP_173 at round start, spawns DBoi for others, and cleans up objects when round ends.

Networking
using Sandbox;
using Sandbox.Network;
using System.Collections.Generic;
using System.Linq;
using System;
using Sandbox.Platform;

public class game : Component, Component.INetworkListener
{
    [Property] public GameObject DBoi {get;set;}
    [Property] public GameObject SCP_173 {get;set;}
    [Property] public GameObject Spectator {get;set;}
    [Property] public GameObject Map {get;set;}
    
    List<GameObject> Humans = new List<GameObject>();
    List<GameObject> SCPs = new List<GameObject>();
    List<GameObject> Spectators = new List<GameObject>();
    List<Connection> Players = new List<Connection>();
    
    bool IsActive;
    bool Can_Start_OR_Stop = true;
    Random random;
    
    protected override async void OnStart()
    {if (!Networking.IsHost) return; random = new Random();
    Networking.CreateLobby(new LobbyConfig());
    await Task.Delay(50); Chat.AddText("You need at least 2 players");}
    
    protected override void OnUpdate()
    { if (!Networking.IsHost) return;
        Lists(); Starting(); Stopping();
    }
    
    void Lists()
    {
        Humans = new List<GameObject>(Scene.FindAllWithTag("human"));
        SCPs = new List<GameObject>(Scene.FindAllWithTag("scp"));
        Spectators = new List<GameObject>(Scene.FindAllWithTag("spectator"));
        
        Players = Connection.All.ToList();
        for (int i = Players.Count - 1; i >= 0; i--)
        {if (!Players[i].IsActive)
        {Players.RemoveAt(i); continue;}}
    }
    
    void Starting()
    {
        if (Players.Count >= 2 && !IsActive && Can_Start_OR_Stop)
        { Grace(); IsActive = true;
            var Spawnpoints = new List<GameObject>(Map.Children);
            for (int i = Spawnpoints.Count - 1; i >= 0; i--)
            {if (Spawnpoints[i].Name != "info_player_start")
            {Spawnpoints.RemoveAt(i); continue;}}
            
            var SCP = Players[random.Next(Players.Count)];
            var SCP_Spawnpoint = Spawnpoints[random.Next(Spawnpoints.Count)];
            
            foreach (var Player in Players)
            {
                if (Player == SCP)
                {
                    var scp173 = SCP_173.Clone(SCP_Spawnpoint.WorldPosition);
                    Spawnpoints.Remove(SCP_Spawnpoint);
                    scp173.NetworkSpawn(Player);
                continue; }
                
                var dboi = DBoi.Clone(Spawnpoints[random.Next(Spawnpoints.Count)].WorldPosition);
                dboi.NetworkSpawn(Player);
            }
            
            foreach (var spectator in Spectators)
                spectator.Destroy();
        }
    }
    
    void Stopping()
    {
        if ((Humans.Count <= 0 || SCPs.Count <= 0) && IsActive && Can_Start_OR_Stop)
        { Grace(); IsActive = false;
            foreach (var SCP in SCPs)
                SCP.Destroy();
            
            foreach (var Human in Humans)
                Human.Destroy();
            
            foreach (var spectator in Spectators)
                spectator.Destroy();
        }
    }
    
    async void Grace()
    {
        Can_Start_OR_Stop = false;
        await Task.Delay(50);
        Can_Start_OR_Stop = true;
    }
    
    public void OnActive(Connection c)
    {
        if (!IsActive || Players.Count < 2)
        {
            var spectator = Spectator.Clone();
            spectator.NetworkSpawn(c);
        }
    }
}