Use ICVar iterator for console partial suggest

Added public interface to ICVarIteratorInternal, this class also deals with the deletion of the iterator. This fixes the problem of cvars not showing up that have been registered after 'CModAppSystemGroup::Create()' has been called. Currently, no cvar is registered after it. This will/could change when the plugin system is utilized.

Additional changes:
- Cvar 'con_suggestion_flags_realtime' has been removed, as we no longer keep an early copy anymore; real time flags are always shows from now on.
 - Fixed a bug in 'CConsole::FindFromPartial()' where we would return in the loop when 'm_vSuggest.size() >= con_suggestion_limit->GetInt()', instead of breaking out, which skips the element sorting process.
This commit is contained in:
Kawe Mazidjatari 2023-07-22 14:51:15 +02:00
parent 9e50266649
commit 00f349c745
8 changed files with 78 additions and 58 deletions

View File

@ -202,7 +202,6 @@ ConVar* con_max_history = nullptr;
ConVar* con_suggestion_limit = nullptr;
ConVar* con_suggestion_showhelptext = nullptr;
ConVar* con_suggestion_showflags = nullptr;
ConVar* con_suggestion_flags_realtime = nullptr;
ConVar* origin_disconnectWhenOffline = nullptr;
@ -394,7 +393,6 @@ void ConVar_StaticInit(void)
con_suggestion_limit = ConVar::StaticCreate("con_suggestion_limit" , "128" , FCVAR_DEVELOPMENTONLY, "Maximum number of suggestions the autocomplete window will show for the console.", true, 0.f, false, 0.f, nullptr, nullptr);
con_suggestion_showhelptext = ConVar::StaticCreate("con_suggestion_showhelptext" , "1" , FCVAR_DEVELOPMENTONLY, "Show CommandBase help text in autocomplete window.", false, 0.f, false, 0.f, nullptr, nullptr);
con_suggestion_showflags = ConVar::StaticCreate("con_suggestion_showflags" , "1" , FCVAR_DEVELOPMENTONLY, "Show CommandBase flags in autocomplete window.", false, 0.f, false, 0.f, nullptr, nullptr);
con_suggestion_flags_realtime = ConVar::StaticCreate("con_suggestion_flags_realtime", "1" , FCVAR_DEVELOPMENTONLY, "Whether to show compile-time or run-time CommandBase flags.", false, 0.f, false, 0.f, nullptr, nullptr);
serverbrowser_hideEmptyServers = ConVar::StaticCreate("serverbrowser_hideEmptyServers", "0", FCVAR_RELEASE, "Hide empty servers in the server browser", false, 0.f, false, 0.f, nullptr, nullptr);
serverbrowser_mapFilter = ConVar::StaticCreate("serverbrowser_mapFilter", "0", FCVAR_RELEASE, "Filter servers by map in the server browser", false, 0.f, false, 0.f, nullptr, nullptr);

View File

@ -192,7 +192,6 @@ extern ConVar* con_max_history;
extern ConVar* con_suggestion_limit;
extern ConVar* con_suggestion_showhelptext;
extern ConVar* con_suggestion_showflags;
extern ConVar* con_suggestion_flags_realtime;
extern ConVar* origin_disconnectWhenOffline;
#endif // !DEDICATED

View File

@ -126,12 +126,6 @@ bool CModAppSystemGroup::StaticCreate(CModAppSystemGroup* pModAppSystemGroup)
g_pEngineTraceClient = g_pFactory->GetFactoryPtr(INTERFACEVERSION_ENGINETRACE_CLIENT, false).RCast<CEngineTraceClient*>();
g_pImGuiConfig->Load(); // Load ImGui configs.
for (auto& map : g_pCVar->DumpToMap())
{
g_pConsole->m_vsvCommandBases.push_back(
CSuggest(map.first, map.second->GetFlags()));
}
DirectX_Init();
#endif // !DEDICATED

View File

