using BrewMonster; using BrewMonster.Network; using CSNetwork; using CSNetwork.GPDataType; using CSNetwork.Protocols; using CSNetwork.Protocols.RPCData; using PerfectWorld.Scripts.Player; using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; using TMPro; using UnityEngine; using UnityEngine.SceneManagement; namespace PerfectWorld.Scripts.Managers { namespace BrewMonster.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(); public bool ProcessMessage(ECMSG Msg) { if (Msg.iSubID == 0) { switch ((int)Msg.dwMsg) { case int value when value == EC_MsgDef.MSG_MM_MATTERINFO: { Debug.Log("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: { Debug.Log("MATTERENTWORLD"); OnMsgMatterEnterWorld(Msg); break; } } } else { } return true; } public 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); Debug.Log($"MATTERINFO: Received {count} matter entries"); // Parse each info_matter entry for (int i = 0; i < count; i++) { // Parse info_matter structure info_matter matterInfo = CSNetwork.GPDataType.GPDataTypeHelper.FromBytes(data, offset); offset += Marshal.SizeOf(typeof(info_matter)); // Store the matter data for later player access matterDataStorage[matterInfo.mid] = matterInfo; Debug.Log($"Matter info - ID: {matterInfo.mid}, TID: {matterInfo.tid}, Position: {matterInfo.pos}, State: {matterInfo.state}"); // Spawn cube for this matter since it has entered the world SpawnMatterCube(matterInfo.mid); } } catch (Exception ex) { Debug.LogError($"Failed to parse matter info data: {ex.Message}"); } } public 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); // Store the matter data for later player access matterDataStorage[matterInfo.mid] = matterInfo; Debug.Log($"Matter entered world - ID: {matterInfo.mid}, TID: {matterInfo.tid}, Position: {matterInfo.pos}, State: {matterInfo.state}"); // Notify pickupItem to create cube for this matter NotifyPickupItem(matterInfo.mid); } catch (Exception ex) { Debug.LogError($"Failed to parse matter data: {ex.Message}"); } } private void SpawnMatterCube(int matterId) { // Check if matter is within 1000 units of the host player /*if (!IsMatterWithinPlayerRange(matterId, 10000f)) { Debug.Log($"Matter {matterId} is too far from player, skipping spawn"); return; }*/ // Find the pickupItem component in the scene and create cube for this specific matter pickupItem pickupScript = UnityEngine.Object.FindFirstObjectByType(); if (pickupScript != null) { pickupScript.CreateMatterCube(matterId); } else { Debug.LogWarning("pickupItem component not found in scene - cannot spawn matter cube"); } } private void NotifyPickupItem(int matterId) { // Check if matter is within 1000 units of the host player if (!IsMatterWithinPlayerRange(matterId, 1000f)) { Debug.Log($"Matter {matterId} is too far from player, skipping notification"); return; } // Find the pickupItem component in the scene and update cubes pickupItem pickupScript = UnityEngine.Object.FindFirstObjectByType(); if (pickupScript != null) { pickupScript.UpdateMatterCubes(); } } /// /// Check if a matter is within the specified distance from the host player /// /// The matter ID to check /// Maximum distance in Unity units /// True if matter is within range, false otherwise private bool IsMatterWithinPlayerRange(int matterId, float maxDistance) { // Get the matter data if (!matterDataStorage.TryGetValue(matterId, out info_matter matterData)) { Debug.LogWarning($"Matter data not found for ID: {matterId}"); return false; } // Get the host player var hostPlayer = GameController.Instance?.GetHostPlayer(); if (hostPlayer == null) { Debug.LogWarning("Host player not found"); return false; } // Convert matter position to Unity Vector3 Vector3 matterPosition = new Vector3(matterData.pos.x, matterData.pos.y, matterData.pos.z); // Get player position Vector3 playerPosition = hostPlayer.transform.position; // Calculate distance float distance = Vector3.Distance(matterPosition, playerPosition); Debug.Log($"Matter {matterId} distance from player: {distance:F2} units (max: {maxDistance})"); return distance <= maxDistance; } // 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 Dictionary GetAllMatterData() { return new Dictionary(matterDataStorage); } public bool HasMatterData(int matterId) { return matterDataStorage.ContainsKey(matterId); } public void RemoveMatterData(int matterId) { if (matterDataStorage.ContainsKey(matterId)) { matterDataStorage.Remove(matterId); Debug.Log($"Removed matter data for ID: {matterId}"); } } public int GetMatterCount() { return matterDataStorage.Count; } // Convenience methods to get specific fields from matter data public int? GetMatterId(int matterId) { return matterDataStorage.TryGetValue(matterId, out info_matter data) ? data.mid : null; } public int? GetMatterTid(int matterId) { return matterDataStorage.TryGetValue(matterId, out info_matter data) ? data.tid : null; } public A3DVECTOR3? GetMatterPosition(int matterId) { return matterDataStorage.TryGetValue(matterId, out info_matter data) ? data.pos : null; } public byte? GetMatterDir0(int matterId) { return matterDataStorage.TryGetValue(matterId, out info_matter data) ? data.dir0 : null; } public byte? GetMatterDir1(int matterId) { return matterDataStorage.TryGetValue(matterId, out info_matter data) ? data.dir1 : null; } public byte? GetMatterRadius(int matterId) { return matterDataStorage.TryGetValue(matterId, out info_matter data) ? data.rad : null; } public byte? GetMatterState(int matterId) { return matterDataStorage.TryGetValue(matterId, out info_matter data) ? data.state : null; } public byte? GetMatterValue(int matterId) { return matterDataStorage.TryGetValue(matterId, out info_matter data) ? data.value : null; } // Get all matter IDs public int[] GetAllMatterIds() { return matterDataStorage.Keys.ToArray(); } // Find matters by template ID (tid) public int[] FindMattersByTid(int tid) { return matterDataStorage.Where(kvp => kvp.Value.tid == tid).Select(kvp => kvp.Key).ToArray(); } // Find matters by state public int[] FindMattersByState(byte state) { return matterDataStorage.Where(kvp => kvp.Value.state == state).Select(kvp => kvp.Key).ToArray(); } // Get matters within a certain distance from a position public int[] FindMattersNearPosition(A3DVECTOR3 position, float maxDistance) { return matterDataStorage.Where(kvp => { float distance = (kvp.Value.pos - position).Magnitude(); return distance <= maxDistance; }).Select(kvp => kvp.Key).ToArray(); } } } }