From e767fad9080a8d21cf843b40bea17cc102e57e1e Mon Sep 17 00:00:00 2001 From: Toys0125 Date: Wed, 15 Apr 2026 16:31:09 -0500 Subject: [PATCH 1/8] Add CilboxAvatar Basis variant, that should be for Basis. --- .../AvatarContentPoliceSelector.asset | 1 + .../com.basis.shim/Shims/CilboxAvatarBasis.cs | 249 ++++++++++++++++++ .../Shims/CilboxAvatarBasis.cs.meta | 2 + 3 files changed, 252 insertions(+) create mode 100644 Basis/Packages/com.basis.shim/Shims/CilboxAvatarBasis.cs create mode 100644 Basis/Packages/com.basis.shim/Shims/CilboxAvatarBasis.cs.meta diff --git a/Basis/Packages/com.basis.sdk/Settings/AvatarContentPoliceSelector.asset b/Basis/Packages/com.basis.sdk/Settings/AvatarContentPoliceSelector.asset index 884cbec445..d087c68a21 100644 --- a/Basis/Packages/com.basis.sdk/Settings/AvatarContentPoliceSelector.asset +++ b/Basis/Packages/com.basis.sdk/Settings/AvatarContentPoliceSelector.asset @@ -190,3 +190,4 @@ MonoBehaviour: - UnityEngine.AudioChorusFilter - UnityEngine.AudioEchoFilter - UnityEngine.AudioDistortionFilter + - Cilbox.CilboxAvatarBasis diff --git a/Basis/Packages/com.basis.shim/Shims/CilboxAvatarBasis.cs b/Basis/Packages/com.basis.shim/Shims/CilboxAvatarBasis.cs new file mode 100644 index 0000000000..6f569333c2 --- /dev/null +++ b/Basis/Packages/com.basis.shim/Shims/CilboxAvatarBasis.cs @@ -0,0 +1,249 @@ +using UnityEngine; +using System.Collections.Generic; +using System; +using System.Collections.Specialized; +using System.Collections; +using System.Runtime.InteropServices; +using System.Reflection; +using Cilbox; + +namespace Cilbox +{ + [CilboxTarget] + public class CilboxAvatarBasis : Cilbox + { + static HashSet whiteListType = new HashSet(){ + // Basis types + "Basis.Scripts.BasisSdk.Interactions.BasisPickUpUseMode", + "Basis.Scripts.Device_Management.Devices.BasisInput", // Restrictive, only used as a type. + "Basis.Scripts.BasisSdk.Interactions.BasisPickupInteractable", // Restrictive (See below), only access field. + "Basis.Scripts.BasisSdk.Interactions.BasisInteractableObject", // Restrictive (See below), only access field. + "Basis.BasisNetworkBehaviour", + "Basis.Network.Core.DeliveryMethod", + "Basis.SafeUtil", + "Basis.Scripts.BasisSdk.Players.BasisLocalPlayer", + "Basis.Scripts.Networking.NetworkedAvatar.BasisNetworkPlayer", + "Basis.Shims.*", + + // Cilbox types + "Cilbox.CilboxPublicUtils", + + // System types + "System.Array", + "System.BitConverter", // HMMMMMMMMM SUSSY + "System.Boolean", + "System.Buffer", + "System.Byte", + "System.Char", + "System.Collections.Generic.*", + "System.Convert", // HMMMMMMMMM SUSSY + "System.DateTime", + "System.DateTimeOffset", + "System.DayOfWeek", + "System.Diagnostics.Stopwatch", + "System.Double", + "System.Exception", + "System.Int*", + "System.Math", + "System.MathF", + "System.Object", + "System.Single", + "System.String", + "System.StringComparison", + "System.TimeSpan", + "System.Text.Encoding", + "System.UInt16", + "System.UInt32", + "System.UInt*", + "System.Void", + "", // Probably remove me? But we need a way to handle string hashing. We can do it with our own function but that's slower. + + // Unity types + "UnityEngine.Animator", + "UnityEngine.AnimatorStateInfo", + "UnityEngine.AnimatorTransitionInfo", + "UnityEngine.AudioClip", + "UnityEngine.AudioSource", + "UnityEngine.Color", + "UnityEngine.Component", + "UnityEngine.Events.UnityAction", + "UnityEngine.Events.UnityEvent", + "UnityEngine.GameObject", // Hyper restrictive. + "UnityEngine.Material", + "UnityEngine.MaterialPropertyBlock", + "UnityEngine.Mathf", + "UnityEngine.MeshRenderer", + "UnityEngine.MonoBehaviour", // Note this is needed for the 'ctor, but we can be very restrictive. + "UnityEngine.Object", + "UnityEngine.Random", + "UnityEngine.Renderer", + "UnityEngine.TextAsset", + "UnityEngine.Texture", + "UnityEngine.Texture2D", + "UnityEngine.Time", + "UnityEngine.Transform", + "UnityEngine.Quaternion", + "UnityEngine.Rigidbody", + "UnityEngine.RenderTexture", + "UnityEngine.RenderTextureFormat", + "UnityEngine.UI.*", + "UnityEngine.Vector*", + "UnityEngine.UI.InputField", + "UnityEngine.UI.InputField+OnChangeEvent", + "UnityEngine.UI.Scrollbar", + "UnityEngine.UI.Selectable", + "UnityEngine.UI.Slider", + "UnityEngine.UI.Text", + "UnityEngine.Vector2", + "UnityEngine.Vector3", + "UnityEngine.Vector4", + }; + + static HashSet whiteListFields = new HashSet(){ + // Unity fields + "UnityEngine.Vector*.x", + "UnityEngine.Vector*.y", + "UnityEngine.Vector*.z", + "UnityEngine.Vector*.w", + + // System fields + "System.Array.*", + "System.String.*", + + + // Basis types + "Basis.Scripts.BasisSdk.Interactions.BasisPickupInteractable.OnPickupUse", + "Basis.Scripts.BasisSdk.Interactions.BasisInteractableObject.OnInteractStartEvent", + "Basis.Scripts.BasisSdk.Interactions.BasisInteractableObject.OnInteractEndEvent", + "Basis.BasisNetworkBehaviour.CurrentOwnerId", + "Basis.BasisNetworkBehaviour.IsOwnedLocallyOnServer", + }; + + static public HashSet GetWhiteListTypes() { return whiteListType; } + + // This is called by CilboxUsage to decide of a type is allowed. + // If a type is allowed, by defalt it is all allowed. + override public bool CheckTypeAllowed( String sType ) + { + if( whiteListType.Contains( sType ) ) return true; + + foreach( string allowedType in whiteListType ) + { + if( !allowedType.Contains( '*' ) ) continue; + + string[] allowedPrefix = allowedType.Split( '*' ); + if( sType.StartsWith( allowedPrefix[0], StringComparison.Ordinal ) && sType.EndsWith( allowedPrefix[1], StringComparison.Ordinal ) ) return true; + } + + return false; + } + + override public bool CheckFieldAllowed( String sType, String sFieldName ) + { + if( !CheckTypeAllowed( sType ) ) return false; + string fullField = sType + "." + sFieldName; + if( whiteListFields.Contains( fullField ) ) return true; + foreach( string allowedType in whiteListFields ) + { + if( !allowedType.Contains( '*' ) ) continue; + + string[] allowedPrefix = allowedType.Split( '*' ); + if( fullField.StartsWith( allowedPrefix[0], StringComparison.Ordinal ) && fullField.EndsWith( allowedPrefix[1], StringComparison.Ordinal ) ) return true; + } + + return false; + } + + // Whitelist methods on native types. + // If a type is not in this dictionary, then all methods are allowed. + static Dictionary> methodWhitelist = new Dictionary>() + { + { typeof(UnityEngine.MonoBehaviour), new HashSet{ ".ctor" } }, + { typeof(UnityEngine.Events.UnityAction), new HashSet{ ".ctor" } }, + { typeof(Basis.Scripts.BasisSdk.Interactions.BasisPickupInteractable), new HashSet { } }, + { typeof(Basis.Scripts.BasisSdk.Interactions.BasisInteractableObject), new HashSet { } }, + { typeof(Basis.Scripts.Device_Management.Devices.BasisInput), new HashSet { } }, + { typeof(Basis.Scripts.Networking.NetworkedAvatar.BasisNetworkPlayer), new HashSet { + typeof(Basis.Scripts.Networking.NetworkedAvatar.BasisNetworkPlayer).GetProperty(nameof(Basis.Scripts.Networking.NetworkedAvatar.BasisNetworkPlayer.playerId)).GetGetMethod().Name, + typeof(Basis.Scripts.Networking.NetworkedAvatar.BasisNetworkPlayer).GetProperty(nameof(Basis.Scripts.Networking.NetworkedAvatar.BasisNetworkPlayer.Player)).GetGetMethod().Name, + typeof(Basis.Scripts.Networking.NetworkedAvatar.BasisNetworkPlayer).GetProperty(nameof(Basis.Scripts.Networking.NetworkedAvatar.BasisNetworkPlayer.LocalPlayer)).GetGetMethod().Name, + typeof(Basis.Scripts.Networking.NetworkedAvatar.BasisNetworkPlayer).GetProperty(nameof(Basis.Scripts.Networking.NetworkedAvatar.BasisNetworkPlayer.displayName)).GetGetMethod().Name, + } }, + { typeof(UnityEngine.GameObject), new HashSet{ + nameof(GameObject.SetActive), + nameof(GameObject.GetComponents), + typeof(GameObject).GetProperty(nameof(GameObject.transform)).GetGetMethod().Name, + typeof(GameObject).GetProperty(nameof(GameObject.activeSelf)).GetGetMethod().Name, + typeof(GameObject).GetProperty(nameof(GameObject.activeInHierarchy)).GetGetMethod().Name, + typeof(GameObject).GetProperty(nameof(GameObject.layer)).GetGetMethod().Name, + } }, + { typeof(Buffer), new HashSet{ "BlockCopy" } }, + { typeof(System.Type), new HashSet() }, // nothing allowed + }; + + // After a type is allowed, this is called to see if the specific method is OK. + override public bool CheckMethodAllowed( out MethodInfo mi, Type declaringType, String name, Serializee [] parametersIn, Serializee [] genericArgumentsIn, String fullSignature ) + { + mi = null; + + if( name.Contains( "Invoke" ) ) return false; + + // UnityEngine.Application.OpenURL opens an arbitrary URL in the native + // browser — the exact payload behind the reported prop exploit. Deny it + // explicitly so this never works from cilbox regardless of how the + // Application type ends up whitelisted. + if( declaringType == typeof(UnityEngine.Application) && name == "OpenURL" ) + return false; + + // UnityEngine.Object.Instantiate spawns a prefab tree verbatim, so the clone + // can carry UnityEvents that execute outside the sandbox (e.g. Button.onClick + // -> Application.OpenURL). Redirect every Instantiate variant through the + // sanitizing shim: it spawns under a disabled host, scrubs disallowed + // components via the prop content-police selector, and kills all persistent + // UnityEvent listeners before the clone becomes active in hierarchy. + if( declaringType == typeof(UnityEngine.Object) && + ( name == "Instantiate" || name == "InstantiateAsync" ) ) + { + mi = Basis.Shims.BasisCilboxInstantiateShim.ResolveShim( + usage, name, parametersIn, genericArgumentsIn, fullSignature ); + return mi != null; + } + + if( methodWhitelist.TryGetValue( declaringType, out var allowed ) ) + { + if( !allowed.Contains( name ) ) return false; + } + + return true; + } + + public override bool GetComponentTypeOverride(string sType, out Type t) + { + switch(sType) + { + + case "UnityEngine.Video.VideoPlayer": + t = typeof(Basis.Shims.VideoPlayerShim); + return true; + case "UnityEngine.Video.VideoPlayer+ErrorEventHandler": + t = typeof(Basis.Shims.VideoPlayerShim.ErrorEventHandlerShim); + return true; + case "UnityEngine.Video.VideoPlayer+EventHandler": + t = typeof(Basis.Shims.VideoPlayerShim.EventHandlerShim); + return true; + case "UnityEngine.Video.VideoPlayer+FrameReadyEventHandler": + t = typeof(Basis.Shims.VideoPlayerShim.FrameReadyEventHandlerShim); + return true; + case "UnityEngine.Video.VideoPlayer+TimeEventHandler": + t = typeof(Basis.Shims.VideoPlayerShim.TimeEventHandlerShim); + return true; + case "UnityEngine.Debug": + t = typeof(Basis.Shims.BasisDebugPropsShim); + return true; + default: + t = null; + return false; + } + } + } +} diff --git a/Basis/Packages/com.basis.shim/Shims/CilboxAvatarBasis.cs.meta b/Basis/Packages/com.basis.shim/Shims/CilboxAvatarBasis.cs.meta new file mode 100644 index 0000000000..35879ee9fc --- /dev/null +++ b/Basis/Packages/com.basis.shim/Shims/CilboxAvatarBasis.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: d9c7c62dd9448e24ea35aeafc5cc99b4 From 73ef3dd3cae318237701746e9a6c75309d86fe84 Mon Sep 17 00:00:00 2001 From: Toys0125 Date: Wed, 15 Apr 2026 16:34:06 -0500 Subject: [PATCH 2/8] Add the shims, and removed the BasisInteractableShim, since the purpose is not longer needed. --- .../AvatarContentPoliceSelector.asset | 2 + .../Shims/BasisInteractableShim.cs | 210 ------------------ .../Shims/BasisInteractableShim.cs.meta | 2 - 3 files changed, 2 insertions(+), 212 deletions(-) delete mode 100644 Basis/Packages/com.basis.shim/Shims/BasisInteractableShim.cs delete mode 100644 Basis/Packages/com.basis.shim/Shims/BasisInteractableShim.cs.meta diff --git a/Basis/Packages/com.basis.sdk/Settings/AvatarContentPoliceSelector.asset b/Basis/Packages/com.basis.sdk/Settings/AvatarContentPoliceSelector.asset index d087c68a21..32f601ec79 100644 --- a/Basis/Packages/com.basis.sdk/Settings/AvatarContentPoliceSelector.asset +++ b/Basis/Packages/com.basis.sdk/Settings/AvatarContentPoliceSelector.asset @@ -191,3 +191,5 @@ MonoBehaviour: - UnityEngine.AudioEchoFilter - UnityEngine.AudioDistortionFilter - Cilbox.CilboxAvatarBasis + - Basis.Shims.BasisNetworkShim + - Basis.Shims.VideoPlayerShim diff --git a/Basis/Packages/com.basis.shim/Shims/BasisInteractableShim.cs b/Basis/Packages/com.basis.shim/Shims/BasisInteractableShim.cs deleted file mode 100644 index d416b03938..0000000000 --- a/Basis/Packages/com.basis.shim/Shims/BasisInteractableShim.cs +++ /dev/null @@ -1,210 +0,0 @@ -using System; -using Basis.Scripts.BasisSdk.Interactions; -using Basis.Scripts.Device_Management.Devices; -using UnityEngine; - -// This is temporarily a clone of ExampleButtonInteractable. - -namespace Basis.Shims -{ - public class BasisInteractableShim : BasisInteractableObject - { - // public BasisObjectSyncNetworking syncNetworking; - - // events other scripts can subscribe to - public delegate void ClickEvent(); - - public ClickEvent ButtonDown { get; set; } - public ClickEvent ButtonUp { get; set; } - - [ContextMenu("Trigger Down")] public void TriggerButtonDown() { ButtonDown(); } - [ContextMenu("Trigger Up")] public void TriggerButtonUp() { ButtonUp(); } - - //public void AddDelegateForButtonDown( Action d ) { ButtonDown += d; }\ - //public void AddDelegateForButtonUp( Action d ) { ButtonUp += d; } - - [Header("Button Settings")] - public bool isEnabled = true; - [Space(10)] - public string PropertyName = "_Color"; - public Color Color = Color.white; - public Color HoverColor = Color.white; - public Color InteractColor = Color.white; - public Color DisabledColor = Color.white; - - [Header("References")] - public Collider ColliderRef; - public MeshRenderer RendererRef; - - private BasisInputWrapper _inputSource; - // Ignore provided list localy, but keep it updated for other scripts - private BasisInputWrapper _InputSource - { - get => _inputSource; - set - { - if (value.Source != null) - { - Inputs = new(0); - Inputs.SetInputByRole(value.Source, value.GetState()); - } - else if (value.Source == null) - { - Inputs = new(0); - } - _inputSource = value; - - } - } - - void Start() - { - _InputSource = default; - if (ColliderRef == null) - { - TryGetComponent(out ColliderRef); - } - if (RendererRef == null) - { - TryGetComponent(out RendererRef); - } - - SetColor(isEnabled ? Color : DisabledColor); - } - - public override bool CanHover(BasisInput input) - { - return _InputSource.GetState() == BasisInteractInputState.NotAdded && IsWithinRange(input.transform.position, InteractRange) && isEnabled; - } - public override bool CanInteract(BasisInput input) - { - // must be the same input hovering - if (!_InputSource.IsInput(input)) return false; - // dont interact again till after interacting stopped - if (_InputSource.GetState() == BasisInteractInputState.Interacting) return false; - - return IsWithinRange(input.transform.position, InteractRange) && isEnabled; - } - - public override void OnHoverStart(BasisInput input) - { - if (!BasisInputWrapper.TryNewTracking(input, BasisInteractInputState.Hovering, out BasisInputWrapper wrapper)) - { - BasisDebug.LogWarning($"{nameof(BasisInteractableShim)}: Failed to setup input on hover"); - return; - } - _InputSource = wrapper; - SetColor(HoverColor); - // call base method (invokes event) - base.OnHoverStart(input); - } - - public override void OnHoverEnd(BasisInput input, bool willInteract) - { - if (_InputSource.IsInput(input)) - { - // leaving hover and wont interact this frame, - if (!willInteract) - { - bool added = BasisInputWrapper.TryNewTracking(null, BasisInteractInputState.NotAdded, out BasisInputWrapper wrapper); - // setting to null should not add the tracker - Debug.Assert(!added); - _InputSource = wrapper; - SetColor(Color); - } - // Oninteract will update color - - // call base method (invokes event) - base.OnHoverEnd(input, willInteract); - } - } - - public override void OnInteractStart(BasisInput input) - { - if (_InputSource.IsInput(input) && _InputSource.GetState() == BasisInteractInputState.Hovering) - { - // Set ownership to the local player - // syncNetworking.IsOwner = true; - SetColor(InteractColor); - - var newSource = _InputSource; - var didSetState = newSource.TrySetState(BasisInteractInputState.Interacting); - Debug.Assert(didSetState); - _InputSource = newSource; - - ButtonDown?.Invoke(); - // call base method (invokes event) - base.OnInteractStart(input); - } - } - - public override void OnInteractEnd(BasisInput input) - { - if (_InputSource.IsInput(input)) - { - SetColor(Color); - bool added = BasisInputWrapper.TryNewTracking(null, BasisInteractInputState.NotAdded, out BasisInputWrapper wrapper); - // setting to null should not add the tracker - Debug.Assert(!added); - _InputSource = wrapper; - - ButtonUp?.Invoke(); - // call base method (invokes event) - base.OnInteractEnd(input); - } - } - public override bool IsInteractingWith(BasisInput input) - { - return _InputSource.IsInput(input) && - _InputSource.GetState() == BasisInteractInputState.Interacting; - } - - public override bool IsHoveredBy(BasisInput input) - { - return _InputSource.IsInput(input) && - _InputSource.GetState() == BasisInteractInputState.Hovering; - } - - // set material property to a color - private void SetColor(Color color) - { - if (RendererRef != null && RendererRef.material != null) - { - RendererRef.material.SetColor(Shader.PropertyToID(PropertyName), color); - } - } - - - private bool _triggerCleanup; - // per-frame update, after IK transform - public override void InputUpdate() - { - if (!isEnabled) - { - if (_triggerCleanup) - { - _triggerCleanup = false; - // clean up currently hovering/interacting - if (_InputSource.GetState() != BasisInteractInputState.NotAdded) - { - if (IsHoveredBy(_InputSource.Source)) - { - OnHoverEnd(_InputSource.Source, false); - } - if (IsInteractingWith(_InputSource.Source)) - { - OnInteractEnd(_InputSource.Source); - } - } - // setting same color every frame isnt optimal but fine for example - SetColor(DisabledColor); - } - } - else - { - _triggerCleanup = true; - } - } - } -} - diff --git a/Basis/Packages/com.basis.shim/Shims/BasisInteractableShim.cs.meta b/Basis/Packages/com.basis.shim/Shims/BasisInteractableShim.cs.meta deleted file mode 100644 index 7f61e36338..0000000000 --- a/Basis/Packages/com.basis.shim/Shims/BasisInteractableShim.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: f8c388c62246d4cbda53a221c1c5408c \ No newline at end of file From 68216d2362af7243bb41eac5bc55770c7146d3bf Mon Sep 17 00:00:00 2001 From: Toys0125 Date: Wed, 15 Apr 2026 16:42:21 -0500 Subject: [PATCH 3/8] Restrict shims. --- .../com.basis.sdk/Settings/AvatarContentPoliceSelector.asset | 1 - Basis/Packages/com.basis.shim/Shims/CilboxAvatarBasis.cs | 4 +++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Basis/Packages/com.basis.sdk/Settings/AvatarContentPoliceSelector.asset b/Basis/Packages/com.basis.sdk/Settings/AvatarContentPoliceSelector.asset index 32f601ec79..f1c2e87616 100644 --- a/Basis/Packages/com.basis.sdk/Settings/AvatarContentPoliceSelector.asset +++ b/Basis/Packages/com.basis.sdk/Settings/AvatarContentPoliceSelector.asset @@ -192,4 +192,3 @@ MonoBehaviour: - UnityEngine.AudioDistortionFilter - Cilbox.CilboxAvatarBasis - Basis.Shims.BasisNetworkShim - - Basis.Shims.VideoPlayerShim diff --git a/Basis/Packages/com.basis.shim/Shims/CilboxAvatarBasis.cs b/Basis/Packages/com.basis.shim/Shims/CilboxAvatarBasis.cs index 6f569333c2..238e94340a 100644 --- a/Basis/Packages/com.basis.shim/Shims/CilboxAvatarBasis.cs +++ b/Basis/Packages/com.basis.shim/Shims/CilboxAvatarBasis.cs @@ -23,7 +23,9 @@ public class CilboxAvatarBasis : Cilbox "Basis.SafeUtil", "Basis.Scripts.BasisSdk.Players.BasisLocalPlayer", "Basis.Scripts.Networking.NetworkedAvatar.BasisNetworkPlayer", - "Basis.Shims.*", + "Basis.Shims.BasisNet*", // Restrictive, only used as a type and for events. + "Basis.Shims.BasisCilboxInstantiateShim", // Restrictive, only used as a type and for Instantiate methods. + "Basis.Shims.BasisDebugPropsShim", // Restrictive, only used as a type and for logging methods. // Cilbox types "Cilbox.CilboxPublicUtils", From 8eea3d67b508aaf5820b7e9eb4b892af9f92d746 Mon Sep 17 00:00:00 2001 From: Toys0125 Date: Wed, 15 Apr 2026 16:45:18 -0500 Subject: [PATCH 4/8] Forgot to remove the make interactable hook. --- Basis/Packages/com.basis.shim/Shims/BasisShims.cs | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/Basis/Packages/com.basis.shim/Shims/BasisShims.cs b/Basis/Packages/com.basis.shim/Shims/BasisShims.cs index f85752a0f6..b3d35b0410 100644 --- a/Basis/Packages/com.basis.shim/Shims/BasisShims.cs +++ b/Basis/Packages/com.basis.shim/Shims/BasisShims.cs @@ -37,21 +37,6 @@ public static BasisNetworkShim MakeNetworkable( MonoBehaviour mb ) return mb.gameObject.AddComponent(); } - - public static BasisInteractableShim MakeInteractable( object o ) - { - // Actually needs to be CilboxProxies. - GameObject go = null; - if( o is CilboxProxy ) - go = ((CilboxProxy)o).gameObject; - else - go = ((MonoBehaviour)o).gameObject; - - BasisInteractableShim bi; - if( go.TryGetComponent( out bi ) ) return bi; - - return go.AddComponent(); - } } From 7b9e7e7ea8932fdcb27622cd043344a65ccbb705 Mon Sep 17 00:00:00 2001 From: Toys0125 Date: Wed, 15 Apr 2026 18:14:31 -0500 Subject: [PATCH 5/8] Add AvatarShim. --- .../Avatar/BasisAvatarFactory.cs | 4 +- .../Scripts/Basis Components/BasisAvatar.cs | 43 +++++++++++ .../AvatarContentPoliceSelector.asset | 1 + .../com.basis.shim/Shims/BasisAvatarShim.cs | 73 +++++++++++++++++++ .../Shims/BasisAvatarShim.cs.meta | 11 +++ .../com.basis.shim/Shims/BasisShims.cs | 1 + .../com.basis.shim/Shims/CilboxAvatarBasis.cs | 2 + 7 files changed, 133 insertions(+), 2 deletions(-) create mode 100644 Basis/Packages/com.basis.shim/Shims/BasisAvatarShim.cs create mode 100644 Basis/Packages/com.basis.shim/Shims/BasisAvatarShim.cs.meta diff --git a/Basis/Packages/com.basis.framework/Avatar/BasisAvatarFactory.cs b/Basis/Packages/com.basis.framework/Avatar/BasisAvatarFactory.cs index fc331036ee..63fe6af7eb 100644 --- a/Basis/Packages/com.basis.framework/Avatar/BasisAvatarFactory.cs +++ b/Basis/Packages/com.basis.framework/Avatar/BasisAvatarFactory.cs @@ -451,7 +451,7 @@ public static async void DeleteLastAvatar(BasisPlayer Player) public static void SetupRemoteAvatar(BasisRemotePlayer Player) { Player.RemoteAvatarDriver.RemoteCalibration(Player); - Player.BasisAvatar.OnAvatarReady?.Invoke(false); + Player.BasisAvatar.NotifyAvatarReady(false); } /// @@ -460,7 +460,7 @@ public static void SetupRemoteAvatar(BasisRemotePlayer Player) public static void SetupLocalAvatar(BasisLocalPlayer Player) { Player.LocalAvatarDriver.InitialLocalCalibration(Player); - Player.BasisAvatar.OnAvatarReady?.Invoke(true); + Player.BasisAvatar.NotifyAvatarReady(true); BasisLocalAvatarDriver.CalibrationComplete?.Invoke(); } diff --git a/Basis/Packages/com.basis.sdk/Scripts/Basis Components/BasisAvatar.cs b/Basis/Packages/com.basis.sdk/Scripts/Basis Components/BasisAvatar.cs index 3c42e59a95..a90ccea794 100644 --- a/Basis/Packages/com.basis.sdk/Scripts/Basis Components/BasisAvatar.cs +++ b/Basis/Packages/com.basis.sdk/Scripts/Basis Components/BasisAvatar.cs @@ -65,6 +65,11 @@ public class BasisAvatar : BasisContentBase /// public bool IsOwnedLocally; + /// + /// True once avatar setup has completed and readiness callbacks have fired for this instance. + /// + public bool IsReady { get; private set; } + /// /// Gets or sets the linked player ID. Setting also marks true. /// @@ -114,6 +119,44 @@ public bool TryGetLinkedPlayer(out ushort Id) /// public OnReady OnAvatarReady; + /// + /// Marks this avatar as ready and notifies listeners with the owner locality. + /// + /// True when this avatar belongs to the local player. + public void NotifyAvatarReady(bool isOwner) + { + IsOwnedLocally = isOwner; + IsReady = true; + OnAvatarReady?.Invoke(isOwner); + } + + public static GameObject GetGameObject (object o) + { + GameObject currentGameobject = null; + if (o is GameObject go) + { + currentGameobject = go; + } + if (o is Component c) + { + currentGameobject = c.gameObject; + } + while (currentGameobject.transform.parent != null) + { + if (currentGameobject.TryGetComponent( out BasisAvatar _ ) ) + { + return currentGameobject; + } + else + { + currentGameobject = currentGameobject.transform.parent.gameObject; + } + } + Debug.LogError( $"Object {o} is not part of an avatar hierarchy." ); + return null; + + } + /// /// Processing options used when the avatar is processed. This is always null after the avatar is processed. /// diff --git a/Basis/Packages/com.basis.sdk/Settings/AvatarContentPoliceSelector.asset b/Basis/Packages/com.basis.sdk/Settings/AvatarContentPoliceSelector.asset index f1c2e87616..5cec2383db 100644 --- a/Basis/Packages/com.basis.sdk/Settings/AvatarContentPoliceSelector.asset +++ b/Basis/Packages/com.basis.sdk/Settings/AvatarContentPoliceSelector.asset @@ -191,4 +191,5 @@ MonoBehaviour: - UnityEngine.AudioEchoFilter - UnityEngine.AudioDistortionFilter - Cilbox.CilboxAvatarBasis + - Basis.Shims.BasisAvatarShim - Basis.Shims.BasisNetworkShim diff --git a/Basis/Packages/com.basis.shim/Shims/BasisAvatarShim.cs b/Basis/Packages/com.basis.shim/Shims/BasisAvatarShim.cs new file mode 100644 index 0000000000..741f5613bb --- /dev/null +++ b/Basis/Packages/com.basis.shim/Shims/BasisAvatarShim.cs @@ -0,0 +1,73 @@ +using Basis.Scripts.BasisSdk; +using Cilbox; +using UnityEngine; + +namespace Basis.Shims +{ + [DisallowMultipleComponent] + public sealed class BasisAvatarShim : CilboxShim + { + public delegate void AvatarReadyEvent(bool isLocalPlayer); + + private AvatarReadyEvent avatarReadyHandlers; + private BasisAvatar avatar; + private bool isReady; + private bool isLocalPlayer; + + public event AvatarReadyEvent AvatarReady + { + add + { + avatarReadyHandlers += value; + if (isReady) + { + value?.Invoke(isLocalPlayer); + } + } + remove => avatarReadyHandlers -= value; + } + + public bool IsReady => isReady; + public bool IsLocalPlayer => isLocalPlayer; + public bool IsOwner => isLocalPlayer; + public BasisAvatar Avatar => avatar; + + private void Awake() + { + avatar = GetComponent(); + if (avatar == null) + { + avatar = GetComponentInParent(true); + } + + if (avatar == null) + { + BasisDebug.LogError("[BasisAvatarShim] Could not resolve a BasisAvatar for this shim."); + return; + } + + avatar.OnAvatarReady -= OnAvatarReady; + avatar.OnAvatarReady += OnAvatarReady; + + if (avatar.IsReady) + { + OnAvatarReady(avatar.IsOwnedLocally); + } + } + + private void OnDestroy() + { + if (avatar != null) + { + avatar.OnAvatarReady -= OnAvatarReady; + } + } + + private void OnAvatarReady(bool ownerIsLocal) + { + isReady = true; + isLocalPlayer = ownerIsLocal; + avatarReadyHandlers?.Invoke(ownerIsLocal); + } + } +} diff --git a/Basis/Packages/com.basis.shim/Shims/BasisAvatarShim.cs.meta b/Basis/Packages/com.basis.shim/Shims/BasisAvatarShim.cs.meta new file mode 100644 index 0000000000..4ae952353d --- /dev/null +++ b/Basis/Packages/com.basis.shim/Shims/BasisAvatarShim.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2ec2ae2858ce4a9b9ef3f5169c12e719 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Basis/Packages/com.basis.shim/Shims/BasisShims.cs b/Basis/Packages/com.basis.shim/Shims/BasisShims.cs index b3d35b0410..29484301f4 100644 --- a/Basis/Packages/com.basis.shim/Shims/BasisShims.cs +++ b/Basis/Packages/com.basis.shim/Shims/BasisShims.cs @@ -1,4 +1,5 @@ using Basis.Shims; +using Basis.Scripts.BasisSdk; using System; using UnityEngine.Networking; using UnityEngine; diff --git a/Basis/Packages/com.basis.shim/Shims/CilboxAvatarBasis.cs b/Basis/Packages/com.basis.shim/Shims/CilboxAvatarBasis.cs index 238e94340a..4251b7f47a 100644 --- a/Basis/Packages/com.basis.shim/Shims/CilboxAvatarBasis.cs +++ b/Basis/Packages/com.basis.shim/Shims/CilboxAvatarBasis.cs @@ -24,6 +24,8 @@ public class CilboxAvatarBasis : Cilbox "Basis.Scripts.BasisSdk.Players.BasisLocalPlayer", "Basis.Scripts.Networking.NetworkedAvatar.BasisNetworkPlayer", "Basis.Shims.BasisNet*", // Restrictive, only used as a type and for events. + "Basis.Shims.BasisAvatarShim", + "Basis.Shims.BasisAvatarShim+AvatarReadyEvent", "Basis.Shims.BasisCilboxInstantiateShim", // Restrictive, only used as a type and for Instantiate methods. "Basis.Shims.BasisDebugPropsShim", // Restrictive, only used as a type and for logging methods. From 37ebd82ed50454cc02d9406e93ab6c34ca5dbac5 Mon Sep 17 00:00:00 2001 From: Toys0125 Date: Thu, 16 Apr 2026 00:56:02 -0500 Subject: [PATCH 6/8] Add nessary hooks, and whitelist for the Froggy Car to work. --- .../Scripts/Basis Components/BasisAvatar.cs | 31 ++-- .../com.basis.shim/Shims/BasisAvatarShim.cs | 170 ++++++++++++++++-- .../Shims/BasisCilboxBuildHook.cs | 7 + .../com.basis.shim/Shims/CilboxAvatarBasis.cs | 26 ++- .../com.basis.shim/Shims/CilboxPropBasis.cs | 5 +- .../com.basis.shim/Shims/CilboxSceneBasis.cs | 3 +- Basis/Packages/com.cnlohr.cilbox/Cilbox.cs | 2 +- .../com.cnlohr.cilbox/CilboxAvatar.cs | 2 +- .../Packages/com.cnlohr.cilbox/CilboxProxy.cs | 2 +- .../Packages/com.cnlohr.cilbox/CilboxScene.cs | 2 +- .../Packages/com.cnlohr.cilbox/CilboxUsage.cs | 27 ++- 11 files changed, 237 insertions(+), 40 deletions(-) diff --git a/Basis/Packages/com.basis.sdk/Scripts/Basis Components/BasisAvatar.cs b/Basis/Packages/com.basis.sdk/Scripts/Basis Components/BasisAvatar.cs index a90ccea794..d1f33de03c 100644 --- a/Basis/Packages/com.basis.sdk/Scripts/Basis Components/BasisAvatar.cs +++ b/Basis/Packages/com.basis.sdk/Scripts/Basis Components/BasisAvatar.cs @@ -63,7 +63,7 @@ public class BasisAvatar : BasisContentBase /// /// True if this avatar is owned by the local player. /// - public bool IsOwnedLocally; + public bool IsOwnedLocally { get; set; } /// /// True once avatar setup has completed and readiness callbacks have fired for this instance. @@ -117,7 +117,7 @@ public bool TryGetLinkedPlayer(out ushort Id) /// /// Event triggered when the avatar is ready for further initialization or data queries. /// - public OnReady OnAvatarReady; + public OnReady OnAvatarReady {get; set;} /// /// Marks this avatar as ready and notifies listeners with the owner locality. @@ -130,31 +130,42 @@ public void NotifyAvatarReady(bool isOwner) OnAvatarReady?.Invoke(isOwner); } - public static GameObject GetGameObject (object o) + public static GameObject GetGameObject(object o) { GameObject currentGameobject = null; if (o is GameObject go) { currentGameobject = go; } - if (o is Component c) + else if (o is Component c) { currentGameobject = c.gameObject; } - while (currentGameobject.transform.parent != null) + + if (currentGameobject == null) + { + Debug.LogError($"Object {o} is not a GameObject or Component."); + return null; + } + + while (currentGameobject != null) { - if (currentGameobject.TryGetComponent( out BasisAvatar _ ) ) + if (currentGameobject.TryGetComponent(out _)) { return currentGameobject; } - else + + Transform parent = currentGameobject.transform.parent; + if (parent == null) { - currentGameobject = currentGameobject.transform.parent.gameObject; + break; } + + currentGameobject = parent.gameObject; } - Debug.LogError( $"Object {o} is not part of an avatar hierarchy." ); - return null; + Debug.LogError($"Object {o} is not part of an avatar hierarchy."); + return null; } /// diff --git a/Basis/Packages/com.basis.shim/Shims/BasisAvatarShim.cs b/Basis/Packages/com.basis.shim/Shims/BasisAvatarShim.cs index 741f5613bb..b6a19f885b 100644 --- a/Basis/Packages/com.basis.shim/Shims/BasisAvatarShim.cs +++ b/Basis/Packages/com.basis.shim/Shims/BasisAvatarShim.cs @@ -1,36 +1,101 @@ using Basis.Scripts.BasisSdk; using Cilbox; using UnityEngine; - namespace Basis.Shims { [DisallowMultipleComponent] public sealed class BasisAvatarShim : CilboxShim { + private static readonly int[] DefaultFaceVisemeMovement = new int[] { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; + private static readonly int[] DefaultBlinkViseme = new int[] { -1 }; + + public delegate void OnReady(bool IsOwner); public delegate void AvatarReadyEvent(bool isLocalPlayer); - private AvatarReadyEvent avatarReadyHandlers; + public Vector2 AvatarEyePosition; + public Vector2 AvatarMouthPosition; + public Vector3 AnimatorHumanScale = Vector3.one; + private BasisAvatar avatar; - private bool isReady; private bool isLocalPlayer; + private OnReady onAvatarReady; - public event AvatarReadyEvent AvatarReady + public OnReady OnAvatarReady { - add + get => onAvatarReady; + set { - avatarReadyHandlers += value; - if (isReady) + OnReady previousHandlers = onAvatarReady; + onAvatarReady = value; + + // Always keep the newly assigned handlers. If the avatar is not ready yet, + // they remain registered and AvatarReady(...) will invoke them later. + bool shouldReplayImmediately = IsReady && onAvatarReady != null; + if (!shouldReplayImmediately) { - value?.Invoke(isLocalPlayer); + return; } + + ReplayNewReadyHandlers(previousHandlers, onAvatarReady, isLocalPlayer); } - remove => avatarReadyHandlers -= value; } - public bool IsReady => isReady; + public bool IsReady => avatar != null && avatar.IsReady; public bool IsLocalPlayer => isLocalPlayer; public bool IsOwner => isLocalPlayer; public BasisAvatar Avatar => avatar; + public bool HasLinkedPlayer => avatar != null && avatar.HasLinkedPlayer; + public Animator Animator + { + get => avatar != null ? avatar.Animator : null; + } + + public SkinnedMeshRenderer FaceVisemeMesh + { + get => avatar != null ? avatar.FaceVisemeMesh : null; + } + + public SkinnedMeshRenderer FaceBlinkMesh + { + get => avatar != null ? avatar.FaceBlinkMesh : null; + } + + public int[] FaceVisemeMovement + { + get => avatar != null ? avatar.FaceVisemeMovement : DefaultFaceVisemeMovement; + } + + public int[] BlinkViseme + { + get => avatar != null ? avatar.BlinkViseme : DefaultBlinkViseme; + } + + public int laughterBlendTarget + { + get => avatar != null ? avatar.laughterBlendTarget : -1; + } + + public bool IsOwnedLocally + { + get => avatar != null ? avatar.IsOwnedLocally : isLocalPlayer; + } + + public float HumanScale + { + get => avatar != null ? avatar.HumanScale : 1; + set + { + if (avatar != null) + { + avatar.HumanScale = value; + } + } + } + + public ushort LinkedPlayerID + { + get => avatar != null ? avatar.LinkedPlayerID : (ushort)0; + } private void Awake() { @@ -46,12 +111,13 @@ private void Awake() return; } - avatar.OnAvatarReady -= OnAvatarReady; - avatar.OnAvatarReady += OnAvatarReady; + SyncFieldsFromAvatar(); + avatar.OnAvatarReady -= AvatarReady; + avatar.OnAvatarReady += AvatarReady; if (avatar.IsReady) { - OnAvatarReady(avatar.IsOwnedLocally); + AvatarReady(avatar.IsOwnedLocally); } } @@ -59,15 +125,85 @@ private void OnDestroy() { if (avatar != null) { - avatar.OnAvatarReady -= OnAvatarReady; + avatar.OnAvatarReady -= AvatarReady; } } - private void OnAvatarReady(bool ownerIsLocal) + private void AvatarReady(bool ownerIsLocal) { - isReady = true; isLocalPlayer = ownerIsLocal; - avatarReadyHandlers?.Invoke(ownerIsLocal); + SyncFieldsFromAvatar(); + OnAvatarReady?.Invoke(ownerIsLocal); + } + + public bool TryGetLinkedPlayer(out ushort Id) + { + if (avatar == null) + { + Id = 0; + return false; + } + + return avatar.TryGetLinkedPlayer(out Id); + } + + public void NotifyAvatarReady(bool isOwner) + { + if (avatar == null) + { + return; + } + + avatar.NotifyAvatarReady(isOwner); + SyncFieldsFromAvatar(); + } + + private static void ReplayNewReadyHandlers(OnReady previousHandlers, OnReady currentHandlers, bool ownerIsLocal) + { + System.Collections.Generic.Dictionary existingHandlers = new System.Collections.Generic.Dictionary(); + if (previousHandlers != null) + { + foreach (System.Delegate handler in previousHandlers.GetInvocationList()) + { + if (existingHandlers.TryGetValue(handler, out int count)) + { + existingHandlers[handler] = count + 1; + } + else + { + existingHandlers[handler] = 1; + } + } + } + + foreach (System.Delegate handler in currentHandlers.GetInvocationList()) + { + if (existingHandlers.TryGetValue(handler, out int count) && count > 0) + { + existingHandlers[handler] = count - 1; + continue; + } + + ((OnReady)handler).Invoke(ownerIsLocal); + } + } + // Cilbox remaps BasisAvatar.GetGameObject(...) to this shim type, so forward to the real avatar helper. + public static GameObject GetGameObject(object o) + { + return BasisAvatar.GetGameObject(o); + } + + private void SyncFieldsFromAvatar() + { + if (avatar == null) + { + return; + } + + AvatarEyePosition = avatar.AvatarEyePosition; + AvatarMouthPosition = avatar.AvatarMouthPosition; + AnimatorHumanScale = avatar.AnimatorHumanScale; + isLocalPlayer = avatar.IsOwnedLocally; } } } diff --git a/Basis/Packages/com.basis.shim/Shims/BasisCilboxBuildHook.cs b/Basis/Packages/com.basis.shim/Shims/BasisCilboxBuildHook.cs index 81557c088f..7e19d59afe 100644 --- a/Basis/Packages/com.basis.shim/Shims/BasisCilboxBuildHook.cs +++ b/Basis/Packages/com.basis.shim/Shims/BasisCilboxBuildHook.cs @@ -17,6 +17,13 @@ private static void Initialize() //Debug.Log("BasisCilboxBuildHook initialized."); BasisAssetBundlePipeline.OnBeforeBuildPrefab -= HandleBeforeBuildPrefab; BasisAssetBundlePipeline.OnBeforeBuildPrefab += HandleBeforeBuildPrefab; + BasisAvatarSDKInspector.OnBeforeTestInEditor -= HandleBeforeTestInEditor; + BasisAvatarSDKInspector.OnBeforeTestInEditor += HandleBeforeTestInEditor; + } + + private static void HandleBeforeTestInEditor(GameObject prefabRoot) + { + HandleBeforeBuildPrefab(prefabRoot, null); } private static void HandleBeforeBuildPrefab(GameObject prefabRoot, BasisAssetBundleObject settings) diff --git a/Basis/Packages/com.basis.shim/Shims/CilboxAvatarBasis.cs b/Basis/Packages/com.basis.shim/Shims/CilboxAvatarBasis.cs index 4251b7f47a..2406170805 100644 --- a/Basis/Packages/com.basis.shim/Shims/CilboxAvatarBasis.cs +++ b/Basis/Packages/com.basis.shim/Shims/CilboxAvatarBasis.cs @@ -25,6 +25,7 @@ public class CilboxAvatarBasis : Cilbox "Basis.Scripts.Networking.NetworkedAvatar.BasisNetworkPlayer", "Basis.Shims.BasisNet*", // Restrictive, only used as a type and for events. "Basis.Shims.BasisAvatarShim", + "Basis.Shims.BasisAvatarShim+OnReady", "Basis.Shims.BasisAvatarShim+AvatarReadyEvent", "Basis.Shims.BasisCilboxInstantiateShim", // Restrictive, only used as a type and for Instantiate methods. "Basis.Shims.BasisDebugPropsShim", // Restrictive, only used as a type and for logging methods. @@ -44,6 +45,7 @@ public class CilboxAvatarBasis : Cilbox "System.DateTime", "System.DateTimeOffset", "System.DayOfWeek", + "System.Delegate", "System.Diagnostics.Stopwatch", "System.Double", "System.Exception", @@ -90,6 +92,7 @@ public class CilboxAvatarBasis : Cilbox "UnityEngine.Rigidbody", "UnityEngine.RenderTexture", "UnityEngine.RenderTextureFormat", + "UnityEngine.SkinnedMeshRenderer", "UnityEngine.UI.*", "UnityEngine.Vector*", "UnityEngine.UI.InputField", @@ -109,6 +112,7 @@ public class CilboxAvatarBasis : Cilbox "UnityEngine.Vector*.y", "UnityEngine.Vector*.z", "UnityEngine.Vector*.w", + "UnityEngine.Quaternion*", // System fields "System.Array.*", @@ -116,6 +120,20 @@ public class CilboxAvatarBasis : Cilbox // Basis types + "Basis.Shims.BasisAvatarShim.Animator", + "Basis.Shims.BasisAvatarShim.FaceVisemeMesh", + "Basis.Shims.BasisAvatarShim.FaceBlinkMesh", + "Basis.Shims.BasisAvatarShim.AvatarEyePosition", + "Basis.Shims.BasisAvatarShim.AvatarMouthPosition", + "Basis.Shims.BasisAvatarShim.FaceVisemeMovement", + "Basis.Shims.BasisAvatarShim.BlinkViseme", + "Basis.Shims.BasisAvatarShim.laughterBlendTarget", + "Basis.Shims.BasisAvatarShim.AnimatorHumanScale", + "Basis.Shims.BasisAvatarShim.IsOwnedLocally", + "Basis.Shims.BasisAvatarShim.Renders", + "Basis.Shims.BasisAvatarShim.ProcessingAvatarOptions", + "Basis.Shims.BasisAvatarShim.HumanScale", + "Basis.Scripts.BasisSdk.BasisProcessingAvatarOptions.doNotAutoRenameBones", "Basis.Scripts.BasisSdk.Interactions.BasisPickupInteractable.OnPickupUse", "Basis.Scripts.BasisSdk.Interactions.BasisInteractableObject.OnInteractStartEvent", "Basis.Scripts.BasisSdk.Interactions.BasisInteractableObject.OnInteractEndEvent", @@ -221,7 +239,7 @@ override public bool CheckMethodAllowed( out MethodInfo mi, Type declaringType, return true; } - public override bool GetComponentTypeOverride(string sType, out Type t) + public override bool GetTypeOverride(string sType, out Type t) { switch(sType) { @@ -244,6 +262,12 @@ public override bool GetComponentTypeOverride(string sType, out Type t) case "UnityEngine.Debug": t = typeof(Basis.Shims.BasisDebugPropsShim); return true; + case "Basis.Scripts.BasisSdk.BasisAvatar": + t = typeof(Basis.Shims.BasisAvatarShim); + return true; + case "Basis.Scripts.BasisSdk.BasisAvatar+OnReady": + t = typeof(Basis.Shims.BasisAvatarShim.OnReady); + return true; default: t = null; return false; diff --git a/Basis/Packages/com.basis.shim/Shims/CilboxPropBasis.cs b/Basis/Packages/com.basis.shim/Shims/CilboxPropBasis.cs index a2cf393599..61025b6340 100644 --- a/Basis/Packages/com.basis.shim/Shims/CilboxPropBasis.cs +++ b/Basis/Packages/com.basis.shim/Shims/CilboxPropBasis.cs @@ -40,6 +40,7 @@ public class CilboxPropBasis : Cilbox "System.DateTime", "System.DateTimeOffset", "System.DayOfWeek", + "System.Delegate", "System.Diagnostics.Stopwatch", "System.Double", "System.Exception", @@ -107,6 +108,7 @@ public class CilboxPropBasis : Cilbox "UnityEngine.Vector*.y", "UnityEngine.Vector*.z", "UnityEngine.Vector*.w", + "UnityEngine.Quaternion*", // System fields "System.Array.*", @@ -219,11 +221,10 @@ override public bool CheckMethodAllowed( out MethodInfo mi, Type declaringType, return true; } - public override bool GetComponentTypeOverride(string sType, out Type t) + public override bool GetTypeOverride(string sType, out Type t) { switch(sType) { - case "UnityEngine.Video.VideoPlayer": t = typeof(Basis.Shims.VideoPlayerShim); return true; diff --git a/Basis/Packages/com.basis.shim/Shims/CilboxSceneBasis.cs b/Basis/Packages/com.basis.shim/Shims/CilboxSceneBasis.cs index bf321b937b..9f33de8fba 100644 --- a/Basis/Packages/com.basis.shim/Shims/CilboxSceneBasis.cs +++ b/Basis/Packages/com.basis.shim/Shims/CilboxSceneBasis.cs @@ -135,6 +135,7 @@ public class CilboxSceneBasis : Cilbox "UnityEngine.Vector*.y", "UnityEngine.Vector*.z", "UnityEngine.Vector*.w", + "UnityEngine.Quaternion*", // System fields "System.Array.*", @@ -233,7 +234,7 @@ override public bool CheckMethodAllowed( out MethodInfo mi, Type declaringType, return true; } - public override bool GetComponentTypeOverride(string sType, out Type t) + public override bool GetTypeOverride(string sType, out Type t) { switch(sType) { diff --git a/Basis/Packages/com.cnlohr.cilbox/Cilbox.cs b/Basis/Packages/com.cnlohr.cilbox/Cilbox.cs index 19953109e2..84d1c79ecf 100644 --- a/Basis/Packages/com.cnlohr.cilbox/Cilbox.cs +++ b/Basis/Packages/com.cnlohr.cilbox/Cilbox.cs @@ -2047,7 +2047,7 @@ public Cilbox() abstract public bool CheckMethodAllowed( out MethodInfo mi, Type declaringType, String name, Serializee [] parametersIn, Serializee [] genericArgumentsIn, String fullSignature ); abstract public bool CheckTypeAllowed( String sType ); abstract public bool CheckFieldAllowed( String sType, String sFieldName ); - abstract public bool GetComponentTypeOverride( String sType, out Type t ); + abstract public bool GetTypeOverride( String sType, out Type t ); public delegate void CilboxDisabledEvent( Cilbox box, string reason ); diff --git a/Basis/Packages/com.cnlohr.cilbox/CilboxAvatar.cs b/Basis/Packages/com.cnlohr.cilbox/CilboxAvatar.cs index 6b33e9e71e..a444341120 100644 --- a/Basis/Packages/com.cnlohr.cilbox/CilboxAvatar.cs +++ b/Basis/Packages/com.cnlohr.cilbox/CilboxAvatar.cs @@ -115,7 +115,7 @@ override public bool CheckMethodAllowed( out MethodInfo mi, Type declaringType, return true; } - public override bool GetComponentTypeOverride(string sType, out Type t) + public override bool GetTypeOverride(string sType, out Type t) { t = null; return false; diff --git a/Basis/Packages/com.cnlohr.cilbox/CilboxProxy.cs b/Basis/Packages/com.cnlohr.cilbox/CilboxProxy.cs index 69e4540120..0e25a67d25 100644 --- a/Basis/Packages/com.cnlohr.cilbox/CilboxProxy.cs +++ b/Basis/Packages/com.cnlohr.cilbox/CilboxProxy.cs @@ -229,7 +229,7 @@ public void RuntimeProxyLoad() continue; } Type t = o.GetType(); - if(box.GetComponentTypeOverride( t.FullName, out Type overrideType )) { + if(box.GetTypeOverride( t.FullName, out Type overrideType )) { Debug.Log( $"RuntimeProxyLoad: Override {t.FullName} with {overrideType.FullName}" ); t = overrideType; if(typeof(CilboxShim).IsAssignableFrom(t) && fieldsObjects[i] is Component gameObjectComponent) diff --git a/Basis/Packages/com.cnlohr.cilbox/CilboxScene.cs b/Basis/Packages/com.cnlohr.cilbox/CilboxScene.cs index 765bc7c0ff..31b8a7b264 100644 --- a/Basis/Packages/com.cnlohr.cilbox/CilboxScene.cs +++ b/Basis/Packages/com.cnlohr.cilbox/CilboxScene.cs @@ -126,7 +126,7 @@ override public bool CheckMethodAllowed( out MethodInfo mi, Type declaringType, return true; } - public override bool GetComponentTypeOverride(string sType, out Type t) + public override bool GetTypeOverride(string sType, out Type t) { t = null; return false; diff --git a/Basis/Packages/com.cnlohr.cilbox/CilboxUsage.cs b/Basis/Packages/com.cnlohr.cilbox/CilboxUsage.cs index 32832584b8..84c7b8a9e0 100644 --- a/Basis/Packages/com.cnlohr.cilbox/CilboxUsage.cs +++ b/Basis/Packages/com.cnlohr.cilbox/CilboxUsage.cs @@ -67,8 +67,8 @@ public MethodBase GetNativeMethodFromTypeAndName( Type declaringType, String nam if( !bDisallowed ) goto disallowed; if( mi != null ) return mi; - // Replace any delegate creations with their proxies. - if( typeof(Delegate).IsAssignableFrom(declaringType) ) + // Replace delegate construction with cilbox-backed host delegates. + if( typeof(Delegate).IsAssignableFrom(declaringType) && name == ".ctor" ) { int argct = declaringType.GenericTypeArguments.Length; Type specific = typeof(CilboxPlatform); @@ -385,7 +385,7 @@ public Type GetNativeTypeFromSerializee( Serializee s ) String typeName = ses["n"].AsString(); String assemblyName = ses["a"].AsString(); if( IsCilboxInternalType( typeName ) ) return null; - if(box.GetComponentTypeOverride( typeName, out Type overrideType )) { + if(box.GetTypeOverride( typeName, out Type overrideType )) { Debug.Log( $"GetNativeTypeFromSerializee: Override {typeName} with {overrideType.FullName}" ); typeName = overrideType.FullName; assemblyName = overrideType.Assembly.GetName().Name; @@ -441,7 +441,7 @@ public String GetNativeTypeNameFromSerializee( Serializee s ) if( ses.TryGetValue( "ut", out utSer ) ) return GetNativeTypeNameFromSerializee( utSer ); String typeName = ses["n"].AsString(); if( IsCilboxInternalType( typeName ) ) return typeName; - if(box.GetComponentTypeOverride( typeName, out Type overrideType )) { + if(box.GetTypeOverride( typeName, out Type overrideType )) { Debug.Log( $"GetNativeTypeFromSerializee: Override {typeName} with {overrideType.FullName}" ); typeName = overrideType.FullName; } @@ -618,8 +618,25 @@ public class CilboxPlatform { // This is called only when creating a new action, not when it's called. // T is the delegate, not the arguments of the delegate. - static public object ProxyForGeneratingActions( CilboxProxy proxy, CilboxMethod method ) + static public object ProxyForGeneratingActions( CilboxProxy proxy, object methodOrDelegate ) { + if( methodOrDelegate is T existingTypedDelegate ) + { + return existingTypedDelegate; + } + + if( methodOrDelegate is Delegate existingDelegate && + typeof(T).IsAssignableFrom( existingDelegate.GetType() ) ) + { + return existingDelegate; + } + + if( methodOrDelegate is not CilboxMethod method ) + { + throw new ArgumentException( + $"ProxyForGeneratingActions expected a CilboxMethod or compatible delegate, got {methodOrDelegate?.GetType().FullName ?? "null"}" ); + } + CilboxPlatform.DelegateRepackage rp = new CilboxPlatform.DelegateRepackage(); rp.meth = method; rp.o = proxy; From a1b1c3c5ccede9942ae25a571df1b6c931b0c963 Mon Sep 17 00:00:00 2001 From: Toys0125 Date: Thu, 16 Apr 2026 01:20:24 -0500 Subject: [PATCH 7/8] Restore BasisInteractableShim.cs.meta --- .../Packages/com.basis.shim/Shims/BasisInteractableShim.cs.meta | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Basis/Packages/com.basis.shim/Shims/BasisInteractableShim.cs.meta diff --git a/Basis/Packages/com.basis.shim/Shims/BasisInteractableShim.cs.meta b/Basis/Packages/com.basis.shim/Shims/BasisInteractableShim.cs.meta new file mode 100644 index 0000000000..7f61e36338 --- /dev/null +++ b/Basis/Packages/com.basis.shim/Shims/BasisInteractableShim.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: f8c388c62246d4cbda53a221c1c5408c \ No newline at end of file From 1d715c266ab45a787922310571c5bb18749a168e Mon Sep 17 00:00:00 2001 From: Toys0125 Date: Thu, 16 Apr 2026 01:55:36 -0500 Subject: [PATCH 8/8] Limit scope. --- Basis/Packages/com.basis.shim/Shims/BasisAvatarShim.cs | 2 +- Basis/Packages/com.basis.shim/Shims/CilboxAvatarBasis.cs | 2 -- Basis/Packages/com.basis.shim/Shims/CilboxSceneBasis.cs | 5 ++++- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Basis/Packages/com.basis.shim/Shims/BasisAvatarShim.cs b/Basis/Packages/com.basis.shim/Shims/BasisAvatarShim.cs index b6a19f885b..05d04c6821 100644 --- a/Basis/Packages/com.basis.shim/Shims/BasisAvatarShim.cs +++ b/Basis/Packages/com.basis.shim/Shims/BasisAvatarShim.cs @@ -147,7 +147,7 @@ public bool TryGetLinkedPlayer(out ushort Id) return avatar.TryGetLinkedPlayer(out Id); } - public void NotifyAvatarReady(bool isOwner) + private void NotifyAvatarReady(bool isOwner) { if (avatar == null) { diff --git a/Basis/Packages/com.basis.shim/Shims/CilboxAvatarBasis.cs b/Basis/Packages/com.basis.shim/Shims/CilboxAvatarBasis.cs index 2406170805..31fe1d4785 100644 --- a/Basis/Packages/com.basis.shim/Shims/CilboxAvatarBasis.cs +++ b/Basis/Packages/com.basis.shim/Shims/CilboxAvatarBasis.cs @@ -130,8 +130,6 @@ public class CilboxAvatarBasis : Cilbox "Basis.Shims.BasisAvatarShim.laughterBlendTarget", "Basis.Shims.BasisAvatarShim.AnimatorHumanScale", "Basis.Shims.BasisAvatarShim.IsOwnedLocally", - "Basis.Shims.BasisAvatarShim.Renders", - "Basis.Shims.BasisAvatarShim.ProcessingAvatarOptions", "Basis.Shims.BasisAvatarShim.HumanScale", "Basis.Scripts.BasisSdk.BasisProcessingAvatarOptions.doNotAutoRenameBones", "Basis.Scripts.BasisSdk.Interactions.BasisPickupInteractable.OnPickupUse", diff --git a/Basis/Packages/com.basis.shim/Shims/CilboxSceneBasis.cs b/Basis/Packages/com.basis.shim/Shims/CilboxSceneBasis.cs index 9f33de8fba..9be7fe6ebf 100644 --- a/Basis/Packages/com.basis.shim/Shims/CilboxSceneBasis.cs +++ b/Basis/Packages/com.basis.shim/Shims/CilboxSceneBasis.cs @@ -135,7 +135,10 @@ public class CilboxSceneBasis : Cilbox "UnityEngine.Vector*.y", "UnityEngine.Vector*.z", "UnityEngine.Vector*.w", - "UnityEngine.Quaternion*", + "UnityEngine.Quaternion.x", + "UnityEngine.Quaternion.y", + "UnityEngine.Quaternion.z", + "UnityEngine.Quaternion.w", // System fields "System.Array.*",