You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
574 lines
19 KiB
C++
574 lines
19 KiB
C++
/*
|
|
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
* its licensors.
|
|
*
|
|
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
* distribution (the "License"). All use of this software is governed by the License,
|
|
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
*
|
|
*/
|
|
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
|
|
|
// Description : Console implementation for UNIX systems, based on curses ncurses.
|
|
|
|
|
|
#pragma once
|
|
|
|
|
|
#include <IConsole.h>
|
|
#include <ITextModeConsole.h>
|
|
|
|
#if defined(USE_DEDICATED_SERVER_CONSOLE)
|
|
|
|
class CSyslogStats
|
|
{
|
|
public:
|
|
CSyslogStats();
|
|
~CSyslogStats();
|
|
|
|
void Init();
|
|
void Update(float srvRate, int numPlayers);
|
|
|
|
private:
|
|
int m_syslog_stats;
|
|
int m_syslog_period;
|
|
CTimeValue m_syslogStartTime;
|
|
CTimeValue m_syslogCurrTime;
|
|
static const int SYSLOG_DEFAULT_PERIOD = 3000; // default timeout (sec)
|
|
};
|
|
|
|
#if defined(USE_UNIXCONSOLE)
|
|
|
|
#if defined(WIN32)
|
|
// Avoid naming conflict with wincon.h.
|
|
#undef MOUSE_MOVED
|
|
#endif
|
|
|
|
#include <CryThread.h>
|
|
#include <ncurses.h>
|
|
|
|
// Avoid naming conflicts with pdcurses.
|
|
// Use werase(stdscr) instead of erase().
|
|
#undef erase
|
|
// Use wclear(stdscr) instead of clear().
|
|
#undef clear
|
|
// (MATT) Could not compile CONTAINER_VALUE etc templates for Vector{Map,Set} in ISerialise apparently because of the
|
|
// clear and erase macros. Changed order to undefine them straight after pdcurses. {2009/04/09}
|
|
|
|
#include <deque>
|
|
|
|
|
|
// Define if you wish to enable the player count feature.
|
|
// Note: The player count feature can not be used when building
|
|
// Windows-style DLLs!
|
|
#if defined(LINUX) || defined(MAC)
|
|
#define UC_ENABLE_PLAYER_COUNT 1
|
|
#else
|
|
#undef UC_ENABLE_PLAYER_COUNT
|
|
#endif
|
|
|
|
// Define if you wish to enable magic console commands.
|
|
// These are commands starting with an '@' character, which are intercepted by
|
|
// the CUNIXConsole class and not passed to the system.
|
|
//#undef UC_ENABLE_MAGIC_COMMANDS
|
|
#define UC_ENABLE_MAGIC_COMMANDS 1
|
|
|
|
class CUNIXConsoleInputThread;
|
|
class CUNIXConsoleSignalHandler;
|
|
|
|
|
|
class CUNIXConsole
|
|
: public ISystemUserCallback
|
|
, public IOutputPrintSink
|
|
, public ITextModeConsole
|
|
{
|
|
friend class CUNIXConsoleInputThread;
|
|
friend class CUNIXConsoleSignalHandler;
|
|
|
|
static const int DEFAULT_COLOR = -1;
|
|
|
|
typedef CryMutex ConsoleLock;
|
|
ConsoleLock m_Lock;
|
|
static CryCriticalSectionNonRecursive m_cleanupLock;
|
|
|
|
enum EConDrawOp
|
|
{
|
|
eCDO_PutText,
|
|
};
|
|
struct SConDrawCmd
|
|
{
|
|
EConDrawOp op;
|
|
int x, y;
|
|
char text[256];
|
|
};
|
|
DynArray<SConDrawCmd> m_drawCmds;
|
|
DynArray<SConDrawCmd> m_newCmds;
|
|
bool m_fsMode;
|
|
|
|
CSyslogStats m_syslogStats;
|
|
bool m_bShowConsole; // hide or show console
|
|
|
|
SSystemUpdateStats m_updStats;
|
|
|
|
bool IsLocked() { return m_Lock.IsLocked(); }
|
|
|
|
// The header string.
|
|
//
|
|
// Should be set by the launcher through SetHeader().
|
|
string m_HeaderString;
|
|
|
|
// The line buffer.
|
|
//
|
|
// We'll use the escape sequence "\1" followed by a digit to encode color
|
|
// changes.
|
|
typedef std::deque<string> TLineBuffer;
|
|
TLineBuffer m_LineBuffer;
|
|
|
|
// The command queue.
|
|
//
|
|
// Commands typed on the console are added to this command queue. It is
|
|
// processed by the OnUpdate() callback.
|
|
typedef std::deque<string> TCommandQueue;
|
|
TCommandQueue m_CommandQueue;
|
|
|
|
// The command history.
|
|
//
|
|
// The UNIX console is decoupled from the system console object through a
|
|
// command queue, so we can't use the history buffer from the system
|
|
// console. This is our own command history.
|
|
//
|
|
// The history index indicates the reverse index (counting from the end)
|
|
// into our command history. The special value -1 indicates that we're not
|
|
// currently showing a command from the history.
|
|
typedef std::deque<string> TCommandHistory;
|
|
TCommandHistory m_CommandHistory;
|
|
int m_HistoryIndex;
|
|
|
|
// Interactive prompt.
|
|
//
|
|
// If this is not empty, then this prompt is shown in the command area. The
|
|
// input thread will wait for one if the response characters. The response is
|
|
// stored to m_PromptResponse and m_PromptCond is notified.
|
|
string m_Prompt;
|
|
char m_PromptResponseChars[16]; // Null-terminated.
|
|
char m_PromptResponse;
|
|
CryConditionVariable m_PromptCond;
|
|
|
|
ISystem* m_pSystem;
|
|
IConsole* m_pConsole;
|
|
ITimer* m_pTimer; // Initialized on the first call to OnUpdate().
|
|
|
|
// Flag indicating if OnUpdate() has been called.
|
|
//
|
|
// The initialization of the console variable pointers for 'sv_map' and
|
|
// 'sv_gamerules' is deferred until the first iteration of the update loop,
|
|
// because OnInit() is called too early for that.
|
|
bool m_OnUpdateCalled;
|
|
CTimeValue m_LastUpdateTime;
|
|
|
|
ICVar* m_svMap;
|
|
ICVar* m_svGameRules;
|
|
|
|
// Terminal window layout.
|
|
//
|
|
// The terminal window is split into 4 logical windows. Top to bottom,
|
|
// these windows are:
|
|
// - Header window. May be empty (height 0).
|
|
// - Log window. This is the area in the middle of the terminal showing the
|
|
// log messages.
|
|
// - Status window. This is a window below the log window showing things
|
|
// like current FPS or other status information.
|
|
// - Command window. This is a few lines (typically 1 or 2) at the
|
|
// bottom of the terminal window. The command prompt and command line
|
|
// editor is shown in the command window.
|
|
//
|
|
// The layout is implementated as a single curses window - the standard
|
|
// screen (stdscr).
|
|
|
|
// The width and height of the terminal window.
|
|
unsigned m_Width, m_Height;
|
|
|
|
// The height of the header window.
|
|
// The header window is displayed at the top of the terminal window.
|
|
// Typically 0 (no header) or 1 (single header line).
|
|
unsigned m_HeaderHeight;
|
|
|
|
// The height of the status window.
|
|
// This is typically a single line between the log window and the command
|
|
// window, displayed in inverse video.
|
|
unsigned m_StatusHeight;
|
|
|
|
// The height of the command window.
|
|
// This is typically a single line at the bottom of the screen.
|
|
unsigned m_CmdHeight;
|
|
|
|
// The current text color.
|
|
int m_Color;
|
|
|
|
// The default text color pair (read from curses when the app starts).
|
|
int m_DefaultColorPair;
|
|
|
|
// Flag indicating if color output is enabled.
|
|
bool m_EnableColor;
|
|
|
|
// Flag indicating that the window has been resized.
|
|
// Set by the SIGWINCH signal handler.
|
|
bool m_WindowResized;
|
|
|
|
// Flag indicating that OnShutdown() has been called.
|
|
bool m_OnShutdownCalled;
|
|
|
|
// Flag indicating if the console has been initialized (i.e. Init() has been
|
|
// called).
|
|
bool m_Initialized;
|
|
|
|
// Flag indicating if the implied console initialization (performed by the
|
|
// OnInit() callback) requires a dedicated server.
|
|
// This flag is set through the public SetRequireDedicatedServer() method.
|
|
bool m_RequireDedicatedServer;
|
|
|
|
// The number of (logical) lines scrolled up.
|
|
// 0 indicates that we're at the bottom of the log.
|
|
int m_ScrollUp;
|
|
|
|
// Array of color pair handles.
|
|
// 0: default terminal color
|
|
// 1: default terminal color, reverse video
|
|
// 2: blue
|
|
// 3: green
|
|
// 4: red, bold font
|
|
// 5: cyan
|
|
// 6: yellow on black, bold font
|
|
// 7: magenta
|
|
// 8: red, normal text
|
|
// 9: black on white
|
|
short m_ColorPair[10];
|
|
|
|
// The keyboard input thread.
|
|
CUNIXConsoleInputThread* m_InputThread;
|
|
|
|
// The current input line, cursor position, and horizontal scroll position.
|
|
string m_InputLine;
|
|
string m_SavedInputLine;
|
|
int m_CursorPosition;
|
|
int m_ScrollPosition;
|
|
|
|
// The current progress status string.
|
|
//
|
|
// Set by the OnInitProgress() method and cleared by OnUpdate(). If this is
|
|
// not empty, then this is shown in the status line.
|
|
string m_ProgressStatus;
|
|
|
|
// Set the size of the terminal window.
|
|
//
|
|
// This method is called when the UNIX console is created and whenever the
|
|
// size of the terminal window changes (i.e. SIGWINCH received).
|
|
//
|
|
// We're relying on the ncurses handler for SIGWINCH, so we'll call this
|
|
// method when getch() returns KEY_RESIZE.
|
|
void SetSize(unsigned width, unsigned height);
|
|
|
|
// Check if the terminal window is too small for drawing.
|
|
bool IsTooSmall();
|
|
|
|
// Check if the window size has changed.
|
|
void CheckResize();
|
|
|
|
// Get the height of the log window.
|
|
unsigned GetLogHeight()
|
|
{
|
|
return m_Height - m_HeaderHeight - m_StatusHeight - m_CmdHeight;
|
|
}
|
|
|
|
// Scroll the log window and start a new log line.
|
|
//
|
|
// Move the cursor position to the beginning of the new log line.
|
|
void NewLine();
|
|
|
|
// Continue the last log line.
|
|
//
|
|
// Move the cursor position to the first character following the last
|
|
// character logged and update the current color.
|
|
void ContinueLine();
|
|
|
|
// Clear the current output line.
|
|
//
|
|
// Move the cursor to the beginning of the current output line.
|
|
//
|
|
// Note: This is a bit fuzzy to implement because long wrapped lines are not
|
|
// easy to deal with. Instead I'll simply call NewLine() and maybe
|
|
// implement this later.
|
|
void ClearLine() { NewLine(); }
|
|
|
|
// Set the output color.
|
|
//
|
|
// The color is one of the 10 color codes (0-9) used by the graphical
|
|
// console. If color output is enabled, then the corresponding terminal
|
|
// color is set. If color output is not enabled, then only the text
|
|
// attributes are changed.
|
|
//
|
|
// In addition to setting the color (if enabled), the method will set the
|
|
// following terminal attributes:
|
|
// 0, 1: Normal text (black, white)
|
|
// 4, 6: Bold text (red, yellow, typically indicates an error or warning)
|
|
// other: Underlined text
|
|
void SetColor(int color = DEFAULT_COLOR);
|
|
void SetColorRaw(int color);
|
|
|
|
// Write a single character or a sequence of characters to the console,
|
|
// using the currently specified color. The specified character must be a
|
|
// printable character.
|
|
//
|
|
// Note:
|
|
// - The Put(const char *) method will interpret '\n' as a line separator an
|
|
// call NewLine() when encountered. All other characters must be
|
|
// printable characters.
|
|
// - Both Put() methods will _not_ update the cursor position before writing
|
|
// the character to the screen. It is up to the caller to update the
|
|
// cursor position (either by calling NewLine() or ContinueLine()).
|
|
void Put(int c);
|
|
void Put(const char* s);
|
|
|
|
// Get the length of the line (number of displayed characters), not counting
|
|
// color change escapes.
|
|
static unsigned GetLineLength(const string& line);
|
|
|
|
// Get the last printable character from the specified line. It is an error
|
|
// if the specified line contains no printable characters. If color is not
|
|
// NULL, then the selected color for the last character is stored to *color.
|
|
static char GetLastCharacter(const string& line, int* color);
|
|
|
|
// Get the height of a line of text.
|
|
//
|
|
// The method returns the number of terminal lines to display the specified
|
|
// line (wrapped). If column is not NULL, then *column is set to the column
|
|
// indicating the end of the last wrapped terminal line.
|
|
unsigned GetLineHeight(const string& line, unsigned* column = NULL);
|
|
|
|
// Scroll the log window one line.
|
|
void ScrollLog();
|
|
|
|
// Flush/repaint the screen.
|
|
void Flush();
|
|
|
|
// Called by the input thread when idle.
|
|
void InputIdle();
|
|
|
|
// Lock/unlock the UNIX console.
|
|
void Lock() { m_Lock.Lock(); }
|
|
void Unlock() { m_Lock.Unlock(); }
|
|
|
|
// Fix the cursor position and scroll position after updating the command
|
|
// input line. Returns true if the command window must be repainted.
|
|
bool FixCursorPosition();
|
|
|
|
// Called when the command line has been edited.
|
|
void OnEdit();
|
|
|
|
// Keyboard input.
|
|
void KeyEnter();
|
|
void KeyUp();
|
|
void KeyDown();
|
|
void KeyLeft();
|
|
void KeyRight();
|
|
void KeyHome(bool ctrl);
|
|
void KeyEnd(bool ctrl);
|
|
void KeyBackspace();
|
|
void KeyDelete();
|
|
void KeyDeleteWord();
|
|
void KeyKill();
|
|
void KeyRepaint();
|
|
void KeyTab();
|
|
void KeyPgUp(bool ctrl);
|
|
void KeyPgDown(bool ctrl);
|
|
void KeyF(int id);
|
|
void Key(int c);
|
|
|
|
// Drawing.
|
|
void Repaint();
|
|
void DrawHeader();
|
|
unsigned DrawLogLine(const string&, bool noOutput = false);
|
|
void DrawLog();
|
|
void DrawFullscreen();
|
|
void DrawStatus(int maxLines = -1);
|
|
void DrawCmd(bool cursorOnly = false);
|
|
void DrawCmdPrompt();
|
|
|
|
CUNIXConsole(const CUNIXConsole&);
|
|
void operator = (const CUNIXConsole&);
|
|
|
|
public:
|
|
CUNIXConsole();
|
|
~CUNIXConsole();
|
|
|
|
// Set or clear the RequireDedicatedServer flag.
|
|
// The implied initialization call performed by the
|
|
// ISystemUserCallback::OnInit() depends on this flag.
|
|
// Note: This method _must_ be called before Init() or OnInit() is called.
|
|
void SetRequireDedicatedServer(bool);
|
|
|
|
// Initialize the console for use.
|
|
//
|
|
// This method must be called before any other method of the console is
|
|
// called.
|
|
// It is perfectly valid to instanciate a console and not use it (i.e. skip
|
|
// the Init() call).
|
|
//
|
|
// Note: If the ISystemUserCallback interface is used, then the call to
|
|
// Init() is optional. OnInit() will call Init() if it has not been called
|
|
// already.
|
|
void Init(const char* headerString = NULL);
|
|
|
|
// Check if the console is initialized.
|
|
bool IsInitialized() { return m_Initialized; }
|
|
|
|
// Cleanup function.
|
|
// This method is called by the destructor.
|
|
// If the instance has not been initialized (via Init() and/or OnInit()),
|
|
// then this method has no effect.
|
|
void Cleanup();
|
|
|
|
// Set the header string.
|
|
// Note:
|
|
// - Setting the header string does _not_ trigger a redraw.
|
|
// - This method may be called before Init() has been called.
|
|
void SetHeader(const char* headerString)
|
|
{
|
|
Lock();
|
|
m_HeaderString = headerString;
|
|
Unlock();
|
|
}
|
|
|
|
// Issue a query-response prompt.
|
|
//
|
|
// promptString is the string to be shown as the query prompt.
|
|
// responseChars is a null-terminated string of valid response characters.
|
|
// Add '@' to the response characters if the user may type any character.
|
|
//
|
|
// The method blocks the caller until the user has typed a response. The
|
|
// return value is the response character typed by the user.
|
|
DLL_EXPORT char Prompt(const char* promptString, const char* responseChars);
|
|
|
|
// Check if the calling thread is the input thread.
|
|
//
|
|
// This may be used to make sure that you're not calling Prompt() from the
|
|
// input thread - which will deadlock.
|
|
DLL_EXPORT bool IsInputThread();
|
|
|
|
// Print formatted. Calls Print().
|
|
DLL_EXPORT void PrintF(const char* format, ...) PRINTF_PARAMS(2, 3);
|
|
|
|
// Interface IOutputPrintSink /////////////////////////////////////////////
|
|
DLL_EXPORT virtual void Print(const char* line);
|
|
|
|
// Interface ISystemUserCallback //////////////////////////////////////////
|
|
virtual bool OnError(const char* errorString);
|
|
virtual bool OnSaveDocument() { return false; }
|
|
virtual bool OnBackupDocument() { return false; }
|
|
virtual void OnProcessSwitch() { }
|
|
virtual void OnInitProgress(const char* sProgressMsg);
|
|
virtual void OnInit(ISystem*);
|
|
virtual void OnShutdown();
|
|
virtual void OnUpdate();
|
|
virtual void GetMemoryUsage(ICrySizer* pSizer);
|
|
|
|
// Interface ITextModeConsole /////////////////////////////////////////////
|
|
virtual Vec2_tpl<int> BeginDraw();
|
|
virtual void PutText(int x, int y, const char* msg);
|
|
virtual void EndDraw();
|
|
};
|
|
|
|
#endif // USE_UNIXCONSOLE
|
|
|
|
#if defined(AZ_RESTRICTED_PLATFORM)
|
|
#include AZ_RESTRICTED_FILE(UnixConsole_h)
|
|
#endif
|
|
#if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED)
|
|
#undef AZ_RESTRICTED_SECTION_IMPLEMENTED
|
|
#else
|
|
// simple light-weight console
|
|
class CNULLConsole
|
|
: public IOutputPrintSink
|
|
, public ISystemUserCallback
|
|
, public ITextModeConsole
|
|
{
|
|
public:
|
|
CNULLConsole(bool isDaemonMode);
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
// IOutputPrintSink
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
virtual void Print(const char* inszText);
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
// ISystemUserCallback
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
/** this method is called at the earliest point the ISystem pointer can be used
|
|
the log might not be yet there
|
|
*/
|
|
virtual void OnSystemConnect([[maybe_unused]] ISystem* pSystem) {};
|
|
/** Signals to User that engine error occured.
|
|
@return true to Halt execution or false to ignore this error.
|
|
*/
|
|
virtual bool OnError([[maybe_unused]] const char* szErrorString) { return false; };
|
|
/** If working in Editor environment notify user that engine want to Save current document.
|
|
This happens if critical error have occured and engine gives a user way to save data and not lose it
|
|
due to crash.
|
|
*/
|
|
virtual bool OnSaveDocument() { return false; }
|
|
|
|
/** If working in Editor environment and a critical error occurs notify the user to backup
|
|
the current document to prevent data loss due to crash.
|
|
*/
|
|
virtual bool OnBackupDocument() { return false; }
|
|
|
|
/** Notify user that system wants to switch out of current process.
|
|
(For ex. Called when pressing ESC in game mode to go to Menu).
|
|
*/
|
|
virtual void OnProcessSwitch() {};
|
|
|
|
// Notify user, usually editor about initialization progress in system.
|
|
virtual void OnInitProgress([[maybe_unused]] const char* sProgressMsg) {};
|
|
|
|
// Initialization callback. This is called early in CSystem::Init(), before
|
|
// any of the other callback methods is called.
|
|
virtual void OnInit(ISystem*);
|
|
|
|
// Shutdown callback.
|
|
virtual void OnShutdown() {};
|
|
|
|
// Notify user of an update iteration. Called in the update loop.
|
|
virtual void OnUpdate();
|
|
|
|
// to collect the memory information in the user program/application
|
|
virtual void GetMemoryUsage([[maybe_unused]] ICrySizer* pSizer) {};
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
// ITextModeConsole
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
virtual Vec2_tpl<int> BeginDraw() { return Vec2_tpl<int>(0, 0); };
|
|
virtual void PutText(int x, int y, const char* msg);
|
|
virtual void EndDraw() {};
|
|
|
|
void SetRequireDedicatedServer(bool)
|
|
{
|
|
// Does nothing
|
|
}
|
|
void SetHeader(const char*)
|
|
{
|
|
//Does nothing
|
|
}
|
|
private:
|
|
#if defined(WIN32) || defined(WIN64)
|
|
HANDLE m_hOut;
|
|
#endif
|
|
bool m_isDaemon;
|
|
CSyslogStats m_syslogStats;
|
|
};
|
|
|
|
#endif
|
|
|
|
#endif // defined(USE_DEDICATED_SERVER_CONSOLE)
|