340 lines
12 KiB
C#
340 lines
12 KiB
C#
using System.IO;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
using UnityEngine.UI;
|
|
using UnityEngine.Networking;
|
|
using Passer.Pawn;
|
|
using UnityEngine.Scripting;
|
|
using Passer.Humanoid;
|
|
|
|
namespace Passer {
|
|
|
|
/// <summary>
|
|
/// The Possession of a Humanoid Visitor
|
|
/// </summary>
|
|
///
|
|
/// \image html PawnPossessionsInspector.png
|
|
///
|
|
/// * Default possessions, see PawnPossessions::defaultPossessions
|
|
/// * Clear at start, see PawnPossessions::clearAtStart
|
|
/// \version 4.0 and higher
|
|
public class VisitorPossessions : MonoBehaviour {
|
|
|
|
[System.Serializable]
|
|
public class Possession {
|
|
public string name;
|
|
public Possessable.Type type;
|
|
public bool persistent;
|
|
public bool removable = true;
|
|
public string siteLocation;
|
|
public string assetPath;
|
|
[System.NonSerialized]
|
|
public Possessable scenePossession;
|
|
}
|
|
|
|
[System.Serializable]
|
|
public class CachedPossession {
|
|
public string siteLocation;
|
|
public AssetBundle assetBundle;
|
|
}
|
|
|
|
protected static List<CachedPossession> cache = new List<CachedPossession>();
|
|
|
|
public class Possessions {
|
|
public List<Possession> list = new List<Possession>();
|
|
}
|
|
|
|
//// May include an amount later
|
|
//public static Possessions possessions;
|
|
|
|
public List<Possession> possessions;
|
|
public List<Possession> myPossessions {
|
|
get {
|
|
return possessions;
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// The possessions which are available from the start
|
|
/// </summary>
|
|
public Possessable[] defaultPossessions;
|
|
/// <summary>
|
|
/// Clear the possessions when the application is started
|
|
/// </summary>
|
|
/// Default possessions will not be cleared.
|
|
/// This works only on real Humanoids, not on HumanoidInterfaces/Sites
|
|
public bool clearOnAwake;
|
|
|
|
private string filePath {
|
|
get {
|
|
string filePath = Path.Combine(Application.persistentDataPath, "MyPossessions.json");
|
|
return filePath;
|
|
}
|
|
}
|
|
|
|
#region Init
|
|
|
|
protected virtual void Awake() {
|
|
// Only do this for real humanoids
|
|
HumanoidControl humanoid = GetComponentInParent<HumanoidControl>();
|
|
if (humanoid != null) {
|
|
if (!clearOnAwake) {
|
|
Debug.Log("Retrieve possessions from " + filePath);
|
|
|
|
if (File.Exists(filePath)) {
|
|
string json = File.ReadAllText(filePath);
|
|
Possessions possessionList = JsonUtility.FromJson<Possessions>(json);
|
|
possessions = possessionList.list; //JsonUtility.FromJson<Possessions>(json);
|
|
}
|
|
else {
|
|
Debug.Log("Cleared Possessions");
|
|
possessions = new List<Possession>();//new Possessions();
|
|
}
|
|
}
|
|
else {
|
|
Debug.Log("Cleared Possessions");
|
|
possessions = new List<Possession>(); // new Possessions();
|
|
}
|
|
}
|
|
|
|
// Default Possessions cannot be deleted
|
|
AddPossessions(defaultPossessions, false);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Stop
|
|
|
|
protected virtual void OnDestroy() {
|
|
//Debug.Log("Store possessions to " + filePath);
|
|
|
|
string json = JsonUtility.ToJson(possessions);
|
|
File.WriteAllText(filePath, json);
|
|
//Debug.Log("Possesions stored");
|
|
}
|
|
|
|
public static void DestroyScenePossessions() {
|
|
//possessions.list.RemoveAll(poss => poss.persistent == false);
|
|
}
|
|
|
|
#endregion
|
|
|
|
/// <summary>
|
|
/// Try to add the gameObject to this humanoidpossessions.
|
|
/// This only succeeds whent the hameObject has a Possessable component.
|
|
/// </summary>
|
|
/// <param name="gameObject">The GameObject to add</param>
|
|
public void TryAddGameObject(GameObject gameObject) {
|
|
Possessable possession = gameObject.GetComponentInChildren<Possessable>();
|
|
if (possession == null)
|
|
return;
|
|
|
|
Add(possession);
|
|
}
|
|
|
|
public void AddPossessions(Possessable[] scenePossessions, bool removable = true) {
|
|
if (possessions == null || scenePossessions == null)
|
|
return;
|
|
|
|
foreach (Possessable possession in scenePossessions) {
|
|
if (possession == null)
|
|
continue;
|
|
|
|
Possession persistentPossession = Add(possession);
|
|
persistentPossession.scenePossession = PreservePossession(possession);
|
|
persistentPossession.persistent = possession.crossSite;
|
|
persistentPossession.removable = removable;
|
|
}
|
|
}
|
|
|
|
private static Possessable PreservePossession(Possessable possession) {
|
|
GameObject preservedPossession = Instantiate(possession.gameObject);
|
|
preservedPossession.SetActive(false);
|
|
Object.DontDestroyOnLoad(preservedPossession);
|
|
return preservedPossession.GetComponent<Possessable>();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Add the possessable object to the humanoidPossessions
|
|
/// </summary>
|
|
/// <param name="possessable">The possessable object to add</param>
|
|
/// <returns>The persistent possession</returns>
|
|
public Possession Add(Possessable possessable) {
|
|
if (possessable == null)
|
|
return null;
|
|
|
|
if (possessable.isUnique) {
|
|
Possession foundPossession = possessions.Find(
|
|
persistentPossession => persistentPossession.assetPath == possessable.assetPath
|
|
);
|
|
if (foundPossession != null)
|
|
return foundPossession;
|
|
}
|
|
|
|
Possession newPossession = new Possession() {
|
|
name = possessable.name,
|
|
siteLocation = possessable.siteLocation,
|
|
assetPath = possessable.assetPath,
|
|
type = possessable.possessionType,
|
|
};
|
|
|
|
possessions.Add(newPossession);
|
|
|
|
return newPossession;
|
|
}
|
|
|
|
public void DeletePossession(Possession possession) {
|
|
Debug.Log("deleting " + possession);
|
|
Possession foundPossession = possessions.Find(
|
|
persistentPossession => persistentPossession.assetPath == possession.assetPath
|
|
);
|
|
if (foundPossession == null)
|
|
return;
|
|
|
|
possessions.Remove(foundPossession);
|
|
Debug.Log("deleted");
|
|
}
|
|
|
|
private void RetrievePossession(Possession possession) {
|
|
StartCoroutine(RetrievePossessionAsync(possession));
|
|
}
|
|
|
|
//public void RetrievePossession(PersistentPossession possession, System.Action<GameObject> callback) {
|
|
// StartCoroutine(RetrievePossessionAsync(possession, callback));
|
|
//}
|
|
|
|
private static IEnumerator RetrievePossessionAsync(Possession possession) {
|
|
string url = "https://" + possession.siteLocation + ".windows" + ".site";
|
|
Debug.Log("Loading possession: " + url);
|
|
|
|
UnityWebRequest request = UnityWebRequestAssetBundle.GetAssetBundle(url);
|
|
yield return request.SendWebRequest();
|
|
|
|
AssetBundle assetBundle = DownloadHandlerAssetBundle.GetContent(request);
|
|
if (assetBundle == null) {
|
|
Debug.LogError("Could not load " + url);
|
|
yield break;
|
|
}
|
|
|
|
GameObject prefab = assetBundle.LoadAsset<GameObject>(possession.assetPath);
|
|
if (prefab != null)
|
|
Object.Instantiate(prefab);
|
|
}
|
|
|
|
private static AssetBundle lastAssetBundle;
|
|
|
|
public static IEnumerator RetrievePossessionAsync(Possession possession, System.Action<GameObject> callback) {
|
|
GameObject prefab;
|
|
|
|
if (possession.siteLocation == "") {
|
|
prefab = possession.scenePossession.gameObject;
|
|
prefab.SetActive(true);
|
|
callback(prefab);
|
|
prefab.SetActive(false);
|
|
}
|
|
else {
|
|
Debug.Log("Cache size: " + cache.Count);
|
|
CachedPossession foundPossession = cache.Find(entry => entry.siteLocation == possession.siteLocation);
|
|
if (foundPossession == null) {
|
|
string url = "https://" + possession.siteLocation + ".windows" + ".site";
|
|
Debug.Log("Loading possession: " + url);
|
|
|
|
UnityWebRequest request = UnityWebRequestAssetBundle.GetAssetBundle(url);
|
|
yield return request.SendWebRequest();
|
|
|
|
AssetBundle assetBundle = DownloadHandlerAssetBundle.GetContent(request);
|
|
if (assetBundle == null) {
|
|
Debug.LogError("Could not load " + url);
|
|
yield break;
|
|
}
|
|
lastAssetBundle = assetBundle;
|
|
|
|
Debug.Log("Load: " + possession.assetPath);
|
|
prefab = assetBundle.LoadAsset<GameObject>(possession.assetPath);
|
|
if (prefab == null) {
|
|
Debug.LogError("Could not load " + possession.assetPath);
|
|
yield break;
|
|
}
|
|
|
|
CachedPossession cachedPossession = new CachedPossession() {
|
|
siteLocation = possession.siteLocation,
|
|
assetBundle = assetBundle,
|
|
};
|
|
cache.Add(cachedPossession);
|
|
}
|
|
else {
|
|
Debug.Log("Load from cache: " + possession.assetPath);
|
|
prefab = foundPossession.assetBundle.LoadAsset<GameObject>(possession.assetPath);
|
|
if (prefab == null) {
|
|
Debug.LogError("Could not load " + possession.assetPath);
|
|
yield break;
|
|
}
|
|
}
|
|
callback(prefab);
|
|
}
|
|
}
|
|
|
|
public static void UnloadPossession() {
|
|
lastAssetBundle.Unload(true);
|
|
}
|
|
|
|
|
|
private int currentAvatarIndex = 0;
|
|
public void UseNextAvatar() {
|
|
List<Possession> avatars = possessions.FindAll(possession => possession.type == Possessable.Type.Avatar);
|
|
if (avatars.Count == 0)
|
|
return;
|
|
|
|
currentAvatarIndex = mod(currentAvatarIndex + 1, avatars.Count);
|
|
UseAvatar(currentAvatarIndex);
|
|
}
|
|
|
|
public void UseAvatar(int avatarIndex) {
|
|
List<Possession> avatars = possessions.FindAll(possession => possession.type == Possessable.Type.Avatar);
|
|
if (avatarIndex < 0 || avatarIndex > avatars.Count)
|
|
return;
|
|
|
|
HumanoidControl humanoid = FindObjectOfType<HumanoidControl>();
|
|
if (humanoid == null)
|
|
return;
|
|
|
|
|
|
if (avatars[avatarIndex] != null) {
|
|
if (avatars[avatarIndex].scenePossession != null)
|
|
humanoid.ChangeAvatar(avatars[avatarIndex].scenePossession.gameObject);
|
|
else
|
|
StartCoroutine(RetrieveAvatarAsync(avatars[avatarIndex]));
|
|
}
|
|
}
|
|
|
|
private static IEnumerator RetrieveAvatarAsync(Possession possession) {
|
|
HumanoidControl humanoid = FindObjectOfType<HumanoidControl>();
|
|
if (humanoid == null)
|
|
yield break;
|
|
|
|
string url = "https://" + possession.siteLocation + ".windows" + ".site";
|
|
Debug.Log("Loading possession: " + url);
|
|
|
|
UnityWebRequest request = UnityWebRequestAssetBundle.GetAssetBundle(url);
|
|
yield return request.SendWebRequest();
|
|
|
|
AssetBundle assetBundle = DownloadHandlerAssetBundle.GetContent(request);
|
|
if (assetBundle == null) {
|
|
Debug.LogError("Could not load " + url);
|
|
yield break;
|
|
}
|
|
|
|
GameObject avatarPrefab = assetBundle.LoadAsset<GameObject>(possession.assetPath);
|
|
if (avatarPrefab != null)
|
|
humanoid.ChangeAvatar(avatarPrefab);
|
|
}
|
|
|
|
public static int mod(int k, int n) {
|
|
k %= n;
|
|
return (k < 0) ? k + n : k;
|
|
}
|
|
}
|
|
|
|
} |