using System.Collections.Generic; using BrewMonster; using BrewMonster.Scripts; using BrewMonster.Scripts.Extensions; using CSNetwork.GPDataType; using TMPro; using UnityEngine; using UnityEngine.U2D; using UnityEngine.UI; namespace PerfectWorld.UI.MiniMap { public class MiniMapUI : MonoBehaviour { public struct MARK { public int nNPC; public string strName; public A3DVECTOR3 vecPos; int mapID; public MARK(int nNPC, string strName, A3DVECTOR3 vecPos, int mapID) { this.nNPC = nNPC; this.strName = strName; this.vecPos = vecPos; this.mapID = mapID; } } public struct MAPTLVERTEX { public float x, y, z, rhw; public uint diffuse; public uint specular; public float tu, tv, tu2, tv2; } // constants private const int MINIMAP_UL = 0; private const int MINIMAP_UR = 1; private const int MINIMAP_LL = 2; private const int MINIMAP_LR = 3; private const int MINIMAP_MAX = 4; [SerializeField] private RectTransform _hostPlayerIcon; [SerializeField] private Texture2D m_pA3DRadarBack; [SerializeField] private Texture2D m_TexRadarBack; [SerializeField] private byte nRow, nCol; // number of rows and cols in the current map instances.txt [SerializeField] private string strSubPath; // path to the minimap textures folder "surfaces/minimaps/a61/{0}" [SerializeField] private RectTransform pObjMiniMap; [SerializeField] private TMP_Text txtHostPos; [SerializeField] private Texture2D[] m_TexMapParts = new Texture2D[MINIMAP_MAX]; [SerializeField] private Sprite[] m_SpriteMapParts = new Sprite[MINIMAP_MAX]; // reference to unity sprite atlas [SerializeField] private SpriteAtlas _spriteAtlas; private List m_vecMark = new(); private List m_vecNPCMark = new(); private Dictionary m_TexMap = new(); private List _texToDelete = new(); // list of texture to delete from m_TexMap, use in update functions. private float m_fZoom = 1.0f; private bool m_bShowMark = true; private bool m_bShowTargetArrow = true; private MAPTLVERTEX[][] m_vertexMiniMap = new MAPTLVERTEX[MINIMAP_MAX][]; // map state private bool isShowMiniMap = true; CECHostPlayer m_pHostPlayer; private void Awake() { // initialize m_vertexMiniMap for(int i = 0; i < MINIMAP_MAX; i++) { m_vertexMiniMap[i] = new MAPTLVERTEX[4]; } } void Update() { UpdateMiniMap(); } private void UpdateMiniMap() { // m_pHostPlayer = GetHostPlayer(); // if (m_pHostPlayer == null) return; // TODO: This should be the position of the host player, not hardcoded. Vector3 vecPosHost = new Vector3(-259.4484f, 52.00275f, -17.2688f);//m_pHostPlayer.transform.position; txtHostPos.text = $"{Mathf.RoundToInt(vecPosHost.x) / 10 + 400}, {Mathf.RoundToInt(vecPosHost.z)}"; float fRatio = 512.0f / 1024.0f / m_fZoom; float fNormal = fRatio; if( m_fZoom < 1.0f ) fNormal = fRatio * m_fZoom; vecPosHost.x = Mathf.Floor(vecPosHost.x * fNormal) / fNormal; vecPosHost.z = Mathf.Floor(vecPosHost.z * fNormal) / fNormal; // TODO: This should be the size of the minimap texture, not hardcoded. Rect rcMiniMap = new Rect(0, 0, 256, 256);//pObjMiniMap.rect; //ASSERT(rcMiniMap.Width() == rcMiniMap.Height()); int W = (int)rcMiniMap.width; int H = (int)rcMiniMap.height; Vector2 C = rcMiniMap.center; Vector2Int ptHost = new Vector2Int(); Vector2Int idxHost = new Vector2Int(); Vector2Int ptThisCenter = new Vector2Int(); Vector2Int[] idxCorner = new Vector2Int[MINIMAP_MAX]; RectInt rcHost = new RectInt(); RectInt rcThis = new RectInt(); RectInt[] rcCell = new RectInt[MINIMAP_MAX]; RectInt[] rcInter = new RectInt[MINIMAP_MAX]; int nSide = 256; float fCell = 1024.0f; float fSide = nSide; float fOffsetX = nCol * fCell / 2.0f; float fOffsetY = nRow * fCell / 2.0f; ptHost.x = Mathf.FloorToInt((vecPosHost.x + fOffsetX) * 512.0f / 1024.0f); ptHost.y = Mathf.FloorToInt((fOffsetY - vecPosHost.z) * 512.0f / 1024.0f); idxHost.x = ptHost.x / nSide; idxHost.y = ptHost.y / nSide; rcThis.x = idxHost.x * nSide; rcThis.y = idxHost.y * nSide; rcThis.width = nSide; rcThis.height = nSide; ptThisCenter = rcThis.Center(); if( ptHost.y <= ptThisCenter.y ) { if( ptHost.x <= ptThisCenter.x ) // Upper left. { idxCorner[MINIMAP_UL].x = idxHost.x - 1; idxCorner[MINIMAP_UL].y = idxHost.y - 1; idxCorner[MINIMAP_UR].x = idxHost.x; idxCorner[MINIMAP_UR].y = idxHost.y - 1; idxCorner[MINIMAP_LL].x = idxHost.x - 1; idxCorner[MINIMAP_LL].y = idxHost.y; idxCorner[MINIMAP_LR].x = idxHost.x; idxCorner[MINIMAP_LR].y = idxHost.y; } else // Upper right. { idxCorner[MINIMAP_UL].x = idxHost.x; idxCorner[MINIMAP_UL].y = idxHost.y - 1; idxCorner[MINIMAP_UR].x = idxHost.x + 1; idxCorner[MINIMAP_UR].y = idxHost.y - 1; idxCorner[MINIMAP_LL].x = idxHost.x; idxCorner[MINIMAP_LL].y = idxHost.y; idxCorner[MINIMAP_LR].x = idxHost.x + 1; idxCorner[MINIMAP_LR].y = idxHost.y; } } else { if( ptHost.x <= ptThisCenter.x ) // Lower left. { idxCorner[MINIMAP_UL].x = idxHost.x - 1; idxCorner[MINIMAP_UL].y = idxHost.y; idxCorner[MINIMAP_UR].x = idxHost.x; idxCorner[MINIMAP_UR].y = idxHost.y; idxCorner[MINIMAP_LL].x = idxHost.x - 1; idxCorner[MINIMAP_LL].y = idxHost.y + 1; idxCorner[MINIMAP_LR].x = idxHost.x; idxCorner[MINIMAP_LR].y = idxHost.y + 1; } else // Lower right. { idxCorner[MINIMAP_UL].x = idxHost.x; idxCorner[MINIMAP_UL].y = idxHost.y; idxCorner[MINIMAP_UR].x = idxHost.x + 1; idxCorner[MINIMAP_UR].y = idxHost.y; idxCorner[MINIMAP_LL].x = idxHost.x; idxCorner[MINIMAP_LL].y = idxHost.y + 1; idxCorner[MINIMAP_LR].x = idxHost.x + 1; idxCorner[MINIMAP_LR].y = idxHost.y + 1; } } // rcHost.left = ptHost.x - int(W * m_fZoom) / 2; // rcHost.top = ptHost.y - int(H * m_fZoom) / 2; // rcHost.right = ptHost.x + int(W * m_fZoom) / 2; // rcHost.bottom = ptHost.y + int(H * m_fZoom) / 2; rcHost.xMin = ptHost.x - Mathf.FloorToInt(W * m_fZoom) / 2; rcHost.yMax = ptHost.y - Mathf.FloorToInt(H * m_fZoom) / 2; rcHost.xMax = ptHost.x + Mathf.FloorToInt(W * m_fZoom) / 2; rcHost.yMin = ptHost.y + Mathf.FloorToInt(H * m_fZoom) / 2; rcHost.width = Mathf.FloorToInt(W * m_fZoom); rcHost.height = Mathf.FloorToInt(H * m_fZoom); _hostPlayerIcon.anchoredPosition = new Vector2(rcHost.x / 10, rcHost.y / 10); int i, j; bool bval; //*/ string strIndex = string.Empty; bool bLoadNewMap = false; Texture2D pA3DTex = m_TexRadarBack; Sprite pSprite = null; for( i = MINIMAP_UL; i < MINIMAP_MAX; i++ ) { rcCell[i].xMin = idxCorner[i].x * nSide; rcCell[i].yMax = idxCorner[i].y * nSide; rcCell[i].xMax = rcCell[i].xMax + nSide; rcCell[i].yMin = rcCell[i].yMax + nSide; // rcCell[i].xMin = idxCorner[i].x * nSide; // rcCell[i].yMin = idxCorner[i].y * nSide; // rcCell[i].xMax = rcCell[i].xMin + nSide; // rcCell[i].yMax = rcCell[i].yMin + nSide; rcCell[i].width = nSide; rcCell[i].height = nSide; rcInter[i] = rcCell[i].Intersect(rcHost); if( rcInter[i].width == 0 && rcInter[i].height == 0 ) rcInter[i].Offset(rcCell[i].x, rcCell[i].y); strIndex = $"{idxCorner[i].y:D2}{idxCorner[i].x:D2}"; if(!m_TexMap.ContainsKey(strIndex)) { if( idxCorner[i].x >= 0 && idxCorner[i].x < nCol * 2 && idxCorner[i].y >= 0 && idxCorner[i].y < nRow * 2 ) { string strFile; // if(GetWorld()->IsRandomMap()) // { // strFile = "temp\\Surfaces\\MiniMaps\\" + GetGameRun()->GetRandomMapProc()->GetMapName() + "\\" + strIndex + ".dds"; // pA3DTex->SetNoDownSample(true); // unsigned char* pData = NULL; // int iLen = 0; // if(GetGameRun()->GetRandomMapProc()->EncodeMap(strFile,pData,iLen)) // { // bool bval = pA3DTex->LoadFromMemory(m_pA3DDevice,pData,iLen,256,256,A3DFMT_UNKNOWN); // ASSERT(bval); // delete [] pData; // } // } // else // { strFile = string.Format(strSubPath, strIndex); //"Surfaces\\MiniMaps\\" + strSubPath + "\\" + strIndex + ".dds"; pA3DTex = Resources.Load(strFile); pSprite = _spriteAtlas.GetSprite(strIndex); // } } m_TexMap[strIndex] = pA3DTex; m_TexMapParts[i] = pA3DTex; bLoadNewMap = true; } } //*/ if( bLoadNewMap ) { bool bNoUse; foreach(var it in m_TexMap) { if(it.Value == m_pA3DRadarBack) { continue; } bNoUse = true; for( i = MINIMAP_UL; i < MINIMAP_MAX; i++ ) { strIndex = $"{idxCorner[i].y:D2}{idxCorner[i].x:D2}"; if( strIndex == it.Key ) { bNoUse = false; break; } } if( bNoUse ) { _texToDelete.Add(it.Key); } } } // delete textures from m_TexMap if needed foreach(var tex in _texToDelete) { m_TexMap.Remove(tex); } _texToDelete.Clear(); m_vertexMiniMap[0][0].x = -W / 2.0f; m_vertexMiniMap[0][0].y = -H / 2.0f; m_vertexMiniMap[0][1].x = -W / 2.0f + rcInter[MINIMAP_UL].width / m_fZoom; m_vertexMiniMap[0][1].y = -H / 2.0f; m_vertexMiniMap[0][2].x = -W / 2.0f; m_vertexMiniMap[0][2].y = -H / 2.0f + rcInter[MINIMAP_UL].height / m_fZoom; m_vertexMiniMap[0][3].x = -W / 2.0f + rcInter[MINIMAP_UL].width / m_fZoom; m_vertexMiniMap[0][3].y = -H / 2.0f + rcInter[MINIMAP_UL].height / m_fZoom; m_vertexMiniMap[1][0].x = +W / 2.0f - rcInter[MINIMAP_UR].width / m_fZoom; m_vertexMiniMap[1][0].y = -H / 2.0f; m_vertexMiniMap[1][1].x = +W / 2.0f; m_vertexMiniMap[1][1].y = -H / 2.0f; m_vertexMiniMap[1][2].x = +W / 2.0f - rcInter[MINIMAP_UR].width / m_fZoom; m_vertexMiniMap[1][2].y = -H / 2.0f + rcInter[MINIMAP_UR].height / m_fZoom; m_vertexMiniMap[1][3].x = +W / 2.0f; m_vertexMiniMap[1][3].y = -H / 2.0f + rcInter[MINIMAP_UR].height / m_fZoom; m_vertexMiniMap[2][0].x = -W / 2.0f; m_vertexMiniMap[2][0].y = +H / 2.0f - rcInter[MINIMAP_LL].height / m_fZoom; m_vertexMiniMap[2][1].x = -W / 2.0f + rcInter[MINIMAP_LL].width / m_fZoom; m_vertexMiniMap[2][1].y = +H / 2.0f - rcInter[MINIMAP_LL].height / m_fZoom; m_vertexMiniMap[2][2].x = -W / 2.0f; m_vertexMiniMap[2][2].y = +H / 2.0f; m_vertexMiniMap[2][3].x = -W / 2.0f + rcInter[MINIMAP_LL].width / m_fZoom; m_vertexMiniMap[2][3].y = +H / 2.0f; m_vertexMiniMap[3][0].x = +W / 2.0f - rcInter[MINIMAP_LR].width / m_fZoom; m_vertexMiniMap[3][0].y = +H / 2.0f - rcInter[MINIMAP_LR].height / m_fZoom; m_vertexMiniMap[3][1].x = +W / 2.0f; m_vertexMiniMap[3][1].y = +H / 2.0f - rcInter[MINIMAP_LR].height / m_fZoom; m_vertexMiniMap[3][2].x = +W / 2.0f - rcInter[MINIMAP_LR].width / m_fZoom; m_vertexMiniMap[3][2].y = +H / 2.0f; m_vertexMiniMap[3][3].x = +W / 2.0f; m_vertexMiniMap[3][3].y = +H / 2.0f; pA3DTex = m_TexRadarBack; ushort[] a_wIndex = new ushort[6] { 0, 1, 2, 2, 1, 3 }; A3DVECTOR3 vecPos = new A3DVECTOR3(0); for (i = 0; i < MINIMAP_MAX; i++) { strIndex = string.Format("{0:D2}{1:D2}", idxCorner[i].y, idxCorner[i].x); pA3DTex = m_TexMap[strIndex]; // m_vertexMiniMap[i][0].tu = float(rcInter[i].left - rcCell[i].left) / fSide; // m_vertexMiniMap[i][0].tv = float(rcInter[i].top - rcCell[i].top) / fSide; // m_vertexMiniMap[i][1].tu = float(rcInter[i].right - rcCell[i].left) / fSide; // m_vertexMiniMap[i][1].tv = float(rcInter[i].top - rcCell[i].top) / fSide; // m_vertexMiniMap[i][2].tu = float(rcInter[i].left - rcCell[i].left) / fSide; // m_vertexMiniMap[i][2].tv = float(rcInter[i].bottom - rcCell[i].top) / fSide; // m_vertexMiniMap[i][3].tu = float(rcInter[i].right - rcCell[i].left) / fSide; // m_vertexMiniMap[i][3].tv = float(rcInter[i].bottom - rcCell[i].top) / fSide; m_vertexMiniMap[i][0].tu = (rcInter[i].xMin - rcCell[i].xMin) / fSide; m_vertexMiniMap[i][0].tv = (rcInter[i].yMax - rcCell[i].yMax) / fSide; m_vertexMiniMap[i][1].tu = (rcInter[i].xMax - rcCell[i].xMin) / fSide; m_vertexMiniMap[i][1].tv = (rcInter[i].yMax - rcCell[i].yMax) / fSide; m_vertexMiniMap[i][2].tu = (rcInter[i].xMin - rcCell[i].xMin) / fSide; m_vertexMiniMap[i][2].tv = (rcInter[i].yMin - rcCell[i].yMax) / fSide; m_vertexMiniMap[i][3].tu = (rcInter[i].xMax - rcCell[i].xMin) / fSide; m_vertexMiniMap[i][3].tv = (rcInter[i].yMin - rcCell[i].yMax) / fSide; for( j = 0; j < 4; j++ ) { m_vertexMiniMap[i][j].tu2 = (m_vertexMiniMap[i][j].x + C.x - rcMiniMap.xMin) / (float)(W); m_vertexMiniMap[i][j].tv2 = (m_vertexMiniMap[i][j].y + C.y - rcMiniMap.yMin) / (float)(H); // if( MODE_A == m_nMode ) // { vecPos.x = m_vertexMiniMap[i][j].x; vecPos.y = m_vertexMiniMap[i][j].y; // vecPos = vecPos * m; // m_vertexMiniMap[i][j].x = vecPos.x + p->X; // m_vertexMiniMap[i][j].y = vecPos.y + p->Y; // } // else // { // m_vertexMiniMap[i][j].x += C.x + p->X; // m_vertexMiniMap[i][j].y += C.y + p->Y; // } m_vertexMiniMap[i][j].x -= 0.5f; m_vertexMiniMap[i][j].y -= 0.5f; } } } private CECHostPlayer GetHostPlayer() { return CECGameRun.Instance.GetHostPlayer(); } [ContextMenu("RenderMiniMapMesh")] public void RenderMiniMapMesh() { for(int i = 0; i < MINIMAP_MAX; i++) { m_vertexMiniMap[i] = new MAPTLVERTEX[4]; } m_TexMap.Clear(); UpdateMiniMap(); return; for(int i = 0; i < MINIMAP_MAX; i++) { var mapPart = new GameObject($"MapPart{i}"); var meshFilter = mapPart.GetComponent(); if (meshFilter == null) { meshFilter = mapPart.AddComponent(); } var meshRenderer = mapPart.GetComponent(); if (meshRenderer == null) { meshRenderer = mapPart.AddComponent(); } var mesh = new Mesh(); mesh.vertices = new Vector3[] { new Vector3(m_vertexMiniMap[i][0].x, m_vertexMiniMap[i][0].y, 0), new Vector3(m_vertexMiniMap[i][1].x, m_vertexMiniMap[i][1].y, 0), new Vector3(m_vertexMiniMap[i][2].x, m_vertexMiniMap[i][2].y, 0), new Vector3(m_vertexMiniMap[i][3].x, m_vertexMiniMap[i][3].y, 0), }; mesh.uv = new Vector2[] { new Vector2(m_vertexMiniMap[i][0].tu, m_vertexMiniMap[i][0].tv), new Vector2(m_vertexMiniMap[i][1].tu, m_vertexMiniMap[i][1].tv), new Vector2(m_vertexMiniMap[i][2].tu, m_vertexMiniMap[i][2].tv), new Vector2(m_vertexMiniMap[i][3].tu, m_vertexMiniMap[i][3].tv), }; mesh.triangles = new int[] { 0, 1, 2, 2, 1, 3 }; meshFilter.mesh = mesh; } } } }