GameScene

Revision as of 16:16, 30 April 2021 by NiceneNerd (talk | contribs) (Added Wii U init address)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

GameScene is a critical subsystem that is responsible for core functionality such as initialising other components, creating stages (world, title screen, etc.) and handling the game's main loop.

GameScene
Subsystem
Official name Yes
Description Handles the main loop and stages
Init function Switch 1.5.0: 0x71007D1DD8
Wii U 1.5.0: 02C23480
Debug only No

Unlike most other subsystems, GameScene is not a singleton: it is a member of the uking::frm::System structure[1].

Definitions

Stages

Also called scenes in XLink code.

Type Description Map types
0 Invalid ("None") -
1 Open world stage (except GameTestField) ("オープンワールド") MainField, AocField
2 Indoor stage ("Cダンジョン") CDungeon, MainFieldSpot, GameTestDungeon
3 Open world stage (GameTestField) ("GameTset") GameTestField
4 MainFieldDungeon ("四大遺物") MainFieldDungeon
5 Indoor stage or viewer stage ("ビューワー") ActorViewer

Maps that have the same stage type typically use the same subsystems and share most characteristics. For example, all open world stages use the Tera height map terrain system and load map units in the same way.

StageBinders

Stage binder types[2]
Type Description
0 OpenWorldStage
1 IndoorStage (CDungeon, ...)
2 MainFieldDungeonStage
3 TitleStage
4 StartupSaveCheckStage
5 Viewer

Fade types

Type Description
0
1
2 Show logo[3]

GameScene state strings

List of state strings in 1.5.0 (incomplete)[4]
Name Description
1st Demo mode [check]
2nd Demo mode
初回シーケンス Initial sequence - New save
TitleMenu Title menu
Presentation Demo mode
E3_2016/Presentation Demo mode
StartupSaveCheckStage
Viewer
CDungeon Shrine world
MainFieldDungeonStage Divine beasts and final trial
MainField The normal overworld
GameTestField
GameTestField2
AocField Trial of the Sword world
GameTestDungeon
MonolithTestDungeon
SrdTestDungeon
MarioClubTestDungeon
TestField
研修用
MonolithTest100enemy
MinimumField
ActorViewer

Init

Initial state

The initial state the game launches into is determined by GameScene[5].

const bool isFirstLaunch = SaveSystem::sInstance->isFirstLaunch();
State* state = isFirstLaunch ? &state_NewSave : &state_LunchTitle;

if ( aocManager::sInstance && aocManager::sInstance->flags & 2 )
  nn::err::ShowUnacceptableAddOnContentVersionError();

const bool isDemo = E3Mgr::sInstance && E3Mgr::sInstance->isDemoMode();
if (isDemo)
  state = &state_LunchTitle;

if (!isDemo && isFirstLaunch)
  sIsFirstNonDemoLaunch = 1;

StateMachine::changeState(&this->stateMachine, state);

States

Note: when the Indoor stage binder is initialised and if the map name changes, a "dungeon" telemetry report is emitted with "leave" or "enter" as the event name and the old/new map name as additional data[6].

StageMgr

StageSelect

StageTransition

Entered before stage generation starts and after Fade (loading screen) has been initialised and made visible. This state machine state is a noop.

LunchTitle

LunchTitle (sic) is entered when the game is launched. The internal state string is "TitleMenu" or (in demo mode) "2nd".

The run function is extremely simple: it simply creates the TitleStage binder (with doNotShowLogo=true[7]) when the "common run" status (see below) is 0xa, then calls the "common run" function (with isNewSave=false[8]).

NewSave

Entered on the first boot or when the new game option is selected. The associated state string is "初回シーケンス" ("initial sequence").

PatchError

Main loop

Three GameScene functions are called in a row from RootTask (see Executable) after initialisation has completed, i.e. in the game's main loop. (Note: these 3 names are unofficial.)

