//╒═════════════════════════════════════════════════════════════════════════════╕ //│ Author: Ben Rollinson Date: 16/05/12 │ //╞═════════════════════════════════════════════════════════════════════════════╡ //│ │ //│ Batch Mission Launcher │ //│ │ //│ A debug system that will read in a block of missions from │ //│ an XML doc and then automatically play through these missions │ //│ in sequence, launching them in the context of the main gameflow. │ //│ │ //╘═════════════════════════════════════════════════════════════════════════════╛ #IF IS_DEBUG_BUILD USING "rage_builtins.sch" USING "globals.sch" USING "commands_script.sch" USING "commands_cutscene.sch" USING "flow_launcher_main_core.sch" CONST_INT MAX_MISSION_BLOCK_SIZE 80 CONST_INT SIMULATE_KEYPRESS_DELAY_TIME 10000 //How long does the script wait between simulated skip keypresses (in milliseconds). CONST_INT SKIP_LIMIT 30 //How many skips without flow progress before the system decides the flow is stuck. CONST_INT LOOP_LIMIT 2 STRUCT BATCH_MISSION_LAUNCHER_STRUCT // Batch mission data. INT iMissionHashList[MAX_MISSION_BLOCK_SIZE] INT iMissionHashListCount INT iCurrentMission STRING strXMLFile STRING strMissionBlock // Logging data. STRING strFile STRING strPath // Autoplay data. BOOL bResetPlaythrough INT iSimulateDebugPressTimer INT iSkipWithoutChangeCounter INT iPlaythroughCount TEXT_LABEL_31 txtLastRunningMissionName TEXT_LABEL_63 txtLogString TEXT_LABEL_63 txtAutoplayMessage enumCharacterList eLastChar //State. BOOL bActive BOOL bDisabled BOOL bMissionRunning ENDSTRUCT //Initialise a new batch mission launcher struct with default setup. PROC Initialise_Batch_Mission_Launcher(BATCH_MISSION_LAUNCHER_STRUCT ¶mBatchLauncher) paramBatchLauncher.iMissionHashListCount = 0 paramBatchLauncher.iCurrentMission = 0 paramBatchLauncher.strXMLFile = "X:/gta5/titleupdate/dev_ng/common/data/script/xml/debug/MissionGroups" paramBatchLauncher.strFile = "autoplay.log" paramBatchLauncher.strPath = "X:/gta5/titleupdate/dev_ng/" paramBatchLauncher.bResetPlaythrough = FALSE paramBatchLauncher.iSkipWithoutChangeCounter = 0 paramBatchLauncher.iPlaythroughCount = 0 paramBatchLauncher.txtLastRunningMissionName = "NO MISSION" paramBatchLauncher.eLastChar = CHAR_BLANK_ENTRY paramBatchLauncher.bActive = FALSE paramBatchLauncher.bDisabled = FALSE paramBatchLauncher.bMissionRunning = FALSE ENDPROC //Log the start of a new session. PROC Log_New_Batch_Mission_Launcher_Session(BATCH_MISSION_LAUNCHER_STRUCT ¶mBatchLauncher) OPEN_NAMED_DEBUG_FILE(paramBatchLauncher.strPath, paramBatchLauncher.strFile) SAVE_NEWLINE_TO_NAMED_DEBUG_FILE(paramBatchLauncher.strPath, paramBatchLauncher.strFile) SAVE_NEWLINE_TO_NAMED_DEBUG_FILE(paramBatchLauncher.strPath, paramBatchLauncher.strFile) SAVE_STRING_TO_NAMED_DEBUG_FILE("---------------------------------------------------",paramBatchLauncher.strPath, paramBatchLauncher.strFile) SAVE_NEWLINE_TO_NAMED_DEBUG_FILE(paramBatchLauncher.strPath, paramBatchLauncher.strFile) paramBatchLauncher.txtLogString = "[NEW BATCH MISSION LAUNCHER SESSION | SKIP_LIMIT=" paramBatchLauncher.txtLogString += SKIP_LIMIT paramBatchLauncher.txtLogString += "]" SAVE_STRING_TO_NAMED_DEBUG_FILE(paramBatchLauncher.txtLogString, paramBatchLauncher.strPath, paramBatchLauncher.strFile) CLOSE_DEBUG_FILE() ENDPROC //Log the start of a new playthrough attempt. PROC Log_New_Playthrough(BATCH_MISSION_LAUNCHER_STRUCT ¶mBatchLauncher) paramBatchLauncher.iPlaythroughCount++ OPEN_NAMED_DEBUG_FILE(paramBatchLauncher.strPath, paramBatchLauncher.strFile) SAVE_NEWLINE_TO_NAMED_DEBUG_FILE(paramBatchLauncher.strPath, paramBatchLauncher.strFile) SAVE_STRING_TO_NAMED_DEBUG_FILE("---------------------------------------------------",paramBatchLauncher.strPath, paramBatchLauncher.strFile) SAVE_NEWLINE_TO_NAMED_DEBUG_FILE(paramBatchLauncher.strPath, paramBatchLauncher.strFile) paramBatchLauncher.txtLogString = "[PLAYTHROUGH #" paramBatchLauncher.txtLogString += paramBatchLauncher.iPlaythroughCount paramBatchLauncher.txtLogString += "]" SAVE_STRING_TO_NAMED_DEBUG_FILE(paramBatchLauncher.txtLogString, paramBatchLauncher.strPath, paramBatchLauncher.strFile) SAVE_NEWLINE_TO_NAMED_DEBUG_FILE(paramBatchLauncher.strPath, paramBatchLauncher.strFile) CLOSE_DEBUG_FILE() ENDPROC //Log a single simulated keypress. PROC Log_Skip_Keypress(BATCH_MISSION_LAUNCHER_STRUCT ¶mBatchLauncher) OPEN_NAMED_DEBUG_FILE(paramBatchLauncher.strPath, paramBatchLauncher.strFile) SAVE_STRING_TO_NAMED_DEBUG_FILE(".",paramBatchLauncher.strPath, paramBatchLauncher.strFile) CLOSE_DEBUG_FILE() ENDPROC PROC Draw_Autoplay_Message(BATCH_MISSION_LAUNCHER_STRUCT ¶mBatchLauncher) DRAW_RECT(0.5, 0.26, 0.22, 0.09, 0, 0, 0, 180) SET_TEXT_FONT(FONT_STANDARD) SET_TEXT_SCALE (0.4, 0.42) SET_TEXT_WRAP(0.0, 1.0) SET_TEXT_DROPSHADOW (0,0,0,0,255) SET_TEXT_COLOUR(255,255,255,85) SET_TEXT_EDGE (0,0,0,0,255) SET_TEXT_PROPORTIONAL (FALSE) SET_TEXT_JUSTIFICATION(FONT_CENTRE) DISPLAY_TEXT_WITH_LITERAL_STRING(0.5, 0.225, "STRING", "Mission Batch") SET_TEXT_FONT(FONT_STANDARD) SET_TEXT_SCALE (0.52, 0.57) SET_TEXT_WRAP(0.0, 1.0) SET_TEXT_DROPSHADOW (0,0,0,0,225) SET_TEXT_COLOUR(0,200,0,180) SET_TEXT_EDGE (0,0,0,0,255) SET_TEXT_PROPORTIONAL (FALSE) SET_TEXT_JUSTIFICATION(FONT_CENTRE) DISPLAY_TEXT_WITH_LITERAL_STRING(0.5, 0.255, "STRING", paramBatchLauncher.txtAutoplayMessage) ENDPROC PROC Load_Batch_Mission_List(BATCH_MISSION_LAUNCHER_STRUCT ¶mBatchLauncher) BOOL bFoundBlock = FALSE //Load the flow diagram XML file. CPRINTLN(DEBUG_AUTOPLAY, "Loading mission list from XML block \"", paramBatchLauncher.strMissionBlock, "\".") IF LOAD_XML_FILE(paramBatchLauncher.strXMLFile) INT iNodeCount = GET_NUMBER_OF_XML_NODES() IF iNodeCount <> 0 INT iNodeIndex, iAttributeIndex REPEAT iNodeCount iNodeIndex IF NOT bFoundBlock //First find the start of the block we want to load. IF ARE_STRINGS_EQUAL(GET_XML_NODE_NAME(), paramBatchLauncher.strMissionBlock) CPRINTLN(DEBUG_AUTOPLAY, "Found XML block \"", paramBatchLauncher.strMissionBlock, "\".") bFoundBlock = TRUE ENDIF ELIF NOT ARE_STRINGS_EQUAL(GET_XML_NODE_NAME(), "mission") //We've found the end of the block. We're done loading. CPRINTLN(DEBUG_AUTOPLAY, "Finished loading XML block \"", paramBatchLauncher.strMissionBlock, "\".") DELETE_XML_FILE() EXIT ELSE //We're in the block, compile mission name list. REPEAT GET_NUMBER_OF_XML_NODE_ATTRIBUTES() iAttributeIndex IF ARE_STRINGS_EQUAL(GET_XML_NODE_ATTRIBUTE_NAME(iAttributeIndex),"name") IF paramBatchLauncher.iMissionHashListCount < MAX_MISSION_BLOCK_SIZE CPRINTLN(DEBUG_AUTOPLAY, " * Added mission \"", GET_STRING_FROM_XML_NODE_ATTRIBUTE(iAttributeIndex), "\".") paramBatchLauncher.iMissionHashList[paramBatchLauncher.iMissionHashListCount] = GET_HASH_KEY(GET_STRING_FROM_XML_NODE_ATTRIBUTE(iAttributeIndex)) paramBatchLauncher.iMissionHashListCount++ ELSE CERRORLN(DEBUG_AUTOPLAY, "The mission batch launcher tried to load a mission list with too many elements. Increase MAX_MISSION_BLOCK_SIZE?") DELETE_XML_FILE() EXIT ENDIF ENDIF ENDREPEAT ENDIF GET_NEXT_XML_NODE() ENDREPEAT IF NOT bFoundBlock CERRORLN(DEBUG_AUTOPLAY, "Could not find a mission grounp defined in XML that matched the specified group.") ELSE CPRINTLN(DEBUG_AUTOPLAY, "Finished loading XML block \"", paramBatchLauncher.strMissionBlock, "\".") ENDIF DELETE_XML_FILE() ENDIF ENDIF ENDPROC PROC Run_Batch_Mission_Autoplay_Routines(BATCH_MISSION_LAUNCHER_STRUCT ¶mBatchLauncher) //Automatically clear wanted level if we have one. IF IS_PLAYER_PLAYING(PLAYER_ID()) IF GET_PLAYER_WANTED_LEVEL(PLAYER_ID()) > 0 SET_PLAYER_WANTED_LEVEL(PLAYER_ID(), 0) SET_PLAYER_WANTED_LEVEL_NOW(PLAYER_ID()) ENDIF ENDIF IF paramBatchLauncher.iSimulateDebugPressTimer < GET_GAME_TIMER() //Is a mocap cutscene running? IF NOT HAS_CUTSCENE_FINISHED() STOP_CUTSCENE() ELSE //Simulate a J-skip, we're on mission or off-mission and not on an RE. FAKE_KEY_PRESS(KEY_J) //Log this key press. Log_Skip_Keypress(paramBatchLauncher) //Increment the skip counter. paramBatchLauncher.iSkipWithoutChangeCounter++ paramBatchLauncher.iSimulateDebugPressTimer = GET_GAME_TIMER() + SIMULATE_KEYPRESS_DELAY_TIME ENDIF ELSE //Update how long until the next J-skip. paramBatchLauncher.txtAutoplayMessage = "Simulating J-skip in " paramBatchLauncher.txtAutoplayMessage += CEIL(TO_FLOAT(paramBatchLauncher.iSimulateDebugPressTimer - GET_GAME_TIMER()) / 1000.0) ENDIF //Have we reached our skip limit? Is the flow stuck? IF paramBatchLauncher.iSkipWithoutChangeCounter >= SKIP_LIMIT CPRINTLN(DEBUG_AUTOPLAY, "Hit J-skip limit!") //Too many J-skips. Log this problem and try and auto-pass the mission. OPEN_NAMED_DEBUG_FILE(paramBatchLauncher.strPath, paramBatchLauncher.strFile) SAVE_STRING_TO_NAMED_DEBUG_FILE("[J-skips stuck!][Attempting S-skip]",paramBatchLauncher.strPath, paramBatchLauncher.strFile) CLOSE_DEBUG_FILE() //Simulate an S-skip to try and auto-pass this mission. FAKE_KEY_PRESS(KEY_S) WAIT(1000) //Did the S-skip work? IF ARE_STRINGS_EQUAL(paramBatchLauncher.txtLastRunningMissionName, g_txtFlowAutoplayRunningMission) //No. Log this and reset the playthrough. OPEN_NAMED_DEBUG_FILE(paramBatchLauncher.strPath, paramBatchLauncher.strFile) SAVE_STRING_TO_NAMED_DEBUG_FILE("[S-skip failed]",paramBatchLauncher.strPath, paramBatchLauncher.strFile) SAVE_NEWLINE_TO_NAMED_DEBUG_FILE(paramBatchLauncher.strPath, paramBatchLauncher.strFile) SAVE_NEWLINE_TO_NAMED_DEBUG_FILE(paramBatchLauncher.strPath, paramBatchLauncher.strFile) CLOSE_DEBUG_FILE() paramBatchLauncher.bResetPlaythrough = TRUE ELSE //Yes, flow change noted. Reset counter. paramBatchLauncher.iSkipWithoutChangeCounter = 0 ENDIF ENDIF //Check if the current running mission has changed. IF NOT ARE_STRINGS_EQUAL(paramBatchLauncher.txtLastRunningMissionName, g_txtFlowAutoplayRunningMission) //The current running mission has changed. Log this. IF ARE_STRINGS_EQUAL(g_txtFlowAutoplayRunningMission, "NO MISSION") CPRINTLN(DEBUG_AUTOPLAY, "Noted that mission ", paramBatchLauncher.txtLastRunningMissionName, " just ended.") //Was the mission passed or failed? IF g_bFlowAutoplayJustPassed OPEN_NAMED_DEBUG_FILE(paramBatchLauncher.strPath, paramBatchLauncher.strFile) SAVE_STRING_TO_NAMED_DEBUG_FILE("[Passed]",paramBatchLauncher.strPath, paramBatchLauncher.strFile) SAVE_NEWLINE_TO_NAMED_DEBUG_FILE(paramBatchLauncher.strPath, paramBatchLauncher.strFile) CLOSE_DEBUG_FILE() ELSE OPEN_NAMED_DEBUG_FILE(paramBatchLauncher.strPath, paramBatchLauncher.strFile) SAVE_STRING_TO_NAMED_DEBUG_FILE("[Failed]",paramBatchLauncher.strPath, paramBatchLauncher.strFile) SAVE_NEWLINE_TO_NAMED_DEBUG_FILE(paramBatchLauncher.strPath, paramBatchLauncher.strFile) CLOSE_DEBUG_FILE() ENDIF //Flow change noted. Reset counter. paramBatchLauncher.iSkipWithoutChangeCounter = 0 ELSE CPRINTLN(DEBUG_AUTOPLAY, "Noted that mission ", g_txtFlowAutoplayRunningMission, " just started.") OPEN_NAMED_DEBUG_FILE(paramBatchLauncher.strPath, paramBatchLauncher.strFile) SAVE_NEWLINE_TO_NAMED_DEBUG_FILE(paramBatchLauncher.strPath, paramBatchLauncher.strFile) paramBatchLauncher.txtLogString = "[" paramBatchLauncher.txtLogString += g_txtFlowAutoplayRunningMission paramBatchLauncher.txtLogString += "]" SAVE_STRING_TO_NAMED_DEBUG_FILE(paramBatchLauncher.txtLogString,paramBatchLauncher.strPath, paramBatchLauncher.strFile) CLOSE_DEBUG_FILE() //Flow change noted. Reset counter. paramBatchLauncher.iSkipWithoutChangeCounter = 0 ENDIF ENDIF //Check if the current character has changed. enumCharacterList eCurrentChar = GET_CURRENT_PLAYER_PED_ENUM() IF paramBatchLauncher.eLastChar <> eCurrentChar //Character has changed. Log who we have switched to. OPEN_NAMED_DEBUG_FILE(paramBatchLauncher.strPath, paramBatchLauncher.strFile) paramBatchLauncher.txtLogString = "[" SWITCH(eCurrentChar) CASE CHAR_MICHAEL paramBatchLauncher.txtLogString += "M" BREAK CASE CHAR_FRANKLIN paramBatchLauncher.txtLogString += "F" BREAK CASE CHAR_TREVOR paramBatchLauncher.txtLogString += "T" BREAK DEFAULT paramBatchLauncher.txtLogString += "Invalid Character Switch!" BREAK ENDSWITCH paramBatchLauncher.txtLogString += "]" SAVE_STRING_TO_NAMED_DEBUG_FILE(paramBatchLauncher.txtLogString,paramBatchLauncher.strPath, paramBatchLauncher.strFile) CLOSE_DEBUG_FILE() //Remember the new current character. paramBatchLauncher.eLastChar = eCurrentChar ENDIF //Has a reset been requested? IF paramBatchLauncher.bResetPlaythrough CPRINTLN(DEBUG_AUTOPLAY, "Restting the game.") paramBatchLauncher.iSkipWithoutChangeCounter = 0 paramBatchLauncher.eLastChar = CHAR_BLANK_ENTRY paramBatchLauncher.bResetPlaythrough = FALSE //Trigger a singleplayer force cleanup as part of the reset procedure. FORCE_CLEANUP(FORCE_CLEANUP_FLAG_DEBUG_MENU) //Reactivate gameflow at the beginning. RESET_GAMEFLOW() ENDIF //Store current running mission index as the last before stepping to the next frame. paramBatchLauncher.txtLastRunningMissionName = g_txtFlowAutoplayRunningMission //Draw the autoplay message box. Draw_Autoplay_Message(paramBatchLauncher) ENDPROC PROC Run_Batch_Mission_Launch_Routines(BATCH_MISSION_LAUNCHER_STRUCT ¶mBatchLauncher, FLOW_LAUNCHER_VARS ¶mFlowLauncher) IF NOT paramBatchLauncher.bDisabled IF NOT paramBatchLauncher.bActive paramBatchLauncher.strMissionBlock = GET_COMMANDLINE_PARAM("missiongroup") IF IS_STRING_NULL_OR_EMPTY(paramBatchLauncher.strMissionBlock) OR ARE_STRINGS_EQUAL(paramBatchLauncher.strMissionBlock, "Debug command not in final build") CPRINTLN(DEBUG_AUTOPLAY, "Batch mission launcher disabled.") paramBatchLauncher.bActive = FALSE paramBatchLauncher.bDisabled = TRUE ELSE CPRINTLN(DEBUG_AUTOPLAY, "Starting batch mission launcher playthrough.") g_bFlowMetricZonesEnabled = TRUE g_bFlowSmokeTestEnabled = ARE_STRINGS_EQUAL(GET_COMMANDLINE_PARAM("smoketest"),"codebuilder_stats") g_bDebugBlockAutosaves = TRUE g_bFlowAutoplayInProgress = TRUE g_iMetricsIteration = 0 FAKE_KEY_PRESS(KEY_V) CPRINTLN(DEBUG_AUTOPLAY, "Smoketest mode enabled = ", g_bFlowSmokeTestEnabled, ".") Log_New_Batch_Mission_Launcher_Session(paramBatchLauncher) //Compile the list of missions that we want to play. Load_Batch_Mission_List(paramBatchLauncher) paramBatchLauncher.bActive = TRUE ENDIF ELSE IF paramBatchLauncher.iCurrentMission < paramBatchLauncher.iMissionHashListCount IF NOT paramBatchLauncher.bMissionRunning //No mission running. //Is this the first mission. If so log a new playthrough. IF paramBatchLauncher.iCurrentMission = 0 Log_New_Playthrough(paramBatchLauncher) IF g_bFlowSmoketestEnabled CPRINTLN(DEBUG_AUTOPLAY, "Waiting for smoketest to start.") WHILE NOT SMOKETEST_STARTED() WAIT(0) ENDWHILE CPRINTLN(DEBUG_AUTOPLAY, "New smoketest started.") ENDIF ENDIF //Launch next mission in gameflow. CPRINTLN(DEBUG_AUTOPLAY, "Starting playthrough of batch mission #", paramBatchLauncher.iCurrentMission, ".") LAUNCHER_LAUNCH_TO_MISSION_SCRIPT_HASH(paramFlowLauncher, paramBatchLauncher.iMissionHashList[paramBatchLauncher.iCurrentMission], TRUE, FALSE, FALSE) //Wait for mission to start. WHILE NOT IS_CURRENTLY_ON_MISSION_TO_TYPE(MISSION_TYPE_STORY) WAIT(0) ENDWHILE paramBatchLauncher.bMissionRunning = TRUE ELIF IS_CURRENTLY_ON_MISSION_TO_TYPE(MISSION_TYPE_STORY) //Mission is running. Automatically skip through it. Run_Batch_Mission_Autoplay_Routines(paramBatchLauncher) ELSE //Mission ended. Step to next mission. CPRINTLN(DEBUG_AUTOPLAY, "Batch mission #", paramBatchLauncher.iCurrentMission, " ended.") paramBatchLauncher.bMissionRunning = FALSE paramBatchLauncher.iCurrentMission++ WAIT(5000) ENDIF ELSE //All missions processed. Have we done enough passes? IF g_iMetricsIteration < LOOP_LIMIT //No, All missions processed. CPRINTLN(DEBUG_AUTOPLAY, "Mission batch launcher finished playing all missions. Starting new pass.") g_iMetricsIteration++ paramBatchLauncher.iCurrentMission = 0 ELSE CPRINTLN(DEBUG_AUTOPLAY, "Mission batch launcher finished playing all missions. All passes finished.") CPRINTLN(DEBUG_AUTOPLAY, "Ending.") paramBatchLauncher.bResetPlaythrough = TRUE Run_Batch_Mission_Autoplay_Routines(paramBatchLauncher) paramBatchLauncher.bActive = FALSE paramBatchLauncher.bDisabled = TRUE ENDIF IF g_bFlowSmoketestEnabled CPRINTLN(DEBUG_AUTOPLAY, "Ending smoketest for this playthrough.") SMOKETEST_END() ENDIF ENDIF ENDIF ENDIF ENDPROC #ENDIF