@ -587,27 +587,30 @@ void CConsole::FindFromPartial(void)
ClearAutoComplete();
m_bCanAutoComplete = false;
for (const CSuggest& suggest : m_vsvCommandBases)
ICvar::Iterator iter(g_pCVar);
for (iter.SetFirst(); iter.IsValid(); iter.Next())
{
if (m_vSuggest.size() >= size_t(con_suggestion_limit->GetInt()))
{
return;
break;
}
if (!HasPartial(suggest.m_svName, m_szInputBuf))
const ConCommandBase* pCommandBase = iter.Get();
if (pCommandBase->IsFlagSet(FCVAR_HIDDEN))
{
continue;
}
const char* pCommandName = pCommandBase->GetName();
if (!V_stristr(pCommandName, m_szInputBuf))
{
continue;
}
if (std::find(m_vSuggest.begin(), m_vSuggest.end(),
suggest.m_svName) == m_vSuggest.end())
pCommandName) == m_vSuggest.end())
{
string svValue; int nFlags = FCVAR_NONE;
const ConCommandBase* pCommandBase = g_pCVar->FindCommandBase(suggest.m_svName.c_str());
if (!pCommandBase || pCommandBase->IsFlagSet(FCVAR_HIDDEN))
{
continue;
}
string svValue;
if (!pCommandBase->IsCommand())
{
@ -636,18 +639,7 @@ void CConsole::FindFromPartial(void)
}
}
}
if (con_suggestion_showflags->GetBool())
{
if (con_suggestion_flags_realtime->GetBool())
{
nFlags = pCommandBase->GetFlags();
}
else // Display compile-time flags instead.
{
nFlags = suggest.m_nFlags;
}
}
m_vSuggest.push_back(CSuggest(suggest.m_svName + svValue, nFlags));
m_vSuggest.push_back(CSuggest(pCommandName + svValue, pCommandBase->GetFlags()));
}
else { break; }
}

View File

@ -106,7 +106,6 @@ private:
public:
bool m_bActivate = false;
vector<CSuggest> m_vsvCommandBases;
};
///////////////////////////////////////////////////////////////////////////////

View File

@ -108,7 +108,40 @@ public:
virtual bool HasQueuedMaterialThreadConVarSets() const = 0;
virtual int ProcessQueuedMaterialThreadConVarSets() = 0;
protected: class ICVarIteratorInternal;
public:
/// Iteration over all cvars.
/// (THIS IS A SLOW OPERATION AND YOU SHOULD AVOID IT.)
/// usage:
/// { ICVar::Iterator iter(g_pCVar);
/// for ( iter.SetFirst() ; iter.IsValid() ; iter.Next() )
/// {
/// ConCommandBase *cmd = iter.Get();
/// }
/// }
/// The Iterator class actually wraps the internal factory methods
/// so you don't need to worry about new/delete -- scope takes care
// of it.
/// We need an iterator like this because we can't simply return a
/// pointer to the internal data type that contains the cvars --
/// it's a custom, protected class with unusual semantics and is
/// prone to change.
class Iterator
{
public:
inline void SetFirst(void) RESTRICT;
inline void Next(void) RESTRICT;
inline bool IsValid(void) RESTRICT;
inline ConCommandBase* Get(void) RESTRICT;
inline Iterator(ICvar* icvar);
inline ~Iterator(void);
private:
ICVarIteratorInternal* m_pIter;
};
protected:
// internals for ICVarIterator
class ICVarIteratorInternal
{
public:
@ -123,4 +156,34 @@ protected:
virtual ICVarIteratorInternal* FactoryInternalIterator(void) = 0;
};
inline void ICvar::Iterator::SetFirst(void) RESTRICT
{
m_pIter->SetFirst();
}
inline void ICvar::Iterator::Next(void) RESTRICT
{
m_pIter->Next();
}
inline bool ICvar::Iterator::IsValid(void) RESTRICT
{
return m_pIter->IsValid();
}
inline ConCommandBase* ICvar::Iterator::Get(void) RESTRICT
{
return m_pIter->Get();
}
inline ICvar::Iterator::Iterator(ICvar* icvar)
{
m_pIter = icvar->FactoryInternalIterator();
}
inline ICvar::Iterator::~Iterator(void)
{
delete m_pIter;
}
#endif // ICVAR_H

View File

@ -66,9 +66,6 @@ extern CCvarUtilities* cv;
class CCvar : public CBaseAppSystem< ICvar >
{ // Implementation in engine.
public:
unordered_map<string, ConCommandBase*> DumpToMap(void);
protected:
enum ConVarSetType_t
{

View File

@ -1061,28 +1061,6 @@ int CCvarUtilities::CvarFindFlagsCompletionCallback(const char* partial,
return values;
}
//-----------------------------------------------------------------------------
// Purpose: returns all ConVars
//-----------------------------------------------------------------------------
unordered_map<string, ConCommandBase*> CCvar::DumpToMap(void)
{
stringstream ss;
CCVarIteratorInternal* itint = FactoryInternalIterator(); // Allocate new InternalIterator.
unordered_map<string, ConCommandBase*> allConVars;
for (itint->SetFirst(); itint->IsValid(); itint->Next()) // Loop through all instances.
{
ConCommandBase* pCommand = itint->Get();
const char* pszCommandName = pCommand->m_pszName;
allConVars[pszCommandName] = pCommand;
}
delete itint;
return allConVars;
}
///////////////////////////////////////////////////////////////////////////////
CCvar* g_pCVar = nullptr;