mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-19 22:48:18 +00:00
Refactor skin refreshing in gameclient, fix crash in skin settings
Add `CGameClient::RefreshSkins` function to refresh skins. This function reloads all skins by calling `CSkins::Refresh` and then notifies all gameclient components about the skins being refreshed by calling the new `CComponent::OnRefreshSkins` function, so the components can properly invalidate their current skin texture handles. The existing `RefindSkins` functions are changed to `OnRefreshSkins`. Additionally, `OnRefreshSkins` is overridden in `CMenus` to set the flag so the skin list will be updated before it is rendered the next time, to fix the client crashing when changing skin related config variables via the console. Closes #7891.
This commit is contained in:
parent
2ed899a259
commit
c40d809282
|
@ -182,6 +182,10 @@ public:
|
|||
* Called when the window has been resized.
|
||||
*/
|
||||
virtual void OnWindowResize() {}
|
||||
/**
|
||||
* Called when skins have been invalidated and must be updated.
|
||||
*/
|
||||
virtual void OnRefreshSkins() {}
|
||||
/**
|
||||
* Called when the component should get rendered.
|
||||
*
|
||||
|
|
|
@ -923,7 +923,7 @@ void CChat::AddLine(int ClientID, int Team, const char *pLine)
|
|||
}
|
||||
}
|
||||
|
||||
void CChat::RefindSkins()
|
||||
void CChat::OnRefreshSkins()
|
||||
{
|
||||
for(auto &Line : m_aLines)
|
||||
{
|
||||
|
|
|
@ -165,8 +165,8 @@ public:
|
|||
void OnWindowResize() override;
|
||||
void OnConsoleInit() override;
|
||||
void OnStateChange(int NewState, int OldState) override;
|
||||
void OnRefreshSkins() override;
|
||||
void OnRender() override;
|
||||
void RefindSkins();
|
||||
void OnPrepareLines(float y);
|
||||
void Reset();
|
||||
void OnRelease() override;
|
||||
|
|
|
@ -684,7 +684,7 @@ int CGhost::GetLastRaceTick() const
|
|||
return m_LastRaceTick;
|
||||
}
|
||||
|
||||
void CGhost::RefindSkins()
|
||||
void CGhost::OnRefreshSkins()
|
||||
{
|
||||
const auto &&RefindSkin = [&](auto &Ghost) {
|
||||
if(Ghost.Empty())
|
||||
|
|
|
@ -155,6 +155,7 @@ public:
|
|||
virtual void OnRender() override;
|
||||
virtual void OnConsoleInit() override;
|
||||
virtual void OnReset() override;
|
||||
virtual void OnRefreshSkins() override;
|
||||
virtual void OnMessage(int MsgType, void *pRawMsg) override;
|
||||
virtual void OnMapLoad() override;
|
||||
virtual void OnShutdown() override;
|
||||
|
@ -175,8 +176,6 @@ public:
|
|||
class IGhostRecorder *GhostRecorder() const { return m_pGhostRecorder; }
|
||||
|
||||
int GetLastRaceTick() const;
|
||||
|
||||
void RefindSkins();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -536,7 +536,7 @@ void CInfoMessages::OnRender()
|
|||
}
|
||||
}
|
||||
|
||||
void CInfoMessages::RefindSkins()
|
||||
void CInfoMessages::OnRefreshSkins()
|
||||
{
|
||||
for(auto &InfoMsg : m_aInfoMsgs)
|
||||
{
|
||||
|
|
|
@ -72,12 +72,11 @@ public:
|
|||
|
||||
virtual int Sizeof() const override { return sizeof(*this); }
|
||||
virtual void OnWindowResize() override;
|
||||
virtual void OnRefreshSkins() override;
|
||||
virtual void OnReset() override;
|
||||
virtual void OnRender() override;
|
||||
virtual void OnMessage(int MsgType, void *pRawMsg) override;
|
||||
virtual void OnInit() override;
|
||||
|
||||
void RefindSkins();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -814,12 +814,6 @@ void CMenus::OnInit()
|
|||
Console()->Chain("cl_asset_hud", ConchainAssetHud, this);
|
||||
Console()->Chain("cl_asset_extras", ConchainAssetExtras, this);
|
||||
|
||||
Console()->Chain("cl_skin_download_url", ConchainReloadSkins, this);
|
||||
Console()->Chain("cl_skin_community_download_url", ConchainReloadSkins, this);
|
||||
Console()->Chain("cl_download_skins", ConchainReloadSkins, this);
|
||||
Console()->Chain("cl_download_community_skins", ConchainReloadSkins, this);
|
||||
Console()->Chain("cl_vanilla_skins_only", ConchainReloadSkins, this);
|
||||
|
||||
m_TextureBlob = Graphics()->LoadTexture("blob.png", IStorage::TYPE_ALL);
|
||||
|
||||
// setup load amount
|
||||
|
|
|
@ -81,8 +81,7 @@ class CMenus : public CComponent
|
|||
void DoJoystickAxisPicker(CUIRect View);
|
||||
void DoJoystickBar(const CUIRect *pRect, float Current, float Tolerance, bool Active);
|
||||
|
||||
void RefreshSkins();
|
||||
|
||||
bool m_SkinListNeedsUpdate = false;
|
||||
void RandomSkin();
|
||||
|
||||
// menus_settings_assets.cpp
|
||||
|
@ -595,8 +594,6 @@ protected:
|
|||
|
||||
class CMenuBackground *m_pBackground;
|
||||
|
||||
static void ConchainReloadSkins(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
|
||||
|
||||
public:
|
||||
void RenderBackground();
|
||||
|
||||
|
@ -619,6 +616,7 @@ public:
|
|||
|
||||
virtual void OnStateChange(int NewState, int OldState) override;
|
||||
virtual void OnWindowResize() override;
|
||||
virtual void OnRefreshSkins() override;
|
||||
virtual void OnReset() override;
|
||||
virtual void OnRender() override;
|
||||
virtual bool OnInput(const IInput::CEvent &Event) override;
|
||||
|
|
|
@ -389,20 +389,9 @@ struct CUISkin
|
|||
bool operator==(const char *pOther) const { return !str_comp_nocase(m_pSkin->GetName(), pOther); }
|
||||
};
|
||||
|
||||
void CMenus::RefreshSkins()
|
||||
void CMenus::OnRefreshSkins()
|
||||
{
|
||||
auto SkinStartLoadTime = time_get_nanoseconds();
|
||||
m_pClient->m_Skins.Refresh([&](int) {
|
||||
// if skin refreshing takes to long, swap to a loading screen
|
||||
if(time_get_nanoseconds() - SkinStartLoadTime > 500ms)
|
||||
{
|
||||
RenderLoading(Localize("Loading skin files"), "", 0, false);
|
||||
}
|
||||
});
|
||||
if(Client()->State() == IClient::STATE_ONLINE || Client()->State() == IClient::STATE_DEMOPLAYBACK)
|
||||
{
|
||||
m_pClient->RefindSkins();
|
||||
}
|
||||
m_SkinListNeedsUpdate = true;
|
||||
}
|
||||
|
||||
void CMenus::RandomSkin()
|
||||
|
@ -560,29 +549,25 @@ void CMenus::RenderSettingsTee(CUIRect MainView)
|
|||
Checkboxes.VSplitRight(20.0f, &Checkboxes, nullptr);
|
||||
|
||||
// Checkboxes
|
||||
static bool s_InitSkinlist = true;
|
||||
Checkboxes.HSplitTop(20.0f, &Button, &Checkboxes);
|
||||
if(DoButton_CheckBox(&g_Config.m_ClDownloadSkins, Localize("Download skins"), g_Config.m_ClDownloadSkins, &Button))
|
||||
{
|
||||
g_Config.m_ClDownloadSkins ^= 1;
|
||||
RefreshSkins();
|
||||
s_InitSkinlist = true;
|
||||
m_pClient->RefreshSkins();
|
||||
}
|
||||
|
||||
Checkboxes.HSplitTop(20.0f, &Button, &Checkboxes);
|
||||
if(DoButton_CheckBox(&g_Config.m_ClDownloadCommunitySkins, Localize("Download community skins"), g_Config.m_ClDownloadCommunitySkins, &Button))
|
||||
{
|
||||
g_Config.m_ClDownloadCommunitySkins ^= 1;
|
||||
RefreshSkins();
|
||||
s_InitSkinlist = true;
|
||||
m_pClient->RefreshSkins();
|
||||
}
|
||||
|
||||
Checkboxes.HSplitTop(20.0f, &Button, &Checkboxes);
|
||||
if(DoButton_CheckBox(&g_Config.m_ClVanillaSkinsOnly, Localize("Vanilla skins only"), g_Config.m_ClVanillaSkinsOnly, &Button))
|
||||
{
|
||||
g_Config.m_ClVanillaSkinsOnly ^= 1;
|
||||
RefreshSkins();
|
||||
s_InitSkinlist = true;
|
||||
m_pClient->RefreshSkins();
|
||||
}
|
||||
|
||||
Checkboxes.HSplitTop(20.0f, &Button, &Checkboxes);
|
||||
|
@ -768,7 +753,7 @@ void CMenus::RenderSettingsTee(CUIRect MainView)
|
|||
// be nice to the CPU
|
||||
static auto s_SkinLastRebuildTime = time_get_nanoseconds();
|
||||
const auto CurTime = time_get_nanoseconds();
|
||||
if(s_InitSkinlist || m_pClient->m_Skins.Num() != s_SkinCount || m_SkinFavoritesChanged || (m_pClient->m_Skins.IsDownloadingSkins() && (CurTime - s_SkinLastRebuildTime > 500ms)))
|
||||
if(m_SkinListNeedsUpdate || m_pClient->m_Skins.Num() != s_SkinCount || m_SkinFavoritesChanged || (m_pClient->m_Skins.IsDownloadingSkins() && (CurTime - s_SkinLastRebuildTime > 500ms)))
|
||||
{
|
||||
s_SkinLastRebuildTime = CurTime;
|
||||
s_vSkinList.clear();
|
||||
|
@ -813,7 +798,7 @@ void CMenus::RenderSettingsTee(CUIRect MainView)
|
|||
std::sort(s_vFavoriteSkinListHelper.begin(), s_vFavoriteSkinListHelper.end());
|
||||
s_vSkinList = s_vFavoriteSkinListHelper;
|
||||
s_vSkinList.insert(s_vSkinList.end(), s_vSkinListHelper.begin(), s_vSkinListHelper.end());
|
||||
s_InitSkinlist = false;
|
||||
m_SkinListNeedsUpdate = false;
|
||||
}
|
||||
|
||||
const auto &&RenderFavIcon = [&](const CUIRect &FavIcon, bool AsFav, bool Hot) {
|
||||
|
@ -890,7 +875,7 @@ void CMenus::RenderSettingsTee(CUIRect MainView)
|
|||
{
|
||||
m_SkinFavorites.emplace(pSkinToBeDraw->GetName());
|
||||
}
|
||||
s_InitSkinlist = true;
|
||||
m_SkinListNeedsUpdate = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -919,7 +904,7 @@ void CMenus::RenderSettingsTee(CUIRect MainView)
|
|||
}
|
||||
s_SkinFilterInput.SetEmptyText(Localize("Search"));
|
||||
if(UI()->DoClearableEditBox(&s_SkinFilterInput, &QuickSearch, 14.0f))
|
||||
s_InitSkinlist = true;
|
||||
m_SkinListNeedsUpdate = true;
|
||||
}
|
||||
|
||||
static CButtonContainer s_SkinDatabaseButton;
|
||||
|
@ -952,8 +937,7 @@ void CMenus::RenderSettingsTee(CUIRect MainView)
|
|||
// reset render flags for possible loading screen
|
||||
TextRender()->SetRenderFlags(0);
|
||||
TextRender()->SetFontPreset(EFontPreset::DEFAULT_FONT);
|
||||
RefreshSkins();
|
||||
s_InitSkinlist = true;
|
||||
m_pClient->RefreshSkins();
|
||||
}
|
||||
TextRender()->SetRenderFlags(0);
|
||||
TextRender()->SetFontPreset(EFontPreset::DEFAULT_FONT);
|
||||
|
@ -3453,13 +3437,3 @@ void CMenus::RenderSettingsDDNet(CUIRect MainView)
|
|||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void CMenus::ConchainReloadSkins(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData)
|
||||
{
|
||||
CMenus *pThis = (CMenus *)pUserData;
|
||||
pfnCallback(pResult, pCallbackUserData);
|
||||
if(pResult->NumArguments() && (pThis->Client()->State() == IClient::STATE_ONLINE || pThis->Client()->State() == IClient::STATE_DEMOPLAYBACK))
|
||||
{
|
||||
pThis->RefreshSkins();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -212,6 +212,12 @@ void CGameClient::OnConsoleInit()
|
|||
Console()->Chain("dummy_color_feet", ConchainSpecialDummyInfoupdate, this);
|
||||
Console()->Chain("dummy_skin", ConchainSpecialDummyInfoupdate, this);
|
||||
|
||||
Console()->Chain("cl_skin_download_url", ConchainRefreshSkins, this);
|
||||
Console()->Chain("cl_skin_community_download_url", ConchainRefreshSkins, this);
|
||||
Console()->Chain("cl_download_skins", ConchainRefreshSkins, this);
|
||||
Console()->Chain("cl_download_community_skins", ConchainRefreshSkins, this);
|
||||
Console()->Chain("cl_vanilla_skins_only", ConchainRefreshSkins, this);
|
||||
|
||||
Console()->Chain("cl_dummy", ConchainSpecialDummy, this);
|
||||
Console()->Chain("cl_text_entities_size", ConchainClTextEntitiesSize, this);
|
||||
|
||||
|
@ -3371,8 +3377,17 @@ void CGameClient::LoadExtrasSkin(const char *pPath, bool AsDir)
|
|||
}
|
||||
}
|
||||
|
||||
void CGameClient::RefindSkins()
|
||||
void CGameClient::RefreshSkins()
|
||||
{
|
||||
const auto SkinStartLoadTime = time_get_nanoseconds();
|
||||
m_Skins.Refresh([&](int) {
|
||||
// if skin refreshing takes to long, swap to a loading screen
|
||||
if(time_get_nanoseconds() - SkinStartLoadTime > 500ms)
|
||||
{
|
||||
m_Menus.RenderLoading(Localize("Loading skin files"), "", 0, false);
|
||||
}
|
||||
});
|
||||
|
||||
for(auto &Client : m_aClients)
|
||||
{
|
||||
Client.m_SkinInfo.m_OriginalRenderSkin.Reset();
|
||||
|
@ -3390,9 +3405,19 @@ void CGameClient::RefindSkins()
|
|||
}
|
||||
Client.UpdateRenderInfo(IsTeamPlay());
|
||||
}
|
||||
m_Ghost.RefindSkins();
|
||||
m_Chat.RefindSkins();
|
||||
m_InfoMessages.RefindSkins();
|
||||
|
||||
for(auto &pComponent : m_vpAll)
|
||||
pComponent->OnRefreshSkins();
|
||||
}
|
||||
|
||||
void CGameClient::ConchainRefreshSkins(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData)
|
||||
{
|
||||
CGameClient *pThis = static_cast<CGameClient *>(pUserData);
|
||||
pfnCallback(pResult, pCallbackUserData);
|
||||
if(pResult->NumArguments() && pThis->m_Menus.IsInit())
|
||||
{
|
||||
pThis->RefreshSkins();
|
||||
}
|
||||
}
|
||||
|
||||
static bool UnknownMapSettingCallback(const char *pCommand, void *pUser)
|
||||
|
|
|
@ -207,6 +207,7 @@ private:
|
|||
static void ConchainLanguageUpdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
|
||||
static void ConchainSpecialInfoupdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
|
||||
static void ConchainSpecialDummyInfoupdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
|
||||
static void ConchainRefreshSkins(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
|
||||
static void ConchainSpecialDummy(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
|
||||
static void ConchainClTextEntitiesSize(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
|
||||
|
||||
|
@ -499,6 +500,8 @@ public:
|
|||
void OnLanguageChange();
|
||||
void HandleLanguageChanged();
|
||||
|
||||
void RefreshSkins();
|
||||
|
||||
void RenderShutdownMessage();
|
||||
|
||||
const char *GetItemName(int Type) const override;
|
||||
|
@ -561,8 +564,6 @@ public:
|
|||
void LoadHudSkin(const char *pPath, bool AsDir = false);
|
||||
void LoadExtrasSkin(const char *pPath, bool AsDir = false);
|
||||
|
||||
void RefindSkins();
|
||||
|
||||
struct SClientGameSkin
|
||||
{
|
||||
// health armor hud
|
||||
|
|
Loading…
Reference in a new issue