using System.Reflection; using System.Threading.Tasks; using BrewMonster; using BrewMonster.Network; using BrewMonster.Scripts; using CSNetwork.GPDataType; using ModelRenderer.Scripts.Common; using PerfectWorld.Scripts.Managers; using UnityEngine; namespace PerfectWorld.Scripts { public class CECMatter : CECObject { // Matter information got from server public struct INFO { public int mid; // Matter id public int tid; // Template id } protected EC_ManMatter m_pMatterMan; protected INFO m_MatterInfo; protected int m_iLevelReq; protected float m_fGatherDist; protected uint m_dwMatterType; // Matter type flags / Matter type flags private bool m_registeredToManMatter = false; // Matter type constants / Matter type constants public const uint MATTER_UNKNOWN = 0; public const uint MATTER_ITEM = 1; public const uint MATTER_MINE = 2; public const uint MATTER_MONEY = 3; public const uint MATTER_TYPEMASK = 0xff; // Constructor / Constructor public CECMatter() { m_iCID = Class_ID.OCID_MATTER; } // Awake is called when the component is initialized / Awake is called when the component is initialized private void Awake() { m_iCID = Class_ID.OCID_MATTER; // Ensure CID is set after Unity initialization / Ensure CID is set after Unity initialization TryRegisterToManMatter(); } private void OnEnable() { TryRegisterToManMatter(); } private void TryRegisterToManMatter() { if (m_registeredToManMatter) return; // Only register once we have a valid mid. int mid = GetMatterID(); if (mid == 0) return; var mono = BrewMonster.Managers.EC_ManMessageMono.Instance; if (mono == null || mono.EC_ManMatter == null) return; mono.EC_ManMatter.RegisterExistingMatter(this); m_registeredToManMatter = true; } // Override SetUpCECObject to set class ID / Override SetUpCECObject to set class ID public override void SetUpCECObject() { base.SetUpCECObject(); m_iCID = Class_ID.OCID_MATTER; // Set after base call to override the reset / Set after base call to override the reset } public void SetMatterInfo(INFO matterInfo) { m_MatterInfo = matterInfo; } public int GetTemplateID() { return m_MatterInfo.tid; } public int GetLevelReq() { return m_iLevelReq; } public float GetGatherDist() { // 采集/拾取距离:某些情况下(例如场景预制体未走 Init 流程)m_fGatherDist 可能为 0。 // Gather/pickup distance: in some cases (e.g. scene prefab not created via Init) m_fGatherDist may be 0. // Provide a safe default consistent with native behavior. return m_fGatherDist > 0.01f ? m_fGatherDist : 3.0f; } // Is this matter a mine? / Is this matter a mine? public bool IsMine() { return (m_dwMatterType & MATTER_TYPEMASK) == MATTER_MINE; } // Is this matter an item? / Is this matter an item? public bool IsItem() { return (m_dwMatterType & MATTER_TYPEMASK) == MATTER_ITEM; } // Is this matter money? / Is this matter money? public bool IsMoney() { return (m_dwMatterType & MATTER_TYPEMASK) == MATTER_MONEY; } public static async Task Init(info_matter Info) { INFO matterInfo = new INFO(); matterInfo.mid = Info.mid; matterInfo.tid = Info.tid & 0x0000ffff; // get the matter template from elementdataman DATA_TYPE DataType = DATA_TYPE.DT_INVALID; var matterData = ElementDataManProvider.GetElementDataMan().get_data_ptr((uint)matterInfo.tid, ID_SPACE.ID_SPACE_ESSENCE, ref DataType); // Determine matter type based on DataType / Determine matter type based on DataType uint dwMatterType = MATTER_UNKNOWN; if (DataType == DATA_TYPE.DT_MINE_ESSENCE) { dwMatterType = MATTER_MINE; } else { // Default to ITEM for other essence types / Default to ITEM for other essence types dwMatterType = MATTER_ITEM; } // 钱币掉落 / Money drop // 服务器用特殊 tid 表示金币/银币拾取物;不应占用背包格子。 // The server uses a special tid to represent money matters; they should not consume inventory slots. if (GPDataTypeHelper.ISMONEYTID(matterInfo.tid)) { dwMatterType = MATTER_MONEY; } if (matterData != null) { var matterDataType = matterData.GetType(); var fileMatterField = matterDataType.GetField("file_matter", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (fileMatterField == null) { fileMatterField = matterDataType.GetField("file_model", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } if (fileMatterField != null) { var fileMatterValue = fileMatterField.GetValue(matterData); string filePath = ByteToStringUtils.ByteArrayToCP936String((byte[])fileMatterValue); var matterPrefab = await AddressableManager.Instance.LoadPrefabAsync(AFile.NormalizePath(filePath.ToLower(), true)); if (matterPrefab != null) { var matterObject = Instantiate(matterPrefab); matterObject.transform.position = new Vector3(Info.pos.x, Info.pos.y, Info.pos.z); matterObject.transform.localScale = new Vector3(1f, 1f, 1f); matterObject.transform.localRotation = Quaternion.identity; matterObject.SetActive(true); // Add a collider if it doesn't have one if (matterObject.GetComponent() == null) { var collider = matterObject.AddComponent(); collider.size = matterObject.GetComponentInChildren().bounds.size; } // Create text object to display item name above the cube // CreateItemNameText(matterObject, info.tid); // Add a script to handle click events // MatterCubeClickHandler clickHandler = matterObject.AddComponent(); // clickHandler.Initialize(Info.mid, this); CECMatter matterScript = matterObject.AddComponent(); // Set CID immediately after AddComponent (before SetUpCECObject resets it) / Set CID immediately after AddComponent (before SetUpCECObject resets it) matterScript.m_iCID = Class_ID.OCID_MATTER; matterScript.SetMatterInfo(matterInfo); matterScript.m_dwMatterType = dwMatterType; // Set matter type / Set matter type // Set level requirement and gather distance for mines / Set level requirement and gather distance for mines if (dwMatterType == MATTER_MINE && DataType == DATA_TYPE.DT_MINE_ESSENCE) { var levelReqField = matterData.GetType().GetField("level_required", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (levelReqField != null) { matterScript.m_iLevelReq = (int)levelReqField.GetValue(matterData); } var gatherDistField = matterData.GetType().GetField("gather_dist", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (gatherDistField != null) { float gatherDist = (float)gatherDistField.GetValue(matterData); matterScript.m_fGatherDist = gatherDist > 3.0f ? gatherDist - 1.0f : 3.0f; } else { matterScript.m_fGatherDist = 3.0f; } } else { // For non-mine items, set a default pickup distance / For non-mine items, set a default pickup distance matterScript.m_fGatherDist = 3.0f; // Default pickup distance / Default pickup distance } matterScript.SetUpCECObject(); // This will reset m_iCID, so we set it again after / This will reset m_iCID, so we set it again after // Force set CID again after SetUpCECObject (which resets it to OCID_OBJECT) / Force set CID again after SetUpCECObject (which resets it to OCID_OBJECT) matterScript.m_iCID = Class_ID.OCID_MATTER; // Store reference to the cube // matterGameObjects[info.mid] = matterObject; return matterScript; } else { Debug.LogWarning($"Failed to load matter prefab from path: {filePath}"); } } else { Debug.LogWarning($"file_matter field not found on matter data type {matterDataType.FullName}"); } } return null; } private new void Update() { // Recovery: after Unity domain reload, manager dictionaries reset but scene objects persist. // Keep trying until we successfully register. if (!m_registeredToManMatter) TryRegisterToManMatter(); // Check for touch input (mobile) if (Input.touchCount > 0) { Touch touch = Input.GetTouch(0); if (touch.phase == TouchPhase.Began) { // Touch handling intentionally disabled for now. / Touch handling intentionally disabled for now. } } // Check for mouse input (desktop) // else if (Input.GetMouseButtonDown(0)) // { // inputPressed = true; // screenPosition = Input.mousePosition; // } // // if (inputPressed) // { // Camera mainCamera = Camera.main; // if (mainCamera == null) // return; // // Ray ray = mainCamera.ScreenPointToRay(screenPosition); // // RaycastHit[] hits = Physics.RaycastAll(ray); // // foreach (RaycastHit hit in hits) // { // if (hit.collider.gameObject == this.gameObject || // hit.collider.transform.IsChildOf(this.transform)) // { // Debug.Log($"CECMatter::RaycastHit():: mid: {m_MatterInfo.mid}"); // UnityGameSession.RequestPickupItem(m_MatterInfo.mid, m_MatterInfo.tid); // break; // } // } // } } public int GetMatterID() { return m_MatterInfo.mid; } } }