diff --git a/.gitignore b/.gitignore
index 1a756e4c..666a9d05 100644
--- a/.gitignore
+++ b/.gitignore
@@ -88,3 +88,4 @@ Assets/Digger/
Assets/Samples/
Assets/Silantro/
Assets/Runtime/StraightFour/3rd-party/
+.worldkit/
diff --git a/Assets/Runtime/Handlers/JavascriptHandler/APIs/Input/Scripts/Input.cs b/Assets/Runtime/Handlers/JavascriptHandler/APIs/Input/Scripts/Input.cs
index fbad2562..0691d8d2 100644
--- a/Assets/Runtime/Handlers/JavascriptHandler/APIs/Input/Scripts/Input.cs
+++ b/Assets/Runtime/Handlers/JavascriptHandler/APIs/Input/Scripts/Input.cs
@@ -627,6 +627,13 @@ public static bool AddRigFollower(BaseEntity entityToFollowRig)
WebVerseRuntime.Instance.vrRig.rigFollowers.Add(entityToFollowRig.internalEntity);
}
}
+
+ // The rig is now the sole writer of this entity's position via UpdateFollowers.
+ // Suppress the entity's own FixedUpdate motion to prevent two-writer ghosting.
+ if (entityToFollowRig.internalEntity is StraightFour.Entity.CharacterEntity ce)
+ {
+ ce.externalPositionControl = true;
+ }
return true;
}
@@ -714,6 +721,12 @@ public static bool RemoveRigFollower(BaseEntity entityToFollowRig)
WebVerseRuntime.Instance.vrRig.rigFollowers.Remove(entityToFollowRig.internalEntity);
}
}
+
+ // Restore entity-owned FixedUpdate motion now that the rig no longer drives position.
+ if (entityToFollowRig.internalEntity is StraightFour.Entity.CharacterEntity ce)
+ {
+ ce.externalPositionControl = false;
+ }
return true;
}
diff --git a/Assets/Runtime/Handlers/JavascriptHandler/APIs/WorldBrowserUtilities/Scripts/World.cs b/Assets/Runtime/Handlers/JavascriptHandler/APIs/WorldBrowserUtilities/Scripts/World.cs
index 584e2cea..9b539da0 100644
--- a/Assets/Runtime/Handlers/JavascriptHandler/APIs/WorldBrowserUtilities/Scripts/World.cs
+++ b/Assets/Runtime/Handlers/JavascriptHandler/APIs/WorldBrowserUtilities/Scripts/World.cs
@@ -28,6 +28,15 @@ public static string GetQueryParam(string key)
return WebVerseRuntime.Instance.straightFour.GetParam(key);
}
+ ///
+ /// Get the URL of the currently loaded World or Web Page.
+ ///
+ /// The URL of the current World or Web Page, or null if none has been loaded.
+ public static string GetWorldURL()
+ {
+ return WebVerseRuntime.Instance.currentURL;
+ }
+
///
/// Get the current World Load State.
///
@@ -59,6 +68,19 @@ public static string GetWorldLoadState()
///
/// The URL of the World to load.
public static void LoadWorld(string url)
+ {
+ LoadWorld(url, null);
+ }
+
+ ///
+ /// Load a World from a URL, along with a script to run in the same JINT engine as the world's
+ /// own scripts.
+ ///
+ /// The URL of the World to load.
+ /// Either inline JavaScript logic, or a URI ending in ".js" pointing
+ /// to a script resource. The script is prepended to the world's script list and runs first.
+ /// Only supported for VEML worlds; ignored for x3d and glTF worlds.
+ public static void LoadWorld(string url, string requireScript)
{
WebVerseRuntime.Instance.LoadWorld(url, new System.Action((name) =>
{
@@ -68,7 +90,33 @@ public static void LoadWorld(string url)
multibar.ToggleMultibar();
multibar.ToggleMultibar();
}
- }));
+ }), requireScript);
+ }
+
+ ///
+ /// Dry-run validation of a World's VEML without switching to it. Downloads and parses the
+ /// VEML, downloads (but does not execute) referenced scripts, and HEAD-requests referenced
+ /// asset URIs. Reports the result via the JS callback. Does not unload the active world,
+ /// mutate runtime state, or touch the JINT engine.
+ ///
+ /// The URL of the World to test.
+ /// Name of a JS function to invoke when the test completes. The
+ /// function is called with three arguments: (success: bool, errorMessage: string|null, title:
+ /// string|null). On success, errorMessage is null. On failure, errorMessage is a
+ /// newline-separated list of issues. title is the parsed metadata.title when the document
+ /// parsed, otherwise null.
+ public static void TestLoadWorld(string url, string onTestComplete)
+ {
+ WebVerseRuntime.Instance.TestLoadWorld(url,
+ new System.Action((success, errorMessage, title) =>
+ {
+ if (string.IsNullOrEmpty(onTestComplete))
+ {
+ return;
+ }
+ WebVerseRuntime.Instance.javascriptHandler.CallWithParams(
+ onTestComplete, new object[] { success, errorMessage, title });
+ }));
}
///
diff --git a/Assets/Runtime/Handlers/JavascriptHandler/Tests/WorldAPITests.cs b/Assets/Runtime/Handlers/JavascriptHandler/Tests/WorldAPITests.cs
new file mode 100644
index 00000000..bd7bc5fe
--- /dev/null
+++ b/Assets/Runtime/Handlers/JavascriptHandler/Tests/WorldAPITests.cs
@@ -0,0 +1,259 @@
+// Copyright (c) 2019-2026 Five Squared Interactive. All rights reserved.
+
+using NUnit.Framework;
+using UnityEngine;
+using UnityEngine.TestTools;
+using FiveSQD.WebVerse.Runtime;
+using FiveSQD.WebVerse.LocalStorage;
+using System.IO;
+using System.Reflection;
+using System.Text.RegularExpressions;
+using WorldAPI = FiveSQD.WebVerse.Handlers.Javascript.APIs.Utilities.World;
+
+///
+/// Unit tests for the World JavaScript API.
+///
+public class WorldAPITests
+{
+ private WebVerseRuntime runtime;
+ private GameObject runtimeGO;
+ private string testDirectory;
+
+ [OneTimeSetUp]
+ public void OneTimeSetUp()
+ {
+ LogAssert.ignoreFailingMessages = true;
+ }
+
+ [SetUp]
+ public void SetUp()
+ {
+ LogAssert.ignoreFailingMessages = true;
+
+ runtimeGO = new GameObject("runtime");
+ runtime = runtimeGO.AddComponent();
+
+ runtime.highlightMaterial = new Material(Shader.Find("Standard"));
+ runtime.skyMaterial = new Material(Shader.Find("Standard"));
+ runtime.characterControllerPrefab = new GameObject("DummyCharacterController");
+ runtime.inputEntityPrefab = new GameObject("DummyInputEntity");
+ runtime.voxelPrefab = new GameObject("DummyVoxel");
+ runtime.webVerseWebViewPrefab = new GameObject("DummyWebView");
+
+ testDirectory = Path.Combine(Path.GetTempPath(), "WorldAPITests");
+ runtime.Initialize(LocalStorageManager.LocalStorageMode.Cache, 128, 128, 128, testDirectory);
+ }
+
+ [TearDown]
+ public void TearDown()
+ {
+ WebVerseRuntime.Instance = null;
+ if (runtime != null && Directory.Exists(testDirectory))
+ {
+ Directory.Delete(testDirectory, true);
+ }
+ if (runtimeGO != null)
+ {
+ Object.DestroyImmediate(runtimeGO);
+ }
+ }
+
+ private static void SetCurrentURL(WebVerseRuntime runtime, string url)
+ {
+ PropertyInfo prop = typeof(WebVerseRuntime).GetProperty(
+ "currentURL", BindingFlags.Public | BindingFlags.Instance);
+ Assert.NotNull(prop, "currentURL property must exist on WebVerseRuntime.");
+ prop.SetValue(runtime, url);
+ }
+
+ [Test]
+ public void GetWorldURL_BeforeAnyLoad_ReturnsNull()
+ {
+ Assert.IsNull(WorldAPI.GetWorldURL());
+ }
+
+ [Test]
+ public void GetWorldURL_AfterCurrentURLSet_ReturnsThatURL()
+ {
+ const string url = "https://example.test/world.veml";
+ SetCurrentURL(runtime, url);
+
+ Assert.AreEqual(url, WorldAPI.GetWorldURL());
+ }
+
+ [Test]
+ public void GetWorldURL_ReflectsLatestAssignment()
+ {
+ SetCurrentURL(runtime, "https://example.test/first.veml");
+ SetCurrentURL(runtime, "https://example.test/second.veml");
+
+ Assert.AreEqual("https://example.test/second.veml", WorldAPI.GetWorldURL());
+ }
+
+ [Test]
+ public void LoadWorld_SetsCurrentURL()
+ {
+ const string url = "https://example.test/load-world.veml";
+
+ // The full load pipeline pulls in handlers and HTTP that aren't wired
+ // up in this test context, so downstream work may throw. We only care
+ // that the currentURL assignment at the top of LoadWorld ran.
+ try { runtime.LoadWorld(url, null); } catch { }
+
+ Assert.AreEqual(url, WorldAPI.GetWorldURL());
+ }
+
+ [Test]
+ public void LoadWebPage_SetsCurrentURL()
+ {
+ const string url = "https://example.test/page.html";
+
+ // The placeholder WebView in this test context isn't fully set up, so LoadURL on it
+ // intentionally errors. We only care that currentURL was assigned at the top of LoadWebPage
+ // before the WebView call ran.
+ LogAssert.Expect(LogType.Error, "[WebVerseWebView->LoadURL] WebVerse WebView not set up.");
+ try { runtime.LoadWebPage(url, null); } catch { }
+
+ Assert.AreEqual(url, WorldAPI.GetWorldURL());
+ }
+
+ [Test]
+ public void LoadWorld_WithInlineRequireScript_AcceptsArgument()
+ {
+ const string url = "https://example.test/with-require.veml";
+
+ // The new overload should accept an inline JS body without throwing at the
+ // signature/dispatch boundary. Downstream load machinery may still throw.
+ try { runtime.LoadWorld(url, null, "var __requireSentinel = 1;"); } catch { }
+
+ Assert.AreEqual(url, WorldAPI.GetWorldURL());
+ }
+
+ [Test]
+ public void LoadWorld_WithURIRequireScript_AcceptsArgument()
+ {
+ const string url = "https://example.test/with-require-uri.veml";
+
+ try { runtime.LoadWorld(url, null, "init.js"); } catch { }
+
+ Assert.AreEqual(url, WorldAPI.GetWorldURL());
+ }
+
+ [Test]
+ public void LoadWorld_DefaultRequireScript_BackwardCompatible()
+ {
+ // The single-onLoaded overload signature still works (default param = null).
+ const string url = "https://example.test/no-require.veml";
+
+ try { runtime.LoadWorld(url, null); } catch { }
+
+ Assert.AreEqual(url, WorldAPI.GetWorldURL());
+ }
+
+ [Test]
+ public void JSAPI_LoadWorld_OneArg_Compiles()
+ {
+ // Verifies the World.LoadWorld(url) overload remains callable.
+ try { WorldAPI.LoadWorld("https://example.test/one-arg.veml"); } catch { }
+ }
+
+ [Test]
+ public void JSAPI_LoadWorld_TwoArg_Compiles()
+ {
+ // Verifies the new World.LoadWorld(url, requireScript) overload is callable.
+ try
+ {
+ WorldAPI.LoadWorld("https://example.test/two-arg.veml", "var __sentinel = 1;");
+ }
+ catch { }
+ }
+
+ [Test]
+ public void TestLoadWorld_DoesNotMutateCurrentURL()
+ {
+ // Pre-condition: simulate a previously loaded world.
+ const string sentinel = "https://example.test/already-loaded.veml";
+ SetCurrentURL(runtime, sentinel);
+
+ try
+ {
+ runtime.TestLoadWorld("https://example.test/test-target.veml",
+ (success, errorMessage, title) => { });
+ }
+ catch { }
+
+ // The contract: TestLoadWorld must not overwrite currentURL even if the network
+ // call later fails or hangs.
+ Assert.AreEqual(sentinel, WorldAPI.GetWorldURL());
+ }
+
+ [Test]
+ public void TestLoadWorld_RejectsNonVEMLExtensions()
+ {
+ bool callbackFired = false;
+ bool reportedSuccess = true;
+ string reportedError = null;
+
+ try
+ {
+ runtime.TestLoadWorld("https://example.test/world.glb",
+ (success, errorMessage, title) =>
+ {
+ callbackFired = true;
+ reportedSuccess = success;
+ reportedError = errorMessage;
+ });
+ }
+ catch { }
+
+ Assert.IsTrue(callbackFired, "Callback should fire synchronously for non-VEML extensions.");
+ Assert.IsFalse(reportedSuccess);
+ StringAssert.Contains("VEML", reportedError);
+ }
+
+ [Test]
+ public void TestLoadWorld_X3DAlsoRejected()
+ {
+ bool callbackFired = false;
+ bool reportedSuccess = true;
+
+ try
+ {
+ runtime.TestLoadWorld("https://example.test/world.x3d",
+ (success, errorMessage, title) =>
+ {
+ callbackFired = true;
+ reportedSuccess = success;
+ });
+ }
+ catch { }
+
+ Assert.IsTrue(callbackFired);
+ Assert.IsFalse(reportedSuccess);
+ }
+
+ [Test]
+ public void JSAPI_TestLoadWorld_Compiles()
+ {
+ // Verifies the JS-facing World.TestLoadWorld(url, callbackName) signature is callable.
+ try
+ {
+ WorldAPI.TestLoadWorld("https://example.test/world.veml", "onTestComplete");
+ }
+ catch { }
+ }
+
+ [Test]
+ public void JSAPI_TestLoadWorld_NullCallback_DoesNotThrow()
+ {
+ // A null/empty callback name should be tolerated (just no JS invocation).
+ Assert.DoesNotThrow(() =>
+ {
+ try
+ {
+ WorldAPI.TestLoadWorld("https://example.test/world.glb", null);
+ }
+ catch { }
+ });
+ }
+}
diff --git a/Assets/Runtime/Handlers/JavascriptHandler/Tests/WorldAPITests.cs.meta b/Assets/Runtime/Handlers/JavascriptHandler/Tests/WorldAPITests.cs.meta
new file mode 100644
index 00000000..0c6c48e8
--- /dev/null
+++ b/Assets/Runtime/Handlers/JavascriptHandler/Tests/WorldAPITests.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 3ebf932f86bb43babcd6706210a81af1
diff --git a/Assets/Runtime/Handlers/VEMLHandler/Scripts/VEMLHandler.cs b/Assets/Runtime/Handlers/VEMLHandler/Scripts/VEMLHandler.cs
index ec60d65f..097839ad 100644
--- a/Assets/Runtime/Handlers/VEMLHandler/Scripts/VEMLHandler.cs
+++ b/Assets/Runtime/Handlers/VEMLHandler/Scripts/VEMLHandler.cs
@@ -122,7 +122,7 @@ public void GetWorldName(string resourceURI, Action onComplete)
/// URI of the world file.
/// Action to invoke upon completion of world loading.
/// Provides a success/fail indication.
- public void LoadVEMLDocumentIntoWorld(string resourceURI, Action onComplete)
+ public void LoadVEMLDocumentIntoWorld(string resourceURI, Action onComplete, string requireScript = null)
{
Action onDownloaded = () =>
{
@@ -136,12 +136,286 @@ public void LoadVEMLDocumentIntoWorld(string resourceURI, Action onComplet
}
else
{
- StartCoroutine(ApplyVEMLDocument(veml, Path.GetDirectoryName(resourceURI), onComplete));
+ StartCoroutine(ApplyVEMLDocument(veml, Path.GetDirectoryName(resourceURI), onComplete, requireScript));
}
};
DownloadVEML(resourceURI, onDownloaded);
}
+ ///
+ /// Dry-run validation of a VEML document. Downloads and parses the VEML, downloads (but does
+ /// not execute) referenced scripts, and HEAD-requests referenced asset URIs (meshes, textures,
+ /// audio, images, html links, panorama, sky textures, terrain-layer textures). Does not touch
+ /// the active world, runtime state, currentURL, or the JINT engine.
+ ///
+ /// URI of the VEML document to test.
+ /// Invoked with (success, errorMessage, title). errorMessage is
+ /// null on success; on failure it is a newline-separated list of issues. title is the parsed
+ /// metadata.title if the document parsed, otherwise null.
+ public void TestVEMLDocument(string resourceURI, Action onTestComplete)
+ {
+ Action onDownloaded = () =>
+ {
+ Schema.V3_0.veml veml;
+ try
+ {
+ veml = LoadVEML(Path.Combine(runtime.fileHandler.fileDirectory,
+ FileHandler.ToFileURI(resourceURI)));
+ }
+ catch (Exception ex)
+ {
+ onTestComplete.Invoke(false,
+ "Failed to parse VEML at " + resourceURI + ": " + ex.Message, null);
+ return;
+ }
+
+ if (veml == null)
+ {
+ onTestComplete.Invoke(false,
+ "Not a valid VEML document: " + resourceURI, null);
+ return;
+ }
+
+ StartCoroutine(TestApplyVEMLDocument(veml,
+ Path.GetDirectoryName(resourceURI), onTestComplete));
+ };
+ DownloadVEML(resourceURI, onDownloaded);
+ }
+
+ ///
+ /// Dry-run coroutine for a parsed VEML document. See TestVEMLDocument for the contract.
+ ///
+ private IEnumerator TestApplyVEMLDocument(Schema.V3_0.veml veml, string baseURI,
+ Action onTestComplete)
+ {
+ string formattedBaseURI = VEMLUtilities.FormatURI(baseURI);
+ List errors = new List();
+ string title = null;
+
+ // Metadata structural validation.
+ if (veml.metadata == null)
+ {
+ errors.Add("Missing required field: metadata.");
+ }
+ else
+ {
+ title = veml.metadata.title;
+ if (string.IsNullOrEmpty(title))
+ {
+ errors.Add("Missing required field: metadata.title.");
+ }
+ }
+
+ // Download all script URIs (we never execute them). Inline scripts are skipped — nothing
+ // to check at the URI level.
+ Dictionary scriptResults = new Dictionary();
+ if (veml.metadata != null && veml.metadata.script != null)
+ {
+ foreach (string script in veml.metadata.script)
+ {
+ if (string.IsNullOrEmpty(script) || !script.EndsWith(".js"))
+ {
+ continue;
+ }
+ string fullURI = VEMLUtilities.FullyQualifyURI(script, formattedBaseURI);
+ if (scriptResults.ContainsKey(fullURI))
+ {
+ continue;
+ }
+ scriptResults[fullURI] = null;
+ string capturedURI = fullURI;
+ LoadScriptResourceAsString(fullURI, new Action((content) =>
+ {
+ scriptResults[capturedURI] = content ?? "";
+ }));
+ }
+ }
+
+ // Walk entity tree, collecting asset URIs to HEAD-check.
+ List assetURIs = new List();
+ if (veml.environment != null && veml.environment.entity != null)
+ {
+ foreach (Schema.V3_0.entity ent in veml.environment.entity)
+ {
+ CollectEntityAssetURIs(ent, formattedBaseURI, assetURIs);
+ }
+ }
+
+ // Background-level asset URIs (panorama image, lite procedural sky textures).
+ if (veml.environment != null && veml.environment.background != null)
+ {
+ Schema.V3_0.background bg = veml.environment.background;
+ if (bg.ItemElementName == Schema.V3_0.ItemChoiceType.panorama
+ && bg.Item is string panoramaURI && !string.IsNullOrEmpty(panoramaURI))
+ {
+ assetURIs.Add(VEMLUtilities.FullyQualifyURI(panoramaURI, formattedBaseURI));
+ }
+ else if (bg.ItemElementName == Schema.V3_0.ItemChoiceType.liteproceduralsky
+ && bg.Item is Schema.V3_0.liteproceduralsky lps)
+ {
+ if (!string.IsNullOrEmpty(lps.startextureuri))
+ {
+ assetURIs.Add(VEMLUtilities.FullyQualifyURI(lps.startextureuri, formattedBaseURI));
+ }
+ if (!string.IsNullOrEmpty(lps.cloudstextureuri))
+ {
+ assetURIs.Add(VEMLUtilities.FullyQualifyURI(lps.cloudstextureuri, formattedBaseURI));
+ }
+ }
+ }
+
+ // HEAD-request each unique asset URI. 0 = pending, -1 = HEAD not supported in this build.
+ Dictionary headResults = new Dictionary();
+ foreach (string uri in assetURIs)
+ {
+ if (string.IsNullOrEmpty(uri) || headResults.ContainsKey(uri))
+ {
+ continue;
+ }
+ headResults[uri] = 0;
+#if USE_WEBINTERFACE
+ string capturedURI = uri;
+ Action, byte[]> onHeadResponse =
+ new Action, byte[]>((code, headers, data) =>
+ {
+ headResults[capturedURI] = code == 0 ? -2 : code;
+ });
+ HTTPRequest headReq = new HTTPRequest(uri, HTTPRequest.HTTPMethod.Head, onHeadResponse);
+ headReq.Send();
+#else
+ headResults[uri] = -1;
+#endif
+ }
+
+ // Wait for all scripts and HEAD-requests to settle, or for timeout.
+ float elapsed = 0f;
+ while (elapsed < timeout)
+ {
+ bool allDone = true;
+ foreach (KeyValuePair kv in scriptResults)
+ {
+ if (kv.Value == null) { allDone = false; break; }
+ }
+ if (allDone)
+ {
+ foreach (KeyValuePair kv in headResults)
+ {
+ if (kv.Value == 0) { allDone = false; break; }
+ }
+ }
+ if (allDone) break;
+ yield return new WaitForSeconds(0.25f);
+ elapsed += 0.25f;
+ }
+
+ // Aggregate failures.
+ foreach (KeyValuePair kv in scriptResults)
+ {
+ if (kv.Value == null)
+ {
+ errors.Add("Script load timeout: " + kv.Key);
+ }
+ else if (kv.Value.Length == 0)
+ {
+ errors.Add("Script empty or unreachable: " + kv.Key);
+ }
+ }
+ foreach (KeyValuePair kv in headResults)
+ {
+ if (kv.Value == 0)
+ {
+ errors.Add("Asset URI request timeout: " + kv.Key);
+ }
+ else if (kv.Value == -1)
+ {
+ // Build lacks USE_WEBINTERFACE; we couldn't verify. Don't flag as error.
+ }
+ else if (kv.Value == -2)
+ {
+ errors.Add("Asset URI request failed (network/no response): " + kv.Key);
+ }
+ else if (kv.Value > 399)
+ {
+ errors.Add("Asset URI returned " + kv.Value + ": " + kv.Key);
+ }
+ }
+
+ bool success = errors.Count == 0;
+ string errorMessage = success ? null : string.Join("\n", errors);
+ onTestComplete.Invoke(success, errorMessage, title);
+ }
+
+ ///
+ /// Recursively collect asset URIs referenced by an entity and its descendants. NOTE: when new
+ /// entity types are added to the V3.0 schema with new URI fields, extend this method to pick
+ /// them up — otherwise TestVEMLDocument's asset checks will silently miss them.
+ ///
+ private void CollectEntityAssetURIs(Schema.V3_0.entity ent, string baseURI, List output)
+ {
+ if (ent == null) return;
+
+ // Mesh-based entity types each carry a meshresource[] array.
+ string[] meshResources = null;
+ if (ent is Schema.V3_0.mesh m) meshResources = m.meshresource;
+ else if (ent is Schema.V3_0.airplane a) meshResources = a.meshresource;
+ else if (ent is Schema.V3_0.automobile au) meshResources = au.meshresource;
+ else if (ent is Schema.V3_0.character c) meshResources = c.meshresource;
+
+ if (meshResources != null)
+ {
+ foreach (string mr in meshResources)
+ {
+ if (!string.IsNullOrEmpty(mr))
+ {
+ output.Add(VEMLUtilities.FullyQualifyURI(mr, baseURI));
+ }
+ }
+ }
+
+ if (ent is Schema.V3_0.image img && !string.IsNullOrEmpty(img.imagefile))
+ {
+ output.Add(VEMLUtilities.FullyQualifyURI(img.imagefile, baseURI));
+ }
+ if (ent is Schema.V3_0.audio aud && !string.IsNullOrEmpty(aud.audiofile))
+ {
+ output.Add(VEMLUtilities.FullyQualifyURI(aud.audiofile, baseURI));
+ }
+ if (ent is Schema.V3_0.html h && !string.IsNullOrEmpty(h.url))
+ {
+ output.Add(VEMLUtilities.FullyQualifyURI(h.url, baseURI));
+ }
+
+ // Terrain-layer textures.
+ if (ent is Schema.V3_0.terrain t && t.layer != null)
+ {
+ foreach (Schema.V3_0.terrainlayer layer in t.layer)
+ {
+ if (layer == null) continue;
+ if (!string.IsNullOrEmpty(layer.diffusetexture))
+ {
+ output.Add(VEMLUtilities.FullyQualifyURI(layer.diffusetexture, baseURI));
+ }
+ if (!string.IsNullOrEmpty(layer.normaltexture))
+ {
+ output.Add(VEMLUtilities.FullyQualifyURI(layer.normaltexture, baseURI));
+ }
+ if (!string.IsNullOrEmpty(layer.masktexture))
+ {
+ output.Add(VEMLUtilities.FullyQualifyURI(layer.masktexture, baseURI));
+ }
+ }
+ }
+
+ // Recurse into children (the schema names this field "entity1" because "entity" is taken).
+ if (ent.entity1 != null)
+ {
+ foreach (Schema.V3_0.entity child in ent.entity1)
+ {
+ CollectEntityAssetURIs(child, baseURI, output);
+ }
+ }
+ }
+
///
/// Download a VEML document.
///
@@ -608,7 +882,7 @@ private void FinishVEMLDownload(string uri, int responseCode, byte[] rawData)
/// Base URI of the VEML document.
/// Action to invoke upon completion of world loading.
/// Provides a success/fail indication.
- private IEnumerator ApplyVEMLDocument(Schema.V3_0.veml vemlDocument, string baseURI, Action onComplete)
+ private IEnumerator ApplyVEMLDocument(Schema.V3_0.veml vemlDocument, string baseURI, Action onComplete, string requireScript = null)
{
string formattedBaseURI = VEMLUtilities.FormatURI(baseURI);
@@ -621,7 +895,7 @@ private IEnumerator ApplyVEMLDocument(Schema.V3_0.veml vemlDocument, string base
scriptsDoneProcessing = true;
});
- if (ProcessMetadata(vemlDocument, baseURI, onScriptsProcessed) == false)
+ if (ProcessMetadata(vemlDocument, baseURI, onScriptsProcessed, requireScript) == false)
{
Logging.LogWarning("[VEMLHandler->ApplyVEMLDocument] Error processing metadata.");
onComplete.Invoke(false);
@@ -698,7 +972,7 @@ private IEnumerator ApplyVEMLDocument(Schema.V3_0.veml vemlDocument, string base
/// Action to invoke when scripts are processed. Provides an array of
/// strings containing the script contents.
/// Whether or not the operation succeeded.
- private bool ProcessMetadata(Schema.V3_0.veml vemlDocument, string baseURI, Action onScriptsProcessed)
+ private bool ProcessMetadata(Schema.V3_0.veml vemlDocument, string baseURI, Action onScriptsProcessed, string requireScript = null)
{
string formattedBaseURI = VEMLUtilities.FormatURI(baseURI);
@@ -726,7 +1000,7 @@ private bool ProcessMetadata(Schema.V3_0.veml vemlDocument, string baseURI, Acti
return false;
}
- StartCoroutine(ProcessScripts(vemlDocument, baseURI, onScriptsProcessed));
+ StartCoroutine(ProcessScripts(vemlDocument, baseURI, onScriptsProcessed, requireScript));
if (ProcessInputEvents(vemlDocument, baseURI) == false)
{
@@ -822,12 +1096,33 @@ private bool ProcessEnvironment(Schema.V3_0.veml vemlDocument, string baseURI)
/// Base URI of the VEML document.
/// Action to invoke when scripts are processed. Provides an array of
/// strings containing the script contents.
- private IEnumerator ProcessScripts(Schema.V3_0.veml vemlDocument, string baseURI, Action onProcessed)
+ private IEnumerator ProcessScripts(Schema.V3_0.veml vemlDocument, string baseURI, Action onProcessed, string requireScript = null)
{
string formattedBaseURI = VEMLUtilities.FormatURI(baseURI);
Dictionary scriptsToRun = new Dictionary();
+ // Set up requireScript (loaded ahead of VEML's own scripts so it runs first).
+ string resolvedRequireScript = null;
+ bool requireScriptLoaded = string.IsNullOrEmpty(requireScript);
+ if (!string.IsNullOrEmpty(requireScript))
+ {
+ if (requireScript.EndsWith(".js"))
+ {
+ LoadScriptResourceAsString(VEMLUtilities.FullyQualifyURI(requireScript, formattedBaseURI),
+ new Action((scr) =>
+ {
+ resolvedRequireScript = scr;
+ requireScriptLoaded = true;
+ }));
+ }
+ else
+ {
+ resolvedRequireScript = requireScript;
+ requireScriptLoaded = true;
+ }
+ }
+
// Set up scripts.
if (vemlDocument.metadata.script != null)
{
@@ -858,20 +1153,30 @@ private IEnumerator ProcessScripts(Schema.V3_0.veml vemlDocument, string baseURI
bool allLoaded = true;
do
{
- allLoaded = true;
- foreach (string script in scriptsToRun.Values)
+ allLoaded = requireScriptLoaded;
+ if (allLoaded)
{
- if (script == null)
+ foreach (string script in scriptsToRun.Values)
{
- allLoaded = false;
- yield return new WaitForSeconds(0.25f);
- elapsedTime += 0.25f;
- break;
+ if (script == null)
+ {
+ allLoaded = false;
+ break;
+ }
}
}
+ if (!allLoaded)
+ {
+ yield return new WaitForSeconds(0.25f);
+ elapsedTime += 0.25f;
+ }
} while (allLoaded == false && elapsedTime < timeout);
List scripts = new List();
+ if (!string.IsNullOrEmpty(resolvedRequireScript))
+ {
+ scripts.Add(resolvedRequireScript);
+ }
foreach (string script in scriptsToRun.Values)
{
scripts.Add(script);
diff --git a/Assets/Runtime/Runtime/Scripts/WebVerseRuntime.cs b/Assets/Runtime/Runtime/Scripts/WebVerseRuntime.cs
index c0371e3d..58dbd6f8 100644
--- a/Assets/Runtime/Runtime/Scripts/WebVerseRuntime.cs
+++ b/Assets/Runtime/Runtime/Scripts/WebVerseRuntime.cs
@@ -312,6 +312,14 @@ public struct RuntimeSettings
[Tooltip("Material to use for highlighting.")]
public Material highlightMaterial;
+ ///
+ /// Material to use for the placement preview of entities (the "ghost" mesh shown while
+ /// the user is positioning an entity). If left unassigned, preview meshes render with
+ /// Unity's missing-material pink.
+ ///
+ [Tooltip("Material to use for entity placement previews.")]
+ public Material previewMaterial;
+
///
/// Material to use for the sky.
///
@@ -690,7 +698,11 @@ public void LoadURL(string url, Action onLoaded = null)
///
/// URL containing the world to load.
/// Action to perform on load. Provides string containing loaded world name.
- public void LoadWorld(string url, Action onLoaded)
+ /// Optional. Either inline JavaScript logic or a URI ending in ".js"
+ /// pointing to a script resource. The script is prepended to the world's script list and runs in
+ /// the same JINT engine as the world's own scripts. Only honored for VEML worlds; a warning is
+ /// logged and the script is ignored for x3d and glTF worlds.
+ public void LoadWorld(string url, Action onLoaded, string requireScript = null)
{
if (straightFour == null)
{
@@ -698,6 +710,8 @@ public void LoadWorld(string url, Action onLoaded)
return;
}
+ currentURL = url;
+
if (StraightFour.StraightFour.ActiveWorld != null)
{
UnloadWorld();
@@ -711,6 +725,14 @@ public void LoadWorld(string url, Action onLoaded)
queryParams = url.Substring(url.IndexOf('?') + 1);
}
+ if (!string.IsNullOrEmpty(requireScript)
+ && (baseURL.EndsWith(".x3d") || baseURL.EndsWith(".x3db") || baseURL.EndsWith(".x3dv")
+ || baseURL.EndsWith(".glb") || baseURL.EndsWith(".gltf")))
+ {
+ Logging.LogWarning("[WebVerseRuntime->LoadWorld] requireScript is only supported for "
+ + "VEML worlds; ignoring for " + baseURL);
+ }
+
if (baseURL.EndsWith(".x3d") || baseURL.EndsWith(".x3db") || baseURL.EndsWith(".x3dv"))
{
x3dHandler.GetX3DTitle(baseURL, (title) =>
@@ -828,13 +850,48 @@ public void LoadWorld(string url, Action onLoaded)
enableDefault = Logging.GetConfiguration().enableDefault
};
StraightFour.StraightFour.LoadWorld(title, queryParams);
- vemlHandler.LoadVEMLDocumentIntoWorld(baseURL, onLoadComplete);
+ vemlHandler.LoadVEMLDocumentIntoWorld(baseURL, onLoadComplete, requireScript);
};
vemlHandler.GetWorldName(baseURL, onFound);
}
}
+ ///
+ /// Dry-run validation of a world's VEML document without switching to it. Downloads and
+ /// parses the VEML, downloads (but does not execute) referenced scripts, and HEAD-requests
+ /// referenced asset URIs. Does not unload the active world, mutate currentURL, change runtime
+ /// state, or touch the JINT engine.
+ ///
+ /// URL of the VEML world to test.
+ /// Invoked with (success, errorMessage, title). errorMessage is
+ /// null on success; on failure it is a newline-separated list of issues. title is the parsed
+ /// metadata.title if the document parsed, otherwise null.
+ public void TestLoadWorld(string url, Action onTestComplete)
+ {
+ if (vemlHandler == null)
+ {
+ onTestComplete.Invoke(false, "VEML handler not initialized.", null);
+ return;
+ }
+
+ string baseURL = url;
+ if (url.Contains("?"))
+ {
+ baseURL = url.Substring(0, url.IndexOf('?'));
+ }
+
+ if (baseURL.EndsWith(".x3d") || baseURL.EndsWith(".x3db") || baseURL.EndsWith(".x3dv")
+ || baseURL.EndsWith(".glb") || baseURL.EndsWith(".gltf"))
+ {
+ onTestComplete.Invoke(false,
+ "TestLoadWorld currently supports VEML worlds only.", null);
+ return;
+ }
+
+ vemlHandler.TestVEMLDocument(baseURL, onTestComplete);
+ }
+
///
/// Unload a world.
///
@@ -922,6 +979,7 @@ public void UnloadWorld()
/// Action to perform on load. Provides string indicating web page.
public void LoadWebPage(string url, Action onLoaded)
{
+ currentURL = url;
state = RuntimeState.WebPage;
webverseWebView.Show();
webverseWebView.LoadURL(url);
@@ -1009,6 +1067,7 @@ private void InitializeComponents(LocalStorageManager.LocalStorageMode storageMo
}
straightFour.airplaneEntityPrefab = airplaneEntityPrefab;
straightFour.highlightMaterial = highlightMaterial;
+ straightFour.previewMaterial = previewMaterial;
straightFour.skyMaterial = skyMaterial;
straightFour.liteProceduralSkyMaterial = liteProceduralSkyMaterial;
straightFour.liteProceduralSkyObject = liteProceduralSkyObject;
diff --git a/Assets/Runtime/StraightFour/Entity/Airplane/Scripts/AirplaneEntity.cs b/Assets/Runtime/StraightFour/Entity/Airplane/Scripts/AirplaneEntity.cs
index e14ad7f8..dc781925 100644
--- a/Assets/Runtime/StraightFour/Entity/Airplane/Scripts/AirplaneEntity.cs
+++ b/Assets/Runtime/StraightFour/Entity/Airplane/Scripts/AirplaneEntity.cs
@@ -690,9 +690,11 @@ private void MakePlacing()
gameObject.SetActive(true);
rbody.isKinematic = true;
+ // Disable colliders during placement so the placement raycast passes through the
+ // preview to hit world geometry. See MeshEntity.MakePlacing for context.
foreach (MeshCollider meshCollider in meshColliders)
{
- meshCollider.enabled = true;
+ meshCollider.enabled = false;
}
interactionState = InteractionState.Placing;
}
@@ -770,17 +772,16 @@ private void SetUpPreviewObject()
DestroyImmediate(entity);
}
- Collider collider = previewObject.GetComponent();
- if (collider)
+ // Remove ALL colliders on the preview (root + descendants). See MeshEntity for context.
+ foreach (Collider c in previewObject.GetComponentsInChildren(true))
{
- Destroy(collider);
+ DestroyImmediate(c);
}
- Rigidbody rbody = previewObject.GetComponent();
- if (rbody)
+ foreach (Rigidbody rb in previewObject.GetComponentsInChildren(true))
{
- Destroy(rbody);
- }
+ DestroyImmediate(rb);
+ }
foreach (MeshRenderer rend in previewObject.GetComponentsInChildren())
{
diff --git a/Assets/Runtime/StraightFour/Entity/Automobile/Scripts/AutomobileEntity.cs b/Assets/Runtime/StraightFour/Entity/Automobile/Scripts/AutomobileEntity.cs
index b4f875be..0cb15b8a 100644
--- a/Assets/Runtime/StraightFour/Entity/Automobile/Scripts/AutomobileEntity.cs
+++ b/Assets/Runtime/StraightFour/Entity/Automobile/Scripts/AutomobileEntity.cs
@@ -809,9 +809,11 @@ private void MakePlacing()
gameObject.SetActive(true);
rbody.isKinematic = true;
+ // Disable colliders during placement so the placement raycast passes through the
+ // preview to hit world geometry. See MeshEntity.MakePlacing for context.
foreach (MeshCollider meshCollider in meshColliders)
{
- meshCollider.enabled = true;
+ meshCollider.enabled = false;
}
interactionState = InteractionState.Placing;
}
@@ -889,17 +891,16 @@ private void SetUpPreviewObject()
DestroyImmediate(entity);
}
- Collider collider = previewObject.GetComponent();
- if (collider)
+ // Remove ALL colliders on the preview (root + descendants). See MeshEntity for context.
+ foreach (Collider c in previewObject.GetComponentsInChildren(true))
{
- Destroy(collider);
+ DestroyImmediate(c);
}
- Rigidbody rbody = previewObject.GetComponent();
- if (rbody)
+ foreach (Rigidbody rb in previewObject.GetComponentsInChildren(true))
{
- Destroy(rbody);
- }
+ DestroyImmediate(rb);
+ }
foreach (MeshRenderer rend in previewObject.GetComponentsInChildren())
{
diff --git a/Assets/Runtime/StraightFour/Entity/Base/Scripts/BaseEntity.cs b/Assets/Runtime/StraightFour/Entity/Base/Scripts/BaseEntity.cs
index f8d0b0d8..10e49ea1 100644
--- a/Assets/Runtime/StraightFour/Entity/Base/Scripts/BaseEntity.cs
+++ b/Assets/Runtime/StraightFour/Entity/Base/Scripts/BaseEntity.cs
@@ -94,6 +94,11 @@ public enum InteractionState { Hidden, Static, Physical, Placing }
///
private List seats = new List();
+ ///
+ /// Animation names tracked by this entity's animation control methods.
+ ///
+ private HashSet definedAnimations = new HashSet();
+
///
/// Interaction state of the entity.
///
@@ -731,8 +736,10 @@ public virtual bool PlayAnimation(string animationName)
AnimationClip clip = animation.GetClip(animationName);
if (clip != null)
{
+ definedAnimations.Add(animationName);
animation[animationName].weight = 0.1f;
animation.Play(animationName);
+ return true;
}
}
}
@@ -764,6 +771,29 @@ public virtual bool StopAnimation(string animationName)
return false;
}
+ ///
+ /// Stop all animations.
+ ///
+ /// Whether or not any animations were found.
+ public virtual bool StopAllAnimations()
+ {
+ if (definedAnimations.Count > 0)
+ {
+ bool foundAnimation = false;
+ foreach (string animationName in definedAnimations)
+ {
+ if (StopAnimation(animationName))
+ {
+ foundAnimation = true;
+ }
+ }
+
+ return foundAnimation;
+ }
+
+ return false;
+ }
+
///
/// Set the speed of an animation.
///
diff --git a/Assets/Runtime/StraightFour/Entity/Character/Scripts/CharacterEntity.cs b/Assets/Runtime/StraightFour/Entity/Character/Scripts/CharacterEntity.cs
index 11d2d2eb..93538c58 100644
--- a/Assets/Runtime/StraightFour/Entity/Character/Scripts/CharacterEntity.cs
+++ b/Assets/Runtime/StraightFour/Entity/Character/Scripts/CharacterEntity.cs
@@ -132,11 +132,27 @@ public override string entityTag
private GameObject highlightCube;
///
- /// The current applied velocity.
+ /// The current horizontal displacement applied this tick (x and z). Resets after each
+ /// FixedUpdate. y is unused; vertical motion lives in verticalVelocity.
///
private Vector3 currentVelocity = Vector3.zero;
///
+ /// Vertical velocity in meters/second. Integrated by gravity each FixedUpdate; displacement
+ /// is verticalVelocity * Time.deltaTime applied via CharacterController.Move. Jump() and the
+ /// y component of Move(amount) treat this as velocity (m/s), not per-frame displacement.
+ ///
+ private float verticalVelocity = 0f;
+
+ ///
+ /// When true, FixedUpdate skips gravity, grounding, and Move() entirely. Some other system
+ /// (typically the VR rig writing position from rigOrigin every Update via UpdateFollowers)
+ /// is the sole writer of this entity's position, so the entity must not also write or the
+ /// two writers fight and the avatar flickers between positions. Wired via
+ /// Input.AddRigFollower / RemoveRigFollower.
+ ///
+ public bool externalPositionControl = false;
+
/// Avatar animation manager for this character.
///
private AvatarAnimationManager _avatarAnimationManager;
@@ -368,7 +384,8 @@ public bool Move(Vector3 amount, bool synchronize = true)
return false;
}
- currentVelocity = new Vector3(currentVelocity.x + amount.x, currentVelocity.y + amount.y, currentVelocity.z + amount.z);
+ currentVelocity.x += amount.x;
+ currentVelocity.z += amount.z;
characterController.Move(amount);
if (synchronizer != null && synchronize == true)
@@ -402,7 +419,7 @@ public bool Jump(float amount, bool discardIfFalling = true, bool synchronize =
if (IsOnSurface() || !discardIfFalling)
{
- currentVelocity.y += amount;
+ verticalVelocity += amount;
}
if (synchronizer != null && synchronize == true)
@@ -431,7 +448,16 @@ public bool IsOnSurface()
return false;
}
- return Physics.Raycast(transform.position - new Vector3(0, characterController.height / 2, 0), Vector3.down, 0.25f);
+ // CharacterController.isGrounded is the canonical signal; it's updated each Move() with
+ // the controller's internal slope/penetration logic and accounts for skinWidth.
+ if (characterController.isGrounded) return true;
+
+ // Fallback raycast for the pre-first-Move case and as a small-gap safety net.
+ // Distance is skinWidth + a small margin so we catch the "just barely above floor"
+ // state without falsely reporting grounded at large gaps.
+ float rayDistance = characterController.skinWidth + 0.1f;
+ return Physics.Raycast(transform.position - new Vector3(0, characterController.height / 2f, 0),
+ Vector3.down, rayDistance);
}
public bool IsAboveGround()
@@ -1205,6 +1231,19 @@ private void MakePhysical()
}
gameObject.SetActive(true);
+ // Keep Rigidbody kinematic in Physical state — character motion is owned by
+ // CharacterController.Move() in FixedUpdate. A non-kinematic Rigidbody on the same
+ // GameObject causes per-frame position fighting (visible as the avatar/label rendering
+ // at two flickering positions). Defends against SetMotion(Moving) flipping this.
+ if (rigidBody != null)
+ {
+ rigidBody.isKinematic = true;
+ }
+ // Leave capsuleCollider disabled — the CharacterController is the canonical collider
+ // for character motion. Enabling the CapsuleCollider on the same GameObject made the
+ // character settle ~0.5 m above the floor (the CapsuleCollider's center.y) because the
+ // two colliders fight during depenetration. MakeHidden and MakeStatic both disable it
+ // for the same reason; Physical should match.
interactionState = InteractionState.Physical;
}
@@ -1268,38 +1307,45 @@ private void SetUpHighlightVolume()
highlightCube.SetActive(false);
}
- private float timeToWaitForUpdate = 0.025f;
- private float timeWaitedForUpdate = 0;
private int stepToRaise = 1;
private int maxStepToRaise = 1024;
void FixedUpdate()
{
- timeWaitedForUpdate += Time.deltaTime;
- if (timeWaitedForUpdate >= timeToWaitForUpdate)
- {
- timeWaitedForUpdate = 0;
- }
- else
+ // No throttling here — FixedUpdate already runs at the fixed physics rate (50 Hz by
+ // default), which is the correct cadence for gravity integration. The previous throttle
+ // (0.025s) caused FixedUpdate to fire only every other tick at fixedDeltaTime=0.02s but
+ // still used Time.deltaTime=0.02s in the integration math — producing gravity at half
+ // the intended rate.
+ if (characterController == null)
{
+ //LogSystem.LogError("[CharacterEntity->Update] No character controller for character entity.");
return;
}
- if (characterController == null)
+ // If some other system (typically the VR rig via UpdateFollowers) is writing this
+ // entity's position each frame, don't add a second writer here — they would fight and
+ // the avatar would flicker between the two writers' positions.
+ if (externalPositionControl)
{
- //LogSystem.LogError("[CharacterEntity->Update] No character controller for character entity.");
return;
}
- if (IsOnSurface() && currentVelocity.y < 0)
+ // Reset vertical velocity when grounded and falling — prevents gravity from compounding
+ // while on a surface, and zeroes any tiny residual downward velocity from prior ticks.
+ if (IsOnSurface() && verticalVelocity < 0)
{
- currentVelocity.y = 0f;
+ verticalVelocity = 0f;
}
if (rigidBody.useGravity)
{
- currentVelocity.y += -9.81f * Time.deltaTime; // TODO: Magic number, tie into larger gravity system.
+ verticalVelocity += -9.81f * Time.deltaTime; // TODO: tie into larger gravity system.
}
- characterController.Move(currentVelocity);
+
+ // currentVelocity.x/z are per-frame displacement (legacy semantics callers depend on).
+ // verticalVelocity is in m/s — multiply by dt to convert to displacement-this-tick.
+ characterController.Move(new Vector3(
+ currentVelocity.x, verticalVelocity * Time.deltaTime, currentVelocity.z));
currentVelocity.x = currentVelocity.z = 0;
if (fixHeight)
diff --git a/Assets/Runtime/StraightFour/Entity/Mesh/Scripts/MeshEntity.cs b/Assets/Runtime/StraightFour/Entity/Mesh/Scripts/MeshEntity.cs
index 2e252175..700c02de 100644
--- a/Assets/Runtime/StraightFour/Entity/Mesh/Scripts/MeshEntity.cs
+++ b/Assets/Runtime/StraightFour/Entity/Mesh/Scripts/MeshEntity.cs
@@ -377,6 +377,7 @@ public override void Initialize(System.Guid idToSet)
MakeHidden();
SetUpHighlightVolume();
+ StopAllAnimations();
}
///
@@ -637,11 +638,15 @@ private void MakePlacing()
gameObject.SetActive(true);
rigidBody.isKinematic = true;
+ // Disable colliders during placement so the placement raycast (camera/pointer) passes
+ // through the preview to hit world geometry. With colliders on, the entity blocks its
+ // own placement raycast, producing erratic positioning. Make* methods that exit Placing
+ // (Static/Physical) re-enable colliders normally.
foreach (MeshCollider meshCollider in meshColliders)
{
- meshCollider.enabled = true;
+ meshCollider.enabled = false;
}
- boxCollider.enabled = true;
+ boxCollider.enabled = false;
interactionState = InteractionState.Placing;
}
@@ -718,16 +723,18 @@ private void SetUpPreviewObject()
DestroyImmediate(entity);
}
- Collider collider = previewObject.GetComponent();
- if (collider)
+ // Remove ALL colliders on the preview (root + descendants). The previous code only
+ // removed one Collider from the root, so entities with multiple colliders or any
+ // colliders on child GameObjects left the preview raycastable.
+ foreach (Collider c in previewObject.GetComponentsInChildren(true))
{
- Destroy(collider);
+ DestroyImmediate(c);
}
- Rigidbody rbody = previewObject.GetComponent();
- if (rbody)
+ // Remove Rigidbodies from root + descendants for consistency.
+ foreach (Rigidbody rb in previewObject.GetComponentsInChildren(true))
{
- Destroy(rbody);
+ DestroyImmediate(rb);
}
// Strip CollisionEmitter from preview clone to prevent ghost events
diff --git a/Assets/Runtime/StraightFour/Entity/Water/Scripts/WaterBlockerEntity.cs b/Assets/Runtime/StraightFour/Entity/Water/Scripts/WaterBlockerEntity.cs
index 5dce8c8a..f2465716 100644
--- a/Assets/Runtime/StraightFour/Entity/Water/Scripts/WaterBlockerEntity.cs
+++ b/Assets/Runtime/StraightFour/Entity/Water/Scripts/WaterBlockerEntity.cs
@@ -579,7 +579,9 @@ private void MakePlacing()
gameObject.SetActive(true);
rigidBody.isKinematic = true;
- boxCollider.enabled = true;
+ // Disable colliders during placement so the placement raycast passes through the
+ // preview to hit world geometry. See MeshEntity.MakePlacing for context.
+ boxCollider.enabled = false;
interactionState = InteractionState.Placing;
}
@@ -656,17 +658,16 @@ private void SetUpPreviewObject()
DestroyImmediate(entity);
}
- Collider collider = previewObject.GetComponent();
- if (collider)
+ // Remove ALL colliders on the preview (root + descendants). See MeshEntity for context.
+ foreach (Collider c in previewObject.GetComponentsInChildren(true))
{
- Destroy(collider);
+ DestroyImmediate(c);
}
- Rigidbody rbody = previewObject.GetComponent();
- if (rbody)
+ foreach (Rigidbody rb in previewObject.GetComponentsInChildren(true))
{
- Destroy(rbody);
- }
+ DestroyImmediate(rb);
+ }
foreach (MeshRenderer rend in previewObject.GetComponentsInChildren())
{
diff --git a/Assets/Runtime/StraightFour/Entity/Water/Scripts/WaterBodyEntity.cs b/Assets/Runtime/StraightFour/Entity/Water/Scripts/WaterBodyEntity.cs
index 00a70b2c..87f2f4ca 100644
--- a/Assets/Runtime/StraightFour/Entity/Water/Scripts/WaterBodyEntity.cs
+++ b/Assets/Runtime/StraightFour/Entity/Water/Scripts/WaterBodyEntity.cs
@@ -689,7 +689,9 @@ private void MakePlacing()
gameObject.SetActive(true);
rigidBody.isKinematic = true;
- meshCollider.enabled = true;
+ // Disable colliders during placement so the placement raycast passes through the
+ // preview to hit world geometry. See MeshEntity.MakePlacing for context.
+ meshCollider.enabled = false;
interactionState = InteractionState.Placing;
}
@@ -766,17 +768,16 @@ private void SetUpPreviewObject()
DestroyImmediate(entity);
}
- Collider collider = previewObject.GetComponent();
- if (collider)
+ // Remove ALL colliders on the preview (root + descendants). See MeshEntity for context.
+ foreach (Collider c in previewObject.GetComponentsInChildren(true))
{
- Destroy(collider);
+ DestroyImmediate(c);
}
- Rigidbody rbody = previewObject.GetComponent();
- if (rbody)
+ foreach (Rigidbody rb in previewObject.GetComponentsInChildren(true))
{
- Destroy(rbody);
- }
+ DestroyImmediate(rb);
+ }
foreach (MeshRenderer rend in previewObject.GetComponentsInChildren())
{
diff --git a/Assets/Runtime/StraightFour/Testing/EntityTests/CharacterEntityGroundingTests.cs b/Assets/Runtime/StraightFour/Testing/EntityTests/CharacterEntityGroundingTests.cs
new file mode 100644
index 00000000..74c4d4a6
--- /dev/null
+++ b/Assets/Runtime/StraightFour/Testing/EntityTests/CharacterEntityGroundingTests.cs
@@ -0,0 +1,368 @@
+// Copyright (c) 2019-2026 Five Squared Interactive. All rights reserved.
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using NUnit.Framework;
+using UnityEngine;
+using UnityEngine.TestTools;
+using FiveSQD.StraightFour;
+using FiveSQD.StraightFour.Entity;
+using UnityEditor;
+
+///
+/// PlayMode tests that exercise CharacterEntity grounding and gravity behavior to validate four
+/// hypotheses about a VR floating/oscillating bug:
+/// (1) IsOnSurface raycast (0.25 units) is too short to reliably detect contact.
+/// (2) CharacterController.isGrounded is never consulted.
+/// (3) Pure-vertical Move() calls behave differently from mixed-axis ones.
+/// (4) currentVelocity is treated inconsistently as both velocity (m/s) and per-tick displacement.
+///
+/// Each test is self-contained: it builds a floor (or no floor for free-fall) and a CharacterEntity,
+/// then asserts on grounded/position state after a known physics interval. The tests are tuned so
+/// they fail on the current code path and pass with the proposed fixes (longer raycast, isGrounded
+/// fallback, units fix, etc.) — so they double as a regression gate.
+///
+public class CharacterEntityGroundingTests
+{
+ private GameObject weGO;
+ private StraightFour straightFour;
+ private GameObject cameraGO;
+ private GameObject floorGO;
+
+ ///
+ /// Helper: compute the transform.y needed to place the controller's foot at the given world Y.
+ /// CharacterController.center stays at Unity default (0,0,0), so foot = transform.y - height/2.
+ ///
+ private static float TransformYForFoot(CharacterEntity ce, float footY)
+ {
+ CharacterController cc = ce.GetComponent();
+ return footY + cc.height / 2f - cc.center.y;
+ }
+
+ [OneTimeSetUp]
+ public void OneTimeSetUp()
+ {
+ LogAssert.ignoreFailingMessages = true;
+ }
+
+ [SetUp]
+ public void SetUp()
+ {
+ LogAssert.ignoreFailingMessages = true;
+ }
+
+ [TearDown]
+ public void TearDown()
+ {
+ try
+ {
+ if (StraightFour.ActiveWorld != null)
+ {
+ StraightFour.UnloadWorld();
+ }
+ }
+ catch (Exception)
+ {
+ // CameraManager may already be destroyed.
+ }
+ if (floorGO != null) { UnityEngine.Object.DestroyImmediate(floorGO); floorGO = null; }
+ if (cameraGO != null) { UnityEngine.Object.DestroyImmediate(cameraGO); cameraGO = null; }
+ }
+
+ ///
+ /// Builds a StraightFour world, a flat floor at y=0 (top surface), and spawns a CharacterEntity
+ /// at the provided spawnPosition. fixHeight is disabled so the rescue-warp doesn't mask grounding
+ /// bugs. The returned CharacterEntity is fully initialized.
+ ///
+ private IEnumerator BuildSceneAndCharacter(Vector3 spawnPosition, bool buildFloor,
+ Action callback)
+ {
+ LogAssert.ignoreFailingMessages = true;
+
+ cameraGO = new GameObject("TestCamera");
+ Camera camera = cameraGO.AddComponent();
+ camera.transform.position = new Vector3(0, 0, -10);
+ cameraGO.tag = "MainCamera";
+
+ if (buildFloor)
+ {
+ // A wide flat box collider with its top surface at y=0.
+ floorGO = GameObject.CreatePrimitive(PrimitiveType.Cube);
+ floorGO.name = "TestFloor";
+ floorGO.transform.position = new Vector3(0, -0.5f, 0);
+ floorGO.transform.localScale = new Vector3(20f, 1f, 20f);
+ }
+
+ weGO = new GameObject("WE");
+ straightFour = weGO.AddComponent();
+ straightFour.characterControllerPrefab = AssetDatabase.LoadAssetAtPath(
+ "Assets/Runtime/StraightFour/Entity/Character/Prefabs/UserAvatar.prefab");
+ straightFour.skyMaterial = AssetDatabase.LoadAssetAtPath(
+ "Assets/Runtime/StraightFour/Environment/Materials/Skybox.mat");
+ yield return null;
+ StraightFour.LoadWorld("grounding-test");
+
+ bool loaded = false;
+ Guid charId = StraightFour.ActiveWorld.entityManager.LoadCharacterEntity(
+ null, null, Vector3.zero, Quaternion.identity, new Vector3(0, 2, 0),
+ spawnPosition, Quaternion.identity, Vector3.one,
+ tag: "test-char",
+ onLoaded: () => { loaded = true; });
+
+ float elapsed = 0f;
+ while (!loaded && elapsed < 5f)
+ {
+ yield return new WaitForSeconds(0.1f);
+ elapsed += 0.1f;
+ }
+
+ CharacterEntity ce = StraightFour.ActiveWorld.entityManager.FindEntity(charId) as CharacterEntity;
+ Assert.IsNotNull(ce, "CharacterEntity failed to load within 5s.");
+
+ // Initialize() leaves the character in Hidden state (gameObject.SetActive(false)) so
+ // FixedUpdate doesn't run. Switch to Physical to match the live VR scenario.
+ ce.SetInteractionState(BaseEntity.InteractionState.Physical);
+ ce.fixHeight = false; // Disable rescue warp so we observe raw grounding behavior.
+
+ // Re-apply spawn position after going Physical, in case prior state changed transform.
+ ce.SetPosition(spawnPosition, local: true, synchronize: false);
+
+ // Give one fixed tick for the controller to register.
+ yield return new WaitForFixedUpdate();
+
+ callback(ce);
+ }
+
+ ///
+ /// Helper: project the character's foot Y from transform.position and CharacterController height.
+ ///
+ private static float FootY(CharacterEntity ce)
+ {
+ CharacterController cc = ce.GetComponent();
+ return ce.transform.position.y - cc.height / 2f + cc.center.y;
+ }
+
+ // ---------------------------------------------------------------------------------------------
+ // Suspect 1 + 4: After dropping from 3m, the character should settle with foot on the floor.
+ // ---------------------------------------------------------------------------------------------
+
+ [UnityTest]
+ public IEnumerator CharacterEntity_Drops_FromThreeMeters_SettlesOnFloor()
+ {
+ CharacterEntity ce = null;
+ yield return BuildSceneAndCharacter(new Vector3(0, 3f, 0), buildFloor: true, c => ce = c);
+
+ // Let physics settle. Free-fall from 3m takes ~0.78s; allow generous margin.
+ yield return new WaitForSeconds(3f);
+
+ float foot = FootY(ce);
+ Assert.That(foot, Is.EqualTo(0f).Within(0.10f),
+ $"Character did not settle on floor. Foot y = {foot:F3}, expected ~0. " +
+ $"Transform y = {ce.transform.position.y:F3}. Suspect 1 (short raycast), " +
+ $"Suspect 4 (units), or a Rigidbody fighting CharacterController.");
+ }
+
+ // ---------------------------------------------------------------------------------------------
+ // Suspect 1: After landing, the character should hold position. Bobbing > a few mm is the bug.
+ // ---------------------------------------------------------------------------------------------
+
+ [UnityTest]
+ public IEnumerator CharacterEntity_AfterLanding_DoesNotOscillate()
+ {
+ CharacterEntity ce = null;
+ yield return BuildSceneAndCharacter(new Vector3(0, 3f, 0), buildFloor: true, c => ce = c);
+
+ // Wait for initial settle.
+ yield return new WaitForSeconds(3f);
+
+ // Sample foot y over ~1s of physics. With CharacterEntity throttled to ~25 Hz updates,
+ // we sample 40 frames to cover one second comfortably.
+ List samples = new List();
+ for (int i = 0; i < 50; i++)
+ {
+ samples.Add(FootY(ce));
+ yield return new WaitForFixedUpdate();
+ }
+
+ float min = float.MaxValue, max = float.MinValue;
+ foreach (float y in samples) { if (y < min) min = y; if (y > max) max = y; }
+ float swing = max - min;
+
+ Assert.Less(swing, 0.02f,
+ $"Character oscillated by {swing:F4} m after settling (min={min:F4} max={max:F4}). " +
+ "Suspect 1 (short raycast) or Rigidbody-vs-CharacterController fight.");
+ }
+
+ // ---------------------------------------------------------------------------------------------
+ // Suspect 1 direct: IsOnSurface() must return true when the foot is touching the floor.
+ // ---------------------------------------------------------------------------------------------
+
+ [UnityTest]
+ public IEnumerator CharacterEntity_IsOnSurface_TrueAtSmallGapAboveFloor()
+ {
+ CharacterEntity ce = null;
+ yield return BuildSceneAndCharacter(new Vector3(0, 5f, 0), buildFloor: true, c => ce = c);
+
+ // Disable gravity so the position holds while we measure.
+ Rigidbody rb = ce.GetComponent();
+ if (rb != null) rb.useGravity = false;
+
+ CharacterController cc = ce.GetComponent();
+ float targetY = TransformYForFoot(ce, 0.05f);
+
+ // CharacterController suppresses direct transform.position writes during simulation in
+ // some Unity versions. Canonical workaround: disable, teleport, re-enable.
+ cc.enabled = false;
+ ce.transform.position = new Vector3(0, targetY, 0);
+ cc.enabled = true;
+
+ yield return new WaitForFixedUpdate();
+ yield return new WaitForFixedUpdate();
+
+ Assert.IsTrue(ce.IsOnSurface(),
+ $"IsOnSurface returned false when foot was 0.05 m above floor. " +
+ $"Foot y={FootY(ce):F4}, transform y={ce.transform.position.y:F4}, " +
+ $"cc.isGrounded={cc.isGrounded}.");
+ }
+
+ ///
+ /// IsOnSurface SHOULD return false when the gap is well beyond the raycast distance — this
+ /// documents current behavior and pairs with the previous test as a boundary regression.
+ ///
+ [UnityTest]
+ public IEnumerator CharacterEntity_IsOnSurface_FalseAtLargeGapAboveFloor()
+ {
+ CharacterEntity ce = null;
+ yield return BuildSceneAndCharacter(new Vector3(0, 5f, 0), buildFloor: true, c => ce = c);
+
+ Rigidbody rb = ce.GetComponent();
+ if (rb != null) rb.useGravity = false;
+
+ CharacterController cc = ce.GetComponent();
+ float targetY = TransformYForFoot(ce, 1.5f);
+
+ cc.enabled = false;
+ ce.transform.position = new Vector3(0, targetY, 0);
+ cc.enabled = true;
+
+ yield return new WaitForFixedUpdate();
+
+ Assert.IsFalse(ce.IsOnSurface(),
+ $"IsOnSurface returned true at a 1.5 m gap. Foot y={FootY(ce):F4}, " +
+ $"transform y={ce.transform.position.y:F4}, cc.isGrounded={cc.isGrounded}. " +
+ "Either the raycast is too long, or it's hitting something other than the floor.");
+ }
+
+ // ---------------------------------------------------------------------------------------------
+ // Free-fall integration should approximate s = 0.5 * g * t^2.
+ //
+ // Analytic free-fall over t=0.3s: dy = 0.5 * 9.81 * 0.09 ≈ 0.44 m.
+ // Discrete sum at 50 Hz fixed-step: ≈ 0.47 m.
+ // Pre-fix bugs to catch:
+ // - Unit-confusion (velocity stored as displacement): dy ≈ 5–7 m (way over).
+ // - FixedUpdate-throttle gating with mismatched dt: dy ≈ 0.11 m (half-rate, way under).
+ // ---------------------------------------------------------------------------------------------
+
+ [UnityTest]
+ public IEnumerator CharacterEntity_FreeFall_RoughlyMatchesGravity()
+ {
+ CharacterEntity ce = null;
+ // No floor. Spawn high so the character has room to fall.
+ yield return BuildSceneAndCharacter(new Vector3(0, 100f, 0), buildFloor: false, c => ce = c);
+
+ // Let one tick pass to ensure the character is initialized in a normal state.
+ yield return new WaitForFixedUpdate();
+ float startY = ce.transform.position.y;
+
+ yield return new WaitForSeconds(0.3f);
+ float endY = ce.transform.position.y;
+ float dropped = startY - endY;
+
+ Assert.Less(dropped, 0.8f,
+ $"Character fell {dropped:F3} m in 0.3 s. Analytic free-fall is ~0.44 m; >0.8 m suggests " +
+ "the units bug (currentVelocity used as displacement per tick).");
+ Assert.Greater(dropped, 0.25f,
+ $"Character only fell {dropped:F3} m in 0.3 s — significantly less than the expected " +
+ "~0.44 m of free-fall. Suggests gravity is being applied at half rate (FixedUpdate " +
+ "throttle gate using Time.deltaTime instead of the throttle interval), or gravity is " +
+ "otherwise weakened.");
+ }
+
+ // ---------------------------------------------------------------------------------------------
+ // Suspect 2 + 3: CharacterController.isGrounded should be consulted in grounding decisions, and
+ // pure-vertical Move() may behave worse than mixed-axis. This test compares behavior of an
+ // idle character vs one that's been "tickled" with a tiny horizontal perturbation each frame.
+ // If the perturbation produces visibly different (less bouncy) settling, Suspect 3 is real.
+ // ---------------------------------------------------------------------------------------------
+
+ [UnityTest]
+ public IEnumerator CharacterEntity_PureVerticalSettle_NoWorseThan_MixedAxisSettle()
+ {
+ CharacterEntity ce = null;
+ yield return BuildSceneAndCharacter(new Vector3(0, 3f, 0), buildFloor: true, c => ce = c);
+
+ // Phase A: idle settle for 3s, measure final y.
+ yield return new WaitForSeconds(3f);
+ float idleFootY = FootY(ce);
+
+ // Reset position to drop again, this time with tiny horizontal Move()s during fall.
+ ce.SetPosition(new Vector3(0, 3f, 0), local: true, synchronize: false);
+ yield return new WaitForFixedUpdate();
+
+ for (int i = 0; i < 120; i++)
+ {
+ // Tiny non-zero horizontal nudge — invokes the CharacterController's mixed-axis solver.
+ ce.Move(new Vector3(0.0001f, 0, 0), synchronize: false);
+ yield return new WaitForFixedUpdate();
+ }
+ float nudgedFootY = FootY(ce);
+
+ // Both should settle near the floor (y=0). If the nudged version is closer to the floor than
+ // the idle version by more than 5 cm, Suspect 3 is confirmed.
+ float diff = Mathf.Abs(idleFootY - nudgedFootY);
+ Assert.Less(diff, 0.05f,
+ $"Idle-settle foot y = {idleFootY:F4}, nudged-settle foot y = {nudgedFootY:F4}, " +
+ $"diff = {diff:F4} m. A large diff means the CharacterController.Move() solver " +
+ "behaves differently for pure-vertical vs mixed-axis input (Suspect 3) — fix C from " +
+ "the diagnosis would address this.");
+ }
+
+ // ---------------------------------------------------------------------------------------------
+ // Diagnostic dump: not a pass/fail test, but exercises the path and logs the key signals every
+ // tick so a human can read the console after a run. Useful first-look during investigation.
+ // ---------------------------------------------------------------------------------------------
+
+ [UnityTest]
+ [Explicit("Diagnostic only — prints per-tick grounding state. Run manually when investigating.")]
+ public IEnumerator CharacterEntity_LogsGroundingStateEachTick()
+ {
+ CharacterEntity ce = null;
+ yield return BuildSceneAndCharacter(new Vector3(0, 3f, 0), buildFloor: true, c => ce = c);
+
+ CharacterController cc = ce.GetComponent();
+ Rigidbody rb = ce.GetComponent();
+
+ for (int i = 0; i < 80; i++)
+ {
+ Vector3 foot = ce.transform.position - new Vector3(0, cc.height / 2f, 0);
+ bool onSurface = ce.IsOnSurface();
+ bool ccGrounded = cc.isGrounded;
+
+ float gap = -1f;
+ if (Physics.Raycast(foot, Vector3.down, out RaycastHit hit, 10f,
+ ~0, QueryTriggerInteraction.Ignore))
+ {
+ gap = hit.distance;
+ }
+
+ Debug.Log($"[t={Time.time:F3}] footY={foot.y:F4} gap={gap:F4} " +
+ $"IsOnSurface={onSurface} cc.isGrounded={ccGrounded} " +
+ $"rb.kinematic={rb?.isKinematic} rb.useGravity={rb?.useGravity}");
+
+ yield return new WaitForFixedUpdate();
+ }
+
+ Assert.Pass("Diagnostic log complete — inspect Console output.");
+ }
+}
diff --git a/Assets/Runtime/StraightFour/Testing/EntityTests/CharacterEntityGroundingTests.cs.meta b/Assets/Runtime/StraightFour/Testing/EntityTests/CharacterEntityGroundingTests.cs.meta
new file mode 100644
index 00000000..a032713f
--- /dev/null
+++ b/Assets/Runtime/StraightFour/Testing/EntityTests/CharacterEntityGroundingTests.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: a56f70a55ee044ed9648d2baff9ae115
diff --git a/Assets/Runtime/TopLevel/Scenes/MobileRuntime.unity b/Assets/Runtime/TopLevel/Scenes/MobileRuntime.unity
index 12b23ecc..e0cc0668 100644
--- a/Assets/Runtime/TopLevel/Scenes/MobileRuntime.unity
+++ b/Assets/Runtime/TopLevel/Scenes/MobileRuntime.unity
@@ -119,6 +119,108 @@ NavMeshSettings:
debug:
m_Flags: 0
m_NavMeshData: {fileID: 0}
+--- !u!1001 &45003657
+PrefabInstance:
+ m_ObjectHideFlags: 0
+ serializedVersion: 2
+ m_Modification:
+ serializedVersion: 3
+ m_TransformParent: {fileID: 0}
+ m_Modifications:
+ - target: {fileID: 4011543431373168956, guid: 7cc144b3038d1ba43be354d7a45820e9, type: 3}
+ propertyPath: m_Pivot.x
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 4011543431373168956, guid: 7cc144b3038d1ba43be354d7a45820e9, type: 3}
+ propertyPath: m_Pivot.y
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 4011543431373168956, guid: 7cc144b3038d1ba43be354d7a45820e9, type: 3}
+ propertyPath: m_AnchorMax.x
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 4011543431373168956, guid: 7cc144b3038d1ba43be354d7a45820e9, type: 3}
+ propertyPath: m_AnchorMax.y
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 4011543431373168956, guid: 7cc144b3038d1ba43be354d7a45820e9, type: 3}
+ propertyPath: m_AnchorMin.x
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 4011543431373168956, guid: 7cc144b3038d1ba43be354d7a45820e9, type: 3}
+ propertyPath: m_AnchorMin.y
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 4011543431373168956, guid: 7cc144b3038d1ba43be354d7a45820e9, type: 3}
+ propertyPath: m_SizeDelta.x
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 4011543431373168956, guid: 7cc144b3038d1ba43be354d7a45820e9, type: 3}
+ propertyPath: m_SizeDelta.y
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 4011543431373168956, guid: 7cc144b3038d1ba43be354d7a45820e9, type: 3}
+ propertyPath: m_LocalPosition.x
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 4011543431373168956, guid: 7cc144b3038d1ba43be354d7a45820e9, type: 3}
+ propertyPath: m_LocalPosition.y
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 4011543431373168956, guid: 7cc144b3038d1ba43be354d7a45820e9, type: 3}
+ propertyPath: m_LocalPosition.z
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 4011543431373168956, guid: 7cc144b3038d1ba43be354d7a45820e9, type: 3}
+ propertyPath: m_LocalRotation.w
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 4011543431373168956, guid: 7cc144b3038d1ba43be354d7a45820e9, type: 3}
+ propertyPath: m_LocalRotation.x
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 4011543431373168956, guid: 7cc144b3038d1ba43be354d7a45820e9, type: 3}
+ propertyPath: m_LocalRotation.y
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 4011543431373168956, guid: 7cc144b3038d1ba43be354d7a45820e9, type: 3}
+ propertyPath: m_LocalRotation.z
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 4011543431373168956, guid: 7cc144b3038d1ba43be354d7a45820e9, type: 3}
+ propertyPath: m_AnchoredPosition.x
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 4011543431373168956, guid: 7cc144b3038d1ba43be354d7a45820e9, type: 3}
+ propertyPath: m_AnchoredPosition.y
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 4011543431373168956, guid: 7cc144b3038d1ba43be354d7a45820e9, type: 3}
+ propertyPath: m_LocalEulerAnglesHint.x
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 4011543431373168956, guid: 7cc144b3038d1ba43be354d7a45820e9, type: 3}
+ propertyPath: m_LocalEulerAnglesHint.y
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 4011543431373168956, guid: 7cc144b3038d1ba43be354d7a45820e9, type: 3}
+ propertyPath: m_LocalEulerAnglesHint.z
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 4071536258802031107, guid: 7cc144b3038d1ba43be354d7a45820e9, type: 3}
+ propertyPath: m_Name
+ value: TabUIWebViewPrefab
+ objectReference: {fileID: 0}
+ m_RemovedComponents: []
+ m_RemovedGameObjects: []
+ m_AddedGameObjects: []
+ m_AddedComponents: []
+ m_SourcePrefab: {fileID: 100100000, guid: 7cc144b3038d1ba43be354d7a45820e9, type: 3}
+--- !u!1 &45003658 stripped
+GameObject:
+ m_CorrespondingSourceObject: {fileID: 4071536258802031107, guid: 7cc144b3038d1ba43be354d7a45820e9, type: 3}
+ m_PrefabInstance: {fileID: 45003657}
+ m_PrefabAsset: {fileID: 0}
--- !u!1 &167713673
GameObject:
m_ObjectHideFlags: 0
@@ -2167,6 +2269,7 @@ MonoBehaviour:
stateSettings: {fileID: 11400000, guid: 3404c49a4170ad94e87f0e8545b86758, type: 2}
airplaneEntityPrefab: {fileID: 2546332423327978143, guid: 9f84e1b9b912d9b4db6c879e27fa1ff8, type: 3}
highlightMaterial: {fileID: 2100000, guid: fb72f213bae4057419539525b597f16d, type: 2}
+ previewMaterial: {fileID: 0}
skyMaterial: {fileID: 2100000, guid: 0aade801f5d375245b8bd2843b11a686, type: 2}
liteProceduralSkyMaterial: {fileID: 2100000, guid: acf78ab0ce284f148a485a21087ea77a, type: 2}
liteProceduralSkyObject: {fileID: 1137534123}
@@ -2821,6 +2924,763 @@ Transform:
m_LocalPosition: {x: 554, y: 499.95, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
+ m_Children:
+ - {fileID: 1988647508222235451}
+ - {fileID: 181125647174249131}
+ - {fileID: 4287565822571781507}
+ - {fileID: 5118400725549204037}
+ - {fileID: 2165298448928398224}
+ - {fileID: 6574365494872069928}
+ m_Father: {fileID: 0}
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!114 &1898133186
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1898133184}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 781ffc189cb8d1a4181bf4e946009b29, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ runtime: {fileID: 472491403}
+ tabUIWebViewPrefab: {fileID: 45003658}
+ vrParent: {fileID: 0}
+ vrCamera: {fileID: 0}
+ maxTabs: 10
+ maxSnapshotMemoryMB: 100
+ homeUrl:
+--- !u!114 &62904377632733555
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 7258881038783247875}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: e70d2552bcc865047bc902f1a2461f87, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ tooltip: {fileID: 4872086524637674466}
+ tooltipText: Click to go forward
+ hoverActivationThreshold: 1
+--- !u!224 &181125647174249131 stripped
+RectTransform:
+ m_CorrespondingSourceObject: {fileID: 4585713414978531267, guid: 1dc8289dee9c3e04bb253d553a6ea5d0, type: 3}
+ m_PrefabInstance: {fileID: 6453882070439004907}
+ m_PrefabAsset: {fileID: 0}
+--- !u!1 &374595054142335279 stripped
+GameObject:
+ m_CorrespondingSourceObject: {fileID: 4323634567748746375, guid: 6243bcac2f86a7a429b19a4b7364f8b1, type: 3}
+ m_PrefabInstance: {fileID: 4498976061784427153}
+ m_PrefabAsset: {fileID: 0}
+--- !u!222 &897725327113868448
+CanvasRenderer:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 7258881038783247875}
+ m_CullTransparentMesh: 1
+--- !u!1 &1018654042979147675
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 1840187026903600140}
+ - component: {fileID: 1668215394590156806}
+ - component: {fileID: 2584217623066612233}
+ - component: {fileID: 4872086524637674466}
+ m_Layer: 5
+ m_Name: Tooltip
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 0
+--- !u!114 &1060188679371143449
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 6315992069626536027}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ m_Material: {fileID: 0}
+ m_Color: {r: 1, g: 1, b: 1, a: 1}
+ m_RaycastTarget: 1
+ m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+ m_Maskable: 1
+ m_OnCullStateChanged:
+ m_PersistentCalls:
+ m_Calls: []
+ m_text:
+ m_isRightToLeft: 0
+ m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
+ m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
+ m_fontSharedMaterials: []
+ m_fontMaterial: {fileID: 0}
+ m_fontMaterials: []
+ m_fontColor32:
+ serializedVersion: 2
+ rgba: 4278190080
+ m_fontColor: {r: 0, g: 0, b: 0, a: 1}
+ m_enableVertexGradient: 0
+ m_colorMode: 3
+ m_fontColorGradient:
+ topLeft: {r: 1, g: 1, b: 1, a: 1}
+ topRight: {r: 1, g: 1, b: 1, a: 1}
+ bottomLeft: {r: 1, g: 1, b: 1, a: 1}
+ bottomRight: {r: 1, g: 1, b: 1, a: 1}
+ m_fontColorGradientPreset: {fileID: 0}
+ m_spriteAsset: {fileID: 0}
+ m_tintAllSprites: 0
+ m_StyleSheet: {fileID: 0}
+ m_TextStyleHashCode: -1183493901
+ m_overrideHtmlColors: 0
+ m_faceColor:
+ serializedVersion: 2
+ rgba: 4294967295
+ m_fontSize: 20
+ m_fontSizeBase: 20
+ m_fontWeight: 400
+ m_enableAutoSizing: 0
+ m_fontSizeMin: 18
+ m_fontSizeMax: 72
+ m_fontStyle: 0
+ m_HorizontalAlignment: 2
+ m_VerticalAlignment: 512
+ m_textAlignment: 65535
+ m_characterSpacing: 0
+ m_wordSpacing: 0
+ m_lineSpacing: 0
+ m_lineSpacingMax: 0
+ m_paragraphSpacing: 0
+ m_charWidthMaxAdj: 0
+ m_TextWrappingMode: 1
+ m_wordWrappingRatios: 0.4
+ m_overflowMode: 0
+ m_linkedTextComponent: {fileID: 0}
+ parentLinkedComponent: {fileID: 0}
+ m_enableKerning: 1
+ m_ActiveFontFeatures: 00000000
+ m_enableExtraPadding: 0
+ checkPaddingRequired: 0
+ m_isRichText: 1
+ m_EmojiFallbackSupport: 1
+ m_parseCtrlCharacters: 1
+ m_isOrthographic: 1
+ m_isCullingEnabled: 0
+ m_horizontalMapping: 0
+ m_verticalMapping: 0
+ m_uvLineOffset: 0
+ m_geometrySortingOrder: 0
+ m_IsTextObjectScaleStatic: 0
+ m_VertexBufferAutoSizeReduction: 0
+ m_useMaxVisibleDescender: 1
+ m_pageToDisplay: 1
+ m_margin: {x: 2.6341553, y: 0, z: -23.213348, w: 0}
+ m_isUsingLegacyAnimationComponent: 0
+ m_isVolumetricText: 0
+ m_hasFontAssetChanged: 0
+ m_baseMaterial: {fileID: 0}
+ m_maskOffset: {x: 0, y: 0, z: 0, w: 0}
+--- !u!222 &1668215394590156806
+CanvasRenderer:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1018654042979147675}
+ m_CullTransparentMesh: 1
+--- !u!224 &1840187026903600140
+RectTransform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1018654042979147675}
+ m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+ m_LocalPosition: {x: 0, y: 0, z: 0}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_ConstrainProportionsScale: 0
+ m_Children:
+ - {fileID: 3195220051027805464}
+ m_Father: {fileID: 5353811237432420247}
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+ m_AnchorMin: {x: 0, y: 1}
+ m_AnchorMax: {x: 0, y: 1}
+ m_AnchoredPosition: {x: 111, y: -80.25}
+ m_SizeDelta: {x: 179.19391, y: 31.594498}
+ m_Pivot: {x: 0.5, y: 0.5}
+--- !u!1 &1870516355556978866 stripped
+GameObject:
+ m_CorrespondingSourceObject: {fileID: 8744682661361095537, guid: 4efdc47942ba3ed4388eb90053f5988b, type: 3}
+ m_PrefabInstance: {fileID: 7716761825581739910}
+ m_PrefabAsset: {fileID: 0}
+--- !u!224 &1988647508222235451 stripped
+RectTransform:
+ m_CorrespondingSourceObject: {fileID: 7765979136907116940, guid: e1752a319f294da48aa4572fd5f4faf7, type: 3}
+ m_PrefabInstance: {fileID: 6089151490756196357}
+ m_PrefabAsset: {fileID: 0}
+--- !u!222 &2061081047798151252
+CanvasRenderer:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 6315992069626536027}
+ m_CullTransparentMesh: 1
+--- !u!224 &2165298448928398224 stripped
+RectTransform:
+ m_CorrespondingSourceObject: {fileID: 2298980698609654716, guid: e90a727d63cb3e64cb131b7d39297a0f, type: 3}
+ m_PrefabInstance: {fileID: 2698370743161617208}
+ m_PrefabAsset: {fileID: 0}
+--- !u!1001 &2249156467525330175
+PrefabInstance:
+ m_ObjectHideFlags: 0
+ serializedVersion: 2
+ m_Modification:
+ serializedVersion: 3
+ m_TransformParent: {fileID: 1898133185}
+ m_Modifications:
+ - target: {fileID: 1742075923792624124, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_AnchorMax.y
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 1742075923792624124, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_AnchorMin.y
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 1742075923792624124, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_AnchoredPosition.x
+ value: 170.75
+ objectReference: {fileID: 0}
+ - target: {fileID: 1742075923792624124, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_AnchoredPosition.y
+ value: -474.7727
+ objectReference: {fileID: 0}
+ - target: {fileID: 2328989087641193109, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_Pivot.x
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 2328989087641193109, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_Pivot.y
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 2328989087641193109, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_AnchorMax.x
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 2328989087641193109, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_AnchorMax.y
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 2328989087641193109, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_AnchorMin.x
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 2328989087641193109, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_AnchorMin.y
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 2328989087641193109, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_SizeDelta.x
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 2328989087641193109, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_SizeDelta.y
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 2328989087641193109, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_LocalPosition.x
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 2328989087641193109, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_LocalPosition.y
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 2328989087641193109, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_LocalPosition.z
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 2328989087641193109, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_LocalRotation.w
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 2328989087641193109, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_LocalRotation.x
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 2328989087641193109, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_LocalRotation.y
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 2328989087641193109, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_LocalRotation.z
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 2328989087641193109, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_AnchoredPosition.x
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 2328989087641193109, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_AnchoredPosition.y
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 2328989087641193109, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_LocalEulerAnglesHint.x
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 2328989087641193109, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_LocalEulerAnglesHint.y
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 2328989087641193109, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_LocalEulerAnglesHint.z
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 2702427302246568075, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_AnchorMax.y
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 2702427302246568075, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_AnchorMin.y
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 2702427302246568075, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_AnchoredPosition.x
+ value: 170.75
+ objectReference: {fileID: 0}
+ - target: {fileID: 2702427302246568075, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_AnchoredPosition.y
+ value: -849.5908
+ objectReference: {fileID: 0}
+ - target: {fileID: 3084871783138012815, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_AnchorMax.x
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 3084871783138012815, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_AnchorMax.y
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 3487255676057137607, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_AnchorMax.y
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 3487255676057137607, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_SizeDelta.y
+ value: -17
+ objectReference: {fileID: 0}
+ - target: {fileID: 3771538046396679732, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_AnchorMax.y
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 3771538046396679732, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_AnchorMin.y
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 3771538046396679732, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_AnchoredPosition.x
+ value: 170.75
+ objectReference: {fileID: 0}
+ - target: {fileID: 3771538046396679732, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_AnchoredPosition.y
+ value: -549.72723
+ objectReference: {fileID: 0}
+ - target: {fileID: 4127085878270801471, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: desktopMode
+ value:
+ objectReference: {fileID: 0}
+ - target: {fileID: 4127085878270801471, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: nativeSettings
+ value:
+ objectReference: {fileID: 472491408}
+ - target: {fileID: 4966645532661389859, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_AnchorMax.x
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 4966645532661389859, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_AnchorMax.y
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 4966645532661389859, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_AnchorMin.y
+ value: 0.77110785
+ objectReference: {fileID: 0}
+ - target: {fileID: 5086805301692129715, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_AnchorMax.y
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 5086805301692129715, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_AnchorMin.y
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 5086805301692129715, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_AnchoredPosition.x
+ value: 170.75
+ objectReference: {fileID: 0}
+ - target: {fileID: 5086805301692129715, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_AnchoredPosition.y
+ value: -224.90909
+ objectReference: {fileID: 0}
+ - target: {fileID: 5184664611584485851, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_AnchorMax.y
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 5184664611584485851, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_AnchorMin.y
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 5184664611584485851, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_AnchoredPosition.x
+ value: 170.75
+ objectReference: {fileID: 0}
+ - target: {fileID: 5184664611584485851, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_AnchoredPosition.y
+ value: -25
+ objectReference: {fileID: 0}
+ - target: {fileID: 5825053534868217129, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_AnchorMax.y
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 5825053534868217129, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_AnchorMin.y
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 5825053534868217129, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_AnchoredPosition.x
+ value: 170.75
+ objectReference: {fileID: 0}
+ - target: {fileID: 5825053534868217129, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_AnchoredPosition.y
+ value: -399.81818
+ objectReference: {fileID: 0}
+ - target: {fileID: 6398496623086018798, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_AnchorMax.x
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 6398496623086018798, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_AnchorMax.y
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 6398496623086018798, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_SizeDelta.x
+ value: -17
+ objectReference: {fileID: 0}
+ - target: {fileID: 6398496623086018798, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_SizeDelta.y
+ value: -17
+ objectReference: {fileID: 0}
+ - target: {fileID: 6762958295356658006, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_AnchorMax.y
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 6762958295356658006, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_AnchorMin.y
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 6762958295356658006, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_AnchoredPosition.x
+ value: 170.75
+ objectReference: {fileID: 0}
+ - target: {fileID: 6762958295356658006, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_AnchoredPosition.y
+ value: -949.54535
+ objectReference: {fileID: 0}
+ - target: {fileID: 7171043448034504270, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_AnchorMax.y
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 7171043448034504270, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_AnchorMin.y
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 7171043448034504270, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_AnchoredPosition.x
+ value: 170.75
+ objectReference: {fileID: 0}
+ - target: {fileID: 7171043448034504270, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_AnchoredPosition.y
+ value: -324.86365
+ objectReference: {fileID: 0}
+ - target: {fileID: 8084162891842064009, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_AnchorMax.y
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 8084162891842064009, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_AnchorMin.y
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 8084162891842064009, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_AnchoredPosition.x
+ value: 170.75
+ objectReference: {fileID: 0}
+ - target: {fileID: 8084162891842064009, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_AnchoredPosition.y
+ value: -749.6363
+ objectReference: {fileID: 0}
+ - target: {fileID: 8112418018014962849, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_AnchorMax.x
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 8112418018014962849, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_SizeDelta.x
+ value: -17
+ objectReference: {fileID: 0}
+ - target: {fileID: 8822790655069677569, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_Name
+ value: Settings-Mobile
+ objectReference: {fileID: 0}
+ - target: {fileID: 8822790655069677569, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_IsActive
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 8858450273282345298, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_AnchorMax.y
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 8858450273282345298, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_AnchorMin.y
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 8858450273282345298, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_AnchoredPosition.x
+ value: 170.75
+ objectReference: {fileID: 0}
+ - target: {fileID: 8858450273282345298, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_AnchoredPosition.y
+ value: -124.954544
+ objectReference: {fileID: 0}
+ - target: {fileID: 9190234847787547429, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_AnchorMax.y
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 9190234847787547429, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_AnchorMin.y
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 9190234847787547429, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_AnchoredPosition.x
+ value: 170.75
+ objectReference: {fileID: 0}
+ - target: {fileID: 9190234847787547429, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+ propertyPath: m_AnchoredPosition.y
+ value: -649.68176
+ objectReference: {fileID: 0}
+ m_RemovedComponents: []
+ m_RemovedGameObjects: []
+ m_AddedGameObjects: []
+ m_AddedComponents: []
+ m_SourcePrefab: {fileID: 100100000, guid: 976f4ee8fbeb3ea499c5717ac9c8acf4, type: 3}
+--- !u!114 &2584217623066612233
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1018654042979147675}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ m_Material: {fileID: 0}
+ m_Color: {r: 1, g: 1, b: 1, a: 0.7019608}
+ m_RaycastTarget: 1
+ m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+ m_Maskable: 1
+ m_OnCullStateChanged:
+ m_PersistentCalls:
+ m_Calls: []
+ m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0}
+ m_Type: 1
+ m_PreserveAspect: 0
+ m_FillCenter: 1
+ m_FillMethod: 4
+ m_FillAmount: 1
+ m_FillClockwise: 1
+ m_FillOrigin: 0
+ m_UseSpriteMesh: 0
+ m_PixelsPerUnitMultiplier: 1
+--- !u!1001 &2698370743161617208
+PrefabInstance:
+ m_ObjectHideFlags: 0
+ serializedVersion: 2
+ m_Modification:
+ serializedVersion: 3
+ m_TransformParent: {fileID: 1898133185}
+ m_Modifications:
+ - target: {fileID: 2298980698609654716, guid: e90a727d63cb3e64cb131b7d39297a0f, type: 3}
+ propertyPath: m_Pivot.x
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 2298980698609654716, guid: e90a727d63cb3e64cb131b7d39297a0f, type: 3}
+ propertyPath: m_Pivot.y
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 2298980698609654716, guid: e90a727d63cb3e64cb131b7d39297a0f, type: 3}
+ propertyPath: m_AnchorMax.x
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 2298980698609654716, guid: e90a727d63cb3e64cb131b7d39297a0f, type: 3}
+ propertyPath: m_AnchorMax.y
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 2298980698609654716, guid: e90a727d63cb3e64cb131b7d39297a0f, type: 3}
+ propertyPath: m_AnchorMin.x
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 2298980698609654716, guid: e90a727d63cb3e64cb131b7d39297a0f, type: 3}
+ propertyPath: m_AnchorMin.y
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 2298980698609654716, guid: e90a727d63cb3e64cb131b7d39297a0f, type: 3}
+ propertyPath: m_SizeDelta.x
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 2298980698609654716, guid: e90a727d63cb3e64cb131b7d39297a0f, type: 3}
+ propertyPath: m_SizeDelta.y
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 2298980698609654716, guid: e90a727d63cb3e64cb131b7d39297a0f, type: 3}
+ propertyPath: m_LocalPosition.x
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 2298980698609654716, guid: e90a727d63cb3e64cb131b7d39297a0f, type: 3}
+ propertyPath: m_LocalPosition.y
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 2298980698609654716, guid: e90a727d63cb3e64cb131b7d39297a0f, type: 3}
+ propertyPath: m_LocalPosition.z
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 2298980698609654716, guid: e90a727d63cb3e64cb131b7d39297a0f, type: 3}
+ propertyPath: m_LocalRotation.w
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 2298980698609654716, guid: e90a727d63cb3e64cb131b7d39297a0f, type: 3}
+ propertyPath: m_LocalRotation.x
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 2298980698609654716, guid: e90a727d63cb3e64cb131b7d39297a0f, type: 3}
+ propertyPath: m_LocalRotation.y
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 2298980698609654716, guid: e90a727d63cb3e64cb131b7d39297a0f, type: 3}
+ propertyPath: m_LocalRotation.z
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 2298980698609654716, guid: e90a727d63cb3e64cb131b7d39297a0f, type: 3}
+ propertyPath: m_AnchoredPosition.x
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 2298980698609654716, guid: e90a727d63cb3e64cb131b7d39297a0f, type: 3}
+ propertyPath: m_AnchoredPosition.y
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 2298980698609654716, guid: e90a727d63cb3e64cb131b7d39297a0f, type: 3}
+ propertyPath: m_LocalEulerAnglesHint.x
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 2298980698609654716, guid: e90a727d63cb3e64cb131b7d39297a0f, type: 3}
+ propertyPath: m_LocalEulerAnglesHint.y
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 2298980698609654716, guid: e90a727d63cb3e64cb131b7d39297a0f, type: 3}
+ propertyPath: m_LocalEulerAnglesHint.z
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 3387419331718106927, guid: e90a727d63cb3e64cb131b7d39297a0f, type: 3}
+ propertyPath: m_AnchorMax.y
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 3387419331718106927, guid: e90a727d63cb3e64cb131b7d39297a0f, type: 3}
+ propertyPath: m_AnchorMin.y
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 3387419331718106927, guid: e90a727d63cb3e64cb131b7d39297a0f, type: 3}
+ propertyPath: m_AnchoredPosition.x
+ value: 254.25
+ objectReference: {fileID: 0}
+ - target: {fileID: 4373880454811058208, guid: e90a727d63cb3e64cb131b7d39297a0f, type: 3}
+ propertyPath: m_AnchorMax.y
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 4373880454811058208, guid: e90a727d63cb3e64cb131b7d39297a0f, type: 3}
+ propertyPath: m_AnchorMin.y
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 4373880454811058208, guid: e90a727d63cb3e64cb131b7d39297a0f, type: 3}
+ propertyPath: m_AnchoredPosition.x
+ value: 184.25
+ objectReference: {fileID: 0}
+ - target: {fileID: 4373880454811058208, guid: e90a727d63cb3e64cb131b7d39297a0f, type: 3}
+ propertyPath: m_AnchoredPosition.y
+ value: -76.87501
+ objectReference: {fileID: 0}
+ - target: {fileID: 5531828587333347769, guid: e90a727d63cb3e64cb131b7d39297a0f, type: 3}
+ propertyPath: m_AnchorMax.y
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 5531828587333347769, guid: e90a727d63cb3e64cb131b7d39297a0f, type: 3}
+ propertyPath: m_AnchorMin.y
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 5531828587333347769, guid: e90a727d63cb3e64cb131b7d39297a0f, type: 3}
+ propertyPath: m_AnchoredPosition.x
+ value: 184.25
+ objectReference: {fileID: 0}
+ - target: {fileID: 5531828587333347769, guid: e90a727d63cb3e64cb131b7d39297a0f, type: 3}
+ propertyPath: m_AnchoredPosition.y
+ value: -180.62503
+ objectReference: {fileID: 0}
+ - target: {fileID: 8438332059091148627, guid: e90a727d63cb3e64cb131b7d39297a0f, type: 3}
+ propertyPath: m_Name
+ value: ExitMenu-Mobile
+ objectReference: {fileID: 0}
+ - target: {fileID: 8438332059091148627, guid: e90a727d63cb3e64cb131b7d39297a0f, type: 3}
+ propertyPath: m_IsActive
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 8517978974965674228, guid: e90a727d63cb3e64cb131b7d39297a0f, type: 3}
+ propertyPath: m_AnchorMax.y
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 8517978974965674228, guid: e90a727d63cb3e64cb131b7d39297a0f, type: 3}
+ propertyPath: m_AnchorMin.y
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 8517978974965674228, guid: e90a727d63cb3e64cb131b7d39297a0f, type: 3}
+ propertyPath: m_AnchoredPosition.x
+ value: 84.75
+ objectReference: {fileID: 0}
+ m_RemovedComponents: []
+ m_RemovedGameObjects: []
+ m_AddedGameObjects: []
+ m_AddedComponents: []
+ m_SourcePrefab: {fileID: 100100000, guid: e90a727d63cb3e64cb131b7d39297a0f, type: 3}
+--- !u!224 &3195220051027805464
+RectTransform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 6315992069626536027}
+ m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+ m_LocalPosition: {x: 0, y: 0, z: 0}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
@@ -2855,3 +3715,4 @@ SceneRoots:
- {fileID: 839982477}
- {fileID: 1137534127}
- {fileID: 167713676}
+ - {fileID: 45003657}
diff --git a/Assets/XR/Settings/OpenXR Package Settings.asset b/Assets/XR/Settings/OpenXR Package Settings.asset
index c84999bb..8a930c6f 100644
--- a/Assets/XR/Settings/OpenXR Package Settings.asset
+++ b/Assets/XR/Settings/OpenXR Package Settings.asset
@@ -33,6 +33,7 @@ MonoBehaviour:
m_Name: MetaXRFeature Android
m_EditorClassIdentifier:
m_enabled: 1
+ k__BackingField: 0
nameUi: Meta XR Feature
version: 0.0.1
featureIdInternal: com.meta.openxr.feature.metaxr
@@ -82,7 +83,6 @@ MonoBehaviour:
m_Name: Standalone
m_EditorClassIdentifier:
features:
- - {fileID: -7441576640521792224}
- {fileID: -4251221511889710573}
- {fileID: -8283934257360705991}
- {fileID: -3043467695985465025}
@@ -95,20 +95,6 @@ MonoBehaviour:
- {fileID: -4233259048951607741}
- {fileID: -2467792937570659600}
- {fileID: -3907765551054486986}
- - {fileID: -7296088344262875955}
- - {fileID: 6770610698521954227}
- - {fileID: -6477775478286594775}
- - {fileID: -7222906391444432655}
- - {fileID: 6575429890421189379}
- - {fileID: 5913630344976663486}
- - {fileID: -7313330577548468968}
- - {fileID: 1158942647253497871}
- - {fileID: 8492585916147005112}
- - {fileID: 7295433065535495109}
- - {fileID: 714606220454857056}
- - {fileID: -3744789857744238503}
- - {fileID: 1690885375729658985}
- - {fileID: 9123467854060196379}
- {fileID: -6322854048430258810}
- {fileID: -2804446222640820088}
- {fileID: 7243270749764318523}
@@ -238,6 +224,7 @@ MonoBehaviour:
m_Name: OpenXRLifeCycleFeature Android
m_EditorClassIdentifier:
m_enabled: 1
+ k__BackingField: 0
nameUi:
version: 0.1.0
featureIdInternal: MetaOpenXR-OpenXRLifeCycle
@@ -278,6 +265,7 @@ MonoBehaviour:
m_Name: OpenXRLifeCycleFeature Standalone
m_EditorClassIdentifier:
m_enabled: 0
+ k__BackingField: 0
nameUi:
version: 0.1.0
featureIdInternal: MetaOpenXR-OpenXRLifeCycle
@@ -298,6 +286,7 @@ MonoBehaviour:
m_Name: AROcclusionFeature Standalone
m_EditorClassIdentifier:
m_enabled: 0
+ k__BackingField: 0
nameUi: 'Meta Quest: Occlusion'
version: 0.1.0
featureIdInternal: com.unity.openxr.feature.arfoundation-meta-occlusion
@@ -339,6 +328,7 @@ MonoBehaviour:
m_Name: ARAnchorFeature Standalone
m_EditorClassIdentifier:
m_enabled: 0
+ k__BackingField: 0
nameUi: 'Meta Quest: Anchors'
version: 0.1.0
featureIdInternal: com.unity.openxr.feature.arfoundation-meta-anchor
@@ -359,6 +349,7 @@ MonoBehaviour:
m_Name: ARCameraFeature Standalone
m_EditorClassIdentifier:
m_enabled: 0
+ k__BackingField: 0
nameUi: 'Meta Quest: Camera (Passthrough)'
version: 0.1.0
featureIdInternal: com.unity.openxr.feature.arfoundation-meta-camera
@@ -379,6 +370,7 @@ MonoBehaviour:
m_Name: ARBoundingBoxFeature Standalone
m_EditorClassIdentifier:
m_enabled: 0
+ k__BackingField: 0
nameUi: 'Meta Quest: Bounding Boxes'
version: 0.1.0
featureIdInternal: com.unity.openxr.feature.arfoundation-meta-bounding-boxes
@@ -523,6 +515,7 @@ MonoBehaviour:
m_Name: BoundaryVisibilityFeature Android
m_EditorClassIdentifier:
m_enabled: 1
+ k__BackingField: 0
nameUi: 'Meta Quest: Boundary Visibility'
version: 0.1.0
featureIdInternal: com.unity.openxr.feature.meta-boundary-visibility
@@ -530,6 +523,7 @@ MonoBehaviour:
company: Unity Technologies
priority: 0
required: 0
+ k__BackingField: 0
--- !u!114 &-5415651528169704530
MonoBehaviour:
m_ObjectHideFlags: 0
@@ -565,6 +559,7 @@ MonoBehaviour:
m_Name: ARRaycastFeature Android
m_EditorClassIdentifier:
m_enabled: 1
+ k__BackingField: 0
nameUi: 'Meta Quest: Raycasts'
version: 0.1.0
featureIdInternal: com.unity.openxr.feature.arfoundation-meta-raycast
@@ -585,6 +580,7 @@ MonoBehaviour:
m_Name: DisplayUtilitiesFeature Android
m_EditorClassIdentifier:
m_enabled: 1
+ k__BackingField: 0
nameUi: 'Meta Quest: Display Utilities'
version: 0.1.0
featureIdInternal: com.unity.openxr.feature.meta-display-utilities
@@ -625,6 +621,7 @@ MonoBehaviour:
m_Name: MetaXREyeTrackedFoveationFeature Android
m_EditorClassIdentifier:
m_enabled: 0
+ k__BackingField: 0
nameUi: Meta XR Eye Tracked Foveation
version: 0.0.1
featureIdInternal: com.meta.openxr.feature.eyetrackedfoveation
@@ -646,6 +643,7 @@ MonoBehaviour:
m_Name: ARSessionFeature Android
m_EditorClassIdentifier:
m_enabled: 1
+ k__BackingField: 0
nameUi: 'Meta Quest: Session'
version: 0.1.0
featureIdInternal: com.unity.openxr.feature.arfoundation-meta-session
@@ -726,6 +724,7 @@ MonoBehaviour:
m_Name: ARCameraFeature Android
m_EditorClassIdentifier:
m_enabled: 1
+ k__BackingField: 0
nameUi: 'Meta Quest: Camera (Passthrough)'
version: 0.1.0
featureIdInternal: com.unity.openxr.feature.arfoundation-meta-camera
@@ -766,6 +765,7 @@ MonoBehaviour:
m_Name: MetaXRFeature Standalone
m_EditorClassIdentifier:
m_enabled: 1
+ k__BackingField: 0
nameUi: Meta XR Feature
version: 0.0.1
featureIdInternal: com.meta.openxr.feature.metaxr
@@ -978,6 +978,7 @@ MonoBehaviour:
m_Name: MetaXRSubsampledLayout Android
m_EditorClassIdentifier:
m_enabled: 0
+ k__BackingField: 0
nameUi: Meta XR Subsampled Layout
version: 0.0.1
featureIdInternal: com.meta.openxr.feature.subsampledLayout
@@ -1018,6 +1019,7 @@ MonoBehaviour:
m_Name: ARBoundingBoxFeature Android
m_EditorClassIdentifier:
m_enabled: 1
+ k__BackingField: 0
nameUi: 'Meta Quest: Bounding Boxes'
version: 0.1.0
featureIdInternal: com.unity.openxr.feature.arfoundation-meta-bounding-boxes
@@ -1095,6 +1097,7 @@ MonoBehaviour:
m_Name: MetaXREyeTrackedFoveationFeature Standalone
m_EditorClassIdentifier:
m_enabled: 0
+ k__BackingField: 0
nameUi: Meta XR Eye Tracked Foveation
version: 0.0.1
featureIdInternal: com.meta.openxr.feature.eyetrackedfoveation
@@ -1116,6 +1119,7 @@ MonoBehaviour:
m_Name: ARAnchorFeature Android
m_EditorClassIdentifier:
m_enabled: 1
+ k__BackingField: 0
nameUi: 'Meta Quest: Anchors'
version: 0.1.0
featureIdInternal: com.unity.openxr.feature.arfoundation-meta-anchor
@@ -1136,6 +1140,7 @@ MonoBehaviour:
m_Name: ARPlaneFeature Standalone
m_EditorClassIdentifier:
m_enabled: 0
+ k__BackingField: 0
nameUi: 'Meta Quest: Planes'
version: 0.1.0
featureIdInternal: com.unity.openxr.feature.arfoundation-meta-plane
@@ -1156,6 +1161,7 @@ MonoBehaviour:
m_Name: MetaXRFoveationFeature Standalone
m_EditorClassIdentifier:
m_enabled: 1
+ k__BackingField: 0
nameUi: Meta XR Foveation
version: 1.0.0
featureIdInternal: com.meta.openxr.feature.foveation
@@ -1176,6 +1182,7 @@ MonoBehaviour:
m_Name: ARMeshFeature Android
m_EditorClassIdentifier:
m_enabled: 1
+ k__BackingField: 0
nameUi: 'Meta Quest: Meshing'
version: 0.1.0
featureIdInternal: com.unity.openxr.feature.arfoundation-meta-mesh
@@ -1344,6 +1351,7 @@ MonoBehaviour:
m_Name: AROcclusionFeature Android
m_EditorClassIdentifier:
m_enabled: 1
+ k__BackingField: 0
nameUi: 'Meta Quest: Occlusion'
version: 0.1.0
featureIdInternal: com.unity.openxr.feature.arfoundation-meta-occlusion
@@ -1405,6 +1413,7 @@ MonoBehaviour:
m_Name: ARPlaneFeature Android
m_EditorClassIdentifier:
m_enabled: 1
+ k__BackingField: 0
nameUi: 'Meta Quest: Planes'
version: 0.1.0
featureIdInternal: com.unity.openxr.feature.arfoundation-meta-plane
@@ -1425,6 +1434,7 @@ MonoBehaviour:
m_Name: MetaXRFoveationFeature Android
m_EditorClassIdentifier:
m_enabled: 0
+ k__BackingField: 0
nameUi: Meta XR Foveation
version: 1.0.0
featureIdInternal: com.meta.openxr.feature.foveation
@@ -1445,6 +1455,7 @@ MonoBehaviour:
m_Name: ARMeshFeature Standalone
m_EditorClassIdentifier:
m_enabled: 0
+ k__BackingField: 0
nameUi: 'Meta Quest: Meshing'
version: 0.1.0
featureIdInternal: com.unity.openxr.feature.arfoundation-meta-mesh
@@ -1466,6 +1477,7 @@ MonoBehaviour:
m_Name: DisplayUtilitiesFeature Standalone
m_EditorClassIdentifier:
m_enabled: 0
+ k__BackingField: 0
nameUi: 'Meta Quest: Display Utilities'
version: 0.1.0
featureIdInternal: com.unity.openxr.feature.meta-display-utilities
@@ -1486,6 +1498,7 @@ MonoBehaviour:
m_Name: BoundaryVisibilityFeature Standalone
m_EditorClassIdentifier:
m_enabled: 0
+ k__BackingField: 0
nameUi: 'Meta Quest: Boundary Visibility'
version: 0.1.0
featureIdInternal: com.unity.openxr.feature.meta-boundary-visibility
@@ -1493,6 +1506,7 @@ MonoBehaviour:
company: Unity Technologies
priority: 0
required: 0
+ k__BackingField: 0
--- !u!114 &7146165264086680457
MonoBehaviour:
m_ObjectHideFlags: 0
@@ -1560,6 +1574,7 @@ MonoBehaviour:
m_Name: ARSessionFeature Standalone
m_EditorClassIdentifier:
m_enabled: 0
+ k__BackingField: 0
nameUi: 'Meta Quest: Session'
version: 0.1.0
featureIdInternal: com.unity.openxr.feature.arfoundation-meta-session
@@ -1600,7 +1615,6 @@ MonoBehaviour:
m_Name: Android
m_EditorClassIdentifier:
features:
- - {fileID: -7633581328313503459}
- {fileID: 4674697878492794949}
- {fileID: 7146165264086680457}
- {fileID: -2340439152450337852}
@@ -1612,21 +1626,6 @@ MonoBehaviour:
- {fileID: 4436760230863042719}
- {fileID: -5909640409290506278}
- {fileID: -4594511983156627525}
- - {fileID: 1085581369992130134}
- - {fileID: -5643199017387485149}
- - {fileID: -803836931037024053}
- - {fileID: -4136287910980941023}
- - {fileID: -4844709515900620156}
- - {fileID: 2486025960671627241}
- - {fileID: 4588223029664240611}
- - {fileID: 5230357031813526908}
- - {fileID: -5273211353462809153}
- - {fileID: -4389619210768067104}
- - {fileID: -4539300325892458710}
- - {fileID: -8917394965726186233}
- - {fileID: 5562653971502655839}
- - {fileID: 8005351155306599530}
- - {fileID: -1428233723045200180}
- {fileID: 8316444451361848473}
- {fileID: -2379692420766146042}
- {fileID: -2367121910693502146}
@@ -1658,6 +1657,7 @@ MonoBehaviour:
m_Name: MetaXRSpaceWarp Android
m_EditorClassIdentifier:
m_enabled: 0
+ k__BackingField: 0
nameUi: Meta XR Space Warp
version: 1.0.0
featureIdInternal: com.meta.openxr.feature.spacewarp
@@ -1698,6 +1698,7 @@ MonoBehaviour:
m_Name: ARRaycastFeature Standalone
m_EditorClassIdentifier:
m_enabled: 0
+ k__BackingField: 0
nameUi: 'Meta Quest: Raycasts'
version: 0.1.0
featureIdInternal: com.unity.openxr.feature.arfoundation-meta-raycast
@@ -1718,6 +1719,7 @@ MonoBehaviour:
m_Name: MetaXRSubsampledLayout Standalone
m_EditorClassIdentifier:
m_enabled: 0
+ k__BackingField: 0
nameUi: Meta XR Subsampled Layout
version: 0.0.1
featureIdInternal: com.meta.openxr.feature.subsampledLayout