基础内容
必要插件安装 缓动曲线和动画基础 ElementFolder,Track与其次级模块,PathNode重构
This commit is contained in:
@@ -0,0 +1,286 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
|
||||
namespace I2.Loc
|
||||
{
|
||||
public static class PersistentStorage
|
||||
{
|
||||
static I2CustomPersistentStorage mStorage;
|
||||
|
||||
public enum eFileType { Raw, Persistent, Temporal, Streaming }
|
||||
|
||||
#region PlayerPrefs
|
||||
public static void SetSetting_String(string key, string value)
|
||||
{
|
||||
if (mStorage == null) mStorage = new I2CustomPersistentStorage();
|
||||
mStorage.SetSetting_String(key, value);
|
||||
}
|
||||
|
||||
public static string GetSetting_String(string key, string defaultValue)
|
||||
{
|
||||
if (mStorage == null) mStorage = new I2CustomPersistentStorage();
|
||||
return mStorage.GetSetting_String(key, defaultValue);
|
||||
}
|
||||
|
||||
public static void DeleteSetting(string key)
|
||||
{
|
||||
if (mStorage == null) mStorage = new I2CustomPersistentStorage();
|
||||
mStorage.DeleteSetting(key);
|
||||
}
|
||||
|
||||
public static bool HasSetting( string key )
|
||||
{
|
||||
if (mStorage == null) mStorage = new I2CustomPersistentStorage();
|
||||
return mStorage.HasSetting(key);
|
||||
}
|
||||
|
||||
public static void ForceSaveSettings()
|
||||
{
|
||||
if (mStorage == null) mStorage = new I2CustomPersistentStorage();
|
||||
mStorage.ForceSaveSettings();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region File Management
|
||||
|
||||
public static bool CanAccessFiles()
|
||||
{
|
||||
if (mStorage == null) mStorage = new I2CustomPersistentStorage();
|
||||
return mStorage.CanAccessFiles();
|
||||
}
|
||||
|
||||
public static bool SaveFile(eFileType fileType, string fileName, string data, bool logExceptions = true)
|
||||
{
|
||||
if (mStorage == null) mStorage = new I2CustomPersistentStorage();
|
||||
return mStorage.SaveFile(fileType, fileName, data, logExceptions);
|
||||
}
|
||||
|
||||
public static string LoadFile(eFileType fileType, string fileName, bool logExceptions=true)
|
||||
{
|
||||
if (mStorage == null) mStorage = new I2CustomPersistentStorage();
|
||||
return mStorage.LoadFile(fileType, fileName, logExceptions);
|
||||
}
|
||||
|
||||
public static bool DeleteFile(eFileType fileType, string fileName, bool logExceptions = true)
|
||||
{
|
||||
if (mStorage == null) mStorage = new I2CustomPersistentStorage();
|
||||
return mStorage.DeleteFile(fileType, fileName, logExceptions);
|
||||
}
|
||||
|
||||
public static bool HasFile(eFileType fileType, string fileName, bool logExceptions = true)
|
||||
{
|
||||
if (mStorage == null) mStorage = new I2CustomPersistentStorage();
|
||||
return mStorage.HasFile(fileType, fileName, logExceptions);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
public abstract class I2BasePersistentStorage
|
||||
{
|
||||
#region PlayerPrefs
|
||||
public virtual void SetSetting_String(string key, string value)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Use PlayerPrefs, but if the data is bigger than the limit, split it into multiple entries
|
||||
var len = value.Length;
|
||||
int maxLength = 8000;
|
||||
if (len<=maxLength)
|
||||
{
|
||||
PlayerPrefs.SetString(key, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
int numSections = Mathf.CeilToInt(len / (float)maxLength);
|
||||
for (int i=0; i<numSections; ++i)
|
||||
{
|
||||
int iStart = maxLength * i;
|
||||
PlayerPrefs.SetString($"[I2split]{i}{key}", value.Substring(iStart, Mathf.Min(maxLength, len-iStart)));
|
||||
}
|
||||
PlayerPrefs.SetString(key, "[$I2#@div$]" + numSections);
|
||||
}
|
||||
}
|
||||
catch (Exception) { Debug.LogError("Error saving PlayerPrefs " + key); }
|
||||
}
|
||||
|
||||
public virtual string GetSetting_String(string key, string defaultValue)
|
||||
{
|
||||
try
|
||||
{
|
||||
var data = PlayerPrefs.GetString(key, defaultValue);
|
||||
|
||||
// Check if the data is splitted, if so, concat all the sections
|
||||
if (!string.IsNullOrEmpty(data) && data.StartsWith("[I2split]", StringComparison.Ordinal))
|
||||
{
|
||||
int nSections = int.Parse(data.Substring("[I2split]".Length), CultureInfo.InvariantCulture);
|
||||
data = "";
|
||||
for (int i=0; i<nSections; ++i)
|
||||
{
|
||||
data += PlayerPrefs.GetString($"[I2split]{i}{key}", "");
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
Debug.LogError("Error loading PlayerPrefs " + key);
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void DeleteSetting( string key)
|
||||
{
|
||||
try
|
||||
{
|
||||
var data = PlayerPrefs.GetString(key, null);
|
||||
|
||||
// If the data is splitted, delete each section as well
|
||||
if (!string.IsNullOrEmpty(data) && data.StartsWith("[I2split]", StringComparison.Ordinal))
|
||||
{
|
||||
int nSections = int.Parse(data.Substring("[I2split]".Length), CultureInfo.InvariantCulture);
|
||||
for (int i = 0; i < nSections; ++i)
|
||||
{
|
||||
PlayerPrefs.DeleteKey($"[I2split]{i}{key}");
|
||||
}
|
||||
}
|
||||
PlayerPrefs.DeleteKey(key);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
Debug.LogError("Error deleting PlayerPrefs " + key);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void ForceSaveSettings()
|
||||
{
|
||||
PlayerPrefs.Save();
|
||||
}
|
||||
|
||||
public virtual bool HasSetting(string key)
|
||||
{
|
||||
return PlayerPrefs.HasKey(key);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region Files
|
||||
|
||||
public virtual bool CanAccessFiles()
|
||||
{
|
||||
#if UNITY_SWITCH || UNITY_WSA
|
||||
return false;
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
string UpdateFilename(PersistentStorage.eFileType fileType, string fileName)
|
||||
{
|
||||
switch (fileType)
|
||||
{
|
||||
case PersistentStorage.eFileType.Persistent: fileName = Application.persistentDataPath + "/" + fileName; break;
|
||||
case PersistentStorage.eFileType.Temporal: fileName = Application.temporaryCachePath + "/" + fileName; break;
|
||||
case PersistentStorage.eFileType.Streaming: fileName = Application.streamingAssetsPath + "/" + fileName; break;
|
||||
}
|
||||
return fileName;
|
||||
}
|
||||
|
||||
public virtual bool SaveFile(PersistentStorage.eFileType fileType, string fileName, string data, bool logExceptions = true)
|
||||
{
|
||||
if (!CanAccessFiles())
|
||||
return false;
|
||||
|
||||
try
|
||||
{
|
||||
fileName = UpdateFilename(fileType, fileName);
|
||||
File.WriteAllText(fileName, data, Encoding.UTF8);
|
||||
return true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (logExceptions)
|
||||
Debug.LogError("Error saving file '" + fileName + "'\n" + e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual string LoadFile(PersistentStorage.eFileType fileType, string fileName, bool logExceptions = true)
|
||||
{
|
||||
if (!CanAccessFiles())
|
||||
return null;
|
||||
|
||||
try
|
||||
{
|
||||
fileName = UpdateFilename(fileType, fileName);
|
||||
return File.ReadAllText(fileName, Encoding.UTF8);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (logExceptions)
|
||||
Debug.LogError("Error loading file '" + fileName + "'\n" + e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual bool DeleteFile(PersistentStorage.eFileType fileType, string fileName, bool logExceptions = true)
|
||||
{
|
||||
if (!CanAccessFiles())
|
||||
return false;
|
||||
|
||||
try
|
||||
{
|
||||
fileName = UpdateFilename(fileType, fileName);
|
||||
File.Delete(fileName);
|
||||
return true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (logExceptions)
|
||||
Debug.LogError("Error deleting file '" + fileName + "'\n" + e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual bool HasFile(PersistentStorage.eFileType fileType, string fileName, bool logExceptions = true)
|
||||
{
|
||||
if (!CanAccessFiles())
|
||||
return false;
|
||||
|
||||
try
|
||||
{
|
||||
fileName = UpdateFilename(fileType, fileName);
|
||||
return File.Exists(fileName);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (logExceptions) Debug.LogError("Error requesting file '" + fileName + "'\n" + e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
public class I2CustomPersistentStorage : I2BasePersistentStorage
|
||||
{
|
||||
//public override void SetSetting_String(string key, string value)
|
||||
//public override string GetSetting_String(string key, string defaultValue)
|
||||
//public override void DeleteSetting(string key)
|
||||
//public override void ForceSaveSettings()
|
||||
//public override bool HasSetting(string key)
|
||||
|
||||
//public virtual bool CanAccessFiles();
|
||||
//public override bool SaveFile(PersistentStorage.eFileType fileType, string fileName, string data, bool logExceptions = true);
|
||||
//public override string LoadFile(PersistentStorage.eFileType fileType, string fileName, bool logExceptions = true);
|
||||
//public override bool DeleteFile(PersistentStorage.eFileType fileType, string fileName, bool logExceptions = true);
|
||||
//public override bool HasFile(PersistentStorage.eFileType fileType, string fileName, bool logExceptions = true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ec5b9e0d683ff2b409340ac814051bb8
|
||||
timeCreated: 1507704861
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,204 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
#if ENABLE_INPUT_SYSTEM
|
||||
using UnityEngine.InputSystem;
|
||||
#endif
|
||||
|
||||
namespace I2.Loc
|
||||
{
|
||||
public class BaseSpecializationManager
|
||||
{
|
||||
public string[] mSpecializations;
|
||||
public Dictionary<string, string> mSpecializationsFallbacks;
|
||||
|
||||
public virtual void InitializeSpecializations()
|
||||
{
|
||||
mSpecializations = new[] { "Any", "PC", "Touch", "Controller", "VR",
|
||||
"XBox", "PS4", "PS5", "OculusVR", "ViveVR", "GearVR", "Android", "IOS",
|
||||
"Switch"
|
||||
};
|
||||
mSpecializationsFallbacks = new Dictionary<string, string>(System.StringComparer.Ordinal)
|
||||
{
|
||||
{ "XBox", "Controller" }, { "PS4", "Controller" },
|
||||
{ "OculusVR", "VR" }, { "ViveVR", "VR" }, { "GearVR", "VR" },
|
||||
{ "Android", "Touch" }, { "IOS", "Touch" }
|
||||
};
|
||||
}
|
||||
|
||||
public virtual string GetCurrentSpecialization()
|
||||
{
|
||||
if (mSpecializations == null)
|
||||
InitializeSpecializations();
|
||||
|
||||
#if UNITY_ANDROID
|
||||
return "Android";
|
||||
#elif UNITY_IOS
|
||||
return "IOS";
|
||||
#elif UNITY_PS4
|
||||
return "PS4";
|
||||
#elif UNITY_XBOXONE
|
||||
return "XBox";
|
||||
#elif UNITY_SWITCH
|
||||
return "Switch";
|
||||
#elif UNITY_STANDALONE || UNITY_WEBGL
|
||||
return "PC";
|
||||
#else
|
||||
return (IsTouchInputSupported() ? "Touch" : "PC");
|
||||
#endif
|
||||
}
|
||||
|
||||
bool IsTouchInputSupported()
|
||||
{
|
||||
#if ENABLE_INPUT_SYSTEM
|
||||
return Touchscreen.current != null;
|
||||
#else
|
||||
return UnityEngine.Input.touchSupported;
|
||||
#endif
|
||||
}
|
||||
|
||||
public virtual string GetFallbackSpecialization(string specialization)
|
||||
{
|
||||
if (mSpecializationsFallbacks == null)
|
||||
InitializeSpecializations();
|
||||
|
||||
string fallback;
|
||||
if (mSpecializationsFallbacks.TryGetValue(specialization, out fallback))
|
||||
return fallback;
|
||||
return "Any";
|
||||
}
|
||||
}
|
||||
public class SpecializationManager : BaseSpecializationManager
|
||||
{
|
||||
public static SpecializationManager Singleton = new SpecializationManager();
|
||||
|
||||
private SpecializationManager()
|
||||
{
|
||||
InitializeSpecializations();
|
||||
}
|
||||
|
||||
public static string GetSpecializedText(string text, string specialization = null)
|
||||
{
|
||||
var idxFirst = text.IndexOf("[i2s_", StringComparison.Ordinal);
|
||||
if (idxFirst < 0)
|
||||
return text;
|
||||
|
||||
if (string.IsNullOrEmpty(specialization))
|
||||
specialization = Singleton.GetCurrentSpecialization();
|
||||
|
||||
while (!string.IsNullOrEmpty(specialization) && specialization != "Any")
|
||||
{
|
||||
var tag = "[i2s_" + specialization + "]";
|
||||
int idx = text.IndexOf(tag, StringComparison.Ordinal);
|
||||
if (idx < 0)
|
||||
{
|
||||
specialization = Singleton.GetFallbackSpecialization(specialization);
|
||||
continue;
|
||||
}
|
||||
|
||||
idx += tag.Length;
|
||||
var idxEnd = text.IndexOf("[i2s_", idx, StringComparison.Ordinal);
|
||||
if (idxEnd < 0) idxEnd = text.Length;
|
||||
|
||||
return text.Substring(idx, idxEnd - idx);
|
||||
}
|
||||
|
||||
return text.Substring(0, idxFirst);
|
||||
}
|
||||
|
||||
public static string SetSpecializedText(string text, string newText, string specialization)
|
||||
{
|
||||
if (string.IsNullOrEmpty(specialization))
|
||||
specialization = "Any";
|
||||
if ((text==null || !text.Contains("[i2s_")) && specialization=="Any")
|
||||
{
|
||||
return newText;
|
||||
}
|
||||
|
||||
var dict = GetSpecializations(text);
|
||||
dict[specialization] = newText;
|
||||
|
||||
return SetSpecializedText(dict);
|
||||
}
|
||||
|
||||
public static string SetSpecializedText( Dictionary<string,string> specializations )
|
||||
{
|
||||
string text;
|
||||
if (!specializations.TryGetValue("Any", out text))
|
||||
text = string.Empty;
|
||||
|
||||
foreach (var kvp in specializations)
|
||||
{
|
||||
if (kvp.Key != "Any" && !string.IsNullOrEmpty(kvp.Value))
|
||||
text += "[i2s_" + kvp.Key + "]" + kvp.Value;
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
public static Dictionary<string, string> GetSpecializations(string text, Dictionary<string, string> buffer = null)
|
||||
{
|
||||
if (buffer == null)
|
||||
buffer = new Dictionary<string, string>(StringComparer.Ordinal);
|
||||
else
|
||||
buffer.Clear();
|
||||
|
||||
if (text==null)
|
||||
{
|
||||
buffer["Any"] = "";
|
||||
return buffer;
|
||||
}
|
||||
|
||||
var idxFirst = 0;
|
||||
var idxEnd = text.IndexOf("[i2s_", StringComparison.Ordinal);
|
||||
if (idxEnd < 0)
|
||||
idxEnd=text.Length;
|
||||
|
||||
buffer["Any"] = text.Substring(0, idxEnd);
|
||||
idxFirst = idxEnd;
|
||||
|
||||
while (idxFirst<text.Length)
|
||||
{
|
||||
idxFirst += "[i2s_".Length;
|
||||
int idx = text.IndexOf(']', idxFirst);
|
||||
if (idx < 0) break;
|
||||
var tag = text.Substring(idxFirst, idx - idxFirst);
|
||||
idxFirst = idx+1; // ']'
|
||||
|
||||
idxEnd = text.IndexOf("[i2s_", idxFirst, StringComparison.Ordinal);
|
||||
if (idxEnd < 0) idxEnd = text.Length;
|
||||
var value = text.Substring(idxFirst, idxEnd - idxFirst);
|
||||
|
||||
buffer[tag] = value;
|
||||
idxFirst = idxEnd;
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
public static void AppendSpecializations(string text, List<string> list=null)
|
||||
{
|
||||
if (text == null)
|
||||
return;
|
||||
|
||||
if (list == null)
|
||||
list = new List<string>();
|
||||
|
||||
if (!list.Contains("Any"))
|
||||
list.Add("Any");
|
||||
|
||||
var idxFirst = 0;
|
||||
while (idxFirst<text.Length)
|
||||
{
|
||||
idxFirst = text.IndexOf("[i2s_", idxFirst, StringComparison.Ordinal);
|
||||
if (idxFirst < 0)
|
||||
break;
|
||||
|
||||
idxFirst += "[i2s_".Length;
|
||||
int idx = text.IndexOf(']', idxFirst);
|
||||
if (idx < 0)
|
||||
break;
|
||||
|
||||
var tag = text.Substring(idxFirst, idx - idxFirst);
|
||||
if (!list.Contains(tag))
|
||||
list.Add(tag);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a72e5d6dba43bf249987cd37521e38bb
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user