using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Sandbox;
///
/// Creates a networked game lobby and assigns player prefabs to connected clients.
///
[Title( "Network Manager" )]
[Category( "Networking" )]
[Icon( "electrical_services" )]
public sealed class NetworkManager : Component, Component.INetworkListener
{
///
/// Create a server (if we're not joining one)
///
[Property]
public bool StartServer { get; set; } = true;
///
/// The prefab to spawn for the player to control.
///
[Property]
public GameObject PlayerPrefab { get; set; }
///
/// A list of points to choose from randomly to spawn the player in. If not set, we'll spawn at the
/// location of the NetworkHelper object.
///
[Property]
public List SpawnPoints { get; set; }
protected override async Task OnLoad()
{
if ( Scene.IsEditor )
return;
if ( StartServer && !Networking.IsActive )
{
LoadingScreen.Title = "Creating Lobby";
await Task.DelayRealtimeSeconds( 0.1f );
Networking.CreateLobby( new() );
}
}
///
/// A client is fully connected to the server. This is called on the host.
///
public void OnActive( Connection channel )
{
Log.Info( $"Player '{channel.DisplayName}' has joined the game" );
if ( !PlayerPrefab.IsValid() )
return;
//
// Find a spawn location for this player
//
var startLocation = FindSpawnLocation().WithScale( 1 );
// Spawn this object and make the client the owner
var player = PlayerPrefab.Clone( startLocation, name: $"Player - {channel.DisplayName}" );
player.NetworkSpawn( channel );
var dedugan = player.Components.Get( true );
dedugan.SetupConnection( channel );
}
///
/// Called when a client disconnects from the server.
///
public void OnDisconnected( Connection channel )
{
}
///
/// Called when the connection is being torn down.
///
public void OnBecomeInactive( Connection channel )
{
// Optional: Handle any cleanup before player becomes fully inactive
}
///
/// Find the most appropriate place to respawn
///
Transform FindSpawnLocation()
{
//
// If they have spawn point set then use those
//
if ( SpawnPoints is not null && SpawnPoints.Count > 0 )
{
return Random.Shared.FromList( SpawnPoints, default ).WorldTransform;
}
//
// If we have any SpawnPoint components in the scene, then use those
//
var spawnPoints = Scene.GetAllComponents().ToArray();
if ( spawnPoints.Length > 0 )
{
return Random.Shared.FromArray( spawnPoints ).WorldTransform;
}
//
// Failing that, spawn where we are
//
return WorldTransform;
}
}