using System; using System.Collections.Generic; using System.IO; using Unity.VisualScripting; using UnityEngine; using UnityEngine.Serialization; namespace BrewMonster.Scripts.Task { [ CreateAssetMenu(fileName = "TaskTemplContainerSO", menuName = "BrewMonster/Task/TaskTemplContainerSO")] public class TaskTemplContainerSO : ScriptableObject { public const ulong TASK_PACK_MAGIC = 0x93858361; public const ulong _task_templ_cur_version = 121; [SerializeField] private bool _loadAllTasksFromSo = false; [HideInInspector] [SerializeField] private List _topTaskTemplates = new List(); [HideInInspector] [SerializeField] private List _allTaskTemplates = new List(); [Header("DEBUG")] [SerializeField] private int _taskDemoIndex = 100; [SerializeField] private ATaskTempl _taskDemo ; private Dictionary _allTaskTemplMap = new Dictionary(); public List TaskTemplates { get { return _topTaskTemplates; } } public int TaskLoadedCount; public bool LoadAllTasksFromSO => _loadAllTasksFromSo; private void OnValidate() { TaskLoadedCount = _topTaskTemplates == null ? 0 : _topTaskTemplates.Count; if (TaskLoadedCount > _taskDemoIndex) { _taskDemo = _topTaskTemplates[_taskDemoIndex]; } } public ATaskTempl GetTaskTemplate(uint id) { return _allTaskTemplMap.ContainsKey(id) ? _allTaskTemplMap[id] : null; } // call when start load data from SO to runtime-memory public void BuildTaskTemplateMap() { _allTaskTemplMap.Clear(); foreach (var templ in _allTaskTemplates) { if (!_allTaskTemplMap.ContainsKey(templ.m_ID)) { _allTaskTemplMap.Add(templ.m_ID, templ); } } Debug.Log($"[TaskTemplContainerSO] Built task template map with {_allTaskTemplMap.Count} entries."); } [ContextMenu(" Load All Tasks From Pack")] public void LoadAllTasksFromPack() { string task_data_path = Path.Combine(Application.streamingAssetsPath, "data/tasks.data"); _topTaskTemplates = LoadTasksFromPack(task_data_path); Debug.Log($"[TaskTemplContainerSO] Loaded {_topTaskTemplates.Count} task templates from pack."); } [ContextMenu(" Clear All Loaded Tasks")] public void ClearDatas() { _topTaskTemplates.Clear(); Debug.Log($"[TaskTemplContainerSO] Cleared all loaded task templates."); } private List LoadTasksFromPack(string szPackPath) { long readBytes = 0; var tasks = new List(); using (var fs = new FileStream( szPackPath, FileMode.Open, FileAccess.Read, FileShare.Read)) { TASK_PACK_HEADER tph = AAssit.ReadFromBinaryOf(fs, ref readBytes); if (tph.magic != TASK_PACK_MAGIC || tph.version != _task_templ_cur_version) throw new Exception("Invalid task pack header"); if (tph.item_count == 0) return tasks; uint[] pOffs = AAssit.ReadArrayFromBinary(fs, (int)tph.item_count, ref readBytes); for (int i = 0; i < tph.item_count; i++) { fs.Seek(pOffs[i], SeekOrigin.Begin); ATaskTempl templ = new ATaskTempl(); if (!templ.LoadFromBinFile(fs)) continue; tasks.Add(templ); RecursiveToSyncSerializableData(templ); } fs.Seek(0, SeekOrigin.Begin); fs.Close(); } return tasks; } private void RecursiveToSyncSerializableData(ATaskTempl pTempl) { // save all task templates to map // reuse when load data from SO to runtime-memory _allTaskTemplates.Add(pTempl); // fill serializable datas from unserialized ones pTempl.SyncSerializableDataAfterLoaded(); ATaskTempl pChild = pTempl.m_pFirstChild; while (pChild != null) { RecursiveToSyncSerializableData(pChild); pChild = pChild.m_pNextSibling; } } } }