Executable

Revision as of 22:14, 9 March 2020 by imported>Leoetlino (→‎EventPatroller)

The executable is where all the game code is stored. It is located in the title code directory on Wii U and in the ExeFS on Switch.

Important note: unless otherwise stated, all addresses on this wiki are for the Switch 1.5.0 executable.

File

Switch

BotW's executable is a standard, compressed NSO which is larger than most other games (about 20MB compressed).

The build path is D:\home\Cafe\U-King\trunk\Game\App\Rom\NX64\Product\code\U-King.nss. For build IDs, see Versions.

Wii U

BotW's executable is a standard, compressed RPX.

Libraries

Full article: Software libraries

Subsystems

Full article: Subsystems

Symbols

Unfortunately, release versions of The Legend of Zelda: Breath of the Wild are stripped and have absolutely no debugging symbols. This has been verified for Switch 1.0.0, Wii U 1.5.0, Switch 1.5.0, Switch 1.6.0 and Switch RID_Demo.

The Switch 1.5.0 and 1.6.0 executables only have some RTTI data for UI classes. This is likely also the case for all older versions.

However, the game uses lots of software libraries, some of which are included in games that do ship with complete symbols such as Super Mario Odyssey. BotW seems to have been compiled at a higher optimisation level that causes unused functions to be fully removed.

Init and main loop outline

Early init and main loop

  • main
    • nn::oe::Initialize
    • sead::GameFrameworkNx::initialize (implicitly calls nn::oe::Initialize again; this looks like a mistake from the Zelda developers)
      • sead::HeapMgr and root heap
      • sead::ThreadMgr
      • sead::GlobalRandom
      • sead::ResourceMgr
      • sead::FileDeviceMgr
    • GameConfig
    • Unknown 71025D1720
    • uking::GameFramework (derived from sead::GameFrameworkNx)
    • GraphicsSystem
    • sead::GameFrameworkNx::initializeGraphicsSystem
    • [Debug] sead::PrimitiveRenderer
    • [Debug] sead::DebugFontMgrNvn
    • [Debug] sead::DebugFontMgrJis1Nvn
    • RootTask
      • sead::TaskBase::CreateArg
      • sead::Framework::RunArg
      • framework->run
        • Constructs a sead::MethodTreeMgr (note: a custom, derived MethodTreeMgr is used in BotW)
        • Constructs a sead::TaskMgr
          • sead::TaskMgr::doInit_
        • framework->runImpl_
          • framework->waitStartDisplayLoop_
          • framework->mainLoop
            • framework->procFrame
              • framework->procCalc
                • methodTreeMgr->calc (sead::SingleScreenMethodTreeMgr). Runs the following methods (sead::MethodTreeNode):
                  • RootCalc
                  • RootDraw
                    • AppDraw
                    • AppDrawFinal
                    • SysDraw
              • framework->present
              • framework->procReset
              • framework->waitForGpuDone
            • framework->setVBlankWaitInterval

RootTask::prepare

  • framework->createSystemTasks
    • sead::ControllerMgr
    • sead::ProcessMeter
    • [Debug] sead::SeadMenuMgr
    • [Debug] sead::HostIOMgr
    • sead::InfLoopChecker
    • [?] sead::CuckooClock
  • InfLoopChecker setup

RootTask::calc

Internal version

1.0.0's nnMain prints "00000010", whereas 1.5.0 prints "0000002d".

1.6.0 prints "0000002e".

Unused content

Arguments

The game accepts three different options: -fhd (flag for Full HD?), -no_sead_log (flag), -out (string). However the code that handles these arguments does not exist in the release version.

Save-breaking bug

Some development versions (1523941 to 1548881) generated unusable saves. These strings are still present in the release version but they are unused.

.rodata.2:0000007101DE98B0 a15239411548881 DCB "@1523941 ~ @1548881のROMからのセーブデータを利用しているようです。",0xA
.rodata.2:0000007101DE98B0                 DCB "バグ報告をせずに、セーブデータを消去してください。",0xA
.rodata.2:0000007101DE98B0                 DCB "@1523941 ~ @1548881からのセーブデータであるはずがないという場合のみ、バグ報告をしてください。",0xA
.rodata.2:0000007101DE98B0                 DCB "num_valid_normal_mode %d/%d, num_valid_hard_mode %d%d",0

