sasalka/Code/NetworkManager.cs
2025-06-29 12:39:23 +03:00

127 lines
3.2 KiB
C#

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Sandbox;
/// <summary>
/// Creates a networked game lobby and assigns player prefabs to connected clients.
/// </summary>
[Title( "Network Manager" )]
[Category( "Networking" )]
[Icon( "electrical_services" )]
public sealed class NetworkManager : Component, Component.INetworkListener
{
/// <summary>
/// Create a server (if we're not joining one)
/// </summary>
[Property]
public bool StartServer { get; set; } = true;
/// <summary>
/// The prefab to spawn for the player to control.
/// </summary>
[Property]
public GameObject PlayerPrefab { get; set; }
/// <summary>
/// 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.
/// </summary>
[Property]
public List<GameObject> 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() );
}
}
/// <summary>
/// A client is fully connected to the server. This is called on the host.
/// </summary>
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<Dedugan>( true );
dedugan.SetupConnection( channel );
}
/// <summary>
/// Called when a client disconnects from the server.
/// </summary>
public void OnDisconnected( Connection channel )
{
// Сохраняем инвентарь игрока перед отключением
var player = Dedugan.GetByID( channel.Id );
if ( player != null )
{
player.SaveInventoryOnExit();
}
Dedugan.InternalPlayers.Remove( Dedugan.GetByID( channel.Id ) );
}
/// <summary>
/// Called when the connection is being torn down.
/// </summary>
public void OnBecomeInactive( Connection channel )
{
// Сохраняем инвентарь игрока при разрыве соединения
var player = Dedugan.GetByID( channel.Id );
if ( player != null )
{
player.SaveInventoryOnExit();
}
}
/// <summary>
/// Find the most appropriate place to respawn
/// </summary>
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<SpawnPoint>().ToArray();
if ( spawnPoints.Length > 0 )
{
return Random.Shared.FromArray( spawnPoints ).WorldTransform;
}
//
// Failing that, spawn where we are
//
return WorldTransform;
}
}