Measuring Time to Display Menus

From the Oblivion ConstructionSet Wiki
Jump to navigation Jump to search

Introduction[edit | edit source]

While opening a menu or switching to another menu, the game is frozen. If it's desired to measure how long this time period lasts, you can use the quest script in this page for this purpose.

This can be useful e.g. to test performance when adding new/modifying existing menu components in Oblivion XML files, especially the inventory, magic or container menu, which can open really slow if there are hundreds of items in these menus.

The quest script:

  • measures the time it takes to open a menu from GameMode,
  • measures the time it takes to switch to another menu when in MenuMode.

As a side effect, the script can also measure the time it takes to load an interior or exterior when opening doors, using fast travel, etc. if loading screens are displayed, but not if loading saved games or starting a new game.

Notes[edit | edit source]

  • The script prints the currently active menu and the measured time to the console.
  • The script requires OBSE to run.
  • The script uses GetUserTime function from OBSE to get the user's current date and time. The GetSecondsPassed function cannot be used for the purposes of the script.
  • The time measured is displayed in seconds with precision up to three decimal places. The number of decimal places is restricted by the GetUserTime function - the "Millisecond" array element returned by the function can only be an integer ranging from 0 to 999.
  • The script runs every frame in order to get the most precise results.
  • The script does not display time below a specified threshold (in seconds). By default, the threshold is 0.2 seconds.

The Script[edit | edit source]

scn OpenMenuTimeMeasureScript

float fQuestDelayTime

array_var previousUserTime
int previousDay
int previousHours
int previousMinutes
int previousSeconds
int previousMilliseconds
float previousTime

array_var currentUserTime
int currentDay
int currentHours
int currentMinutes
int currentSeconds
int currentMilliseconds
float currentTime

float timePassed
float timePassedLowerBound   ; time below this threshold will not be displayed

int previousMenuMode
int currentMenuMode
short isNewMenu
short isMenuMode             ; 0 = GameMode, 1 = MenuMode

short runOpenMenuOnce
short initOnce

Begin GameMode
	set fQuestDelayTime to 0.01

	let previousUserTime := GetUserTime
	
	if (initOnce == 0)
		set initOnce to 1
		set timePassedLowerBound to 0.2
	endif
	
	if isMenuMode
		set isMenuMode to 0
	endif
	if runOpenMenuOnce
		set runOpenMenuOnce to 0
	endif
End

Begin MenuMode
	set fQuestDelayTime to 0.01
	
	let currentMenuMode := GetActiveMenuMode
	
	if (isNewMenu == 0)   ; The first time the current (= active) menu is displayed
		let previousMenuMode := currentMenuMode
		set isNewMenu to 1
	elseif (previousMenuMode != currentMenuMode)
		; User switched to another menu
		set runOpenMenuOnce to 0
		set isNewMenu to 0
	elseif (previousMenuMode == currentMenuMode)
		if isMenuMode
			; In case user switches to another menu from the current menu
			let previousUserTime := GetUserTime
		endif
	endif

	; In case user leaves to GameMode and then reopens the last active menu again
	set isMenuMode to 1


	if runOpenMenuOnce
		return
	endif
	
	set runOpenMenuOnce to 1
	
	if (initOnce == 0)
		set initOnce to 1
		; Initialize the previousUserTime array in case the GameMode portion of the
		; script hasn't kicked in yet (where this array is initialized and assigned values).
		let previousUserTime := GetUserTime
		set timePassedLowerBound to 0.2
	endif
	
	let currentUserTime := GetUserTime
	
	let previousDay := previousUserTime["Day"]
	let previousHours := previousUserTime["Hour"]
	let previousMinutes := previousUserTime["Minute"]
	let previousSeconds := previousUserTime["Second"]
	let previousMilliseconds := previousUserTime["Millisecond"]
	
	let currentDay := currentUserTime["Day"]
	let currentHours := previousUserTime["Hour"]
	let currentMinutes := currentUserTime["Minute"]
	let currentSeconds := currentUserTime["Second"]
	let currentMilliseconds := currentUserTime["Millisecond"]

	; Milliseconds are added later (because of precision errors I encountered)
	let previousTime := (previousHours * 3600) + (previousMinutes * 60) + previousSeconds
	let currentTime := (currentHours * 3600) + (currentMinutes * 60) + currentSeconds
	
	if (previousDay != currentDay)
		; Previous timestamp was captured before midnight
		; and the current timestamp after midnight.
		; 86400 seconds = 24 * 60 * 60 seconds = 1 day
		let currentTime := currentTime + 86400
	endif
	
	let timePassed := currentTime - previousTime + ((currentMilliseconds - previousMilliseconds) / 1000)

	if timePassed >= timePassedLowerBound
		printc "Menu %g", currentMenuMode
		printc "Time passed: %.3f", timePassed
	endif
End

Issues[edit | edit source]

  • The script will not yield correct values if the time measured is longer than one day (= 86400 seconds), which is extremely unlikely to happen.
  • The script will not measure time if a menu is reloaded via the reload command from the console.

As already mentioned, the script also measures time it takes to switch to another menu. There is an issue with this behavior, however. For example, in player's inventory menu, there are multiple menus on the screen that can be active (one at a time) - inventory menu, magic popup menu and HUD main menu. Moving your mouse outside the inventory menu causes the game to switch to the HUD main menu, which triggers the time measure. Moving your mouse back to the inventory menu triggers it again.

Ignoring the HUD main menu is not a solution, because if player opens the inventory menu and the mouse cursor points outside the inventory menu, the HUD main menu will be active first. The entire time the mouse is positioned over the HUD main menu would add to the time measured, causing it to be incorrect.

If you didn't understand from the description what the issue is, it should be clearer once you change the timePassedLowerBound variable to 0, use the script in game and watch the console output. You may want to toggle debug text on by typing tdt in the console so that the output is displayed even if the console is not active.

This issue occurs in any menu. Thankfully, the 0.2 second threshold filters most of the "bogus" time measures.