This commit is contained in:
2026-05-17 15:12:16 +07:00
parent 93da00c206
commit bf0ebe447d
902 changed files with 142169 additions and 31515 deletions

View File

@@ -0,0 +1,143 @@
using DA_Assets.DAI;
using DA_Assets.Extensions;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using UnityEngine;
namespace DA_Assets.Singleton
{
public class AssetConfig<T> : SingletonScriptableObject<T> where T : ScriptableObject
{
public string ProductVersion => productVersion;
[SerializeField] string productVersion;
public InternalLocalizator Localizator => localizator.Init();
[SerializeField] InternalLocalizator localizator;
}
[Serializable]
public class InternalLocalizator
{
[SerializeField] TextAsset locFile;
private List<LocItem> localizations = new List<LocItem>();
public InternalLocalizator Init()
{
#if UNITY_EDITOR
if (localizations.IsEmpty())
{
try
{
if (locFile == null)
{
throw new NullReferenceException("Localization file missing.");
}
localizations = ConvertFileToLocItems(locFile.text);
}
catch
{
}
}
#endif
return this;
}
private List<LocItem> ConvertFileToLocItems(string csvText)
{
List<LocItem> locItems = new List<LocItem>();
using (var reader = new StringReader(csvText))
{
string line;
LocItem currentLocItem = default;
StringBuilder currentText = null;
while ((line = reader.ReadLine()) != null)
{
if (currentLocItem.Equals(default(LocItem)))
{
string[] columns = line.Split(';');
if (columns.Length >= 2)
{
currentLocItem = new LocItem
{
key = columns[0],
en = columns[1]
};
if (currentLocItem.en.StartsWith("\"") && !currentLocItem.en.EndsWith("\""))
{
currentText = new StringBuilder();
currentText.AppendLine(currentLocItem.en.TrimStart('\"'));
}
else
{
locItems.Add(currentLocItem);
currentLocItem = default;
}
}
}
else if (currentText != null)
{
if (line.EndsWith("\"") && !line.EndsWith(";\""))
{
currentText.AppendLine(line.TrimEnd('\"'));
currentLocItem.en = currentText.ToString();
locItems.Add(currentLocItem);
currentLocItem = default;
currentText = null;
}
else
{
currentText.AppendLine(line);
}
}
}
}
return locItems;
}
public string GetLocalizedText(Enum key, params object[] args)
{
return GetLocalizedText(key.ToString(), args);
}
private string GetLocalizedText(string key, params object[] args)
{
foreach (LocItem item in localizations)
{
if (item.key == key)
{
string txt = item.en;
if (txt == "")
{
return key;
}
try
{
return string.Format(txt, args);
}
catch
{
return txt;
}
}
}
return key;
}
}
internal struct LocItem
{
internal string key { get; set; }
internal string en { get; set; }
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f1d4a4f7829e18049831fcb1cb974278
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,156 @@
using System;
using System.IO;
using System.Threading.Tasks;
using UnityEngine;
#pragma warning disable IDE1006
#pragma warning disable CS1998
namespace DA_Assets.Singleton
{
/// <summary>
/// An analogue of the <see href="https://docs.unity3d.com/6000.0/Documentation/ScriptReference/ScriptableSingleton_1.html">
/// ScriptableSingleton&lt;T&gt;</see> class, but works both in Playmode and in the Editor.
/// <para>The asset is searched in the <see cref="Resources"/> folder by sequentially traversing the subfolders
/// specified in the <see cref="ResourcePathAttribute"/> parameters. If the attribute is defined as
/// <see cref="ResourcePathAttribute"/>(""), the search occurs in the root of the <see cref="Resources"/> folder,
/// and each subsequent parameter indicates the corresponding subfolder.</para>
/// <para>Inherits from <see cref="ScriptableObject"/>.</para>
/// </summary>
public class SingletonScriptableObject<T> : ScriptableObject where T : ScriptableObject
{
private static T _instance;
/// <summary>
/// Called upon the first access to the object instance after script recompilation and when entering Playmode.
/// </summary>
protected virtual void OnCreateInstance() { }
public virtual async Task OnCreateInstanceAsync() { }
/// <summary>
/// Called after exiting PlayMode.
/// </summary>
protected virtual void OnExitPlayMode() { }
private static SingletonScriptableObject<T> _genericInstance => _instance as SingletonScriptableObject<T>;
/// <summary>
/// <para>Gets the instance of the Singleton. Unity creates the Singleton instance when this property is accessed for the first time.</para>
/// </summary>
public static T Instance
{
get
{
CreateInstance();
return _instance;
}
}
public static async Task<T> GetInstanceAsync()
{
await InitializeAsync();
return _instance;
}
public static void CreateInstance()
{
if (_instance == null)
{
_instance = LoadInstance();
SetupPlayModeExitEvent();
_genericInstance?.OnCreateInstance();
}
}
public static async Task InitializeAsync()
{
if (_instance == null)
{
_instance = await LoadInstanceAsync();
SetupPlayModeExitEvent();
await _genericInstance?.OnCreateInstanceAsync();
}
}
private static string GetAssetPath()
{
object[] attributes = typeof(T).GetCustomAttributes(typeof(ResourcePathAttribute), true);
if (attributes != null && attributes.Length > 0)
{
ResourcePathAttribute foldersAttribute = attributes[0] as ResourcePathAttribute;
string path = Path.Combine(foldersAttribute.Path);
path = Path.Combine(path, typeof(T).Name);
return path;
}
return typeof(T).Name;
}
private static T LoadInstance()
{
string assetPath = GetAssetPath();
T instance = Resources.Load<T>(assetPath);
if (instance == null)
{
throw new NullReferenceException(_objectNotFoundErrorStr);
}
return instance;
}
private static async Task<T> LoadInstanceAsync()
{
string assetPath = GetAssetPath();
ResourceRequest request = Resources.LoadAsync<T>(assetPath);
while (!request.isDone)
await Task.Yield();
T instance = request.asset as T;
if (instance == null)
{
throw new NullReferenceException(_objectNotFoundErrorStr);
}
return instance;
}
private static void SetupPlayModeExitEvent()
{
#if UNITY_EDITOR
UnityEditor.EditorApplication.playModeStateChanged -= PlayModeExitEvent;
UnityEditor.EditorApplication.playModeStateChanged += PlayModeExitEvent;
#endif
}
#if UNITY_EDITOR
private static void PlayModeExitEvent(UnityEditor.PlayModeStateChange change)
{
if (change == UnityEditor.PlayModeStateChange.EnteredEditMode)
{
_genericInstance?.OnExitPlayMode();
}
}
#endif
private static string _missingAttributeErrorStr => $"Missing {nameof(ResourcePathAttribute)} in {typeof(T).Name}";
private static string _objectNotFoundErrorStr => $"{nameof(ScriptableObject)} '{typeof(T).Name}' not found in the project.";
}
[AttributeUsage(AttributeTargets.Class)]
public class ResourcePathAttribute : Attribute
{
public string[] Path { get; private set; }
public ResourcePathAttribute(params string[] path)
{
Path = path;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4839a49a0907ef644974b18b47da2fdb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,21 @@
using System;
namespace DA_Assets.Singleton
{
public class StaticSingleton<T>
{
private static T instance;
public static T Instance
{
get
{
if (instance == null)
{
instance = Activator.CreateInstance<T>();
}
return instance;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: afc81ce8e8e88024d9a377086dd52ee0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: