Files
test/Assets/PerfectWorld/Scripts/UI/WorldMap/DlgWorldMap.cs
T

407 lines
16 KiB
C#

using System.Collections.Generic;
using BrewMonster.Network;
using CSNetwork.Common;
using CSNetwork.GPDataType;
using ModelRenderer.Scripts.Common;
using ModelRenderer.Scripts.GameData;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.UI;
namespace BrewMonster.UI
{
public class DlgWorldMap : AUIDialog
{
[SerializeField] private Image mapImage;
[SerializeField] private Image _hostPlayerPositionImage;
[Space(10)]
[SerializeField] private float _positionFactor = 2f;
[SerializeField] private Button _closeButton;
[Space(10)]
[Header("Transmit Service")]
[SerializeField] private RectTransform _transPointButtonParent;
// this is the prefab for the trans point button
[SerializeField] private WorldMapTransPoint _transPointButtonPrefab;
[SerializeField] private Image _trasmitWayImagePrefab; // this is the line to connect the trans point to the host player.
private List<Image> _waypointImages = new(); // this is the list of waypoint images.
private Dictionary<int, WorldMapTransPoint> _transPoints = new();
// 世界 / World
const int MAJOR_MAP = 1;
// 仙魔 / Good Evil // Tiên Ma
static bool GOOD_EVIL_MAP(int id)
{
return id == 121 || id == 122;
}
// 城战 / Guild War // Thành Chiến
static bool GUILD_WAR_MAP(int id)
{
return id >= 230 && id <= 235;
}
// 蓬莱 / Penglai // Bồng Lai
static bool PENGLAI_MAP(int id)
{
return id == 137;
}
static bool IS_MAP_MARKABLE(int mapID)
{
return MAJOR_MAP == mapID || GOOD_EVIL_MAP(mapID) || GUILD_WAR_MAP(mapID) || PENGLAI_MAP(mapID);
}
public override void Awake()
{
base.Awake();
_closeButton.onClick.AddListener(OnCloseButtonClicked);
}
#region Override
public override void Show(bool value)
{
base.Show(value);
if (value)
{
UpdateHostPlayerPositionImage();
}
}
public override void CloseDialogue()
{
base.CloseDialogue();
// hide all the trans points
foreach(var transPoint in _transPoints)
{
transPoint.Value.gameObject.SetActive(false);
}
// clear the waypoint images
foreach(var waypointImage in _waypointImages)
{
waypointImage.gameObject.SetActive(false);
}
}
public override bool Render()
{
UpdateHostPlayerPositionImage();
return base.Render();
}
#endregion
#region Rendering Functions
Vector3 _hostPlayerPosition;
Quaternion _hostPlayerRotation;
private void UpdateHostPlayerPositionImage()
{
if (_hostPlayerPositionImage == null)
{
return;
}
if (!TryGetHostPlayerPosition(out _hostPlayerPosition, out _hostPlayerRotation))
{
_hostPlayerPositionImage.enabled = false;
return;
}
if (Mathf.Approximately(_positionFactor, 0f))
{
BMLogger.LogError("DlgWorldMap _positionFactor cannot be zero.");
_hostPlayerPositionImage.enabled = false;
return;
}
_hostPlayerPositionImage.enabled = true;
RectTransform hostPlayerRectTransform = _hostPlayerPositionImage.rectTransform;
hostPlayerRectTransform.anchoredPosition = new Vector2(
_hostPlayerPosition.x / _positionFactor,
_hostPlayerPosition.z / _positionFactor);
hostPlayerRectTransform.localRotation = Quaternion.Euler(0, 0, -_hostPlayerRotation.eulerAngles.y);
}
/// <summary>
/// If use use Transmit Scroll or Transmit Service, we have to show the transmit points on the map.
/// </summary>
private void ShowTranPoints()
{
CECGameUIMan pGameUI = CECUIManager.Instance.GetInGameUIMan();
var transPoints = pGameUI.GetMapDlgsMgr().m_transPoints;
WorldMapTransPoint transPointObject = null;
int currentMapId = (int)GetDataPtr("WorldID");
foreach(var transPointPair in transPoints)
{
// Only show the trans points for the current map.
if (transPointPair.Value.worldid != currentMapId) continue;
// check if the trans point is already created. If not, create it.
if(_transPoints.TryGetValue(transPointPair.Key, out transPointObject))
{
// now enable the trans point object
transPointObject.gameObject.SetActive(true);
}
else
{
// create the trans point object
transPointObject = Instantiate(_transPointButtonPrefab, _transPointButtonParent);
transPointObject.Init(this, transPointPair.Key);
transPointObject.GetComponent<RectTransform>().anchoredPosition = new Vector2(transPointPair.Value.vecPos.x / _positionFactor, transPointPair.Value.vecPos.z / _positionFactor);
_transPoints[transPointPair.Key] = transPointObject;
transPointObject.gameObject.SetActive(true);
}
}
}
private void ShowTransWays()
{
}
private bool TryGetHostPlayerPosition(out Vector3 hostPlayerPosition, out Quaternion hostPlayerRotation)
{
hostPlayerPosition = Vector3.zero;
hostPlayerRotation = Quaternion.identity;
CECHostPlayer hostPlayer = GetHostPlayer();
if (hostPlayer == null || hostPlayer.transform == null)
{
return false;
}
hostPlayerPosition = hostPlayer.transform.position;
hostPlayerRotation = hostPlayer.transform.rotation;
return true;
}
public void BuildTravelMap(uint dwType, object pData)
{
// default world id
int worldid = MAJOR_MAP;
// select the correct map background
// PAUIIMAGEPICTURE pImage = (PAUIIMAGEPICTURE)GetDlgItem("WorldMapTravel");
// prepare the necessary information
// This set the type of the map to show (DT_NPC_TRANSMIT_SERVICE or DT_TRANSMITSCROLL_ESSENCE)
SetData(dwType);
// CECMapDlgsMgr *pMgr = GetGameUIMan()->GetMapDlgsMgr();
// ÖØÐ¿ªÊ¼¼ÆËã´«ËÍÏß·
// pMgr->ResetTransWay();
if(dwType == (uint)DATA_TYPE.DT_NPC_TRANSMIT_SERVICE)
{
var serviceData = (NPC_TRANSMIT_SERVICE)pData;
var worldInstanceName = UnityGameSession.Instance.GetWorldInstanceName((int)serviceData.id);
// save the worldid so the ShowTranPoints() function know which map to show.
//TODO: We have to get the worldid from the service data.
worldid = 161;//(int)serviceData.worldid;
SetDataPtr(worldid, "WorldID");
ShowTranPoints();
DrawWayPoints(GetGameUIMan().m_pCurNPCEssence, worldid, true);
}
else if(dwType == (uint)DATA_TYPE.DT_TRANSMITSCROLL_ESSENCE)
{
// save the slot info
// SetDataPtr(pData, "ItemSlot");
// pMgr->LoadMapTexture(m_pA3DDevice, pImage, CECMapDlgsMgr::MAP_TYPE_SCROLL);
}
else
{
// invalid transmit type
BMLogger.LogError($"Invalid transmit type: {dwType}");
}
}
// This function onriginally is in the CECMapDlgsMgr class.
// However I moved it here since we need to draw the waypoints on Unity Canvas.
/// <summary>Draw the waypoints from the current NPC Position to all the possible Transmit targets.</summary>
public void DrawWayPoints(NPC_ESSENCE? pNPC, int iWorldID, bool bDrawLines)
{
if (!pNPC.HasValue && bDrawLines) return; // only draw lines if the NPC is not null and bDrawLines is true.
DATA_TYPE dataType = DATA_TYPE.DT_INVALID;
int idCur = (int)pNPC.Value.id_to_discover;
var dataPtr = ElementDataManProvider.GetElementDataMan().get_data_ptr(pNPC.Value.id_transmit_service, ID_SPACE.ID_SPACE_ESSENCE, ref dataType);
if (dataType == DATA_TYPE.DT_NPC_TRANSMIT_SERVICE)
{
var serviceData = (NPC_TRANSMIT_SERVICE)dataPtr;
// start point is current location of the player or NPC
Vector3 startPoint = Vector3.zero;
bool hasHostPlayerPosition = TryGetHostPlayerPosition(out startPoint, out var startRotation);
CECGameUIMan pGameUI = CECUIManager.Instance.GetInGameUIMan();
var transPoints = pGameUI.GetMapDlgsMgr().m_transPoints;
if (transPoints.TryGetValue(idCur, out var transPoint))
{
startPoint = new Vector3(transPoint.vecPos.x, transPoint.vecPos.y, transPoint.vecPos.z);
}
int targetNum = GetTransmitTargetsNum(serviceData);
TRANS_POINT traget;
Vector2 anchoredTargetPosition = Vector2.zero;
Image waypointImage = null;
for (int i = 0; i < targetNum; i++)
{
if (transPoints.TryGetValue(serviceData.targets[i].idTarget, out traget))
{
// instantiate the waypoint image
if (i < _waypointImages.Count)
{
waypointImage = _waypointImages[i];
}
else
{
waypointImage = Instantiate(_trasmitWayImagePrefab, _transPointButtonParent);
_waypointImages.Add(waypointImage);
}
var rectTransform = waypointImage.rectTransform;
rectTransform.anchoredPosition = new Vector2(startPoint.x / _positionFactor, startPoint.z / _positionFactor);
anchoredTargetPosition = new Vector2(traget.vecPos.x / _positionFactor, traget.vecPos.z / _positionFactor);
Vector2 direction = anchoredTargetPosition - rectTransform.anchoredPosition;
float distance = direction.magnitude;
rectTransform.sizeDelta = new Vector2(distance, 2);
float angle = Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg;
rectTransform.localEulerAngles = new Vector3(0, 0, angle);
waypointImage.gameObject.SetActive(true);
}
}
}
}
public static int GetTransmitTargetsNum(NPC_TRANSMIT_SERVICE pService)
{
int num_targets = 0;
num_targets = Mathf.Max(0, pService.num_targets);
num_targets = Mathf.Min(num_targets, pService.targets.Length);
return num_targets;
}
#endregion
#region UI Event Handlers
/// <summary>
/// When user click on the map texture.
/// We will calculate the world coordinates from the local cursor position. Then move the host player to the world coordinates.
/// </summary>
/// <param name="localCursorPosition"></param>
public void OnMapClicked(Vector2 localCursorPosition)
{
var worldCoordinates = localCursorPosition * _positionFactor;
UnityGameSession.c2s_CmdGoto(worldCoordinates.x, 1.0f, worldCoordinates.y);
// close the map
OnCloseButtonClicked();
}
public void OnTransPointClicked(int id)
{
var transPoints = CECUIManager.Instance.GetInGameUIMan().GetMapDlgsMgr().m_transPoints;
if(transPoints.TryGetValue(id, out var transPoint))
{
UnityGameSession.c2s_CmdGoto(transPoint.vecPos.x, transPoint.vecPos.y, transPoint.vecPos.z);
// close the map
OnCloseButtonClicked();
}
}
private void OnCloseButtonClicked()
{
CloseDialogue();
}
#endregion
}
public struct TRANS_POINT
{
public int id;
public int worldid;
public string strName;
public A3DVECTOR3 vecPos;
};
public enum TransMode
{
TM_INVALID = 0,
TM_TRANSMITSCROLL = 1, // 通过传送卷轴传送 / Transmit scroll
TM_NPC_TRANSMIT_NORMAL = 2, // 通过 NPC 传送服务、向当前 NPC 连接点传送 / Transmit service to the current NPC connection point
TM_NPC_TRANSMIT_DIRECT = 3, // 通过 NPC 传送服务、向当前 NPC 可达点直接传送 / Transmit service to the current NPC reachable point directly
};
public class CECMapDlgsMgr
{
public int m_nCurFlagIndex;
public bool m_bMarking;
public bool m_bMapDragging;
public List<TRANS_POINT> m_vecTeamMate = new();
public Dictionary<int, TRANS_POINT> m_transPoints = new();
// update player way-points
public void UpdateWayPoints(ushort[] pData, uint iSize, bool bClear)
{
var vecTarget = GlobalTransmitData.globaldata_gettranstargets;
if(bClear)
{
m_transPoints.Clear();
}
// got valid points.
for(int i = 0; i < iSize; i++ )
{
int idThis = pData[i];//*(pData+i);
for(int j = 0; j < vecTarget.Count; j++ )
{
if( idThis != vecTarget[j].id ) continue;
TRANS_POINT tp;
tp.id = idThis;
tp.strName = vecTarget[j].Name;
tp.vecPos = vecTarget[j].vecPos;
tp.worldid = vecTarget[j].world_id;
m_transPoints[idThis] = tp;
break;
}
}
}
}
public class TransWay
{
public const int WAYPOINT_ME = 0;
public const int WAYPOINT_TARGET = 1;
public const int MINIMAP_UL = 0;
public const int MINIMAP_UR = 1;
public const int MINIMAP_LL = 2;
public const int MINIMAP_LR = 3;
public const int MINIMAP_MAX = 4;
// The transmission mode to use when sending the transmission protocol (TM_NPC_TRANSMIT_NORMAL =2 and the number of wayPoints is greater than 1 may be true at the same time)
public TransMode mode; // 发送传送协议时应使用的传送模式(TM_NPC_TRANSMIT_NORMAL =2 与 wayPoints 个数大于1可能同时成立)
public int nCost; // 需要的完美币 / The required perfect coin
public int nLevel; // 需求的等级 / The required level
// The transmission route (excluding the start point and including the end point) (can be used for display in all modes, can only be used for protocol in TM_NPC_TRANSMIT_DIRECT mode)
public List<TRANS_POINT> wayPoints = new(); // 传送路线(不含起点、包括终点)(各模式下均可用于显示,TM_NPC_TRANSMIT_DIRECT 模式下才可用于协议)
}
}