// Copyright (c) Pixel Crushers. All rights reserved.
using UnityEngine;
using UnityEngine.SceneManagement;
using System;
using System.Collections.Generic;
#if USE_NAVMESH
using UnityEngine.AI;
#endif
namespace PixelCrushers
{
///
/// Saves a GameObject's position.
///
[AddComponentMenu("")] // Use wrapper instead.
public class PositionSaver : Saver
{
[Tooltip("If set, save position of target. Otherwise save this GameObject's position.")]
[SerializeField]
private Transform m_target = null;
[Tooltip("When changing scenes, if a player spawnpoint is specified, move this GameObject to the spawnpoint.")]
[SerializeField]
private bool m_usePlayerSpawnpoint = false;
[Tooltip("Record positions in every scene. If unticked, only records position in most recent scene.")]
[SerializeField]
private bool m_multiscene = false;
[Serializable]
public class PositionData
{
public int scene = -1;
public Vector3 position;
public Quaternion rotation;
}
[Serializable]
public class ScenePositionData
{
public int scene;
public Vector3 position;
public Quaternion rotation;
public ScenePositionData(int _scene, Vector3 _position, Quaternion _rotation)
{
scene = _scene;
position = _position;
rotation = _rotation;
}
}
[Serializable]
public class MultiscenePositionData
{
public List positions = new List();
}
protected PositionData m_data;
protected MultiscenePositionData m_multisceneData;
#if USE_NAVMESH
protected NavMeshAgent m_navMeshAgent;
#endif
public Transform target
{
get { return (m_target == null) ? this.transform : m_target; }
set { m_target = value; }
}
public bool usePlayerSpawnpoint
{
get { return m_usePlayerSpawnpoint; }
set { m_usePlayerSpawnpoint = value; }
}
protected bool multiscene { get { return m_multiscene; } }
public override void Awake()
{
base.Awake();
if (m_multiscene) m_multisceneData = new MultiscenePositionData();
else m_data = new PositionData();
#if USE_NAVMESH
m_navMeshAgent = target.GetComponent();
#endif
}
public override string RecordData()
{
var currentScene = SceneManager.GetActiveScene().buildIndex;
if (multiscene)
{
var found = false;
for (int i = 0; i < m_multisceneData.positions.Count; i++)
{
if (m_multisceneData.positions[i].scene == currentScene)
{
found = true;
m_multisceneData.positions[i].position = target.transform.position;
m_multisceneData.positions[i].rotation = target.transform.rotation;
break;
}
}
if (!found)
{
m_multisceneData.positions.Add(new ScenePositionData(currentScene, target.transform.position, target.transform.rotation));
}
return SaveSystem.Serialize(m_multisceneData);
}
else
{
m_data.scene = currentScene;
m_data.position = target.transform.position;
m_data.rotation = target.transform.rotation;
return SaveSystem.Serialize(m_data);
}
}
public override void ApplyData(string s)
{
if (usePlayerSpawnpoint && SaveSystem.playerSpawnpoint != null)
{
SetPosition(SaveSystem.playerSpawnpoint.transform.position, SaveSystem.playerSpawnpoint.transform.rotation);
}
else if (!string.IsNullOrEmpty(s))
{
var currentScene = SceneManager.GetActiveScene().buildIndex;
if (multiscene)
{
var multisceneData = SaveSystem.Deserialize(s, m_multisceneData);
if (multisceneData == null) return;
m_multisceneData = multisceneData;
for (int i = 0; i < m_multisceneData.positions.Count; i++)
{
if (m_multisceneData.positions[i].scene == currentScene)
{
SetPosition(m_multisceneData.positions[i].position, m_multisceneData.positions[i].rotation);
break;
}
}
}
else
{
var data = SaveSystem.Deserialize(s, m_data);
if (data == null) return;
m_data = data;
if (data.scene == currentScene || data.scene == -1)
{
SetPosition(data.position, data.rotation);
}
}
}
}
protected virtual void SetPosition(Vector3 position, Quaternion rotation)
{
#if USE_NAVMESH
// If we have a NavMeshAgent, use its Warp() method:
if (m_navMeshAgent != null)
{
m_navMeshAgent.Warp(position);
target.transform.rotation = rotation;
return;
}
#endif
// Otherwise if we have a Rigidbody, set the Rigidbody's position:
var rb = GetComponent();
if (rb != null)
{
var wasKinematic = rb.isKinematic;
rb.isKinematic = true;
rb.position = position;
rb.rotation = rotation;
rb.isKinematic = wasKinematic;
}
#if USE_PHYSICS2D
// If we have a Rigidbody2D, set the Rigidbody2D's position:
var rb2d = GetComponent();
if (rb2d != null)
{
var bodyType = rb2d.bodyType;
rb2d.bodyType = RigidbodyType2D.Kinematic;
rb2d.position = position;
rb2d.bodyType = bodyType;
}
#endif
// Set the plain old transform's position:
target.transform.SetPositionAndRotation(position, rotation);
}
}
}