Leftover debug or development tools

EventPatroller

Used to generate movies (prerendered cutscenes) for event flows. Receives orders via HostIO (in BYML format) in %UKING_ROOT%/../workdir/EventPatroller/order.byml and writes:

  • A YAML report containing frame-by-frame data with camera position, actor information, etc. Written to %s/report.yml % (name).
  • Screenshots for the entire event (maximum 18000 frames) captured using agl::utl::ScreenshotMgr, and written to %s/%05d.tga % (name, frame).

Throughout the execution of the order, %%KSYS_ROOT%%/tools/EventPatroller/ChangeStatus.bat is spawned to update the order status on the host computer.

EventPatroller can apparently make use of Havok script files (hks) in dev builds[1]. However, all script-related code is stubbed in release builds and both the hks and lua resource factories are unused.

Demo ROM types

The game calls sead::EnvUtil::getRomType() to get the ROM type. The result is printed to a debug log along with SD card, revision and AoC (DLC) information.

The ROM type is loaded from System/RegionLangMask.txt. Possible values are:

  • "Normal": used in retail versions (at least 1.0.0 and 1.5.0)
  • "Show_2017_1st": demo version, used for 12S?
  • "RID_Demo": Retail Interactive Display demo (aka kiosk version). Seen in the Switch kiosk version.
  • Anything else is treated as "Normal".

The release build crashes if the ROM type is set to Show_2017_1st or RID_Demo, presumably because these types activate code paths that require a global debug heap which never gets initialised in release versions.

ErrorViewer and Stage Select

There are references to debugging tools like Error (an in-game integrated bug tracker) and a stage select mode (uking::StageSelect + more strings). UI data and structures for the ErrorViewerTask still exist to a certain extent, but whether these features can be reactivated or not is still unknown.

Disabled functionality

In 1.5.0, the Patrol subsystem has a reference to BUILD_URL. Unfortunately, the function that is supposed to set the BUILD_URL string (sub_7100B0B728) is stubbed in the release build.

Similarly, the Revision subsystem is disabled in release builds. According to strings in the stage select screen function, it would have contained information about a program number (int), resource number (int) and a 'build from' string.

ActorDebug

This is a rather large subsystem that interacts with the actor system and all related components such as demos, events and maps. It can print debug information about the current state and override actor creation behaviour.

Debug options

A large amount of debug config strings have been left in the executable. These show the existence of debug game config files that were used to make testing more convenient during development.

The debug config files do not exist in the release version; the config loading code was removed as well.

