Files
2025-09-29 00:52:08 +02:00

436 lines
18 KiB
Scheme
Executable File

//
// 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 &paramBatchLauncher)
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 &paramBatchLauncher)
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 &paramBatchLauncher)
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 &paramBatchLauncher)
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 &paramBatchLauncher)
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 &paramBatchLauncher)
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 &paramBatchLauncher)
//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 &paramBatchLauncher, FLOW_LAUNCHER_VARS &paramFlowLauncher)
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