Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions Client/mods/deathmatch/logic/CClientGame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -551,6 +551,12 @@ CClientGame::~CClientGame()
discord->UpdatePresence();
}

if (m_pPlayerMap)
{
m_pPlayerMap->ResetCustomMapImage();
m_pPlayerMap->ResetMapOpacity();
}

// Destroy our stuff
SAFE_DELETE(m_pManager); // Will trigger onClientResourceStop

Expand Down
219 changes: 214 additions & 5 deletions Client/mods/deathmatch/logic/CPlayerMap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "StdInc.h"

using SharedUtil::CalcMTASAPath;
using SharedUtil::FileExists;
using std::list;

enum
Expand Down Expand Up @@ -61,6 +62,12 @@ CPlayerMap::CPlayerMap(CClientManager* pManager)
m_mapImageTexture = nullptr;
m_playerMarkerTexture = nullptr;

// Custom map image variables
m_ucCustomMapOpacity = 255;
m_bHasCustomMapOpacity = false;
m_pCustomOpacityResource = nullptr;
m_pRadarMapDisabledResource = nullptr;

// Create all map textures
CreateAllTextures();

Expand Down Expand Up @@ -109,6 +116,20 @@ CPlayerMap::~CPlayerMap()
// Delete our images
SAFE_RELEASE(m_mapImageTexture);
SAFE_RELEASE(m_playerMarkerTexture);

// Release custom map textures
for (int i = 0; i < 2; i++)
{
if (m_customMapData[i].bHasCustomMap && m_customMapData[i].pTexture && !m_customMapData[i].pTextureElement)
{
SAFE_RELEASE(m_customMapData[i].pTexture);
}
m_customMapData[i].pTexture = nullptr;
m_customMapData[i].pTextureElement = nullptr;
m_customMapData[i].pResource = nullptr;
m_customMapData[i].bHasCustomMap = false;
}

