using Lidgren.Network; using MonomiPark.SlimeRancher.DataModel; using MonomiPark.SlimeRancher.Regions; using Newtonsoft.Json; using SRMultiplayer; using SRMultiplayer.Packets; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; using UnityEngine; namespace SRMultiplayer.Networking { public partial class NetworkPlayer : MonoBehaviour { public NetConnection Connection { get; internal set; } public Guid UUID { get; internal set; } public byte ID { get; internal set; } public string Username { get; internal set; } public bool IsLocal { get { return ID == Globals.LocalID; } } public List Mods { get; set; } public List DLCs { get; set; } public bool HasLoaded; public RegionRegistry.RegionSetId CurrentRegionSet { get { return m_RegionSet; } set { m_RegionMember.actorModel.currRegionSetId = value; m_RegionSet = value; } } public QuicksilverEnergyGenerator CurrentGenerator { get { QuicksilverEnergyGenerator generator = null; foreach (var region in Globals.LocalPlayer.Regions) { generator = region.GetComponent(); if (generator != null) { break; } } return generator; } } private RegionRegistry.RegionSetId m_RegionSet; private RegionMember m_RegionMember; private Transform m_Label; private float m_MovementUpdateTimer; private Vector3 m_ActualPosition; // where we render private Vector3 m_LatestPosition; // last position reported by server private float m_LatestPositionTime; // the time we want to arrive at the last position reported by server private Vector3 m_PreviousPosition; // the previous point we're interpolating from private float m_InterpolationPeriod = 0.1f; private float m_PreviousRotation; private float m_LatestRotation; private float m_ActualRotation; private float m_ActualWeaponY; private float m_LatestWeaponY; private float m_PreviousWeaponY; private Animator m_Animator; private GameObject m_Camera; private SECTR_PointSource m_VacAudio; private SECTR_PointSource m_JetpackAudio; private SECTR_AudioCue m_VacStartCue; private SECTR_AudioCue m_VacRunCue; private SECTR_AudioCue m_VacEndCue; private SECTR_AudioCue m_JetpackStartCue; private SECTR_AudioCue m_JetpackRunCue; private SECTR_AudioCue m_JetpackEndCue; private bool m_VacAudioActive; private bool m_JetpackAudioActive; private Transform m_LeftHandTarget; private WeaponVacuum m_WeaponVacuum; public GameObject PlayerObj; public GameObject VacFX; public GameObject AirBurstFX; public GameObject ShootFX; public GameObject CaptureFX; public GameObject CaptureFailedFX; public GameObject DestroyOnVacFX; public Transform VacTransform; public List Regions = new List(); public float airBurstRadius; public float airBurstPower; private void Update() { if (!HasLoaded) return; if(IsLocal) { m_MovementUpdateTimer -= Time.deltaTime; if (m_MovementUpdateTimer <= 0 && m_WeaponVacuum != null) { if (Vector3.Distance(m_ActualPosition, SRSingleton.Instance.Player.transform.position) > 0.1f || !Utils.CloseEnoughForMe(m_ActualRotation, SRSingleton.Instance.Player.transform.eulerAngles.y, 0.1f) || !Utils.CloseEnoughForMe(m_ActualWeaponY, m_WeaponVacuum.transform.eulerAngles.x, 0.1f)) { m_ActualPosition = SRSingleton.Instance.Player.transform.position; m_ActualRotation = SRSingleton.Instance.Player.transform.eulerAngles.y; m_ActualWeaponY = m_WeaponVacuum.transform.eulerAngles.x; m_MovementUpdateTimer = 0.1f; new PacketPlayerPosition() { ID = Globals.LocalID, Position = SRSingleton.Instance.Player.transform.position, Rotation = SRSingleton.Instance.Player.transform.eulerAngles.y, RegionSet = (byte)SRSingleton.Instance.PlayerState.model.currRegionSetId, WeaponY = m_WeaponVacuum.transform.eulerAngles.x }.Send(); } m_Animator.SetFloat("MoveX", SRInput.Actions.horizontal); m_Animator.SetFloat("MoveY", SRInput.Actions.vertical); } } else { if (m_Label != null) { m_Label.rotation = Quaternion.LookRotation(m_Label.position - Camera.main.transform.position); } float t = 1.0f - ((m_LatestPositionTime - Time.time) / m_InterpolationPeriod); m_ActualPosition = Vector3.Lerp(m_PreviousPosition, m_LatestPosition, t); transform.position = m_ActualPosition; m_ActualRotation = Mathf.LerpAngle(m_PreviousRotation, m_LatestRotation, t); transform.eulerAngles = new Vector3(0, m_ActualRotation, 0); if (m_Animator != null) { m_ActualWeaponY = Mathf.LerpAngle(m_PreviousWeaponY, m_LatestWeaponY, t); m_Animator.SetFloat("WeaponY", m_ActualWeaponY); } } } public float GetWeaponLocation() { return m_ActualWeaponY; } private void OnAnimatorIK() { if(m_Animator != null && m_LeftHandTarget != null) { m_Animator.SetIKPositionWeight(AvatarIKGoal.LeftFoot, 1); m_Animator.SetIKRotationWeight(AvatarIKGoal.LeftFoot, 1); m_Animator.SetIKPosition(AvatarIKGoal.LeftFoot, m_LeftHandTarget.position); m_Animator.SetIKRotation(AvatarIKGoal.LeftFoot, m_LeftHandTarget.rotation); } } public void UpdateWeaponRotation(float angle) { if (angle > 180) angle -= 360; var val = (1 - (Mathf.InverseLerp(-90, 90, angle) * 2)) + 0.1f; m_LatestWeaponY = val; m_PreviousWeaponY = m_ActualWeaponY; } public void PositionRotationUpdate(Vector3 pos, float rot, bool immediate) { if(Vector3.Distance(pos, m_ActualPosition) > 10f) // Teleport detection { immediate = true; } if (!immediate) { m_LatestPosition = pos; m_LatestPositionTime = Time.time + m_InterpolationPeriod; m_PreviousPosition = m_ActualPosition; m_LatestRotation = rot; m_PreviousRotation = m_ActualRotation; } else { m_LatestPosition = pos; m_LatestPositionTime = Time.time + m_InterpolationPeriod; m_PreviousPosition = pos; m_ActualPosition = pos; transform.position = m_ActualPosition; m_PreviousRotation = rot; m_LatestRotation = rot; m_ActualRotation = rot; transform.eulerAngles = new Vector3(0, rot, 0); } } internal void Spawn() { SRMP.Log("Spawning " + Username); PlayerObj = GameObject.Instantiate(Globals.BeatrixModel); PlayerObj.transform.SetParent(transform); PlayerObj.transform.localPosition = Vector3.zero; m_Animator = PlayerObj.GetComponentInChildren(); m_Animator.runtimeAnimatorController = Globals.BeatrixController; m_Animator.applyRootMotion = false; StartCoroutine(SetupAnimator()); m_WeaponVacuum = SRSingleton.Instance.player.GetComponentInChildren(); if (!IsLocal) { var barrel = PlayerObj.transform.FindDisabled("bone_barrel"); var handle = PlayerObj.transform.FindDisabled("bone_handle"); VacTransform = new GameObject("VacTransform").transform; VacTransform.SetParent(barrel, false); VacTransform.localEulerAngles = new Vector3(90, 0, 0); handle.localPosition = new Vector3(0.0092f, -0.00916f, 0.01449f); m_LeftHandTarget = new GameObject("LeftHandTarget").transform; m_LeftHandTarget.SetParent(handle, false); m_LeftHandTarget.localPosition = new Vector3(0.0174f, -0.0024f, -0.0045f); m_LeftHandTarget.localEulerAngles = new Vector3(27.636f, 72.67101f, -15.03f); var energyJetpack = SRSingleton.Instance.player.GetComponentInChildren(); m_JetpackAudio = energyJetpack.jetpackAudio.CopyComponent(PlayerObj); m_JetpackStartCue = energyJetpack.jetpackStartCue; m_JetpackRunCue = energyJetpack.jetpackRunCue; m_JetpackEndCue = energyJetpack.jetpackEndCue; m_VacAudio = m_WeaponVacuum.vacAudio.CopyComponent(PlayerObj); m_VacStartCue = m_WeaponVacuum.vacStartCue; m_VacRunCue = m_WeaponVacuum.vacRunCue; m_VacEndCue = m_WeaponVacuum.vacEndCue; airBurstPower = m_WeaponVacuum.airBurstPower; airBurstRadius = m_WeaponVacuum.airBurstRadius; AirBurstFX = m_WeaponVacuum.airBurstFX; CaptureFailedFX = m_WeaponVacuum.captureFailedFX; CaptureFX = m_WeaponVacuum.captureFX; DestroyOnVacFX = m_WeaponVacuum.destroyOnVacFX; ShootFX = m_WeaponVacuum.shootFX; VacFX = GameObject.Instantiate(m_WeaponVacuum.vacFX, VacTransform, false); VacFX.transform.localScale = new Vector3(.05f, .05f, .05f); VacFX.transform.localPosition = new Vector3(0, 0, 0); var realMarker = SRSingleton.Instance.player.GetComponent(); m_RegionMember = PlayerObj.AddComponent(); var mapDisplay = PlayerObj.AddComponent(); m_RegionMember.canHibernate = false; m_RegionMember.actorModel = new PlayerModel(); mapDisplay.Player = this; mapDisplay.Member = m_RegionMember; mapDisplay.markerPrefab = realMarker.markerPrefab; mapDisplay.HideInFog = realMarker.HideInFog; var label = new GameObject("PlayerLabel"); var textMesh = label.AddComponent(); textMesh.text = $"{this}"; textMesh.characterSize = 0.2f; textMesh.anchor = TextAnchor.MiddleCenter; textMesh.fontSize = 24; label.transform.SetParent(PlayerObj.transform); label.transform.localPosition = new Vector3(0, 3, 0); label.transform.localScale *= 0.5f; m_Label = label.transform; foreach (var collider in PlayerObj.GetComponentsInChildren()) { collider.enabled = false; } var col = PlayerObj.AddComponent(); col.height = 2; col.center = new Vector3(0, 1.2f, 0); } else { PlayerObj.transform.localEulerAngles = new Vector3(0, 0, 0); foreach (var renderer in PlayerObj.GetComponentsInChildren()) { renderer.enabled = false; } foreach (var collider in PlayerObj.GetComponentsInChildren()) { collider.enabled = false; } var cameraObj = new GameObject("Camera"); cameraObj.transform.SetParent(PlayerObj.transform); cameraObj.transform.localPosition = new Vector3(0, 3, -4); cameraObj.transform.localEulerAngles = new Vector3(20, 0, 0); cameraObj.AddComponent(); cameraObj.SetActive(false); m_Camera = cameraObj; } PlayerObj.SetActive(true); } internal void Save() { var path = Path.Combine(SRMP.ModDataPath, SRSingleton.Instance.AutoSaveDirector.SavedGame.GetName(), UUID.ToString() + ".json"); File.WriteAllText(path, JsonConvert.SerializeObject(new NetworkPlayerSave() { LastUsername = Username, RegionSet = (byte)CurrentRegionSet, WeaponY = m_LatestWeaponY, PositionX = transform.position.x, PositionY = transform.position.y, PositionZ = transform.position.z, Rotation = transform.eulerAngles.y })); } internal void Load() { var path = Path.Combine(SRMP.ModDataPath, SRSingleton.Instance.AutoSaveDirector.SavedGame.GetName(), UUID.ToString() + ".json"); if (File.Exists(path)) { var playerSave = JsonConvert.DeserializeObject(File.ReadAllText(path)); transform.position = new Vector3(playerSave.PositionX, playerSave.PositionY, playerSave.PositionZ); transform.eulerAngles = new Vector3(0, playerSave.Rotation, 0); UpdateWeaponRotation(playerSave.WeaponY); CurrentRegionSet = (RegionRegistry.RegionSetId)playerSave.RegionSet; new PacketPlayerPosition() { ID = ID, Position = transform.position, Rotation = transform.eulerAngles.y, WeaponY = m_LatestWeaponY, RegionSet = (byte)CurrentRegionSet }.Send(this); } } internal void OnLeft() { foreach (var netRegion in Globals.Regions.Values) { if (netRegion.Owner == ID) { netRegion.SetOwnership(0); } netRegion.RemovePlayer(this); } foreach (var netActor in Globals.Actors.Values) { if (netActor.Owner == ID) { netActor.SetOwnership(0); } netActor.KnownPlayers.Remove(this); } } public void Airburst() { Vector3 position = VacTransform.position; foreach (Collider collider in Physics.OverlapSphere(position, airBurstRadius)) { if (collider && collider.GetComponent() != null && collider.gameObject != gameObject) { Identifiable component = collider.gameObject.GetComponent(); if (component != null && (Identifiable.IsSlime(component.id) || component.id == Identifiable.Id.PLAYER) && Vector3.Dot(VacTransform.transform.up, collider.gameObject.transform.position - VacTransform.transform.position) > 0f) { Rigidbody component2 = collider.GetComponent(); if (component.id == Identifiable.Id.PLAYER) { vp_FPController playerComponent = collider.gameObject.GetComponent(); Vector3 a = component2.position - position; float magnitude = a.magnitude; a.Normalize(); float num = 1f - Mathf.Max(2f, magnitude) / airBurstRadius; var force = a * ((airBurstPower * component2.mass) * num * num); playerComponent.AddForce(force * 0.001f); } else { PhysicsUtil.SoftExplosionForce(airBurstPower * component2.mass, position, airBurstRadius, component2); } } } } GameObject.Instantiate(AirBurstFX, Vector3.zero, Quaternion.identity).transform.SetParent(VacTransform, false); } internal void SetVacAudio(bool active) { if (active && !m_VacAudioActive) { m_VacAudio.Cue = m_VacStartCue; m_VacAudio.Play(); m_VacAudio.Cue = m_VacRunCue; m_VacAudio.Play(); } else if (!active && m_VacAudioActive) { m_VacAudio.Cue = m_VacEndCue; m_VacAudio.Play(); } m_VacAudioActive = active; } internal void SetJetpackAudio(bool active) { if (active && !m_JetpackAudioActive) { m_JetpackAudio.Cue = m_JetpackStartCue; m_JetpackAudio.Play(); m_JetpackAudio.Cue = m_JetpackRunCue; m_JetpackAudio.Play(); } else if (!active && m_JetpackAudioActive) { m_JetpackAudio.Cue = m_JetpackEndCue; m_JetpackAudio.Play(); } m_JetpackAudioActive = active; } internal void ToggleThirdPerson(bool enable) { foreach (var renderer in SRSingleton.Instance.Player.GetComponentsInChildren()) { renderer.enabled = !enable; } foreach (var renderer in PlayerObj.GetComponentsInChildren()) { renderer.enabled = enable; } m_Camera.SetActive(enable); } public override bool Equals(object other) { if (other == null || !(other is NetworkPlayer)) return false; return ((NetworkPlayer)other).ID == ID; } public override int GetHashCode() { return ID.GetHashCode(); } public override string ToString() { return $"{Username} ({ID})"; } } }