Files

287 lines
12 KiB
C#

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<CECMatter> 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);
// use same rotation as Prefab
// matterObject.transform.localRotation = Quaternion.identity;
matterObject.SetActive(true);
// Add a collider if it doesn't have one
if (matterObject.GetComponent<Collider>() == null)
{
var collider = matterObject.AddComponent<BoxCollider>();
collider.size = matterObject.GetComponentInChildren<Renderer>().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<MatterCubeClickHandler>();
// clickHandler.Initialize(Info.mid, this);
CECMatter matterScript = matterObject.AddComponent<CECMatter>();
// 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;
}
}
}