using BrewMonster; using BrewMonster.Network; using BrewMonster.Scripts.World; using CSNetwork; using CSNetwork.GPDataType; using CSNetwork.Protocols; using CSNetwork.Protocols.RPCData; using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; using System.Threading.Tasks; using TMPro; using UnityEngine; using UnityEngine.SceneManagement; namespace PerfectWorld.Scripts.Managers { /// /// Matter Manager - Handles matter data storage and provides access to other classes /// /// Usage Examples: /// // Get matter manager instance /// var matterManager = EC_ManMessageMono.Instance.GetECManMatter; /// /// // Get specific matter data /// var matterData = matterManager.GetMatterData(12345); /// /// // Get individual fields /// int? mid = matterManager.GetMatterId(12345); /// int? tid = matterManager.GetMatterTid(12345); /// A3DVECTOR3? pos = matterManager.GetMatterPosition(12345); /// byte? state = matterManager.GetMatterState(12345); /// /// // Find matters by criteria /// int[] mattersByTid = matterManager.FindMattersByTid(100); /// int[] mattersByState = matterManager.FindMattersByState(1); /// int[] nearbyMatters = matterManager.FindMattersNearPosition(new A3DVECTOR3(0,0,0), 10.0f); /// [Serializable] public class EC_ManMatter : IMsgHandler { public int HandlerId => (int)MANAGER_INDEX.MAN_MATTER; // Storage for matter data that players can access later private Dictionary matterDataStorage = new Dictionary(); private Dictionary m_MatterTab = new Dictionary(); /// /// Unity-only recovery: ensure an existing scene matter is present in the manager table. /// This helps recover after Unity script/domain reload where Dictionaries are not serialized. /// public void RegisterExistingMatter(CECMatter matter) { if (matter == null) return; int mid = matter.GetMatterID(); if (mid == 0) return; m_MatterTab[mid] = matter; } public bool ProcessMessage(ECMSG Msg) { if (Msg.iSubID == 0) { switch ((int)Msg.dwMsg) { case int value when value == EC_MsgDef.MSG_MM_MATTERINFO: { //ENABLE LATER: It fetch all matters in the game world, causing performance issues OnMsgMatterInfo(Msg); break; } case int value when value == EC_MsgDef.MSG_MM_MATTERENTWORLD: { OnMsgMatterEnterWorld(Msg); break; } case int value when value == EC_MsgDef.MSG_MM_MATTERDISAPPEAR: { OnMsgMatterDisappear(Msg); break; } } } else { } return true; } public async void OnMsgMatterInfo(ECMSG Msg) { byte[] data = (byte[])Msg.dwParam1; try { // Parse the data structure: count + info_matter array int offset = 0; // Read count (ushort) ushort count = BitConverter.ToUInt16(data, offset); offset += sizeof(ushort); // Parse each info_matter entry for (int i = 0; i < count; i++) { // Parse info_matter structure info_matter info = CSNetwork.GPDataType.GPDataTypeHelper.FromBytes(data, offset); offset += Marshal.SizeOf(typeof(info_matter)); // Store the matter data for later player access matterDataStorage[info.mid] = info; await MatterEnter(info); } } catch (Exception ex) { Debug.LogError($"Failed to parse matter info data: {ex.Message}"); } } public async void OnMsgMatterEnterWorld(ECMSG Msg) { byte[] data = (byte[])Msg.dwParam1; try { // Parse the byte array into info_matter structure info_matter matterInfo = CSNetwork.GPDataType.GPDataTypeHelper.FromBytes(data); await MatterEnter(matterInfo); } catch (Exception ex) { Debug.LogError($"Failed to parse matter data: {ex.Message}"); } } public void OnMsgMatterDisappear(ECMSG Msg) { byte[] data = (byte[])Msg.dwParam1; int matterId = BitConverter.ToInt32(data); MatterLeave(matterId); } private async Task MatterEnter(info_matter info) { CECMatter pMatter = GetMatter(info.mid); if (pMatter != null) return true; // Create a new matter pMatter = await CECMatter.Init(info); if (pMatter == null) { Debug.LogError($"Failed to create matter: {info.mid}"); return false; } pMatter.SetBornStamp(CECWorld.Instance.GetBornStamp()); m_MatterTab[info.mid] = pMatter; return true; } // Remove a matter public void RemoveMatter(int idMatter) { MatterLeave(idMatter); } public void MatterLeave(int mid) { CECMatter pMatter = GetMatter(mid); if (pMatter != null) { UnityEngine.Object.Destroy(pMatter.gameObject); m_MatterTab.Remove(mid); } //TODO: Might need to implement later /*/ else { MatterTable::pair_type Pair = m_DynModelTab.get(mid); if (Pair.second) { pMatter = *Pair.first; ReleaseMatter(pMatter); // Remove it from active matter table m_DynModelTab.erase(mid); QueueMatterUndoLoad(mid); } } CECPlayerWrapper* pWrapper = CECAutoPolicy::GetInstance().GetPlayerWrapper(); if( pWrapper ) pWrapper->OnObjectDisappear(mid); //*/ } // Public methods for players to access matter data public info_matter? GetMatterData(int matterId) { return matterDataStorage.TryGetValue(matterId, out info_matter data) ? data : null; } public bool HasMatterData(int matterId) { return matterDataStorage.ContainsKey(matterId); } public CECMatter GetMatter(int mid, uint dwBornStamp = 0) { if (m_MatterTab.TryGetValue(mid, out CECMatter matter)) { if (dwBornStamp != 0) { if (matter.GetBornStamp() != dwBornStamp) { return null; } } return matter; } return null; } public CECMatter CreateMatter(info_matter info) { return null; } } }