Files
FC1/CrySystem/XConsole.cpp
romkazvo 34d6c5d489 123
2023-08-07 19:29:24 +08:00

2120 lines
51 KiB
C++
Raw Permalink Blame History

// XConsole.cpp: implementation of the CXConsole class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "XConsole.h"
#include "XConsoleVariable.h"
#include "Font.h"
#include "System.h"
#include <IInput.h>
#include <ITimer.h>
#include <IScriptSystem.h>
#include <IInput.h>
#include <IRenderer.h>
#include <ISystem.h>
#include <ILog.h>
#include <IProcess.h>
#include <IGame.h>
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CXConsole::CXConsole()
{
m_pFont=NULL;
m_pRenderer=NULL;
m_pInput=NULL;
m_pImage=NULL;
m_pXFont=NULL;
m_pScriptSystem=NULL;
m_nCursorPos=0;
m_nScrollPos=0;
m_nScrollMax=600;
m_nScrollLine=0;
m_nHistoryPos=-1;
m_bRepeat=false;
m_nTabCount=0;
m_bConsoleActive=false;
m_sdScrollDir = sdNONE;
m_pSystem=NULL;
m_pKeyboard = NULL;
con_line_buffer_size=NULL;
m_bStaticBackground=false;
m_nProgress = 0;
m_nProgressRange = 0;
m_nLoadingBarTexID = 0;
m_nLoadingBackTexID = 0;
}
CXConsole::~CXConsole()
{
if(!m_mapVariables.empty())
{
while (!m_mapVariables.empty())
{
m_mapVariables.begin()->second->Release();
}
m_mapVariables.clear();
}
if(m_pXFont)
{
SAFE_RELEASE(m_pXFont);
m_pXFont=NULL;
}
}
void CXConsole::FreeRenderResources()
{
if (m_pRenderer)
{
if (m_nLoadingBarTexID)
{
m_pRenderer->RemoveTexture(m_nLoadingBarTexID);
m_nLoadingBarTexID = -1;
}
if (m_nLoadingBackTexID)
{
m_pRenderer->RemoveTexture(m_nLoadingBackTexID);
m_nLoadingBackTexID = -1;
}
if (m_pImage)
m_pImage->Release();
}
}
//////////////////////////////////////////////////////////////////////////
void CXConsole::Release()
{
delete this;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*! Initialize the Console
@param pSystem pointer to the System
*/
void CXConsole::Init(CSystem *pSystem)
{
m_pSystem=pSystem;
if (pSystem->GetICryFont())
m_pFont=pSystem->GetICryFont()->GetFont("Console");
m_pRenderer=pSystem->GetIRenderer();
m_pInput=pSystem->GetIInput();
m_pTimer=pSystem->GetITimer();
m_pScriptSystem=pSystem->GetIScriptSystem();
if (m_pInput)
{
m_pKeyboard=m_pInput->GetIKeyboard();
// Assign this class as input listener.
m_pInput->AddConsoleEventListener( this );
}
con_display_last_messages=CreateVariable("con_display_last_messages","0",0); // keep default at 1, needed for gameplay
con_line_buffer_size=CreateVariable("con_line_buffer_size","1000",0);
if (m_pRenderer)
{
m_nLoadingBarTexID = -1;
m_nLoadingBackTexID = -1;
ITexPic *pTex = 0;
pTex = pSystem->GetIRenderer()->EF_LoadTexture("console/loadingbar", FT_NORESIZE | FT_NOMIPS, 0, eTT_Base);
if (pTex) m_nLoadingBarTexID = pTex->GetTextureID();
}
else
{
m_nLoadingBarTexID = -1;
m_nLoadingBackTexID = -1;
}
if(pSystem && pSystem->IsDedicated())
m_bConsoleActive = true;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*! Crate a new console variable
@param sName console variable name
@param sValue default value
@param nFlag user definded flag, this parameter is used by other subsystems
and doesn't affect the console varible(besically of user data)
@see ICVar
*/
ICVar *CXConsole::CreateVariable(const char *sName,const char *sValue,int nFlags, const char *help)
{
ConsoleVariablesMapItor itor;
CXConsoleVariable *pCVar;
itor=m_mapVariables.find(sName);
if(itor!=m_mapVariables.end())
{
return itor->second;
}
pCVar=new CXConsoleVariable(this,m_pScriptSystem,sName,nFlags,CVAR_STRING, help);
/*
char sTemp[200];
sprintf(sTemp,"%s=%s\n",sName,sValue);
::OutputDebugString(sTemp);
*/
//the script ovveride the .ini file
if(!pCVar->m_bLoadedFromScript){
// char *res=GetVariable(sName, "Engine.Ini",sValue);
// TRACE("%s=%s",sName,res);
pCVar->Set(sValue);
}
m_mapVariables.insert(ConsoleVariablesMapItor::value_type(sName,pCVar));
return pCVar;
}
//////////////////////////////////////////////////////////////////////////
ICVar *CXConsole::CreateVariable(const char *sName,float fValue,int nFlags, const char *help)
{
ConsoleVariablesMapItor itor;
CXConsoleVariable *pCVar;
itor=m_mapVariables.find(sName);
if(itor!=m_mapVariables.end())
{
return itor->second;
}
pCVar=new CXConsoleVariable(this,m_pScriptSystem,sName,nFlags,CVAR_FLOAT, help);
//the script ovveride the .ini file
if(!pCVar->m_bLoadedFromScript){
pCVar->Set(fValue);
}
m_mapVariables.insert(ConsoleVariablesMapItor::value_type(sName,pCVar));
return pCVar;
}
//////////////////////////////////////////////////////////////////////////
ICVar *CXConsole::CreateVariable(const char *sName,int iValue,int nFlags, const char *help)
{
ConsoleVariablesMapItor itor;
CXConsoleVariable *pCVar;
itor=m_mapVariables.find(sName);
if(itor!=m_mapVariables.end())
{
return itor->second;
}
pCVar=new CXConsoleVariable(this,m_pScriptSystem,sName,nFlags,CVAR_INT, help);
//the script ovveride the .ini file
if(!pCVar->m_bLoadedFromScript){
pCVar->Set(iValue);
}
m_mapVariables.insert(ConsoleVariablesMapItor::value_type(sName,pCVar));
return pCVar;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*! Remove a variable from the console
@param sVarName console variable name
@param bDelete if true the variable is deleted
@see ICVar
*/
void CXConsole::UnregisterVariable(const char *sVarName,bool bDelete)
{
ConsoleVariablesMapItor itor;
itor=m_mapVariables.find(sVarName);
if(itor==m_mapVariables.end())
return;
ICVar *pCVar=itor->second;
m_mapVariables.erase(sVarName);
if(bDelete)
{
pCVar->Release();
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*! Set the y coordinate where the console will stop to scroll when is dropped
@param value y in screen coordinates
*/
void CXConsole::SetScrollMax(int value)
{
m_nScrollMax=value;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void CXConsole::SetImage(ITexPic *pImage,bool bDeleteCurrent)
{
if (bDeleteCurrent)
{
m_pRenderer=m_pSystem->GetIRenderer();
if (m_pRenderer)
m_pRenderer->RemoveTexture(m_pImage);
}
m_pImage=pImage;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*! show/hide the console
@param specifies if the window must be (true=show,false=hide)
*/
void CXConsole::ShowConsole(bool show)
{
SetStatus(show);
if(m_bConsoleActive)
m_sdScrollDir=sdDOWN;
else
m_sdScrollDir=sdUP;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*! Crate a new console variable that store the value in a user defined memory block
@param sName console variable name
@param src pointer to the memory that will store the value
@param value default value
@param type type of the value (can be CVAR_INT|CVAR_FLOAT)
@see ICVar
*/
int CXConsole::Register(const char *sName, void *src, float value, int flags, int type, const char *help)
{
int nRes=0;
float fRes=0;
ConsoleVariablesMapItor itor;
CXConsoleVariable *pICVar;
itor=m_mapVariables.find(sName);
if(itor!=m_mapVariables.end())
{
if (flags & CVF_CHANGE_SOURCE)
itor->second->SetSrc(src);
// found such variable; just set its
return 0;
}
char *sValue=NULL;
switch(type)
{
case CVAR_INT:
pICVar=new CXConsoleVariable(this,m_pScriptSystem,sName,src,flags,CVAR_INT, help);
if(!pICVar->m_bLoadedFromScript)
{
// nRes=(int)(GetVariable(sName, "Engine.Ini", value));
pICVar->Set((int)nRes);
}
m_mapVariables.insert(ConsoleVariablesMapItor::value_type(sName,pICVar));
return nRes;
break;
case CVAR_FLOAT:
pICVar=new CXConsoleVariable(this,m_pScriptSystem,sName,src,flags,CVAR_FLOAT, help);
if(!pICVar->m_bLoadedFromScript)
{
// fRes=GetVariable(sName, "Engine.Ini", value);
pICVar->Set(fRes);
}
m_mapVariables.insert(ConsoleVariablesMapItor::value_type(sName,pICVar));
return ((int)(fRes));
break;
default:
CryError( "<CrySystem> (CXConsole::Register) Unknown console variable type" );
break;
}
return 0;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*! Crate a new console variable that store the value in a user defined floating point
@param sName console variable name
@param src pointer to the memory that will store the value
@param value default value
@see ICVar
*/
float CXConsole::Register(const char *sName, float *src, float value, int flags, const char *help)
{
// float nRes=0;
ConsoleVariablesMapItor itor;
CXConsoleVariable *pICVar;
itor=m_mapVariables.find(sName);
if(itor!=m_mapVariables.end())
{
if (flags & CVF_CHANGE_SOURCE)
itor->second->SetSrc(src);
return itor->second->GetFVal();
}
pICVar=new CXConsoleVariable(this,m_pScriptSystem,sName,src,flags,CVAR_FLOAT, help);
if(!pICVar->m_bLoadedFromScript)
{
// nRes=GetVariable(sName, "Engine.Ini", value);
pICVar->Set(value);
}
m_mapVariables.insert(ConsoleVariablesMapItor::value_type(sName,pICVar));
return pICVar->GetFVal();//value;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*! Crate a new console variable that store the value in a user defined integer
@param sName console variable name
@param src pointer to the memory that will store the value
@param value default value
@see ICVar
*/
int CXConsole::Register(const char *sName, int *src, float value, int flags, const char *help)
{
// int nRes=0;
ConsoleVariablesMapItor itor;
CXConsoleVariable *pICVar;
itor=m_mapVariables.find(sName);
if(itor!=m_mapVariables.end())
{
if (flags & CVF_CHANGE_SOURCE)
itor->second->SetSrc(src);
return itor->second->GetIVal();
}
pICVar=new CXConsoleVariable(this,m_pScriptSystem,sName,src,flags,CVAR_INT, help);
if(!pICVar->m_bLoadedFromScript)
{
// nRes=(int)(GetVariable(sName, "Engine.Ini", value));
pICVar->Set(value);
}
m_mapVariables.insert(ConsoleVariablesMapItor::value_type(sName,pICVar));
return (int)pICVar->GetIVal();//value;
}
////////////////////////////////////////////////////////
/*! Bind a console command to a key
@param sCmd console command that must be executed
@param sRes name of the key to invoke the command
@param bExecute legacy parameter(will be removed soon)
*/
void CXConsole::CreateKeyBind(const char *sCmd,const char *sRes,bool bExecute)
{
m_mapBinds.insert(ConsoleBindsMapItor::value_type(sRes,sCmd));
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*! Dump all key binds to a callback-interface
@param Callback callback-interface which needs to be called for each element
*/
void CXConsole::DumpKeyBinds( IKeyBindDumpSink *pCallback )
{
for (ConsoleBindsMap::iterator it = m_mapBinds.begin(); it != m_mapBinds.end(); ++it)
{
pCallback->OnKeyBindFound( it->first.c_str(),it->second.c_str() );
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
const char* CXConsole::FindKeyBind( const char *sCmd )
{
ConsoleBindsMap::iterator it = m_mapBinds.find(sCmd);
if (it != m_mapBinds.end())
return it->second.c_str();
return 0;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*! Dump all console-variables to a callback-interface
@param Callback callback-interface which needs to be called for each element
*/
void CXConsole::DumpCVars(ICVarDumpSink *pCallback,unsigned int nFlagsFilter)
{
ConsoleVariablesMapItor It=m_mapVariables.begin();
while (It!=m_mapVariables.end())
{
if((nFlagsFilter==0) || ((nFlagsFilter!=0) && (It->second->GetFlags()&nFlagsFilter) ))
pCallback->OnElementFound(It->second);
++It;
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*! Retrieve a console variable by name
@param sName variable name
@see ICVar
*/
ICVar* CXConsole::GetCVar( const char *sName, const bool bCaseSensitive )
{
assert(this);
assert(sName);
if(bCaseSensitive)
{
// faster
ConsoleVariablesMapItor itor;
itor=m_mapVariables.find(sName);
if(itor!=m_mapVariables.end()){
return itor->second;
}
}
else
{
// much slower but allowes names with wrong case (use only where performce doesn't matter)
ConsoleVariablesMapItor it;
for(it=m_mapVariables.begin(); it!=m_mapVariables.end(); ++it)
{
if(stricmp(it->first.c_str(),sName)==0)
return it->second;
}
}
return NULL; // haven't found this name
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*! Refresh the internal values of a console variable
@param sVarName variable name
@see ICVar
*/
void CXConsole::RefreshVariable(string sVarName)
{
ConsoleVariablesMapItor itor;
itor=m_mapVariables.find(sVarName);
if(itor!=m_mapVariables.end()){
CXConsoleVariable *pCV=itor->second;
pCV->Refresh();
if(pCV->GetFlags()&VF_REQUIRE_NET_SYNC){
m_pSystem->m_pGame->OnSetVar(pCV);
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*! Legacy function
*/
void CXConsole::Help(const char *command)
{
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*! Read a value from a configuration file (.ini) and return the value
@param szVarName variable name
@param szFileName source configuration file
@param def_val default value (if the variable is not found into the file)
*/
char *CXConsole::GetVariable( const char * szVarName, const char * szFileName, const char * def_val )
{
assert( m_pSystem );
//return m_pSystem->GetIniVar( szVarName, szFileName, def_val);
return 0;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*! Read a value from a configuration file (.ini) and return the value
@param szVarName variable name
@param szFileName source configuration file
@param def_val default value (if the variable is not found into the file)
*/
float CXConsole::GetVariable( const char * szVarName, const char * szFileName, float def_val )
{
assert( m_pSystem );
//return m_pSystem->GetIniVar( szVarName, szFileName, def_val);
return 0;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*! Retreive the status of the console (active/not active)
*/
bool CXConsole::GetStatus()
{
return m_bConsoleActive;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*! Clear the console text
*/
void CXConsole::Clear()
{
m_dqConsoleBuffer.clear();
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*! Update the console
*/
void CXConsole::Update()
{
// Repeat GetIRenderer (For Editor).
if (!m_pSystem)
return;
m_pRenderer = m_pSystem->GetIRenderer();
// Process Key press repeat.
if (m_bConsoleActive)
{
if (m_nRepeatKey > XKEY_NULL)
{
float fRepeatSpeed = 40.0;
if (GetCVar("ui_RepeatSpeed"))
{
fRepeatSpeed = (float)GetCVar("ui_RepeatSpeed")->GetIVal();
}
float fTime = m_pSystem->GetITimer()->GetAsyncCurTime() * 1000.0f;
float fNextTimer = (1000.0f / fRepeatSpeed); // repeat speed
while (fTime - m_nRepeatTimer > fNextTimer)
{
ProcessInput(m_nRepeatKey, m_sLastKeyName.c_str());
m_nRepeatTimer += fNextTimer;
}
}
}
}
//////////////////////////////////////////////////////////////////////////
bool CXConsole::OnInputEvent( const SInputEvent &event )
{
// Process input event.
ConsoleBindsMapItor itorBind;
int nKeyCode = event.key;
int nModifiers = event.moidifiers;
const char *sKeyName = event.keyname;
if (event.type == SInputEvent::KEY_RELEASE && m_bConsoleActive)
{
m_nRepeatKey = XKEY_NULL;
if ((nKeyCode == XKEY_RETURN) || (nKeyCode == XKEY_NUMPADENTER))
{
ExecuteInputBuffer();
m_nScrollLine=0;
return false;
}
}
if (event.type != SInputEvent::KEY_PRESS)
return false;
if (nKeyCode <= XKEY_NULL)
return false;
m_nRepeatKey = nKeyCode;
m_sLastKeyName = sKeyName;
float fRepeatDelay = 200.0f;
if (GetCVar("ui_RepeatDelay"))
{
fRepeatDelay = (float)GetCVar("ui_RepeatDelay")->GetIVal();
}
m_nRepeatTimer = m_pTimer->GetAsyncCurTime() * 1000.0f + fRepeatDelay;
//execute Binds
if(!m_bConsoleActive)
{
itorBind = m_mapBinds.find(sKeyName);
if(itorBind != m_mapBinds.end())
{
ExecuteString(itorBind->second.c_str(),true);
m_sInputBuffer = "";
m_nCursorPos=0;
}
}
else
{
if (nKeyCode != XKEY_TAB)
ResetAutoCompletion();
if (nKeyCode == XKEY_V && (nModifiers&XKEY_MOD_CONTROL) != 0)
{
Paste();
return false;
}
if (nKeyCode == XKEY_C && (nModifiers&XKEY_MOD_CONTROL) != 0)
{
Copy();
return false;
}
}
switch(nKeyCode)
{
case XKEY_TILDE:
ShowConsole(!GetStatus());
m_sInputBuffer="";
m_nCursorPos=0;
return false;
////////////////////////////////////////////////////////////
case XKEY_ESCAPE:
//switch process or page or other things
m_sInputBuffer="";
m_nCursorPos=0;
if (m_pSystem)
{
if (!m_bConsoleActive)
{
m_pSystem->GetIGame()->SendMessage("Switch");
}
ISystemUserCallback *pCallback = ((CSystem*)m_pSystem)->GetUserCallback();
if (pCallback)
pCallback->OnProcessSwitch();
}
return false;
////////////////////////////////////////////////////////////
default:
break;
}
ProcessInput( nKeyCode,m_pInput->GetKeyName(event.key, event.moidifiers, 1) );
return false;
}
//////////////////////////////////////////////////////////////////////////
void CXConsole::ProcessInput( int nKeyCode,const char *sKeyName )
{
if (!m_bConsoleActive)
return;
switch(nKeyCode)
{
////////////////////////////////////////////////////////////
case XKEY_BACKSPACE:
RemoveInputChar(true);
break;
////////////////////////////////////////////////////////////
case XKEY_LEFT:
if(m_nCursorPos)
m_nCursorPos--;
break;
////////////////////////////////////////////////////////////
case XKEY_RIGHT:
if(m_nCursorPos<(int)(m_sInputBuffer.length()))
m_nCursorPos++;
break;
////////////////////////////////////////////////////////////
case XKEY_UP:
{
const char *szHistoryLine=GetHistoryElement(true); // true=UP
if(szHistoryLine)
{
m_sInputBuffer=szHistoryLine;
m_nCursorPos=(int)m_sInputBuffer.size();
}
}
break;
////////////////////////////////////////////////////////////
case XKEY_DOWN:
{
const char *szHistoryLine=GetHistoryElement(false); // false=DOWN
if(szHistoryLine)
{
m_sInputBuffer=szHistoryLine;
m_nCursorPos=(int)m_sInputBuffer.size();
}
}
break;
////////////////////////////////////////////////////////////
case XKEY_TAB:
if (
(!m_pSystem->GetIInput()->KeyDown(XKEY_LALT)) &&
(!m_pSystem->GetIInput()->KeyDown(XKEY_RALT)) &&
(!m_pSystem->GetIInput()->KeyDown(XKEY_ALT)))
{
m_sInputBuffer = ProcessCompletion(m_sInputBuffer.c_str());
m_nCursorPos = m_sInputBuffer.size();
}
break;
////////////////////////////////////////////////////////////
case XKEY_PAGE_UP:
if(m_nScrollLine<(int)(m_dqConsoleBuffer.size()-2))
m_nScrollLine++;
break;
////////////////////////////////////////////////////////////
case XKEY_PAGE_DOWN:
if(m_nScrollLine)
m_nScrollLine--;
break;
////////////////////////////////////////////////////////////
case XKEY_HOME:
m_nCursorPos=0;
break;
////////////////////////////////////////////////////////////
case XKEY_END:
m_nCursorPos=(int)m_sInputBuffer.length();
break;
////////////////////////////////////////////////////////////
case XKEY_DELETE:
RemoveInputChar(false);
break;
////////////////////////////////////////////////////////////
default:
if (sKeyName)
{
if(nKeyCode==XKEY_SPACE)
{
AddInputChar(' ');
}
else{
if(strlen(sKeyName)!=1)
return;
AddInputChar( sKeyName[0] );
}
}
break;
////////////////////////////////////////////////////////////
}
m_nLastKey = nKeyCode;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
const char* CXConsole::GetHistoryElement( const bool bUpOrDown )
{
static string sReturnString; // is that save enough?
if(bUpOrDown)
{
if(!m_dqHistory.empty())
{
if(m_nHistoryPos<(int)(m_dqHistory.size()-1))
{
m_nHistoryPos++;
sReturnString=m_dqHistory[m_nHistoryPos];
return sReturnString.c_str();
}
}
}
else
{
if(m_nHistoryPos>0)
{
m_nHistoryPos--;
sReturnString=m_dqHistory[m_nHistoryPos];
return sReturnString.c_str();
}
}
return 0;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*! Draw the console
*/
void CXConsole::Draw()
{
if(!m_pSystem || !m_nScrollMax)
return;
if(!m_pRenderer)
{
// For Editor.
m_pRenderer = m_pSystem->GetIRenderer();
}
if(!m_pRenderer)
return;
if (!m_pFont)
{
// For Editor.
ICryFont *pICryFont=m_pSystem->GetICryFont();
if(pICryFont)
m_pFont= m_pSystem->GetICryFont()->GetFont("Default");
}
float fCurrTime=m_pTimer->GetCurrTime();
ScrollConsole();
if (m_nScrollPos<=0)
{
//#ifdef _DEBUG
DrawBuffer(70, "buttonfocus");
//#endif
return;
}
const double fBlinkTime=CURSOR_TIME*2.0;
m_bDrawCursor = fmod((double)fCurrTime,fBlinkTime)<0.5;
if (m_pImage)
{
float time = fCurrTime*0.05f;
//#ifndef _XBOX
if (!m_nProgressRange)
{
if (m_bStaticBackground)
{
m_pRenderer->SetState(GS_NODEPTHTEST);
m_pRenderer->Draw2dImage(0,0,800,600,m_pImage->GetTextureID(), 0.0f, 1.0f, 1.0f, 0.0f);
}else
{
m_pRenderer->SetState(GS_NODEPTHTEST);
m_pRenderer->TransformTextureMatrix(time,0,0,1);
m_pRenderer->Draw2dImage(0,(float)(m_nScrollPos-m_nScrollMax),800,(float)(m_nScrollMax),m_pImage->GetTextureID(),4.0f,2.0f);
m_pRenderer->ResetTextureMatrix();
m_pRenderer->SetState(GS_BLSRC_SRCALPHA | GS_BLDST_ONEMINUSSRCALPHA | GS_NODEPTHTEST);
m_pRenderer->SetMaterialColor(1,1,1,0.5f);
m_pRenderer->TransformTextureMatrix(time,0,0,-1);
m_pRenderer->Draw2dImage(0,(float)(m_nScrollPos-m_nScrollMax),800,(float)(m_nScrollMax),m_pImage->GetTextureID(),4.0f,2.0f);
m_pRenderer->ResetTextureMatrix();
}
}
/*#else
if(m_bStaticBackground)
m_pRenderer->Draw2dImage(0,(float)(m_nScrollPos-m_nScrollMax),800,(float)m_nScrollMax,m_pImage->GetTextureID(),4.0f,2.0f);
else
m_pRenderer->Draw2dImage(0,0,800,600,m_pImage->GetTextureID());
#endif */
}
// draw progress bar
if(m_nProgressRange)
{
float fRcp1024 = 1.0f / 1024.0f;
float fProgress = min(1.0f, m_nProgress / (float)m_nProgressRange);
float fTexProgress0 = 51.0f * fRcp1024;
float fTexProgress1 = (51.0f + fProgress * (1024.0f - 51.0f*2.0f)) * fRcp1024;
m_pRenderer->SetState(GS_BLSRC_SRCALPHA | GS_BLDST_ONEMINUSSRCALPHA | GS_NODEPTHTEST);
m_pRenderer->Draw2dImage(0.0, 0.0, 800.0f, 600.0f, m_nLoadingBackTexID, 0.0f, 1.0f, 1.0f, 0.0f);
m_pRenderer->Draw2dImage(40, 480, fProgress * (800.0f - 40.0f*2.0f), 13, m_nLoadingBarTexID, fTexProgress0, 1.0f, fTexProgress1, 0.0f);
}
int nPrevMode = m_pRenderer->SetPolygonMode(0);
//if (!m_bStaticBackground)
DrawBuffer(m_nScrollPos, "console");
m_pRenderer->SetPolygonMode(nPrevMode);
}
void CXConsole::DrawBuffer(int nScrollPos, const char *szEffect)
{
if(!m_bConsoleActive && (con_display_last_messages->GetIVal()==0))
return;
if (m_pFont && m_pRenderer)
{
m_pFont->UseRealPixels(false);
m_pFont->SetEffect(szEffect);
m_pFont->SetSameSize(true);
m_pFont->SetCharWidthScale(1.5f / 3.0f);
m_pFont->SetSize(vector2f(14, 14));
m_pFont->SetColor(color4f(1,1,1,1));
m_pFont->UseRealPixels(true);
float csize = 0.8f * m_pFont->GetCharHeight();
m_pFont->UseRealPixels(false);
float ypos = nScrollPos-csize-3.0f;
float fCharWidth=(m_pFont->GetCharWidth() * m_pFont->GetCharWidthScale());
/*if (GetFont() && m_pRenderer)
{
float fXScale = 0.5f;
float fYScale = 1.0f;
CXFont *pFont= GetFont();
m_pRenderer->SetFontScale(fXScale, fYScale);
int csize = (int)(pFont->m_charsize*fYScale*(float)(m_pRenderer->GetHeight())/600.0f);
int nCharWidth = (int)(pFont->m_charsize*fXScale*(float)(m_pRenderer->GetWidth())/800.0f);
m_pRenderer->SetCurFontColor(Col_White);*/
//int ypos=nScrollPos-csize-3;
//Draw the input line
if(m_bConsoleActive && !m_nProgressRange)
{
/*m_pRenderer->DrawString(LINE_BORDER-nCharWidth, ypos, false, ">");
m_pRenderer->DrawString(LINE_BORDER, ypos, false, m_sInputBuffer.c_str());
if(m_bDrawCursor)
m_pRenderer->DrawString(LINE_BORDER+nCharWidth*m_nCursorPos, ypos, false, "_");*/
m_pFont->DrawString((float)(LINE_BORDER-fCharWidth), (float)ypos, ">");
m_pFont->DrawString((float)LINE_BORDER, (float)ypos, m_sInputBuffer.c_str(),false);
if(m_bDrawCursor)
{
string szCursorLeft(m_sInputBuffer.c_str(), m_sInputBuffer.c_str() + m_nCursorPos);
int n = m_pFont->GetTextLength(szCursorLeft.c_str(), false);
m_pFont->DrawString((float)(LINE_BORDER+(fCharWidth * n)), (float)ypos, "_");
}
}
ypos-=csize;
ConsoleBufferRItor ritor;
ritor=m_dqConsoleBuffer.rbegin();
int nScroll=0;
while(ritor!=m_dqConsoleBuffer.rend() && ypos>=0)
{
if(nScroll>=m_nScrollLine)
{
const char *buf=ritor->c_str();// GetBuf(k);
if(*buf>0 && *buf<32) buf++; // to jump over verbosity level character
if (ypos+csize>0)
m_pFont->DrawString((float)LINE_BORDER, (float)ypos, buf,false);
//m_pRenderer->DrawString(LINE_BORDER, ypos, false, buf);
//CSystem::GetRenderer()->WriteXY(m_font,0,ypos,0.5f,1,1,1,1,1,buf);
ypos-=csize;
}
nScroll++;
++ritor;
} //k
}
}
bool CXConsole::GetLineNo( const DWORD indwLineNo, char *outszBuffer, const DWORD indwBufferSize ) const
{
assert(outszBuffer);
assert(indwBufferSize>0);
outszBuffer[0]=0;
ConsoleBuffer::const_reverse_iterator ritor = m_dqConsoleBuffer.rbegin();
ritor+=indwLineNo;
if(indwLineNo>=m_dqConsoleBuffer.size())
return false;
const char *buf=ritor->c_str();// GetBuf(k);
if(*buf>0 && *buf<32) buf++; // to jump over verbosity level character
strncpy(outszBuffer,buf,indwBufferSize-1);
outszBuffer[indwBufferSize-1]=0;
return true;
}
int CXConsole::GetLineCount() const
{
return m_dqConsoleBuffer.size();
}
void CXConsole::ScrollConsole()
{
if(!m_pRenderer)
return;
int nCurrHeight=m_pRenderer->GetHeight();
switch (m_sdScrollDir)
{
/////////////////////////////////
case sdDOWN: // The console is scrolling down
// Vlads note: console should go down immediately, otherwise it can look very bad on startup
//m_nScrollPos+=nCurrHeight/2;
m_nScrollPos = m_nScrollMax;
if (m_nScrollPos>m_nScrollMax)
{
m_nScrollPos = m_nScrollMax;
m_sdScrollDir = sdNONE;
}
break;
/////////////////////////////////
case sdUP: // The console is scrolling up
m_nScrollPos-=nCurrHeight;//2;
if (m_nScrollPos<0)
{
m_nScrollPos = 0;
m_sdScrollDir = sdNONE;
}
break;
/////////////////////////////////
case sdNONE:
break;
/////////////////////////////////
}
}
void CXConsole::AddCommand(const char *sName, const char *sScriptFunc, const DWORD indwFlags, const char *help)
{
#if defined(_DEBUG) && !defined(LINUX)
if(!*help)
{
char buf[100];
sprintf(buf, "MISSING HELP FOR COMMAND: %s\n", sName);
OutputDebugString(buf);
};
#endif
XConsoleCommand cmd;
cmd.m_sName=sName;
cmd.m_sCommand=sScriptFunc;
cmd.m_psHelp=help;
cmd.m_dwFlags=indwFlags;
m_mapCommands.insert(ConsoleCommandsMapItor::value_type(sName,cmd));
}
bool hasprefix(const char *s, const char *prefix)
{
while(*prefix) if(*prefix++!=*s++) return false;
return true;
};
void CXConsole::DumpCommandsVars(char *prefix)
{
FILE *f = fopen("consolecommandsandvars.txt", "w");
if(!f) return;
fprintf(f," CHEAT: stays in the default value if cheats are not disabled\n");
fprintf(f," REQUIRE_NET_SYNC: cannot be changed on client and when connecting it<69>s sent to the client\n");
fprintf(f," SAVEGAME: stored when saving a savegame\n");
fprintf(f," READONLY: can not be changed by the user\n");
fprintf(f,"-------------------------\n");
fprintf(f,"\n");
for(ConsoleCommandsMapItor itrCmd = m_mapCommands.begin(); itrCmd!=m_mapCommands.end(); ++itrCmd)
{
XConsoleCommand &cmd = itrCmd->second;
if(hasprefix(cmd.m_sName.c_str(), prefix))
{
string sFlags;
if(cmd.m_dwFlags&VF_CHEAT) sFlags+=" CHEAT";
if(cmd.m_dwFlags&VF_REQUIRE_NET_SYNC) sFlags+=" REQUIRE_NET_SYNC";
if(cmd.m_dwFlags&VF_SAVEGAME) sFlags+=" SAVEGAME";
if(cmd.m_dwFlags&VF_READONLY) sFlags+=" READONLY";
fprintf(f, "command: %s %s\nscript: %s\nhelp: %s\n\n", cmd.m_sName.c_str(), sFlags.c_str(), cmd.m_sCommand.c_str(), cmd.m_psHelp);
}
};
for(ConsoleVariablesMapItor itrVar = m_mapVariables.begin(); itrVar!=m_mapVariables.end(); ++itrVar)
{
ICVar *var = itrVar->second;
char *types[] = { "?", "int", "float", "string", "?" };
if(hasprefix(var->GetName(), prefix))
{
string sFlags;
if(var->GetFlags()&VF_CHEAT) sFlags+=" CHEAT";
if(var->GetFlags()&VF_REQUIRE_NET_SYNC) sFlags+=" REQUIRE_NET_SYNC";
if(var->GetFlags()&VF_SAVEGAME) sFlags+=" SAVEGAME";
if(var->GetFlags()&VF_READONLY) sFlags+=" READONLY";
fprintf(f, "variable: %s %s\ntype: %s\ncurrent: %s\nhelp: %s\n\n", var->GetName(), sFlags.c_str(), types[var->GetType()], var->GetString(), var->GetHelp());
}
};
ConsoleLog( "succesfully wrote list of commands & variables to $3consolecommandsandvars.txt");
fclose(f);
};
void CXConsole::DisplayHelp( const char *help, const char *name)
{
if(!*help)
{
ConsoleLog("No help available for $3%s", name);
}
else
{
char *start, *pos;
for(pos = (char *)help, start = (char *)help; pos = strstr(pos, "\n"); start = ++pos)
{
string s = start;
s.resize(pos-start);
ConsoleLog(" $3%s", s.c_str());
};
ConsoleLog(" $3%s", start);
};
};
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*! Execute a string in the console
@param command console command
*/
void CXConsole::ExecuteString( const char *command,bool bNeedSlash,bool bIgnoreDevMode )
{
ILog *pLog=m_pSystem->GetILog(); assert(pLog);
string sTemp=command;
string sCommand;
ConsoleCommandsMapItor itrCmd;
ConsoleVariablesMapItor itrVar;
if(sTemp.empty())
return;
///////////////////////////
//Execute as string
if(command[0]=='#')
{
if ( !bIgnoreDevMode ) AddLine(sTemp);//don't put line in console if we are overriding devmode: TRay 3/4/04
IGame *pGame=m_pSystem->GetIGame(); assert(pGame);
if (m_pSystem->IsDevMode() || bIgnoreDevMode)
{
sTemp=&command[1];
m_pScriptSystem->ExecuteBuffer(sTemp.c_str(),sTemp.length());
m_bDrawCursor = 0;
}
else
{
// Warning.
// No Cheat warnings. ConsoleWarning("Console execution is cheat protected");
}
return;
}
string::size_type nPos;
//is a command or console var
if(command[0]=='\\' || !bNeedSlash)
{
if (GetStatus())
AddLine(sTemp);
sTemp=&command[bNeedSlash?1:0];
if (strnicmp(sTemp.c_str(),"pb_",3 ) == 0)
{
ICVar *pVar = GetCVar("sys_punkbuster_loaded");
if (!pVar)
{
ConsoleLog( "PunkBuster is not currently loaded." );
}
return;
}
if((nPos=sTemp.find_first_of(' '))==string::npos)
{
sCommand=sTemp;
}
else
{
sCommand=sTemp.substr(0,nPos);
}
//////////////////////////////////////////
//Check if is a command
itrCmd=m_mapCommands.find(sCommand);
if(itrCmd!=m_mapCommands.end())
{
sTemp=command;
ExecuteCommand((itrCmd->second), sTemp,bIgnoreDevMode);
return;
}
//////////////////////////////////////////
//Check if is a variable
itrVar=m_mapVariables.find(sCommand);
if(itrVar!=m_mapVariables.end())
{
string sScriptCommand;
sCommand=itrVar->first;
if(nPos==string::npos)
{
}
else
{
sTemp=sTemp.substr(nPos+1);
// "" clears the cvar's contents
if (sTemp == "\"\"")
{
sScriptCommand=sCommand+"=\"\"";
m_pScriptSystem->ExecuteBuffer(sScriptCommand.c_str(),sScriptCommand.length());
}
else
{
sScriptCommand=sCommand+"=\""+sTemp+"\"";
//remove useles spaces
while((nPos=sTemp.find(' '))!=string::npos)
{
sTemp.erase(nPos,1);
}
ICVar *v = itrVar->second;
if(sTemp=="?" && ((v->GetFlags() & VF_NOHELP) == 0))
{
ICVar *v = itrVar->second;
DisplayHelp( v->GetHelp(), sCommand.c_str());
return;
};
if(sTemp.length())
m_pScriptSystem->ExecuteBuffer(sScriptCommand.c_str(),sScriptCommand.length());
}
}
ICVar *pVar=itrVar->second;
// the following line called AddLine() indirectly
ConsoleLog("\001%s",(string(pVar->GetName())+"="+string(pVar->GetString())).c_str() );
return;
}
}
else if(bNeedSlash)
{
string tmp=command;
size_t pp=0;
AddLine(sTemp);
while((pp=tmp.find("\""))!=string::npos){
tmp.replace(pp, 1,"'");
}
//<<FIXME>> think a better way to the broadcast string thing
tmp=string("if(Client)then Client:Say(\"")+tmp+string("\"); end");
m_pScriptSystem->ExecuteBuffer(tmp.c_str(),tmp.size());
return;
}
ConsoleWarning("Unknown command: %s", command);
}
//////////////////////////////////////////////////////////////////////////
void CXConsole::ExecuteCommand(XConsoleCommand &cmd,string &str,bool bIgnoreDevMode)
{
std::vector<string> args;
size_t t=1;
for(;;)
{
t = str.find_first_of("\\",t);
if (t==string::npos)break;
str.replace(t, 1, "\\\\", 2);
t+=2;
}
for(t=1;;)
{
t = str.find_first_of("\"",t);
if (t==string::npos)break;
str.replace(t, 1, "\\\"", 2);
t+=2;
}
for(char *p = (char *)str.c_str(); *p;)
{
while(*p==' ') p++;
char *s = p;
while(*p && *p!=' ') p++;
if(p!=s) args.push_back(string(s, p));
}
if(args.size()>=2 && args[1]=="?" && ((cmd.m_dwFlags & VF_NOHELP) == 0))
{
DisplayHelp( cmd.m_psHelp, cmd.m_sName.c_str() );
return;
}
if((cmd.m_dwFlags&VF_CHEAT)!=0 && !m_pSystem->IsDevMode() && !bIgnoreDevMode)
{
// No Log. ConsoleWarning("Command %s is cheat protected.", cmd.m_sName.c_str());
return;
}
string buf = cmd.m_sCommand.c_str();
size_t pp = buf.find("%%");
if(pp!=string::npos)
{
string list = "";
for(unsigned int i = 1; i<args.size(); i++)
{
list += "\""+args[i]+"\"";
if(i<args.size()-1) list += ",";
};
buf.replace(pp, 2, list);
}else if((pp = buf.find("%line"))!=string::npos){
string tmp="\""+str.substr(str.find(" ")+1)+"\"";
if(args.size()>1)
{
buf.replace(pp, 5, tmp);
}
else
{
buf.replace(pp, 5, "");
}
}
else
{
for(unsigned int i = 1; i<=args.size(); i++)
{
char pat[10];
sprintf(pat, "%%%d", i);
size_t pos = buf.find(pat);
if(pos==string::npos)
{
if(i!=args.size())
{
ConsoleWarning("Too many arguments for: %s", cmd.m_sName.c_str());
return;
};
}
else
{
if(i==args.size())
{
ConsoleWarning("Not enough arguments for: %s", cmd.m_sName.c_str());
return;
};
string arg = "\""+args[i]+"\"";
buf.replace(pos, strlen(pat), arg);
};
};
};
m_pScriptSystem->ExecuteBuffer(buf.c_str(), buf.length());
m_bDrawCursor = 0;
/*
string::size_type nPos;
string sTemp;
string sParam;
string sParamList;
sTemp=str;
string::npos;
string sCommandBuf=cmd.sCommand;
int nParam=0;
nParam=sCommandBuf.find("%%");
nPos = 0;
while(sTemp[nPos]==' ') nPos++;
sTemp=sTemp.substr(nPos);
nPos=sTemp.find(' ');
while((nPos!=string::npos))
{
sParam=sTemp.substr(0,nPos);
sParam="\""+sParam+"\"";
while(sTemp[nPos]==' ') nPos++;
sTemp=sTemp.substr(nPos);
sParamList+=sParam+",";
nPos=sTemp.find(' ');
}
if(!sTemp.empty())
{
sParam="\""+sTemp+"\"";
sParamList+=sParam;
}
while((nParam=sCommandBuf.find("%%"))!=string::npos)
{
sCommandBuf.replace(nParam,2,sParamList.c_str(),sParamList.length());
}
//TRACE("sCommandBuf %d",sCommandBuf.c_str());
m_pScriptSystem->ExecuteBuffer(sCommandBuf.c_str(),sCommandBuf.length());
*/
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*! Print a message into the log and abort the execution of the application
@param message error string to print in the log
*/
void CXConsole::Exit(const char * szExitComments, ...)
{
char sResultMessageText[4096]="";
if(szExitComments)
{ // make result string
va_list arglist;
va_start(arglist, szExitComments);
vsprintf(sResultMessageText, szExitComments, arglist);
va_end(arglist);
}
else
strcpy(sResultMessageText, "No comments from application");
CryError( sResultMessageText );
}
void CXConsole::ResetAutoCompletion()
{
m_nTabCount = 0;
m_sPrevTab = "";
}
char *CXConsole::ProcessCompletion(const char *szInputBuffer)
{
static string szInput;
szInput = szInputBuffer;
int offset = (szInputBuffer[0] == '\\' ? 1 : 0);
if ((m_sPrevTab.size() > strlen(szInputBuffer + offset)) || strnicmp(m_sPrevTab.c_str(), (szInputBuffer + offset), m_sPrevTab.size()))
{
m_nTabCount = 0;
m_sPrevTab = "";
}
if(szInput == "")
{
szInput = "\\";
return (char *)szInput.c_str();
}
int nMatch = 0;
ConsoleCommandsMapItor itrCmds;
ConsoleVariablesMapItor itrVars;
bool showlist = !m_nTabCount && m_sPrevTab=="";
if (m_nTabCount==0)
{
if(szInput.size()>0)
if(szInput[0]=='\\')
m_sPrevTab=&szInput.c_str()[1];
else
{
m_sPrevTab=szInput;
szInput="\\"+szInput;
}
else
m_sPrevTab="";
}
//try to search in command list
std::vector<char *> matches;
itrCmds=m_mapCommands.begin();
while(itrCmds!=m_mapCommands.end())
{
XConsoleCommand &cmd = itrCmds->second;
if((cmd.m_dwFlags&(VF_CHEAT|VF_READONLY))==0 || m_pSystem->IsDevMode())
{
if(strnicmp(m_sPrevTab.c_str(),itrCmds->first.c_str(),m_sPrevTab.length())==0)
{
matches.push_back((char *const)itrCmds->first.c_str());
}
}
++itrCmds;
}
itrVars=m_mapVariables.begin();
while(itrVars!=m_mapVariables.end())
{
CXConsoleVariable *pVar = itrVars->second;
if((pVar->GetFlags()&(VF_CHEAT|VF_READONLY))==0 || m_pSystem->IsDevMode())
{
//if(itrVars->first.compare(0,m_sPrevTab.length(),m_sPrevTab)==0)
if(strnicmp(m_sPrevTab.c_str(),itrVars->first.c_str(),m_sPrevTab.length())==0)
{
matches.push_back((char *const)itrVars->first.c_str());
}
}
++itrVars;
}
if (showlist && matches.size()>1)
{
ConsoleInputLog( " " );
for(std::vector<char *>::iterator i = matches.begin(); i!=matches.end(); ++i)
{
// List matching variables
const char *sVar = *i;
const char *sValue = "";
ICVar *pVar = GetCVar( sVar );
if (pVar)
{
sValue = pVar->GetString();
char szFalgsString[512]="";
{ // make string containing enabled flags names
static struct { long nFlag; const char * szName; } FlagNames[] =
{
VF_CHEAT,"CHEAT",
VF_REQUIRE_NET_SYNC,"REQUIRE_NET_SYNC",
VF_REQUIRE_LEVEL_RELOAD,"REQUIRE_LEVEL_RELOAD",
VF_REQUIRE_APP_RESTART,"REQUIRE_APP_RESTART",
VF_DUMPTODISK,"DUMPTODISK",
0,0
};
for(int i=0; FlagNames[i].nFlag; i++)
if(pVar->GetFlags()&FlagNames[i].nFlag)
{
if(szFalgsString[0])
strncat(szFalgsString,", ", sizeof(szFalgsString));
strncat(szFalgsString,FlagNames[i].szName, sizeof(szFalgsString));
}
}
ConsoleInputLog( " $3%s = $6%s $5[%s]", sVar,sValue,szFalgsString );
}
else
{
ConsoleInputLog( " $3%s", sVar,sValue );
}
}
}
for(std::vector<char *>::iterator i = matches.begin(); i!=matches.end(); ++i)
{
if(m_nTabCount<=nMatch)
{
szInput="\\";
szInput+=*i;
szInput+=" ";
m_nTabCount=nMatch+1;
return (char *)szInput.c_str();
}
nMatch++;
};
if (m_nTabCount>0)
{
m_nTabCount=0;
szInput=string("\\")+m_sPrevTab;
szInput = ProcessCompletion(szInput.c_str());
}
return (char *)szInput.c_str();
}
bool CXConsole::IsOpened()
{
return m_nScrollPos == m_nScrollMax;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*! Print a string in the console and go to the new line
@param s the string to print
*/
void CXConsole::PrintLine(const char *s)
{
AddLine(s);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*! Append a string in the last console line
@param s the string to print
*/
void CXConsole::PrintLinePlus(const char *s)
{
AddLinePlus(s);
}
void CXConsole::AddLine(string str)
{
string::size_type nPos;
while ((nPos=str.find('\n'))!=string::npos)
{
str.replace(nPos,1,1,' ');
}
while ((nPos=str.find('\r'))!=string::npos)
{
str.replace(nPos,1,1,' ');
}
//m_pSystem->GetIGame()->GetString
m_dqConsoleBuffer.push_back(str);
int nBufferSize=200;
if(con_line_buffer_size)
{
nBufferSize=con_line_buffer_size->GetIVal();
}
while(((int)(m_dqConsoleBuffer.size()))>nBufferSize)
{
m_dqConsoleBuffer.pop_front();
}
// tell everyone who is interested (e.g. dedicated server printout)
{
std::vector<IOutputPrintSink *>::iterator it;
for(it=m_OutputSinks.begin();it!=m_OutputSinks.end();++it)
(*it)->Print(str.c_str());
}
}
void CXConsole::ResetProgressBar(int nProgressBarRange)
{
m_nProgressRange = nProgressBarRange;
m_nProgress = 0;
if (nProgressBarRange < 0)
nProgressBarRange = 0;
if (!m_nProgressRange)
{
if (m_nLoadingBackTexID)
{
if (m_pRenderer)
m_pRenderer->RemoveTexture(m_nLoadingBackTexID);
m_nLoadingBackTexID = -1;
}
}
ICVar *log_Verbosity = GetCVar("log_Verbosity");
if ((log_Verbosity) && (!log_Verbosity->GetIVal()))
{
Clear();
}
}
void CXConsole::TickProgressBar()
{
if (m_nProgressRange != 0 && m_nProgressRange > m_nProgress)
{
m_nProgress++;
m_pSystem->UpdateLoadingScreen();
}
if(m_pSystem->GetIGame())
m_pSystem->GetIGame()->UpdateDuringLoading(); // network update
}
//////////////////////////////////////////////////////////////////////////
void CXConsole::SetLoadingImage(const char *szFilename )
{
ITexPic *pTex = 0;
pTex = m_pSystem->GetIRenderer()->EF_LoadTexture( szFilename, FT_NORESIZE | FT_NOMIPS, 0, eTT_Base);
if (!pTex || (pTex && (pTex->GetFlags() & FT_NOTFOUND)))
{
pTex = m_pSystem->GetIRenderer()->EF_LoadTexture("console/loadscreen_default", FT_NORESIZE | FT_NOMIPS, 0, eTT_Base);
}
if (pTex)
{
m_nLoadingBackTexID = pTex->GetTextureID();
}
else
{
m_nLoadingBackTexID = -1;
}
}
void CXConsole::AddOutputPrintSink( IOutputPrintSink *inpSink )
{
assert(inpSink);
m_OutputSinks.push_back(inpSink);
}
void CXConsole::RemoveOutputPrintSink( IOutputPrintSink *inpSink )
{
assert(inpSink);
int nCount=m_OutputSinks.size();
for(int i=0;i<nCount;i++)
{
if(m_OutputSinks[i]==inpSink)
{
if(nCount<=1) m_OutputSinks.clear();
else
{
m_OutputSinks[i]=m_OutputSinks.back();
m_OutputSinks.pop_back();
}
return;
}
}
assert(0);
}
void CXConsole::AddLinePlus(string str)
{
if(!m_dqConsoleBuffer.size())
return;
string::size_type nPos;
while ((nPos=str.find('\n'))!=string::npos)
str.replace(nPos,1,1,' ');
while ((nPos=str.find('\r'))!=string::npos)
str.replace(nPos,1,1,' ');
string tmpStr = m_dqConsoleBuffer.back();// += str;
m_dqConsoleBuffer.pop_back();
if(tmpStr.size()<256)
m_dqConsoleBuffer.push_back(tmpStr + str);
else
m_dqConsoleBuffer.push_back(tmpStr);
// tell everyone who is interested (e.g. dedicated server printout)
{
std::vector<IOutputPrintSink *>::iterator it;
for(it=m_OutputSinks.begin();it!=m_OutputSinks.end();++it)
(*it)->Print((tmpStr + str).c_str());
}
}
void CXConsole::AddInputChar(const char c)
{
if(m_nCursorPos<(int)(m_sInputBuffer.length()))
m_sInputBuffer.insert(m_nCursorPos,1,c);
else
m_sInputBuffer=m_sInputBuffer+c;
m_nCursorPos++;
}
void CXConsole::ExecuteInputBuffer()
{
string sTemp=m_sInputBuffer;
if(m_sInputBuffer.empty())
return;
m_sInputBuffer="";
AddCommandToHistory(sTemp.c_str());
ExecuteString(sTemp.c_str(),true);
m_nCursorPos=0;
}
void CXConsole::RemoveInputChar(bool bBackSpace)
{
if(m_sInputBuffer.empty())
return;
if(bBackSpace)
{
if(m_nCursorPos>0){
m_sInputBuffer.erase(m_nCursorPos-1,1);
m_nCursorPos--;
}
}
else
{
if(m_nCursorPos<(int)(m_sInputBuffer.length()))
m_sInputBuffer.erase(m_nCursorPos,1);
}
}
void CXConsole::AddCommandToHistory( const char *szCommand )
{
assert(szCommand);
m_nHistoryPos=-1;
if(!m_dqHistory.empty())
{
// add only if the command is != than the last
if(m_dqHistory.front()!=szCommand)
m_dqHistory.push_front(szCommand);
}
else
m_dqHistory.push_front(szCommand);
while(m_dqHistory.size()>MAX_HISTORY_ENTRIES)
m_dqHistory.pop_back();
}
void CXConsole::Copy()
{
#if !defined(_XBOX) && !defined(LINUX)
if (m_sInputBuffer.empty())
return;
if (!OpenClipboard(NULL))
return;
size_t cbLength = m_sInputBuffer.length();
HGLOBAL hGlobal;
LPVOID pGlobal;
hGlobal = GlobalAlloc(GHND, cbLength + 1);
pGlobal = GlobalLock (hGlobal);
strcpy((char *)pGlobal, m_sInputBuffer.c_str());
GlobalUnlock(hGlobal);
EmptyClipboard();
SetClipboardData(CF_TEXT, hGlobal);
CloseClipboard();
return;
#endif
}
void CXConsole::Paste()
{
#if !defined(_XBOX) && !defined(LINUX)
//TRACE("Paste\n");
static char sTemp[256];
HGLOBAL hGlobal;
void* pGlobal;
if (!IsClipboardFormatAvailable(CF_TEXT))
return;
if (!OpenClipboard(NULL))
return;
hGlobal = GetClipboardData(CF_TEXT);
if(!hGlobal)
return;
pGlobal = GlobalLock(hGlobal);
size_t cbLength = min(sizeof(sTemp)-1, strlen((char *)pGlobal));
strncpy(sTemp, (char *)pGlobal, cbLength);
sTemp[cbLength] = '\0';
GlobalUnlock(hGlobal);
CloseClipboard();
m_sInputBuffer.insert(m_nCursorPos,sTemp,strlen(sTemp));
m_nCursorPos+=(int)strlen(sTemp);
#endif
}
inline bool less_stricmp( const char* left,const char* right )
{
return stricmp(left,right) < 0;
}
//////////////////////////////////////////////////////////////////////////
int CXConsole::GetNumVars()
{
return (int)m_mapVariables.size();
}
//////////////////////////////////////////////////////////////////////////
void CXConsole::GetSortedVars( const char **pszArray,size_t numItems )
{
assert( pszArray );
if (numItems == 0)
return;
size_t i = 0;
for (ConsoleVariablesMap::iterator it = m_mapVariables.begin(); it != m_mapVariables.end(); it++)
{
if (i >= numItems)
break;
/*
if (i > 0)
{
// Ignore duplicate strings.
if (stricmp(pszArray[i-1],it->first.c_str()) == 0)
continue;
}
*/
pszArray[i] = it->first.c_str();
i++;
}
std::sort( pszArray,pszArray+numItems,less_stricmp );
}
//////////////////////////////////////////////////////////////////////////
const char* CXConsole::AutoComplete( const char* substr )
{
std::vector<const char*> cmds;
cmds.resize( GetNumVars() );
GetSortedVars( &cmds[0],cmds.size() );
size_t substrLen = strlen(substr);
// If substring is empty return first command.
if (substrLen==0 && cmds.size()>0)
return cmds[0];
for (size_t i = 0; i < cmds.size(); i++)
{
size_t cmdlen = strlen(cmds[i]);
if (cmdlen >= substrLen && memicmp(cmds[i],substr,substrLen) == 0)
{
if (substrLen == cmdlen)
{
i++;
if (i < cmds.size())
return cmds[i];
return cmds[i-1];
}
return cmds[i];
}
}
// Not found.
return "";
}
//////////////////////////////////////////////////////////////////////////
const char* CXConsole::AutoCompletePrev( const char* substr )
{
std::vector<const char*> cmds;
cmds.resize( GetNumVars() );
GetSortedVars( &cmds[0],cmds.size() );
// If substring is empty return last command.
if (strlen(substr)==0 && cmds.size()>0)
return cmds[cmds.size()-1];
for (unsigned int i = 0; i < cmds.size(); i++)
{
if (stricmp(substr,cmds[i])==0)
{
if (i > 0)
return cmds[i-1];
else
return cmds[0];
}
}
return AutoComplete( substr );
}
size_t sizeOf (const string& str)
{
return str.capacity()+1;
}
size_t sizeOf (const char* sz)
{
return sz? strlen(sz)+1:0;
}
size_t sizeOf (const ConsoleBuffer& Buffer)
{
size_t nSize = 0;
ConsoleBuffer::const_iterator it = Buffer.begin(), itEnd = Buffer.end();
for (; it != itEnd; ++it)
{
nSize += sizeof(*it) + sizeOf (*it);
}
return nSize;
}
//! Calculation of the memory used by the whole console system
void CXConsole::GetMemoryUsage (class ICrySizer* pSizer)
{
pSizer->AddObject (this, sizeof(*this)
+ sizeOf (m_dqConsoleBuffer)
+ sizeOf (m_dqHistory)
+ sizeOf (m_sInputBuffer)
+ sizeOf (m_sPrevTab)
);
{
ConsoleCommandsMap::const_iterator it = m_mapCommands.begin(), itEnd = m_mapCommands.end();
for (;it != itEnd; ++it)
pSizer->AddObject (&(*it), sizeof(*it) + sizeOf(it->first) + it->second.sizeofThis());
}
{
ConsoleBindsMap::const_iterator it = m_mapBinds.begin(), itEnd = m_mapBinds.end();
for (; it != itEnd; ++it)
pSizer->AddObject (&(*it), sizeof(*it) + sizeOf (it->first) + sizeOf (it->second));
}
{
ConsoleVariablesMap::const_iterator it = m_mapVariables.begin(), itEnd = m_mapVariables.end();
for (; it != itEnd; ++it)
{
pSizer->AddObject (&*it, sizeof(*it) + sizeOf(it->first));
it->second->GetMemoryUsage (pSizer);
}
}
}
//////////////////////////////////////////////////////////////////////////
void CXConsole::ConsoleInputLog( const char *format,... )
{
va_list args;
va_start(args,format);
GetISystem()->GetILog()->LogV( ILog::eInput,format,args );
va_end(args);
}
//////////////////////////////////////////////////////////////////////////
void CXConsole::ConsoleLog( const char *format,... )
{
va_list args;
va_start(args,format);
GetISystem()->GetILog()->LogV( ILog::eAlways,format,args );
va_end(args);
}
//////////////////////////////////////////////////////////////////////////
void CXConsole::ConsoleWarning( const char *format,... )
{
va_list args;
va_start(args,format);
GetISystem()->GetILog()->LogV( ILog::eWarningAlways,format,args );
va_end(args);
}
//////////////////////////////////////////////////////////////////////////
bool CXConsole::OnBeforeVarChange( ICVar *pVar,const char *sNewValue )
{
if (!m_consoleVarSinks.empty())
{
ConsoleVarSinks::iterator it,next;
for (it = m_consoleVarSinks.begin(); it != m_consoleVarSinks.end(); it = next)
{
next = it; next++;
if (!(*it)->OnBeforeVarChange(pVar,sNewValue))
return false;
}
}
return true;
}
//////////////////////////////////////////////////////////////////////////
void CXConsole::AddConsoleVarSink( IConsoleVarSink *pSink )
{
m_consoleVarSinks.push_back(pSink);
}
//////////////////////////////////////////////////////////////////////////
void CXConsole::RemoveConsoleVarSink( IConsoleVarSink *pSink )
{
m_consoleVarSinks.remove(pSink);
}