.rodata.2:0000007101DC9625 aDebugGameconfi DCB "Debug/GameConfigSettingForGameROM.xml",0
.rodata.2:0000007101DC9625                                         ; DATA XREF: initDebugConfigFilePaths+18↑o
.rodata.2:0000007101DC9625                                         ; initDebugConfigFilePaths+2C↑o
.rodata.2:0000007101DC964B aDebugGameconfi_0 DCB "Debug/GameConfigForGameROM.xml",0
.rodata.2:0000007101DC964B                                         ; DATA XREF: initDebugConfigFilePaths+20↑o
.rodata.2:0000007101DC964B                                         ; initDebugConfigFilePaths+38↑o
.rodata.2:0000007101DC966A aDebugSystemgam DCB "Debug/SystemGameConfigForGameROM.xml",0
.rodata.2:0000007101DC966A                                         ; DATA XREF: initDebugConfigFilePaths+24↑o
.rodata.2:0000007101DC966A                                         ; initDebugConfigFilePaths+3C↑o
.rodata.2:0000007101DC968F aOpenworldOverr DCB "OpenWorld_OverrideStartPos",0
.rodata.2:0000007101DC96AA aOpenworldStart DCB "OpenWorld_StartX",0
.rodata.2:0000007101DC96BB aOpenworldStart_0 DCB "OpenWorld_StartY",0
.rodata.2:0000007101DC96CC aOpenworldStart_1 DCB "OpenWorld_StartZ",0
.rodata.2:0000007101DC96DD aOpenworlddesig DCB "OpenWorldDesign_OverrideStartPos",0
.rodata.2:0000007101DC96FE aOpenworlddesig_0 DCB "OpenWorldDesign_StartX",0
.rodata.2:0000007101DC9715 aOpenworlddesig_1 DCB "OpenWorldDesign_StartY",0
.rodata.2:0000007101DC972C aOpenworlddesig_2 DCB "OpenWorldDesign_StartZ",0
.rodata.2:0000007101DC9743 aIsdisabledpick DCB "IsDisabledPickUpDemo",0
.rodata.2:0000007101DC9758 aIsenabledcdung DCB "IsEnabledCDungeonEntranceDemo",0
.rodata.2:0000007101DC9776 aIsdisabledcdun DCB "IsDisabledCDungeonGoalTerminalDemo",0
.rodata.2:0000007101DC9799 aAlwayswaitscen DCB "AlwaysWaitSceneCreate",0
.rodata.2:0000007101DC97AF aIsequipweaponr DCB "IsEquipWeaponRandom",0
.rodata.2:0000007101DC97C3 aIsequiparmorra DCB "IsEquipArmorRandom",0
.rodata.2:0000007101DC97D6 aIssetweaponran DCB "IsSetWeaponRandom",0
.rodata.2:0000007101DC97E8 aIssetarmorrand DCB "IsSetArmorRandom",0
.rodata.2:0000007101DC97F9 aIssetarmorscri DCB "IsSetArmorScript",0
.rodata.2:0000007101DC980A aIssetitemrando DCB "IsSetItemRandom",0
.rodata.2:0000007101DC981A aIssetcookitemr DCB "IsSetCookItemRandom",0
.rodata.2:0000007101DC982E aDisabletimesto DCB "DisableTimeStop",0
.rodata.2:0000007101DC983E aSetdebugtime   DCB "SetDebugTime",0
.rodata.2:0000007101DC984B aDefaultfinewea DCB "DefaultFineWeather",0
.rodata.2:0000007101DC985E aDefaulttoolenv DCB "DefaultToolEnv",0
.rodata.2:0000007101DC986D aDefaultplayren DCB "DefaultPlayreNoTired",0
.rodata.2:0000007101DC9882 aDefaultplayern DCB "DefaultPlayerNoTemperture",0
.rodata.2:0000007101DC989C aAutoplacement  DCB "AutoPlacement",0
.rodata.2:0000007101DC98AA aTeam           DCB "Team",0
.rodata.2:0000007101DC98AF aShowmergeddung DCB "ShowMergedDungeonActor",0
.rodata.2:0000007101DC98C6 aShowmergedgrud DCB "ShowMergedGrudgeActor",0
.rodata.2:0000007101DC98DC aIsopenmapall   DCB "IsOpenMapAll",0
.rodata.2:0000007101DC98E9 aDebugcameraspe DCB "DebugCameraSpeed",0
.rodata.2:0000007101DC98FA aDebugcamerarep DCB "DebugCameraReplaceStick",0
.rodata.2:0000007101DC9912 aDebugcamerarev DCB "DebugCameraReverseVerticalRotation",0
.rodata.2:0000007101DC9935 aDebugcamerarev_0 DCB "DebugCameraReverseHorizontalRotation",0
.rodata.2:0000007101DC995A aDebugcameracon DCB "DebugCameraControlFovy",0
.rodata.2:0000007101DC9971 aIstexturememor DCB "IsTextureMemoryIncrese",0
.rodata.2:0000007101DC9988 aIstexturememor_0 DCB "IsTextureMemoryBothIncrease",0
.rodata.2:0000007101DC99A4 aIspilottexture DCB "IsPilotTextureMemoryIncrese",0
.rodata.2:0000007101DC99C0 aIspassstagesel DCB "IsPassStageSelect",0
.rodata.2:0000007101DC99D2 aIsstageselectr DCB "IsStageSelectRegularGameOver",0
.rodata.2:0000007101DC99EF aIsenableuidebu DCB "IsEnableUiDebugCommand",0
.rodata.2:0000007101DC9A06 aFirstscene     DCB "FirstScene",0
.rodata.2:0000007101DC9A11 aToolFrontEnd   DCB "Tool Front-End",0
.rodata.2:0000007101DC9A20 aDefaulttoolfro DCB "DefaultToolFrontEndPage",0

Option values are hardcoded in the Switch kiosk version as well.

  1. script_name (in the order data) is a path to a hks file.