using UnityEngine; using UnityEngine.UI; using BrewMonster.Network; using PerfectWorld.Scripts.Managers.BrewMonster.Managers; using PerfectWorld.Scripts.Managers; using CSNetwork.GPDataType; using System.Collections.Generic; using System.Reflection; using BrewMonster; using TMPro; using BrewMonster.Managers; using BrewMonster.Scripts.Managers; using ModelRenderer.Scripts.Common; using BrewMonster.Scripts; public class pickupItem : MonoBehaviour { // Singleton instance private static pickupItem _instance; public static pickupItem Instance { get { if (_instance == null) { _instance = FindFirstObjectByType(); if (_instance == null) { // Create a new GameObject with pickupItem component if none exists GameObject pickupManager = new GameObject("PickupManager"); _instance = pickupManager.AddComponent(); DontDestroyOnLoad(pickupManager); } } return _instance; } } // Dictionary to store created cubes with their matter IDs private Dictionary matterGameObjects = new Dictionary(); // Dictionary to track pending pickups by TID private Dictionary pendingPickups = new Dictionary(); // TID -> MatterID // Set to track items that have been picked up by the player (to prevent respawn) private HashSet pickedUpItems = new HashSet(); // MID of picked up items // Reference to the matter manager private EC_ManMatter matterManager; // Start is called once before the first execution of Update after the MonoBehaviour is created void Start() { // Ensure this is the singleton instance if (_instance == null) { _instance = this; DontDestroyOnLoad(gameObject); } else if (_instance != this) { // If another instance already exists, destroy this one Destroy(gameObject); return; } // Get reference to matter manager if (EC_ManMessageMono.Instance != null) { matterManager = EC_ManMessageMono.Instance.GetECManMatter; } else { Debug.LogError("EC_ManMessageMono.Instance is null - matter manager not available"); } // Subscribe to matter enter world events SubscribeToMatterEvents(); } // Update is called once per frame void Update() { // Check for mouse clicks on cubes if (Input.GetMouseButtonDown(0)) { if (CECUIManager.IsPointerOverInteractiveUI()) return; var uiMan = EC_Game.GetGameRun()?.GetUIManager(); if (uiMan != null && uiMan.IsWorldInteractionBlockedByUI()) return; HandleCubeClick(); } } private void SubscribeToMatterEvents() { // We'll need to hook into the matter manager's events // For now, we'll check for new matters in Update } private void HandleCubeClick() { // Find the main camera Camera mainCamera = Camera.main; if (mainCamera == null) { mainCamera = FindFirstObjectByType(); } if (mainCamera == null) { Debug.LogWarning("No camera found for raycast"); return; } Ray ray = mainCamera.ScreenPointToRay(Input.mousePosition); RaycastHit hit; if (Physics.Raycast(ray, out hit)) { GameObject clickedObject = hit.collider.gameObject; // Check if the clicked object is one of our matter cubes foreach (var kvp in matterGameObjects) { if (kvp.Value == clickedObject) { int matterId = kvp.Key; SendPickupCommand(matterId); break; } } } } public void SendPickupCommand(int matterId) { if (matterManager != null) { var matterData = matterManager.GetMatterData(matterId); if (matterData.HasValue) { // Track this pickup request pendingPickups[(int)matterData.Value.tid] = matterId; UnityGameSession.RequestPickupItem((int)matterData.Value.mid, (int)matterData.Value.tid); Debug.Log($"Pickup request sent for matter - MID: {matterData.Value.mid}, TID: {matterData.Value.tid}"); } else { Debug.LogWarning($"No matter data found for matter ID: {matterId}"); } } else { Debug.LogError("Matter manager is null - cannot send pickup command"); } } public void CreateMatterCube(int matterId) { if (matterManager == null) return; var matterData = matterManager.GetMatterData(matterId); if (!matterData.HasValue) return; // Check if this item was previously picked up by the player if (pickedUpItems.Contains(matterId)) { Debug.Log($"Skipping cube creation for matter {matterId} - item was previously picked up by player"); return; } // Check if cube already exists if (matterGameObjects.ContainsKey(matterId)) { Debug.Log($"Cube for matter {matterId} already exists"); return; } // Create cube GameObject GameObject cube = GameObject.CreatePrimitive(PrimitiveType.Cube); cube.name = $"Matter_{matterData.Value.mid}_TID_{matterData.Value.tid}"; cube.transform.localScale = new Vector3(1f, 1f, 1f); // Position the cube based on matter position Vector3 position = new Vector3( matterData.Value.pos.x, matterData.Value.pos.y, matterData.Value.pos.z ); cube.transform.position = position; // Add a collider if it doesn't have one if (cube.GetComponent() == null) { cube.AddComponent(); } // Create text object to display item name above the cube CreateItemNameText(cube, matterData.Value.tid); // Add a script to handle click events MatterCubeClickHandler clickHandler = cube.AddComponent(); clickHandler.Initialize(matterId, this); // Store reference to the cube matterGameObjects[matterId] = cube; //Debug.Log($"Created cube for matter {matterId} at position {position}"); } public async void CreateMatterModelObject(info_matter info) { DATA_TYPE dataType = DATA_TYPE.DT_INVALID; var matterData = ElementDataManProvider.GetElementDataMan().get_data_ptr((uint)info.tid, ID_SPACE.ID_SPACE_ESSENCE, ref dataType); BMLogger.Log($"CreateMatterModelObject():: tid: {info.tid}, mid: {info.mid}, pos: {info.pos.x}, {info.pos.y}, {info.pos.z}"); if (matterData != null) { var matterType = matterData.GetType(); var fileMatterField = matterType.GetField("file_matter", 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); // Store reference to the cube matterGameObjects[info.mid] = matterObject; } else { Debug.LogWarning($"Failed to load matter prefab from path: {filePath}"); } } else { Debug.LogWarning($"file_matter field not found on matter data type {matterType.FullName}"); } } else { CreateMatterCube(info.mid); } } private void CreateItemNameText(GameObject cube, int tid) { // Create a child GameObject for the text GameObject textObject = new GameObject("ItemNameText"); textObject.transform.SetParent(cube.transform); // Position the text above the cube textObject.transform.localPosition = new Vector3(0, 1.2f, 0); // Above the cube // Add TextMeshPro component TextMeshPro textMesh = textObject.AddComponent(); // Get the item name string itemName = EC_IvtrItemUtils.Instance.ResolveItemName(tid); if (string.IsNullOrEmpty(itemName)) { itemName = $"Item {tid}"; } // Configure the text textMesh.text = itemName; textMesh.fontSize = 10f; textMesh.color = Color.white; textMesh.alignment = TextAlignmentOptions.Center; // Make the text face the camera textObject.AddComponent(); // Add a background for better visibility GameObject background = new GameObject("TextBackground"); background.transform.SetParent(textObject.transform); background.transform.localPosition = Vector3.zero; background.transform.localScale = new Vector3(2f, 0.8f, 0.1f); // Add a simple quad renderer for background MeshRenderer bgRenderer = background.AddComponent(); MeshFilter bgFilter = background.AddComponent(); // Create a simple quad mesh for the background Mesh quadMesh = new Mesh(); quadMesh.vertices = new Vector3[] { new Vector3(-0.5f, -0.5f, 0), new Vector3(0.5f, -0.5f, 0), new Vector3(0.5f, 0.5f, 0), new Vector3(-0.5f, 0.5f, 0) }; quadMesh.triangles = new int[] { 0, 1, 2, 0, 2, 3 }; quadMesh.uv = new Vector2[] { new Vector2(0, 0), new Vector2(1, 0), new Vector2(1, 1), new Vector2(0, 1) }; quadMesh.RecalculateNormals(); bgFilter.mesh = quadMesh; // Create a simple material for the background Material bgMaterial = new Material(Shader.Find("Standard")); bgMaterial.color = new Color(0, 0, 0, 0.7f); // Semi-transparent black bgRenderer.material = bgMaterial; } public void RemoveMatterObject(int matterId) { if (matterGameObjects.ContainsKey(matterId)) { GameObject cube = matterGameObjects[matterId]; if (cube != null) { Destroy(cube); } matterGameObjects.Remove(matterId); } } public void UpdateMatterObjects() { if (matterManager == null) return; // Get all current matter IDs // info_matter[] allMatterInfo = matterManager.GetAllMatterInfo(); // // Create cubes for new matters (but skip items previously picked up by player) // foreach (info_matter info in allMatterInfo) // { // if (!matterGameObjects.ContainsKey(info.mid) && !pickedUpItems.Contains(info.mid)) // { // CreateMatterModelObject(info); // } // } // Remove cubes for matters that no longer exist List matterToRemove = new List(); foreach (var kvp in matterGameObjects) { if (!matterManager.HasMatterData(kvp.Key)) { matterToRemove.Add(kvp.Key); } } foreach (int matterId in matterToRemove) { RemoveMatterObject(matterId); } } /// /// Called when a pickup is successful. Removes the cube for the picked up item. /// /// Template ID of the picked up item public void OnPickupSuccess(int tid) { if (pendingPickups.ContainsKey(tid)) { int matterId = pendingPickups[tid]; // Track this item as picked up by the player pickedUpItems.Add(matterId); // Remove the cube RemoveMatterObject(matterId); // Remove from pending pickups pendingPickups.Remove(tid); Debug.Log($"Successfully picked up item with TID: {tid}, removed cube for matter ID: {matterId}"); } else { Debug.LogWarning($"Received pickup success for TID {tid} but no pending pickup found"); } } /// /// Called when a pickup fails. Removes the pending pickup tracking. /// /// Template ID of the failed pickup public void OnPickupFailed(int tid) { if (pendingPickups.ContainsKey(tid)) { pendingPickups.Remove(tid); Debug.Log($"Pickup failed for TID: {tid}, removed from pending pickups"); } } /// /// Clears the tracking of picked up items. Call this when player changes areas or logs out. /// public void ClearPickedUpItemsTracking() { pickedUpItems.Clear(); Debug.Log("Cleared picked up items tracking"); } /// /// Gets the count of items that have been picked up by the player. /// /// Number of items picked up public int GetPickedUpItemsCount() { return pickedUpItems.Count; } private void OnDestroy() { // Clean up all matter cubes foreach (var kvp in matterGameObjects) { if (kvp.Value != null) { Destroy(kvp.Value); } } matterGameObjects.Clear(); // Clean up pending pickups pendingPickups.Clear(); // Clean up picked up items tracking pickedUpItems.Clear(); } } // Helper class to handle click events on matter cubes public class MatterCubeClickHandler : MonoBehaviour { private int matterId; private pickupItem pickupItemScript; public void Initialize(int id, pickupItem script) { matterId = id; pickupItemScript = script; } private void OnMouseDown() { if (pickupItemScript != null) { pickupItemScript.SendPickupCommand(matterId); } } } // Simple Billboard component to make text always face the camera public class Billboard : MonoBehaviour { private Camera mainCamera; void Start() { mainCamera = Camera.main; if (mainCamera == null) { mainCamera = FindFirstObjectByType(); } } void Update() { if (mainCamera != null) { // Make the text face the camera transform.LookAt(mainCamera.transform); transform.Rotate(0, 180, 0); // Flip to face the camera properly } } }