Measuring Time to Display Menus
IntroductionEdit
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.
NotesEdit
- 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 ScriptEdit
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
IssuesEdit
- 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.