summaryrefslogtreecommitdiff
path: root/dedicated
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /dedicated
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'dedicated')
-rw-r--r--dedicated/console/TextConsoleUnix.cpp419
-rw-r--r--dedicated/console/TextConsoleUnix.h44
-rw-r--r--dedicated/console/TextConsoleWin32.cpp644
-rw-r--r--dedicated/console/TextConsoleWin32.h82
-rw-r--r--dedicated/console/conproc.cpp428
-rw-r--r--dedicated/console/conproc.h30
-rw-r--r--dedicated/console/textconsole.cpp22
-rw-r--r--dedicated/console/textconsole.h38
-rw-r--r--dedicated/dedicated.h78
-rw-r--r--dedicated/dedicated.rc72
-rw-r--r--dedicated/dedicated.vpc149
-rw-r--r--dedicated/filesystem.cpp56
-rw-r--r--dedicated/isys.h45
-rw-r--r--dedicated/resource.h25
-rw-r--r--dedicated/sys_common.cpp300
-rw-r--r--dedicated/sys_ded.cpp530
-rw-r--r--dedicated/sys_linux.cpp298
-rw-r--r--dedicated/sys_windows.cpp411
-rw-r--r--dedicated/vgui/CreateMultiplayerGameServerPage.cpp872
-rw-r--r--dedicated/vgui/CreateMultiplayerGameServerPage.h126
-rw-r--r--dedicated/vgui/MainPanel.cpp274
-rw-r--r--dedicated/vgui/MainPanel.h89
-rw-r--r--dedicated/vgui/vguihelpers.cpp187
-rw-r--r--dedicated/vgui/vguihelpers.h26
-rw-r--r--dedicated/vgui/vguihelpers_linux.cpp39
25 files changed, 5284 insertions, 0 deletions
diff --git a/dedicated/console/TextConsoleUnix.cpp b/dedicated/console/TextConsoleUnix.cpp
new file mode 100644
index 0000000..4f71845
--- /dev/null
+++ b/dedicated/console/TextConsoleUnix.cpp
@@ -0,0 +1,419 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+// CTextConsoleUnix.cpp: Unix implementation of the TextConsole class.
+//
+//////////////////////////////////////////////////////////////////////
+
+#ifndef _WIN32
+
+#include <sys/ioctl.h>
+
+#include "TextConsoleUnix.h"
+#include "tier0/icommandline.h"
+#include "tier1/utllinkedlist.h"
+#include "filesystem.h"
+#include "../thirdparty/libedit-3.1/src/histedit.h"
+#include "tier0/vprof.h"
+
+#define CONSOLE_LOG_FILE "console.log"
+
+static pthread_mutex_t g_lock;
+static pthread_t g_threadid = (pthread_t)-1;
+CUtlLinkedList< CUtlString > g_Commands;
+static volatile int g_ProcessingCommands = false;
+
+#if defined( LINUX )
+
+// Dynamically load the libtinfo stuff. On servers without a tty attached,
+// we get to skip all of these dependencies on servers without ttys.
+#define TINFO_SYM(rc, fn, params, args, ret) \
+ typedef rc (*DYNTINFOFN_##fn) params; \
+ static DYNTINFOFN_##fn g_TINFO_##fn; \
+ extern "C" rc fn params \
+ { \
+ ret g_TINFO_##fn args; \
+ }
+
+TINFO_SYM(char *, tgoto, (char *string, int x, int y), (string, x, y), return);
+TINFO_SYM(int, tputs, (const char *str, int affcnt, int (*putc)(int)), (str, affcnt, putc), return);
+TINFO_SYM(int, tgetflag, (char *id), (id), return);
+TINFO_SYM(int, tgetnum, (char *id), (id), return);
+TINFO_SYM(int, tgetent, (char *bufp, const char *name), (bufp, name), return);
+TINFO_SYM(char *, tgetstr, (char *id, char **area), (id, area), return);
+
+#endif // LINUX
+
+//----------------------------------------------------------------------------------------------------------------------
+// init_tinfo_functions
+//----------------------------------------------------------------------------------------------------------------------
+static bool init_tinfo_functions()
+{
+#if !defined( LINUX )
+ return true;
+#else
+ static void *s_ncurses_handle = NULL;
+
+ if ( !s_ncurses_handle )
+ {
+ // Long time ago, ncurses was two libraries. So if libtinfo fails, try libncurses.
+ static const char *names[] = { "libtinfo.so.5", "libncurses.so.5" };
+
+ for ( int i = 0; !s_ncurses_handle && ( i < ARRAYSIZE( names ) ); i++ )
+ {
+ bool bFailed = true;
+ s_ncurses_handle = dlopen( names[i], RTLD_NOW );
+
+ if ( s_ncurses_handle )
+ {
+ bFailed = false;
+#define LOADTINFOFUNC(_handle, _func, _failed) \
+ do { \
+ g_TINFO_##_func = ( DYNTINFOFN_##_func )dlsym(_handle, #_func); \
+ if ( !g_TINFO_##_func) \
+ _failed = true; \
+ } while (0)
+
+ LOADTINFOFUNC( s_ncurses_handle, tgoto, bFailed );
+ LOADTINFOFUNC( s_ncurses_handle, tputs, bFailed );
+ LOADTINFOFUNC( s_ncurses_handle, tgetflag, bFailed );
+ LOADTINFOFUNC( s_ncurses_handle, tgetnum, bFailed );
+ LOADTINFOFUNC( s_ncurses_handle, tgetent, bFailed );
+ LOADTINFOFUNC( s_ncurses_handle, tgetstr, bFailed );
+#undef LOADTINFOFUNC
+ }
+
+ if ( bFailed )
+ s_ncurses_handle = NULL;
+ }
+
+ if ( !s_ncurses_handle )
+ {
+ fprintf( stderr, "\nWARNING: Failed to load 32-bit libtinfo.so.5 or libncurses.so.5.\n"
+ " Please install (lib32tinfo5 / ncurses-libs.i686 / equivalent) to enable readline.\n\n");
+ }
+ }
+
+ return !!s_ncurses_handle;
+#endif // LINUX
+}
+
+static unsigned char editline_complete( EditLine *el, int ch __attribute__((__unused__)) )
+{
+ static const char *s_cmds[] =
+ {
+ "cvarlist ",
+ "find ",
+ "help ",
+ "maps ",
+ "nextlevel",
+ "quit",
+ "status",
+ "sv_cheats ",
+ "tf_bot_quota ",
+ "toggle ",
+ "sv_dump_edicts",
+#ifdef STAGING_ONLY
+ "tf_bot_use_items ",
+#endif
+ };
+
+ const LineInfo *lf = el_line(el);
+ const char *cmd = lf->buffer;
+ size_t len = lf->cursor - cmd;
+
+ if ( len > 0 )
+ {
+ for (int i = 0; i < ARRAYSIZE(s_cmds); i++)
+ {
+ if ( len > strlen( s_cmds[i] ) )
+ continue;
+
+ if ( !Q_strncmp( cmd, s_cmds[i], len ) )
+ {
+ if ( el_insertstr( el, s_cmds[i] + len ) == -1 )
+ return CC_ERROR;
+ else
+ return CC_REFRESH;
+ }
+ }
+ }
+
+ return CC_ERROR;
+}
+
+static const char *editline_prompt( EditLine *e )
+{
+ // Something like: "\1\033[7m\1Srcds$\1\033[0m\1 "
+ static const char *szPrompt = getenv( "SRCDS_PROMPT" );
+ return szPrompt ? szPrompt : "";
+}
+
+static void editline_cleanup_handler( void *arg )
+{
+ if ( arg )
+ {
+ EditLine *el = (EditLine *)arg;
+ el_end( el );
+ }
+}
+
+static bool add_command( const char *cmd, int cmd_len )
+{
+ if ( cmd )
+ {
+ tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );
+
+ // Trim trailing whitespace.
+ while ( ( cmd_len > 0 ) && isspace( cmd[ cmd_len - 1 ] ) )
+ cmd_len--;
+
+ if ( cmd_len > 0 )
+ {
+ pthread_mutex_lock( &g_lock );
+ if ( g_Commands.Count() < 32 )
+ {
+ CUtlString szCommand( cmd, cmd_len );
+ g_Commands.AddToTail( szCommand );
+
+ g_ProcessingCommands = true;
+ }
+ pthread_mutex_unlock( &g_lock );
+
+ // Wait a bit until we've processed the command we added.
+ for ( int i = 0; i < 6; i++ )
+ {
+ while ( g_ProcessingCommands )
+ usleep( 500 );
+ }
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static void *editline_threadproc( void *arg )
+{
+ HistEvent ev;
+ EditLine *el;
+ History *myhistory;
+ FILE *tty = (FILE *)arg;
+
+ ThreadSetDebugName( "libedit" );
+
+ // Set up state
+ el = el_init( "srcds_linux", stdin, tty, stderr );
+ el_set( el, EL_PROMPT, &editline_prompt );
+ el_set( el, EL_EDITOR, "emacs" ); // or "vi"
+
+ // Hitting Ctrl+R will reset prompt.
+ el_set( el, EL_BIND, "^R", "ed-redisplay", NULL );
+
+ /* Add a user-defined function */
+ el_set( el, EL_ADDFN, "ed-complete", "Complete argument", editline_complete );
+ /* Bind tab to it */
+ el_set( el, EL_BIND, "^I", "ed-complete", NULL );
+
+ // Init history.
+ myhistory = history_init();
+ if (myhistory == 0)
+ {
+ fprintf( stderr, "history could not be initialized\n" );
+ g_threadid = (pthread_t)-1;
+ return (void *)-1;
+ }
+
+ // History size.
+ history( myhistory, &ev, H_SETSIZE, 800 );
+
+ // History callback.
+ el_set( el, EL_HIST, history, myhistory );
+
+ // Source user's defaults.
+ el_source( el, NULL );
+
+ pthread_cleanup_push( editline_cleanup_handler, el );
+
+ while ( g_threadid != (pthread_t)-1 )
+ {
+ // count is the number of characters read.
+ // line is a const char* of our command line with the tailing \n
+ int count;
+ const char *line = el_gets( el, &count );
+
+ if ( add_command( line, count ) )
+ {
+ // Add command to history.
+ history( myhistory, &ev, H_ENTER, line );
+ }
+ }
+
+ pthread_cleanup_pop( 0 );
+
+ // Clean up...
+ history_end( myhistory );
+ el_end( el );
+ return NULL;
+}
+
+static void *fgets_threadproc( void *arg )
+{
+ pthread_cleanup_push( editline_cleanup_handler, NULL );
+
+ while ( g_threadid != (pthread_t)-1 )
+ {
+ char cmd[ 512 ];
+
+ if ( fgets( cmd, sizeof( cmd ), stdin ) )
+ {
+ cmd[ sizeof(cmd) - 1 ] = 0;
+ add_command( cmd, strlen( cmd ) );
+ }
+ }
+
+ pthread_cleanup_pop( 0 );
+ return NULL;
+}
+
+bool CTextConsoleUnix::Init()
+{
+ if( g_threadid != (pthread_t)-1 )
+ {
+ Assert( !"CTextConsoleUnix can only handle a single thread!" );
+ return false;
+ }
+
+ pthread_mutex_init( &g_lock, NULL );
+
+ // This code is for echo-ing key presses to the connected tty
+ // (which is != STDOUT)
+ if ( isatty( STDIN_FILENO ) )
+ {
+ const char *termid_str = ctermid( NULL );
+
+ m_tty = fopen( termid_str, "w+" );
+ if ( !m_tty )
+ {
+ fprintf( stderr, "WARNING: Unable to open tty(%s) for output.\n", termid_str );
+ m_tty = stdout;
+ }
+
+ void *(*terminal_threadproc) (void *) = editline_threadproc;
+ if ( !init_tinfo_functions() )
+ terminal_threadproc = fgets_threadproc;
+
+ if ( pthread_create( &g_threadid, NULL, terminal_threadproc, (void *)m_tty ) != 0 )
+ {
+ g_threadid = (pthread_t)-1;
+ fprintf( stderr, "WARNING: pthread_create failed: %s.\n", strerror(errno) );
+ }
+ }
+ else
+ {
+ m_tty = fopen( "/dev/null", "w+" );
+ if ( !m_tty )
+ m_tty = stdout;
+ }
+
+ m_bConDebug = CommandLine()->FindParm( "-condebug" ) != 0;
+ if ( m_bConDebug && CommandLine()->FindParm( "-conclearlog" ) )
+ g_pFullFileSystem->RemoveFile( CONSOLE_LOG_FILE, "GAME" );
+
+ return CTextConsole::Init();
+}
+
+void CTextConsoleUnix::ShutDown()
+{
+ if ( g_threadid != (pthread_t)-1 )
+ {
+ void *status = NULL;
+ pthread_t tid = g_threadid;
+
+ g_threadid = (pthread_t)-1;
+
+ pthread_cancel( tid );
+ pthread_join( tid, &status );
+ }
+
+ pthread_mutex_destroy( &g_lock );
+}
+
+void CTextConsoleUnix::Print( char * pszMsg )
+{
+ int nChars = strlen( pszMsg );
+
+ if ( nChars > 0 )
+ {
+ if ( m_bConDebug )
+ {
+ FileHandle_t fh = g_pFullFileSystem->Open( CONSOLE_LOG_FILE, "a" );
+ if ( fh != FILESYSTEM_INVALID_HANDLE )
+ {
+ g_pFullFileSystem->Write( pszMsg, nChars, fh );
+ g_pFullFileSystem->Close( fh );
+ }
+ }
+
+ fwrite( pszMsg, 1, nChars, m_tty );
+ }
+}
+
+void CTextConsoleUnix::SetTitle( char *pszTitle )
+{
+}
+
+void CTextConsoleUnix::SetStatusLine( char *pszStatus )
+{
+}
+
+void CTextConsoleUnix::UpdateStatus()
+{
+}
+
+char *CTextConsoleUnix::GetLine( int index, char *buf, int buflen )
+{
+ if ( g_threadid != (pthread_t)-1 )
+ {
+ if ( g_Commands.Count() > 0 )
+ {
+ pthread_mutex_lock( &g_lock );
+
+ const CUtlString& psCommand = g_Commands[ g_Commands.Head() ];
+ V_strncpy( buf, psCommand.Get(), buflen );
+ g_Commands.Remove( g_Commands.Head() );
+
+ pthread_mutex_unlock( &g_lock );
+ return buf;
+ }
+ else if ( index == 0 )
+ {
+ // We're being asked for the first command. Must be a new frame.
+ // Reset the processed commands global.
+ g_ProcessingCommands = false;
+ }
+ }
+
+ return NULL;
+}
+
+int CTextConsoleUnix::GetWidth()
+{
+ int nWidth = 0;
+ struct winsize ws;
+
+ if ( ioctl( STDOUT_FILENO, TIOCGWINSZ, &ws ) == 0 )
+ nWidth = (int)ws.ws_col;
+
+ if ( nWidth <= 1 )
+ nWidth = 80;
+
+ return nWidth;
+}
+
+#endif // !_WIN32
diff --git a/dedicated/console/TextConsoleUnix.h b/dedicated/console/TextConsoleUnix.h
new file mode 100644
index 0000000..b32fe12
--- /dev/null
+++ b/dedicated/console/TextConsoleUnix.h
@@ -0,0 +1,44 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+// TextConsoleUnix.h: Unix interface for the TextConsole class.
+//
+//////////////////////////////////////////////////////////////////////
+
+#if !defined TEXTCONSOLE_UNIX_H
+#define TEXTCONSOLE_UNIX_H
+
+#ifndef _WIN32
+
+#include <stdio.h>
+#include "textconsole.h"
+
+class CTextConsoleUnix : public CTextConsole
+{
+public:
+ virtual ~CTextConsoleUnix() { }
+
+ // CTextConsole
+ bool Init();
+ void ShutDown();
+ void Print( char * pszMsg );
+
+ void SetTitle( char *pszTitle );
+ void SetStatusLine( char *pszStatus );
+ void UpdateStatus();
+
+ char * GetLine( int index, char *buf, int buflen );
+ int GetWidth();
+
+private:
+ bool m_bConDebug;
+ FILE *m_tty;
+};
+
+#endif // _ndef WIN32
+
+#endif // !defined TEXTCONSOLE_UNIX_H
diff --git a/dedicated/console/TextConsoleWin32.cpp b/dedicated/console/TextConsoleWin32.cpp
new file mode 100644
index 0000000..ece1eff
--- /dev/null
+++ b/dedicated/console/TextConsoleWin32.cpp
@@ -0,0 +1,644 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+// CTextConsoleWin32.cpp: Win32 implementation of the TextConsole class.
+//
+//////////////////////////////////////////////////////////////////////
+
+#include "TextConsoleWin32.h"
+#include "tier0/dbg.h"
+#include "utlvector.h"
+
+// Could possibly switch all this code over to using readline. This:
+// http://mingweditline.sourceforge.net/?Description
+// readline() / add_history(char *)
+
+#ifdef _WIN32
+
+BOOL WINAPI ConsoleHandlerRoutine( DWORD CtrlType )
+{
+ NOTE_UNUSED( CtrlType );
+ /* TODO ?
+ if ( CtrlType != CTRL_C_EVENT && CtrlType != CTRL_BREAK_EVENT )
+ m_System->Stop(); // don't quit on break or ctrl+c
+ */
+
+ return TRUE;
+}
+
+// GetConsoleHwnd() helper function from MSDN Knowledge Base Article Q124103
+// needed, because HWND GetConsoleWindow(VOID) is not avaliable under Win95/98/ME
+
+HWND GetConsoleHwnd(void)
+{
+ typedef HWND (WINAPI *PFNGETCONSOLEWINDOW)( VOID );
+ static PFNGETCONSOLEWINDOW s_pfnGetConsoleWindow = (PFNGETCONSOLEWINDOW) GetProcAddress( GetModuleHandle("kernel32"), "GetConsoleWindow" );
+ if ( s_pfnGetConsoleWindow )
+ return s_pfnGetConsoleWindow();
+
+ HWND hwndFound; // This is what is returned to the caller.
+ char pszNewWindowTitle[1024]; // Contains fabricated WindowTitle
+ char pszOldWindowTitle[1024]; // Contains original WindowTitle
+
+ // Fetch current window title.
+ GetConsoleTitle( pszOldWindowTitle, 1024 );
+
+ // Format a "unique" NewWindowTitle.
+ wsprintf( pszNewWindowTitle,"%d/%d", GetTickCount(), GetCurrentProcessId() );
+
+ // Change current window title.
+ SetConsoleTitle(pszNewWindowTitle);
+
+ // Ensure window title has been updated.
+ Sleep(40);
+
+ // Look for NewWindowTitle.
+ hwndFound = FindWindow( NULL, pszNewWindowTitle );
+
+ // Restore original window title.
+
+ SetConsoleTitle( pszOldWindowTitle );
+
+ return hwndFound;
+}
+
+CTextConsoleWin32::CTextConsoleWin32()
+{
+ hinput = NULL;
+ houtput = NULL;
+ Attrib = 0;
+ statusline[0] = '\0';
+}
+
+bool CTextConsoleWin32::Init()
+{
+ (void) AllocConsole();
+ SetTitle( "SOURCE DEDICATED SERVER" );
+
+ hinput = GetStdHandle ( STD_INPUT_HANDLE );
+ houtput = GetStdHandle ( STD_OUTPUT_HANDLE );
+
+ if ( !SetConsoleCtrlHandler( &ConsoleHandlerRoutine, TRUE) )
+ {
+ Print( "WARNING! TextConsole::Init: Could not attach console hook.\n" );
+ }
+
+ Attrib = FOREGROUND_GREEN | FOREGROUND_INTENSITY | BACKGROUND_INTENSITY ;
+
+ SetWindowPos( GetConsoleHwnd(), HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW );
+
+ memset( m_szConsoleText, 0, sizeof( m_szConsoleText ) );
+ m_nConsoleTextLen = 0;
+ m_nCursorPosition = 0;
+
+ memset( m_szSavedConsoleText, 0, sizeof( m_szSavedConsoleText ) );
+ m_nSavedConsoleTextLen = 0;
+
+ memset( m_aszLineBuffer, 0, sizeof( m_aszLineBuffer ) );
+ m_nTotalLines = 0;
+ m_nInputLine = 0;
+ m_nBrowseLine = 0;
+
+ // these are log messages, not related to console
+ Msg( "\n" );
+ Msg( "Console initialized.\n" );
+
+ return CTextConsole::Init();
+}
+
+void CTextConsoleWin32::ShutDown( void )
+{
+ FreeConsole();
+}
+
+void CTextConsoleWin32::SetVisible( bool visible )
+{
+ ShowWindow ( GetConsoleHwnd(), visible ? SW_SHOW : SW_HIDE );
+ m_ConsoleVisible = visible;
+}
+
+char * CTextConsoleWin32::GetLine( int index, char *buf, int buflen )
+{
+ while ( 1 )
+ {
+ INPUT_RECORD recs[ 1024 ];
+ unsigned long numread;
+ unsigned long numevents;
+
+ if ( !GetNumberOfConsoleInputEvents( hinput, &numevents ) )
+ {
+ Error("CTextConsoleWin32::GetLine: !GetNumberOfConsoleInputEvents");
+ return NULL;
+ }
+
+ if ( numevents <= 0 )
+ break;
+
+ if ( !ReadConsoleInput( hinput, recs, ARRAYSIZE( recs ), &numread ) )
+ {
+ Error("CTextConsoleWin32::GetLine: !ReadConsoleInput");
+ return NULL;
+ }
+
+ if ( numread == 0 )
+ return NULL;
+
+ for ( int i=0; i < (int)numread; i++ )
+ {
+ INPUT_RECORD *pRec = &recs[i];
+ if ( pRec->EventType != KEY_EVENT )
+ continue;
+
+ if ( pRec->Event.KeyEvent.bKeyDown )
+ {
+ // check for cursor keys
+ if ( pRec->Event.KeyEvent.wVirtualKeyCode == VK_UP )
+ {
+ ReceiveUpArrow();
+ }
+ else if ( pRec->Event.KeyEvent.wVirtualKeyCode == VK_DOWN )
+ {
+ ReceiveDownArrow();
+ }
+ else if ( pRec->Event.KeyEvent.wVirtualKeyCode == VK_LEFT )
+ {
+ ReceiveLeftArrow();
+ }
+ else if ( pRec->Event.KeyEvent.wVirtualKeyCode == VK_RIGHT )
+ {
+ ReceiveRightArrow();
+ }
+ else
+ {
+ char ch;
+ int nLen;
+
+ ch = pRec->Event.KeyEvent.uChar.AsciiChar;
+ switch ( ch )
+ {
+ case '\r': // Enter
+ nLen = ReceiveNewline();
+ if ( nLen )
+ {
+ strncpy( buf, m_szConsoleText, buflen );
+ buf[ buflen - 1 ] = 0;
+ return buf;
+ }
+ break;
+
+ case '\b': // Backspace
+ ReceiveBackspace();
+ break;
+
+ case '\t': // TAB
+ ReceiveTab();
+ break;
+
+ default:
+ if ( ( ch >= ' ') && ( ch <= '~' ) ) // dont' accept nonprintable chars
+ {
+ ReceiveStandardChar( ch );
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ return NULL;
+}
+
+void CTextConsoleWin32::Print( char * pszMsg )
+{
+ if ( m_nConsoleTextLen )
+ {
+ int nLen;
+
+ nLen = m_nConsoleTextLen;
+
+ while ( nLen-- )
+ {
+ PrintRaw( "\b \b" );
+ }
+ }
+
+ PrintRaw( pszMsg );
+
+ if ( m_nConsoleTextLen )
+ {
+ PrintRaw( m_szConsoleText, m_nConsoleTextLen );
+ }
+
+ UpdateStatus();
+}
+
+void CTextConsoleWin32::PrintRaw( const char * pszMsg, int nChars )
+{
+ unsigned long dummy;
+
+ if ( houtput == NULL )
+ {
+ houtput = GetStdHandle ( STD_OUTPUT_HANDLE );
+ if ( houtput == NULL )
+ return;
+ }
+
+ if ( nChars <= 0 )
+ {
+ nChars = strlen( pszMsg );
+ if ( nChars <= 0 )
+ return;
+ }
+
+ // filter out ASCII BEL characters because windows actually plays a
+ // bell sound, which can be used to lag the server in a DOS attack.
+ char * pTempBuf = NULL;
+ for ( int i = 0; i < nChars; ++i )
+ {
+ if ( pszMsg[i] == 0x07 /*BEL*/ )
+ {
+ if ( !pTempBuf )
+ {
+ pTempBuf = ( char * ) malloc( nChars );
+ memcpy( pTempBuf, pszMsg, nChars );
+ }
+ pTempBuf[i] = '.';
+ }
+ }
+
+ WriteFile( houtput, pTempBuf ? pTempBuf : pszMsg, nChars, &dummy, NULL );
+
+ free( pTempBuf ); // usually NULL
+}
+
+int CTextConsoleWin32::GetWidth( void )
+{
+ CONSOLE_SCREEN_BUFFER_INFO csbi;
+ int nWidth;
+
+ nWidth = 0;
+
+ if ( GetConsoleScreenBufferInfo( houtput, &csbi ) )
+ {
+ nWidth = csbi.dwSize.X;
+ }
+
+ if ( nWidth <= 1 )
+ nWidth = 80;
+
+ return nWidth;
+}
+
+void CTextConsoleWin32::SetStatusLine( char * pszStatus )
+{
+ strncpy( statusline, pszStatus, 80 );
+ statusline[ 79 ] = '\0';
+ UpdateStatus();
+}
+
+void CTextConsoleWin32::UpdateStatus( void )
+{
+ COORD coord;
+ DWORD dwWritten = 0;
+ WORD wAttrib[ 80 ];
+
+ for ( int i = 0; i < 80; i++ )
+ {
+ wAttrib[i] = Attrib; //FOREGROUND_GREEN | FOREGROUND_INTENSITY | BACKGROUND_INTENSITY ;
+ }
+
+ coord.X = coord.Y = 0;
+
+ WriteConsoleOutputAttribute( houtput, wAttrib, 80, coord, &dwWritten );
+ WriteConsoleOutputCharacter( houtput, statusline, 80, coord, &dwWritten );
+}
+
+
+void CTextConsoleWin32::SetTitle( char * pszTitle )
+{
+ SetConsoleTitle( pszTitle );
+}
+
+void CTextConsoleWin32::SetColor(WORD attrib)
+{
+ Attrib = attrib;
+}
+
+int CTextConsoleWin32::ReceiveNewline( void )
+{
+ int nLen = 0;
+
+ PrintRaw( "\n" );
+
+ if ( m_nConsoleTextLen )
+ {
+ nLen = m_nConsoleTextLen;
+
+ m_szConsoleText[ m_nConsoleTextLen ] = 0;
+ m_nConsoleTextLen = 0;
+ m_nCursorPosition = 0;
+
+ // cache line in buffer, but only if it's not a duplicate of the previous line
+ if ( ( m_nInputLine == 0 ) || ( strcmp( m_aszLineBuffer[ m_nInputLine - 1 ], m_szConsoleText ) ) )
+ {
+ strncpy( m_aszLineBuffer[ m_nInputLine ], m_szConsoleText, MAX_CONSOLE_TEXTLEN );
+
+ m_nInputLine++;
+
+ if ( m_nInputLine > m_nTotalLines )
+ m_nTotalLines = m_nInputLine;
+
+ if ( m_nInputLine >= MAX_BUFFER_LINES )
+ m_nInputLine = 0;
+
+ }
+
+ m_nBrowseLine = m_nInputLine;
+ }
+
+ return nLen;
+}
+
+
+void CTextConsoleWin32::ReceiveBackspace( void )
+{
+ int nCount;
+
+ if ( m_nCursorPosition == 0 )
+ {
+ return;
+ }
+
+ m_nConsoleTextLen--;
+ m_nCursorPosition--;
+
+ PrintRaw( "\b" );
+
+ for ( nCount = m_nCursorPosition; nCount < m_nConsoleTextLen; nCount++ )
+ {
+ m_szConsoleText[ nCount ] = m_szConsoleText[ nCount + 1 ];
+ PrintRaw( m_szConsoleText + nCount, 1 );
+ }
+
+ PrintRaw( " " );
+
+ nCount = m_nConsoleTextLen;
+ while ( nCount >= m_nCursorPosition )
+ {
+ PrintRaw( "\b" );
+ nCount--;
+ }
+
+ m_nBrowseLine = m_nInputLine;
+}
+
+
+void CTextConsoleWin32::ReceiveTab( void )
+{
+ CUtlVector<char *> matches;
+
+ m_szConsoleText[ m_nConsoleTextLen ] = 0;
+
+ if ( matches.Count() == 0 )
+ {
+ return;
+ }
+
+ if ( matches.Count() == 1 )
+ {
+ char * pszCmdName;
+ char * pszRest;
+
+ pszCmdName = matches[0];
+ pszRest = pszCmdName + strlen( m_szConsoleText );
+
+ if ( pszRest )
+ {
+ PrintRaw( pszRest );
+ strcat( m_szConsoleText, pszRest );
+ m_nConsoleTextLen += strlen( pszRest );
+
+ PrintRaw( " " );
+ strcat( m_szConsoleText, " " );
+ m_nConsoleTextLen++;
+ }
+ }
+ else
+ {
+ int nLongestCmd;
+ int nTotalColumns;
+ int nCurrentColumn;
+ char * pszCurrentCmd;
+ int i = 0;
+
+ nLongestCmd = 0;
+
+ pszCurrentCmd = matches[0];
+ while ( pszCurrentCmd )
+ {
+ if ( (int)strlen( pszCurrentCmd) > nLongestCmd )
+ {
+ nLongestCmd = strlen( pszCurrentCmd);
+ }
+
+ i++;
+ pszCurrentCmd = (char *)matches[i];
+ }
+
+ nTotalColumns = ( GetWidth() - 1 ) / ( nLongestCmd + 1 );
+ nCurrentColumn = 0;
+
+ PrintRaw( "\n" );
+
+ // Would be nice if these were sorted, but not that big a deal
+ pszCurrentCmd = matches[0];
+ i = 0;
+ while ( pszCurrentCmd )
+ {
+ char szFormatCmd[ 256 ];
+
+ nCurrentColumn++;
+
+ if ( nCurrentColumn > nTotalColumns )
+ {
+ PrintRaw( "\n" );
+ nCurrentColumn = 1;
+ }
+
+ Q_snprintf( szFormatCmd, sizeof(szFormatCmd), "%-*s ", nLongestCmd, pszCurrentCmd );
+ PrintRaw( szFormatCmd );
+
+ i++;
+ pszCurrentCmd = matches[i];
+ }
+
+ PrintRaw( "\n" );
+ PrintRaw( m_szConsoleText );
+ // TODO: Tack on 'common' chars in all the matches, i.e. if I typed 'con' and all the
+ // matches begin with 'connect_' then print the matches but also complete the
+ // command up to that point at least.
+ }
+
+ m_nCursorPosition = m_nConsoleTextLen;
+ m_nBrowseLine = m_nInputLine;
+}
+
+
+
+void CTextConsoleWin32::ReceiveStandardChar( const char ch )
+{
+ int nCount;
+
+ // If the line buffer is maxed out, ignore this char
+ if ( m_nConsoleTextLen >= ( sizeof( m_szConsoleText ) - 2 ) )
+ {
+ return;
+ }
+
+ nCount = m_nConsoleTextLen;
+ while ( nCount > m_nCursorPosition )
+ {
+ m_szConsoleText[ nCount ] = m_szConsoleText[ nCount - 1 ];
+ nCount--;
+ }
+
+ m_szConsoleText[ m_nCursorPosition ] = ch;
+
+ PrintRaw( m_szConsoleText + m_nCursorPosition, m_nConsoleTextLen - m_nCursorPosition + 1 );
+
+ m_nConsoleTextLen++;
+ m_nCursorPosition++;
+
+ nCount = m_nConsoleTextLen;
+ while ( nCount > m_nCursorPosition )
+ {
+ PrintRaw( "\b" );
+ nCount--;
+ }
+
+ m_nBrowseLine = m_nInputLine;
+}
+
+
+void CTextConsoleWin32::ReceiveUpArrow( void )
+{
+ int nLastCommandInHistory;
+
+ nLastCommandInHistory = m_nInputLine + 1;
+ if ( nLastCommandInHistory > m_nTotalLines )
+ {
+ nLastCommandInHistory = 0;
+ }
+
+ if ( m_nBrowseLine == nLastCommandInHistory )
+ {
+ return;
+ }
+
+ if ( m_nBrowseLine == m_nInputLine )
+ {
+ if ( m_nConsoleTextLen > 0 )
+ {
+ // Save off current text
+ strncpy( m_szSavedConsoleText, m_szConsoleText, m_nConsoleTextLen );
+ // No terminator, it's a raw buffer we always know the length of
+ }
+
+ m_nSavedConsoleTextLen = m_nConsoleTextLen;
+ }
+
+ m_nBrowseLine--;
+ if ( m_nBrowseLine < 0 )
+ {
+ m_nBrowseLine = m_nTotalLines - 1;
+ }
+
+ while ( m_nConsoleTextLen-- ) // delete old line
+ {
+ PrintRaw( "\b \b" );
+ }
+
+ // copy buffered line
+ PrintRaw( m_aszLineBuffer[ m_nBrowseLine ] );
+
+ strncpy( m_szConsoleText, m_aszLineBuffer[ m_nBrowseLine ], MAX_CONSOLE_TEXTLEN );
+ m_nConsoleTextLen = strlen( m_aszLineBuffer[ m_nBrowseLine ] );
+
+ m_nCursorPosition = m_nConsoleTextLen;
+}
+
+
+void CTextConsoleWin32::ReceiveDownArrow( void )
+{
+ if ( m_nBrowseLine == m_nInputLine )
+ {
+ return;
+ }
+
+ m_nBrowseLine++;
+ if ( m_nBrowseLine > m_nTotalLines )
+ {
+ m_nBrowseLine = 0;
+ }
+
+ while ( m_nConsoleTextLen-- ) // delete old line
+ {
+ PrintRaw( "\b \b" );
+ }
+
+ if ( m_nBrowseLine == m_nInputLine )
+ {
+ if ( m_nSavedConsoleTextLen > 0 )
+ {
+ // Restore current text
+ strncpy( m_szConsoleText, m_szSavedConsoleText, m_nSavedConsoleTextLen );
+ // No terminator, it's a raw buffer we always know the length of
+
+ PrintRaw( m_szConsoleText, m_nSavedConsoleTextLen );
+ }
+
+ m_nConsoleTextLen = m_nSavedConsoleTextLen;
+ }
+ else
+ {
+ // copy buffered line
+ PrintRaw( m_aszLineBuffer[ m_nBrowseLine ] );
+
+ strncpy( m_szConsoleText, m_aszLineBuffer[ m_nBrowseLine ], MAX_CONSOLE_TEXTLEN );
+
+ m_nConsoleTextLen = strlen( m_aszLineBuffer[ m_nBrowseLine ] );
+ }
+
+ m_nCursorPosition = m_nConsoleTextLen;
+}
+
+
+void CTextConsoleWin32::ReceiveLeftArrow( void )
+{
+ if ( m_nCursorPosition == 0 )
+ {
+ return;
+ }
+
+ PrintRaw( "\b" );
+ m_nCursorPosition--;
+}
+
+
+void CTextConsoleWin32::ReceiveRightArrow( void )
+{
+ if ( m_nCursorPosition == m_nConsoleTextLen )
+ {
+ return;
+ }
+
+ PrintRaw( m_szConsoleText + m_nCursorPosition, 1 );
+ m_nCursorPosition++;
+}
+
+#endif // _WIN32
diff --git a/dedicated/console/TextConsoleWin32.h b/dedicated/console/TextConsoleWin32.h
new file mode 100644
index 0000000..4c762ec
--- /dev/null
+++ b/dedicated/console/TextConsoleWin32.h
@@ -0,0 +1,82 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+// TextConsoleWin32.h: Win32 interface for the TextConsole class.
+//
+//////////////////////////////////////////////////////////////////////
+
+#if !defined TEXTCONSOLE_WIN32_H
+#define TEXTCONSOLE_WIN32_H
+#pragma once
+
+#ifdef _WIN32
+
+#include <windows.h>
+#include "TextConsole.h"
+
+#define MAX_CONSOLE_TEXTLEN 256
+#define MAX_BUFFER_LINES 30
+
+class CTextConsoleWin32 : public CTextConsole
+{
+public:
+ CTextConsoleWin32();
+ virtual ~CTextConsoleWin32() { };
+
+ // CTextConsole
+ bool Init();
+ void ShutDown( void );
+ void Print( char *pszMsg );
+
+ void SetTitle( char * pszTitle );
+ void SetStatusLine( char * pszStatus );
+ void UpdateStatus( void );
+
+ char * GetLine( int index, char *buf, int buflen );
+ int GetWidth( void );
+
+ void SetVisible( bool visible );
+
+protected:
+ // CTextConsoleWin32
+ void SetColor( WORD );
+ void PrintRaw( const char * pszMsg, int nChars = -1 );
+
+private:
+ char m_szConsoleText[ MAX_CONSOLE_TEXTLEN ]; // console text buffer
+ int m_nConsoleTextLen; // console textbuffer length
+ int m_nCursorPosition; // position in the current input line
+
+ // Saved input data when scrolling back through command history
+ char m_szSavedConsoleText[ MAX_CONSOLE_TEXTLEN ]; // console text buffer
+ int m_nSavedConsoleTextLen; // console textbuffer length
+
+ char m_aszLineBuffer[ MAX_BUFFER_LINES ][ MAX_CONSOLE_TEXTLEN ]; // command buffer last MAX_BUFFER_LINES commands
+ int m_nInputLine; // Current line being entered
+ int m_nBrowseLine; // current buffer line for up/down arrow
+ int m_nTotalLines; // # of nonempty lines in the buffer
+
+ int ReceiveNewline( void );
+ void ReceiveBackspace( void );
+ void ReceiveTab( void );
+ void ReceiveStandardChar( const char ch );
+ void ReceiveUpArrow( void );
+ void ReceiveDownArrow( void );
+ void ReceiveLeftArrow( void );
+ void ReceiveRightArrow( void );
+
+private:
+ HANDLE hinput; // standard input handle
+ HANDLE houtput; // standard output handle
+ WORD Attrib; // attrib colours for status bar
+
+ char statusline[81]; // first line in console is status line
+};
+
+#endif // _WIN32
+
+#endif // !defined TEXTCONSOLE_WIN32_H
diff --git a/dedicated/console/conproc.cpp b/dedicated/console/conproc.cpp
new file mode 100644
index 0000000..2156450
--- /dev/null
+++ b/dedicated/console/conproc.cpp
@@ -0,0 +1,428 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+#ifdef _WIN32
+// conproc.c -- support for qhost
+#include <stdio.h>
+#include <process.h>
+#include <windows.h>
+#include "conproc.h"
+#include "isys.h"
+#include "tier0/icommandline.h"
+#include "tier1/strtools.h"
+
+static HANDLE heventDone;
+static HANDLE hfileBuffer;
+static HANDLE heventChildSend;
+static HANDLE heventParentSend;
+static HANDLE hStdout;
+static HANDLE hStdin;
+
+/*
+==============
+SetConsoleCXCY
+
+==============
+*/
+BOOL SetConsoleCXCY(HANDLE hStdout, int cx, int cy)
+{
+ CONSOLE_SCREEN_BUFFER_INFO info;
+ COORD coordMax;
+
+ coordMax = GetLargestConsoleWindowSize(hStdout);
+
+ if (cy > coordMax.Y)
+ cy = coordMax.Y;
+
+ if (cx > coordMax.X)
+ cx = coordMax.X;
+
+ if (!GetConsoleScreenBufferInfo(hStdout, &info))
+ return FALSE;
+
+// height
+ info.srWindow.Left = 0;
+ info.srWindow.Right = info.dwSize.X - 1;
+ info.srWindow.Top = 0;
+ info.srWindow.Bottom = cy - 1;
+
+ if (cy < info.dwSize.Y)
+ {
+ if (!SetConsoleWindowInfo(hStdout, TRUE, &info.srWindow))
+ return FALSE;
+
+ info.dwSize.Y = cy;
+
+ if (!SetConsoleScreenBufferSize(hStdout, info.dwSize))
+ return FALSE;
+ }
+ else if (cy > info.dwSize.Y)
+ {
+ info.dwSize.Y = cy;
+
+ if (!SetConsoleScreenBufferSize(hStdout, info.dwSize))
+ return FALSE;
+
+ if (!SetConsoleWindowInfo(hStdout, TRUE, &info.srWindow))
+ return FALSE;
+ }
+
+ if (!GetConsoleScreenBufferInfo(hStdout, &info))
+ return FALSE;
+
+// width
+ info.srWindow.Left = 0;
+ info.srWindow.Right = cx - 1;
+ info.srWindow.Top = 0;
+ info.srWindow.Bottom = info.dwSize.Y - 1;
+
+ if (cx < info.dwSize.X)
+ {
+ if (!SetConsoleWindowInfo(hStdout, TRUE, &info.srWindow))
+ return FALSE;
+
+ info.dwSize.X = cx;
+
+ if (!SetConsoleScreenBufferSize(hStdout, info.dwSize))
+ return FALSE;
+ }
+ else if (cx > info.dwSize.X)
+ {
+ info.dwSize.X = cx;
+
+ if (!SetConsoleScreenBufferSize(hStdout, info.dwSize))
+ return FALSE;
+
+ if (!SetConsoleWindowInfo(hStdout, TRUE, &info.srWindow))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/*
+==============
+GetMappedBuffer
+
+==============
+*/
+LPVOID GetMappedBuffer (HANDLE hfileBuffer)
+{
+ LPVOID pBuffer;
+
+ pBuffer = MapViewOfFile (hfileBuffer,
+ FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0);
+
+ return pBuffer;
+}
+
+/*
+==============
+ReleaseMappedBuffer
+
+==============
+*/
+void ReleaseMappedBuffer (LPVOID pBuffer)
+{
+ UnmapViewOfFile (pBuffer);
+}
+
+/*
+==============
+GetScreenBufferLines
+
+==============
+*/
+BOOL GetScreenBufferLines (int *piLines)
+{
+ CONSOLE_SCREEN_BUFFER_INFO info;
+ BOOL bRet;
+
+ bRet = GetConsoleScreenBufferInfo (hStdout, &info);
+
+ if (bRet)
+ *piLines = info.dwSize.Y;
+
+ return bRet;
+}
+
+/*
+==============
+SetScreenBufferLines
+
+==============
+*/
+BOOL SetScreenBufferLines (int iLines)
+{
+ return SetConsoleCXCY (hStdout, 80, iLines);
+}
+
+/*
+==============
+ReadText
+
+==============
+*/
+BOOL ReadText (LPTSTR pszText, int iBeginLine, int iEndLine)
+{
+ COORD coord;
+ DWORD dwRead;
+ BOOL bRet;
+
+ coord.X = 0;
+ coord.Y = iBeginLine;
+
+ bRet = ReadConsoleOutputCharacter(
+ hStdout,
+ pszText,
+ 80 * (iEndLine - iBeginLine + 1),
+ coord,
+ &dwRead);
+
+ // Make sure it's null terminated.
+ if (bRet)
+ pszText[dwRead] = '\0';
+
+ return bRet;
+}
+
+/*
+==============
+CharToCode
+
+==============
+*/
+int CharToCode (char c)
+{
+ char upper;
+
+ upper = toupper(c);
+
+ switch (c)
+ {
+ case 13:
+ return 28;
+
+ default:
+ break;
+ }
+
+ if (V_isalpha(c))
+ return (30 + upper - 65);
+
+ if (V_isdigit(c))
+ return (1 + upper - 47);
+
+ return c;
+}
+
+/*
+==============
+WriteText
+
+==============
+*/
+BOOL WriteText (LPCTSTR szText)
+{
+ DWORD dwWritten;
+ INPUT_RECORD rec;
+ char upper, *sz;
+
+ sz = (LPTSTR) szText;
+
+ while (*sz)
+ {
+ // 13 is the code for a carriage return (\n) instead of 10.
+ if (*sz == 10)
+ *sz = 13;
+
+ upper = toupper(*sz);
+
+ rec.EventType = KEY_EVENT;
+ rec.Event.KeyEvent.bKeyDown = TRUE;
+ rec.Event.KeyEvent.wRepeatCount = 1;
+ rec.Event.KeyEvent.wVirtualKeyCode = upper;
+ rec.Event.KeyEvent.wVirtualScanCode = CharToCode (*sz);
+ rec.Event.KeyEvent.uChar.AsciiChar = *sz;
+ rec.Event.KeyEvent.uChar.UnicodeChar = *sz;
+ rec.Event.KeyEvent.dwControlKeyState = V_isupper(*sz) ? 0x80 : 0x0;
+
+ WriteConsoleInput(
+ hStdin,
+ &rec,
+ 1,
+ &dwWritten);
+
+ rec.Event.KeyEvent.bKeyDown = FALSE;
+
+ WriteConsoleInput(
+ hStdin,
+ &rec,
+ 1,
+ &dwWritten);
+
+ sz++;
+ }
+
+ return TRUE;
+}
+
+/*
+==============
+RequestProc
+
+==============
+*/
+unsigned _stdcall RequestProc (void *arg)
+{
+ int *pBuffer;
+ DWORD dwRet;
+ HANDLE heventWait[2];
+ int iBeginLine, iEndLine;
+
+ heventWait[0] = heventParentSend;
+ heventWait[1] = heventDone;
+
+ while (1)
+ {
+ dwRet = WaitForMultipleObjects (2, heventWait, FALSE, INFINITE);
+
+ // heventDone fired, so we're exiting.
+ if (dwRet == WAIT_OBJECT_0 + 1)
+ break;
+
+ pBuffer = (int *) GetMappedBuffer (hfileBuffer);
+
+ // hfileBuffer is invalid. Just leave.
+ if (!pBuffer)
+ {
+ sys->Printf ("Request Proc: Invalid -HFILE handle\n");
+ break;
+ }
+
+ switch (pBuffer[0])
+ {
+ case CCOM_WRITE_TEXT:
+ // Param1 : Text
+ pBuffer[0] = WriteText ((LPCTSTR) (pBuffer + 1));
+ break;
+
+ case CCOM_GET_TEXT:
+ // Param1 : Begin line
+ // Param2 : End line
+ iBeginLine = pBuffer[1];
+ iEndLine = pBuffer[2];
+ pBuffer[0] = ReadText ((LPTSTR) (pBuffer + 1), iBeginLine,
+ iEndLine);
+ break;
+
+ case CCOM_GET_SCR_LINES:
+ // No params
+ pBuffer[0] = GetScreenBufferLines (&pBuffer[1]);
+ break;
+
+ case CCOM_SET_SCR_LINES:
+ // Param1 : Number of lines
+ pBuffer[0] = SetScreenBufferLines (pBuffer[1]);
+ break;
+ }
+
+ ReleaseMappedBuffer (pBuffer);
+ SetEvent (heventChildSend);
+ }
+
+ _endthreadex (0);
+ return 0;
+}
+
+/*
+==============
+DeinitConProc
+
+==============
+*/
+void DeinitConProc (void)
+{
+ if ( heventDone )
+ {
+ SetEvent ( heventDone );
+ }
+}
+
+/*
+==============
+InitConProc
+
+==============
+*/
+void InitConProc ( void )
+{
+ unsigned threadAddr;
+ HANDLE hFile = (HANDLE)0;
+ HANDLE heventParent = (HANDLE)0;
+ HANDLE heventChild = (HANDLE)0;
+ int WantHeight = 50;
+ const char *p;
+
+ // give external front ends a chance to hook into the console
+ if ( CommandLine()->CheckParm ( "-HFILE", &p ) && p )
+ {
+ hFile = (HANDLE)atoi ( p );
+ }
+
+ if ( CommandLine()->CheckParm ( "-HPARENT", &p ) && p )
+ {
+ heventParent = (HANDLE)atoi ( p );
+ }
+
+ if ( CommandLine()->CheckParm ( "-HCHILD", &p ) && p )
+ {
+ heventChild = (HANDLE)atoi ( p );
+ }
+
+ // ignore if we don't have all the events.
+ if ( !hFile || !heventParent || !heventChild )
+ {
+ //sys->Printf ("\n\nNo external front end present.\n" );
+ return;
+ }
+
+ sys->Printf( "\n\nInitConProc: Setting up external control.\n" );
+
+ hfileBuffer = hFile;
+ heventParentSend = heventParent;
+ heventChildSend = heventChild;
+
+ // So we'll know when to go away.
+ heventDone = CreateEvent (NULL, FALSE, FALSE, NULL);
+ if (!heventDone)
+ {
+ sys->Printf ("InitConProc: Couldn't create heventDone\n");
+ return;
+ }
+
+ if (!_beginthreadex (NULL, 0, RequestProc, NULL, 0, &threadAddr))
+ {
+ CloseHandle (heventDone);
+ sys->Printf ("InitConProc: Couldn't create third party thread\n");
+ return;
+ }
+
+ // save off the input/output handles.
+ hStdout = GetStdHandle (STD_OUTPUT_HANDLE);
+ hStdin = GetStdHandle (STD_INPUT_HANDLE);
+
+ if ( CommandLine()->CheckParm( "-conheight", &p ) && p )
+ {
+ WantHeight = atoi( p );
+ }
+
+ // Force 80 character width, at least 25 character height
+ SetConsoleCXCY( hStdout, 80, WantHeight );
+}
+#endif // _WIN32
+
diff --git a/dedicated/console/conproc.h b/dedicated/console/conproc.h
new file mode 100644
index 0000000..ef84c42
--- /dev/null
+++ b/dedicated/console/conproc.h
@@ -0,0 +1,30 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+// conproc.h -- support for external server monitoring programs
+#ifndef INC_CONPROCH
+#define INC_CONPROCH
+
+#define CCOM_WRITE_TEXT 0x2
+// Param1 : Text
+
+#define CCOM_GET_TEXT 0x3
+// Param1 : Begin line
+// Param2 : End line
+
+#define CCOM_GET_SCR_LINES 0x4
+// No params
+
+#define CCOM_SET_SCR_LINES 0x5
+// Param1 : Number of lines
+
+void InitConProc ( void );
+void DeinitConProc ( void );
+
+void WriteStatusText( char *psz );
+
+#endif // !INC_CONPROCH \ No newline at end of file
diff --git a/dedicated/console/textconsole.cpp b/dedicated/console/textconsole.cpp
new file mode 100644
index 0000000..c52ae23
--- /dev/null
+++ b/dedicated/console/textconsole.cpp
@@ -0,0 +1,22 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+// TextConsole.cpp: implementation of the TextConsole class.
+//
+//////////////////////////////////////////////////////////////////////
+
+#include "textconsole.h"
+
+//////////////////////////////////////////////////////////////////////
+// Construction/Destruction
+//////////////////////////////////////////////////////////////////////
+
+bool CTextConsole::Init()
+{
+ m_ConsoleVisible = true;
+ return true;
+}
diff --git a/dedicated/console/textconsole.h b/dedicated/console/textconsole.h
new file mode 100644
index 0000000..69cf366
--- /dev/null
+++ b/dedicated/console/textconsole.h
@@ -0,0 +1,38 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+
+#if !defined TEXTCONSOLE_H
+#define TEXTCONSOLE_H
+#pragma once
+
+class CTextConsole
+{
+public:
+ CTextConsole() : m_ConsoleVisible( true ) {}
+ virtual ~CTextConsole() {};
+
+ virtual bool Init ();
+ virtual void ShutDown() = 0;
+ virtual void Print( char * pszMsg ) = 0;
+
+ virtual void SetTitle( char * pszTitle ) = 0;
+ virtual void SetStatusLine( char * pszStatus ) = 0;
+ virtual void UpdateStatus() = 0;
+
+ // Must be provided by children
+ virtual char * GetLine( int index, char *buf, int buflen ) = 0;
+ virtual int GetWidth() = 0;
+
+ virtual void SetVisible( bool visible ) { m_ConsoleVisible = visible; }
+ virtual bool IsVisible() { return m_ConsoleVisible; }
+
+protected:
+ bool m_ConsoleVisible;
+};
+
+#endif // !defined TEXTCONSOLE_H
diff --git a/dedicated/dedicated.h b/dedicated/dedicated.h
new file mode 100644
index 0000000..1dbe25f
--- /dev/null
+++ b/dedicated/dedicated.h
@@ -0,0 +1,78 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// Purpose: Defines a group of app systems that all have the same lifetime
+// that need to be connected/initialized, etc. in a well-defined order
+//
+// $NoKeywords: $
+//
+//===========================================================================//
+
+#ifndef DEDICATED_H
+#define DEDICATED_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "appframework/tier3app.h"
+
+
+//-----------------------------------------------------------------------------
+// Forward declarations
+//-----------------------------------------------------------------------------
+class IDedicatedServerAPI;
+
+
+//-----------------------------------------------------------------------------
+// Singleton interfaces
+//-----------------------------------------------------------------------------
+extern IDedicatedServerAPI *engine;
+
+
+extern char g_szEXEName[ MAX_PATH ];
+
+
+//-----------------------------------------------------------------------------
+// Inner loop: initialize, shutdown main systems, load steam to
+//-----------------------------------------------------------------------------
+#ifdef POSIX
+#define DEDICATED_BASECLASS CTier2SteamApp
+#else
+#define DEDICATED_BASECLASS CVguiSteamApp
+#endif
+
+class CDedicatedAppSystemGroup : public DEDICATED_BASECLASS
+{
+ typedef DEDICATED_BASECLASS BaseClass;
+
+public:
+ // Methods of IApplication
+ virtual bool Create( );
+ virtual bool PreInit( );
+ virtual int Main( );
+ virtual void PostShutdown();
+ virtual void Destroy();
+
+ // Used to chain to base class
+ AppModule_t LoadModule( CreateInterfaceFn factory )
+ {
+ return CSteamAppSystemGroup::LoadModule( factory );
+ }
+
+ // Method to add various global singleton systems
+ bool AddSystems( AppSystemInfo_t *pSystems )
+ {
+ return CSteamAppSystemGroup::AddSystems( pSystems );
+ }
+
+ void *FindSystem( const char *pInterfaceName )
+ {
+ return CSteamAppSystemGroup::FindSystem( pInterfaceName );
+ }
+};
+
+
+
+#endif // DEDICATED_H
diff --git a/dedicated/dedicated.rc b/dedicated/dedicated.rc
new file mode 100644
index 0000000..0427b0a
--- /dev/null
+++ b/dedicated/dedicated.rc
@@ -0,0 +1,72 @@
+//Microsoft Developer Studio generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_HALFLIFE ICON DISCARDABLE "..\\launcher\\res\\launcher.ico"
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/dedicated/dedicated.vpc b/dedicated/dedicated.vpc
new file mode 100644
index 0000000..949ba09
--- /dev/null
+++ b/dedicated/dedicated.vpc
@@ -0,0 +1,149 @@
+//-----------------------------------------------------------------------------
+// DEDICATED.VPC
+//
+// Project Script
+//-----------------------------------------------------------------------------
+
+$Macro SRCDIR ".."
+$Macro OUTBINDIR "$SRCDIR\..\game\bin"
+
+$Include "$SRCDIR\vpc_scripts\source_dll_base.vpc"
+$include "$SRCDIR\vpc_scripts\source_cryptlib_include.vpc"
+
+$Configuration
+{
+ $Compiler
+ {
+ $AdditionalIncludeDirectories "$BASE,.\,$SRCDIR\engine"
+ $PreprocessorDefinitions "$BASE;DEDICATED;LAUNCHERONLY;SUPPORT_PACKED_STORE"
+ }
+
+ $Linker
+ {
+ $AdditionalDependencies "$BASE wsock32.lib odbc32.lib odbccp32.lib winmm.lib"
+ $SystemLibraries "iconv;edit;curses" [$OSXALL]
+ $SystemFrameworks "AppKit" [$OSXALL]
+ }
+}
+
+$Project "Dedicated"
+{
+ $Folder "Source Files"
+ {
+ $File "dedicated.rc"
+ $File "sys_linux.cpp"
+ {
+ $Configuration
+ {
+ $ExcludedFromBuild "Yes"
+ }
+ }
+ $File "filesystem.cpp"
+ $File "$SRCDIR\public\filesystem_init.cpp"
+ $File "$SRCDIR\common\netapi.cpp"
+ $File "$SRCDIR\common\SteamAppStartup.cpp"
+ $File "sys_common.cpp"
+ $File "sys_ded.cpp"
+ $File "sys_windows.cpp" [$WINDOWS]
+ $File "sys_linux.cpp" [$POSIX]
+ {
+ $Configuration
+ {
+ $Compiler
+ {
+ $AdditionalOptions "/EHa"
+ $EnableC++Exceptions "Yes (/EHsc)"
+ }
+ }
+ }
+
+ $Folder "Console"
+ {
+ $File "console\conproc.cpp"
+ $File "console\textconsole.cpp"
+ $File "console\TextConsoleUnix.cpp" [$POSIX]
+ $File "console\TextConsoleWin32.cpp" [$WINDOWS]
+ }
+
+ $Folder "VGUI" [$WINDOWS]
+ {
+ $File "vgui\CreateMultiplayerGameServerPage.cpp"
+ $File "vgui\MainPanel.cpp"
+ $File "$SRCDIR\public\vgui_controls\vgui_controls.cpp"
+ $File "vgui\vguihelpers.cpp"
+ }
+
+ $Folder "FileSystem"
+ {
+ $File "$SRCDIR\filesystem\filetracker.cpp"
+ $File "$SRCDIR\filesystem\basefilesystem.cpp"
+ $File "$SRCDIR\filesystem\packfile.cpp"
+ $File "$SRCDIR\filesystem\filesystem_async.cpp"
+ $File "$SRCDIR\filesystem\filesystem_stdio.cpp"
+ $File "$SRCDIR\filesystem\QueuedLoader.cpp"
+ $File "$SRCDIR\public\zip_utils.cpp"
+ $File "$SRCDIR\filesystem\linux_support.cpp" [$POSIX]
+ }
+ }
+
+ $Folder "Header Files"
+ {
+ $File "$SRCDIR\filesystem\filetracker.h"
+ $File "$SRCDIR\filesystem\threadsaferefcountedobject.h"
+ $File "$SRCDIR\public\ifilelist.h"
+ $File "$SRCDIR\public\tier0\basetypes.h"
+ $File "$SRCDIR\public\tier0\commonmacros.h"
+ $File "$SRCDIR\public\tier0\dbg.h"
+ $File "dedicated.h"
+ $File "$SRCDIR\public\engine_hlds_api.h"
+ $File "$SRCDIR\public\tier0\fasttimer.h"
+ $File "$SRCDIR\public\filesystem.h"
+ $File "$SRCDIR\common\IAdminServer.h"
+ $File "$SRCDIR\public\appframework\IAppSystem.h"
+ $File "$SRCDIR\public\tier0\icommandline.h"
+ $File "$SRCDIR\public\idedicatedexports.h"
+ $File "$SRCDIR\common\IManageServer.h"
+ $File "$SRCDIR\public\tier1\interface.h"
+ $File "isys.h"
+ $File "$SRCDIR\public\mathlib\mathlib.h"
+ $File "$SRCDIR\common\netapi.h"
+ $File "$SRCDIR\common\GameUI\ObjectList.h"
+ $File "$SRCDIR\public\tier0\platform.h"
+ $File "$SRCDIR\public\tier0\protected_things.h"
+ $File "$SRCDIR\common\SteamAppStartup.h"
+ $File "$SRCDIR\public\string_t.h"
+ $File "$SRCDIR\public\tier1\strtools.h"
+ $File "$SRCDIR\public\tier0\vcr_shared.h"
+ $File "$SRCDIR\public\tier0\vcrmode.h"
+ $File "$SRCDIR\public\mathlib\vector.h"
+ $File "$SRCDIR\public\mathlib\vector2d.h"
+ $File "$SRCDIR\public\vstdlib\vstdlib.h"
+
+ $Folder "Console Headers"
+ {
+ $File "console\conproc.h"
+ $File "$SRCDIR\common\IObjectContainer.h"
+ $File "console\textconsole.h"
+ $File "console\TextConsoleWin32.h"
+ }
+
+ $Folder "VGUI Headers"
+ {
+ $File "vgui\CreateMultiplayerGameServerPage.h"
+ $File "vgui\MainPanel.h"
+ $File "vgui\vguihelpers.h"
+ }
+ }
+
+ $Folder "Link Libraries"
+ {
+ $Lib appframework
+ $Lib mathlib
+ $Lib tier2
+ $Lib tier3
+ $Lib vgui_controls [$WIN32]
+ $LibExternal "$SRCDIR/thirdparty/libedit-3.1/src/.libs/libedit" [$LINUXALL]
+ $ImpLibExternal steam_api
+ $ImpLib SDL2 [$SDL]
+ }
+}
diff --git a/dedicated/filesystem.cpp b/dedicated/filesystem.cpp
new file mode 100644
index 0000000..6d908a6
--- /dev/null
+++ b/dedicated/filesystem.cpp
@@ -0,0 +1,56 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $Workfile: $
+// $Date: $
+// $NoKeywords: $
+//===========================================================================//
+
+#include "filesystem.h"
+#include "dedicated.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include "interface.h"
+#include <string.h>
+#include <malloc.h>
+#include "tier1/strtools.h"
+#include "tier0/icommandline.h"
+#include "tier0/dbg.h"
+#include "../filesystem/basefilesystem.h"
+#include "appframework/AppFramework.h"
+#include "tier2/tier2.h"
+
+
+extern IFileSystem *g_pFileSystem;
+extern IBaseFileSystem *g_pBaseFileSystem;
+
+// implement our own special factory that we don't export outside of the DLL, to stop
+// people being able to get a pointer to a FILESYSTEM_INTERFACE_VERSION stdio interface
+void* FileSystemFactory(const char *pName, int *pReturnCode)
+{
+ {
+ if ( !Q_stricmp(pName, FILESYSTEM_INTERFACE_VERSION ) )
+ {
+ if ( pReturnCode )
+ {
+ *pReturnCode = IFACE_OK;
+ }
+ return g_pFileSystem;
+ }
+ if ( !Q_stricmp(pName, BASEFILESYSTEM_INTERFACE_VERSION ) )
+ {
+ if ( pReturnCode )
+ {
+ *pReturnCode = IFACE_OK;
+ }
+ return g_pBaseFileSystem;
+ }
+ }
+
+ if ( pReturnCode )
+ {
+ *pReturnCode = IFACE_FAILED;
+ }
+ return NULL;
+}
diff --git a/dedicated/isys.h b/dedicated/isys.h
new file mode 100644
index 0000000..d86769a
--- /dev/null
+++ b/dedicated/isys.h
@@ -0,0 +1,45 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#if !defined( ISYS_H )
+#define ISYS_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "interface.h"
+
+class CDedicatedAppSystemGroup;
+
+
+abstract_class ISys
+{
+public:
+ virtual ~ISys( void ) { }
+
+ virtual bool LoadModules( CDedicatedAppSystemGroup *pAppSystemGroup ) = 0;
+
+ virtual void Sleep( int msec ) = 0;
+ virtual bool GetExecutableName( char *out ) = 0;
+ virtual void ErrorMessage( int level, const char *msg ) = 0;
+
+ virtual void WriteStatusText( char *szText ) = 0;
+ virtual void UpdateStatus( int force ) = 0;
+
+ virtual long LoadLibrary( char *lib ) = 0;
+ virtual void FreeLibrary( long library ) = 0;
+
+ virtual bool CreateConsoleWindow( void ) = 0;
+ virtual void DestroyConsoleWindow( void ) = 0;
+
+ virtual void ConsoleOutput ( char *string ) = 0;
+ virtual char *ConsoleInput ( int index, char *buf, int buflen ) = 0;
+ virtual void Printf( PRINTF_FORMAT_STRING const char *fmt, ...) FMTFUNCTION( 2, 3 ) = 0;
+};
+
+extern ISys *sys;
+
+#endif // ISYS_H \ No newline at end of file
diff --git a/dedicated/resource.h b/dedicated/resource.h
new file mode 100644
index 0000000..3447d84
--- /dev/null
+++ b/dedicated/resource.h
@@ -0,0 +1,25 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by Dedicated.rc
+//
+#define IDI_HALFLIFE 101
+#define IDD_CDKEY 102
+#define IDC_KEY 1000
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 105
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1001
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/dedicated/sys_common.cpp b/dedicated/sys_common.cpp
new file mode 100644
index 0000000..5138bd3
--- /dev/null
+++ b/dedicated/sys_common.cpp
@@ -0,0 +1,300 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//===========================================================================//
+#ifdef _WIN32
+#include <windows.h>
+#elif POSIX
+#include <unistd.h>
+#else
+#error
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include "isys.h"
+#include "dedicated.h"
+#include "engine_hlds_api.h"
+#include "filesystem.h"
+#include "tier0/vcrmode.h"
+#include "tier0/dbg.h"
+#include "tier1/strtools.h"
+#include "tier0/icommandline.h"
+#include "idedicatedexports.h"
+#include "vgui/vguihelpers.h"
+
+static long hDLLThirdParty = 0L;
+
+//-----------------------------------------------------------------------------
+// Modules...
+//-----------------------------------------------------------------------------
+CSysModule *s_hMatSystemModule = NULL;
+CSysModule *s_hEngineModule = NULL;
+CSysModule *s_hSoundEmitterModule = NULL;
+
+CreateInterfaceFn s_MaterialSystemFactory;
+CreateInterfaceFn s_EngineFactory;
+CreateInterfaceFn s_SoundEmitterFactory;
+
+/*
+==============
+Load3rdParty
+
+Load support for third party .dlls ( gamehost )
+==============
+*/
+void Load3rdParty( void )
+{
+ // Only do this if the server operator wants the support.
+ // ( In case of malicious code, too )
+ if ( CommandLine()->CheckParm( "-usegh" ) )
+ {
+ hDLLThirdParty = sys->LoadLibrary( "ghostinj.dll" );
+ }
+}
+
+/*
+==============
+EF_VID_ForceUnlockedAndReturnState
+
+Dummy funcion called by engine
+==============
+*/
+int EF_VID_ForceUnlockedAndReturnState(void)
+{
+ return 0;
+}
+
+/*
+==============
+EF_VID_ForceLockState
+
+Dummy funcion called by engine
+==============
+*/
+void EF_VID_ForceLockState(int)
+{
+}
+
+/*
+==============
+InitInstance
+
+==============
+*/
+bool InitInstance( )
+{
+ Load3rdParty();
+
+ return true;
+}
+
+/*
+==============
+ProcessConsoleInput
+
+==============
+*/
+int ProcessConsoleInput(void)
+{
+ char *s;
+ int count = 0;
+
+ if ( engine )
+ {
+ do
+ {
+ char szBuf[ 256 ];
+ s = sys->ConsoleInput( count++, szBuf, sizeof( szBuf ) );
+ if (s && s[0] )
+ {
+ V_strcat_safe( szBuf, "\n" );
+ engine->AddConsoleText ( szBuf );
+ }
+ } while (s);
+ }
+
+ return count;
+}
+
+void RunServer( void );
+
+class CDedicatedExports : public CBaseAppSystem<IDedicatedExports>
+{
+public:
+ virtual void Sys_Printf( char *text )
+ {
+ if ( sys )
+ {
+ sys->Printf( "%s", text );
+ }
+ }
+
+ virtual void RunServer()
+ {
+ void RunServer( void );
+ ::RunServer();
+ }
+};
+
+EXPOSE_SINGLE_INTERFACE( CDedicatedExports, IDedicatedExports, VENGINE_DEDICATEDEXPORTS_API_VERSION );
+
+static const char *get_consolelog_filename()
+{
+ static bool s_bInited = false;
+ static char s_consolelog[ MAX_PATH ];
+
+ if ( !s_bInited )
+ {
+ s_bInited = true;
+
+ // Don't do the -consolelog thing if -consoledebug is present.
+ // CTextConsoleUnix::Print() looks for -consoledebug.
+ const char *filename = NULL;
+ if ( !CommandLine()->FindParm( "-consoledebug" ) &&
+ CommandLine()->CheckParm( "-consolelog", &filename ) &&
+ filename )
+ {
+ V_strcpy_safe( s_consolelog, filename );
+ }
+ }
+
+ return s_consolelog;
+}
+
+SpewRetval_t DedicatedSpewOutputFunc( SpewType_t spewType, char const *pMsg )
+{
+ if ( sys )
+ {
+ sys->Printf( "%s", pMsg );
+
+ // If they have specified -consolelog, log this message there. Otherwise these
+ // wind up being lost because Sys_InitGame hasn't been called yet, and
+ // Sys_SpewFunc is the thing that logs stuff to -consolelog, etc.
+ const char *filename = get_consolelog_filename();
+ if ( filename[ 0 ] && pMsg[ 0 ] )
+ {
+ FileHandle_t fh = g_pFullFileSystem->Open( filename, "a" );
+ if ( fh != FILESYSTEM_INVALID_HANDLE )
+ {
+ g_pFullFileSystem->Write( pMsg, V_strlen( pMsg ), fh );
+ g_pFullFileSystem->Close( fh );
+ }
+ }
+ }
+#ifdef _WIN32
+ Plat_DebugString( pMsg );
+#endif
+
+ if (spewType == SPEW_ERROR)
+ {
+ // In Windows vgui mode, make a message box or they won't ever see the error.
+#ifdef _WIN32
+ extern bool g_bVGui;
+ if ( g_bVGui )
+ {
+ MessageBox( NULL, pMsg, "Error", MB_OK | MB_TASKMODAL );
+ }
+ TerminateProcess( GetCurrentProcess(), 1 );
+#elif POSIX
+ fflush(stdout);
+ _exit(1);
+#else
+#error "Implement me"
+#endif
+
+ return SPEW_ABORT;
+ }
+ if (spewType == SPEW_ASSERT)
+ {
+ if ( CommandLine()->FindParm( "-noassert" ) == 0 )
+ return SPEW_DEBUGGER;
+ else
+ return SPEW_CONTINUE;
+ }
+ return SPEW_CONTINUE;
+}
+
+int Sys_GetExecutableName( char *out )
+{
+#ifdef _WIN32
+ if ( !::GetModuleFileName( ( HINSTANCE )GetModuleHandle( NULL ), out, 256 ) )
+ {
+ return 0;
+ }
+#else
+ strcpy( out, g_szEXEName );
+#endif
+ return 1;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Return the directory where this .exe is running from
+// Output : char
+//-----------------------------------------------------------------------------
+const char *UTIL_GetExecutableDir( )
+{
+ static char exedir[ MAX_PATH ];
+
+ exedir[ 0 ] = 0;
+ if ( !Sys_GetExecutableName(exedir) )
+ return NULL;
+
+ char *pSlash;
+ char *pSlash2;
+ pSlash = strrchr( exedir,'\\' );
+ pSlash2 = strrchr( exedir,'/' );
+ if ( pSlash2 > pSlash )
+ {
+ pSlash = pSlash2;
+ }
+ if (pSlash)
+ {
+ *pSlash = 0;
+ }
+
+ // Return the bin directory as the executable dir if it's not in there
+ // because that's really where we're running from...
+ int exeLen = strlen(exedir);
+ if ( exedir[exeLen-4] != CORRECT_PATH_SEPARATOR ||
+ exedir[exeLen-3] != 'b' ||
+ exedir[exeLen-2] != 'i' ||
+ exedir[exeLen-1] != 'n' )
+ {
+ Q_strncat( exedir, "\\bin", sizeof( exedir ), COPY_ALL_CHARACTERS );
+ Q_FixSlashes( exedir );
+ }
+
+ return exedir;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Return the directory where this .exe is running from
+// Output : char
+//-----------------------------------------------------------------------------
+const char *UTIL_GetBaseDir( void )
+{
+ static char basedir[ MAX_PATH ];
+
+ char const *pOverrideDir = CommandLine()->CheckParm( "-basedir" );
+ if ( pOverrideDir )
+ return pOverrideDir;
+
+ basedir[ 0 ] = 0;
+ const char *pExeDir = UTIL_GetExecutableDir( );
+ if ( pExeDir )
+ {
+ strcpy( basedir, pExeDir );
+ int dirlen = strlen( basedir );
+ if ( basedir[ dirlen - 3 ] == 'b' &&
+ basedir[ dirlen - 2 ] == 'i' &&
+ basedir[ dirlen - 1 ] == 'n' )
+ {
+ basedir[ dirlen - 4 ] = 0;
+ }
+ }
+
+ return basedir;
+}
diff --git a/dedicated/sys_ded.cpp b/dedicated/sys_ded.cpp
new file mode 100644
index 0000000..c7a9be9
--- /dev/null
+++ b/dedicated/sys_ded.cpp
@@ -0,0 +1,530 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//===========================================================================//
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "isys.h"
+#include "console/conproc.h"
+#include "dedicated.h"
+#include "engine_hlds_api.h"
+#include "checksum_md5.h"
+#include "mathlib/mathlib.h"
+#include "tier0/vcrmode.h"
+#include "tier0/dbg.h"
+#include "tier1/strtools.h"
+#include "tier0/icommandline.h"
+#include "idedicatedexports.h"
+#include "vgui/vguihelpers.h"
+#include "appframework/AppFramework.h"
+#include "filesystem_init.h"
+#include "tier2/tier2.h"
+#include "dedicated.h"
+#include "vstdlib/cvar.h"
+#include "inputsystem/iinputsystem.h"
+
+#ifdef _WIN32
+#include <windows.h>
+#include <direct.h>
+#include "KeyValues.h"
+#else
+#define _chdir chdir
+#include <unistd.h>
+#endif
+
+void* FileSystemFactory( const char *pName, int *pReturnCode );
+bool InitInstance( );
+int ProcessConsoleInput( void );
+bool NET_Init( void );
+void NET_Shutdown( void );
+const char *UTIL_GetBaseDir( void );
+#ifdef _WIN32
+bool g_bVGui = false;
+#endif
+
+#if defined ( _WIN32 )
+#include "console/TextConsoleWin32.h"
+CTextConsoleWin32 console;
+#else
+#include "console/TextConsoleUnix.h"
+CTextConsoleUnix console;
+#endif
+
+#ifdef _WIN32
+extern char *gpszCvars;
+#endif
+
+IDedicatedServerAPI *engine = NULL;
+
+//-----------------------------------------------------------------------------
+// Implementation of IVCRHelpers.
+//-----------------------------------------------------------------------------
+class CVCRHelpers : public IVCRHelpers
+{
+public:
+ virtual void ErrorMessage( const char *pMsg )
+ {
+ printf( "ERROR: %s\n", pMsg );
+ }
+
+ virtual void* GetMainWindow()
+ {
+ return 0;
+ }
+};
+CVCRHelpers g_VCRHelpers;
+
+SpewRetval_t DedicatedSpewOutputFunc( SpewType_t spewType, char const *pMsg ); // in sys_common.cpp
+
+//-----------------------------------------------------------------------------
+// Run a single VGUI frame. if bFinished is true, run VGUIFinishedConfig() first.
+//-----------------------------------------------------------------------------
+static bool DoRunVGUIFrame( bool bFinished = false )
+{
+#ifdef _WIN32
+ if ( g_bVGui )
+ {
+ if ( bFinished )
+ VGUIFinishedConfig();
+ RunVGUIFrame();
+ return true;
+ }
+#endif
+
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Handle the VCRHook PeekMessage loop.
+// Return true if WM_QUIT received.
+//-----------------------------------------------------------------------------
+static bool HandleVCRHook()
+{
+#if defined ( _WIN32 )
+ MSG msg;
+
+ bool bDone = false;
+ while( VCRHook_PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
+ {
+ //if (!GetMessage( &msg, NULL, 0, 0))
+ if ( msg.message == WM_QUIT )
+ {
+ bDone = true;
+ break;
+ }
+
+ TranslateMessage( &msg );
+ DispatchMessage( &msg );
+ }
+
+ if ( IsPC() )
+ {
+ // NOTE: Under some implementations of Win9x,
+ // dispatching messages can cause the FPU control word to change
+ SetupFPUControlWord();
+ }
+
+ if ( bDone /*|| gbAppHasBeenTerminated*/ )
+ return true;
+#endif // _WIN32
+
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+//
+// Server loop
+//
+//-----------------------------------------------------------------------------
+void RunServer( void )
+{
+#ifdef _WIN32
+ if(gpszCvars)
+ {
+ engine->AddConsoleText(gpszCvars);
+ }
+#endif
+
+ // Run 2 engine frames first to get the engine to load its resources.
+ for ( int i = 0; i < 2; i++ )
+ {
+ DoRunVGUIFrame();
+ if ( !engine->RunFrame() )
+ return;
+ }
+
+ // Run final VGUI frame.
+ DoRunVGUIFrame( true );
+
+ int bDone = false;
+ while ( !bDone )
+ {
+ // Check on VCRHook_PeekMessage...
+ if ( HandleVCRHook() )
+ break;
+
+ if ( !DoRunVGUIFrame() )
+ ProcessConsoleInput();
+
+ if ( !engine->RunFrame() )
+ bDone = true;
+
+ sys->UpdateStatus( 0 /* don't force */ );
+ }
+}
+
+//-----------------------------------------------------------------------------
+//
+// initialize the console or wait for vgui to start the server
+//
+//-----------------------------------------------------------------------------
+static bool ConsoleStartup( )
+{
+#ifdef _WIN32
+ if ( g_bVGui )
+ {
+ RunVGUIFrame();
+
+ // Run the config screen
+ while (VGUIIsInConfig() && VGUIIsRunning())
+ RunVGUIFrame();
+
+ if ( VGUIIsStopping() )
+ return false;
+
+ return true;
+ }
+ else
+ {
+ if ( !console.Init() )
+ {
+ return false;
+ }
+ }
+#endif // _WIN32
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Instantiate all main libraries
+//-----------------------------------------------------------------------------
+bool CDedicatedAppSystemGroup::Create( )
+{
+#ifndef _WIN32
+ if ( !console.Init() )
+ return false;
+#endif
+
+ // Hook the debug output stuff (override the spew func in the appframework)
+ SpewOutputFunc( DedicatedSpewOutputFunc );
+
+ // Added the dedicated exports module for the engine to grab
+ AppModule_t dedicatedModule = LoadModule( Sys_GetFactoryThis() );
+ IAppSystem *pSystem = AddSystem( dedicatedModule, VENGINE_DEDICATEDEXPORTS_API_VERSION );
+ if ( !pSystem )
+ return false;
+
+ if ( sys->LoadModules( this ) )
+ {
+ // Find the input system and tell it to skip Steam Controller initialization (we have to set this flag before Init gets called on the
+ // input system). Dedicated server should skip controller initialization to avoid initializing Steam, because we don't want the user to be
+ // flagged as "playing" the game.
+ auto inputsystem = ( IInputSystem* )FindSystem( INPUTSYSTEM_INTERFACE_VERSION );
+ if ( inputsystem )
+ {
+ inputsystem->SetSkipControllerInitialization( true );
+ }
+
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+bool CDedicatedAppSystemGroup::PreInit( )
+{
+ // A little hack needed because dedicated links directly to filesystem .cpp files
+ g_pFullFileSystem = NULL;
+
+ if ( !BaseClass::PreInit() )
+ return false;
+
+ CFSSteamSetupInfo steamInfo;
+ steamInfo.m_pDirectoryName = NULL;
+ steamInfo.m_bOnlyUseDirectoryName = false;
+ steamInfo.m_bToolsMode = false;
+ steamInfo.m_bSetSteamDLLPath = false;
+ steamInfo.m_bSteam = g_pFullFileSystem->IsSteam();
+ steamInfo.m_bNoGameInfo = steamInfo.m_bSteam;
+ if ( FileSystem_SetupSteamEnvironment( steamInfo ) != FS_OK )
+ return false;
+
+ CFSMountContentInfo fsInfo;
+ fsInfo.m_pFileSystem = g_pFullFileSystem;
+ fsInfo.m_bToolsMode = false;
+ fsInfo.m_pDirectoryName = steamInfo.m_GameInfoPath;
+
+ if ( FileSystem_MountContent( fsInfo ) != FS_OK )
+ return false;
+
+ if ( !NET_Init() )
+ return false;
+
+#ifdef _WIN32
+ g_bVGui = !CommandLine()->CheckParm( "-console" );
+#endif
+
+ CreateInterfaceFn factory = GetFactory();
+ IInputSystem *inputsystem = (IInputSystem *)factory( INPUTSYSTEM_INTERFACE_VERSION, NULL );
+ if ( inputsystem )
+ {
+ inputsystem->SetConsoleTextMode( true );
+ }
+
+#ifdef _WIN32
+ if ( g_bVGui )
+ {
+ StartVGUI( GetFactory() );
+ }
+ else
+#endif
+ {
+ if ( !sys->CreateConsoleWindow() )
+ return false;
+ }
+
+ return true;
+}
+
+int CDedicatedAppSystemGroup::Main( )
+{
+ if ( !ConsoleStartup() )
+ return -1;
+
+#ifdef _WIN32
+ if ( g_bVGui )
+ RunVGUIFrame();
+#endif
+
+ // Set up mod information
+ ModInfo_t info;
+ info.m_pInstance = GetAppInstance();
+ info.m_pBaseDirectory = UTIL_GetBaseDir();
+ info.m_pInitialMod = CommandLine()->ParmValue( "-game", "hl2" );
+ info.m_pInitialGame = CommandLine()->ParmValue( "-defaultgamedir", "hl2" );
+ info.m_pParentAppSystemGroup = this;
+ info.m_bTextMode = CommandLine()->CheckParm( "-textmode" );
+
+ if ( engine->ModInit( info ) )
+ {
+ engine->ModShutdown();
+ } // if engine->ModInit
+
+ return 0;
+}
+
+//-----------------------------------------------------------------------------
+//
+//-----------------------------------------------------------------------------
+void CDedicatedAppSystemGroup::PostShutdown()
+{
+#ifdef _WIN32
+ if ( g_bVGui )
+ StopVGUI();
+#endif
+
+ sys->DestroyConsoleWindow();
+ console.ShutDown();
+ NET_Shutdown();
+ BaseClass::PostShutdown();
+}
+
+//-----------------------------------------------------------------------------
+//
+//-----------------------------------------------------------------------------
+void CDedicatedAppSystemGroup::Destroy()
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Gets the executable name
+//-----------------------------------------------------------------------------
+bool GetExecutableName( char *out, int nMaxLen )
+{
+#ifdef _WIN32
+ if ( !::GetModuleFileName( ( HINSTANCE )GetModuleHandle( NULL ), out, nMaxLen ) )
+ return false;
+ return true;
+#elif POSIX
+ Q_strncpy( out, g_szEXEName, nMaxLen );
+ return true;
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Return the directory where this .exe is running from
+// Output : char
+//-----------------------------------------------------------------------------
+void UTIL_ComputeBaseDir( char *pBaseDir, int nMaxLen )
+{
+ int j;
+ char *pBuffer = NULL;
+
+ pBaseDir[ 0 ] = 0;
+
+ if ( GetExecutableName( pBaseDir, nMaxLen ) )
+ {
+ pBuffer = strrchr( pBaseDir, CORRECT_PATH_SEPARATOR );
+ if ( pBuffer && *pBuffer )
+ {
+ *(pBuffer+1) = '\0';
+ }
+
+ j = strlen( pBaseDir );
+ if (j > 0)
+ {
+ if ( ( pBaseDir[ j-1 ] == '\\' ) ||
+ ( pBaseDir[ j-1 ] == '/' ) )
+ {
+ pBaseDir[ j-1 ] = 0;
+ }
+ }
+ }
+
+ char const *pOverrideDir = CommandLine()->CheckParm( "-basedir" );
+ if ( pOverrideDir )
+ {
+ strcpy( pBaseDir, pOverrideDir );
+ }
+
+ Q_strlower( pBaseDir );
+ Q_FixSlashes( pBaseDir );
+}
+
+
+//-----------------------------------------------------------------------------
+// This class is a helper class used for steam-based applications.
+// It loads up the file system in preparation for using it to load other
+// required modules from steam.
+//
+// I couldn't use the one in appframework because the dedicated server
+// inlines all the filesystem code.
+//-----------------------------------------------------------------------------
+class CDedicatedSteamApplication : public CSteamApplication
+{
+public:
+ CDedicatedSteamApplication( CSteamAppSystemGroup *pAppSystemGroup );
+ virtual bool Create( );
+};
+
+
+//-----------------------------------------------------------------------------
+// This class is a helper class used for steam-based applications.
+// It loads up the file system in preparation for using it to load other
+// required modules from steam.
+//
+// I couldn't use the one in appframework because the dedicated server
+// inlines all the filesystem code.
+//-----------------------------------------------------------------------------
+CDedicatedSteamApplication::CDedicatedSteamApplication( CSteamAppSystemGroup *pAppSystemGroup ) : CSteamApplication( pAppSystemGroup )
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Implementation of IAppSystemGroup
+//-----------------------------------------------------------------------------
+bool CDedicatedSteamApplication::Create( )
+{
+ // Add in the cvar factory
+ AppModule_t cvarModule = LoadModule( VStdLib_GetICVarFactory() );
+ AddSystem( cvarModule, CVAR_INTERFACE_VERSION );
+
+ AppModule_t fileSystemModule = LoadModule( FileSystemFactory );
+ m_pFileSystem = (IFileSystem*)AddSystem( fileSystemModule, FILESYSTEM_INTERFACE_VERSION );
+
+ if ( !m_pFileSystem )
+ {
+ Warning( "Unable to load the file system!\n" );
+ return false;
+ }
+
+ return true;
+}
+
+
+
+//-----------------------------------------------------------------------------
+//
+// Main entry point for dedicated server, shared between win32 and linux
+//
+//-----------------------------------------------------------------------------
+int main(int argc, char **argv)
+{
+#ifndef POSIX
+ _asm
+ {
+ fninit
+ }
+#endif
+
+ SetupFPUControlWord();
+
+#ifdef POSIX
+ Q_strncpy( g_szEXEName, *argv, ARRAYSIZE( g_szEXEName ) );
+ // Store off command line for argument searching
+ BuildCmdLine( argc, argv );
+#endif
+
+ MathLib_Init( 2.2f, 2.2f, 0.0f, 1.0f );
+
+ // Store off command line for argument searching
+ CommandLine()->CreateCmdLine( VCRHook_GetCommandLine() );
+#ifndef _WIN32
+ Plat_SetCommandLine( CommandLine()->GetCmdLine() );
+#endif
+
+ // Start VCR mode?
+ const char *filename;
+ if( CommandLine()->CheckParm( "-vcrrecord", &filename ) )
+ {
+ if ( !VCRStart( filename, true, &g_VCRHelpers ) )
+ {
+ Error( "-vcrrecord: can't open '%s' for writing.\n", filename );
+ return -1;
+ }
+ }
+ else if( CommandLine()->CheckParm( "-vcrplayback", &filename ) )
+ {
+ if ( !VCRStart( filename, false, &g_VCRHelpers ) )
+ {
+ Error( "-vcrplayback: can't open '%s' for reading.\n", filename );
+ return -1;
+ }
+ }
+
+ // Figure out the directory the executable is running from
+ // and make that be the current working directory
+ char pBasedir[ MAX_PATH ];
+ UTIL_ComputeBaseDir( pBasedir, MAX_PATH );
+ _chdir( pBasedir );
+
+ // Rehook the command line through VCR mode.
+ CommandLine()->CreateCmdLine( VCRHook_GetCommandLine() );
+
+ if ( !InitInstance() )
+ return -1;
+
+ CDedicatedAppSystemGroup dedicatedSystems;
+ CDedicatedSteamApplication steamApplication( &dedicatedSystems );
+ return steamApplication.Run( );
+}
diff --git a/dedicated/sys_linux.cpp b/dedicated/sys_linux.cpp
new file mode 100644
index 0000000..28e9b6c
--- /dev/null
+++ b/dedicated/sys_linux.cpp
@@ -0,0 +1,298 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+
+#include <unistd.h>
+#include <string.h>
+#include <dlfcn.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <malloc.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <dlfcn.h>
+#include "isys.h"
+#include "console/conproc.h"
+#include "dedicated.h"
+#include "engine_hlds_api.h"
+#include "checksum_md5.h"
+#include "idedicatedexports.h"
+#include "tier0/vcrmode.h"
+#include "tier0/dbg.h"
+#include "mathlib/mathlib.h"
+#include "interface.h"
+#include "tier1/strtools.h"
+#include "tier0/icommandline.h"
+#include "materialsystem/imaterialsystem.h"
+#include "istudiorender.h"
+#include "SoundEmitterSystem/isoundemittersystembase.h"
+#include "datacache/idatacache.h"
+#include "datacache/imdlcache.h"
+#include "vphysics_interface.h"
+#include "icvar.h"
+#include "filesystem/IQueuedLoader.h"
+#include "console/TextConsoleUnix.h"
+
+bool InitInstance( );
+
+char g_szEXEName[ MAX_PATH ];
+
+extern CTextConsoleUnix console;
+
+//-----------------------------------------------------------------------------
+// Purpose: Implements OS Specific layer ( loosely )
+//-----------------------------------------------------------------------------
+class CSys : public ISys
+{
+public:
+ virtual ~CSys();
+
+ virtual bool LoadModules( CDedicatedAppSystemGroup *pAppSystemGroup );
+
+ void Sleep( int msec );
+ bool GetExecutableName( char *out );
+ void ErrorMessage( int level, const char *msg );
+
+ void WriteStatusText( char *szText );
+ void UpdateStatus( int force );
+
+ long LoadLibrary( char *lib );
+ void FreeLibrary( long library );
+ void *GetProcAddress( long library, const char *name );
+
+ bool CreateConsoleWindow( void );
+ void DestroyConsoleWindow( void );
+
+ void ConsoleOutput ( char *string );
+ char *ConsoleInput ( int index, char *buf, int buflen );
+ void Printf( const char *fmt, ...);
+};
+
+static CSys g_Sys;
+ISys *sys = &g_Sys;
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CSys::~CSys()
+{
+ sys = NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : msec
+// Output :
+//-----------------------------------------------------------------------------
+void CSys::Sleep( int msec )
+{
+ usleep(msec * 1000);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : handle, function name-
+// Output : void *
+//-----------------------------------------------------------------------------
+void *CSys::GetProcAddress( long library, const char *name )
+{
+ return dlsym( library, name );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *lib -
+// Output : long
+//-----------------------------------------------------------------------------
+long CSys::LoadLibrary( char *lib )
+{
+ void *hDll = NULL;
+
+ char cwd[1024];
+ char absolute_lib[1024];
+
+ if (!getcwd(cwd, sizeof(cwd)))
+ ErrorMessage(1, "Sys_LoadLibrary: Couldn't determine current directory.");
+
+ if (cwd[strlen(cwd)-1] == '/')
+ cwd[strlen(cwd)-1] = 0;
+
+ Q_snprintf(absolute_lib, sizeof( absolute_lib ), "%s/%s", cwd, lib);
+
+ hDll = dlopen( absolute_lib, RTLD_NOW );
+ if ( !hDll )
+ {
+ ErrorMessage( 1, dlerror() );
+ }
+ return (long)hDll;
+}
+
+void CSys::FreeLibrary( long library )
+{
+ if ( !library )
+ return;
+
+ dlclose( (void *)library );
+}
+
+bool CSys::GetExecutableName( char *out )
+{
+ char *name = strrchr(g_szEXEName, '/' );
+ if ( name )
+ {
+ strcpy( out, name + 1);
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+/*
+==============
+ErrorMessage
+
+Engine is erroring out, display error in message box
+==============
+*/
+void CSys::ErrorMessage( int level, const char *msg )
+{
+ Error( "%s\n", msg );
+ exit( -1 );
+}
+
+void CSys::UpdateStatus( int force )
+{
+}
+
+/*
+================
+ConsoleOutput
+
+Print text to the dedicated console
+================
+*/
+void CSys::ConsoleOutput (char *string)
+{
+ console.Print(string);
+}
+
+/*
+==============
+Printf
+
+Engine is printing to console
+==============
+*/
+void CSys::Printf( const char *fmt, ...)
+{
+ // Dump text to debugging console.
+ va_list argptr;
+ char szText[1024];
+
+ va_start (argptr, fmt);
+ Q_vsnprintf (szText, sizeof( szText ), fmt, argptr);
+ va_end (argptr);
+
+ // Get Current text and append it.
+ ConsoleOutput( szText );
+}
+
+/*
+================
+ConsoleInput
+
+================
+*/
+char *CSys::ConsoleInput( int index, char *buf, int buflen )
+{
+ return console.GetLine( index, buf, buflen );
+}
+
+/*
+==============
+WriteStatusText
+
+==============
+*/
+void CSys::WriteStatusText( char *szText )
+{
+}
+
+/*
+==============
+CreateConsoleWindow
+
+Create console window ( overridable? )
+==============
+*/
+bool CSys::CreateConsoleWindow( void )
+{
+ return true;
+}
+
+/*
+==============
+DestroyConsoleWindow
+
+==============
+*/
+void CSys::DestroyConsoleWindow( void )
+{
+}
+
+/*
+================
+GameInit
+================
+*/
+bool CSys::LoadModules( CDedicatedAppSystemGroup *pAppSystemGroup )
+{
+ AppSystemInfo_t appSystems[] =
+ {
+ { "engine" DLL_EXT_STRING, CVAR_QUERY_INTERFACE_VERSION },
+ { "soundemittersystem" DLL_EXT_STRING, SOUNDEMITTERSYSTEM_INTERFACE_VERSION }, // loaded for backwards compatability, prevents crash on exit for old game dlls
+ { "materialsystem" DLL_EXT_STRING, MATERIAL_SYSTEM_INTERFACE_VERSION },
+ { "studiorender" DLL_EXT_STRING, STUDIO_RENDER_INTERFACE_VERSION },
+ { "vphysics" DLL_EXT_STRING, VPHYSICS_INTERFACE_VERSION },
+ { "datacache" DLL_EXT_STRING, DATACACHE_INTERFACE_VERSION },
+ { "datacache" DLL_EXT_STRING, MDLCACHE_INTERFACE_VERSION },
+ { "datacache" DLL_EXT_STRING, STUDIO_DATA_CACHE_INTERFACE_VERSION },
+ { "dedicated" DLL_EXT_STRING, QUEUEDLOADER_INTERFACE_VERSION },
+ { "engine" DLL_EXT_STRING, VENGINE_HLDS_API_VERSION },
+ { "", "" } // Required to terminate the list
+ };
+
+ if ( !pAppSystemGroup->AddSystems( appSystems ) )
+ return false;
+
+ engine = (IDedicatedServerAPI *)pAppSystemGroup->FindSystem( VENGINE_HLDS_API_VERSION );
+ // obsolete i think SetCVarIF( (ICvar*)pAppSystemGroup->FindSystem( VENGINE_CVAR_INTERFACE_VERSION ) );
+
+ IMaterialSystem* pMaterialSystem = (IMaterialSystem*)pAppSystemGroup->FindSystem( MATERIAL_SYSTEM_INTERFACE_VERSION );
+ pMaterialSystem->SetShaderAPI( "shaderapiempty" DLL_EXT_STRING );
+ return true;
+}
+
+bool NET_Init()
+{
+ return true;
+}
+
+void NET_Shutdown()
+{
+}
+
+extern int main(int argc, char *argv[]);
+DLL_EXPORT int DedicatedMain( int argc, char *argv[] );
+
+int DedicatedMain( int argc, char *argv[] )
+{
+ return main(argc,argv);
+}
diff --git a/dedicated/sys_windows.cpp b/dedicated/sys_windows.cpp
new file mode 100644
index 0000000..aacf0aa
--- /dev/null
+++ b/dedicated/sys_windows.cpp
@@ -0,0 +1,411 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+#include <windows.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <eh.h>
+#include "isys.h"
+#include "console/conproc.h"
+#include "dedicated.h"
+#include "engine_hlds_api.h"
+#include "checksum_md5.h"
+#include "tier0/vcrmode.h"
+#include "tier0/dbg.h"
+#include "tier1/strtools.h"
+#include "tier0/icommandline.h"
+#include "inputsystem/iinputsystem.h"
+#include "SteamAppStartup.h"
+#include "console/textconsole.h"
+#include "vgui/vguihelpers.h"
+#include "appframework/appframework.h"
+#include "materialsystem/imaterialsystem.h"
+#include "istudiorender.h"
+#include "vgui/ivgui.h"
+#include "console/TextConsoleWin32.h"
+#include "icvar.h"
+#include "datacache/idatacache.h"
+#include "datacache/imdlcache.h"
+#include "vphysics_interface.h"
+#include "filesystem.h"
+#include "steam/steam_api.h"
+#include "filesystem/IQueuedLoader.h"
+
+extern CTextConsoleWin32 console;
+extern bool g_bVGui;
+
+//-----------------------------------------------------------------------------
+// Purpose: Implements OS Specific layer ( loosely )
+//-----------------------------------------------------------------------------
+class CSys : public ISys
+{
+public:
+ virtual ~CSys( void );
+
+ virtual bool LoadModules( CDedicatedAppSystemGroup *pAppSystemGroup );
+
+ void Sleep( int msec );
+ bool GetExecutableName( char *out );
+ void ErrorMessage( int level, const char *msg );
+
+ void WriteStatusText( char *szText );
+ void UpdateStatus( int force );
+
+ long LoadLibrary( char *lib );
+ void FreeLibrary( long library );
+
+ bool CreateConsoleWindow( void );
+ void DestroyConsoleWindow( void );
+
+ void ConsoleOutput ( char *string );
+ char *ConsoleInput ( int index, char *buf, int buflen );
+ void Printf( PRINTF_FORMAT_STRING const char *fmt, ... );
+};
+
+static CSys g_Sys;
+ISys *sys = &g_Sys;
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CSys::~CSys()
+{
+ sys = NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : msec -
+//-----------------------------------------------------------------------------
+void CSys::Sleep( int msec )
+{
+ // Call ThreadSleep because it has the necessary magic to set the system
+ // timer resolution so that Sleep( 1 ) will sleep for one millisecond
+ // instead of for 10-16 ms.
+ ThreadSleep( msec );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *lib -
+// Output : long
+//-----------------------------------------------------------------------------
+long CSys::LoadLibrary( char *lib )
+{
+ void *hDll = ::LoadLibrary( lib );
+ return (long)hDll;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : library -
+//-----------------------------------------------------------------------------
+void CSys::FreeLibrary( long library )
+{
+ if ( !library )
+ return;
+
+ ::FreeLibrary( (HMODULE)library );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *out -
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CSys::GetExecutableName( char *out )
+{
+ if ( !::GetModuleFileName( ( HINSTANCE )GetModuleHandle( NULL ), out, 256 ) )
+ {
+ return false;
+ }
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : level -
+// *msg -
+//-----------------------------------------------------------------------------
+void CSys::ErrorMessage( int level, const char *msg )
+{
+ MessageBox( NULL, msg, "Half-Life", MB_OK );
+ PostQuitMessage(0);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : force -
+//-----------------------------------------------------------------------------
+void CSys::UpdateStatus( int force )
+{
+ static double tLast = 0.0;
+ double tCurrent;
+ char szPrompt[256];
+ int n, nMax;
+ char szMap[64];
+ char szHostname[128];
+ float fps;
+
+ if ( !engine )
+ return;
+
+ tCurrent = Sys_FloatTime();
+
+ if ( !force )
+ {
+ if ( ( tCurrent - tLast ) < 0.5f )
+ return;
+ }
+
+ tLast = tCurrent;
+
+ engine->UpdateStatus( &fps, &n, &nMax, szMap, sizeof( szMap ) );
+ engine->UpdateHostname( szHostname, sizeof( szHostname ) );
+
+ console.SetTitle( szHostname );
+
+ Q_snprintf( szPrompt, sizeof( szPrompt ), "%.1f fps %2i/%2i on map %16s", (float)fps, n, nMax, szMap);
+
+ console.SetStatusLine(szPrompt);
+ console.UpdateStatus();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *string -
+// Output : void CSys::ConsoleOutput
+//-----------------------------------------------------------------------------
+void CSys::ConsoleOutput (char *string)
+{
+ if ( g_bVGui )
+ {
+ VGUIPrintf( string );
+ }
+ else
+ {
+ console.Print(string);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *fmt -
+// ... -
+//-----------------------------------------------------------------------------
+void CSys::Printf( PRINTF_FORMAT_STRING const char *fmt, ... )
+{
+ // Dump text to debugging console.
+ va_list argptr;
+ char szText[1024];
+
+ va_start (argptr, fmt);
+ Q_vsnprintf (szText, sizeof( szText ), fmt, argptr);
+ va_end (argptr);
+
+ // Get Current text and append it.
+ ConsoleOutput( szText );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : char *
+//-----------------------------------------------------------------------------
+char *CSys::ConsoleInput ( int index, char *buf, int buflen )
+{
+ return console.GetLine( index, buf, buflen );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *szText -
+//-----------------------------------------------------------------------------
+void CSys::WriteStatusText( char *szText )
+{
+ SetConsoleTitle( szText );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CSys::CreateConsoleWindow( void )
+{
+ if ( !AllocConsole () )
+ {
+ return false;
+ }
+
+ InitConProc();
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CSys::DestroyConsoleWindow( void )
+{
+ FreeConsole ();
+
+ // shut down QHOST hooks if necessary
+ DeinitConProc ();
+}
+
+
+//-----------------------------------------------------------------------------
+// Loading modules used by the dedicated server.
+//-----------------------------------------------------------------------------
+bool CSys::LoadModules( CDedicatedAppSystemGroup *pAppSystemGroup )
+{
+ AppSystemInfo_t appSystems[] =
+ {
+ { "engine.dll", CVAR_QUERY_INTERFACE_VERSION }, // NOTE: This one must be first!!
+ { "inputsystem.dll", INPUTSYSTEM_INTERFACE_VERSION },
+ { "materialsystem.dll", MATERIAL_SYSTEM_INTERFACE_VERSION },
+ { "studiorender.dll", STUDIO_RENDER_INTERFACE_VERSION },
+ { "vphysics.dll", VPHYSICS_INTERFACE_VERSION },
+ { "datacache.dll", DATACACHE_INTERFACE_VERSION },
+ { "datacache.dll", MDLCACHE_INTERFACE_VERSION },
+ { "datacache.dll", STUDIO_DATA_CACHE_INTERFACE_VERSION },
+ { "vgui2.dll", VGUI_IVGUI_INTERFACE_VERSION },
+ { "engine.dll", VENGINE_HLDS_API_VERSION },
+ { "dedicated.dll", QUEUEDLOADER_INTERFACE_VERSION },
+ { "", "" } // Required to terminate the list
+ };
+
+ if ( !pAppSystemGroup->AddSystems( appSystems ) )
+ return false;
+
+ engine = (IDedicatedServerAPI *)pAppSystemGroup->FindSystem( VENGINE_HLDS_API_VERSION );
+
+ IMaterialSystem* pMaterialSystem = (IMaterialSystem*)pAppSystemGroup->FindSystem( MATERIAL_SYSTEM_INTERFACE_VERSION );
+ pMaterialSystem->SetShaderAPI( "shaderapiempty.dll" );
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool NET_Init( void )
+{
+ // Startup winock
+ WORD version = MAKEWORD( 1, 1 );
+ WSADATA wsaData;
+
+ int err = WSAStartup( version, &wsaData );
+ if ( err != 0 )
+ {
+ char msg[ 256 ];
+ Q_snprintf( msg, sizeof( msg ), "Winsock 1.1 unavailable...\n" );
+ sys->Printf( "%s", msg );
+ Plat_DebugString( msg );
+ return false;
+ }
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void NET_Shutdown( void )
+{
+ // Kill winsock
+ WSACleanup();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : hInstance -
+// hPrevInstance -
+// lpszCmdLine -
+// nCmdShow -
+// Output : int PASCAL
+//-----------------------------------------------------------------------------
+int main(int argc, char **argv); // in sys_ded.cpp
+static char *GetBaseDir( const char *pszBuffer )
+{
+ static char basedir[ MAX_PATH ];
+ char szBuffer[ MAX_PATH ];
+ int j;
+ char *pBuffer = NULL;
+
+ V_strcpy_safe( szBuffer, pszBuffer );
+
+ pBuffer = strrchr( szBuffer,'\\' );
+ if ( pBuffer )
+ {
+ *(pBuffer+1) = '\0';
+ }
+
+ strcpy( basedir, szBuffer );
+
+ j = strlen( basedir );
+ if (j > 0)
+ {
+ if ( ( basedir[ j-1 ] == '\\' ) ||
+ ( basedir[ j-1 ] == '/' ) )
+ {
+ basedir[ j-1 ] = 0;
+ }
+ }
+
+ return basedir;
+}
+
+void MiniDumpFunction( unsigned int nExceptionCode, EXCEPTION_POINTERS *pException )
+{
+ SteamAPI_WriteMiniDump( nExceptionCode, pException, 0 );
+}
+
+extern "C" __declspec(dllexport) int DedicatedMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
+{
+ SetAppInstance( hInstance );
+
+ // Check that we are running on Win32
+ OSVERSIONINFO vinfo;
+ vinfo.dwOSVersionInfoSize = sizeof(vinfo);
+
+ if ( !GetVersionEx ( &vinfo ) )
+ return -1;
+
+ if ( vinfo.dwPlatformId == VER_PLATFORM_WIN32s )
+ return -1;
+
+ int argc, iret = -1;
+ LPWSTR * argv= CommandLineToArgvW(GetCommandLineW(),&argc);
+ CommandLine()->CreateCmdLine( VCRHook_GetCommandLine() );
+
+ if ( !Plat_IsInDebugSession() && !CommandLine()->FindParm( "-nominidumps") )
+ {
+ // This warning only applies if you want to catch structured exceptions (crashes)
+ // using C++ exceptions. We do not want to do that so we can build with C++ exceptions
+ // completely disabled, and just suppress this warning.
+ // warning C4535: calling _set_se_translator() requires /EHa
+ #pragma warning( suppress : 4535 )
+ _set_se_translator( MiniDumpFunction );
+
+ try // this try block allows the SE translator to work
+ {
+ iret = main(argc,(char **)argv);
+ }
+ catch( ... )
+ {
+ return -1;
+ }
+ }
+ else
+ {
+ iret = main(argc,(char **)argv);
+ }
+
+ GlobalFree( argv );
+ return iret;
+}
+
diff --git a/dedicated/vgui/CreateMultiplayerGameServerPage.cpp b/dedicated/vgui/CreateMultiplayerGameServerPage.cpp
new file mode 100644
index 0000000..d4e6308
--- /dev/null
+++ b/dedicated/vgui/CreateMultiplayerGameServerPage.cpp
@@ -0,0 +1,872 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifdef _WIN32
+#include <stdio.h>
+
+#include "CreateMultiplayerGameServerPage.h"
+#include <Winsock2.h>
+
+using namespace vgui;
+
+#include <vgui_controls/Controls.h>
+#include <KeyValues.h>
+#include <vgui_controls/ListPanel.h>
+#include <vgui_controls/ComboBox.h>
+#include <vgui_controls/MessageBox.h>
+#include <vgui_controls/CheckButton.h>
+#include <vgui/IVGui.h>
+
+#include <OfflineMode.h>
+
+#include "filesystem.h"
+#include "mainpanel.h"
+#include "tier0/icommandline.h"
+#include "netapi.h"
+// for SRC
+#include <vstdlib/random.h>
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+
+//#define ALLOW_OLD_ENGINE_GAMES
+
+
+bool IsEp1EraAppID( int iSteamAppId )
+{
+ return iSteamAppId == 211 || iSteamAppId == 215;
+}
+
+// Checks the liblist.gam file for a "fallback_dir"
+const char *GetLiblistFallbackDir( const char *pszGameDir )
+{
+ static char szFallback[512];
+ char szTemp[512];
+
+ szFallback[0] = 0;
+
+ V_sprintf_safe( szTemp, "%s\\liblist.gam", pszGameDir );
+ g_pFullFileSystem->GetLocalCopy( szTemp );
+
+ FileHandle_t hFile = g_pFullFileSystem->Open( szTemp, "rt" );
+
+ if ( hFile )
+ {
+ char szLine[512];
+
+ // look for the line starting with 'fallback_dir'
+ while ( !g_pFullFileSystem->EndOfFile( hFile ) )
+ {
+ // get a single line
+ szLine[0] = 0;
+ g_pFullFileSystem->ReadLine( szLine, sizeof(szLine) - 1, hFile );
+ szLine[sizeof(szLine) - 1] = 0;
+
+ if ( !strnicmp( szLine, "fallback_dir", 12 ) )
+ {
+ // we got the line, get the value between the quotes
+ char *start = strchr( szLine, '\"' );
+
+ if ( !start )
+ {
+ break;
+ }
+
+ char *end = strchr( start + 1, '\"' );
+ if ( !end )
+ {
+ break;
+ }
+
+ // copy out between start and end
+ int bytesToCopy = end - start - 1;
+ if ( bytesToCopy >= sizeof(szFallback) - 1 )
+ {
+ bytesToCopy = sizeof(szFallback) - 1;
+ break;
+ }
+
+ if ( bytesToCopy > 0 )
+ {
+ strncpy( szFallback, start + 1, bytesToCopy );
+ szFallback[bytesToCopy] = 0;
+ }
+ }
+ }
+
+ g_pFullFileSystem->Close( hFile );
+ }
+
+ return szFallback;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CCreateMultiplayerGameServerPage::CCreateMultiplayerGameServerPage(vgui::Panel *parent, const char *name) : Frame(parent, name)
+{
+ memset(&m_iServer,0x0,sizeof(serveritem_t));
+
+ m_MainPanel = parent; // as we are a popup frame we need to store this seperately
+ m_pSavedData = NULL;
+ m_pGameInfo = NULL;
+
+ SetMinimumSize(310, 350);
+ SetSize(310, 350);
+ SetSizeable(false);
+
+
+ SetTitle("#Start_Server_Title",true);
+
+ m_pMapList = new ComboBox(this, "MapList",10,false);
+ m_pMapList->SetEnabled(false); // a mod needs to be chosen first to populate the map list
+ m_pMapList->SetEditable(false);
+
+ m_pNetworkCombo = new ComboBox(this, "NetworkCombo",10,false);
+ int defaultItem = m_pNetworkCombo->AddItem("#Internet", NULL);
+ int lanItem = m_pNetworkCombo->AddItem("#LAN", NULL);
+ if ( CommandLine()->CheckParm("-steam") && IsSteamInOfflineMode() )
+ {
+ defaultItem = lanItem;
+ }
+ m_pNetworkCombo->ActivateItem(defaultItem);
+
+ m_pNumPlayers = new ComboBox(this, "NumPlayers",10,false);
+ char num[3];
+ int i;
+ for( i = 1 ; i <= MAX_PLAYERS ; i++ )
+ {
+ V_sprintf_safe(num, "%i", i);
+ m_pNumPlayers->AddItem(num, NULL);
+ }
+ m_pNumPlayers->ActivateItemByRow(23); // 24 players by default
+
+ m_pGameCombo = new ComboBox(this,"MODCombo", 10, false);
+
+ m_pStartServerButton = new Button(this, "StartButton", "#Start_Server_Button");
+ m_pStartServerButton->SetCommand("start");
+
+ m_pCancelButton = new Button(this, "CancelButton", "#Start_Server_Cancel");
+ m_pCancelButton->SetCommand("cancel");
+
+ m_pSecureCheck = new CheckButton(this, "SecureCheck", "#Start_Server_Secure");
+ m_pSecureCheck->SetSelected(true);
+
+ LoadControlSettingsAndUserConfig("Admin/CreateMultiplayerGameServerPage.res");
+
+ // load some defaults into the controls
+ SetControlString("ServerNameEdit", "Half-Life dedicated server");
+ V_strcpy_safe(m_szGameName, "Half-Life");
+
+ LoadMODList();
+
+ m_pGameCombo->RequestFocus();
+
+ // get default port from commandline if possible
+ m_iPort = 27015;
+ const char *portVal = NULL;
+ if (CommandLine()->CheckParm("-port", &portVal) && portVal && atoi(portVal) > 0)
+ {
+ m_iPort = atoi(portVal);
+ }
+ SetControlInt("PortEdit", m_iPort);
+
+ LoadConfig();
+
+ m_szMapName[0] = 0;
+ m_szHostName[0] = 0;
+ m_szPassword[0] = 0;
+ m_iMaxPlayers = 24;
+
+ if ( CommandLine()->CheckParm("-steam") && IsSteamInOfflineMode() )
+ {
+ m_pNetworkCombo->SetEnabled( false );
+ }
+
+ SetVisible(true);
+
+ if ( CommandLine()->CheckParm("-steam") && IsSteamInOfflineMode() )
+ {
+ MessageBox *box = new vgui::MessageBox( "#Start_Server_Offline_Title", "#Start_Server_Offline_Warning" );
+ box->DoModal();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+CCreateMultiplayerGameServerPage::~CCreateMultiplayerGameServerPage()
+{
+ SaveConfig();
+ if (m_pSavedData)
+ {
+ m_pSavedData->deleteThis();
+ m_pSavedData = NULL;
+ }
+ if ( m_pGameInfo )
+ {
+ m_pGameInfo->deleteThis();
+ m_pGameInfo = NULL;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CCreateMultiplayerGameServerPage::OnResetData()
+{
+ m_pGameCombo->SetEnabled(true);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: loads settings from a config file
+//-----------------------------------------------------------------------------
+void CCreateMultiplayerGameServerPage::LoadConfig()
+{
+ // free any old filters
+ if (m_pSavedData)
+ {
+ m_pSavedData->deleteThis();
+ }
+ m_pSavedData = new KeyValues ("Server");
+
+ if (!m_pSavedData->LoadFromFile(g_pFullFileSystem, "Server.vdf", "CONFIG"))
+ {
+ // file not successfully loaded
+ }
+ else
+ {
+ if (m_pSavedData->FindKey("RconPassword", false))
+ {
+ const char *password = m_pSavedData->GetString("RconPassword", "");
+ if (strlen(password)>0)
+ {
+ SetControlString("RCONPasswordEdit", password);
+ }
+ }
+ if (m_pSavedData->FindKey("MaxPlayers", false))
+ {
+ int maxPlayers = m_pSavedData->GetInt("MaxPlayers", -1);
+ if (maxPlayers > 0 && maxPlayers <= 32)
+ {
+ m_pNumPlayers->ActivateItemByRow(maxPlayers - 1);
+ }
+ }
+ if (m_pSavedData->FindKey("MOD", false))
+ {
+ const char *mod = m_pSavedData->GetString("MOD", "");
+ if (strlen(mod) > 0)
+ {
+ // look for the item in the dropdown
+ m_szMod[0] = 0;
+ for (int i = 0; i < m_pGameCombo->GetItemCount(); i++)
+ {
+ if (!m_pGameCombo->IsItemIDValid(i))
+ continue;
+
+ if (!stricmp(m_pGameCombo->GetItemUserData(i)->GetString("gamedir"), mod))
+ {
+ // item found in list, activate
+ m_pGameCombo->ActivateItem(i);
+ break;
+ }
+ }
+ }
+ }
+ if (m_pSavedData->FindKey("Map", false))
+ {
+ const char *map = m_pSavedData->GetString("Map", "");
+ if (strlen(map) > 0)
+ {
+ SetControlString("MapList", map);
+ }
+ }
+
+ if (m_pSavedData->FindKey("Network", false))
+ {
+ int nwIndex = m_pSavedData->GetInt("Network");
+ if (nwIndex > 0 && nwIndex < 2)
+ {
+ m_pNetworkCombo->ActivateItemByRow(nwIndex);
+ }
+ }
+ if (m_pSavedData->FindKey("Secure", false))
+ {
+ int secure = m_pSavedData->GetInt("Secure");
+ m_pSecureCheck->SetSelected(secure);
+ }
+ if (m_pSavedData->FindKey("ServerName", false))
+ {
+ const char *serverName = m_pSavedData->GetString("ServerName","");
+ if (strlen(serverName) > 0)
+ {
+ SetControlString("ServerNameEdit", serverName);
+ }
+ }
+ m_iPort = m_pSavedData->GetInt("Port", m_iPort);
+ SetControlInt("PortEdit", m_iPort);
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: data accessor
+//-----------------------------------------------------------------------------
+void CCreateMultiplayerGameServerPage::SetConfig(const char *serverName, const char *rconPassword, int maxPlayers, const char *mod, const char *map, int network, int secure, int port)
+{
+ m_pSavedData->SetInt("MaxPlayers", maxPlayers);
+ m_pSavedData->SetString("RconPassword", rconPassword);
+ m_pSavedData->SetString("ServerName", serverName);
+ m_pSavedData->SetString("MOD", mod);
+ m_pSavedData->SetString("Map", map);
+ m_pSavedData->SetInt("Secure", secure);
+ m_pSavedData->SetInt("Network", network);
+ m_pSavedData->SetInt("Port", port);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CCreateMultiplayerGameServerPage::SaveConfig()
+{
+ m_pSavedData->SaveToFile(g_pFullFileSystem, "Server.vdf", "CONFIG");
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: returns true if one of the characters in the string is not a valid alpha numeric character
+//-----------------------------------------------------------------------------
+bool CCreateMultiplayerGameServerPage::BadRconChars(const char *pass)
+{
+ bool bad = false;
+
+ for(unsigned int i=0;i<strlen(pass);i++)
+ {
+ bad |= !( V_isalnum(pass[i]) ? true : false );
+ }
+ return bad;
+}
+
+const char *ToString( int val )
+{
+ static char text[256];
+ Q_snprintf( text, sizeof(text), "%i", val );
+ return text;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: called to get the info from the dialog
+//-----------------------------------------------------------------------------
+void CCreateMultiplayerGameServerPage::OnCommand(const char *cmd)
+{
+ char cvars[1024];
+ int secure = GetControlInt("SecureCheck", 1);
+ m_pNumPlayers->GetText(cvars, 1024);
+ m_iMaxPlayers = atoi(cvars);
+ V_strcpy_safe(m_szHostName, GetControlString("ServerNameEdit", ""));
+ V_strcpy_safe(m_szPassword, GetControlString("RCONPasswordEdit", ""));
+ m_iPort = GetControlInt("PortEdit", 27015);
+
+ if (!stricmp(cmd, "cancel"))
+ {
+ vgui::ivgui()->PostMessage( m_MainPanel->GetVPanel(), new KeyValues("Quit"), NULL);
+ Close();
+ }
+ else if (!stricmp(cmd, "start"))
+ {
+ // save our current settings
+ SetConfig(m_szHostName, m_szPassword, m_iMaxPlayers, m_szMod, GetMapName(), m_pNetworkCombo->GetActiveItem() != 0, secure, m_iPort);
+ SaveConfig();
+
+ // create the command to execute
+ bool isLanOnly = (m_pNetworkCombo->GetActiveItem() != 0);
+ CommandLine()->AppendParm("-game", m_szMod);
+ CommandLine()->AppendParm("-maxplayers", ToString(m_iMaxPlayers));
+ CommandLine()->AppendParm("+sv_lan", ToString(isLanOnly));
+ CommandLine()->AppendParm("+map", GetMapName());
+ CommandLine()->AppendParm("-port", ToString(m_iPort));
+ if (!secure) // if they don't want it secure...
+ {
+ CommandLine()->AppendParm("-insecure", "");
+ }
+
+
+ // V_strcpy_safe(m_szPassword, GetControlString("RCONPasswordEdit", ""));
+ if (strlen(m_szPassword) < 3 || BadRconChars(m_szPassword))
+ {
+ MessageBox *dlg = new MessageBox("#Start_Server_RCON_Error_Title", "#Start_Server_RCON_Error");
+ dlg->DoModal();
+ }
+ else
+ {
+ V_sprintf_safe(cvars, "rcon_password \"%s\"\nsetmaster enable\nhostname \"%s\"\n", m_szPassword, m_szHostName);
+
+ m_pGameCombo->SetEnabled(false);
+ m_pNumPlayers->SetEnabled(false);
+
+ netadr_t local;
+ net->GetLocalIP(&local);
+ local.port = ::htons(m_iPort);
+
+ for (int i = 0; i < 4; i++)
+ {
+ m_iServer.ip[i] = local.ip[i];
+ }
+ m_iServer.port = (local.port & 0xff) << 8 | (local.port & 0xff00) >> 8;;
+
+ V_strcpy_safe(m_iServer.name, m_szHostName);
+ V_strcpy_safe(m_iServer.map, GetMapName());
+ V_strcpy_safe(m_iServer.gameDir, m_szMod);
+ m_iServer.maxPlayers = m_iMaxPlayers;
+
+ SetVisible(false);
+
+ KeyValues *gameData = m_pGameCombo->GetActiveItemUserData();
+
+// // mount the caches
+// if (CommandLine()->CheckParm("-steam"))
+// {
+// if (gameData)
+// {
+// KeyValues *pFileSystem = gameData->FindKey( "FileSystem" );
+// if ( !pFileSystem )
+// Error( "Game %s missing FileSystem key.", gameData->GetString( "game" ) );
+//
+// // Mods just specify their app ID (CS, HL2, HL2MP, etc), and it mounts all the necessary caches.
+// int iAppId = pFileSystem->GetInt( "SteamAppId" );
+// if ( iAppId )
+// {
+// CUtlVector<unsigned int> depList;
+// MountDependencies( iAppId, depList );
+//
+// char gameinfoFilename[MAX_PATH];
+// Q_snprintf( gameinfoFilename, sizeof( gameinfoFilename ), "%s\\gameinfo.txt", m_iServer.gameDir );
+// g_pFullFileSystem->GetLocalCopy( gameinfoFilename );
+// }
+// }
+// }
+
+ // Launch the old dedicated server if necessary.
+ if ( LaunchOldDedicatedServer( gameData ) )
+ {
+ vgui::ivgui()->PostMessage( m_MainPanel->GetVPanel(), new KeyValues("Quit"), NULL);
+ Close();
+ }
+
+ CMainPanel::GetInstance()->StartServer(cvars);
+ }
+ }
+}
+
+bool CCreateMultiplayerGameServerPage::LaunchOldDedicatedServer( KeyValues *pGameInfo )
+{
+#if defined( ALLOW_OLD_ENGINE_GAMES )
+ // Validate the gameinfo.txt format..
+ KeyValues *pSub = pGameInfo->FindKey( "FileSystem" );
+ if ( pSub )
+ {
+ int iSteamAppId = pSub->GetInt( "SteamAppId", -1 );
+ if ( iSteamAppId != -1 )
+ {
+ if ( IsEp1EraAppID( iSteamAppId ) )
+ {
+ // Old-skool app. Launch the old dedicated server.
+ char steamDir[MAX_PATH];
+ if ( !system()->GetRegistryString( "HKEY_CURRENT_USER\\Software\\Valve\\Steam\\SteamPath", steamDir, sizeof( steamDir ) ) )
+ Error( "LaunchOldDedicatedServer: can't get SteamPath." );
+
+ V_FixSlashes( steamDir );
+ V_AppendSlash( steamDir, sizeof( steamDir ) );
+
+ char commandLine[1024 * 4];
+ commandLine[0] = 0;
+ V_snprintf( commandLine, sizeof( commandLine ), "\"%ssteam.exe\" -applaunch 205 -HiddenLaunch", steamDir );
+
+ // Feed it all the parameters chosen in the UI so it doesn't redisplay the UI.
+ STARTUPINFO si;
+ memset( &si, 0, sizeof( si ) );
+ si.cb = sizeof( si );
+
+ PROCESS_INFORMATION pi;
+ if ( !CreateProcess( NULL, commandLine, NULL, NULL, false, 0, NULL, steamDir, &si, &pi ) )
+ {
+ Error( "LaunchOldDedicatedServer: Unable to launch old srcds." );
+ }
+
+ return true;
+ }
+ }
+ }
+#endif
+
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: loads the list of available maps into the map list
+//-----------------------------------------------------------------------------
+void CCreateMultiplayerGameServerPage::LoadMODList()
+{
+ m_pGameCombo->DeleteAllItems();
+
+ // add steam games
+ if (CommandLine()->CheckParm("-steam"))
+ {
+ const char *pSteamGamesFilename = "hlds_steamgames.vdf";
+
+ KeyValues *gamesFile = new KeyValues( pSteamGamesFilename );
+
+ if ( gamesFile->LoadFromFile( g_pFullFileSystem, pSteamGamesFilename, NULL ) )
+ {
+ for ( KeyValues *kv = gamesFile->GetFirstSubKey(); kv != NULL; kv = kv->GetNextKey() )
+ {
+ const char *pGameDir = kv->GetString( "gamedir", NULL );
+ if ( !pGameDir )
+ Error( "Mod %s in %s missing 'gamedir'.", kv->GetName(), pSteamGamesFilename );
+
+ AddMod( pGameDir, pSteamGamesFilename, kv );
+ }
+ }
+ gamesFile->deleteThis();
+ gamesFile = NULL;
+ }
+
+
+ // For backward compatibility, check inside the dedicated server's own directory for mods.
+ LoadModListInDirectory( "." );
+
+ // Also, check in SourceMods.
+ char sourceModsDir[MAX_PATH];
+ if ( system()->GetRegistryString( "HKEY_CURRENT_USER\\Software\\Valve\\Steam\\SourceModInstallPath", sourceModsDir, sizeof( sourceModsDir ) ) )
+ LoadModListInDirectory( sourceModsDir );
+
+ m_pGameCombo->ActivateItem(0);
+}
+
+
+void CCreateMultiplayerGameServerPage::LoadModListInDirectory( const char *pDirectoryName )
+{
+ char searchString[MAX_PATH*2];
+ V_strcpy_safe( searchString, pDirectoryName );
+ Q_AppendSlash( searchString, sizeof( searchString ) );
+ Q_strncat( searchString, "*.*", sizeof( searchString ), COPY_ALL_CHARACTERS );
+
+ FileFindHandle_t findHandle = NULL;
+ const char *filename = g_pFullFileSystem->FindFirst( searchString, &findHandle );
+ while ( filename )
+ {
+ // add to the mod list
+ if (filename[0] != '.' && g_pFullFileSystem->FindIsDirectory(findHandle))
+ {
+ char fullFilename[MAX_PATH];
+ if ( Q_stricmp( pDirectoryName, "." ) == 0 )
+ {
+ // If we don't do this, then the games in hlds_steamgames.vdf will get listed twice
+ // since their gamedir is listed as "cstrike" and "hl2mp", not ".\cstrike" or ".\hl2mp".
+ V_strcpy_safe( fullFilename, filename );
+ }
+ else
+ {
+ V_strcpy_safe( fullFilename, pDirectoryName );
+ Q_AppendSlash( fullFilename, sizeof( fullFilename ) );
+ Q_strncat( fullFilename, filename, sizeof( fullFilename ), COPY_ALL_CHARACTERS );
+ }
+
+ LoadPossibleMod( fullFilename );
+ }
+
+ filename = g_pFullFileSystem->FindNext(findHandle);
+ }
+ g_pFullFileSystem->FindClose(findHandle);
+}
+
+
+void CCreateMultiplayerGameServerPage::LoadPossibleMod( const char *pGameDirName )
+{
+ char gameInfoFilename[1024];
+ Q_snprintf(gameInfoFilename, sizeof(gameInfoFilename) - 1, "%s\\gameinfo.txt", pGameDirName);
+ if ( !g_pFullFileSystem->FileExists(gameInfoFilename) )
+ return;
+
+ // don't want to add single player games to the list
+ KeyValues *pGameInfo = new KeyValues( "GameInfo" );
+ bool loadedFile = pGameInfo->LoadFromFile( g_pFullFileSystem, gameInfoFilename );
+ if ( !loadedFile )
+ return;
+
+ AddMod( pGameDirName, gameInfoFilename, pGameInfo );
+
+ pGameInfo->deleteThis();
+ pGameInfo = NULL;
+}
+
+
+void CCreateMultiplayerGameServerPage::AddMod( const char *pGameDirName, const char *pGameInfoFilename, KeyValues *pGameInfo )
+{
+ // Don't re-add something with the same gamedir name (this can happen with games listed in hlds_steamgames.vdf,
+ // since after the first time a game is run, it'll also have a gameinfo.txt that will be found).
+ for ( int i=0; i < m_pGameCombo->GetItemCount(); i++ )
+ {
+ if ( !m_pGameCombo->IsItemIDValid(i) )
+ continue;
+
+ if ( Q_stricmp( m_pGameCombo->GetItemUserData(i)->GetString("gamedir"), pGameDirName ) == 0 )
+ return;
+ }
+
+ // If this mod supports multiplayer, then we'll add it.
+ const char *gameType = pGameInfo->GetString( "type", "singleplayer_only" );
+ if ( Q_stricmp(gameType, "singleplayer_only") != 0 )
+ {
+ // Validate the gameinfo.txt format..
+ KeyValues *pSub = pGameInfo->FindKey( "FileSystem" );
+ if ( !pSub )
+ Error( "%s missing FileSystem key.", pGameInfoFilename );
+
+ int iSteamAppId = pSub->GetInt( "SteamAppId", -1 );
+ if ( iSteamAppId == -1 )
+ Error( "%s missing FileSystem\\SteamAppId key.", pGameInfoFilename );
+
+#if !defined( ALLOW_OLD_ENGINE_GAMES )
+ // If we're not supporting old games in here and its appid is old, forget about it.
+ if ( IsEp1EraAppID( iSteamAppId ) )
+ return;
+#endif
+
+ const char *gameName = pGameInfo->GetString( "game", NULL );
+ if ( !gameName )
+ Error( "%s missing 'game' key.", pGameInfoFilename );
+
+
+ // add to drop-down combo and mod list
+ KeyValues *kv = pGameInfo->MakeCopy();
+ kv->SetString( "gamedir", pGameDirName );
+
+ m_pGameCombo->AddItem( gameName, kv );
+
+ kv->deleteThis();
+ kv = NULL;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: loads the list of available maps for the given path into the map list
+// Returns: number of maps loaded into the list
+//-----------------------------------------------------------------------------
+int CCreateMultiplayerGameServerPage::LoadMaps( const char *pszMod )
+{
+ // iterate the filesystem getting the list of all the files
+ // UNDONE: steam wants this done in a special way, need to support that
+ FileFindHandle_t findHandle = NULL;
+ char szSearch[256];
+ sprintf( szSearch, "%s/maps/*.bsp", pszMod );
+
+ int iMapsFound = 0;
+
+ const char *pszFilename = g_pFullFileSystem->FindFirst( szSearch, &findHandle );
+
+ KeyValues *hiddenMaps = NULL;
+ if ( m_pGameInfo )
+ {
+ hiddenMaps = m_pGameInfo->FindKey( "hidden_maps" );
+ }
+
+ while ( pszFilename )
+ {
+ // remove the text 'maps/' and '.bsp' from the file name to get the map name
+ char mapname[256];
+ const char *str = strstr( pszFilename, "maps" );
+ if ( str )
+ {
+ V_strcpy_safe( mapname, str + 5 ); // maps + \\ = 5
+ }
+ else
+ {
+ V_strcpy_safe( mapname, pszFilename );
+ }
+
+ char *ext = strstr( mapname, ".bsp" );
+ if ( ext )
+ {
+ *ext = 0;
+ }
+
+ //!! hack: strip out single player HL maps
+ // this needs to be specified in a seperate file
+ if ( ( mapname[0] == 'c' || mapname[0] == 't' ) && mapname[2] == 'a' && mapname[1] >= '0' && mapname[1] <= '5' )
+ {
+ goto nextFile;
+ }
+
+ // strip out maps that shouldn't be displayed
+ if ( hiddenMaps )
+ {
+ if ( hiddenMaps->GetInt( mapname, 0 ) )
+ {
+ goto nextFile;
+ }
+ }
+
+ iMapsFound++;
+
+ // add to the map list
+ m_pMapList->AddItem( mapname, NULL );
+
+ // get the next file
+ nextFile:
+ pszFilename = g_pFullFileSystem->FindNext( findHandle );
+ }
+
+ g_pFullFileSystem->FindClose( findHandle );
+
+ return iMapsFound;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: loads the list of available maps into the map list
+//-----------------------------------------------------------------------------
+void CCreateMultiplayerGameServerPage::LoadMapList()
+{
+ int iMapsFound = 0;
+
+ // clear the current list (if any)
+ m_pMapList->DeleteAllItems();
+
+ Assert( strlen(m_szMod ) > 0);
+ if ( strlen( m_szMod ) < 1)
+ {
+ m_pMapList->SetEnabled( false );
+ return;
+ }
+
+ m_pMapList->SetEnabled( true );
+ m_pStartServerButton->SetEnabled( true );
+
+ if ( CommandLine()->CheckParm( "-steam" ) )
+ {
+ KeyValues *userData = m_pGameCombo->GetActiveItemUserData();
+ if ( userData && userData->GetString( "DedicatedServerStartMap", NULL ) )
+ {
+ // set only
+ m_pMapList->AddItem( userData->GetString( "DedicatedServerStartMap" ), NULL );
+ m_pMapList->ActivateItemByRow( 0 );
+ m_pMapList->SetEnabled( false );
+ return;
+ }
+ }
+
+ // Load the maps for the GameDir
+ iMapsFound += LoadMaps( m_szMod );
+
+ // If we're using a "fallback_dir" in liblist.gam then include those maps...
+ const char *pszFallback = GetLiblistFallbackDir( m_szMod );
+ if ( pszFallback[0] )
+ {
+ iMapsFound += LoadMaps( pszFallback );
+ }
+
+ if ( iMapsFound < 1 )
+ {
+ m_pMapList->SetEnabled( false );
+ }
+
+ // set the first item to be selected
+ m_pMapList->ActivateItemByRow( 0 );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: returns the name of the map selected from the map combo
+//-----------------------------------------------------------------------------
+const char *CCreateMultiplayerGameServerPage::GetMapName()
+{
+ m_pMapList->GetText(m_szMapName, DATA_STR_LENGTH);
+ return m_szMapName;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: data accessor
+//-----------------------------------------------------------------------------
+const char *CCreateMultiplayerGameServerPage::GetRconPassword()
+{
+ return m_szPassword;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: updates "s" with the details of the chosen server to run
+//-----------------------------------------------------------------------------
+void CCreateMultiplayerGameServerPage::GetServer(serveritem_t &s)
+{
+ s=m_iServer;
+ V_strcpy_safe(s.name,m_iServer.name);
+ V_strcpy_safe(s.rconPassword,m_iServer.rconPassword);
+ memcpy(s.ip,m_iServer.ip,sizeof(m_iServer.ip));
+ memcpy(s.pings,m_iServer.pings,3*sizeof(int));
+ V_strcpy_safe(s.gameDir,m_iServer.gameDir);
+ V_strcpy_safe(s.map,m_iServer.map);
+ V_strcpy_safe(s.gameDescription,m_iServer.gameDescription);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Handles changes to combo boxes
+//-----------------------------------------------------------------------------
+void CCreateMultiplayerGameServerPage::OnTextChanged(Panel *panel)
+{
+ if (panel == m_pGameCombo)
+ {
+ // see if we should update the game name
+ bool updateHostname = false;
+ char hostname[256];
+ GetControlString("ServerNameEdit", m_szHostName, sizeof(m_szHostName));
+ V_sprintf_safe(hostname, "%s dedicated server", m_szGameName);
+ if (!stricmp(m_szHostName, hostname))
+ {
+ updateHostname = true;
+ }
+
+ // update the game name
+ m_pGameCombo->GetText( m_szGameName, sizeof(m_szGameName) );
+
+
+ // Copy the gamedir into m_szMod.
+ KeyValues *gameData = m_pGameCombo->GetActiveItemUserData();
+ if ( !gameData )
+ Error( "Missing gameData for active item." );
+
+ const char *pGameDir = gameData->GetString( "gamedir", NULL );
+ if ( !pGameDir )
+ Error( "Game %s missing 'gamedir' key.", m_szGameName );
+
+ V_strcpy_safe( m_szMod, pGameDir );
+
+
+ // re-load the GameInfo KeyValues
+ if ( m_pGameInfo )
+ {
+ m_pGameInfo->deleteThis();
+ }
+ char liblist[1024];
+ Q_snprintf(liblist, sizeof(liblist) - 1, "%s\\gameinfo.txt", m_szMod);
+ m_pGameInfo = new KeyValues( "GameInfo" );
+ m_pGameInfo->LoadFromFile( g_pFullFileSystem, liblist );
+
+ // redo the hostname with the new game name
+ if (updateHostname)
+ {
+ V_sprintf_safe(hostname, "%s dedicated server", m_szGameName);
+ SetControlString("ServerNameEdit", hostname);
+ }
+
+ // reload the list of maps we display
+ LoadMapList();
+ }
+}
+
+#endif // _WIN32
+
diff --git a/dedicated/vgui/CreateMultiplayerGameServerPage.h b/dedicated/vgui/CreateMultiplayerGameServerPage.h
new file mode 100644
index 0000000..6cabef4
--- /dev/null
+++ b/dedicated/vgui/CreateMultiplayerGameServerPage.h
@@ -0,0 +1,126 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef CREATEMULTIPLAYERGAMESERVERPAGE_H
+#define CREATEMULTIPLAYERGAMESERVERPAGE_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <vgui_controls/Frame.h>
+#include <vgui_controls/Button.h>
+#include <vgui_controls/ComboBox.h>
+
+//-----------------------------------------------------------------------------
+// Purpose: Data describing a single server
+//-----------------------------------------------------------------------------
+struct serveritem_t
+{
+ serveritem_t()
+ {
+ pings[0] = 0;
+ pings[1] = 0;
+ pings[2] = 0;
+ }
+
+ unsigned char ip[4];
+ int port;
+ int received;
+ float time;
+ int ping; // current ping time, derived from pings[]
+ int pings[3]; // last 3 ping times
+ bool hadSuccessfulResponse; // server has responded successfully in the past
+ bool doNotRefresh; // server is marked as not responding and should no longer be refreshed
+ char gameDir[32]; // current game directory
+ char map[32]; // current map
+ char gameDescription[64]; // game description
+ char name[64]; // server name
+ int players;
+ int maxPlayers;
+ int botPlayers;
+ bool proxy;
+ bool password;
+ bool secure;
+ bool loadedFromFile; // true if this entry was loaded from file rather than comming from the master
+ unsigned int serverID;
+ int listEntryID;
+ char rconPassword[64]; // the rcon password for this server
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: server options page of the create game server dialog
+//-----------------------------------------------------------------------------
+class CCreateMultiplayerGameServerPage : public vgui::Frame
+{
+ DECLARE_CLASS_SIMPLE( CCreateMultiplayerGameServerPage, vgui::Frame );
+public:
+ CCreateMultiplayerGameServerPage(vgui::Panel *parent, const char *name);
+ ~CCreateMultiplayerGameServerPage();
+
+ // returns currently entered information about the server
+ int GetMaxPlayers() { return m_iMaxPlayers; }
+ const char *GetPassword() { return m_szPassword; }
+ const char *GetHostName() { return m_szHostName; }
+ const char *GetMapName();
+ const char *GetModName() { return m_szMod; }
+ const char *GetGameName() { return m_szGameName; }
+ void LoadMapList();
+ int LoadMaps( const char *pszMod );
+
+ virtual void OnCommand(const char *cmd);
+
+ virtual void OnResetData();
+
+ void GetServer(serveritem_t &s);
+ const char *GetRconPassword();
+
+private:
+ enum { MAX_PLAYERS = 32 };
+ enum { DATA_STR_LENGTH = 64 };
+
+ void LoadConfig();
+ void SaveConfig();
+ void SetConfig(const char *serverName, const char *rconPassword, int maxPlayers, const char *map, const char *mod, int network, int secure, int port);
+
+ bool LaunchOldDedicatedServer( KeyValues *pGameInfo );
+
+ //void OnCommand(const char *text);
+ void LoadMODList();
+ void LoadModListInDirectory( const char *pDirectoryName );
+ void LoadPossibleMod( const char *pGameDirName );
+ void AddMod( const char *pGameDirName, const char *pGameInfoFilename, KeyValues *pGameInfo );
+
+ bool BadRconChars(const char *pass);
+
+ vgui::ComboBox *m_pGameCombo;
+ vgui::ComboBox *m_pMapList;
+ vgui::ComboBox *m_pNumPlayers;
+ vgui::ComboBox *m_pNetworkCombo;
+ vgui::Button *m_pStartServerButton;
+ vgui::Button *m_pCancelButton;
+ vgui::CheckButton *m_pSecureCheck;
+
+ MESSAGE_FUNC_PTR( OnTextChanged, "TextChanged", panel );
+
+ serveritem_t m_iServer;
+
+ char m_szHostName[DATA_STR_LENGTH];
+ char m_szPassword[DATA_STR_LENGTH];
+ char m_szMapName[DATA_STR_LENGTH];
+ char m_szMod[DATA_STR_LENGTH];
+ char m_szGameName[DATA_STR_LENGTH];
+ char m_szExtra[DATA_STR_LENGTH*2];
+ int m_iMaxPlayers;
+ int m_iPort;
+
+ vgui::Panel *m_MainPanel;
+ KeyValues *m_pSavedData; // data to save away
+ KeyValues *m_pGameInfo;
+};
+
+
+#endif // CREATEMULTIPLAYERGAMESERVERPAGE_H
diff --git a/dedicated/vgui/MainPanel.cpp b/dedicated/vgui/MainPanel.cpp
new file mode 100644
index 0000000..f7fc51b
--- /dev/null
+++ b/dedicated/vgui/MainPanel.cpp
@@ -0,0 +1,274 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $Workfile: $
+// $Date: $
+//
+//-----------------------------------------------------------------------------
+// $Log: $
+//
+// $NoKeywords: $
+//=============================================================================//
+#ifdef _WIN32
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include <windows.h>
+// base vgui interfaces
+#include <vgui/vgui.h>
+#include <vgui_controls/Panel.h>
+#include <vgui/IVGui.h>
+#include <vgui/ISurface.h>
+#include <vgui/Cursor.h>
+#include <vgui_controls/ProgressBox.h>
+
+#include "filesystem.h"
+#include "IAdminServer.h"
+
+#include "MainPanel.h"
+#include <imanageserver.h>
+#include "ivguimodule.h"
+#include <vgui/IVGui.h>
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+using namespace vgui;
+
+static CMainPanel *s_InternetDlg = NULL;
+CSysModule *g_hAdminServerModule = NULL;
+extern IAdminServer *g_pAdminServer;
+char *gpszCvars = NULL;
+
+
+void Sys_Sleep_Old( int msec );
+
+extern BOOL gbAppHasBeenTerminated; // used to signal the server thread
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CMainPanel::CMainPanel( ) : Panel(NULL, "CMainPanel")
+{
+ SetPaintBackgroundEnabled( false );
+ SetFgColor( Color( 0,0,0,0 ) );
+ m_bStarting = false;
+ m_flPreviousSteamProgress = 0.0f;
+ m_pGameServer= NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+CMainPanel::~CMainPanel()
+{
+ if (gpszCvars)
+ {
+ free(gpszCvars);
+ }
+
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Called once to set up
+//-----------------------------------------------------------------------------
+void CMainPanel::Initialize( )
+{
+ s_InternetDlg = this;
+ m_pGameServer = NULL;
+
+ m_bStarted = false;
+ m_bIsInConfig = true;
+ m_bClosing = false;
+ m_pProgressBox = NULL;
+ m_hShutdown = NULL;
+
+ MoveToFront();
+
+ m_pConfigPage = new CCreateMultiplayerGameServerPage(this, "Config");
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMainPanel::Open( void )
+{
+ m_pConfigPage->SetVisible(true);
+ m_pConfigPage->MoveToFront();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMainPanel::OnClose()
+{
+ DoStop();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: returns a pointer to a static instance of this dialog
+//-----------------------------------------------------------------------------
+CMainPanel *CMainPanel::GetInstance()
+{
+ return s_InternetDlg;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Changes to the console page and starts up the actual server
+//-----------------------------------------------------------------------------
+void CMainPanel::StartServer(const char *cvars)
+{
+ surface()->SetCursor(dc_hourglass);
+ m_pConfigPage->GetServer(s1);
+
+ // hide the config page and close it
+ m_pConfigPage->SetVisible(false);
+ m_pConfigPage->Close();
+
+ gpszCvars = strdup(cvars);
+
+ // show the basic progress box immediately
+ m_pProgressBox = new ProgressBox("#Start_Server_Loading_Title", "#Server_UpdatingSteamResources", "Starting dedicated server...");
+ m_pProgressBox->SetCancelButtonVisible(true);
+ m_pProgressBox->ShowWindow();
+
+ // make sure we have all the steam content for this mod
+ char reslist[_MAX_PATH];
+ _snprintf(reslist, sizeof(reslist), "reslists/%s/preload.lst", m_pConfigPage->GetGameName());
+ m_hResourceWaitHandle = g_pFullFileSystem->WaitForResources(reslist);
+ if (!m_hResourceWaitHandle)
+ {
+ Assert( 0 );
+ }
+
+ m_pProgressBox->SetCancelButtonEnabled(false);
+
+ m_hShutdown = CreateEvent( NULL, TRUE, FALSE, NULL );
+ ivgui()->AddTickSignal(GetVPanel());
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: lets us delay the loading of the management screen until the server has started
+//-----------------------------------------------------------------------------
+void CMainPanel::OnTick()
+{
+ if (m_hResourceWaitHandle)
+ {
+ // see if we've been cancelled
+ if (!m_pProgressBox.Get() || !m_pProgressBox->IsVisible())
+ {
+ // cancel out
+ g_pFullFileSystem->CancelWaitForResources(m_hResourceWaitHandle);
+ m_hResourceWaitHandle = NULL;
+ DoStop();
+ return;
+ }
+
+ // update resource waiting
+ bool complete;
+ float progress;
+ if (g_pFullFileSystem->GetWaitForResourcesProgress(m_hResourceWaitHandle, &progress, &complete))
+ {
+ vgui::ivgui()->DPrintf2( "progress %.2f %s\n", progress, complete ? "not complete" : "complete" );
+
+ // don't set the progress if we've jumped straight from 0 to 100% complete
+ if (!(progress == 1.0f && m_flPreviousSteamProgress == 0.0f))
+ {
+ m_pProgressBox->SetProgress(progress);
+ m_flPreviousSteamProgress = progress;
+ }
+ }
+
+ // This is here because without it, the dedicated server will consume a lot of CPU and it will slow Steam down
+ // so much that it'll download at 64k instead of 6M.
+ Sleep( 200 );
+
+ // see if we're done
+ if (complete)
+ {
+ m_hResourceWaitHandle = NULL;
+ m_bStarting = true;
+ m_bIsInConfig = false;
+ // at this stage in the process the user can no longer cancel
+ m_pProgressBox->SetCancelButtonEnabled(false);
+ }
+ }
+
+ if (m_bStarting) // if we are actively launching the app
+ {
+ static int count = 0;
+ if (WAIT_OBJECT_0 == WaitForSingleObject(m_hShutdown, 10) || count > 5000)
+ {
+ if (!m_bStarted)
+ {
+ serveritem_t server;
+ m_pConfigPage->GetServer(server);
+ ManageServerUIHandle_t managePage = g_pAdminServer->OpenManageServerDialog(server.name, server.gameDir);
+ m_pGameServer = g_pAdminServer->GetManageServerInterface(managePage);
+ m_bStarted = true;
+
+ if (m_pProgressBox)
+ {
+ m_pProgressBox->Close();
+ m_pProgressBox = NULL;
+ }
+ }
+ else // must be stopping the server
+ {
+ DoStop();
+ }
+
+ surface()->SetCursor(dc_user);
+ m_bStarting = false;
+ ResetEvent(m_hShutdown);
+ }
+ else
+ {
+ count++;
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: stops VGUI and kills any progress dialog we may have been displaying
+//-----------------------------------------------------------------------------
+void CMainPanel::DoStop()
+{
+ surface()->SetCursor(dc_user);
+
+ m_bStarted = false;
+ m_bClosing = true;
+
+ if (m_pProgressBox)
+ {
+ m_pProgressBox->Close();
+ m_pProgressBox = NULL;
+ }
+
+ ivgui()->Stop();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Pushes text into the console
+//-----------------------------------------------------------------------------
+void CMainPanel::AddConsoleText(const char *msg)
+{
+ if (m_pGameServer)
+ {
+ m_pGameServer->AddToConsole(msg);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Message map
+//-----------------------------------------------------------------------------
+MessageMapItem_t CMainPanel::m_MessageMap[] =
+{
+ MAP_MESSAGE( CMainPanel, "Quit", OnClose ),
+};
+
+IMPLEMENT_PANELMAP(CMainPanel, BaseClass);
+
+#endif // _WIN32
diff --git a/dedicated/vgui/MainPanel.h b/dedicated/vgui/MainPanel.h
new file mode 100644
index 0000000..04f558e
--- /dev/null
+++ b/dedicated/vgui/MainPanel.h
@@ -0,0 +1,89 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $Workfile: $
+// $Date: $
+// $NoKeywords: $
+//===========================================================================//
+#ifndef CMAINPANEL_H
+#define CMAINPANEL_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <vgui_controls/Frame.h>
+#include <vgui_controls/Panel.h>
+#include <vgui_controls/ListPanel.h>
+#include <vgui_controls/PHandle.h>
+#include "utlvector.h"
+
+//#include <GamePanelInfo.h>
+
+#include "imanageserver.h"
+//#include "gameserver.h"
+#include "CreateMultiplayerGameServerPage.h"
+
+class IAdminServer;
+
+//-----------------------------------------------------------------------------
+// Purpose: Root panel for dedicated server GUI
+//-----------------------------------------------------------------------------
+class CMainPanel : public vgui::Panel
+{
+public:
+ // Construction/destruction
+ CMainPanel( );
+ virtual ~CMainPanel();
+
+ virtual void Initialize( );
+
+ // displays the dialog, moves it into focus, updates if it has to
+ virtual void Open( void );
+
+ // returns a pointer to a static instance of this dialog
+ // valid for use only in sort functions
+ static CMainPanel *GetInstance();
+ virtual void StartServer(const char *cvars);
+
+ void ActivateBuildMode();
+
+ void *GetShutdownHandle() { return m_hShutdown; }
+
+ void AddConsoleText(const char *msg);
+
+ bool Stopping() { return m_bClosing; }
+
+ bool IsInConfig() { return m_bIsInConfig; }
+
+private:
+
+ // called when dialog is shut down
+ virtual void OnClose();
+ virtual void OnTick();
+ void DoStop();
+
+ // GUI elements
+ IManageServer *m_pGameServer;
+
+ // the popup menu
+ vgui::DHANDLE<vgui::ProgressBox> m_pProgressBox;
+ CCreateMultiplayerGameServerPage *m_pConfigPage;
+
+ // Event that lets the thread tell the main window it shutdown
+ void *m_hShutdown;
+
+ bool m_bStarting; // whether the server is currently starting
+ bool m_bStarted; // whether the server has been started or not
+ bool m_bClosing; // whether we are shutting down
+ bool m_bIsInConfig;
+ serveritem_t s1;
+ int m_hResourceWaitHandle;
+ float m_flPreviousSteamProgress;
+
+ typedef vgui::Panel BaseClass;
+ DECLARE_PANELMAP();
+
+};
+
+#endif // CMAINPANEL_H \ No newline at end of file
diff --git a/dedicated/vgui/vguihelpers.cpp b/dedicated/vgui/vguihelpers.cpp
new file mode 100644
index 0000000..11cf33e
--- /dev/null
+++ b/dedicated/vgui/vguihelpers.cpp
@@ -0,0 +1,187 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//===========================================================================//
+#ifdef _WIN32
+#include <windows.h>
+#include <direct.h>
+
+// includes for the VGUI version
+#include <vgui_controls/Panel.h>
+#include <vgui_controls/Controls.h>
+#include <vgui/ISystem.h>
+#include <vgui/IVGui.h>
+#include <vgui/IPanel.h>
+#include "filesystem.h"
+#include <vgui/ILocalize.h>
+#include <vgui/IScheme.h>
+#include <vgui/ISurface.h>
+#include <IVGuiModule.h>
+
+#include "vgui/MainPanel.h"
+#include "IAdminServer.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+
+static CMainPanel *g_pMainPanel = NULL; // the main panel to show
+static CSysModule *g_hAdminServerModule;
+IAdminServer *g_pAdminServer = NULL;
+static IVGuiModule *g_pAdminVGuiModule = NULL;
+
+void* DedicatedFactory(const char *pName, int *pReturnCode);
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Starts up the VGUI system and loads the base panel
+//-----------------------------------------------------------------------------
+int StartVGUI( CreateInterfaceFn dedicatedFactory )
+{
+ // the "base dir" so we can scan mod name
+ g_pFullFileSystem->AddSearchPath(".", "MAIN");
+ // the main platform dir
+ g_pFullFileSystem->AddSearchPath( "platform", "PLATFORM", PATH_ADD_TO_HEAD);
+
+ vgui::ivgui()->SetSleep(false);
+
+ // find our configuration directory
+ char szConfigDir[512];
+ const char *steamPath = getenv("SteamInstallPath");
+ if (steamPath)
+ {
+ // put the config dir directly under steam
+ Q_snprintf(szConfigDir, sizeof(szConfigDir), "%s/config", steamPath);
+ }
+ else
+ {
+ // we're not running steam, so just put the config dir under the platform
+ Q_strncpy( szConfigDir, "platform/config", sizeof(szConfigDir));
+ }
+ g_pFullFileSystem->CreateDirHierarchy("config", "PLATFORM");
+ g_pFullFileSystem->AddSearchPath(szConfigDir, "CONFIG", PATH_ADD_TO_HEAD);
+
+ // initialize the user configuration file
+ vgui::system()->SetUserConfigFile("DedicatedServerDialogConfig.vdf", "CONFIG");
+
+ // Init the surface
+ g_pMainPanel = new CMainPanel( );
+ g_pMainPanel->SetVisible(true);
+
+ vgui::surface()->SetEmbeddedPanel(g_pMainPanel->GetVPanel());
+
+ // load the scheme
+ vgui::scheme()->LoadSchemeFromFile("Resource/SourceScheme.res", NULL);
+
+ // localization
+ g_pVGuiLocalize->AddFile( "Resource/platform_%language%.txt" );
+ g_pVGuiLocalize->AddFile( "Resource/vgui_%language%.txt" );
+ g_pVGuiLocalize->AddFile( "Admin/server_%language%.txt" );
+
+ // Start vgui
+ vgui::ivgui()->Start();
+
+ // load the module
+ g_pFullFileSystem->GetLocalCopy("bin/AdminServer.dll");
+ g_hAdminServerModule = g_pFullFileSystem->LoadModule("AdminServer");
+ Assert(g_hAdminServerModule != NULL);
+ CreateInterfaceFn adminFactory = NULL;
+
+ if (!g_hAdminServerModule)
+ {
+ vgui::ivgui()->DPrintf2("Admin Error: module version (Admin/AdminServer.dll, %s) invalid, not loading\n", IMANAGESERVER_INTERFACE_VERSION );
+ }
+ else
+ {
+ // make sure we get the right version
+ adminFactory = Sys_GetFactory(g_hAdminServerModule);
+ g_pAdminServer = (IAdminServer *)adminFactory(ADMINSERVER_INTERFACE_VERSION, NULL);
+ g_pAdminVGuiModule = (IVGuiModule *)adminFactory("VGuiModuleAdminServer001", NULL);
+ Assert(g_pAdminServer != NULL);
+ Assert(g_pAdminVGuiModule != NULL);
+ if (!g_pAdminServer || !g_pAdminVGuiModule)
+ {
+ vgui::ivgui()->DPrintf2("Admin Error: module version (Admin/AdminServer.dll, %s) invalid, not loading\n", IMANAGESERVER_INTERFACE_VERSION );
+ }
+ }
+
+ // finish initializing admin module
+ g_pAdminVGuiModule->Initialize( &dedicatedFactory, 1 );
+ g_pAdminVGuiModule->PostInitialize(&adminFactory, 1);
+ g_pAdminVGuiModule->SetParent( g_pMainPanel->GetVPanel() );
+
+ // finish setting up main panel
+ g_pMainPanel->Initialize( );
+ g_pMainPanel->Open();
+
+ return 0;
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Shuts down the VGUI system
+//-----------------------------------------------------------------------------
+void StopVGUI()
+{
+ SetEvent(g_pMainPanel->GetShutdownHandle());
+
+ delete g_pMainPanel;
+ g_pMainPanel = NULL;
+
+ if (g_hAdminServerModule)
+ {
+ g_pAdminVGuiModule->Shutdown( );
+ Sys_UnloadModule(g_hAdminServerModule);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Run a single VGUI frame
+//-----------------------------------------------------------------------------
+void RunVGUIFrame()
+{
+ vgui::ivgui()->RunFrame();
+}
+
+
+bool VGUIIsStopping()
+{
+ return g_pMainPanel->Stopping();
+}
+
+
+bool VGUIIsRunning()
+{
+ return vgui::ivgui()->IsRunning();
+}
+
+bool VGUIIsInConfig()
+{
+ return g_pMainPanel->IsInConfig();
+}
+
+void VGUIFinishedConfig()
+{
+ Assert( g_pMainPanel );
+ if(g_pMainPanel) // engine is loaded, pass the message on
+ {
+ SetEvent(g_pMainPanel->GetShutdownHandle());
+ }
+}
+
+void VGUIPrintf( const char *msg )
+{
+ if ( !g_pMainPanel || VGUIIsInConfig() || VGUIIsStopping() )
+ {
+ OutputDebugStringA( msg );
+ }
+ else if ( g_pMainPanel )
+ {
+ g_pMainPanel->AddConsoleText( msg );
+ }
+}
+
+#endif // _WIN32
+
diff --git a/dedicated/vgui/vguihelpers.h b/dedicated/vgui/vguihelpers.h
new file mode 100644
index 0000000..e29203e
--- /dev/null
+++ b/dedicated/vgui/vguihelpers.h
@@ -0,0 +1,26 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//===========================================================================//
+
+#ifndef VGUIHELPERS_H
+#define VGUIHELPERS_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "tier1/interface.h"
+
+int StartVGUI( CreateInterfaceFn dedicatedFactory );
+void StopVGUI();
+void RunVGUIFrame();
+bool VGUIIsRunning();
+bool VGUIIsStopping();
+bool VGUIIsInConfig();
+void VGUIFinishedConfig();
+void VGUIPrintf( const char *msg );
+
+#endif // VGUIHELPERS_H
+
diff --git a/dedicated/vgui/vguihelpers_linux.cpp b/dedicated/vgui/vguihelpers_linux.cpp
new file mode 100644
index 0000000..4b8f474
--- /dev/null
+++ b/dedicated/vgui/vguihelpers_linux.cpp
@@ -0,0 +1,39 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+#include "interface.h"
+
+bool InitializeVGui(CreateInterfaceFn *factorylist, int factorycount)
+{
+}
+
+int StartVGUI()
+{
+}
+
+void StopVGUI()
+{
+}
+
+void RunVGUIFrame()
+{
+}
+
+bool VGUIIsRunning()
+{
+}
+
+bool VGUIIsStopping()
+{
+}
+
+bool VGUIIsInConfig()
+{
+}
+
+void VGUIFinishedConfig()
+{
+}
+