Files
Nitrox/NitroxClient/GameLogic/LocalPlayer.cs
2025-07-06 00:23:46 +02:00

146 lines
5.3 KiB
C#

using System;
using NitroxClient.Communication.Abstract;
using NitroxClient.GameLogic.PlayerLogic.PlayerModel;
using NitroxClient.GameLogic.PlayerLogic.PlayerModel.Abstract;
using NitroxClient.MonoBehaviours;
using NitroxClient.Unity.Helper;
using NitroxModel.DataStructures;
using NitroxModel.DataStructures.GameLogic;
using NitroxModel.DataStructures.Util;
using NitroxModel.MultiplayerSession;
using NitroxModel.Packets;
using NitroxModel_Subnautica.DataStructures;
using UnityEngine;
using UnityEngine.Rendering;
using Object = UnityEngine.Object;
namespace NitroxClient.GameLogic;
public class LocalPlayer : ILocalNitroxPlayer
{
private readonly IMultiplayerSession multiplayerSession;
private readonly IPacketSender packetSender;
private readonly ThrottledPacketSender throttledPacketSender;
private readonly Lazy<GameObject> body;
private readonly Lazy<GameObject> playerModel;
private readonly Lazy<GameObject> bodyPrototype;
public GameObject Body => body.Value;
public GameObject PlayerModel => playerModel.Value;
public GameObject BodyPrototype => bodyPrototype.Value;
public string PlayerName => multiplayerSession.AuthenticationContext.Username;
/// <summary>
/// Gets the player id. The session is lost on disconnect so this can return null.
/// </summary>
public ushort? PlayerId => multiplayerSession?.Reservation?.PlayerId;
public PlayerSettings PlayerSettings => multiplayerSession.PlayerSettings;
public Perms Permissions { get; set; }
public IntroCinematicMode IntroCinematicMode { get; set; }
public bool KeepInventoryOnDeath { get; set; }
public LocalPlayer(IMultiplayerSession multiplayerSession, IPacketSender packetSender, ThrottledPacketSender throttledPacketSender)
{
this.multiplayerSession = multiplayerSession;
this.packetSender = packetSender;
this.throttledPacketSender = throttledPacketSender;
body = new Lazy<GameObject>(() => Player.main.RequireGameObject("body"));
playerModel = new Lazy<GameObject>(() => Body.RequireGameObject("player_view"));
bodyPrototype = new Lazy<GameObject>(CreateBodyPrototype);
Permissions = Perms.PLAYER;
IntroCinematicMode = IntroCinematicMode.NONE;
KeepInventoryOnDeath = false;
}
public void BroadcastLocation(Vector3 location, Vector3 velocity, Quaternion bodyRotation, Quaternion aimingRotation)
{
if (!PlayerId.HasValue)
{
return;
}
PlayerMovement playerMovement = new(PlayerId.Value, location.ToDto(), velocity.ToDto(), bodyRotation.ToDto(), aimingRotation.ToDto());
packetSender.Send(playerMovement);
}
public void AnimationChange(AnimChangeType type, AnimChangeState state)
{
if (PlayerId.HasValue)
{
packetSender.Send(new AnimationChangeEvent(PlayerId.Value, (int)type, (int)state));
}
}
public void BroadcastStats(float oxygen, float maxOxygen, float health, float food, float water, float infectionAmount)
{
if (PlayerId.HasValue)
{
packetSender.Send(new PlayerStats(PlayerId.Value, oxygen, maxOxygen, health, food, water, infectionAmount));
}
}
public void BroadcastDeath(Vector3 deathPosition)
{
if (PlayerId.HasValue)
{
packetSender.Send(new PlayerDeathEvent(PlayerId.Value, deathPosition.ToDto()));
}
}
public void BroadcastSubrootChange(Optional<NitroxId> subrootId)
{
if (PlayerId.HasValue)
{
packetSender.Send(new SubRootChanged(PlayerId.Value, subrootId));
}
}
public void BroadcastEscapePodChange(Optional<NitroxId> escapePodId)
{
if (PlayerId.HasValue)
{
packetSender.Send(new EscapePodChanged(PlayerId.Value, escapePodId));
}
}
public void BroadcastWeld(NitroxId id, float healthAdded) => packetSender.Send(new WeldAction(id, healthAdded));
public void BroadcastHeldItemChanged(NitroxId itemId, PlayerHeldItemChanged.ChangeType techType, NitroxTechType isFirstTime)
{
if (PlayerId.HasValue)
{
packetSender.Send(new PlayerHeldItemChanged(PlayerId.Value, itemId, techType, isFirstTime));
}
}
public void BroadcastQuickSlotsBindingChanged(Optional<NitroxId>[] slotItemIds) => throttledPacketSender.SendThrottled(new PlayerQuickSlotsBindingChanged(slotItemIds), (packet) => 1);
private GameObject CreateBodyPrototype()
{
GameObject prototype = Body;
// Cheap fix for showing head, much easier since male_geo contains many different heads
prototype.GetComponentInParent<Player>().head.shadowCastingMode = ShadowCastingMode.On;
GameObject clone = Object.Instantiate(prototype, Multiplayer.Main.transform, false);
prototype.GetComponentInParent<Player>().head.shadowCastingMode = ShadowCastingMode.ShadowsOnly;
clone.SetActive(false);
clone.name = "RemotePlayerPrototype";
// Removing items that are held in hand
foreach (Transform child in clone.transform.Find($"player_view/{PlayerEquipmentConstants.ITEM_ATTACH_POINT_GAME_OBJECT_NAME}"))
{
if (!child.gameObject.name.Contains("attach1_"))
{
Object.DestroyImmediate(child.gameObject);
}
}
return clone;
}
}