138 lines
4.8 KiB
C#
138 lines
4.8 KiB
C#
using System.Collections;
|
|
using NitroxClient.GameLogic.PlayerLogic.PlayerModel.Abstract;
|
|
using NitroxClient.MonoBehaviours;
|
|
using NitroxModel.DataStructures;
|
|
using NitroxModel.DataStructures.GameLogic.Entities;
|
|
using NitroxModel.DataStructures.Util;
|
|
using NitroxModel_Subnautica.DataStructures;
|
|
using UnityEngine;
|
|
|
|
namespace NitroxClient.GameLogic.Spawning.WorldEntities;
|
|
|
|
public class PlayerWorldEntitySpawner : IWorldEntitySpawner
|
|
{
|
|
private readonly PlayerManager playerManager;
|
|
private readonly ILocalNitroxPlayer localPlayer;
|
|
|
|
public PlayerWorldEntitySpawner(PlayerManager playerManager, ILocalNitroxPlayer localPlayer)
|
|
{
|
|
this.playerManager = playerManager;
|
|
this.localPlayer = localPlayer;
|
|
}
|
|
|
|
public IEnumerator SpawnAsync(WorldEntity entity, Optional<GameObject> parent, EntityCell cellRoot, TaskResult<Optional<GameObject>> result)
|
|
{
|
|
if (Player.main.TryGetNitroxId(out NitroxId localPlayerId) && localPlayerId == entity.Id)
|
|
{
|
|
// No special setup for the local player. Simply return saying it is spawned.
|
|
result.Set(Player.main.gameObject);
|
|
yield break;
|
|
}
|
|
|
|
Optional<RemotePlayer> remotePlayer = playerManager.Find(entity.Id);
|
|
|
|
// The server may send us a player entity but they are not guarenteed to be actively connected at the moment - don't spawn them. In the
|
|
// future, we could make this configurable to be able to spawn disconnected players in the world.
|
|
if (remotePlayer.HasValue && !remotePlayer.Value.Body)
|
|
{
|
|
GameObject remotePlayerBody = CloneLocalPlayerBodyPrototype();
|
|
|
|
remotePlayer.Value.InitializeGameObject(remotePlayerBody);
|
|
|
|
if (!IsSwimming(entity.Transform.Position.ToUnity(), parent))
|
|
{
|
|
remotePlayer.Value.UpdateAnimationAndCollider(AnimChangeType.UNDERWATER, AnimChangeState.OFF);
|
|
}
|
|
|
|
if (parent.HasValue)
|
|
{
|
|
AttachToParent(remotePlayer.Value, parent.Value);
|
|
}
|
|
|
|
result.Set(Optional.Of(remotePlayerBody));
|
|
yield break;
|
|
}
|
|
|
|
result.Set(Optional.Empty);
|
|
}
|
|
|
|
public bool SpawnsOwnChildren()
|
|
{
|
|
return false;
|
|
}
|
|
|
|
private GameObject CloneLocalPlayerBodyPrototype()
|
|
{
|
|
GameObject clone = Object.Instantiate(localPlayer.BodyPrototype, null, false);
|
|
clone.SetActive(true);
|
|
return clone;
|
|
}
|
|
|
|
private void AttachToParent(RemotePlayer remotePlayer, GameObject parent)
|
|
{
|
|
if (parent.TryGetComponent(out SubRoot subRoot))
|
|
{
|
|
Log.Debug($"Found sub root for {remotePlayer.PlayerName}. Will add him and update animation.");
|
|
remotePlayer.SetSubRoot(subRoot);
|
|
}
|
|
else if (parent.TryGetComponent(out EscapePod escapePod))
|
|
{
|
|
Log.Debug($"Found EscapePod for {remotePlayer.PlayerName}.");
|
|
remotePlayer.SetEscapePod(escapePod);
|
|
}
|
|
else
|
|
{
|
|
Log.Error($"Found neither SubRoot component nor EscapePod on {parent.name} for {remotePlayer.PlayerName}.");
|
|
}
|
|
}
|
|
|
|
private bool IsSwimming(Vector3 playerPosition, Optional<GameObject> parent)
|
|
{
|
|
if (parent.HasValue)
|
|
{
|
|
parent.Value.TryGetComponent<SubRoot>(out SubRoot subroot);
|
|
|
|
// Set the animation for the remote player to standing instead of swimming if player is not in a flooded subroot
|
|
// or in a waterpark
|
|
if (subroot)
|
|
{
|
|
if (subroot.IsUnderwater(playerPosition))
|
|
{
|
|
return true;
|
|
}
|
|
if (subroot.isCyclops)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// We know that we are in a subroot. But we can also be in a waterpark in a subroot, where we would swim
|
|
BaseRoot baseRoot = subroot.GetComponentInParent<BaseRoot>();
|
|
if (baseRoot)
|
|
{
|
|
WaterPark[] waterParks = baseRoot.GetComponentsInChildren<WaterPark>();
|
|
foreach (WaterPark waterPark in waterParks)
|
|
{
|
|
if (waterPark.IsPointInside(playerPosition))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
Log.Debug($"Trying to find escape pod for {parent}.");
|
|
parent.Value.TryGetComponent<EscapePod>(out EscapePod escapePod);
|
|
if (escapePod)
|
|
{
|
|
Log.Debug("Found escape pod for player. Will add him and update animation.");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Player can be above ocean level.
|
|
float oceanLevel = Ocean.GetOceanLevel();
|
|
return playerPosition.y < oceanLevel;
|
|
}
|
|
}
|