/* ** Command & Conquer Generals(tm) ** Copyright 2025 Electronic Arts Inc. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . */ //////////////////////////////////////////////////////////////////////////////// // // // (c) 2001-2003 Electronic Arts Inc. // // // //////////////////////////////////////////////////////////////////////////////// #include "PreRTS.h" // This must go first in EVERY cpp file in the GameEngine #include "Common/ArchiveFileSystem.h" #include "Common/CommandLine.h" #include "Common/CRCDebug.h" #include "Common/LocalFileSystem.h" #include "Common/Version.h" #include "GameClient/TerrainVisual.h" // for TERRAIN_LOD_MIN definition #include "GameClient/GameText.h" Bool TheDebugIgnoreSyncErrors = FALSE; extern Int DX8Wrapper_PreserveFPU; #ifdef DEBUG_CRC Int TheCRCFirstFrameToLog = -1; UnsignedInt TheCRCLastFrameToLog = 0xffffffff; Bool g_keepCRCSaves = FALSE; Bool g_crcModuleDataFromLogic = FALSE; Bool g_crcModuleDataFromClient = FALSE; Bool g_verifyClientCRC = FALSE; // verify that GameLogic CRC doesn't change from client Bool g_clientDeepCRC = FALSE; Bool g_logObjectCRCs = FALSE; #endif #if defined(_DEBUG) || defined(_INTERNAL) extern Bool g_useStringFile; #endif // Retval is number of cmd-line args eaten typedef Int (*FuncPtr)( char *args[], int num ); static const UnsignedByte F_NOCASE = 1; // Case-insensitive struct CommandLineParam { const char *name; FuncPtr func; }; static void ConvertShortMapPathToLongMapPath(AsciiString &mapName) { AsciiString path = mapName; AsciiString token; AsciiString actualpath; if ((path.find('\\') == NULL) && (path.find('/') == NULL)) { DEBUG_CRASH(("Invalid map name %s", mapName.str())); return; } path.nextToken(&token, "\\/"); while (!token.endsWithNoCase(".map") && (token.getLength() > 0)) { actualpath.concat(token); actualpath.concat('\\'); path.nextToken(&token, "\\/"); } if (!token.endsWithNoCase(".map")) { DEBUG_CRASH(("Invalid map name %s", mapName.str())); } // remove the .map from the end. token.removeLastChar(); token.removeLastChar(); token.removeLastChar(); token.removeLastChar(); actualpath.concat(token); actualpath.concat('\\'); actualpath.concat(token); actualpath.concat(".map"); mapName = actualpath; } //============================================================================= //============================================================================= Int parseNoLogOrCrash(char *args[], int) { #ifdef ALLOW_DEBUG_UTILS DEBUG_CRASH(("-NoLogOrCrash not supported in this build\n")); #endif return 1; } //============================================================================= //============================================================================= Int parseWin(char *args[], int) { if (TheWritableGlobalData) { TheWritableGlobalData->m_windowed = true; } return 1; } //============================================================================= //============================================================================= Int parseNoMusic(char *args[], int) { if (TheWritableGlobalData) { TheWritableGlobalData->m_musicOn = false; } return 1; } //============================================================================= //============================================================================= Int parseNoVideo(char *args[], int) { if (TheWritableGlobalData) { TheWritableGlobalData->m_videoOn = false; } return 1; } //============================================================================= //============================================================================= Int parseFPUPreserve(char *args[], int argc) { if (argc > 1) { DX8Wrapper_PreserveFPU = atoi(args[1]); } return 2; } #if defined(_DEBUG) || defined(_INTERNAL) //============================================================================= //============================================================================= Int parseUseCSF(char *args[], int) { g_useStringFile = FALSE; return 1; } //============================================================================= //============================================================================= Int parseNoInputDisable(char *args[], int) { if (TheWritableGlobalData) { TheWritableGlobalData->m_disableScriptedInputDisabling = true; } return 1; } //============================================================================= //============================================================================= Int parseNoFade(char *args[], int) { if (TheWritableGlobalData) { TheWritableGlobalData->m_disableCameraFade = true; } return 1; } //============================================================================= //============================================================================= Int parseNoMilCap(char *args[], int) { if (TheWritableGlobalData) { TheWritableGlobalData->m_disableMilitaryCaption = true; } return 1; } //============================================================================= //============================================================================= Int parseDebugCRCFromFrame(char *args[], int argc) { #ifdef DEBUG_CRC if (argc > 1) { TheCRCFirstFrameToLog = atoi(args[1]); } #endif return 2; } //============================================================================= //============================================================================= Int parseDebugCRCUntilFrame(char *args[], int argc) { #ifdef DEBUG_CRC if (argc > 1) { TheCRCLastFrameToLog = atoi(args[1]); } #endif return 2; } //============================================================================= //============================================================================= Int parseKeepCRCSave(char *args[], int argc) { #ifdef DEBUG_CRC g_keepCRCSaves = TRUE; #endif return 1; } //============================================================================= //============================================================================= Int parseCRCLogicModuleData(char *args[], int argc) { #ifdef DEBUG_CRC g_crcModuleDataFromLogic = TRUE; #endif return 1; } //============================================================================= //============================================================================= Int parseCRCClientModuleData(char *args[], int argc) { #ifdef DEBUG_CRC g_crcModuleDataFromClient = TRUE; #endif return 1; } //============================================================================= //============================================================================= Int parseClientDeepCRC(char *args[], int argc) { #ifdef DEBUG_CRC g_clientDeepCRC = TRUE; #endif return 1; } //============================================================================= //============================================================================= Int parseVerifyClientCRC(char *args[], int argc) { #ifdef DEBUG_CRC g_verifyClientCRC = TRUE; #endif return 1; } //============================================================================= //============================================================================= Int parseLogObjectCRCs(char *args[], int argc) { #ifdef DEBUG_CRC g_logObjectCRCs = TRUE; #endif return 1; } //============================================================================= //============================================================================= Int parseNetCRCInterval(char *args[], int argc) { #ifdef DEBUG_CRC if (argc > 1) { NET_CRC_INTERVAL = atoi(args[1]); } #endif return 2; } //============================================================================= //============================================================================= Int parseReplayCRCInterval(char *args[], int argc) { #ifdef DEBUG_CRC if (argc > 1) { REPLAY_CRC_INTERVAL = atoi(args[1]); } #endif return 2; } //============================================================================= //============================================================================= Int parseNoDraw(char *args[], int argc) { #ifdef DEBUG_CRC if (TheWritableGlobalData) { TheWritableGlobalData->m_noDraw = TRUE; } #endif return 1; } //============================================================================= //============================================================================= Int parseLogToConsole(char *args[], int) { DebugSetFlags(DebugGetFlags() | DEBUG_FLAG_LOG_TO_CONSOLE); return 1; } #endif // _DEBUG || _INTERNAL //============================================================================= //============================================================================= Int parseNoAudio(char *args[], int) { if (TheWritableGlobalData) { TheWritableGlobalData->m_audioOn = false; TheWritableGlobalData->m_speechOn = false; TheWritableGlobalData->m_soundsOn = false; TheWritableGlobalData->m_musicOn = false; } return 1; } //============================================================================= //============================================================================= Int parseNoWin(char *args[], int) { if (TheWritableGlobalData) { TheWritableGlobalData->m_windowed = false; } return 1; } Int parseFullVersion(char *args[], int num) { if (TheVersion && num > 1) { TheVersion->setShowFullVersion(atoi(args[1]) != 0); } return 1; } Int parseNoShadows(char *args[], int) { if (TheWritableGlobalData) { TheWritableGlobalData->m_useShadowVolumes = false; TheWritableGlobalData->m_useShadowDecals = false; } return 1; } Int parseMapName(char *args[], int num) { if (TheWritableGlobalData && num == 2) { TheWritableGlobalData->m_mapName.set( args[ 1 ] ); ConvertShortMapPathToLongMapPath(TheWritableGlobalData->m_mapName); } return 1; } Int parseXRes(char *args[], int num) { if (TheWritableGlobalData && num > 1) { TheWritableGlobalData->m_xResolution = atoi(args[1]); return 2; } return 1; } Int parseYRes(char *args[], int num) { if (TheWritableGlobalData && num > 1) { TheWritableGlobalData->m_yResolution = atoi(args[1]); return 2; } return 1; } #if defined(_DEBUG) || defined(_INTERNAL) //============================================================================= //============================================================================= Int parseLatencyAverage(char *args[], int num) { if (TheWritableGlobalData && num > 1) { TheWritableGlobalData->m_latencyAverage = atoi(args[1]); } return 2; } //============================================================================= //============================================================================= Int parseLatencyAmplitude(char *args[], int num) { if (TheWritableGlobalData && num > 1) { TheWritableGlobalData->m_latencyAmplitude = atoi(args[1]); } return 2; } //============================================================================= //============================================================================= Int parseLatencyPeriod(char *args[], int num) { if (TheWritableGlobalData && num > 1) { TheWritableGlobalData->m_latencyPeriod = atoi(args[1]); } return 2; } //============================================================================= //============================================================================= Int parseLatencyNoise(char *args[], int num) { if (TheWritableGlobalData && num > 1) { TheWritableGlobalData->m_latencyNoise = atoi(args[1]); } return 2; } //============================================================================= //============================================================================= Int parsePacketLoss(char *args[], int num) { if (TheWritableGlobalData && num > 1) { TheWritableGlobalData->m_packetLoss = atoi(args[1]); } return 2; } //============================================================================= //============================================================================= Int parseLowDetail(char *args[], int num) { if (TheWritableGlobalData) { TheWritableGlobalData->m_terrainLOD = TERRAIN_LOD_MIN; } return 1; } //============================================================================= //============================================================================= Int parseNoDynamicLOD(char *args[], int num) { if (TheWritableGlobalData) { TheWritableGlobalData->m_enableDynamicLOD = FALSE; } return 1; } //============================================================================= //============================================================================= Int parseNoStaticLOD(char *args[], int num) { if (TheWritableGlobalData) { TheWritableGlobalData->m_enableStaticLOD = FALSE; } return 1; } //============================================================================= //============================================================================= Int parseUseWaveEditor(char *args[], int num) { if (TheWritableGlobalData) { TheWritableGlobalData->m_usingWaterTrackEditor = TRUE; } return 1; } //============================================================================= //============================================================================= Int parseFPSLimit(char *args[], int num) { if (TheWritableGlobalData && num > 1) { TheWritableGlobalData->m_framesPerSecondLimit = atoi(args[1]); } return 2; } //============================================================================= Int parseNoViewLimit(char *args[], int) { if (TheWritableGlobalData) { TheWritableGlobalData->m_useCameraConstraints = FALSE; } return 1; } Int parseWireframe(char *args[], int) { if (TheWritableGlobalData) { TheWritableGlobalData->m_wireframe = TRUE; } return 1; } Int parseShowCollision(char *args[], int) { if (TheWritableGlobalData) { TheWritableGlobalData->m_showCollisionExtents = TRUE; } return 1; } Int parseNoShowClientPhysics(char *args[], int) { if (TheWritableGlobalData) { TheWritableGlobalData->m_showClientPhysics = FALSE; } return 1; } Int parseShowTerrainNormals(char *args[], int) { if (TheWritableGlobalData) { TheWritableGlobalData->m_showTerrainNormals = TRUE; } return 1; } Int parseStateMachineDebug(char *args[], int) { if (TheWritableGlobalData) { TheWritableGlobalData->m_stateMachineDebug = TRUE; } return 1; } Int parseJabber(char *args[], int) { if (TheWritableGlobalData) { TheWritableGlobalData->m_jabberOn = TRUE; } return 1; } Int parseMunkee(char *args[], int) { if (TheWritableGlobalData) { TheWritableGlobalData->m_munkeeOn = TRUE; } return 1; } #endif // defined(_DEBUG) || defined(_INTERNAL) Int parseScriptDebug(char *args[], int) { if (TheWritableGlobalData) { TheWritableGlobalData->m_scriptDebug = TRUE; TheWritableGlobalData->m_winCursors = TRUE; } return 1; } Int parseParticleEdit(char *args[], int) { if (TheWritableGlobalData) { TheWritableGlobalData->m_particleEdit = TRUE; TheWritableGlobalData->m_winCursors = TRUE; TheWritableGlobalData->m_windowed = TRUE; } return 1; } Int parseBuildMapCache(char *args[], int) { if (TheWritableGlobalData) { TheWritableGlobalData->m_buildMapCache = true; } return 1; } #if defined(_DEBUG) || defined(_INTERNAL) Int parseDisplayDebug(char *args[], int) { if (TheWritableGlobalData) { TheWritableGlobalData->m_displayDebug = TRUE; } return 1; } Int parseFile(char *args[], int num) { if (TheWritableGlobalData && num > 1) { TheWritableGlobalData->m_initialFile = args[1]; ConvertShortMapPathToLongMapPath(TheWritableGlobalData->m_initialFile); } return 2; } Int parsePreload( char *args[], int num ) { if( TheWritableGlobalData ) TheWritableGlobalData->m_preloadAssets = TRUE; return 1; } Int parsePreloadEverything( char *args[], int num ) { if( TheWritableGlobalData ) { TheWritableGlobalData->m_preloadAssets = TRUE; TheWritableGlobalData->m_preloadEverything = TRUE; } return 1; } Int parseLogAssets( char *args[], int num ) { if( TheWritableGlobalData ) { FILE *logfile=fopen("PreloadedAssets.txt","w"); if (logfile) //clear the file fclose(logfile); TheWritableGlobalData->m_preloadReport = TRUE; } return 1; } /// begin stuff for VTUNE Int parseVTune ( char *args[], int num ) { if( TheWritableGlobalData ) TheWritableGlobalData->m_vTune = TRUE; return 1; } /// end stuff for VTUNE #endif // defined(_DEBUG) || defined(_INTERNAL) //============================================================================= //============================================================================= Int parseNoFX(char *args[], int) { if (TheWritableGlobalData) { TheWritableGlobalData->m_useFX = FALSE; } return 1; } #if defined(_DEBUG) || defined(_INTERNAL) Int parseNoShroud(char *args[], int) { if (TheWritableGlobalData) { TheWritableGlobalData->m_shroudOn = FALSE; } return 1; } #endif Int parseForceBenchmark(char *args[], int) { if (TheWritableGlobalData) { TheWritableGlobalData->m_forceBenchmark = TRUE; } return 1; } Int parseNoMoveCamera(char *args[], int) { if (TheWritableGlobalData) { TheWritableGlobalData->m_disableCameraMovement = true; } return 1; } #if defined(_DEBUG) || defined(_INTERNAL) Int parseNoCinematic(char *args[], int) { if (TheWritableGlobalData) { TheWritableGlobalData->m_disableCameraMovement = true; TheWritableGlobalData->m_disableMilitaryCaption = true; TheWritableGlobalData->m_disableCameraFade = true; TheWritableGlobalData->m_disableScriptedInputDisabling = true; } return 1; } #endif Int parseSync(char *args[], int) { if (TheWritableGlobalData) { TheDebugIgnoreSyncErrors = true; } return 1; } Int parseNoShellMap(char *args[], int) { if (TheWritableGlobalData) { TheWritableGlobalData->m_shellMapOn = FALSE; } return 1; } #if !defined(_PLAYTEST) || (defined(_DEBUG) || defined(_INTERNAL)) Int parseNoLogo(char *args[], int) { if (TheWritableGlobalData) { TheWritableGlobalData->m_playIntro = FALSE; TheWritableGlobalData->m_afterIntro = TRUE; } return 1; } #endif Int parseShellMap(char *args[], int num) { if (TheWritableGlobalData && num > 1) { TheWritableGlobalData->m_shellMapName = args[1]; } return 2; } Int parseNoWindowAnimation(char *args[], int num) { if (TheWritableGlobalData) { TheWritableGlobalData->m_animateWindows = FALSE; } return 1; } Int parseWinCursors(char *args[], int num) { if (TheWritableGlobalData) { TheWritableGlobalData->m_winCursors = TRUE; } return 1; } Int parseQuickStart( char *args[], int num ) { parseNoLogo( args, num ); parseNoShellMap( args, num ); parseNoWindowAnimation( args, num ); return 1; } Int parseConstantDebug( char *args[], int num ) { if (TheWritableGlobalData) { TheWritableGlobalData->m_constantDebugUpdate = TRUE; } return 1; } Int parseShowTeamDot( char *args[], int num ) { if( TheWritableGlobalData ) { TheWritableGlobalData->m_showTeamDot = TRUE; } return 1; } #if defined(_DEBUG) || defined(_INTERNAL) Int parseSelectAll( char *args[], int num ) { if( TheWritableGlobalData ) { TheWritableGlobalData->m_allowUnselectableSelection = TRUE; } return 1; } Int parseRunAhead( char *args[], Int num ) { if (num > 2) { MIN_RUNAHEAD = atoi(args[1]); MAX_FRAMES_AHEAD = atoi(args[2]); FRAME_DATA_LENGTH = (MAX_FRAMES_AHEAD + 1)*2; } return 3; } #endif Int parseSeed(char *args[], int num) { if (TheWritableGlobalData && num > 1) { TheWritableGlobalData->m_fixedSeed = atoi(args[1]); } return 2; } Int parseIncrAGPBuf(char *args[], int num) { if (TheWritableGlobalData) { TheWritableGlobalData->m_incrementalAGPBuf = TRUE; } return 1; } Int parseNetMinPlayers(char *args[], int num) { if (TheWritableGlobalData && num > 1) { TheWritableGlobalData->m_netMinPlayers = atoi(args[1]); } return 2; } Int parsePlayStats(char *args[], int num) { if (TheWritableGlobalData && num > 1) { TheWritableGlobalData->m_playStats = atoi(args[1]); } return 2; } Int parseDemoLoadScreen(char *args[], int num) { if (TheWritableGlobalData) { TheWritableGlobalData->m_loadScreenDemo = TRUE; } return 1; } #if defined(_DEBUG) || defined(_INTERNAL) Int parseSaveStats(char *args[], int num) { if (TheWritableGlobalData && num > 1) { TheWritableGlobalData->m_saveStats = TRUE; TheWritableGlobalData->m_baseStatsDir = args[1]; } return 2; } #endif #if defined(_DEBUG) || defined(_INTERNAL) Int parseSaveAllStats(char *args[], int num) { if (TheWritableGlobalData && num > 1) { TheWritableGlobalData->m_saveStats = TRUE; TheWritableGlobalData->m_baseStatsDir = args[1]; TheWritableGlobalData->m_saveAllStats = TRUE; } return 2; } #endif #if defined(_DEBUG) || defined(_INTERNAL) Int parseLocalMOTD(char *args[], int num) { if (TheWritableGlobalData && num > 1) { TheWritableGlobalData->m_useLocalMOTD = TRUE; TheWritableGlobalData->m_MOTDPath = args[1]; } return 2; } #endif #if defined(_DEBUG) || defined(_INTERNAL) Int parseCameraDebug(char *args[], int num) { if (TheWritableGlobalData) { TheWritableGlobalData->m_debugCamera = TRUE; } return 1; } #endif #if defined(_DEBUG) || defined(_INTERNAL) Int parseBenchmark(char *args[], int num) { if (TheWritableGlobalData && num > 1) { TheWritableGlobalData->m_benchmarkTimer = atoi(args[1]); TheWritableGlobalData->m_playStats = atoi(args[1]); } return 2; } #endif #if defined(_DEBUG) || defined(_INTERNAL) Int parseIgnoreAsserts(char *args[], int num) { if (TheWritableGlobalData && num > 0) { TheWritableGlobalData->m_debugIgnoreAsserts = true; } return 1; } #endif #if defined(_DEBUG) || defined(_INTERNAL) Int parseIgnoreStackTrace(char *args[], int num) { if (TheWritableGlobalData && num > 0) { TheWritableGlobalData->m_debugIgnoreStackTrace = true; } return 1; } #endif Int parseNoFPSLimit(char *args[], int num) { if (TheWritableGlobalData) { TheWritableGlobalData->m_useFpsLimit = false; TheWritableGlobalData->m_framesPerSecondLimit = 30000; } return 1; } Int parseDumpAssetUsage(char *args[], int num) { if (TheWritableGlobalData) { TheWritableGlobalData->m_dumpAssetUsage = true; } return 1; } Int parseJumpToFrame(char *args[], int num) { if (TheWritableGlobalData && num > 1) { parseNoFPSLimit(args, num); TheWritableGlobalData->m_noDraw = atoi(args[1]); return 2; } return 1; } Int parseUpdateImages(char *args[], int num) { if (TheWritableGlobalData) { TheWritableGlobalData->m_shouldUpdateTGAToDDS = TRUE; } return 1; } Int parseMod(char *args[], Int num) { if (TheWritableGlobalData && num > 1) { AsciiString modPath = args[1]; if (strchr(modPath.str(), ':') || modPath.startsWith("/") || modPath.startsWith("\\")) { // full path passed in. Don't append base path. } else { modPath.format("%s%s", TheGlobalData->getPath_UserData().str(), args[1]); } DEBUG_LOG(("Looking for mod '%s'\n", modPath.str())); if (!TheLocalFileSystem->doesFileExist(modPath.str())) { DEBUG_LOG(("Mod does not exist.\n")); return 2; // no such file/dir. } // now check for dir-ness struct stat statBuf; if (stat(modPath.str(), &statBuf) != 0) { DEBUG_LOG(("Could not _stat() mod.\n")); return 2; // could not stat the file/dir. } if (statBuf.st_mode & S_IFDIR) { if (!modPath.endsWith("\\") && !modPath.endsWith("/")) modPath.concat('\\'); DEBUG_LOG(("Mod dir is '%s'.\n", modPath.str())); TheWritableGlobalData->m_modDir = modPath; } else { DEBUG_LOG(("Mod file is '%s'.\n", modPath.str())); TheWritableGlobalData->m_modBIG = modPath; } return 2; } return 1; } #if defined(_DEBUG) || defined(_INTERNAL) Int parseSetDebugLevel(char *args[], int num) { if (num > 1) { AsciiString val = args[1]; for (Int i=0; i 1) { AsciiString val = args[1]; for (Int i=0; iloadMods(); }