precalc

  • FadeProgress: Update the progress gauge on the Fade screen (animated).
  • Update current map name based on player position (when Link is not in a dungeon).
  • Run StageMgr and StageSelect code.
  • If a flag is set, run the final step of stage generation. (Unused?)
  • If stage status is "NeedsGeneration":
    • Call some MCMgr function at 0x71007A9198.
    • Run save upload subsystem if needed.
    • Call GameScene::genStage with second argument being !EventMgr::sInstance->hasActiveEvent() || EventMgr::sInstance->getActiveEvent()->name != "Demo169_0".
  • If stage status is "NeedsUnload":
    • Call some MCMgr function at 0x71007A9198.
    • Run save upload subsystem if needed.
    • Call GameScene::unloadStage.
  • If no stage is being unloaded, call this->activeStageBinder->getStage()->preCalc.
  • ??? (something involving GameScene Subsystem #12)
  • Call some MCMgr function at 0x71007A9198, again.
  • If the current state is StageMgr:
    • Reset the current stage binder by setting a flag for StageMgr if needed (after a Blood Moon[check])
    • If a forced blood moon is ready
      • If panic blood moons can be triggered (see Blood moon), call the Blood Moon demo (Demo011_0).
      • Report the panic blood moon via the telemetry system.
    • If any panic condition is true, and if panic blood moons are enabled[9], request a panic blood moon by setting a SkyMgr flag. SkyMgr will start a 90 frame timer (3 seconds) and set a ready flag once it has expired. The timer is reset every time the panic blood moon is temporarily inhibited.

calc

postcalc

Common state run function

Called from StageSelectRun, LunchTitleRun and NewSaveRun.

  • Status 0:
    • Start loading
      • Finish startup logo (Switch)[10]
      • If the state string is set to 初回シーケンス, clear the Resource system cache ("ClearAllCaches")[11].
      • Debug stuff[12].
      • E3 Demo stuff[13].
      • Show the Fade screen (loading screen) if the state string does not[14] end with "Viewer" or is not any of the following strings: 1st, 2nd, Presentation, TitleMenu, 初回シーケンス, StartupSaveCheckStage
        • And then show the FadeStatus[15] and the LoadSaveIcon screens[16].
        • Otherwise, only open the Fade screen but do not show loading progress[17].
      • StageSelect stuff[18].
      • Stop "resource compaction" and wait for it to be stopped[19].
      • If the stage string starts with CDungeon[20] or MainFieldDungeonStage[21], start loading the associated DungeonPack[22].
      • BaseProcMgr: start ActorCreate initializer thread[23][check].
      • FadeProgress: reset internal state[24], set progress to 0%[25] and mark loading as active[26].
  • Status 2:
    • If the GameScene state machine's current state is StageSelect or NewSave, do something involving LayerMgrTask and the Renderer.[check]
  • Status 0xa:
    • TipsMgr: update tips if the loading screen is visible (not just opened). TipsMgr will load tips depending on the stage that is being loaded.
  • Status 0xb:
    • Set GameScene's isNewSave property.
    • Reset status to 0.
    • Change GameScene state to StageTransition[27].
    • Set stage status to "NeedsGeneration" (2)[28].

Stage generation

  • Terrain::sInstance->flags |= 0x180u
  • Step 0
    • Reload Title.pack if the stage that needs to be generated is TitleStage (3)[29].
    • StageSelect checks[30]
  • Step 1
    • If a pack was loaded by DungeonPackMgr, wait for DungeonPack loading to finish[31] and switch active pack to the dungeon pack.
  • Step 2
    • If the stage to load is TitleStage, wait for TitlePack loading to finish[32] and switch active pack to the title pack.
  • Step 3: start stage generation[33]
    • PlacementMgr
    • ActorSystem::sInstance->field_13A = 0
    • Update current map flags (e.g. sIsDungeon)
    • Clear BaseProcMgr ActorCreate queue[check]
    • Create uking::Stage::ForBaseProcDual heap (if not already done), which will be used for actors, ActorCreator and BaseProcMgr
    • ActorSystem::sInstance->field_139 = 0
    • If the state string starts with 初回シーケンス, MainField, GameTestField, GameTestField2, AocField, CDungeon, MainFieldDungeonStage, GameTestDungeon, MonolithTestDungeon, SrdTestDungeon, MarioClubTestDungeon, TestField, 研修用, MonolithTest100enemy, MinimumField, or ActorViewer, call GameScene::startBgProcessing (0x71007B2054)
    • If "new save" was selected, initialize PauseMenuDataMgr data
    • If the stage to load is TitleStage, load Layout/Title.blarc for ui::LayoutResourceMgr.
    • If "new save" was selected and the awakening demo hasn't been played since the game was launched[34], ask EventMgr to call Demo169_0.
    • Some PhysicsMemSys stuff (0x71007ADBE0).
  • Step 4
    • Wait for completion of Title BG processing (20% of the loading bar)
    • uiManager (0x71007ACD04)
    • Initialize StatisticsMgr paths depending on current map type.
    • Update aoc2's mapType and mapName fields.
  • Step 5
    • PhysicsMemSys stuff (0x71007ACDB8, 0x71007ACDC0, 0x71007ACDD0)
    • BaseProcMgr: request "PreDelete" actors[35]
    • BaseProcMgr: stop ActorCreate initializer thread and clean up internal state[check]
    • agl::lyr::Renderer and Graphics stuff
  • Step 6
    • Load env.genvb binary (gsys::ModelSceneEnv::clearImpl + loadBinaryImpl)
    • If the stage binder type is 0, 1 or 2 (OpenWorldStage, IndoorStage or MainFieldDungeonStage):
      • Set loading progress to 40%.
      • Graphics stuff, again
      • OnUiActorMgr
      • GameScene::loadTera (on a separate thread)
  • Step 7
    • If the stage binder type is 0, 1 or 2 (OpenWorldStage, IndoorStage or MainFieldDungeonStage):
      • Wait for Tera to load[36]
  • Step 8
    • ...[check]
    • Wait for Tera to generate collision
    • ...[check]
  • Step 9
    • Initialize QuestMgr.
    • Set loading progress to 60%.
  • Step 10
    • Load stage specific resources[37]: if the binder type is StageBinderType::Title (3), the Title layout archive is loaded by LayoutResourceMgr. Otherwise, nothing happens.
  • Step 11
    • #Stage generation step 11
    • Update player saved position, map type, map name, ...
    • Change GameScene state to StageSelect or StageMgr (step 11-6 sets the state pointer to StageMgr).
    • Terrain stuff[check]
    • DungeonPackMgr: clean up state (destroy arena and heap) and unregister entry factory.
    • Set flag 0xa25 (genStageStep12Reached?[check]) on the Fade screen instance.
    • Stop resource compaction and set some flags on the TextureHandleMgr.
  • Step 12
  • Step 13 (final)
    • #Stage generation final step
    • Various flags are set upon completion, for example GameScene stage status is set to 0, isInitializingStage is set to false, etc.
    • FadeProgress is reset.
    • Stage generation debug timer is stopped.
    • aoc2: IsLastPlayHardMode is updated.
    • GameScene::sNeedsOptionLoad is set to true.

Stage generation step 11

  • Step 0: init before stage gen (ステージ生成前の初期化処理)[38]
    • Various flags are set (GameScene, BaseProcMgr, Awareness, EventMgr), in particular field 0x1d12a is set to true if !isNewSave.
    • Set initial position based on the stage binder. This may be overridden with a saved position or an event position later on.
    • GameSceneSubsys2, ActorSystem: set some flags
    • GameSceneSubsys14: Update current location name (game data flag: SaveLocationName). The flag is written to if the player is in a shrine or a Divine Beast. Otherwise, it's read.
    • PhysicsMemSys: set indoor flag if the stage binder type is Indoor (1)
    • aoc2: Set flag 0x1 (IsLastPlayHardMode) if the corresponding game data flag is set. This is what the rest of the game uses to determine if Master Mode is enabled.
    • Effect, Reaction, PhysicsMemSys, EventMgr
    • PlacementMgr, LODMgr, EventMgr, WorldMgr, Awareness, Effect, XLink, VFR
    • aocManager: set latest version played and HasAocVer{1,2,3} flags.
    • Terrain
    • Initialize the sound system and the UI manager
    • If the stage binder type is OpenWorld (0) or the map name is ActorViewer or the current stage is a debug map:
      • Create the HorseMgr instance, initialize it and create the horse actor.
      • Create the WolfLinkMgr instance and initialize it.
      • Create the MotorcycleMgr instance and initialize it.
    • GameSceneSubsys5, GameSceneSubsys4: ? [check]
    • If a flag is set (GameScene @ 0x6e5), SaveSystem::startLoad is called.
    • TipsMgr: Initialize the TipsSystemActor.
  • Step 1: wait for horse generation (馬の生成待ち)
  • Step 2: if the stage binder type is not Title and not Viewer and not StartupSaveCheck, initialize PauseMenuDataMgr (PauseMenuDataMgr::fromSaveData).
  • Step 3: wait for player equipment actor generation to complete (プレイヤーの装備アクターの生成完了待ち): CreatePlayerEquipActorMgr
  • Step 4
    • aocManager: parse MainField static map unit (if aocManager exists)
    • Something involving vectors and calculations[check]
  • Step 5
    • Update FadeProgress based on the queue size of the BaseProcMgr actor create initializer[check] and PlacementMgr load progress[check]. This step represents the last 40% of the progress bar.
    • Start #Stage generation step 11-5b as an async task[39] and wait for it to complete.
    • Stop the Fade screen "color animator".
    • Call this->stage->initForStageGen (vtable @ 0x60). For most stages, this calls WorldMgr's SkyMgr::update.
    • Graphics, uiManager, agl::lyr::Renderer: ?[check]
    • Set this->activeStageBinder (@ 0x2a0) to this->stageBinder (@ 0x2a8)[40].
  • Step 6
    • Set next GameScene state to StageMgr.
    • qword_71025D16C0: ?[check]
    • If the binder type is Title (3):
      • If the ROM type is "RID_Demo": reset some internal state in SaveMgr and SaveSystem.
      • If aoc3 is initialized, set Blight rematch counters to 0 for all four blights.
    • PauseMenuDataMgr: Update IsOpenItemCategory flags if necessary.
  • Step 7: wait for save data upload to finish (if an upload is in progress).
  • Step 8: BaseProcMgr: wait for some actor create initializer event and reset it[check]

Stage generation step 11-5b

  • ProductReporter: reset scene work time (the amount of time since the last scene generation) and reset the blood moon reporter.
  • Destroy the previous stage binder (this->activeStageBinder) if it's different from the current binder (this->stageBinder), and also set this->stage to nullptr.
  • Set the scene change event flow and entry point names:
  • WorldMgr ShootingStarMgr: Update the isMainField flag.
  • AmiiboMgr: Set flag 0x40 if the map name is MainField, otherwise clear it.
  • Create the stage[41].
    • The stage class is automatically selected based on the stage binder type.
    • stage->init and stage->postInit are called here[42].

Stage generation step 12

  • Step 0:
    • [1.4.0+] If BalladOfHeroes_Step02 is false or BalladOfHeroes_Step03 is true, and if the player's equipped weapon (category 0) is Weapon_Sword_502 (One-Hit Obliterator), that weapon is removed from the inventory.
    • FadeProgress is set to 100%.
  • Step 1: Wait for environment map, grass, etc. (環境マップや草などの準備待ち) and set various flags (GameScene globals, Fade, BaseProcMgr).
  • Step 2: Wait for 3 game ticks.
  • Step 3: Terrain stuff[check]
  • Step 4: ?[check]
  • Step 5: Call the scene start event flow.
  • Step 6:
    • Wait for the scene start event flow (シーン開始イベントスタート待ち)
    • Set some flags (Player, WorldMgr, PlacementMgr, ActorSystem)

Stage generation final step

  • Sound, qword_71025D04F0, qword_71025D16C0, qword_71025D1740: ? [check]
  • Clear the temporary stage binder pointer (which was used only during generation).
  • Close the Fade and the FadeStatus screens. This effectively hides the loading screen.
  • TipsMgr: TipsSystemActor is reset and the current date is stored.
  • In dev mode, write a list of all loaded resources to %PROJECT_ROOT%/Log/BootupPatrol/res_title.csv.
  • If the active stage binder type is Title (3) and resident actors haven't been loaded yet, start title background processing.
  • Clear the "has played awakening demo" flag (not the game data flag!) if there is no active event or if the active event is not Demo169_0.
  • Set this->stageGenerated to 1[43].

References

  1. uking::frm::System::gameScene @ 0x10 (Switch)
  2. As returned by the first virtual function in the StageBinderBase interface
  3. See 0x71007B8CD0 and AIDef:Action/ExitGame
  4. The state string is a sead::FixedSafeString<0x100> stored in GameScene @ 0x720.
  5. GameScene::initialize, 0x71007A86CC
  6. StageBinder::initAndReportDungeonLeaveEnter[unofficial name] at 0x71007B79A8
  7. 0x71007B47D8
  8. 0x71007B47F4
  9. GameConfig::sInstance->disablePanicBloodMoons (@ 0x3da on Switch 1.5.0) must be false.
  10. 0x71007AF6F8
  11. 0x71007AFBDC
  12. 0x71007AFDE4
  13. 0x71007AFEF4
  14. 0x71007AFF08
  15. 0x71007AFFC4
  16. 0x71007AFFCC
  17. See function at 0x71007B0C60
  18. 0x71007B0000
  19. 0x71007B00B4 (stop compaction) to 0x71007B010C (end of the busy loop)
  20. 0x71007B0124
  21. 0x71007B0160
  22. 0x71007B0190
  23. 0x71011BF1C4
  24. 0x71007B01D4
  25. 0x71007B01E0
  26. 0x71007B01E8
  27. 0x71007B1058
  28. 0x71007B105C
  29. 0x71007AC8A0
  30. 0x71007AD3AC
  31. DungeonPack読み込み待ち
  32. TitlePack読み込み待ち
  33. ステージ生成開始
  34. 0x71007ADB3C
  35. 0x71007ACDE4
  36. tera読み込み待ち
  37. ステージ固有リソースの読み込み待ち
  38. The function can be found at 0x71007B15A8 in Switch 1.5.0.
  39. 0x71007B2C78
  40. 0x71007B1A88
  41. 0x71007B3C5C
  42. 0x71007CC024
  43. 0x71007B2038