for (uint i = 0; i < m_markerTextureList.size(); i++)
SAFE_RELEASE(m_markerTextureList[i]);
m_markerTextureList.clear();
Expand All @@ -118,7 +139,7 @@ CPlayerMap::~CPlayerMap()
void CPlayerMap::CreateOrUpdateMapTexture()
{
const std::uint32_t mapSize = MAP_IMAGE_SIZES[m_playerMapImageIndex];
const SString fileName("MTA\\cgui\\images\\map_%d.png", mapSize);
const SString fileName("MTA\\cgui\\images\\radar\\map_%d.png", mapSize);

auto* newTexture = g_pCore->GetGraphics()->GetRenderItemManager()->CreateTexture(CalcMTASAPath(fileName), nullptr, false, mapSize, mapSize, RFORMAT_DXT1);
if (!newTexture)
Expand Down Expand Up @@ -156,13 +177,17 @@ void CPlayerMap::CreateAllTextures()
{
// Create the map texture
m_playerMapImageIndex = g_pCore->GetCVars()->GetValue<std::size_t>("mapimage");
m_defaultMapImageIndex = m_playerMapImageIndex;
CreateOrUpdateMapTexture();

// Create the player blip texture
CreatePlayerBlipTexture();

// Create the other marker textures
CreateMarkerTextures();

// Try to load a user custom map if it exists
LoadUserCustomMapIfExists();
}
catch (const std::exception& e)
{
Expand Down Expand Up @@ -292,20 +317,43 @@ void CPlayerMap::DoRender()
// Render if showing and textures are all loaded
if (isMapShowing && !m_failedToLoadTextures)
{
// Check if the current size texture element is still valid
std::size_t currentIdx = m_playerMapImageIndex;
if (m_customMapData[currentIdx].bHasCustomMap && m_customMapData[currentIdx].pTextureElement)
{
if (m_customMapData[currentIdx].pTextureElement->IsBeingDeleted())
{
// Delete the texture, reset
m_customMapData[currentIdx].pTexture = nullptr;
m_customMapData[currentIdx].bHasCustomMap = false;
m_customMapData[currentIdx].strPath = "";
m_customMapData[currentIdx].pResource = nullptr;
m_customMapData[currentIdx].pTextureElement = nullptr;

// Try to load a user custom map if it exists
LoadUserCustomMapIfExists();
}
}

// Get the alpha value from the settings
int mapAlpha;
g_pCore->GetCVars()->Get("mapalpha", mapAlpha);
uchar mapAlpha = GetMapOpacity();
const SColorARGB mapColor(mapAlpha, 255, 255, 255);

// Update the image if the user changed it via a setting
auto mapImageIndex = g_pCore->GetCVars()->GetValue<std::size_t>("mapimage");
if (mapImageIndex != m_playerMapImageIndex)
{
UpdateOrRevertMapTexture(mapImageIndex);
if (!m_customMapData[m_playerMapImageIndex].bHasCustomMap)
LoadUserCustomMapIfExists();
}

g_pCore->GetGraphics()->DrawTexture(m_mapImageTexture, static_cast<float>(m_iMapMinX), static_cast<float>(m_iMapMinY),
m_fMapSize / m_mapImageTexture->m_uiSizeX, m_fMapSize / m_mapImageTexture->m_uiSizeY, 0.0f, 0.0f, 0.0f, mapColor);
CTextureItem* pMapTexture = m_customMapData[m_playerMapImageIndex].bHasCustomMap
? m_customMapData[m_playerMapImageIndex].pTexture
: m_mapImageTexture;

g_pCore->GetGraphics()->DrawTexture(pMapTexture, static_cast<float>(m_iMapMinX), static_cast<float>(m_iMapMinY),
m_fMapSize / pMapTexture->m_uiSizeX, m_fMapSize / pMapTexture->m_uiSizeY, 0.0f, 0.0f, 0.0f, mapColor);

// Grab the info for the local player blip
CVector2D vecLocalPos;
Expand Down Expand Up @@ -752,3 +800,164 @@ SString CPlayerMap::GetBoundKeyName(const SString& strCommand)
return strCommand;
return pCommandBind->boundKey->szKey;
}
bool CPlayerMap::SetCustomMapImage(const std::string& strTexturePath, ECustomMapResolution resolution, CResource* pResource)
{
if (!pResource)
return false;

std::size_t idx = MapResolutionToIndex(resolution);
std::uint32_t uiSize = MapResolutionToSize(resolution);
SString strFullPath = pResource->GetResourceDirectoryPath() + strTexturePath;

CTextureItem* pNewTexture = g_pCore->GetGraphics()->GetRenderItemManager()->CreateTexture(strFullPath, nullptr, false, uiSize, uiSize, RFORMAT_DXT1);

if (!pNewTexture)
throw std::invalid_argument("Failed to load texture from path: " + strTexturePath);

// Release old texture if it existed and was not element-based
if (!m_customMapData[idx].pTextureElement && m_customMapData[idx].pTexture)
{
SAFE_RELEASE(m_customMapData[idx].pTexture);
m_customMapData[idx].pTexture = nullptr;
}

m_customMapData[idx].pTexture = pNewTexture;
m_customMapData[idx].strPath = strFullPath;
m_customMapData[idx].bHasCustomMap = true;
m_customMapData[idx].pResource = pResource;
m_customMapData[idx].pTextureElement = nullptr;

return true;
}

bool CPlayerMap::SetCustomMapImageFromTexture(CClientTexture* pTexture, ECustomMapResolution resolution, CResource* pResource)
{
if (!pTexture || !pResource)
return false;

CTextureItem* pTextureItem = pTexture->GetTextureItem();
if (!pTextureItem)
throw std::invalid_argument("Invalid texture element");

std::size_t idx = MapResolutionToIndex(resolution);

m_customMapData[idx].pTexture = pTextureItem;
m_customMapData[idx].strPath = "";
m_customMapData[idx].bHasCustomMap = true;
m_customMapData[idx].pResource = pResource;
m_customMapData[idx].pTextureElement = pTexture;

return true;
}

void CPlayerMap::ResetCustomMapImage(std::optional<ECustomMapResolution> resolution)
{
// If resolution is not provided, reset both sizes
if (!resolution.has_value())
{
ResetCustomMapImage(ECustomMapResolution::Res_1024);
ResetCustomMapImage(ECustomMapResolution::Res_2048);
return;
}

std::size_t idx = MapResolutionToIndex(resolution.value());

if (!m_customMapData[idx].pTextureElement && m_customMapData[idx].pTexture)
{
SAFE_RELEASE(m_customMapData[idx].pTexture);
m_customMapData[idx].pTexture = nullptr;
}

m_customMapData[idx].bHasCustomMap = false;
m_customMapData[idx].strPath = "";
m_customMapData[idx].pResource = nullptr;
m_customMapData[idx].pTextureElement = nullptr;

// Try to load the user custom map if it exists
if (idx == m_playerMapImageIndex)
LoadUserCustomMapIfExists();
}

bool CPlayerMap::SetMapOpacity(uchar ucOpacity, CResource* pResource)
{
m_ucCustomMapOpacity = static_cast<uchar>(Clamp(0, static_cast<int>(ucOpacity), 255));
m_bHasCustomMapOpacity = true;
m_pCustomOpacityResource = pResource;
return true;
}

void CPlayerMap::ResetMapOpacity()
{
m_bHasCustomMapOpacity = false;
m_ucCustomMapOpacity = 255;
m_pCustomOpacityResource = nullptr;
}

uchar CPlayerMap::GetMapOpacity() const
{
if (m_bHasCustomMapOpacity)
return m_ucCustomMapOpacity;

int mapAlpha;
g_pCore->GetCVars()->Get("mapalpha", mapAlpha);
return static_cast<uchar>(Clamp(0, mapAlpha, 255));
}

void CPlayerMap::LoadUserCustomMapIfExists()
{
std::size_t idx = m_playerMapImageIndex;

// If already has a script-set custom map for this size, do not override
if (m_customMapData[idx].bHasCustomMap && m_customMapData[idx].pResource != nullptr)
return;

const std::uint32_t mapSize = MAP_IMAGE_SIZES[idx];
const SString customFileName = CalcMTASAPath(SString("MTA\\cgui\\images\\radar\\map_%d-custom.png", mapSize));

if (FileExists(customFileName))
{
CTextureItem* pCustomTexture = g_pCore->GetGraphics()->GetRenderItemManager()->CreateTexture(customFileName, nullptr, false, mapSize, mapSize, RFORMAT_DXT1);

if (pCustomTexture)
{
// Release old texture if it existed and was not element-based
if (!m_customMapData[idx].pTextureElement && m_customMapData[idx].pTexture)
SAFE_RELEASE(m_customMapData[idx].pTexture);

m_customMapData[idx].pTexture = pCustomTexture;
m_customMapData[idx].strPath = customFileName;
m_customMapData[idx].bHasCustomMap = true;
m_customMapData[idx].pResource = nullptr;
m_customMapData[idx].pTextureElement = nullptr;
}
}
}

void CPlayerMap::OnResourceStopping(CResource* pResource)
{
// Check both size custom maps
for (int i = 0; i < 2; i++)
{
if (m_customMapData[i].bHasCustomMap && m_customMapData[i].pResource == pResource)
{
if (!m_customMapData[i].pTextureElement && m_customMapData[i].pTexture)
SAFE_RELEASE(m_customMapData[i].pTexture);

m_customMapData[i].pTexture = nullptr;
m_customMapData[i].pTextureElement = nullptr;
m_customMapData[i].bHasCustomMap = false;
m_customMapData[i].strPath = "";
m_customMapData[i].pResource = nullptr;
}
}

// If the current map size had a custom map, try to load the user custom map
LoadUserCustomMapIfExists();

if (m_bHasCustomMapOpacity && m_pCustomOpacityResource == pResource)
{
m_bHasCustomMapOpacity = false;
m_ucCustomMapOpacity = 255;
m_pCustomOpacityResource = nullptr;
}
}
58 changes: 58 additions & 0 deletions Client/mods/deathmatch/logic/CPlayerMap.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,38 @@
#include <CClientTextDisplay.h>
#include <gui/CGUI.h>

class CResource;
class CClientTexture;

enum class ECustomMapResolution : std::uint32_t
{
Res_1024 = 1024,
Res_2048 = 2048
};

inline std::size_t MapResolutionToIndex(ECustomMapResolution resolution)
{
return resolution == ECustomMapResolution::Res_1024 ? 0 : 1;
}

inline std::uint32_t MapResolutionToSize(ECustomMapResolution resolution)
{
return static_cast<std::uint32_t>(resolution);
}

inline std::optional<ECustomMapResolution> UIntToMapResolution(std::uint32_t value)
{
switch (value)
{
case static_cast<std::uint32_t>(ECustomMapResolution::Res_1024):
return ECustomMapResolution::Res_1024;
case static_cast<std::uint32_t>(ECustomMapResolution::Res_2048):
return ECustomMapResolution::Res_2048;
default:
return std::nullopt;
}
}

class CPlayerMap
{
public:
Expand All @@ -37,6 +69,17 @@ class CPlayerMap

void ToggleHelpText();

bool SetCustomMapImage(const std::string& strTexturePath, ECustomMapResolution resolution, CResource* pResource = nullptr);
bool SetCustomMapImageFromTexture(CClientTexture* pTexture, ECustomMapResolution resolution, CResource* pResource = nullptr);
void ResetCustomMapImage(std::optional<ECustomMapResolution> resolution = std::nullopt);
bool SetMapOpacity(uchar ucOpacity, CResource* pResource = nullptr);
void ResetMapOpacity();
uchar GetMapOpacity() const;
bool HasCustomMapImage(ECustomMapResolution resolution) const {
return m_customMapData[MapResolutionToIndex(resolution)].bHasCustomMap;
}
void OnResourceStopping(CResource* pResource);

protected:
void InternalSetPlayerMapEnabled(bool bEnabled);

Expand All @@ -46,6 +89,7 @@ class CPlayerMap
void CreateOrUpdateMapTexture();
void UpdateOrRevertMapTexture(std::size_t imageIndex);
void CreateAllTextures();
void LoadUserCustomMapIfExists();

public:
bool IsAttachedToLocalPlayer() const { return m_bIsAttachedToLocal; };
Expand Down Expand Up @@ -125,4 +169,18 @@ class CPlayerMap
bool m_bRadarVisible;
bool m_bDebugVisible;
bool m_bTextVisible;
struct CustomMapData
{
bool bHasCustomMap = false;
CTextureItem* pTexture = nullptr;
std::string strPath = "";
CClientTexture* pTextureElement = nullptr;
CResource* pResource = nullptr;
};
CustomMapData m_customMapData[2]; // [0] = 1024, [1] = 2048
std::size_t m_defaultMapImageIndex;
uchar m_ucCustomMapOpacity;
bool m_bHasCustomMapOpacity;
CResource* m_pCustomOpacityResource;
CResource* m_pRadarMapDisabledResource;
};
8 changes: 8 additions & 0 deletions Client/mods/deathmatch/logic/CResource.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,14 @@ void CResource::Stop()
{
m_bStarting = false;
m_bStopping = true;

if (g_pClientGame)
{
CPlayerMap* pPlayerMap = g_pClientGame->GetPlayerMap();
if (pPlayerMap)
pPlayerMap->OnResourceStopping(this);
}

CLuaArguments Arguments;
Arguments.PushResource(this);
m_pResourceEntity->CallEvent("onClientResourceStop", Arguments, true);
Expand Down
Loading