using System; using System.Collections.Generic; using System.IO; using System.Net; using System.Threading.Tasks; 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 _topTaskTemplIds = new (); [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 TopTaskTemplates { get; } = new List(); public int TaskLoadedCount; public bool LoadAllTasksFromSO => _loadAllTasksFromSo; private void OnValidate() { TaskLoadedCount = _topTaskTemplIds == null ? 0 : _topTaskTemplIds.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(); TopTaskTemplates.Clear(); // build all-task map foreach (var templ in _allTaskTemplates) { if (!_allTaskTemplMap.ContainsKey(templ.m_ID)) { _allTaskTemplMap.Add(templ.m_ID, templ); } } // build top-task list foreach (var topId in _topTaskTemplIds) { if (_allTaskTemplMap.ContainsKey((uint)topId)) { TopTaskTemplates.Add(_allTaskTemplMap[(uint)topId]); } } Debug.Log($"[TaskTemplContainerSO] Built task template map with {_allTaskTemplMap.Count} entries."); } [ContextMenu(" Load All Tasks From Pack")] public async void LoadAllTasksFromPack() { //string task_data_path = Path.Combine(Application.streamingAssetsPath, "data/tasks.data"); string task_data_path = "Assets/PerfectWorld/Data/tasks.bytes"; _topTaskTemplIds = await LoadTasksFromPack(task_data_path); Debug.Log($"[TaskTemplContainerSO] Loaded {_topTaskTemplIds.Count} task templates from pack."); } [ContextMenu(" Clear All Loaded Tasks")] public void ClearDatas() { _topTaskTemplIds.Clear(); _allTaskTemplates.Clear(); _allTaskTemplMap.Clear(); Debug.Log($"[TaskTemplContainerSO] Cleared all loaded task templates."); } private async Task> LoadTasksFromPack(string address) { long readBytes = 0; // var tasks = new List(); var taskIds = new List(); var handle = await AddressableManager.Instance.LoadTextAssetAsync(address); byte[] data = handle.bytes; using var fs = new MemoryStream(data); 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 taskIds; 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; taskIds.Add(templ.m_ID); RecursiveToSyncSerializableData(templ); } fs.Seek(0, SeekOrigin.Begin); fs.Close(); return taskIds; } 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; } } } }