2010-11-20 10:37:14 +00:00
|
|
|
/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
|
|
|
|
/* If you are missing that file, acquire a complete release at teeworlds.com. */
|
2008-03-17 01:41:11 +00:00
|
|
|
#include <math.h>
|
2008-08-14 17:19:13 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
#include <base/math.h>
|
2020-09-26 19:41:58 +00:00
|
|
|
#include <base/system.h>
|
2019-09-30 13:03:37 +00:00
|
|
|
#include <ctime>
|
2008-08-14 17:19:13 +00:00
|
|
|
|
2020-09-20 00:19:24 +00:00
|
|
|
#include <engine/engine.h>
|
2010-05-29 07:25:38 +00:00
|
|
|
#include <engine/graphics.h>
|
2020-09-19 23:49:26 +00:00
|
|
|
#include <engine/shared/config.h>
|
2020-09-20 00:19:32 +00:00
|
|
|
#include <engine/storage.h>
|
2008-10-21 18:05:06 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
#include "skins.h"
|
2008-10-21 18:05:06 +00:00
|
|
|
|
2018-07-24 15:26:39 +00:00
|
|
|
static const char *VANILLA_SKINS[] = {"bluekitty", "bluestripe", "brownbear",
|
|
|
|
"cammo", "cammostripes", "coala", "default", "limekitty",
|
|
|
|
"pinky", "redbopp", "redstripe", "saddo", "toptri",
|
2020-06-21 15:48:33 +00:00
|
|
|
"twinbop", "twintri", "warpaint", "x_ninja", "x_spec"};
|
2014-08-17 03:34:16 +00:00
|
|
|
|
2018-07-24 15:26:39 +00:00
|
|
|
static bool IsVanillaSkin(const char *pName)
|
2007-11-18 12:03:59 +00:00
|
|
|
{
|
2018-07-24 15:26:39 +00:00
|
|
|
for(unsigned int i = 0; i < sizeof(VANILLA_SKINS) / sizeof(VANILLA_SKINS[0]); i++)
|
2014-08-17 03:34:16 +00:00
|
|
|
{
|
2018-07-24 15:26:39 +00:00
|
|
|
if(str_comp(pName, VANILLA_SKINS[i]) == 0)
|
2014-08-17 03:34:16 +00:00
|
|
|
{
|
2018-07-24 15:26:39 +00:00
|
|
|
return true;
|
2014-08-17 03:34:16 +00:00
|
|
|
}
|
|
|
|
}
|
2018-07-24 15:26:39 +00:00
|
|
|
return false;
|
|
|
|
}
|
2014-08-17 03:34:16 +00:00
|
|
|
|
2018-07-24 15:26:39 +00:00
|
|
|
int CSkins::SkinScan(const char *pName, int IsDir, int DirType, void *pUser)
|
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
CSkins *pSelf = (CSkins *)pUser;
|
2014-11-25 19:13:40 +00:00
|
|
|
|
2018-07-25 08:29:05 +00:00
|
|
|
if(IsDir || !str_endswith(pName, ".png"))
|
2011-02-21 10:23:30 +00:00
|
|
|
return 0;
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2018-07-25 08:29:05 +00:00
|
|
|
char aNameWithoutPng[128];
|
|
|
|
str_copy(aNameWithoutPng, pName, sizeof(aNameWithoutPng));
|
|
|
|
aNameWithoutPng[str_length(aNameWithoutPng) - 4] = 0;
|
2018-07-24 15:26:39 +00:00
|
|
|
|
2014-11-25 19:13:40 +00:00
|
|
|
// Don't add duplicate skins (one from user's config directory, other from
|
|
|
|
// client itself)
|
|
|
|
for(int i = 0; i < pSelf->Num(); i++)
|
|
|
|
{
|
2018-07-24 15:26:39 +00:00
|
|
|
const char *pExName = pSelf->Get(i)->m_aName;
|
2018-07-25 08:29:05 +00:00
|
|
|
if(str_comp(pExName, aNameWithoutPng) == 0)
|
2014-11-25 19:13:40 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-09-20 00:19:24 +00:00
|
|
|
char aBuf[MAX_PATH_LENGTH];
|
2020-09-19 23:51:23 +00:00
|
|
|
str_format(aBuf, sizeof(aBuf), "skins/%s", pName);
|
2020-09-20 00:19:24 +00:00
|
|
|
return pSelf->LoadSkin(aNameWithoutPng, aBuf, DirType);
|
|
|
|
}
|
|
|
|
|
2020-10-09 07:07:05 +00:00
|
|
|
int CSkins::LoadSkin(const char *pName, const char *pPath, int DirType, int *pGetSkinID)
|
2020-09-20 00:19:24 +00:00
|
|
|
{
|
|
|
|
char aBuf[512];
|
2010-05-29 07:25:38 +00:00
|
|
|
CImageInfo Info;
|
2020-09-20 00:19:24 +00:00
|
|
|
if(!Graphics()->LoadPNG(&Info, pPath, DirType))
|
2007-11-18 12:03:59 +00:00
|
|
|
{
|
2010-08-17 22:06:00 +00:00
|
|
|
str_format(aBuf, sizeof(aBuf), "failed to load skin from %s", pName);
|
2020-09-20 00:19:24 +00:00
|
|
|
Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "game", aBuf);
|
2011-02-21 10:23:30 +00:00
|
|
|
return 0;
|
2007-11-18 12:03:59 +00:00
|
|
|
}
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2010-09-18 18:48:49 +00:00
|
|
|
CSkin Skin;
|
2020-09-20 00:19:24 +00:00
|
|
|
Skin.m_IsVanilla = IsVanillaSkin(pName);
|
2020-10-09 07:07:05 +00:00
|
|
|
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_Feet = Graphics()->LoadSpriteTexture(Info, &g_pData->m_aSprites[SPRITE_TEE_FOOT]);
|
|
|
|
Skin.m_OriginalSkin.m_FeetOutline = Graphics()->LoadSpriteTexture(Info, &g_pData->m_aSprites[SPRITE_TEE_FOOT_OUTLINE]);
|
|
|
|
Skin.m_OriginalSkin.m_Hands = Graphics()->LoadSpriteTexture(Info, &g_pData->m_aSprites[SPRITE_TEE_HAND]);
|
|
|
|
Skin.m_OriginalSkin.m_HandsOutline = Graphics()->LoadSpriteTexture(Info, &g_pData->m_aSprites[SPRITE_TEE_HAND_OUTLINE]);
|
|
|
|
|
|
|
|
for(int i = 0; i < 6; ++i)
|
|
|
|
Skin.m_OriginalSkin.m_Eyes[i] = Graphics()->LoadSpriteTexture(Info, &g_pData->m_aSprites[SPRITE_TEE_EYE_NORMAL + i]);
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
int BodySize = 96; // body size
|
2020-09-26 19:41:58 +00:00
|
|
|
if(BodySize > Info.m_Height)
|
2016-01-17 08:48:21 +00:00
|
|
|
return 0;
|
2010-05-29 07:25:38 +00:00
|
|
|
unsigned char *d = (unsigned char *)Info.m_pData;
|
2020-09-26 19:41:58 +00:00
|
|
|
int Pitch = Info.m_Width * 4;
|
2008-03-17 01:41:11 +00:00
|
|
|
|
|
|
|
// dig out blood color
|
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
int aColors[3] = {0};
|
|
|
|
for(int y = 0; y < BodySize; y++)
|
|
|
|
for(int x = 0; x < BodySize; x++)
|
2008-03-17 01:41:11 +00:00
|
|
|
{
|
2020-09-26 19:41:58 +00:00
|
|
|
if(d[y * Pitch + x * 4 + 3] > 128)
|
2008-03-17 01:41:11 +00:00
|
|
|
{
|
2020-09-26 19:41:58 +00:00
|
|
|
aColors[0] += d[y * Pitch + x * 4 + 0];
|
|
|
|
aColors[1] += d[y * Pitch + x * 4 + 1];
|
|
|
|
aColors[2] += d[y * Pitch + x * 4 + 2];
|
2008-03-17 01:41:11 +00:00
|
|
|
}
|
|
|
|
}
|
2020-10-17 15:59:18 +00:00
|
|
|
if(aColors[0] != 0 && aColors[1] != 0 && aColors[2] != 0)
|
|
|
|
Skin.m_BloodColor = ColorRGBA(normalize(vec3(aColors[0], aColors[1], aColors[2])));
|
|
|
|
else
|
|
|
|
Skin.m_BloodColor = ColorRGBA(0, 0, 0, 1);
|
2008-03-17 01:41:11 +00:00
|
|
|
}
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2008-03-17 01:41:11 +00:00
|
|
|
// create colorless version
|
2010-05-29 07:25:38 +00:00
|
|
|
int Step = Info.m_Format == CImageInfo::FORMAT_RGBA ? 4 : 3;
|
2008-03-23 12:36:24 +00:00
|
|
|
|
|
|
|
// make the texture gray scale
|
2020-09-26 19:41:58 +00:00
|
|
|
for(int i = 0; i < Info.m_Width * Info.m_Height; i++)
|
2007-11-18 12:03:59 +00:00
|
|
|
{
|
2020-09-26 19:41:58 +00:00
|
|
|
int v = (d[i * Step] + d[i * Step + 1] + d[i * Step + 2]) / 3;
|
|
|
|
d[i * Step] = v;
|
|
|
|
d[i * Step + 1] = v;
|
|
|
|
d[i * Step + 2] = v;
|
2007-11-18 12:03:59 +00:00
|
|
|
}
|
2008-03-17 01:41:11 +00:00
|
|
|
|
2011-02-13 12:58:59 +00:00
|
|
|
int Freq[256] = {0};
|
|
|
|
int OrgWeight = 0;
|
|
|
|
int NewWeight = 192;
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2011-02-13 12:58:59 +00:00
|
|
|
// find most common frequence
|
|
|
|
for(int y = 0; y < BodySize; y++)
|
|
|
|
for(int x = 0; x < BodySize; x++)
|
2007-11-26 22:26:33 +00:00
|
|
|
{
|
2020-09-26 19:41:58 +00:00
|
|
|
if(d[y * Pitch + x * 4 + 3] > 128)
|
|
|
|
Freq[d[y * Pitch + x * 4]]++;
|
2007-11-26 22:26:33 +00:00
|
|
|
}
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2011-02-13 12:58:59 +00:00
|
|
|
for(int i = 1; i < 256; i++)
|
|
|
|
{
|
|
|
|
if(Freq[OrgWeight] < Freq[i])
|
|
|
|
OrgWeight = i;
|
2007-11-26 22:26:33 +00:00
|
|
|
}
|
2011-02-13 12:58:59 +00:00
|
|
|
|
|
|
|
// reorder
|
2020-09-26 19:41:58 +00:00
|
|
|
int InvOrgWeight = 255 - OrgWeight;
|
|
|
|
int InvNewWeight = 255 - NewWeight;
|
2011-02-13 12:58:59 +00:00
|
|
|
for(int y = 0; y < BodySize; y++)
|
|
|
|
for(int x = 0; x < BodySize; x++)
|
|
|
|
{
|
2020-09-26 19:41:58 +00:00
|
|
|
int v = d[y * Pitch + x * 4];
|
2020-10-12 10:31:43 +00:00
|
|
|
if(v <= OrgWeight && OrgWeight == 0)
|
Don't divide by 0 in LoadSkin
src/game/client/components/skins.cpp:142:14: runtime error: -nan is outside the range of representable values of type 'int'
#0 0x55b6bd0f49e1 in CSkins::LoadSkin(char const*, char const*, int, int*) /media/ddnet/src/game/client/components/skins.cpp:142:14
#1 0x55b6bd0f0942 in CSkins::SkinScan(char const*, int, int, void*) /media/ddnet/src/game/client/components/skins.cpp:55:16
#2 0x55b6bcb33928 in fs_listdir /media/ddnet/src/base/system.c:2033:6
#3 0x55b6bcb04024 in CStorage::ListDirectory(int, char const*, int (*)(char const*, int, int, void*), void*) /media/ddnet/src/engine/shared/storage.cpp:316:5
#4 0x55b6bd0f9e2f in CSkins::Refresh() /media/ddnet/src/game/client/components/skins.cpp:222:13
#5 0x55b6bd0f6e33 in CSkins::OnInit() /media/ddnet/src/game/client/components/skins.cpp:194:2
#6 0x55b6bd14c63f in CGameClient::OnInit() /media/ddnet/src/game/client/gameclient.cpp:322:28
#7 0x55b6bcc5f9f8 in CClient::Run() /media/ddnet/src/engine/client/client.cpp:3089:16
#8 0x55b6bcc84b7e in main /media/ddnet/src/engine/client/client.cpp:4341:11
#9 0x7f1144ded151 in __libc_start_main (/usr/lib/libc.so.6+0x28151)
#10 0x55b6bc9d1e0d in _start (/media/ddnet/DDNet+0x705e0d)
2020-10-10 10:14:07 +00:00
|
|
|
v = 0;
|
|
|
|
else if(v <= OrgWeight)
|
2020-09-26 19:41:58 +00:00
|
|
|
v = (int)(((v / (float)OrgWeight) * NewWeight));
|
Don't divide by 0 in LoadSkin
src/game/client/components/skins.cpp:142:14: runtime error: -nan is outside the range of representable values of type 'int'
#0 0x55b6bd0f49e1 in CSkins::LoadSkin(char const*, char const*, int, int*) /media/ddnet/src/game/client/components/skins.cpp:142:14
#1 0x55b6bd0f0942 in CSkins::SkinScan(char const*, int, int, void*) /media/ddnet/src/game/client/components/skins.cpp:55:16
#2 0x55b6bcb33928 in fs_listdir /media/ddnet/src/base/system.c:2033:6
#3 0x55b6bcb04024 in CStorage::ListDirectory(int, char const*, int (*)(char const*, int, int, void*), void*) /media/ddnet/src/engine/shared/storage.cpp:316:5
#4 0x55b6bd0f9e2f in CSkins::Refresh() /media/ddnet/src/game/client/components/skins.cpp:222:13
#5 0x55b6bd0f6e33 in CSkins::OnInit() /media/ddnet/src/game/client/components/skins.cpp:194:2
#6 0x55b6bd14c63f in CGameClient::OnInit() /media/ddnet/src/game/client/gameclient.cpp:322:28
#7 0x55b6bcc5f9f8 in CClient::Run() /media/ddnet/src/engine/client/client.cpp:3089:16
#8 0x55b6bcc84b7e in main /media/ddnet/src/engine/client/client.cpp:4341:11
#9 0x7f1144ded151 in __libc_start_main (/usr/lib/libc.so.6+0x28151)
#10 0x55b6bc9d1e0d in _start (/media/ddnet/DDNet+0x705e0d)
2020-10-10 10:14:07 +00:00
|
|
|
else if(InvOrgWeight == 0)
|
|
|
|
v = NewWeight;
|
2011-02-13 12:58:59 +00:00
|
|
|
else
|
2020-09-26 19:41:58 +00:00
|
|
|
v = (int)(((v - OrgWeight) / (float)InvOrgWeight) * InvNewWeight + NewWeight);
|
|
|
|
d[y * Pitch + x * 4] = v;
|
|
|
|
d[y * Pitch + x * 4 + 1] = v;
|
|
|
|
d[y * Pitch + x * 4 + 2] = v;
|
2011-02-13 12:58:59 +00:00
|
|
|
}
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2020-10-09 07:07:05 +00:00
|
|
|
Skin.m_ColorableSkin.m_Body = Graphics()->LoadSpriteTexture(Info, &g_pData->m_aSprites[SPRITE_TEE_BODY]);
|
|
|
|
Skin.m_ColorableSkin.m_BodyOutline = Graphics()->LoadSpriteTexture(Info, &g_pData->m_aSprites[SPRITE_TEE_BODY_OUTLINE]);
|
|
|
|
Skin.m_ColorableSkin.m_Feet = Graphics()->LoadSpriteTexture(Info, &g_pData->m_aSprites[SPRITE_TEE_FOOT]);
|
|
|
|
Skin.m_ColorableSkin.m_FeetOutline = Graphics()->LoadSpriteTexture(Info, &g_pData->m_aSprites[SPRITE_TEE_FOOT_OUTLINE]);
|
|
|
|
Skin.m_ColorableSkin.m_Hands = Graphics()->LoadSpriteTexture(Info, &g_pData->m_aSprites[SPRITE_TEE_HAND]);
|
|
|
|
Skin.m_ColorableSkin.m_HandsOutline = Graphics()->LoadSpriteTexture(Info, &g_pData->m_aSprites[SPRITE_TEE_HAND_OUTLINE]);
|
|
|
|
|
|
|
|
for(int i = 0; i < 6; ++i)
|
|
|
|
Skin.m_ColorableSkin.m_Eyes[i] = Graphics()->LoadSpriteTexture(Info, &g_pData->m_aSprites[SPRITE_TEE_EYE_NORMAL + i]);
|
|
|
|
|
2018-04-09 09:56:39 +00:00
|
|
|
free(Info.m_pData);
|
2007-11-18 12:03:59 +00:00
|
|
|
|
2011-04-13 18:37:12 +00:00
|
|
|
// set skin data
|
2020-09-20 00:19:24 +00:00
|
|
|
str_copy(Skin.m_aName, pName, sizeof(Skin.m_aName));
|
2011-12-10 17:23:29 +00:00
|
|
|
if(g_Config.m_Debug)
|
|
|
|
{
|
|
|
|
str_format(aBuf, sizeof(aBuf), "load skin %s", Skin.m_aName);
|
2020-09-20 00:19:24 +00:00
|
|
|
Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "game", aBuf);
|
2011-12-10 17:23:29 +00:00
|
|
|
}
|
2020-09-20 00:19:24 +00:00
|
|
|
m_aSkins.add(Skin);
|
2011-02-21 10:23:30 +00:00
|
|
|
|
2020-10-09 07:07:05 +00:00
|
|
|
if(pGetSkinID)
|
|
|
|
*pGetSkinID = m_aSkins.size() - 1;
|
|
|
|
|
2011-02-21 10:23:30 +00:00
|
|
|
return 0;
|
2007-11-18 12:03:59 +00:00
|
|
|
}
|
|
|
|
|
2011-02-13 12:58:59 +00:00
|
|
|
void CSkins::OnInit()
|
2007-11-18 12:03:59 +00:00
|
|
|
{
|
2018-12-23 21:53:10 +00:00
|
|
|
m_EventSkinPrefix[0] = '\0';
|
|
|
|
|
|
|
|
if(g_Config.m_Events)
|
|
|
|
{
|
|
|
|
time_t rawtime;
|
2020-09-26 19:41:58 +00:00
|
|
|
struct tm *timeinfo;
|
2019-09-30 13:03:37 +00:00
|
|
|
std::time(&rawtime);
|
2018-12-23 21:53:10 +00:00
|
|
|
timeinfo = localtime(&rawtime);
|
|
|
|
if(timeinfo->tm_mon == 11 && timeinfo->tm_mday >= 24 && timeinfo->tm_mday <= 26)
|
|
|
|
{ // Christmas
|
|
|
|
str_copy(m_EventSkinPrefix, "santa", sizeof(m_EventSkinPrefix));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-11-18 12:03:59 +00:00
|
|
|
// load skins
|
2020-10-06 14:00:18 +00:00
|
|
|
Refresh();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CSkins::Refresh()
|
|
|
|
{
|
|
|
|
for(int i = 0; i < m_aSkins.size(); ++i)
|
|
|
|
{
|
2020-10-09 07:07:05 +00:00
|
|
|
Graphics()->UnloadTextureNew(m_aSkins[i].m_OriginalSkin.m_Body);
|
|
|
|
Graphics()->UnloadTextureNew(m_aSkins[i].m_OriginalSkin.m_BodyOutline);
|
|
|
|
Graphics()->UnloadTextureNew(m_aSkins[i].m_OriginalSkin.m_Feet);
|
|
|
|
Graphics()->UnloadTextureNew(m_aSkins[i].m_OriginalSkin.m_FeetOutline);
|
|
|
|
Graphics()->UnloadTextureNew(m_aSkins[i].m_OriginalSkin.m_Hands);
|
|
|
|
Graphics()->UnloadTextureNew(m_aSkins[i].m_OriginalSkin.m_HandsOutline);
|
|
|
|
for(int n = 0; n < 6; ++n)
|
|
|
|
Graphics()->UnloadTextureNew(m_aSkins[i].m_OriginalSkin.m_Eyes[n]);
|
|
|
|
|
|
|
|
Graphics()->UnloadTextureNew(m_aSkins[i].m_ColorableSkin.m_Body);
|
|
|
|
Graphics()->UnloadTextureNew(m_aSkins[i].m_ColorableSkin.m_BodyOutline);
|
|
|
|
Graphics()->UnloadTextureNew(m_aSkins[i].m_ColorableSkin.m_Feet);
|
|
|
|
Graphics()->UnloadTextureNew(m_aSkins[i].m_ColorableSkin.m_FeetOutline);
|
|
|
|
Graphics()->UnloadTextureNew(m_aSkins[i].m_ColorableSkin.m_Hands);
|
|
|
|
Graphics()->UnloadTextureNew(m_aSkins[i].m_ColorableSkin.m_HandsOutline);
|
|
|
|
for(int n = 0; n < 6; ++n)
|
|
|
|
Graphics()->UnloadTextureNew(m_aSkins[i].m_ColorableSkin.m_Eyes[n]);
|
2020-10-06 14:00:18 +00:00
|
|
|
}
|
|
|
|
|
2010-09-18 18:48:49 +00:00
|
|
|
m_aSkins.clear();
|
2020-10-07 10:16:59 +00:00
|
|
|
m_aDownloadSkins.clear();
|
2010-05-29 07:25:38 +00:00
|
|
|
Storage()->ListDirectory(IStorage::TYPE_ALL, "skins", SkinScan, this);
|
2011-01-06 21:55:57 +00:00
|
|
|
if(!m_aSkins.size())
|
|
|
|
{
|
|
|
|
Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "gameclient", "failed to load skins. folder='skins/'");
|
|
|
|
CSkin DummySkin;
|
2018-07-25 12:13:07 +00:00
|
|
|
DummySkin.m_IsVanilla = true;
|
2011-01-06 21:55:57 +00:00
|
|
|
str_copy(DummySkin.m_aName, "dummy", sizeof(DummySkin.m_aName));
|
2019-04-26 12:06:32 +00:00
|
|
|
DummySkin.m_BloodColor = ColorRGBA(1.0f, 1.0f, 1.0f);
|
2011-01-06 21:55:57 +00:00
|
|
|
m_aSkins.add(DummySkin);
|
|
|
|
}
|
2007-11-18 12:03:59 +00:00
|
|
|
}
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
int CSkins::Num()
|
2007-11-18 12:03:59 +00:00
|
|
|
{
|
2011-04-13 18:37:12 +00:00
|
|
|
return m_aSkins.size();
|
2007-11-18 12:03:59 +00:00
|
|
|
}
|
|
|
|
|
2020-10-09 07:07:05 +00:00
|
|
|
const CSkin *CSkins::Get(int Index)
|
2007-11-18 12:03:59 +00:00
|
|
|
{
|
2018-07-25 20:41:24 +00:00
|
|
|
if(Index < 0)
|
|
|
|
{
|
|
|
|
Index = Find("default");
|
|
|
|
|
2020-09-26 19:41:58 +00:00
|
|
|
if(Index < 0)
|
2018-07-25 20:41:24 +00:00
|
|
|
Index = 0;
|
|
|
|
}
|
|
|
|
return &m_aSkins[Index % m_aSkins.size()];
|
2007-11-18 12:03:59 +00:00
|
|
|
}
|
|
|
|
|
2020-09-04 14:40:35 +00:00
|
|
|
int CSkins::Find(const char *pName)
|
2007-11-18 12:03:59 +00:00
|
|
|
{
|
2018-12-23 21:53:10 +00:00
|
|
|
const char *pSkinPrefix = m_EventSkinPrefix[0] ? m_EventSkinPrefix : g_Config.m_ClSkinPrefix;
|
2018-08-21 16:27:34 +00:00
|
|
|
if(g_Config.m_ClVanillaSkinsOnly && !IsVanillaSkin(pName))
|
2017-07-24 22:11:25 +00:00
|
|
|
{
|
2018-08-21 16:27:34 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2020-09-20 00:19:24 +00:00
|
|
|
else if(pSkinPrefix && pSkinPrefix[0])
|
2018-08-21 16:27:34 +00:00
|
|
|
{
|
2020-09-20 00:19:02 +00:00
|
|
|
char aBuf[24];
|
2018-12-23 21:53:10 +00:00
|
|
|
str_format(aBuf, sizeof(aBuf), "%s_%s", pSkinPrefix, pName);
|
2018-08-21 16:27:34 +00:00
|
|
|
// If we find something, use it, otherwise fall back to normal skins.
|
|
|
|
int Result = FindImpl(aBuf);
|
2018-08-21 16:29:25 +00:00
|
|
|
if(Result != -1)
|
2018-08-13 18:54:01 +00:00
|
|
|
{
|
2018-08-21 16:27:34 +00:00
|
|
|
return Result;
|
2017-07-24 22:11:25 +00:00
|
|
|
}
|
|
|
|
}
|
2018-07-24 15:26:39 +00:00
|
|
|
return FindImpl(pName);
|
|
|
|
}
|
|
|
|
|
2020-09-04 14:40:35 +00:00
|
|
|
int CSkins::FindImpl(const char *pName)
|
2018-07-24 15:26:39 +00:00
|
|
|
{
|
2020-09-04 14:40:35 +00:00
|
|
|
auto r = ::find_binary(m_aSkins.all(), pName);
|
2020-09-20 00:19:24 +00:00
|
|
|
if(!r.empty())
|
|
|
|
return &r.front() - m_aSkins.base_ptr();
|
|
|
|
|
|
|
|
if(str_comp(pName, "default") == 0)
|
2020-09-04 14:40:35 +00:00
|
|
|
return -1;
|
|
|
|
|
2020-09-20 00:19:24 +00:00
|
|
|
if(!g_Config.m_ClDownloadSkins)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if(str_find(pName, "/") != 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
auto d = ::find_binary(m_aDownloadSkins.all(), pName);
|
|
|
|
if(!d.empty())
|
|
|
|
{
|
2020-10-09 07:07:05 +00:00
|
|
|
int SkinID = -1;
|
2020-09-20 00:19:24 +00:00
|
|
|
if(d.front().m_pTask && d.front().m_pTask->State() == HTTP_DONE)
|
|
|
|
{
|
|
|
|
char aPath[MAX_PATH_LENGTH];
|
|
|
|
str_format(aPath, sizeof(aPath), "downloadedskins/%s.png", d.front().m_aName);
|
|
|
|
Storage()->RenameFile(d.front().m_aPath, aPath, IStorage::TYPE_SAVE);
|
2020-10-09 07:07:05 +00:00
|
|
|
LoadSkin(d.front().m_aName, aPath, IStorage::TYPE_SAVE, &SkinID);
|
2020-09-20 00:19:24 +00:00
|
|
|
d.front().m_pTask = nullptr;
|
|
|
|
}
|
2020-09-18 21:06:35 +00:00
|
|
|
if(d.front().m_pTask && (d.front().m_pTask->State() == HTTP_ERROR || d.front().m_pTask->State() == HTTP_ABORTED))
|
2020-09-20 00:19:24 +00:00
|
|
|
{
|
|
|
|
d.front().m_pTask = nullptr;
|
|
|
|
}
|
2020-10-09 07:07:05 +00:00
|
|
|
return SkinID;
|
2020-09-20 00:19:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
CDownloadSkin Skin;
|
|
|
|
str_copy(Skin.m_aName, pName, sizeof(Skin.m_aName));
|
|
|
|
|
|
|
|
char aUrl[256];
|
|
|
|
str_format(aUrl, sizeof(aUrl), "%s%s.png", g_Config.m_ClSkinDownloadUrl, pName);
|
|
|
|
str_format(Skin.m_aPath, sizeof(Skin.m_aPath), "downloadedskins/%s.%d.tmp", pName, pid());
|
2020-09-22 13:10:35 +00:00
|
|
|
Skin.m_pTask = std::make_shared<CGetFile>(Storage(), aUrl, Skin.m_aPath, IStorage::TYPE_SAVE, CTimeout{0, 0, 0}, false);
|
2020-09-20 00:19:24 +00:00
|
|
|
m_pClient->Engine()->AddJob(Skin.m_pTask);
|
|
|
|
m_aDownloadSkins.add(Skin);
|
|
|
|
return -1;
|
2007-11-18 12:03:59 +00:00
|
|
|
}
|