Skip to content

Missing-world fallback: load a default world with an in-world browser - #170

Merged
sidequestlegend merged 3 commits into
feature/greenfieldfrom
feature/world-fallback
Sep 9, 2026
Merged

sidequestlegend merged 3 commits into
feature/greenfieldfrom
feature/world-fallback

Conversation

@sidequestlegend

Copy link
Copy Markdown
Contributor

When a space URL produces nothing - a DNS failure, a 404 or plain web page that never constructs the SDK scene, or a page that reaches SCENE_READY with zero objects - BSScene now abandons the load and takes the player to a known world instead of leaving them behind the loading cage (or opening it into a void). The fallback world is the combined scene bundle at MISSING_WORLD_ASSET_URL; inside it an interactive BSBrowser opens the address the user typed, with a BSText label above it explaining that the world does not exist so we opened the address in a browser instead.

How it works

  • A pure decision (MissingWorldFallback.Evaluate) is polled while a load waits: nothing registered AND (browser/JS failure after a 1 s grace, OR ready-but-empty after the empty-scene grace, OR no SDK scene constructed within MissingWorldTimeoutSeconds). Pages that did construct the scene are never timed out. User cancels are never redirected.
  • The fallback reuses the normal load path: LoadUrl became a wrapper over LoadUrlInternal(displayUrl, pageUrl, ...), and LoadMissingWorldFallback navigates the space browser to a small page shipped in this package (Resources/MissingWorld/missing-world.html, served as a base64 data: URL built by MissingWorldPage). Under the SDK JS that Ora injects into every page, that page loads the world.asset, sets the spawn point and creates the label and browser exactly like a real world would, so the cage, networking and spawn placement all behave normally. CurrentUrl keeps the user's URL so the address bar, Rejoin and history still show it.
  • BSPipe ignores loadFailed with ERR_ABORTED (-3): Ora forwards did-fail-load for any code, and -3 is what a page still loading reports when the next LoadUrl interrupts it. Cancelling the newer load on that was also a latent bug for portals and mid-load joins.
  • BSLink.LoadUrl takes an abort predicate so a page that never reaches SCENE_READY cannot park the load body forever.
  • The data URL carries a #OraDefault/ fragment so OraView's own error-page redirect guard leaves the fallback page alone.
  • A superseded LoadUrl body no longer fires OnUnitySceneLoad for the URL it lost to (pre-existing latent bug).
  • New BSSceneEvents.OnMissingWorldFallback(originalUrl) and public IsFallbackWorld / FallbackOriginalUrl / Registered*Count for app code.

When a space URL produces nothing - a DNS failure, a 404 or plain web page
that never constructs the SDK scene, or a page that reaches SCENE_READY with
zero objects - BSScene now abandons the load and takes the player to a
known world instead of leaving them behind the loading cage (or opening it
into a void). The fallback world is the combined scene bundle at
MISSING_WORLD_ASSET_URL; inside it an interactive BSBrowser opens the
address the user typed, with a BSText label above it explaining that the
world does not exist so we opened the address in a browser instead.

How it works
- A pure decision (MissingWorldFallback.Evaluate) is polled while a load
  waits: nothing registered AND (browser/JS failure after a 1 s grace, OR
  ready-but-empty after the empty-scene grace, OR no SDK scene constructed
  within MissingWorldTimeoutSeconds). Pages that did construct the scene
  are never timed out. User cancels are never redirected.
- The fallback reuses the normal load path: LoadUrl became a wrapper over
  LoadUrlInternal(displayUrl, pageUrl, ...), and LoadMissingWorldFallback
  navigates the space browser to a small page shipped in this package
  (Resources/MissingWorld/missing-world.html, served as a base64 data: URL
  built by MissingWorldPage). Under the SDK JS that Ora injects into every
  page, that page loads the world.asset, sets the spawn point and creates
  the label and browser exactly like a real world would, so the cage,
  networking and spawn placement all behave normally. CurrentUrl keeps the
  user's URL so the address bar, Rejoin and history still show it.
- BSPipe ignores loadFailed with ERR_ABORTED (-3): Ora forwards did-fail-load
  for any code, and -3 is what a page still loading reports when the next
  LoadUrl interrupts it. Cancelling the newer load on that was also a latent
  bug for portals and mid-load joins.
- BSLink.LoadUrl takes an abort predicate so a page that never reaches
  SCENE_READY cannot park the load body forever.
- The data URL carries a #OraDefault/ fragment so OraView's own error-page
  redirect guard leaves the fallback page alone.
- A superseded LoadUrl body no longer fires OnUnitySceneLoad for the URL it
  lost to (pre-existing latent bug).
- New BSSceneEvents.OnMissingWorldFallback(originalUrl) and public
  IsFallbackWorld / FallbackOriginalUrl / Registered*Count for app code.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Sep 9, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Essentials

Run ID: 15d9d62e-4ea0-4a21-b79c-f340cf7f83f3

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Comment @coderabbitai help to get the list of available commands.

shane and others added 2 commits September 9, 2026 16:47
Narrow the trigger to the one case that was asked for: the injected page
script reporting that no objects were created (SceneState.NOTHING_20S /
NOTHING) while nothing is registered on the Unity side. Every other way a
load can go wrong keeps its existing behaviour and still surfaces on the
loading cage as an error: the browser failing to load the page, the page's
own load-failed message, a user or app cancel, and a page that reaches
SCENE_READY with nothing in it.

MissingWorldFallback.ShouldFallBack(enabled, isFallbackWorld,
hasRegisteredContent, loadFailed, state) replaces the reason enum; the
post-cancel grace, the empty-scene switch and the C# no-scene timeout are
gone with it. The load body's wait is back to "loaded, superseded, failed,
or NOTHING reported"; HasLoadFailed() stays in the abort predicate so a
failed page cannot park BSLink.LoadUrl forever when its error-page redirect
overwrites LOAD_FAILED a frame later.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ording

From the first in-editor run: the label wrapped to four lines of large
glyphs over a smallish panel. Browser scale 1.5 -> 2.5 (~2.5 m wide) at 3 m
instead of 2.5 m, label font size 2.5 -> 1 with a 5 m wrap width so it stays
on one line just above the panel, and the text no longer quotes the URL:
"We couldn't find that world, so we opened the browser instead."

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@sidequestlegend
sidequestlegend merged commit 9b88a39 into feature/greenfield Sep 9, 2026
1 of 2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant