mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-19 22:48:18 +00:00
5933: Inline `Is(GameType)` functions and remove support for legacy 64 player info protocol r=def- a=heinrich5991 ## Checklist - [ ] Tested the change ingame - [ ] Provided screenshots if it is a visual change - [ ] Tested in combination with possibly related configuration options - [ ] Written a unit test (especially base/) or added coverage to integration test - [ ] Considered possible null pointers and out of bounds array indexing - [ ] Changed no physics that affect existing maps - [ ] Tested the change with [ASan+UBSan or valgrind's memcheck](https://github.com/ddnet/ddnet/#using-addresssanitizer--undefinedbehavioursanitizer-or-valgrinds-memcheck) (optional) 5941: Get away from vector for skins r=def- a=Jupeyy most of the time it uses the index just to get the skin, downloaded skins change the index. Now its simply a heap object and downloaded skins load directly. Also the loading might be a bit faster bcs it had a loop lookup .Also O(1) lookup not 100% tested. also fixes a bug with favorite skins hopefully ## Checklist - [x] Tested the change ingame - [ ] Provided screenshots if it is a visual change - [ ] Tested in combination with possibly related configuration options - [ ] Written a unit test (especially base/) or added coverage to integration test - [ ] Considered possible null pointers and out of bounds array indexing - [ ] Changed no physics that affect existing maps - [ ] Tested the change with [ASan+UBSan or valgrind's memcheck](https://github.com/ddnet/ddnet/#using-addresssanitizer--undefinedbehavioursanitizer-or-valgrinds-memcheck) (optional) Co-authored-by: heinrich5991 <heinrich5991@gmail.com> Co-authored-by: Jupeyy <jupjopjap@gmail.com>
This commit is contained in:
commit
6c3d0e999b
|
@ -1345,8 +1345,6 @@ void CClient::ProcessConnlessPacket(CNetChunk *pPacket)
|
||||||
int Type = -1;
|
int Type = -1;
|
||||||
if(mem_comp(pPacket->m_pData, SERVERBROWSE_INFO, sizeof(SERVERBROWSE_INFO)) == 0)
|
if(mem_comp(pPacket->m_pData, SERVERBROWSE_INFO, sizeof(SERVERBROWSE_INFO)) == 0)
|
||||||
Type = SERVERINFO_VANILLA;
|
Type = SERVERINFO_VANILLA;
|
||||||
else if(mem_comp(pPacket->m_pData, SERVERBROWSE_INFO_64_LEGACY, sizeof(SERVERBROWSE_INFO_64_LEGACY)) == 0)
|
|
||||||
Type = SERVERINFO_64_LEGACY;
|
|
||||||
else if(mem_comp(pPacket->m_pData, SERVERBROWSE_INFO_EXTENDED, sizeof(SERVERBROWSE_INFO_EXTENDED)) == 0)
|
else if(mem_comp(pPacket->m_pData, SERVERBROWSE_INFO_EXTENDED, sizeof(SERVERBROWSE_INFO_EXTENDED)) == 0)
|
||||||
Type = SERVERINFO_EXTENDED;
|
Type = SERVERINFO_EXTENDED;
|
||||||
else if(mem_comp(pPacket->m_pData, SERVERBROWSE_INFO_EXTENDED_MORE, sizeof(SERVERBROWSE_INFO_EXTENDED_MORE)) == 0)
|
else if(mem_comp(pPacket->m_pData, SERVERBROWSE_INFO_EXTENDED_MORE, sizeof(SERVERBROWSE_INFO_EXTENDED_MORE)) == 0)
|
||||||
|
@ -1375,8 +1373,7 @@ void CClient::ProcessServerInfo(int RawType, NETADDR *pFrom, const void *pData,
|
||||||
|
|
||||||
CServerInfo Info = {0};
|
CServerInfo Info = {0};
|
||||||
int SavedType = SavedServerInfoType(RawType);
|
int SavedType = SavedServerInfoType(RawType);
|
||||||
if((SavedType == SERVERINFO_64_LEGACY || SavedType == SERVERINFO_EXTENDED) &&
|
if(SavedType == SERVERINFO_EXTENDED && pEntry && pEntry->m_GotInfo && SavedType == pEntry->m_Info.m_Type)
|
||||||
pEntry && pEntry->m_GotInfo && SavedType == pEntry->m_Info.m_Type)
|
|
||||||
{
|
{
|
||||||
Info = pEntry->m_Info;
|
Info = pEntry->m_Info;
|
||||||
}
|
}
|
||||||
|
@ -1391,7 +1388,6 @@ void CClient::ProcessServerInfo(int RawType, NETADDR *pFrom, const void *pData,
|
||||||
#define GET_STRING(array) str_copy(array, Up.GetString(CUnpacker::SANITIZE_CC | CUnpacker::SKIP_START_WHITESPACES), sizeof(array))
|
#define GET_STRING(array) str_copy(array, Up.GetString(CUnpacker::SANITIZE_CC | CUnpacker::SKIP_START_WHITESPACES), sizeof(array))
|
||||||
#define GET_INT(integer) (integer) = str_toint(Up.GetString())
|
#define GET_INT(integer) (integer) = str_toint(Up.GetString())
|
||||||
|
|
||||||
int Offset = 0; // Only used for SavedType == SERVERINFO_64_LEGACY
|
|
||||||
int Token;
|
int Token;
|
||||||
int PacketNo = 0; // Only used if SavedType == SERVERINFO_EXTENDED
|
int PacketNo = 0; // Only used if SavedType == SERVERINFO_EXTENDED
|
||||||
|
|
||||||
|
@ -1449,13 +1445,6 @@ void CClient::ProcessServerInfo(int RawType, NETADDR *pFrom, const void *pData,
|
||||||
dbg_assert(false, "unknown serverinfo type");
|
dbg_assert(false, "unknown serverinfo type");
|
||||||
}
|
}
|
||||||
|
|
||||||
if(SavedType == SERVERINFO_64_LEGACY)
|
|
||||||
Offset = Up.GetInt();
|
|
||||||
|
|
||||||
// Check for valid offset.
|
|
||||||
if(Offset < 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if(SavedType == SERVERINFO_EXTENDED)
|
if(SavedType == SERVERINFO_EXTENDED)
|
||||||
PacketNo = 0;
|
PacketNo = 0;
|
||||||
}
|
}
|
||||||
|
@ -1478,7 +1467,7 @@ void CClient::ProcessServerInfo(int RawType, NETADDR *pFrom, const void *pData,
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IgnoreError = false;
|
bool IgnoreError = false;
|
||||||
for(int i = Offset; i < MAX_CLIENTS && Info.m_NumReceivedClients < MAX_CLIENTS && !Up.Error(); i++)
|
for(int i = 0; i < MAX_CLIENTS && Info.m_NumReceivedClients < MAX_CLIENTS && !Up.Error(); i++)
|
||||||
{
|
{
|
||||||
CServerInfo::CClient *pClient = &Info.m_aClients[Info.m_NumReceivedClients];
|
CServerInfo::CClient *pClient = &Info.m_aClients[Info.m_NumReceivedClients];
|
||||||
GET_STRING(pClient->m_aName);
|
GET_STRING(pClient->m_aName);
|
||||||
|
@ -1572,15 +1561,6 @@ void CClient::ProcessServerInfo(int RawType, NETADDR *pFrom, const void *pData,
|
||||||
#undef GET_INT
|
#undef GET_INT
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CClient::ShouldSendChatTimeoutCodeHeuristic()
|
|
||||||
{
|
|
||||||
if(m_ServerSentCapabilities)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return IsDDNet(&m_CurrentServerInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
static CServerCapabilities GetServerCapabilities(int Version, int Flags)
|
static CServerCapabilities GetServerCapabilities(int Version, int Flags)
|
||||||
{
|
{
|
||||||
CServerCapabilities Result;
|
CServerCapabilities Result;
|
||||||
|
@ -2167,7 +2147,7 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket, int Conn, bool Dummy)
|
||||||
|
|
||||||
if(m_aReceivedSnapshots[Conn] > 50 && !m_aCodeRunAfterJoin[Conn])
|
if(m_aReceivedSnapshots[Conn] > 50 && !m_aCodeRunAfterJoin[Conn])
|
||||||
{
|
{
|
||||||
if(m_ServerCapabilities.m_ChatTimeoutCode || ShouldSendChatTimeoutCodeHeuristic())
|
if(m_ServerCapabilities.m_ChatTimeoutCode)
|
||||||
{
|
{
|
||||||
CNetMsg_Cl_Say MsgP;
|
CNetMsg_Cl_Say MsgP;
|
||||||
MsgP.m_Team = 0;
|
MsgP.m_Team = 0;
|
||||||
|
|
|
@ -251,8 +251,6 @@ class CClient : public IClient, public CDemoPlayer::IListener
|
||||||
bool m_ServerSentCapabilities;
|
bool m_ServerSentCapabilities;
|
||||||
CServerCapabilities m_ServerCapabilities;
|
CServerCapabilities m_ServerCapabilities;
|
||||||
|
|
||||||
bool ShouldSendChatTimeoutCodeHeuristic();
|
|
||||||
|
|
||||||
CServerInfo m_CurrentServerInfo;
|
CServerInfo m_CurrentServerInfo;
|
||||||
int64_t m_CurrentServerInfoRequestTime; // >= 0 should request, == -1 got info
|
int64_t m_CurrentServerInfoRequestTime; // >= 0 should request, == -1 got info
|
||||||
|
|
||||||
|
|
|
@ -720,12 +720,6 @@ void CServerBrowser::OnServerInfoUpdate(const NETADDR &Addr, int Token, const CS
|
||||||
{
|
{
|
||||||
SetInfo(pEntry, *pInfo);
|
SetInfo(pEntry, *pInfo);
|
||||||
pEntry->m_Info.m_Latency = minimum(static_cast<int>((time_get() - m_BroadcastTime) * 1000 / time_freq()), 999);
|
pEntry->m_Info.m_Latency = minimum(static_cast<int>((time_get() - m_BroadcastTime) * 1000 / time_freq()), 999);
|
||||||
if(pInfo->m_Type == SERVERINFO_VANILLA && Is64Player(pInfo))
|
|
||||||
{
|
|
||||||
pEntry->m_Request64Legacy = true;
|
|
||||||
// Force a quick update.
|
|
||||||
RequestImpl64(Addr, pEntry);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if(pEntry->m_RequestTime > 0)
|
else if(pEntry->m_RequestTime > 0)
|
||||||
{
|
{
|
||||||
|
@ -747,16 +741,6 @@ void CServerBrowser::OnServerInfoUpdate(const NETADDR &Addr, int Token, const CS
|
||||||
SetLatency(Addr, Latency);
|
SetLatency(Addr, Latency);
|
||||||
}
|
}
|
||||||
pEntry->m_RequestTime = -1; // Request has been answered
|
pEntry->m_RequestTime = -1; // Request has been answered
|
||||||
|
|
||||||
if(!pEntry->m_RequestIgnoreInfo)
|
|
||||||
{
|
|
||||||
if(pInfo->m_Type == SERVERINFO_VANILLA && Is64Player(pInfo))
|
|
||||||
{
|
|
||||||
pEntry->m_Request64Legacy = true;
|
|
||||||
// Force a quick update.
|
|
||||||
RequestImpl64(Addr, pEntry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
RemoveRequest(pEntry);
|
RemoveRequest(pEntry);
|
||||||
|
|
||||||
|
@ -872,35 +856,6 @@ void CServerBrowser::RequestImpl(const NETADDR &Addr, CServerEntry *pEntry, int
|
||||||
pEntry->m_RequestTime = time_get();
|
pEntry->m_RequestTime = time_get();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CServerBrowser::RequestImpl64(const NETADDR &Addr, CServerEntry *pEntry) const
|
|
||||||
{
|
|
||||||
unsigned char aBuffer[sizeof(SERVERBROWSE_GETINFO_64_LEGACY) + 1];
|
|
||||||
CNetChunk Packet;
|
|
||||||
|
|
||||||
if(g_Config.m_Debug)
|
|
||||||
{
|
|
||||||
char aAddrStr[NETADDR_MAXSTRSIZE];
|
|
||||||
net_addr_str(&Addr, aAddrStr, sizeof(aAddrStr), true);
|
|
||||||
char aBuf[256];
|
|
||||||
str_format(aBuf, sizeof(aBuf), "requesting server info 64 from %s", aAddrStr);
|
|
||||||
m_pConsole->Print(IConsole::OUTPUT_LEVEL_DEBUG, "client_srvbrowse", aBuf);
|
|
||||||
}
|
|
||||||
|
|
||||||
mem_copy(aBuffer, SERVERBROWSE_GETINFO_64_LEGACY, sizeof(SERVERBROWSE_GETINFO_64_LEGACY));
|
|
||||||
aBuffer[sizeof(SERVERBROWSE_GETINFO_64_LEGACY)] = GetBasicToken(GenerateToken(Addr));
|
|
||||||
|
|
||||||
Packet.m_ClientID = -1;
|
|
||||||
Packet.m_Address = Addr;
|
|
||||||
Packet.m_Flags = NETSENDFLAG_CONNLESS;
|
|
||||||
Packet.m_DataSize = sizeof(aBuffer);
|
|
||||||
Packet.m_pData = aBuffer;
|
|
||||||
|
|
||||||
m_pNetClient->Send(&Packet);
|
|
||||||
|
|
||||||
if(pEntry)
|
|
||||||
pEntry->m_RequestTime = time_get();
|
|
||||||
}
|
|
||||||
|
|
||||||
void CServerBrowser::RequestCurrentServer(const NETADDR &Addr) const
|
void CServerBrowser::RequestCurrentServer(const NETADDR &Addr) const
|
||||||
{
|
{
|
||||||
RequestImpl(Addr, nullptr, nullptr, nullptr, false);
|
RequestImpl(Addr, nullptr, nullptr, nullptr, false);
|
||||||
|
@ -1123,9 +1078,6 @@ void CServerBrowser::Update(bool ForceResort)
|
||||||
|
|
||||||
if(pEntry->m_RequestTime == 0)
|
if(pEntry->m_RequestTime == 0)
|
||||||
{
|
{
|
||||||
if(pEntry->m_Request64Legacy)
|
|
||||||
RequestImpl64(pEntry->m_Info.m_aAddresses[0], pEntry);
|
|
||||||
else
|
|
||||||
RequestImpl(pEntry->m_Info.m_aAddresses[0], pEntry, nullptr, nullptr, false);
|
RequestImpl(pEntry->m_Info.m_aAddresses[0], pEntry, nullptr, nullptr, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1563,71 +1515,3 @@ bool CServerInfo::ParseLocation(int *pResult, const char *pString)
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsVanilla(const CServerInfo *pInfo)
|
|
||||||
{
|
|
||||||
return !str_comp(pInfo->m_aGameType, "DM") || !str_comp(pInfo->m_aGameType, "TDM") || !str_comp(pInfo->m_aGameType, "CTF");
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsCatch(const CServerInfo *pInfo)
|
|
||||||
{
|
|
||||||
return str_find_nocase(pInfo->m_aGameType, "catch");
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsInsta(const CServerInfo *pInfo)
|
|
||||||
{
|
|
||||||
return str_find_nocase(pInfo->m_aGameType, "idm") || str_find_nocase(pInfo->m_aGameType, "itdm") || str_find_nocase(pInfo->m_aGameType, "ictf");
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsFNG(const CServerInfo *pInfo)
|
|
||||||
{
|
|
||||||
return str_find_nocase(pInfo->m_aGameType, "fng");
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsRace(const CServerInfo *pInfo)
|
|
||||||
{
|
|
||||||
return str_find_nocase(pInfo->m_aGameType, "race") || str_find_nocase(pInfo->m_aGameType, "fastcap");
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsFastCap(const CServerInfo *pInfo)
|
|
||||||
{
|
|
||||||
return str_find_nocase(pInfo->m_aGameType, "fastcap");
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsBlockInfectionZ(const CServerInfo *pInfo)
|
|
||||||
{
|
|
||||||
return str_find_nocase(pInfo->m_aGameType, "blockz") ||
|
|
||||||
str_find_nocase(pInfo->m_aGameType, "infectionz");
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsBlockWorlds(const CServerInfo *pInfo)
|
|
||||||
{
|
|
||||||
return (str_startswith(pInfo->m_aGameType, "bw ")) || (str_comp_nocase(pInfo->m_aGameType, "bw") == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsCity(const CServerInfo *pInfo)
|
|
||||||
{
|
|
||||||
return str_find_nocase(pInfo->m_aGameType, "city");
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsDDRace(const CServerInfo *pInfo)
|
|
||||||
{
|
|
||||||
return str_find_nocase(pInfo->m_aGameType, "ddrace") || str_find_nocase(pInfo->m_aGameType, "mkrace");
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsDDNet(const CServerInfo *pInfo)
|
|
||||||
{
|
|
||||||
return str_find_nocase(pInfo->m_aGameType, "ddracenet") || str_find_nocase(pInfo->m_aGameType, "ddnet");
|
|
||||||
}
|
|
||||||
|
|
||||||
// other
|
|
||||||
|
|
||||||
bool Is64Player(const CServerInfo *pInfo)
|
|
||||||
{
|
|
||||||
return str_find(pInfo->m_aGameType, "64") || str_find(pInfo->m_aName, "64") || IsDDNet(pInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsPlus(const CServerInfo *pInfo)
|
|
||||||
{
|
|
||||||
return str_find(pInfo->m_aGameType, "+");
|
|
||||||
}
|
|
||||||
|
|
|
@ -32,7 +32,6 @@ public:
|
||||||
int64_t m_RequestTime;
|
int64_t m_RequestTime;
|
||||||
bool m_RequestIgnoreInfo;
|
bool m_RequestIgnoreInfo;
|
||||||
int m_GotInfo;
|
int m_GotInfo;
|
||||||
bool m_Request64Legacy;
|
|
||||||
CServerInfo m_Info;
|
CServerInfo m_Info;
|
||||||
|
|
||||||
CServerEntry *m_pPrevReq; // request list
|
CServerEntry *m_pPrevReq; // request list
|
||||||
|
@ -131,7 +130,6 @@ public:
|
||||||
void SetBaseInfo(class CNetClient *pClient, const char *pNetVersion);
|
void SetBaseInfo(class CNetClient *pClient, const char *pNetVersion);
|
||||||
void OnInit();
|
void OnInit();
|
||||||
|
|
||||||
void RequestImpl64(const NETADDR &Addr, CServerEntry *pEntry) const;
|
|
||||||
void QueueRequest(CServerEntry *pEntry);
|
void QueueRequest(CServerEntry *pEntry);
|
||||||
CServerEntry *Find(const NETADDR &Addr);
|
CServerEntry *Find(const NETADDR &Addr);
|
||||||
int GetCurrentType() override { return m_ServerlistType; }
|
int GetCurrentType() override { return m_ServerlistType; }
|
||||||
|
|
|
@ -85,20 +85,6 @@ public:
|
||||||
static bool ParseLocation(int *pResult, const char *pString);
|
static bool ParseLocation(int *pResult, const char *pString);
|
||||||
};
|
};
|
||||||
|
|
||||||
bool IsVanilla(const CServerInfo *pInfo);
|
|
||||||
bool IsCatch(const CServerInfo *pInfo);
|
|
||||||
bool IsInsta(const CServerInfo *pInfo);
|
|
||||||
bool IsFNG(const CServerInfo *pInfo);
|
|
||||||
bool IsRace(const CServerInfo *pInfo);
|
|
||||||
bool IsFastCap(const CServerInfo *pInfo);
|
|
||||||
bool IsDDRace(const CServerInfo *pInfo);
|
|
||||||
bool IsDDNet(const CServerInfo *pInfo);
|
|
||||||
bool IsBlockWorlds(const CServerInfo *pInfo);
|
|
||||||
bool IsCity(const CServerInfo *pInfo);
|
|
||||||
|
|
||||||
bool Is64Player(const CServerInfo *pInfo);
|
|
||||||
bool IsPlus(const CServerInfo *pInfo);
|
|
||||||
|
|
||||||
class IServerBrowser : public IInterface
|
class IServerBrowser : public IInterface
|
||||||
{
|
{
|
||||||
MACRO_INTERFACE("serverbrowser", 0)
|
MACRO_INTERFACE("serverbrowser", 0)
|
||||||
|
|
|
@ -928,7 +928,7 @@ void CChat::RefindSkins()
|
||||||
{
|
{
|
||||||
if(Line.m_HasRenderTee)
|
if(Line.m_HasRenderTee)
|
||||||
{
|
{
|
||||||
const CSkin *pSkin = m_pClient->m_Skins.Get(m_pClient->m_Skins.Find(Line.m_aSkinName));
|
const CSkin *pSkin = m_pClient->m_Skins.Find(Line.m_aSkinName);
|
||||||
if(Line.m_CustomColoredSkin)
|
if(Line.m_CustomColoredSkin)
|
||||||
Line.m_RenderSkin = pSkin->m_ColorableSkin;
|
Line.m_RenderSkin = pSkin->m_ColorableSkin;
|
||||||
else
|
else
|
||||||
|
|
|
@ -352,15 +352,14 @@ void CGhost::OnRender()
|
||||||
if(Player.m_Weapon == WEAPON_NINJA && g_Config.m_ClShowNinja)
|
if(Player.m_Weapon == WEAPON_NINJA && g_Config.m_ClShowNinja)
|
||||||
{
|
{
|
||||||
// change the skin for the ghost to the ninja
|
// change the skin for the ghost to the ninja
|
||||||
int Skin = m_pClient->m_Skins.Find("x_ninja");
|
const auto *pSkin = m_pClient->m_Skins.FindOrNullptr("x_ninja");
|
||||||
if(Skin != -1)
|
if(pSkin != nullptr)
|
||||||
{
|
{
|
||||||
bool IsTeamplay = false;
|
bool IsTeamplay = false;
|
||||||
if(m_pClient->m_Snap.m_pGameInfoObj)
|
if(m_pClient->m_Snap.m_pGameInfoObj)
|
||||||
IsTeamplay = (m_pClient->m_Snap.m_pGameInfoObj->m_GameFlags & GAMEFLAG_TEAMS) != 0;
|
IsTeamplay = (m_pClient->m_Snap.m_pGameInfoObj->m_GameFlags & GAMEFLAG_TEAMS) != 0;
|
||||||
|
|
||||||
GhostNinjaRenderInfo = Ghost.m_RenderInfo;
|
GhostNinjaRenderInfo = Ghost.m_RenderInfo;
|
||||||
const CSkin *pSkin = m_pClient->m_Skins.Get(Skin);
|
|
||||||
GhostNinjaRenderInfo.m_OriginalRenderSkin = pSkin->m_OriginalSkin;
|
GhostNinjaRenderInfo.m_OriginalRenderSkin = pSkin->m_OriginalSkin;
|
||||||
GhostNinjaRenderInfo.m_ColorableRenderSkin = pSkin->m_ColorableSkin;
|
GhostNinjaRenderInfo.m_ColorableRenderSkin = pSkin->m_ColorableSkin;
|
||||||
GhostNinjaRenderInfo.m_BloodColor = pSkin->m_BloodColor;
|
GhostNinjaRenderInfo.m_BloodColor = pSkin->m_BloodColor;
|
||||||
|
@ -387,8 +386,7 @@ void CGhost::InitRenderInfos(CGhostItem *pGhost)
|
||||||
IntsToStr(&pGhost->m_Skin.m_Skin0, 6, aSkinName);
|
IntsToStr(&pGhost->m_Skin.m_Skin0, 6, aSkinName);
|
||||||
CTeeRenderInfo *pRenderInfo = &pGhost->m_RenderInfo;
|
CTeeRenderInfo *pRenderInfo = &pGhost->m_RenderInfo;
|
||||||
|
|
||||||
int SkinId = m_pClient->m_Skins.Find(aSkinName);
|
const CSkin *pSkin = m_pClient->m_Skins.Find(aSkinName);
|
||||||
const CSkin *pSkin = m_pClient->m_Skins.Get(SkinId);
|
|
||||||
pRenderInfo->m_OriginalRenderSkin = pSkin->m_OriginalSkin;
|
pRenderInfo->m_OriginalRenderSkin = pSkin->m_OriginalSkin;
|
||||||
pRenderInfo->m_ColorableRenderSkin = pSkin->m_ColorableSkin;
|
pRenderInfo->m_ColorableRenderSkin = pSkin->m_ColorableSkin;
|
||||||
pRenderInfo->m_BloodColor = pSkin->m_BloodColor;
|
pRenderInfo->m_BloodColor = pSkin->m_BloodColor;
|
||||||
|
@ -679,8 +677,7 @@ void CGhost::RefindSkin()
|
||||||
{
|
{
|
||||||
CTeeRenderInfo *pRenderInfo = &Ghost.m_RenderInfo;
|
CTeeRenderInfo *pRenderInfo = &Ghost.m_RenderInfo;
|
||||||
|
|
||||||
int SkinId = m_pClient->m_Skins.Find(aSkinName);
|
const CSkin *pSkin = m_pClient->m_Skins.Find(aSkinName);
|
||||||
const CSkin *pSkin = m_pClient->m_Skins.Get(SkinId);
|
|
||||||
pRenderInfo->m_OriginalRenderSkin = pSkin->m_OriginalSkin;
|
pRenderInfo->m_OriginalRenderSkin = pSkin->m_OriginalSkin;
|
||||||
pRenderInfo->m_ColorableRenderSkin = pSkin->m_ColorableSkin;
|
pRenderInfo->m_ColorableRenderSkin = pSkin->m_ColorableSkin;
|
||||||
pRenderInfo->m_SkinMetrics = pSkin->m_Metrics;
|
pRenderInfo->m_SkinMetrics = pSkin->m_Metrics;
|
||||||
|
@ -691,8 +688,7 @@ void CGhost::RefindSkin()
|
||||||
{
|
{
|
||||||
CTeeRenderInfo *pRenderInfo = &m_CurGhost.m_RenderInfo;
|
CTeeRenderInfo *pRenderInfo = &m_CurGhost.m_RenderInfo;
|
||||||
|
|
||||||
int SkinId = m_pClient->m_Skins.Find(aSkinName);
|
const CSkin *pSkin = m_pClient->m_Skins.Find(aSkinName);
|
||||||
const CSkin *pSkin = m_pClient->m_Skins.Get(SkinId);
|
|
||||||
pRenderInfo->m_OriginalRenderSkin = pSkin->m_OriginalSkin;
|
pRenderInfo->m_OriginalRenderSkin = pSkin->m_OriginalSkin;
|
||||||
pRenderInfo->m_ColorableRenderSkin = pSkin->m_ColorableSkin;
|
pRenderInfo->m_ColorableRenderSkin = pSkin->m_ColorableSkin;
|
||||||
pRenderInfo->m_SkinMetrics = pSkin->m_Metrics;
|
pRenderInfo->m_SkinMetrics = pSkin->m_Metrics;
|
||||||
|
|
|
@ -464,19 +464,19 @@ void CMenus::RenderServerbrowserServerList(CUIRect View)
|
||||||
{
|
{
|
||||||
ColorHSLA hsl = ColorHSLA(1.0f, 1.0f, 1.0f);
|
ColorHSLA hsl = ColorHSLA(1.0f, 1.0f, 1.0f);
|
||||||
|
|
||||||
if(IsVanilla(pItem))
|
if(str_comp(pItem->m_aGameType, "DM") == 0 || str_comp(pItem->m_aGameType, "TDM") == 0 || str_comp(pItem->m_aGameType, "CTF") == 0)
|
||||||
hsl = ColorHSLA(0.33f, 1.0f, 0.75f);
|
hsl = ColorHSLA(0.33f, 1.0f, 0.75f);
|
||||||
else if(IsCatch(pItem))
|
else if(str_find_nocase(pItem->m_aGameType, "catch"))
|
||||||
hsl = ColorHSLA(0.17f, 1.0f, 0.75f);
|
hsl = ColorHSLA(0.17f, 1.0f, 0.75f);
|
||||||
else if(IsInsta(pItem))
|
else if(str_find_nocase(pItem->m_aGameType, "idm") || str_find_nocase(pItem->m_aGameType, "itdm") || str_find_nocase(pItem->m_aGameType, "ictf"))
|
||||||
hsl = ColorHSLA(0.00f, 1.0f, 0.75f);
|
hsl = ColorHSLA(0.00f, 1.0f, 0.75f);
|
||||||
else if(IsFNG(pItem))
|
else if(str_find_nocase(pItem->m_aGameType, "fng"))
|
||||||
hsl = ColorHSLA(0.83f, 1.0f, 0.75f);
|
hsl = ColorHSLA(0.83f, 1.0f, 0.75f);
|
||||||
else if(IsDDNet(pItem))
|
else if(str_find_nocase(pItem->m_aGameType, "ddracenet") || str_find_nocase(pItem->m_aGameType, "ddnet"))
|
||||||
hsl = ColorHSLA(0.58f, 1.0f, 0.75f);
|
hsl = ColorHSLA(0.58f, 1.0f, 0.75f);
|
||||||
else if(IsDDRace(pItem))
|
else if(str_find_nocase(pItem->m_aGameType, "ddrace") || str_find_nocase(pItem->m_aGameType, "mkrace"))
|
||||||
hsl = ColorHSLA(0.75f, 1.0f, 0.75f);
|
hsl = ColorHSLA(0.75f, 1.0f, 0.75f);
|
||||||
else if(IsRace(pItem))
|
else if(str_find_nocase(pItem->m_aGameType, "race") || str_find_nocase(pItem->m_aGameType, "fastcap"))
|
||||||
hsl = ColorHSLA(0.46f, 1.0f, 0.75f);
|
hsl = ColorHSLA(0.46f, 1.0f, 0.75f);
|
||||||
|
|
||||||
ColorRGBA rgb = color_cast<ColorRGBA>(hsl);
|
ColorRGBA rgb = color_cast<ColorRGBA>(hsl);
|
||||||
|
@ -1167,7 +1167,7 @@ void CMenus::RenderServerbrowserServerDetail(CUIRect View)
|
||||||
|
|
||||||
if(!pSelectedServer->m_aClients[i].m_Player)
|
if(!pSelectedServer->m_aClients[i].m_Player)
|
||||||
str_copy(aTemp, "SPEC");
|
str_copy(aTemp, "SPEC");
|
||||||
else if(IsRace(pSelectedServer) && g_Config.m_ClDDRaceScoreBoard)
|
else if((str_find_nocase(pSelectedServer->m_aGameType, "race") || str_find_nocase(pSelectedServer->m_aGameType, "fastcap")) && g_Config.m_ClDDRaceScoreBoard)
|
||||||
{
|
{
|
||||||
if(pSelectedServer->m_aClients[i].m_Score == -9999 || pSelectedServer->m_aClients[i].m_Score == 0)
|
if(pSelectedServer->m_aClients[i].m_Score == -9999 || pSelectedServer->m_aClients[i].m_Score == 0)
|
||||||
aTemp[0] = 0;
|
aTemp[0] = 0;
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include <game/client/components/sounds.h>
|
#include <game/client/components/sounds.h>
|
||||||
#include <game/client/gameclient.h>
|
#include <game/client/gameclient.h>
|
||||||
#include <game/client/render.h>
|
#include <game/client/render.h>
|
||||||
|
#include <game/client/skin.h>
|
||||||
#include <game/client/ui.h>
|
#include <game/client/ui.h>
|
||||||
#include <game/client/ui_scrollregion.h>
|
#include <game/client/ui_scrollregion.h>
|
||||||
#include <game/localization.h>
|
#include <game/localization.h>
|
||||||
|
@ -404,10 +405,10 @@ struct CUISkin
|
||||||
CUISkin(const CSkin *pSkin) :
|
CUISkin(const CSkin *pSkin) :
|
||||||
m_pSkin(pSkin) {}
|
m_pSkin(pSkin) {}
|
||||||
|
|
||||||
bool operator<(const CUISkin &Other) const { return str_comp_nocase(m_pSkin->m_aName, Other.m_pSkin->m_aName) < 0; }
|
bool operator<(const CUISkin &Other) const { return str_comp_nocase(m_pSkin->GetName(), Other.m_pSkin->GetName()) < 0; }
|
||||||
|
|
||||||
bool operator<(const char *pOther) const { return str_comp_nocase(m_pSkin->m_aName, pOther) < 0; }
|
bool operator<(const char *pOther) const { return str_comp_nocase(m_pSkin->GetName(), pOther) < 0; }
|
||||||
bool operator==(const char *pOther) const { return !str_comp_nocase(m_pSkin->m_aName, pOther); }
|
bool operator==(const char *pOther) const { return !str_comp_nocase(m_pSkin->GetName(), pOther); }
|
||||||
};
|
};
|
||||||
|
|
||||||
void CMenus::RefreshSkins()
|
void CMenus::RefreshSkins()
|
||||||
|
@ -571,7 +572,7 @@ void CMenus::RenderSettingsTee(CUIRect MainView)
|
||||||
// which invalidates the skin
|
// which invalidates the skin
|
||||||
// skin info
|
// skin info
|
||||||
CTeeRenderInfo OwnSkinInfo;
|
CTeeRenderInfo OwnSkinInfo;
|
||||||
const CSkin *pSkin = m_pClient->m_Skins.Get(m_pClient->m_Skins.Find(pSkinName));
|
const CSkin *pSkin = m_pClient->m_Skins.Find(pSkinName);
|
||||||
OwnSkinInfo.m_OriginalRenderSkin = pSkin->m_OriginalSkin;
|
OwnSkinInfo.m_OriginalRenderSkin = pSkin->m_OriginalSkin;
|
||||||
OwnSkinInfo.m_ColorableRenderSkin = pSkin->m_ColorableSkin;
|
OwnSkinInfo.m_ColorableRenderSkin = pSkin->m_ColorableSkin;
|
||||||
OwnSkinInfo.m_SkinMetrics = pSkin->m_Metrics;
|
OwnSkinInfo.m_SkinMetrics = pSkin->m_Metrics;
|
||||||
|
@ -718,15 +719,14 @@ void CMenus::RenderSettingsTee(CUIRect MainView)
|
||||||
// a downloading skin
|
// a downloading skin
|
||||||
s_SkinCount = m_pClient->m_Skins.Num();
|
s_SkinCount = m_pClient->m_Skins.Num();
|
||||||
m_SkinFavoritesChanged = false;
|
m_SkinFavoritesChanged = false;
|
||||||
bool RequiresRebuild = false;
|
|
||||||
|
|
||||||
auto &&SkinNotFiltered = [&](const CSkin *pSkinToBeSelected) {
|
auto &&SkinNotFiltered = [&](const CSkin *pSkinToBeSelected) {
|
||||||
// filter quick search
|
// filter quick search
|
||||||
if(g_Config.m_ClSkinFilterString[0] != '\0' && !str_utf8_find_nocase(pSkinToBeSelected->m_aName, g_Config.m_ClSkinFilterString))
|
if(g_Config.m_ClSkinFilterString[0] != '\0' && !str_utf8_find_nocase(pSkinToBeSelected->GetName(), g_Config.m_ClSkinFilterString))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// no special skins
|
// no special skins
|
||||||
if((pSkinToBeSelected->m_aName[0] == 'x' && pSkinToBeSelected->m_aName[1] == '_'))
|
if((pSkinToBeSelected->GetName()[0] == 'x' && pSkinToBeSelected->GetName()[1] == '_'))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if(pSkinToBeSelected == 0)
|
if(pSkinToBeSelected == 0)
|
||||||
|
@ -737,38 +737,27 @@ void CMenus::RenderSettingsTee(CUIRect MainView)
|
||||||
|
|
||||||
for(const auto &it : m_SkinFavorites)
|
for(const auto &it : m_SkinFavorites)
|
||||||
{
|
{
|
||||||
const auto FirstSkinIndex = m_pClient->m_Skins.Find(it.c_str());
|
const CSkin *pSkinToBeSelected = m_pClient->m_Skins.FindOrNullptr(it.c_str());
|
||||||
// second call is intended, our implemention doesnt return the index in the call where the download finished
|
|
||||||
const auto SkinIndex = m_pClient->m_Skins.Find(it.c_str());
|
|
||||||
if(SkinIndex == -1)
|
|
||||||
continue;
|
|
||||||
if(FirstSkinIndex == -1 && SkinIndex != -1)
|
|
||||||
{
|
|
||||||
// skin list changed, rebuild next frame
|
|
||||||
RequiresRebuild = true;
|
|
||||||
}
|
|
||||||
const CSkin *pSkinToBeSelected = m_pClient->m_Skins.Get(SkinIndex);
|
|
||||||
|
|
||||||
if(!SkinNotFiltered(pSkinToBeSelected))
|
if(pSkinToBeSelected == nullptr || !SkinNotFiltered(pSkinToBeSelected))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
s_vFavoriteSkinListHelper.emplace_back(pSkinToBeSelected);
|
s_vFavoriteSkinListHelper.emplace_back(pSkinToBeSelected);
|
||||||
}
|
}
|
||||||
for(int i = 0; i < m_pClient->m_Skins.Num(); ++i)
|
for(const auto &SkinIt : m_pClient->m_Skins.GetSkinsUnsafe())
|
||||||
{
|
{
|
||||||
const CSkin *pSkinToBeSelected = m_pClient->m_Skins.Get(i);
|
const auto &pSkinToBeSelected = SkinIt.second;
|
||||||
|
if(!SkinNotFiltered(pSkinToBeSelected.get()))
|
||||||
if(!SkinNotFiltered(pSkinToBeSelected))
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if(std::find(m_SkinFavorites.begin(), m_SkinFavorites.end(), pSkinToBeSelected->m_aName) == m_SkinFavorites.end())
|
if(std::find(m_SkinFavorites.begin(), m_SkinFavorites.end(), pSkinToBeSelected->GetName()) == m_SkinFavorites.end())
|
||||||
s_vSkinListHelper.emplace_back(pSkinToBeSelected);
|
s_vSkinListHelper.emplace_back(pSkinToBeSelected.get());
|
||||||
}
|
}
|
||||||
std::sort(s_vSkinListHelper.begin(), s_vSkinListHelper.end());
|
std::sort(s_vSkinListHelper.begin(), s_vSkinListHelper.end());
|
||||||
std::sort(s_vFavoriteSkinListHelper.begin(), s_vFavoriteSkinListHelper.end());
|
std::sort(s_vFavoriteSkinListHelper.begin(), s_vFavoriteSkinListHelper.end());
|
||||||
s_vSkinList = s_vFavoriteSkinListHelper;
|
s_vSkinList = s_vFavoriteSkinListHelper;
|
||||||
s_vSkinList.insert(s_vSkinList.end(), s_vSkinListHelper.begin(), s_vSkinListHelper.end());
|
s_vSkinList.insert(s_vSkinList.end(), s_vSkinListHelper.begin(), s_vSkinListHelper.end());
|
||||||
s_InitSkinlist = RequiresRebuild;
|
s_InitSkinlist = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto &&RenderFavIcon = [&](const CUIRect &FavIcon, bool AsFav) {
|
auto &&RenderFavIcon = [&](const CUIRect &FavIcon, bool AsFav) {
|
||||||
|
@ -793,7 +782,7 @@ void CMenus::RenderSettingsTee(CUIRect MainView)
|
||||||
{
|
{
|
||||||
const CSkin *pSkinToBeDraw = s_vSkinList[i].m_pSkin;
|
const CSkin *pSkinToBeDraw = s_vSkinList[i].m_pSkin;
|
||||||
|
|
||||||
if(str_comp(pSkinToBeDraw->m_aName, pSkinName) == 0)
|
if(str_comp(pSkinToBeDraw->GetName(), pSkinName) == 0)
|
||||||
OldSelected = i;
|
OldSelected = i;
|
||||||
|
|
||||||
CListboxItem Item = UiDoListboxNextItem(pSkinToBeDraw, OldSelected >= 0 && (size_t)OldSelected == i);
|
CListboxItem Item = UiDoListboxNextItem(pSkinToBeDraw, OldSelected >= 0 && (size_t)OldSelected == i);
|
||||||
|
@ -816,7 +805,7 @@ void CMenus::RenderSettingsTee(CUIRect MainView)
|
||||||
{
|
{
|
||||||
SLabelProperties Props;
|
SLabelProperties Props;
|
||||||
Props.m_MaxWidth = Item.m_Rect.w;
|
Props.m_MaxWidth = Item.m_Rect.w;
|
||||||
UI()->DoLabel(&Item.m_Rect, pSkinToBeDraw->m_aName, 12.0f, TEXTALIGN_LEFT, Props);
|
UI()->DoLabel(&Item.m_Rect, pSkinToBeDraw->GetName(), 12.0f, TEXTALIGN_LEFT, Props);
|
||||||
}
|
}
|
||||||
if(g_Config.m_Debug)
|
if(g_Config.m_Debug)
|
||||||
{
|
{
|
||||||
|
@ -831,7 +820,7 @@ void CMenus::RenderSettingsTee(CUIRect MainView)
|
||||||
|
|
||||||
// render skin favorite icon
|
// render skin favorite icon
|
||||||
{
|
{
|
||||||
const auto SkinItFav = m_SkinFavorites.find(pSkinToBeDraw->m_aName);
|
const auto SkinItFav = m_SkinFavorites.find(pSkinToBeDraw->GetName());
|
||||||
const auto IsFav = SkinItFav != m_SkinFavorites.end();
|
const auto IsFav = SkinItFav != m_SkinFavorites.end();
|
||||||
CUIRect FavIcon;
|
CUIRect FavIcon;
|
||||||
OriginalRect.HSplitTop(20.0f, &FavIcon, nullptr);
|
OriginalRect.HSplitTop(20.0f, &FavIcon, nullptr);
|
||||||
|
@ -847,7 +836,7 @@ void CMenus::RenderSettingsTee(CUIRect MainView)
|
||||||
RenderFavIcon(FavIcon, IsFav);
|
RenderFavIcon(FavIcon, IsFav);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(UI()->DoButtonLogic(pSkinToBeDraw->m_aName, 0, &FavIcon))
|
if(UI()->DoButtonLogic(pSkinToBeDraw->GetName(), 0, &FavIcon))
|
||||||
{
|
{
|
||||||
if(IsFav)
|
if(IsFav)
|
||||||
{
|
{
|
||||||
|
@ -855,7 +844,7 @@ void CMenus::RenderSettingsTee(CUIRect MainView)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_SkinFavorites.emplace(pSkinToBeDraw->m_aName);
|
m_SkinFavorites.emplace(pSkinToBeDraw->GetName());
|
||||||
}
|
}
|
||||||
s_InitSkinlist = true;
|
s_InitSkinlist = true;
|
||||||
}
|
}
|
||||||
|
@ -866,7 +855,7 @@ void CMenus::RenderSettingsTee(CUIRect MainView)
|
||||||
const int NewSelected = UiDoListboxEnd(&s_ScrollValue, 0);
|
const int NewSelected = UiDoListboxEnd(&s_ScrollValue, 0);
|
||||||
if(OldSelected != NewSelected)
|
if(OldSelected != NewSelected)
|
||||||
{
|
{
|
||||||
mem_copy(pSkinName, s_vSkinList[NewSelected].m_pSkin->m_aName, sizeof(g_Config.m_ClPlayerSkin));
|
mem_copy(pSkinName, s_vSkinList[NewSelected].m_pSkin->GetName(), sizeof(g_Config.m_ClPlayerSkin));
|
||||||
SetNeedSendInfo();
|
SetNeedSendInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2900,7 +2889,7 @@ void CMenus::RenderSettingsAppearance(CUIRect MainView)
|
||||||
|
|
||||||
// Load skins
|
// Load skins
|
||||||
|
|
||||||
int DefaultInd = GameClient()->m_Skins.Find("default");
|
const auto *pDefaultSkin = GameClient()->m_Skins.Find("default");
|
||||||
|
|
||||||
for(auto &Info : aRenderInfo)
|
for(auto &Info : aRenderInfo)
|
||||||
{
|
{
|
||||||
|
@ -2908,13 +2897,13 @@ void CMenus::RenderSettingsAppearance(CUIRect MainView)
|
||||||
Info.m_CustomColoredSkin = false;
|
Info.m_CustomColoredSkin = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ind = -1;
|
const CSkin *pSkin = nullptr;
|
||||||
int pos = 0;
|
int pos = 0;
|
||||||
|
|
||||||
aRenderInfo[pos++].m_OriginalRenderSkin = GameClient()->m_Skins.Get(DefaultInd)->m_OriginalSkin;
|
aRenderInfo[pos++].m_OriginalRenderSkin = pDefaultSkin->m_OriginalSkin;
|
||||||
aRenderInfo[pos++].m_OriginalRenderSkin = (ind = GameClient()->m_Skins.Find("pinky")) != -1 ? GameClient()->m_Skins.Get(ind)->m_OriginalSkin : aRenderInfo[0].m_OriginalRenderSkin;
|
aRenderInfo[pos++].m_OriginalRenderSkin = (pSkin = GameClient()->m_Skins.FindOrNullptr("pinky")) != nullptr ? pSkin->m_OriginalSkin : aRenderInfo[0].m_OriginalRenderSkin;
|
||||||
aRenderInfo[pos++].m_OriginalRenderSkin = (ind = GameClient()->m_Skins.Find("cammostripes")) != -1 ? GameClient()->m_Skins.Get(ind)->m_OriginalSkin : aRenderInfo[0].m_OriginalRenderSkin;
|
aRenderInfo[pos++].m_OriginalRenderSkin = (pSkin = GameClient()->m_Skins.FindOrNullptr("cammostripes")) != nullptr ? pSkin->m_OriginalSkin : aRenderInfo[0].m_OriginalRenderSkin;
|
||||||
aRenderInfo[pos++].m_OriginalRenderSkin = (ind = GameClient()->m_Skins.Find("beast")) != -1 ? GameClient()->m_Skins.Get(ind)->m_OriginalSkin : aRenderInfo[0].m_OriginalRenderSkin;
|
aRenderInfo[pos++].m_OriginalRenderSkin = (pSkin = GameClient()->m_Skins.FindOrNullptr("beast")) != nullptr ? pSkin->m_OriginalSkin : aRenderInfo[0].m_OriginalRenderSkin;
|
||||||
}
|
}
|
||||||
|
|
||||||
// System
|
// System
|
||||||
|
|
|
@ -769,10 +769,9 @@ void CPlayers::OnRender()
|
||||||
if((CharacterInfo.m_Cur.m_Weapon == WEAPON_NINJA || (CharacterInfo.m_HasExtendedData && CharacterInfo.m_ExtendedData.m_FreezeEnd != 0)) && g_Config.m_ClShowNinja)
|
if((CharacterInfo.m_Cur.m_Weapon == WEAPON_NINJA || (CharacterInfo.m_HasExtendedData && CharacterInfo.m_ExtendedData.m_FreezeEnd != 0)) && g_Config.m_ClShowNinja)
|
||||||
{
|
{
|
||||||
// change the skin for the player to the ninja
|
// change the skin for the player to the ninja
|
||||||
int Skin = m_pClient->m_Skins.Find("x_ninja");
|
const auto *pSkin = m_pClient->m_Skins.FindOrNullptr("x_ninja");
|
||||||
if(Skin != -1)
|
if(pSkin != nullptr)
|
||||||
{
|
{
|
||||||
const CSkin *pSkin = m_pClient->m_Skins.Get(Skin);
|
|
||||||
m_aRenderInfo[i].m_OriginalRenderSkin = pSkin->m_OriginalSkin;
|
m_aRenderInfo[i].m_OriginalRenderSkin = pSkin->m_OriginalSkin;
|
||||||
m_aRenderInfo[i].m_ColorableRenderSkin = pSkin->m_ColorableSkin;
|
m_aRenderInfo[i].m_ColorableRenderSkin = pSkin->m_ColorableSkin;
|
||||||
m_aRenderInfo[i].m_BloodColor = pSkin->m_BloodColor;
|
m_aRenderInfo[i].m_BloodColor = pSkin->m_BloodColor;
|
||||||
|
@ -786,8 +785,7 @@ void CPlayers::OnRender()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
int Skin = m_pClient->m_Skins.Find("x_spec");
|
const CSkin *pSkin = m_pClient->m_Skins.Find("x_spec");
|
||||||
const CSkin *pSkin = m_pClient->m_Skins.Get(Skin);
|
|
||||||
m_RenderInfoSpec.m_OriginalRenderSkin = pSkin->m_OriginalSkin;
|
m_RenderInfoSpec.m_OriginalRenderSkin = pSkin->m_OriginalSkin;
|
||||||
m_RenderInfoSpec.m_ColorableRenderSkin = pSkin->m_ColorableSkin;
|
m_RenderInfoSpec.m_ColorableRenderSkin = pSkin->m_ColorableSkin;
|
||||||
m_RenderInfoSpec.m_BloodColor = pSkin->m_BloodColor;
|
m_RenderInfoSpec.m_BloodColor = pSkin->m_BloodColor;
|
||||||
|
|
|
@ -70,18 +70,14 @@ int CSkins::SkinScan(const char *pName, int IsDir, int DirType, void *pUser)
|
||||||
|
|
||||||
// Don't add duplicate skins (one from user's config directory, other from
|
// Don't add duplicate skins (one from user's config directory, other from
|
||||||
// client itself)
|
// client itself)
|
||||||
for(int i = 0; i < pSelf->Num(); i++)
|
if(pSelf->m_Skins.find(aNameWithoutPng) != pSelf->m_Skins.end())
|
||||||
{
|
|
||||||
const char *pExName = pSelf->Get(i)->m_aName;
|
|
||||||
if(str_comp(pExName, aNameWithoutPng) == 0)
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
char aBuf[IO_MAX_PATH_LENGTH];
|
char aBuf[IO_MAX_PATH_LENGTH];
|
||||||
str_format(aBuf, sizeof(aBuf), "skins/%s", pName);
|
str_format(aBuf, sizeof(aBuf), "skins/%s", pName);
|
||||||
auto SkinID = pSelf->LoadSkin(aNameWithoutPng, aBuf, DirType);
|
pSelf->LoadSkin(aNameWithoutPng, aBuf, DirType);
|
||||||
pUserReal->m_SkinLoadedFunc(SkinID);
|
pUserReal->m_SkinLoadedFunc((int)pSelf->m_Skins.size());
|
||||||
return SkinID;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void CheckMetrics(CSkin::SSkinMetricVariable &Metrics, uint8_t *pImg, int ImgWidth, int ImgX, int ImgY, int CheckWidth, int CheckHeight)
|
static void CheckMetrics(CSkin::SSkinMetricVariable &Metrics, uint8_t *pImg, int ImgWidth, int ImgX, int ImgY, int CheckWidth, int CheckHeight)
|
||||||
|
@ -119,7 +115,7 @@ static void CheckMetrics(CSkin::SSkinMetricVariable &Metrics, uint8_t *pImg, int
|
||||||
Metrics.m_MaxHeight = CheckHeight;
|
Metrics.m_MaxHeight = CheckHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
int CSkins::LoadSkin(const char *pName, const char *pPath, int DirType)
|
const CSkin *CSkins::LoadSkin(const char *pName, const char *pPath, int DirType)
|
||||||
{
|
{
|
||||||
CImageInfo Info;
|
CImageInfo Info;
|
||||||
if(!LoadSkinPNG(Info, pName, pPath, DirType))
|
if(!LoadSkinPNG(Info, pName, pPath, DirType))
|
||||||
|
@ -139,7 +135,7 @@ bool CSkins::LoadSkinPNG(CImageInfo &Info, const char *pName, const char *pPath,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int CSkins::LoadSkin(const char *pName, CImageInfo &Info)
|
const CSkin *CSkins::LoadSkin(const char *pName, CImageInfo &Info)
|
||||||
{
|
{
|
||||||
char aBuf[512];
|
char aBuf[512];
|
||||||
|
|
||||||
|
@ -147,16 +143,16 @@ int CSkins::LoadSkin(const char *pName, CImageInfo &Info)
|
||||||
{
|
{
|
||||||
str_format(aBuf, sizeof(aBuf), "skin failed image divisibility: %s", pName);
|
str_format(aBuf, sizeof(aBuf), "skin failed image divisibility: %s", pName);
|
||||||
Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "game", aBuf);
|
Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "game", aBuf);
|
||||||
return 0;
|
return nullptr;
|
||||||
}
|
}
|
||||||
if(!Graphics()->IsImageFormatRGBA(pName, Info))
|
if(!Graphics()->IsImageFormatRGBA(pName, Info))
|
||||||
{
|
{
|
||||||
str_format(aBuf, sizeof(aBuf), "skin format is not RGBA: %s", pName);
|
str_format(aBuf, sizeof(aBuf), "skin format is not RGBA: %s", pName);
|
||||||
Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "game", aBuf);
|
Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "game", aBuf);
|
||||||
return 0;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
CSkin Skin;
|
CSkin Skin{pName};
|
||||||
Skin.m_OriginalSkin.m_Body = Graphics()->LoadSpriteTexture(Info, &g_pData->m_aSprites[SPRITE_TEE_BODY]);
|
Skin.m_OriginalSkin.m_Body = Graphics()->LoadSpriteTexture(Info, &g_pData->m_aSprites[SPRITE_TEE_BODY]);
|
||||||
Skin.m_OriginalSkin.m_BodyOutline = Graphics()->LoadSpriteTexture(Info, &g_pData->m_aSprites[SPRITE_TEE_BODY_OUTLINE]);
|
Skin.m_OriginalSkin.m_BodyOutline = Graphics()->LoadSpriteTexture(Info, &g_pData->m_aSprites[SPRITE_TEE_BODY_OUTLINE]);
|
||||||
Skin.m_OriginalSkin.m_Feet = Graphics()->LoadSpriteTexture(Info, &g_pData->m_aSprites[SPRITE_TEE_FOOT]);
|
Skin.m_OriginalSkin.m_Feet = Graphics()->LoadSpriteTexture(Info, &g_pData->m_aSprites[SPRITE_TEE_FOOT]);
|
||||||
|
@ -194,7 +190,7 @@ int CSkins::LoadSkin(const char *pName, CImageInfo &Info)
|
||||||
int BodyWidth = g_pData->m_aSprites[SPRITE_TEE_BODY].m_W * (Info.m_Width / g_pData->m_aSprites[SPRITE_TEE_BODY].m_pSet->m_Gridx); // body width
|
int BodyWidth = g_pData->m_aSprites[SPRITE_TEE_BODY].m_W * (Info.m_Width / g_pData->m_aSprites[SPRITE_TEE_BODY].m_pSet->m_Gridx); // body width
|
||||||
int BodyHeight = g_pData->m_aSprites[SPRITE_TEE_BODY].m_H * (Info.m_Height / g_pData->m_aSprites[SPRITE_TEE_BODY].m_pSet->m_Gridy); // body height
|
int BodyHeight = g_pData->m_aSprites[SPRITE_TEE_BODY].m_H * (Info.m_Height / g_pData->m_aSprites[SPRITE_TEE_BODY].m_pSet->m_Gridy); // body height
|
||||||
if(BodyWidth > Info.m_Width || BodyHeight > Info.m_Height)
|
if(BodyWidth > Info.m_Width || BodyHeight > Info.m_Height)
|
||||||
return 0;
|
return nullptr;
|
||||||
unsigned char *pData = (unsigned char *)Info.m_pData;
|
unsigned char *pData = (unsigned char *)Info.m_pData;
|
||||||
const int PixelStep = 4;
|
const int PixelStep = 4;
|
||||||
int Pitch = Info.m_Width * PixelStep;
|
int Pitch = Info.m_Width * PixelStep;
|
||||||
|
@ -290,16 +286,16 @@ int CSkins::LoadSkin(const char *pName, CImageInfo &Info)
|
||||||
Graphics()->FreePNG(&Info);
|
Graphics()->FreePNG(&Info);
|
||||||
|
|
||||||
// set skin data
|
// set skin data
|
||||||
str_copy(Skin.m_aName, pName);
|
|
||||||
if(g_Config.m_Debug)
|
if(g_Config.m_Debug)
|
||||||
{
|
{
|
||||||
str_format(aBuf, sizeof(aBuf), "load skin %s", Skin.m_aName);
|
str_format(aBuf, sizeof(aBuf), "load skin %s", Skin.GetName());
|
||||||
Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "game", aBuf);
|
Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "game", aBuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_vSkins.insert(std::lower_bound(m_vSkins.begin(), m_vSkins.end(), Skin), Skin);
|
auto &&pSkin = std::make_unique<CSkin>(std::move(Skin));
|
||||||
|
const auto SkinInsertIt = m_Skins.insert({pSkin->GetName(), std::move(pSkin)});
|
||||||
|
|
||||||
return 0;
|
return SkinInsertIt.first->second.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSkins::OnInit()
|
void CSkins::OnInit()
|
||||||
|
@ -319,132 +315,132 @@ void CSkins::OnInit()
|
||||||
}
|
}
|
||||||
|
|
||||||
// load skins;
|
// load skins;
|
||||||
Refresh([this](int SkinID) {
|
Refresh([this](int SkinCounter) {
|
||||||
GameClient()->m_Menus.RenderLoading(Localize("Loading DDNet Client"), Localize("Loading skin files"), 0);
|
GameClient()->m_Menus.RenderLoading(Localize("Loading DDNet Client"), Localize("Loading skin files"), 0);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSkins::Refresh(TSkinLoadedCBFunc &&SkinLoadedFunc)
|
void CSkins::Refresh(TSkinLoadedCBFunc &&SkinLoadedFunc)
|
||||||
{
|
{
|
||||||
for(auto &Skin : m_vSkins)
|
for(const auto &SkinIt : m_Skins)
|
||||||
{
|
{
|
||||||
Graphics()->UnloadTexture(&Skin.m_OriginalSkin.m_Body);
|
const auto &pSkin = SkinIt.second;
|
||||||
Graphics()->UnloadTexture(&Skin.m_OriginalSkin.m_BodyOutline);
|
Graphics()->UnloadTexture(&pSkin->m_OriginalSkin.m_Body);
|
||||||
Graphics()->UnloadTexture(&Skin.m_OriginalSkin.m_Feet);
|
Graphics()->UnloadTexture(&pSkin->m_OriginalSkin.m_BodyOutline);
|
||||||
Graphics()->UnloadTexture(&Skin.m_OriginalSkin.m_FeetOutline);
|
Graphics()->UnloadTexture(&pSkin->m_OriginalSkin.m_Feet);
|
||||||
Graphics()->UnloadTexture(&Skin.m_OriginalSkin.m_Hands);
|
Graphics()->UnloadTexture(&pSkin->m_OriginalSkin.m_FeetOutline);
|
||||||
Graphics()->UnloadTexture(&Skin.m_OriginalSkin.m_HandsOutline);
|
Graphics()->UnloadTexture(&pSkin->m_OriginalSkin.m_Hands);
|
||||||
for(auto &Eye : Skin.m_OriginalSkin.m_aEyes)
|
Graphics()->UnloadTexture(&pSkin->m_OriginalSkin.m_HandsOutline);
|
||||||
|
for(auto &Eye : pSkin->m_OriginalSkin.m_aEyes)
|
||||||
Graphics()->UnloadTexture(&Eye);
|
Graphics()->UnloadTexture(&Eye);
|
||||||
|
|
||||||
Graphics()->UnloadTexture(&Skin.m_ColorableSkin.m_Body);
|
Graphics()->UnloadTexture(&pSkin->m_ColorableSkin.m_Body);
|
||||||
Graphics()->UnloadTexture(&Skin.m_ColorableSkin.m_BodyOutline);
|
Graphics()->UnloadTexture(&pSkin->m_ColorableSkin.m_BodyOutline);
|
||||||
Graphics()->UnloadTexture(&Skin.m_ColorableSkin.m_Feet);
|
Graphics()->UnloadTexture(&pSkin->m_ColorableSkin.m_Feet);
|
||||||
Graphics()->UnloadTexture(&Skin.m_ColorableSkin.m_FeetOutline);
|
Graphics()->UnloadTexture(&pSkin->m_ColorableSkin.m_FeetOutline);
|
||||||
Graphics()->UnloadTexture(&Skin.m_ColorableSkin.m_Hands);
|
Graphics()->UnloadTexture(&pSkin->m_ColorableSkin.m_Hands);
|
||||||
Graphics()->UnloadTexture(&Skin.m_ColorableSkin.m_HandsOutline);
|
Graphics()->UnloadTexture(&pSkin->m_ColorableSkin.m_HandsOutline);
|
||||||
for(auto &Eye : Skin.m_ColorableSkin.m_aEyes)
|
for(auto &Eye : pSkin->m_ColorableSkin.m_aEyes)
|
||||||
Graphics()->UnloadTexture(&Eye);
|
Graphics()->UnloadTexture(&Eye);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_vSkins.clear();
|
m_Skins.clear();
|
||||||
m_vDownloadSkins.clear();
|
m_DownloadSkins.clear();
|
||||||
m_DownloadingSkins = 0;
|
m_DownloadingSkins = 0;
|
||||||
SSkinScanUser SkinScanUser;
|
SSkinScanUser SkinScanUser;
|
||||||
SkinScanUser.m_pThis = this;
|
SkinScanUser.m_pThis = this;
|
||||||
SkinScanUser.m_SkinLoadedFunc = SkinLoadedFunc;
|
SkinScanUser.m_SkinLoadedFunc = SkinLoadedFunc;
|
||||||
Storage()->ListDirectory(IStorage::TYPE_ALL, "skins", SkinScan, &SkinScanUser);
|
Storage()->ListDirectory(IStorage::TYPE_ALL, "skins", SkinScan, &SkinScanUser);
|
||||||
if(m_vSkins.empty())
|
if(m_Skins.empty())
|
||||||
{
|
{
|
||||||
Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "gameclient", "failed to load skins. folder='skins/'");
|
Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "gameclient", "failed to load skins. folder='skins/'");
|
||||||
CSkin DummySkin;
|
CSkin DummySkin{"dummy"};
|
||||||
str_copy(DummySkin.m_aName, "dummy");
|
|
||||||
DummySkin.m_BloodColor = ColorRGBA(1.0f, 1.0f, 1.0f);
|
DummySkin.m_BloodColor = ColorRGBA(1.0f, 1.0f, 1.0f);
|
||||||
m_vSkins.push_back(DummySkin);
|
auto &&pDummySkin = std::make_unique<CSkin>(std::move(DummySkin));
|
||||||
|
m_Skins.insert({pDummySkin->GetName(), std::move(pDummySkin)});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int CSkins::Num()
|
int CSkins::Num()
|
||||||
{
|
{
|
||||||
return m_vSkins.size();
|
return m_Skins.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
const CSkin *CSkins::Get(int Index)
|
const CSkin *CSkins::Find(const char *pName)
|
||||||
{
|
{
|
||||||
if(Index < 0)
|
const auto *pSkin = FindOrNullptr(pName);
|
||||||
|
if(pSkin == nullptr)
|
||||||
{
|
{
|
||||||
Index = Find("default");
|
pSkin = FindOrNullptr("default");
|
||||||
|
if(pSkin == nullptr)
|
||||||
if(Index < 0)
|
return m_Skins.begin()->second.get();
|
||||||
Index = 0;
|
else
|
||||||
|
return pSkin;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return pSkin;
|
||||||
}
|
}
|
||||||
return &m_vSkins[Index % m_vSkins.size()];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int CSkins::Find(const char *pName)
|
const CSkin *CSkins::FindOrNullptr(const char *pName)
|
||||||
{
|
{
|
||||||
const char *pSkinPrefix = m_aEventSkinPrefix[0] ? m_aEventSkinPrefix : g_Config.m_ClSkinPrefix;
|
const char *pSkinPrefix = m_aEventSkinPrefix[0] ? m_aEventSkinPrefix : g_Config.m_ClSkinPrefix;
|
||||||
if(g_Config.m_ClVanillaSkinsOnly && !IsVanillaSkin(pName))
|
if(g_Config.m_ClVanillaSkinsOnly && !IsVanillaSkin(pName))
|
||||||
{
|
{
|
||||||
return -1;
|
return nullptr;
|
||||||
}
|
}
|
||||||
else if(pSkinPrefix && pSkinPrefix[0])
|
else if(pSkinPrefix && pSkinPrefix[0])
|
||||||
{
|
{
|
||||||
char aBuf[24];
|
char aBuf[24];
|
||||||
str_format(aBuf, sizeof(aBuf), "%s_%s", pSkinPrefix, pName);
|
str_format(aBuf, sizeof(aBuf), "%s_%s", pSkinPrefix, pName);
|
||||||
// If we find something, use it, otherwise fall back to normal skins.
|
// If we find something, use it, otherwise fall back to normal skins.
|
||||||
int Result = FindImpl(aBuf);
|
const auto *pResult = FindImpl(aBuf);
|
||||||
if(Result != -1)
|
if(pResult != nullptr)
|
||||||
{
|
{
|
||||||
return Result;
|
return pResult;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return FindImpl(pName);
|
return FindImpl(pName);
|
||||||
}
|
}
|
||||||
|
|
||||||
int CSkins::FindImpl(const char *pName)
|
const CSkin *CSkins::FindImpl(const char *pName)
|
||||||
{
|
{
|
||||||
CSkin Needle;
|
auto SkinIt = m_Skins.find(pName);
|
||||||
mem_zero(&Needle, sizeof(Needle));
|
if(SkinIt != m_Skins.end())
|
||||||
str_copy(Needle.m_aName, pName);
|
return SkinIt->second.get();
|
||||||
auto Range = std::equal_range(m_vSkins.begin(), m_vSkins.end(), Needle);
|
|
||||||
if(std::distance(Range.first, Range.second) == 1)
|
|
||||||
return Range.first - m_vSkins.begin();
|
|
||||||
|
|
||||||
if(str_comp(pName, "default") == 0)
|
if(str_comp(pName, "default") == 0)
|
||||||
return -1;
|
return nullptr;
|
||||||
|
|
||||||
if(!g_Config.m_ClDownloadSkins)
|
if(!g_Config.m_ClDownloadSkins)
|
||||||
return -1;
|
return nullptr;
|
||||||
|
|
||||||
if(str_find(pName, "/") != 0)
|
if(str_find(pName, "/") != 0)
|
||||||
return -1;
|
return nullptr;
|
||||||
|
|
||||||
CDownloadSkin DownloadNeedle;
|
const auto SkinDownloadIt = m_DownloadSkins.find(pName);
|
||||||
mem_zero(&DownloadNeedle, sizeof(DownloadNeedle));
|
if(SkinDownloadIt != m_DownloadSkins.end())
|
||||||
str_copy(DownloadNeedle.m_aName, pName);
|
|
||||||
const auto &[RangeBegin, RangeEnd] = std::equal_range(m_vDownloadSkins.begin(), m_vDownloadSkins.end(), DownloadNeedle);
|
|
||||||
if(std::distance(RangeBegin, RangeEnd) == 1)
|
|
||||||
{
|
{
|
||||||
if(RangeBegin->m_pTask && RangeBegin->m_pTask->State() == HTTP_DONE)
|
if(SkinDownloadIt->second->m_pTask && SkinDownloadIt->second->m_pTask->State() == HTTP_DONE)
|
||||||
{
|
{
|
||||||
char aPath[IO_MAX_PATH_LENGTH];
|
char aPath[IO_MAX_PATH_LENGTH];
|
||||||
str_format(aPath, sizeof(aPath), "downloadedskins/%s.png", RangeBegin->m_aName);
|
str_format(aPath, sizeof(aPath), "downloadedskins/%s.png", SkinDownloadIt->second->GetName());
|
||||||
Storage()->RenameFile(RangeBegin->m_aPath, aPath, IStorage::TYPE_SAVE);
|
Storage()->RenameFile(SkinDownloadIt->second->m_aPath, aPath, IStorage::TYPE_SAVE);
|
||||||
LoadSkin(RangeBegin->m_aName, RangeBegin->m_pTask->m_Info);
|
const auto *pSkin = LoadSkin(SkinDownloadIt->second->GetName(), SkinDownloadIt->second->m_pTask->m_Info);
|
||||||
RangeBegin->m_pTask = nullptr;
|
SkinDownloadIt->second->m_pTask = nullptr;
|
||||||
--m_DownloadingSkins;
|
--m_DownloadingSkins;
|
||||||
|
return pSkin;
|
||||||
}
|
}
|
||||||
if(RangeBegin->m_pTask && (RangeBegin->m_pTask->State() == HTTP_ERROR || RangeBegin->m_pTask->State() == HTTP_ABORTED))
|
if(SkinDownloadIt->second->m_pTask && (SkinDownloadIt->second->m_pTask->State() == HTTP_ERROR || SkinDownloadIt->second->m_pTask->State() == HTTP_ABORTED))
|
||||||
{
|
{
|
||||||
RangeBegin->m_pTask = nullptr;
|
SkinDownloadIt->second->m_pTask = nullptr;
|
||||||
--m_DownloadingSkins;
|
--m_DownloadingSkins;
|
||||||
}
|
}
|
||||||
return -1;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
CDownloadSkin Skin;
|
CDownloadSkin Skin{pName};
|
||||||
str_copy(Skin.m_aName, pName);
|
|
||||||
|
|
||||||
char aUrl[IO_MAX_PATH_LENGTH];
|
char aUrl[IO_MAX_PATH_LENGTH];
|
||||||
char aEscapedName[256];
|
char aEscapedName[256];
|
||||||
|
@ -454,7 +450,8 @@ int CSkins::FindImpl(const char *pName)
|
||||||
str_format(Skin.m_aPath, sizeof(Skin.m_aPath), "downloadedskins/%s", IStorage::FormatTmpPath(aBuf, sizeof(aBuf), pName));
|
str_format(Skin.m_aPath, sizeof(Skin.m_aPath), "downloadedskins/%s", IStorage::FormatTmpPath(aBuf, sizeof(aBuf), pName));
|
||||||
Skin.m_pTask = std::make_shared<CGetPngFile>(this, aUrl, Storage(), Skin.m_aPath);
|
Skin.m_pTask = std::make_shared<CGetPngFile>(this, aUrl, Storage(), Skin.m_aPath);
|
||||||
m_pClient->Engine()->AddJob(Skin.m_pTask);
|
m_pClient->Engine()->AddJob(Skin.m_pTask);
|
||||||
m_vDownloadSkins.insert(std::lower_bound(m_vDownloadSkins.begin(), m_vDownloadSkins.end(), Skin), std::move(Skin));
|
auto &&pDownloadSkin = std::make_unique<CDownloadSkin>(std::move(Skin));
|
||||||
|
m_DownloadSkins.insert({pDownloadSkin->GetName(), std::move(pDownloadSkin)});
|
||||||
++m_DownloadingSkins;
|
++m_DownloadingSkins;
|
||||||
return -1;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,14 +3,18 @@
|
||||||
#ifndef GAME_CLIENT_COMPONENTS_SKINS_H
|
#ifndef GAME_CLIENT_COMPONENTS_SKINS_H
|
||||||
#define GAME_CLIENT_COMPONENTS_SKINS_H
|
#define GAME_CLIENT_COMPONENTS_SKINS_H
|
||||||
|
|
||||||
|
#include <base/system.h>
|
||||||
#include <engine/shared/http.h>
|
#include <engine/shared/http.h>
|
||||||
#include <game/client/component.h>
|
#include <game/client/component.h>
|
||||||
#include <game/client/skin.h>
|
#include <game/client/skin.h>
|
||||||
#include <vector>
|
#include <string_view>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
class CSkins : public CComponent
|
class CSkins : public CComponent
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
CSkins() = default;
|
||||||
|
|
||||||
class CGetPngFile : public CHttpRequest
|
class CGetPngFile : public CHttpRequest
|
||||||
{
|
{
|
||||||
CSkins *m_pSkins;
|
CSkins *m_pSkins;
|
||||||
|
@ -25,12 +29,18 @@ public:
|
||||||
|
|
||||||
struct CDownloadSkin
|
struct CDownloadSkin
|
||||||
{
|
{
|
||||||
std::shared_ptr<CSkins::CGetPngFile> m_pTask;
|
private:
|
||||||
char m_aPath[IO_MAX_PATH_LENGTH];
|
|
||||||
char m_aName[24];
|
char m_aName[24];
|
||||||
|
|
||||||
|
public:
|
||||||
|
std::shared_ptr<CSkins::CGetPngFile> m_pTask;
|
||||||
|
char m_aPath[IO_MAX_PATH_LENGTH];
|
||||||
|
|
||||||
CDownloadSkin(CDownloadSkin &&Other) = default;
|
CDownloadSkin(CDownloadSkin &&Other) = default;
|
||||||
CDownloadSkin() = default;
|
CDownloadSkin(const char *pName)
|
||||||
|
{
|
||||||
|
str_copy(m_aName, pName);
|
||||||
|
}
|
||||||
|
|
||||||
~CDownloadSkin()
|
~CDownloadSkin()
|
||||||
{
|
{
|
||||||
|
@ -42,6 +52,8 @@ public:
|
||||||
bool operator==(const char *pOther) const { return !str_comp(m_aName, pOther); }
|
bool operator==(const char *pOther) const { return !str_comp(m_aName, pOther); }
|
||||||
|
|
||||||
CDownloadSkin &operator=(CDownloadSkin &&Other) = default;
|
CDownloadSkin &operator=(CDownloadSkin &&Other) = default;
|
||||||
|
|
||||||
|
const char *GetName() const { return m_aName; }
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::function<void(int)> TSkinLoadedCBFunc;
|
typedef std::function<void(int)> TSkinLoadedCBFunc;
|
||||||
|
@ -51,21 +63,22 @@ public:
|
||||||
|
|
||||||
void Refresh(TSkinLoadedCBFunc &&SkinLoadedFunc);
|
void Refresh(TSkinLoadedCBFunc &&SkinLoadedFunc);
|
||||||
int Num();
|
int Num();
|
||||||
const CSkin *Get(int Index);
|
std::unordered_map<std::string_view, std::unique_ptr<CSkin>> &GetSkinsUnsafe() { return m_Skins; }
|
||||||
int Find(const char *pName);
|
const CSkin *FindOrNullptr(const char *pName);
|
||||||
|
const CSkin *Find(const char *pName);
|
||||||
|
|
||||||
bool IsDownloadingSkins() { return m_DownloadingSkins; }
|
bool IsDownloadingSkins() { return m_DownloadingSkins; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<CSkin> m_vSkins;
|
std::unordered_map<std::string_view, std::unique_ptr<CSkin>> m_Skins;
|
||||||
std::vector<CDownloadSkin> m_vDownloadSkins;
|
std::unordered_map<std::string_view, std::unique_ptr<CDownloadSkin>> m_DownloadSkins;
|
||||||
size_t m_DownloadingSkins = 0;
|
size_t m_DownloadingSkins = 0;
|
||||||
char m_aEventSkinPrefix[24];
|
char m_aEventSkinPrefix[24];
|
||||||
|
|
||||||
bool LoadSkinPNG(CImageInfo &Info, const char *pName, const char *pPath, int DirType);
|
bool LoadSkinPNG(CImageInfo &Info, const char *pName, const char *pPath, int DirType);
|
||||||
int LoadSkin(const char *pName, const char *pPath, int DirType);
|
const CSkin *LoadSkin(const char *pName, const char *pPath, int DirType);
|
||||||
int LoadSkin(const char *pName, CImageInfo &Info);
|
const CSkin *LoadSkin(const char *pName, CImageInfo &Info);
|
||||||
int FindImpl(const char *pName);
|
const CSkin *FindImpl(const char *pName);
|
||||||
static int SkinScan(const char *pName, int IsDir, int DirType, void *pUser);
|
static int SkinScan(const char *pName, int IsDir, int DirType, void *pUser);
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1009,15 +1009,16 @@ static CGameInfo GetGameInfo(const CNetObj_GameInfoEx *pInfoEx, int InfoExSize,
|
||||||
bool FDDrace;
|
bool FDDrace;
|
||||||
if(Version < 1)
|
if(Version < 1)
|
||||||
{
|
{
|
||||||
Race = IsRace(pFallbackServerInfo);
|
const char *pGameType = pFallbackServerInfo->m_aGameType;
|
||||||
FastCap = IsFastCap(pFallbackServerInfo);
|
Race = str_find_nocase(pGameType, "race") || str_find_nocase(pGameType, "fastcap");
|
||||||
FNG = IsFNG(pFallbackServerInfo);
|
FastCap = str_find_nocase(pGameType, "fastcap");
|
||||||
DDRace = IsDDRace(pFallbackServerInfo);
|
FNG = str_find_nocase(pGameType, "fng");
|
||||||
DDNet = IsDDNet(pFallbackServerInfo);
|
DDRace = str_find_nocase(pGameType, "ddrace") || str_find_nocase(pGameType, "mkrace");
|
||||||
BlockWorlds = IsBlockWorlds(pFallbackServerInfo);
|
DDNet = str_find_nocase(pGameType, "ddracenet") || str_find_nocase(pGameType, "ddnet");
|
||||||
City = IsCity(pFallbackServerInfo);
|
BlockWorlds = str_startswith(pGameType, "bw ") || str_comp_nocase(pGameType, "bw") == 0;
|
||||||
Vanilla = IsVanilla(pFallbackServerInfo);
|
City = str_find_nocase(pGameType, "city");
|
||||||
Plus = IsPlus(pFallbackServerInfo);
|
Vanilla = str_comp(pGameType, "DM") == 0 || str_comp(pGameType, "TDM") == 0 || str_comp(pGameType, "CTF") == 0;
|
||||||
|
Plus = str_find(pGameType, "+");
|
||||||
FDDrace = false;
|
FDDrace = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -1227,7 +1228,7 @@ void CGameClient::OnNewSnapshot()
|
||||||
pClient->m_SkinInfo.m_Size = 64;
|
pClient->m_SkinInfo.m_Size = 64;
|
||||||
|
|
||||||
// find new skin
|
// find new skin
|
||||||
const CSkin *pSkin = m_Skins.Get(m_Skins.Find(pClient->m_aSkinName));
|
const CSkin *pSkin = m_Skins.Find(pClient->m_aSkinName);
|
||||||
pClient->m_SkinInfo.m_OriginalRenderSkin = pSkin->m_OriginalSkin;
|
pClient->m_SkinInfo.m_OriginalRenderSkin = pSkin->m_OriginalSkin;
|
||||||
pClient->m_SkinInfo.m_ColorableRenderSkin = pSkin->m_ColorableSkin;
|
pClient->m_SkinInfo.m_ColorableRenderSkin = pSkin->m_ColorableSkin;
|
||||||
pClient->m_SkinInfo.m_SkinMetrics = pSkin->m_Metrics;
|
pClient->m_SkinInfo.m_SkinMetrics = pSkin->m_Metrics;
|
||||||
|
@ -3185,7 +3186,7 @@ void CGameClient::RefindSkins()
|
||||||
Client.m_SkinInfo.m_ColorableRenderSkin.Reset();
|
Client.m_SkinInfo.m_ColorableRenderSkin.Reset();
|
||||||
if(Client.m_aSkinName[0] != '\0')
|
if(Client.m_aSkinName[0] != '\0')
|
||||||
{
|
{
|
||||||
const CSkin *pSkin = m_Skins.Get(m_Skins.Find(Client.m_aSkinName));
|
const CSkin *pSkin = m_Skins.Find(Client.m_aSkinName);
|
||||||
Client.m_SkinInfo.m_OriginalRenderSkin = pSkin->m_OriginalSkin;
|
Client.m_SkinInfo.m_OriginalRenderSkin = pSkin->m_OriginalSkin;
|
||||||
Client.m_SkinInfo.m_ColorableRenderSkin = pSkin->m_ColorableSkin;
|
Client.m_SkinInfo.m_ColorableRenderSkin = pSkin->m_ColorableSkin;
|
||||||
Client.UpdateRenderInfo(IsTeamPlay());
|
Client.UpdateRenderInfo(IsTeamPlay());
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#ifndef GAME_CLIENT_SKIN_H
|
#ifndef GAME_CLIENT_SKIN_H
|
||||||
#define GAME_CLIENT_SKIN_H
|
#define GAME_CLIENT_SKIN_H
|
||||||
#include <base/color.h>
|
#include <base/color.h>
|
||||||
|
#include <base/system.h>
|
||||||
#include <base/vmath.h>
|
#include <base/vmath.h>
|
||||||
#include <engine/graphics.h>
|
#include <engine/graphics.h>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
@ -8,6 +9,10 @@
|
||||||
// do this better and nicer
|
// do this better and nicer
|
||||||
struct CSkin
|
struct CSkin
|
||||||
{
|
{
|
||||||
|
private:
|
||||||
|
char m_aName[24];
|
||||||
|
|
||||||
|
public:
|
||||||
struct SSkinTextures
|
struct SSkinTextures
|
||||||
{
|
{
|
||||||
IGraphics::CTextureHandle m_Body;
|
IGraphics::CTextureHandle m_Body;
|
||||||
|
@ -36,7 +41,6 @@ struct CSkin
|
||||||
|
|
||||||
SSkinTextures m_OriginalSkin;
|
SSkinTextures m_OriginalSkin;
|
||||||
SSkinTextures m_ColorableSkin;
|
SSkinTextures m_ColorableSkin;
|
||||||
char m_aName[24];
|
|
||||||
ColorRGBA m_BloodColor;
|
ColorRGBA m_BloodColor;
|
||||||
|
|
||||||
template<bool IsSizeType>
|
template<bool IsSizeType>
|
||||||
|
@ -129,6 +133,15 @@ struct CSkin
|
||||||
|
|
||||||
bool operator<(const CSkin &Other) const { return str_comp(m_aName, Other.m_aName) < 0; }
|
bool operator<(const CSkin &Other) const { return str_comp(m_aName, Other.m_aName) < 0; }
|
||||||
bool operator==(const CSkin &Other) const { return !str_comp(m_aName, Other.m_aName); }
|
bool operator==(const CSkin &Other) const { return !str_comp(m_aName, Other.m_aName); }
|
||||||
|
|
||||||
|
CSkin(const char *pName)
|
||||||
|
{
|
||||||
|
str_copy(m_aName, pName);
|
||||||
|
}
|
||||||
|
CSkin(CSkin &&) = default;
|
||||||
|
CSkin &operator=(CSkin &&) = default;
|
||||||
|
|
||||||
|
const char *GetName() const { return m_aName; }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue