mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-15 04:28:20 +00:00
Refactor CSkins7
accessor functions and 0.7 skin json parsing
- Combine `CSkins7::FindSkinPart` and `CSkins7::GetSkinPart` functions into `CSkins7::FindSkinPart` function to simplify the usage. - Replace `CSkins7::Num` and `CSkins7::Get` functions with `CSkins7::GetSkins` function to return all skins to improve readability using for-each loops. - Replace `CSkins7::NumSkinPart` and `CSkins7::GetSkinPart` functions with `CSkins7::GetSkinParts` function to return all skin parts to improve readability using for-each loops. - Add `CSkins7::FindSkinPartOrNullptr` function to find a skin by name or return `nullptr` if it's not found. Let the `CSkins7::FindSkinPart` function return the desired part, then the default part, and lastly the placeholder part. - Add `CSkins7::FindDefaultSkinPart` function to find the default skin part or placeholder skin part (never `nullptr`). - Remove redundant check for duplicate skin parts. This is already prevented by the `IStorage::ListDirectory` function. - Remove separate placeholder skin that was being used to initialized every loaded and created skin. - Remove unused `CSkins7::GetInitAmount` function. - Add `CSkins7::InitPlaceholderSkinParts` function to initialize the placeholder skin parts. Keep placeholder skin parts separate from normal skin parts, i.e. not in the vectors of parts. - Rename `CSkins7::AddSkin` function to `AddSkinFromConfigVariables` for clarity about its behavior. - Fix `CSkins7::RandomizeSkin` function not terminating if there exist only special skin parts for any part type. - Add `CSkins7::XmasHatTexture` and `CSkins7::BotDecorationTexture` getter functions instead of exposing the respective member variables. - Improve validation when parsing 0.7 skin json format. Fail loading and log error messages on invalid skin json files instead of silently loading incorrect/incomplete skins.
This commit is contained in:
parent
15cd607a2d
commit
f0c9faf654
|
@ -116,8 +116,7 @@ void CMenus::RenderSettingsTee7(CUIRect MainView)
|
||||||
OwnSkinInfo.m_Size = 50.0f;
|
OwnSkinInfo.m_Size = 50.0f;
|
||||||
for(int Part = 0; Part < protocol7::NUM_SKINPARTS; Part++)
|
for(int Part = 0; Part < protocol7::NUM_SKINPARTS; Part++)
|
||||||
{
|
{
|
||||||
int SkinPart = m_pClient->m_Skins7.FindSkinPart(Part, apSkinPartsPtr[Part], false);
|
const CSkins7::CSkinPart *pSkinPart = m_pClient->m_Skins7.FindSkinPart(Part, apSkinPartsPtr[Part], false);
|
||||||
const CSkins7::CSkinPart *pSkinPart = m_pClient->m_Skins7.GetSkinPart(Part, SkinPart);
|
|
||||||
if(aUCCVars[Part])
|
if(aUCCVars[Part])
|
||||||
{
|
{
|
||||||
OwnSkinInfo.m_aSixup[g_Config.m_ClDummy].m_aTextures[Part] = pSkinPart->m_ColorTexture;
|
OwnSkinInfo.m_aSixup[g_Config.m_ClDummy].m_aTextures[Part] = pSkinPart->m_ColorTexture;
|
||||||
|
@ -160,21 +159,12 @@ void CMenus::RenderSettingsTee7(CUIRect MainView)
|
||||||
}
|
}
|
||||||
m_pClient->m_Skins7.ValidateSkinParts(apSkinPartsPtr, aUCCVars, aColorVars, GAMEFLAG_TEAMS);
|
m_pClient->m_Skins7.ValidateSkinParts(apSkinPartsPtr, aUCCVars, aColorVars, GAMEFLAG_TEAMS);
|
||||||
|
|
||||||
CTeeRenderInfo TeamSkinInfo = OwnSkinInfo;
|
CTeeRenderInfo TeamSkinInfo;
|
||||||
|
TeamSkinInfo.m_Size = OwnSkinInfo.m_Size;
|
||||||
for(int Part = 0; Part < protocol7::NUM_SKINPARTS; Part++)
|
for(int Part = 0; Part < protocol7::NUM_SKINPARTS; Part++)
|
||||||
{
|
{
|
||||||
int SkinPart = m_pClient->m_Skins7.FindSkinPart(Part, apSkinPartsPtr[Part], false);
|
const CSkins7::CSkinPart *pSkinPart = m_pClient->m_Skins7.FindSkinPart(Part, apSkinPartsPtr[Part], false);
|
||||||
const CSkins7::CSkinPart *pSkinPart = m_pClient->m_Skins7.GetSkinPart(Part, SkinPart);
|
TeamSkinInfo.m_aSixup[g_Config.m_ClDummy].m_aTextures[Part] = aUCCVars[Part] ? pSkinPart->m_ColorTexture : pSkinPart->m_OrgTexture;
|
||||||
if(aUCCVars[Part])
|
|
||||||
{
|
|
||||||
TeamSkinInfo.m_aSixup[g_Config.m_ClDummy].m_aTextures[Part] = pSkinPart->m_ColorTexture;
|
|
||||||
TeamSkinInfo.m_aSixup[g_Config.m_ClDummy].m_aColors[Part] = m_pClient->m_Skins7.GetColor(aColorVars[Part], Part == protocol7::SKINPART_MARKING);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
TeamSkinInfo.m_aSixup[g_Config.m_ClDummy].m_aTextures[Part] = pSkinPart->m_OrgTexture;
|
|
||||||
TeamSkinInfo.m_aSixup[g_Config.m_ClDummy].m_aColors[Part] = ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for(int Part = 0; Part < protocol7::NUM_SKINPARTS; Part++)
|
for(int Part = 0; Part < protocol7::NUM_SKINPARTS; Part++)
|
||||||
|
@ -327,22 +317,21 @@ void CMenus::RenderSkinSelection7(CUIRect MainView)
|
||||||
static float s_LastSelectionTime = -10.0f;
|
static float s_LastSelectionTime = -10.0f;
|
||||||
static std::vector<const CSkins7::CSkin *> s_vpSkinList;
|
static std::vector<const CSkins7::CSkin *> s_vpSkinList;
|
||||||
static CListBox s_ListBox;
|
static CListBox s_ListBox;
|
||||||
static int s_SkinCount = 0;
|
static size_t s_SkinCount = 0;
|
||||||
if(m_SkinListNeedsUpdate || m_pClient->m_Skins7.Num() != s_SkinCount)
|
|
||||||
|
const std::vector<CSkins7::CSkin> &vCurrentSkins = GameClient()->m_Skins7.GetSkins();
|
||||||
|
if(m_SkinListNeedsUpdate || vCurrentSkins.size() != s_SkinCount)
|
||||||
{
|
{
|
||||||
s_vpSkinList.clear();
|
s_vpSkinList.clear();
|
||||||
s_SkinCount = m_pClient->m_Skins7.Num();
|
s_SkinCount = vCurrentSkins.size();
|
||||||
for(int i = 0; i < s_SkinCount; ++i)
|
for(const CSkins7::CSkin &Skin : vCurrentSkins)
|
||||||
{
|
{
|
||||||
const CSkins7::CSkin *pSkin = m_pClient->m_Skins7.Get(i);
|
if((Skin.m_Flags & CSkins7::SKINFLAG_SPECIAL) != 0)
|
||||||
if(g_Config.m_ClSkinFilterString[0] != '\0' && !str_utf8_find_nocase(pSkin->m_aName, g_Config.m_ClSkinFilterString))
|
continue;
|
||||||
|
if(g_Config.m_ClSkinFilterString[0] != '\0' && !str_utf8_find_nocase(Skin.m_aName, g_Config.m_ClSkinFilterString))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// no special skins
|
s_vpSkinList.emplace_back(&Skin);
|
||||||
if((pSkin->m_Flags & CSkins7::SKINFLAG_SPECIAL) == 0)
|
|
||||||
{
|
|
||||||
s_vpSkinList.emplace_back(pSkin);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
m_SkinListNeedsUpdate = false;
|
m_SkinListNeedsUpdate = false;
|
||||||
}
|
}
|
||||||
|
@ -416,24 +405,23 @@ void CMenus::RenderSkinPartSelection7(CUIRect MainView)
|
||||||
{
|
{
|
||||||
static std::vector<const CSkins7::CSkinPart *> s_paList[protocol7::NUM_SKINPARTS];
|
static std::vector<const CSkins7::CSkinPart *> s_paList[protocol7::NUM_SKINPARTS];
|
||||||
static CListBox s_ListBox;
|
static CListBox s_ListBox;
|
||||||
static int s_aSkinPartCount[protocol7::NUM_SKINPARTS] = {0};
|
static size_t s_aSkinPartCount[protocol7::NUM_SKINPARTS] = {0};
|
||||||
for(int Part = 0; Part < protocol7::NUM_SKINPARTS; Part++)
|
for(int Part = 0; Part < protocol7::NUM_SKINPARTS; Part++)
|
||||||
{
|
{
|
||||||
if(m_SkinPartListNeedsUpdate || m_pClient->m_Skins7.NumSkinPart(Part) != s_aSkinPartCount[Part])
|
const std::vector<CSkins7::CSkinPart> &vCurrentSkinParts = GameClient()->m_Skins7.GetSkinParts(Part);
|
||||||
|
if(m_SkinPartListNeedsUpdate || vCurrentSkinParts.size() != s_aSkinPartCount[Part])
|
||||||
{
|
{
|
||||||
s_paList[Part].clear();
|
s_paList[Part].clear();
|
||||||
s_aSkinPartCount[Part] = m_pClient->m_Skins7.NumSkinPart(Part);
|
s_aSkinPartCount[Part] = vCurrentSkinParts.size();
|
||||||
for(int i = 0; i < s_aSkinPartCount[Part]; ++i)
|
for(const CSkins7::CSkinPart &SkinPart : vCurrentSkinParts)
|
||||||
{
|
{
|
||||||
const CSkins7::CSkinPart *pPart = m_pClient->m_Skins7.GetSkinPart(Part, i);
|
if((SkinPart.m_Flags & CSkins7::SKINFLAG_SPECIAL) != 0)
|
||||||
if(g_Config.m_ClSkinFilterString[0] != '\0' && !str_utf8_find_nocase(pPart->m_aName, g_Config.m_ClSkinFilterString))
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// no special skins
|
if(g_Config.m_ClSkinFilterString[0] != '\0' && !str_utf8_find_nocase(SkinPart.m_aName, g_Config.m_ClSkinFilterString))
|
||||||
if((pPart->m_Flags & CSkins7::SKINFLAG_SPECIAL) == 0)
|
continue;
|
||||||
{
|
|
||||||
s_paList[Part].emplace_back(pPart);
|
s_paList[Part].emplace_back(&SkinPart);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -460,19 +448,18 @@ void CMenus::RenderSkinPartSelection7(CUIRect MainView)
|
||||||
Item.m_Rect.HSplitBottom(12.0f, &Item.m_Rect, &Label);
|
Item.m_Rect.HSplitBottom(12.0f, &Item.m_Rect, &Label);
|
||||||
|
|
||||||
CTeeRenderInfo Info;
|
CTeeRenderInfo Info;
|
||||||
for(int j = 0; j < protocol7::NUM_SKINPARTS; j++)
|
for(int Part = 0; Part < protocol7::NUM_SKINPARTS; Part++)
|
||||||
{
|
{
|
||||||
int SkinPart = m_pClient->m_Skins7.FindSkinPart(j, CSkins7::ms_apSkinVariables[(int)m_Dummy][j], false);
|
const CSkins7::CSkinPart *pSkinPart = m_pClient->m_Skins7.FindSkinPart(Part, CSkins7::ms_apSkinVariables[(int)m_Dummy][Part], false);
|
||||||
const CSkins7::CSkinPart *pSkinPart = m_pClient->m_Skins7.GetSkinPart(j, SkinPart);
|
if(*CSkins7::ms_apUCCVariables[(int)m_Dummy][Part])
|
||||||
if(*CSkins7::ms_apUCCVariables[(int)m_Dummy][j])
|
|
||||||
{
|
{
|
||||||
Info.m_aSixup[g_Config.m_ClDummy].m_aTextures[j] = m_TeePartSelected == j ? pPart->m_ColorTexture : pSkinPart->m_ColorTexture;
|
Info.m_aSixup[g_Config.m_ClDummy].m_aTextures[Part] = m_TeePartSelected == Part ? pPart->m_ColorTexture : pSkinPart->m_ColorTexture;
|
||||||
Info.m_aSixup[g_Config.m_ClDummy].m_aColors[j] = m_pClient->m_Skins7.GetColor(*CSkins7::ms_apColorVariables[(int)m_Dummy][j], j == protocol7::SKINPART_MARKING);
|
Info.m_aSixup[g_Config.m_ClDummy].m_aColors[Part] = m_pClient->m_Skins7.GetColor(*CSkins7::ms_apColorVariables[(int)m_Dummy][Part], Part == protocol7::SKINPART_MARKING);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Info.m_aSixup[g_Config.m_ClDummy].m_aTextures[j] = m_TeePartSelected == j ? pPart->m_OrgTexture : pSkinPart->m_OrgTexture;
|
Info.m_aSixup[g_Config.m_ClDummy].m_aTextures[Part] = m_TeePartSelected == Part ? pPart->m_OrgTexture : pSkinPart->m_OrgTexture;
|
||||||
Info.m_aSixup[0].m_aColors[j] = ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f);
|
Info.m_aSixup[g_Config.m_ClDummy].m_aColors[Part] = ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Info.m_Size = 50.0f;
|
Info.m_Size = 50.0f;
|
||||||
|
|
|
@ -48,11 +48,6 @@ int CSkins7::SkinPartScan(const char *pName, int IsDir, int DirType, void *pUser
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
CSkinPart Part;
|
|
||||||
str_copy(Part.m_aName, pName, minimum<int>(PartNameSize + 1, sizeof(Part.m_aName)));
|
|
||||||
if(pSelf->FindSkinPart(pSelf->m_ScanningPart, Part.m_aName, true) != -1)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
char aFilename[IO_MAX_PATH_LENGTH];
|
char aFilename[IO_MAX_PATH_LENGTH];
|
||||||
str_format(aFilename, sizeof(aFilename), SKINS_DIR "/%s/%s", CSkins7::ms_apSkinPartNames[pSelf->m_ScanningPart], pName);
|
str_format(aFilename, sizeof(aFilename), SKINS_DIR "/%s/%s", CSkins7::ms_apSkinPartNames[pSelf->m_ScanningPart], pName);
|
||||||
CImageInfo Info;
|
CImageInfo Info;
|
||||||
|
@ -68,6 +63,8 @@ int CSkins7::SkinPartScan(const char *pName, int IsDir, int DirType, void *pUser
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CSkinPart Part;
|
||||||
|
str_copy(Part.m_aName, pName, minimum<int>(PartNameSize + 1, sizeof(Part.m_aName)));
|
||||||
Part.m_OrgTexture = pSelf->Graphics()->LoadTextureRaw(Info, 0, aFilename);
|
Part.m_OrgTexture = pSelf->Graphics()->LoadTextureRaw(Info, 0, aFilename);
|
||||||
Part.m_BloodColor = ColorRGBA(1.0f, 1.0f, 1.0f);
|
Part.m_BloodColor = ColorRGBA(1.0f, 1.0f, 1.0f);
|
||||||
|
|
||||||
|
@ -131,14 +128,15 @@ int CSkins7::SkinScan(const char *pName, int IsDir, int DirType, void *pUser)
|
||||||
}
|
}
|
||||||
|
|
||||||
// init
|
// init
|
||||||
CSkin Skin = pSelf->m_DummySkin;
|
CSkin Skin;
|
||||||
int NameLength = str_length(pName);
|
str_copy(Skin.m_aName, pName, 1 + str_length(pName) - str_length(".json"));
|
||||||
str_copy(Skin.m_aName, pName, 1 + NameLength - str_length(".json"));
|
const bool SpecialSkin = pName[0] == 'x' && pName[1] == '_';
|
||||||
bool SpecialSkin = pName[0] == 'x' && pName[1] == '_';
|
Skin.m_Flags = SpecialSkin ? SKINFLAG_SPECIAL : 0;
|
||||||
|
if(DirType != IStorage::TYPE_SAVE)
|
||||||
|
Skin.m_Flags |= SKINFLAG_STANDARD;
|
||||||
|
|
||||||
// parse json data
|
// parse json data
|
||||||
json_settings JsonSettings;
|
json_settings JsonSettings{};
|
||||||
mem_zero(&JsonSettings, sizeof(JsonSettings));
|
|
||||||
char aError[256];
|
char aError[256];
|
||||||
json_value *pJsonData = json_parse_ex(&JsonSettings, static_cast<const json_char *>(pFileData), JsonFileSize, aError);
|
json_value *pJsonData = json_parse_ex(&JsonSettings, static_cast<const json_char *>(pFileData), JsonFileSize, aError);
|
||||||
free(pFileData);
|
free(pFileData);
|
||||||
|
@ -151,64 +149,78 @@ int CSkins7::SkinScan(const char *pName, int IsDir, int DirType, void *pUser)
|
||||||
|
|
||||||
// extract data
|
// extract data
|
||||||
const json_value &Start = (*pJsonData)["skin"];
|
const json_value &Start = (*pJsonData)["skin"];
|
||||||
if(Start.type == json_object)
|
if(Start.type != json_object)
|
||||||
{
|
{
|
||||||
for(int PartIndex = 0; PartIndex < protocol7::NUM_SKINPARTS; ++PartIndex)
|
log_error("skins7", "Failed to parse skin json file '%s': root must be an object", aFilename);
|
||||||
|
json_value_free(pJsonData);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int PartIndex = 0; PartIndex < protocol7::NUM_SKINPARTS; ++PartIndex)
|
||||||
|
{
|
||||||
|
Skin.m_aUseCustomColors[PartIndex] = 0;
|
||||||
|
Skin.m_aPartColors[PartIndex] = (PartIndex == protocol7::SKINPART_MARKING ? 0xFF000000u : 0u) + 0x00FF80u;
|
||||||
|
|
||||||
|
const json_value &Part = Start[(const char *)ms_apSkinPartNames[PartIndex]];
|
||||||
|
if(Part.type == json_none)
|
||||||
{
|
{
|
||||||
const json_value &Part = Start[(const char *)ms_apSkinPartNames[PartIndex]];
|
Skin.m_apParts[PartIndex] = pSelf->FindDefaultSkinPart(PartIndex);
|
||||||
if(Part.type != json_object)
|
continue;
|
||||||
|
}
|
||||||
|
if(Part.type != json_object)
|
||||||
|
{
|
||||||
|
log_error("skins7", "Failed to parse skin json file '%s': attribute '%s' must specify an object", aFilename, ms_apSkinPartNames[PartIndex]);
|
||||||
|
json_value_free(pJsonData);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// filename
|
||||||
|
const json_value &Filename = Part["filename"];
|
||||||
|
if(Filename.type == json_string)
|
||||||
|
{
|
||||||
|
Skin.m_apParts[PartIndex] = pSelf->FindSkinPart(PartIndex, (const char *)Filename, SpecialSkin);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
log_error("skins7", "Failed to parse skin json file '%s': part '%s' attribute 'filename' must specify a string", aFilename, ms_apSkinPartNames[PartIndex]);
|
||||||
|
json_value_free(pJsonData);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// use custom colors
|
||||||
|
bool UseCustomColors = false;
|
||||||
|
const json_value &Color = Part["custom_colors"];
|
||||||
|
if(Color.type == json_string)
|
||||||
|
UseCustomColors = str_comp((const char *)Color, "true") == 0;
|
||||||
|
else if(Color.type == json_boolean)
|
||||||
|
UseCustomColors = Color.u.boolean;
|
||||||
|
Skin.m_aUseCustomColors[PartIndex] = UseCustomColors;
|
||||||
|
|
||||||
|
// color components
|
||||||
|
if(!UseCustomColors)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for(int i = 0; i < NUM_COLOR_COMPONENTS; i++)
|
||||||
|
{
|
||||||
|
if(PartIndex != protocol7::SKINPART_MARKING && i == 3)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// filename
|
const json_value &Component = Part[(const char *)ms_apColorComponents[i]];
|
||||||
const json_value &Filename = Part["filename"];
|
if(Component.type == json_integer)
|
||||||
if(Filename.type == json_string)
|
|
||||||
{
|
{
|
||||||
int SkinPart = pSelf->FindSkinPart(PartIndex, (const char *)Filename, SpecialSkin);
|
switch(i)
|
||||||
if(SkinPart > -1)
|
|
||||||
Skin.m_apParts[PartIndex] = pSelf->GetSkinPart(PartIndex, SkinPart);
|
|
||||||
}
|
|
||||||
|
|
||||||
// use custom colors
|
|
||||||
bool UseCustomColors = false;
|
|
||||||
const json_value &Color = Part["custom_colors"];
|
|
||||||
if(Color.type == json_string)
|
|
||||||
UseCustomColors = str_comp((const char *)Color, "true") == 0;
|
|
||||||
else if(Color.type == json_boolean)
|
|
||||||
UseCustomColors = Color.u.boolean;
|
|
||||||
Skin.m_aUseCustomColors[PartIndex] = UseCustomColors;
|
|
||||||
|
|
||||||
// color components
|
|
||||||
if(!UseCustomColors)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
for(int i = 0; i < NUM_COLOR_COMPONENTS; i++)
|
|
||||||
{
|
|
||||||
if(PartIndex != protocol7::SKINPART_MARKING && i == 3)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
const json_value &Component = Part[(const char *)ms_apColorComponents[i]];
|
|
||||||
if(Component.type == json_integer)
|
|
||||||
{
|
{
|
||||||
switch(i)
|
case 0: Skin.m_aPartColors[PartIndex] = (Skin.m_aPartColors[PartIndex] & 0xFF00FFFFu) | (Component.u.integer << 16); break;
|
||||||
{
|
case 1: Skin.m_aPartColors[PartIndex] = (Skin.m_aPartColors[PartIndex] & 0xFFFF00FFu) | (Component.u.integer << 8); break;
|
||||||
case 0: Skin.m_aPartColors[PartIndex] = (Skin.m_aPartColors[PartIndex] & 0xFF00FFFF) | (Component.u.integer << 16); break;
|
case 2: Skin.m_aPartColors[PartIndex] = (Skin.m_aPartColors[PartIndex] & 0xFFFFFF00u) | Component.u.integer; break;
|
||||||
case 1: Skin.m_aPartColors[PartIndex] = (Skin.m_aPartColors[PartIndex] & 0xFFFF00FF) | (Component.u.integer << 8); break;
|
case 3: Skin.m_aPartColors[PartIndex] = (Skin.m_aPartColors[PartIndex] & 0x00FFFFFFu) | (Component.u.integer << 24); break;
|
||||||
case 2: Skin.m_aPartColors[PartIndex] = (Skin.m_aPartColors[PartIndex] & 0xFFFFFF00) | Component.u.integer; break;
|
|
||||||
case 3: Skin.m_aPartColors[PartIndex] = (Skin.m_aPartColors[PartIndex] & 0x00FFFFFF) | (Component.u.integer << 24); break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// clean up
|
|
||||||
json_value_free(pJsonData);
|
json_value_free(pJsonData);
|
||||||
|
|
||||||
// set skin data
|
|
||||||
Skin.m_Flags = SpecialSkin ? SKINFLAG_SPECIAL : 0;
|
|
||||||
if(DirType != IStorage::TYPE_SAVE)
|
|
||||||
Skin.m_Flags |= SKINFLAG_STANDARD;
|
|
||||||
|
|
||||||
if(pSelf->Config()->m_Debug)
|
if(pSelf->Config()->m_Debug)
|
||||||
{
|
{
|
||||||
log_trace("skins7", "Loaded skin '%s'", Skin.m_aName);
|
log_trace("skins7", "Loaded skin '%s'", Skin.m_aName);
|
||||||
|
@ -218,11 +230,6 @@ int CSkins7::SkinScan(const char *pName, int IsDir, int DirType, void *pUser)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int CSkins7::GetInitAmount() const
|
|
||||||
{
|
|
||||||
return protocol7::NUM_SKINPARTS * 5 + 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CSkins7::OnInit()
|
void CSkins7::OnInit()
|
||||||
{
|
{
|
||||||
int Dummy = 0;
|
int Dummy = 0;
|
||||||
|
@ -267,6 +274,8 @@ void CSkins7::OnInit()
|
||||||
ms_apColorVariables[Dummy][protocol7::SKINPART_FEET] = &Config()->m_ClDummy7ColorFeet;
|
ms_apColorVariables[Dummy][protocol7::SKINPART_FEET] = &Config()->m_ClDummy7ColorFeet;
|
||||||
ms_apColorVariables[Dummy][protocol7::SKINPART_EYES] = &Config()->m_ClDummy7ColorEyes;
|
ms_apColorVariables[Dummy][protocol7::SKINPART_EYES] = &Config()->m_ClDummy7ColorEyes;
|
||||||
|
|
||||||
|
InitPlaceholderSkinParts();
|
||||||
|
|
||||||
for(int Part = 0; Part < protocol7::NUM_SKINPARTS; Part++)
|
for(int Part = 0; Part < protocol7::NUM_SKINPARTS; Part++)
|
||||||
{
|
{
|
||||||
m_avSkinParts[Part].clear();
|
m_avSkinParts[Part].clear();
|
||||||
|
@ -282,56 +291,36 @@ void CSkins7::OnInit()
|
||||||
}
|
}
|
||||||
|
|
||||||
// load skin parts
|
// load skin parts
|
||||||
char aBuf[64];
|
char aBuf[IO_MAX_PATH_LENGTH];
|
||||||
str_format(aBuf, sizeof(aBuf), SKINS_DIR "/%s", ms_apSkinPartNames[Part]);
|
str_format(aBuf, sizeof(aBuf), SKINS_DIR "/%s", ms_apSkinPartNames[Part]);
|
||||||
m_ScanningPart = Part;
|
m_ScanningPart = Part;
|
||||||
Storage()->ListDirectory(IStorage::TYPE_ALL, aBuf, SkinPartScan, this);
|
Storage()->ListDirectory(IStorage::TYPE_ALL, aBuf, SkinPartScan, this);
|
||||||
|
|
||||||
// add dummy skin part
|
|
||||||
if(m_avSkinParts[Part].empty())
|
|
||||||
{
|
|
||||||
CSkinPart DummySkinPart;
|
|
||||||
DummySkinPart.m_Flags = SKINFLAG_STANDARD;
|
|
||||||
str_copy(DummySkinPart.m_aName, "dummy");
|
|
||||||
DummySkinPart.m_BloodColor = vec3(1.0f, 1.0f, 1.0f);
|
|
||||||
m_avSkinParts[Part].emplace_back(DummySkinPart);
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
// create dummy skin
|
|
||||||
m_DummySkin.m_Flags = SKINFLAG_STANDARD;
|
|
||||||
str_copy(m_DummySkin.m_aName, "dummy");
|
|
||||||
for(int Part = 0; Part < protocol7::NUM_SKINPARTS; Part++)
|
|
||||||
{
|
|
||||||
int Default;
|
|
||||||
if(Part == protocol7::SKINPART_MARKING || Part == protocol7::SKINPART_DECORATION)
|
|
||||||
Default = FindSkinPart(Part, "", false);
|
|
||||||
else
|
|
||||||
Default = FindSkinPart(Part, "standard", false);
|
|
||||||
if(Default < 0)
|
|
||||||
Default = 0;
|
|
||||||
m_DummySkin.m_apParts[Part] = GetSkinPart(Part, Default);
|
|
||||||
m_DummySkin.m_aPartColors[Part] = Part == protocol7::SKINPART_MARKING ? (255 << 24) + 65408 : 65408;
|
|
||||||
m_DummySkin.m_aUseCustomColors[Part] = 0;
|
|
||||||
}
|
|
||||||
GameClient()->m_Menus.RenderLoading(Localize("Loading DDNet Client"), Localize("Loading skin files"), 0);
|
|
||||||
|
|
||||||
// load skins
|
// load skins
|
||||||
m_vSkins.clear();
|
m_vSkins.clear();
|
||||||
Storage()->ListDirectory(IStorage::TYPE_ALL, SKINS_DIR, SkinScan, this);
|
Storage()->ListDirectory(IStorage::TYPE_ALL, SKINS_DIR, SkinScan, this);
|
||||||
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);
|
||||||
|
|
||||||
// add dummy skin
|
|
||||||
if(m_vSkins.empty())
|
|
||||||
m_vSkins.emplace_back(m_DummySkin);
|
|
||||||
|
|
||||||
LoadXmasHat();
|
LoadXmasHat();
|
||||||
LoadBotDecoration();
|
LoadBotDecoration();
|
||||||
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 CSkins7::InitPlaceholderSkinParts()
|
||||||
|
{
|
||||||
|
for(CSkinPart &SkinPart : m_aPlaceholderSkinParts)
|
||||||
|
{
|
||||||
|
SkinPart.m_Flags = SKINFLAG_STANDARD;
|
||||||
|
str_copy(SkinPart.m_aName, "dummy");
|
||||||
|
SkinPart.m_OrgTexture.Invalidate();
|
||||||
|
SkinPart.m_ColorTexture.Invalidate();
|
||||||
|
SkinPart.m_BloodColor = ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void CSkins7::LoadXmasHat()
|
void CSkins7::LoadXmasHat()
|
||||||
{
|
{
|
||||||
const char *pFilename = SKINS_DIR "/xmas_hat.png";
|
const char *pFilename = SKINS_DIR "/xmas_hat.png";
|
||||||
|
@ -374,24 +363,26 @@ void CSkins7::LoadBotDecoration()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSkins7::AddSkin(const char *pSkinName, int Dummy)
|
void CSkins7::AddSkinFromConfigVariables(const char *pName, int Dummy)
|
||||||
{
|
{
|
||||||
CSkin Skin = m_DummySkin;
|
auto OldSkin = std::find_if(m_vSkins.begin(), m_vSkins.end(), [pName](const CSkin &Skin) {
|
||||||
Skin.m_Flags = 0;
|
return str_comp(Skin.m_aName, pName) == 0;
|
||||||
str_copy(Skin.m_aName, pSkinName, sizeof(Skin.m_aName));
|
});
|
||||||
|
if(OldSkin != m_vSkins.end())
|
||||||
|
{
|
||||||
|
m_vSkins.erase(OldSkin);
|
||||||
|
}
|
||||||
|
|
||||||
|
CSkin NewSkin;
|
||||||
|
NewSkin.m_Flags = 0;
|
||||||
|
str_copy(NewSkin.m_aName, pName);
|
||||||
for(int PartIndex = 0; PartIndex < protocol7::NUM_SKINPARTS; ++PartIndex)
|
for(int PartIndex = 0; PartIndex < protocol7::NUM_SKINPARTS; ++PartIndex)
|
||||||
{
|
{
|
||||||
int SkinPart = FindSkinPart(PartIndex, ms_apSkinVariables[Dummy][PartIndex], false);
|
NewSkin.m_apParts[PartIndex] = FindSkinPart(PartIndex, ms_apSkinVariables[Dummy][PartIndex], false);
|
||||||
if(SkinPart > -1)
|
NewSkin.m_aUseCustomColors[PartIndex] = *ms_apUCCVariables[Dummy][PartIndex];
|
||||||
Skin.m_apParts[PartIndex] = GetSkinPart(PartIndex, SkinPart);
|
NewSkin.m_aPartColors[PartIndex] = *ms_apColorVariables[Dummy][PartIndex];
|
||||||
Skin.m_aUseCustomColors[PartIndex] = *ms_apUCCVariables[Dummy][PartIndex];
|
|
||||||
Skin.m_aPartColors[PartIndex] = *ms_apColorVariables[Dummy][PartIndex];
|
|
||||||
}
|
}
|
||||||
int SkinIndex = Find(Skin.m_aName, false);
|
m_vSkins.insert(std::lower_bound(m_vSkins.begin(), m_vSkins.end(), NewSkin), NewSkin);
|
||||||
if(SkinIndex != -1)
|
|
||||||
m_vSkins[SkinIndex] = Skin;
|
|
||||||
else
|
|
||||||
m_vSkins.emplace_back(Skin);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CSkins7::RemoveSkin(const CSkin *pSkin)
|
bool CSkins7::RemoveSkin(const CSkin *pSkin)
|
||||||
|
@ -403,53 +394,60 @@ bool CSkins7::RemoveSkin(const CSkin *pSkin)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Position = std::find(m_vSkins.begin(), m_vSkins.end(), *pSkin);
|
auto FoundSkin = std::find(m_vSkins.begin(), m_vSkins.end(), *pSkin);
|
||||||
m_vSkins.erase(Position);
|
dbg_assert(FoundSkin != m_vSkins.end(), "Skin not found");
|
||||||
|
m_vSkins.erase(FoundSkin);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int CSkins7::Num()
|
const std::vector<CSkins7::CSkin> &CSkins7::GetSkins() const
|
||||||
{
|
{
|
||||||
return m_vSkins.size();
|
return m_vSkins;
|
||||||
}
|
}
|
||||||
|
|
||||||
int CSkins7::NumSkinPart(int Part)
|
const std::vector<CSkins7::CSkinPart> &CSkins7::GetSkinParts(int Part) const
|
||||||
{
|
{
|
||||||
return m_avSkinParts[Part].size();
|
return m_avSkinParts[Part];
|
||||||
}
|
}
|
||||||
|
|
||||||
const CSkins7::CSkin *CSkins7::Get(int Index)
|
const CSkins7::CSkinPart *CSkins7::FindSkinPartOrNullptr(int Part, const char *pName, bool AllowSpecialPart) const
|
||||||
{
|
{
|
||||||
return &m_vSkins[maximum((std::size_t)0, Index % m_vSkins.size())];
|
auto FoundPart = std::find_if(m_avSkinParts[Part].begin(), m_avSkinParts[Part].end(), [pName](const CSkinPart &SkinPart) {
|
||||||
}
|
return str_comp(SkinPart.m_aName, pName) == 0;
|
||||||
|
});
|
||||||
int CSkins7::Find(const char *pName, bool AllowSpecialSkin)
|
if(FoundPart == m_avSkinParts[Part].end())
|
||||||
{
|
|
||||||
for(unsigned int i = 0; i < m_vSkins.size(); i++)
|
|
||||||
{
|
{
|
||||||
if(str_comp(m_vSkins[i].m_aName, pName) == 0 && ((m_vSkins[i].m_Flags & SKINFLAG_SPECIAL) == 0 || AllowSpecialSkin))
|
return nullptr;
|
||||||
return i;
|
|
||||||
}
|
}
|
||||||
return -1;
|
if((FoundPart->m_Flags & SKINFLAG_SPECIAL) != 0 && !AllowSpecialPart)
|
||||||
}
|
|
||||||
|
|
||||||
const CSkins7::CSkinPart *CSkins7::GetSkinPart(int Part, int Index)
|
|
||||||
{
|
|
||||||
int Size = m_avSkinParts[Part].size();
|
|
||||||
return &m_avSkinParts[Part][maximum(0, Index % Size)];
|
|
||||||
}
|
|
||||||
|
|
||||||
int CSkins7::FindSkinPart(int Part, const char *pName, bool AllowSpecialPart)
|
|
||||||
{
|
|
||||||
for(unsigned int i = 0; i < m_avSkinParts[Part].size(); i++)
|
|
||||||
{
|
{
|
||||||
if(str_comp(m_avSkinParts[Part][i].m_aName, pName) == 0 && ((m_avSkinParts[Part][i].m_Flags & SKINFLAG_SPECIAL) == 0 || AllowSpecialPart))
|
return nullptr;
|
||||||
return i;
|
|
||||||
}
|
}
|
||||||
return -1;
|
return &*FoundPart;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSkins7::RandomizeSkin(int Dummy)
|
const CSkins7::CSkinPart *CSkins7::FindDefaultSkinPart(int Part) const
|
||||||
|
{
|
||||||
|
const char *pDefaultPartName = Part == protocol7::SKINPART_MARKING || Part == protocol7::SKINPART_DECORATION ? "" : "default";
|
||||||
|
const CSkinPart *pDefault = FindSkinPartOrNullptr(Part, pDefaultPartName, false);
|
||||||
|
if(pDefault != nullptr)
|
||||||
|
{
|
||||||
|
return pDefault;
|
||||||
|
}
|
||||||
|
return &m_aPlaceholderSkinParts[Part];
|
||||||
|
}
|
||||||
|
|
||||||
|
const CSkins7::CSkinPart *CSkins7::FindSkinPart(int Part, const char *pName, bool AllowSpecialPart) const
|
||||||
|
{
|
||||||
|
const CSkinPart *pSkinPart = FindSkinPartOrNullptr(Part, pName, AllowSpecialPart);
|
||||||
|
if(pSkinPart != nullptr)
|
||||||
|
{
|
||||||
|
return pSkinPart;
|
||||||
|
}
|
||||||
|
return FindDefaultSkinPart(Part);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSkins7::RandomizeSkin(int Dummy) const
|
||||||
{
|
{
|
||||||
for(int Part = 0; Part < protocol7::NUM_SKINPARTS; Part++)
|
for(int Part = 0; Part < protocol7::NUM_SKINPARTS; Part++)
|
||||||
{
|
{
|
||||||
|
@ -466,10 +464,23 @@ void CSkins7::RandomizeSkin(int Dummy)
|
||||||
|
|
||||||
for(int Part = 0; Part < protocol7::NUM_SKINPARTS; Part++)
|
for(int Part = 0; Part < protocol7::NUM_SKINPARTS; Part++)
|
||||||
{
|
{
|
||||||
const CSkinPart *pSkinPart = GetSkinPart(Part, rand() % NumSkinPart(Part));
|
std::vector<const CSkins7::CSkinPart *> vConsideredSkinParts;
|
||||||
while(pSkinPart->m_Flags & SKINFLAG_SPECIAL)
|
for(const CSkinPart &SkinPart : GetSkinParts(Part))
|
||||||
pSkinPart = GetSkinPart(Part, rand() % NumSkinPart(Part));
|
{
|
||||||
str_copy(ms_apSkinVariables[Dummy][Part], pSkinPart->m_aName, protocol7::MAX_SKIN_ARRAY_SIZE);
|
if((SkinPart.m_Flags & CSkins7::SKINFLAG_SPECIAL) != 0)
|
||||||
|
continue;
|
||||||
|
vConsideredSkinParts.push_back(&SkinPart);
|
||||||
|
}
|
||||||
|
const CSkins7::CSkinPart *pRandomPart;
|
||||||
|
if(vConsideredSkinParts.empty())
|
||||||
|
{
|
||||||
|
pRandomPart = FindDefaultSkinPart(Part);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pRandomPart = vConsideredSkinParts[rand() % vConsideredSkinParts.size()];
|
||||||
|
}
|
||||||
|
str_copy(CSkins7::ms_apSkinVariables[Dummy][Part], pRandomPart->m_aName, protocol7::MAX_SKIN_ARRAY_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
ms_apSkinNameVariables[Dummy][0] = '\0';
|
ms_apSkinNameVariables[Dummy][0] = '\0';
|
||||||
|
@ -523,10 +534,13 @@ bool CSkins7::ValidateSkinParts(char *apPartNames[protocol7::NUM_SKINPARTS], int
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CSkins7::SaveSkinfile(const char *pSaveSkinName, int Dummy)
|
bool CSkins7::SaveSkinfile(const char *pName, int Dummy)
|
||||||
{
|
{
|
||||||
|
const bool SpecialSkin = pName[0] == 'x' && pName[1] == '_';
|
||||||
|
dbg_assert(!SpecialSkin, "Cannot save special skins");
|
||||||
|
|
||||||
char aBuf[IO_MAX_PATH_LENGTH];
|
char aBuf[IO_MAX_PATH_LENGTH];
|
||||||
str_format(aBuf, sizeof(aBuf), SKINS_DIR "/%s.json", pSaveSkinName);
|
str_format(aBuf, sizeof(aBuf), SKINS_DIR "/%s.json", pName);
|
||||||
IOHANDLE File = Storage()->OpenFile(aBuf, IOFLAG_WRITE, IStorage::TYPE_SAVE);
|
IOHANDLE File = Storage()->OpenFile(aBuf, IOFLAG_WRITE, IStorage::TYPE_SAVE);
|
||||||
if(!File)
|
if(!File)
|
||||||
return false;
|
return false;
|
||||||
|
@ -573,7 +587,6 @@ bool CSkins7::SaveSkinfile(const char *pSaveSkinName, int Dummy)
|
||||||
Writer.EndObject();
|
Writer.EndObject();
|
||||||
Writer.EndObject();
|
Writer.EndObject();
|
||||||
|
|
||||||
// add new skin to the skin list
|
AddSkinFromConfigVariables(pName, Dummy);
|
||||||
AddSkin(pSaveSkinName, Dummy);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,16 +2,19 @@
|
||||||
/* If you are missing that file, acquire a complete release at teeworlds.com. */
|
/* If you are missing that file, acquire a complete release at teeworlds.com. */
|
||||||
#ifndef GAME_CLIENT_COMPONENTS_SKINS7_H
|
#ifndef GAME_CLIENT_COMPONENTS_SKINS7_H
|
||||||
#define GAME_CLIENT_COMPONENTS_SKINS7_H
|
#define GAME_CLIENT_COMPONENTS_SKINS7_H
|
||||||
|
|
||||||
#include <base/color.h>
|
#include <base/color.h>
|
||||||
#include <base/vmath.h>
|
#include <base/vmath.h>
|
||||||
|
|
||||||
#include <engine/client/enums.h>
|
#include <engine/client/enums.h>
|
||||||
#include <engine/graphics.h>
|
#include <engine/graphics.h>
|
||||||
#include <game/client/component.h>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
|
#include <game/client/component.h>
|
||||||
#include <game/generated/protocol.h>
|
#include <game/generated/protocol.h>
|
||||||
#include <game/generated/protocol7.h>
|
#include <game/generated/protocol7.h>
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
class CSkins7 : public CComponent
|
class CSkins7 : public CComponent
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -26,8 +29,9 @@ public:
|
||||||
HAT_OFFSET_SIDE = 2,
|
HAT_OFFSET_SIDE = 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CSkinPart
|
class CSkinPart
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
int m_Flags;
|
int m_Flags;
|
||||||
char m_aName[24];
|
char m_aName[24];
|
||||||
IGraphics::CTextureHandle m_OrgTexture;
|
IGraphics::CTextureHandle m_OrgTexture;
|
||||||
|
@ -37,13 +41,14 @@ public:
|
||||||
bool operator<(const CSkinPart &Other) { return str_comp_nocase(m_aName, Other.m_aName) < 0; }
|
bool operator<(const CSkinPart &Other) { return str_comp_nocase(m_aName, Other.m_aName) < 0; }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CSkin
|
class CSkin
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
int m_Flags;
|
int m_Flags;
|
||||||
char m_aName[24];
|
char m_aName[24];
|
||||||
const CSkinPart *m_apParts[protocol7::NUM_SKINPARTS];
|
const CSkinPart *m_apParts[protocol7::NUM_SKINPARTS];
|
||||||
int m_aPartColors[protocol7::NUM_SKINPARTS];
|
|
||||||
int m_aUseCustomColors[protocol7::NUM_SKINPARTS];
|
int m_aUseCustomColors[protocol7::NUM_SKINPARTS];
|
||||||
|
unsigned m_aPartColors[protocol7::NUM_SKINPARTS];
|
||||||
|
|
||||||
bool operator<(const CSkin &Other) const { return str_comp_nocase(m_aName, Other.m_aName) < 0; }
|
bool operator<(const CSkin &Other) const { return str_comp_nocase(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); }
|
||||||
|
@ -56,23 +61,17 @@ public:
|
||||||
static char *ms_apSkinNameVariables[NUM_DUMMIES];
|
static char *ms_apSkinNameVariables[NUM_DUMMIES];
|
||||||
static char *ms_apSkinVariables[NUM_DUMMIES][protocol7::NUM_SKINPARTS];
|
static char *ms_apSkinVariables[NUM_DUMMIES][protocol7::NUM_SKINPARTS];
|
||||||
static int *ms_apUCCVariables[NUM_DUMMIES][protocol7::NUM_SKINPARTS]; // use custom color
|
static int *ms_apUCCVariables[NUM_DUMMIES][protocol7::NUM_SKINPARTS]; // use custom color
|
||||||
static unsigned int *ms_apColorVariables[NUM_DUMMIES][protocol7::NUM_SKINPARTS];
|
static unsigned *ms_apColorVariables[NUM_DUMMIES][protocol7::NUM_SKINPARTS];
|
||||||
IGraphics::CTextureHandle m_XmasHatTexture;
|
|
||||||
IGraphics::CTextureHandle m_BotTexture;
|
|
||||||
|
|
||||||
int GetInitAmount() const;
|
int Sizeof() const override { return sizeof(*this); }
|
||||||
void OnInit() override;
|
void OnInit() override;
|
||||||
|
|
||||||
void AddSkin(const char *pSkinName, int Dummy);
|
const std::vector<CSkin> &GetSkins() const;
|
||||||
bool RemoveSkin(const CSkin *pSkin);
|
const std::vector<CSkinPart> &GetSkinParts(int Part) const;
|
||||||
|
const CSkinPart *FindSkinPartOrNullptr(int Part, const char *pName, bool AllowSpecialPart) const;
|
||||||
int Num();
|
const CSkinPart *FindDefaultSkinPart(int Part) const;
|
||||||
int NumSkinPart(int Part);
|
const CSkinPart *FindSkinPart(int Part, const char *pName, bool AllowSpecialPart) const;
|
||||||
const CSkin *Get(int Index);
|
void RandomizeSkin(int Dummy) const;
|
||||||
int Find(const char *pName, bool AllowSpecialSkin);
|
|
||||||
const CSkinPart *GetSkinPart(int Part, int Index);
|
|
||||||
int FindSkinPart(int Part, const char *pName, bool AllowSpecialPart);
|
|
||||||
void RandomizeSkin(int Dummy);
|
|
||||||
|
|
||||||
ColorRGBA GetColor(int Value, bool UseAlpha) const;
|
ColorRGBA GetColor(int Value, bool UseAlpha) const;
|
||||||
ColorRGBA GetTeamColor(int UseCustomColors, int PartColor, int Team, int Part) const;
|
ColorRGBA GetTeamColor(int UseCustomColors, int PartColor, int Team, int Part) const;
|
||||||
|
@ -80,21 +79,30 @@ public:
|
||||||
// returns true if everything was valid and nothing changed
|
// returns true if everything was valid and nothing changed
|
||||||
bool ValidateSkinParts(char *apPartNames[protocol7::NUM_SKINPARTS], int *pUseCustomColors, int *pPartColors, int GameFlags) const;
|
bool ValidateSkinParts(char *apPartNames[protocol7::NUM_SKINPARTS], int *pUseCustomColors, int *pPartColors, int GameFlags) const;
|
||||||
|
|
||||||
bool SaveSkinfile(const char *pSaveSkinName, int Dummy);
|
bool SaveSkinfile(const char *pName, int Dummy);
|
||||||
|
bool RemoveSkin(const CSkin *pSkin);
|
||||||
|
|
||||||
virtual int Sizeof() const override { return sizeof(*this); }
|
IGraphics::CTextureHandle XmasHatTexture() const { return m_XmasHatTexture; }
|
||||||
|
IGraphics::CTextureHandle BotDecorationTexture() const { return m_BotTexture; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int m_ScanningPart;
|
int m_ScanningPart;
|
||||||
|
|
||||||
std::vector<CSkinPart> m_avSkinParts[protocol7::NUM_SKINPARTS];
|
std::vector<CSkinPart> m_avSkinParts[protocol7::NUM_SKINPARTS];
|
||||||
|
CSkinPart m_aPlaceholderSkinParts[protocol7::NUM_SKINPARTS];
|
||||||
std::vector<CSkin> m_vSkins;
|
std::vector<CSkin> m_vSkins;
|
||||||
CSkin m_DummySkin;
|
|
||||||
|
IGraphics::CTextureHandle m_XmasHatTexture;
|
||||||
|
IGraphics::CTextureHandle m_BotTexture;
|
||||||
|
|
||||||
static int SkinPartScan(const char *pName, int IsDir, int DirType, void *pUser);
|
static int SkinPartScan(const char *pName, int IsDir, int DirType, void *pUser);
|
||||||
static int SkinScan(const char *pName, int IsDir, int DirType, void *pUser);
|
static int SkinScan(const char *pName, int IsDir, int DirType, void *pUser);
|
||||||
|
|
||||||
|
void InitPlaceholderSkinParts();
|
||||||
void LoadXmasHat();
|
void LoadXmasHat();
|
||||||
void LoadBotDecoration();
|
void LoadBotDecoration();
|
||||||
|
|
||||||
|
void AddSkinFromConfigVariables(const char *pName, int Dummy);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -94,7 +94,7 @@ void CGameClient::ApplySkin7InfoFromGameMsg(const T *pMsg, int ClientId, int Con
|
||||||
|
|
||||||
if(time_season() == SEASON_XMAS)
|
if(time_season() == SEASON_XMAS)
|
||||||
{
|
{
|
||||||
pClient->m_SkinInfo.m_aSixup[Conn].m_HatTexture = m_Skins7.m_XmasHatTexture;
|
pClient->m_SkinInfo.m_aSixup[Conn].m_HatTexture = m_Skins7.XmasHatTexture();
|
||||||
pClient->m_SkinInfo.m_aSixup[Conn].m_HatSpriteIndex = ClientId % CSkins7::HAT_NUM;
|
pClient->m_SkinInfo.m_aSixup[Conn].m_HatSpriteIndex = ClientId % CSkins7::HAT_NUM;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -102,8 +102,7 @@ void CGameClient::ApplySkin7InfoFromGameMsg(const T *pMsg, int ClientId, int Con
|
||||||
|
|
||||||
for(int Part = 0; Part < protocol7::NUM_SKINPARTS; Part++)
|
for(int Part = 0; Part < protocol7::NUM_SKINPARTS; Part++)
|
||||||
{
|
{
|
||||||
int Id = m_Skins7.FindSkinPart(Part, pClient->m_aSixup[Conn].m_aaSkinPartNames[Part], false);
|
const CSkins7::CSkinPart *pSkinPart = m_Skins7.FindSkinPart(Part, pClient->m_aSixup[Conn].m_aaSkinPartNames[Part], false);
|
||||||
const CSkins7::CSkinPart *pSkinPart = m_Skins7.GetSkinPart(Part, Id);
|
|
||||||
if(pClient->m_aSixup[Conn].m_aUseCustomColors[Part])
|
if(pClient->m_aSixup[Conn].m_aUseCustomColors[Part])
|
||||||
{
|
{
|
||||||
pClient->m_SkinInfo.m_aSixup[Conn].m_aTextures[Part] = pSkinPart->m_ColorTexture;
|
pClient->m_SkinInfo.m_aSixup[Conn].m_aTextures[Part] = pSkinPart->m_ColorTexture;
|
||||||
|
|
Loading…
Reference in a new issue