Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,11 @@
[CustomEditor(typeof(BasisAvatar))]
public partial class BasisAvatarSDKInspector : Editor
{
private const string PendingTestInEditorAvatarIdSessionKey = "BasisAvatarSDKInspector.PendingTestInEditorAvatarId";

public delegate void BeforeTestInEditorHandler(GameObject clone);
public static BeforeTestInEditorHandler OnBeforeTestInEditor;
private static BasisAvatar ScheduledTestInEditorAvatar;

public static event Action<BasisAvatarSDKInspector> InspectorGuiCreated;
public static event Action ButtonClicked;
Expand All @@ -32,6 +35,71 @@ public partial class BasisAvatarSDKInspector : Editor
private Label resultLabel; // Store the result label for later clearing
public string Error;
public BasisAvatarValidator BasisAvatarValidator;

[InitializeOnLoadMethod]
private static void InitializeTestInEditorHooks()
{
EditorApplication.playModeStateChanged -= OnPlayModeStateChanged;
EditorApplication.playModeStateChanged += OnPlayModeStateChanged;
}

private static void OnPlayModeStateChanged(PlayModeStateChange state)
{
if (state != PlayModeStateChange.EnteredPlayMode || !HasPendingTestInEditorAvatarId())
{
return;
}

EditorApplication.delayCall -= TryExecutePendingTestInEditor;
EditorApplication.delayCall += TryExecutePendingTestInEditor;
}

private static void TryExecutePendingTestInEditor()
{
string pendingAvatarId = GetPendingTestInEditorAvatarId();
if (string.IsNullOrEmpty(pendingAvatarId))
{
return;
}

if (!GlobalObjectId.TryParse(pendingAvatarId, out GlobalObjectId avatarId))
{
ClearPendingTestInEditorAvatarId();
return;
}

BasisAvatar avatar = GlobalObjectId.GlobalObjectIdentifierToObjectSlow(avatarId) as BasisAvatar;
ClearPendingTestInEditorAvatarId();
if (avatar == null)
{
BasisDebug.LogError("Unable to resolve the pending avatar for Test In Editor.", BasisDebug.LogTag.Editor);
return;
}

RequestAvatarLoad(avatar);
}

private static bool HasPendingTestInEditorAvatarId()
{
return SessionState.GetBool(PendingTestInEditorAvatarIdSessionKey + ".Exists", false);
}

private static string GetPendingTestInEditorAvatarId()
{
return SessionState.GetString(PendingTestInEditorAvatarIdSessionKey, string.Empty);
}

private static void SetPendingTestInEditorAvatarId(string avatarId)
{
SessionState.SetString(PendingTestInEditorAvatarIdSessionKey, avatarId ?? string.Empty);
SessionState.SetBool(PendingTestInEditorAvatarIdSessionKey + ".Exists", !string.IsNullOrEmpty(avatarId));
}

private static void ClearPendingTestInEditorAvatarId()
{
SessionState.EraseString(PendingTestInEditorAvatarIdSessionKey);
SessionState.SetBool(PendingTestInEditorAvatarIdSessionKey + ".Exists", false);
}
private void OnEnable()
{
visualTree = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(BasisSDKConstants.AvataruxmlPath);
Expand Down Expand Up @@ -513,9 +581,10 @@ public void AvatarTestInEditorClickFunction()
{
if (!Application.isPlaying)
{
bool result = EditorUtility.DisplayDialog("Confirmation", "this feature requires the editor to be in playmode. do you want to enter play mode now? once done you will need to press it again! please also make sure you have a floor in your scene!", "yes", "no");
bool result = EditorUtility.DisplayDialog("Confirmation", "this feature requires the editor to be in playmode. do you want to enter play mode now and run Test In Editor automatically? please also make sure you have a floor in your scene!", "yes", "no");
if (result)
{
SetPendingTestInEditorAvatarId(GlobalObjectId.GetGlobalObjectIdSlow(Avatar).ToString());
EditorApplication.EnterPlaymode();
}
}
Expand All @@ -525,34 +594,50 @@ public void AvatarTestInEditorClickFunction()
}
}
public void RequestAvatarLoad()
{
RequestAvatarLoad(Avatar);
}

private static void RequestAvatarLoad(BasisAvatar avatar)
{
#if BASIS_FRAMEWORK_EXISTS
if (BasisLocalPlayer.PlayerReady)
{
BasisDebug.Log("Player Ready Loading", BasisDebug.LogTag.Editor);
LoadAvatar();
LoadAvatar(avatar);
}
else
{
ScheduleCallback = true;
ScheduledTestInEditorAvatar = avatar;
BasisDebug.Log("Scheduling Load Avatar", BasisDebug.LogTag.Editor);
BasisLocalPlayer.OnLocalPlayerInitalized += LoadAvatar;
BasisLocalPlayer.OnLocalPlayerInitalized -= LoadScheduledAvatar;
BasisLocalPlayer.OnLocalPlayerInitalized += LoadScheduledAvatar;
}
#endif
}
public bool ScheduleCallback = false;
public async void LoadAvatar()

private static void LoadScheduledAvatar()
{
#if BASIS_FRAMEWORK_EXISTS
if (ScheduleCallback)
BasisLocalPlayer.OnLocalPlayerInitalized -= LoadScheduledAvatar;
if (ScheduledTestInEditorAvatar == null)
{
BasisLocalPlayer.OnLocalPlayerInitalized -= LoadAvatar;
ScheduleCallback = false;
return;
}

BasisAvatar avatar = ScheduledTestInEditorAvatar;
ScheduledTestInEditorAvatar = null;
LoadAvatar(avatar);
#endif
}

private static async void LoadAvatar(BasisAvatar avatar)
{
#if BASIS_FRAMEWORK_EXISTS
BasisDebug.Log("LoadAvatar Called", BasisDebug.LogTag.Editor);

var jigglesToReset = new List<MonoBehaviour>();
foreach (MonoBehaviour jiggle in Avatar.gameObject.GetComponentsInChildren<MonoBehaviour>(false))
foreach (MonoBehaviour jiggle in avatar.gameObject.GetComponentsInChildren<MonoBehaviour>(false))
{
if (jiggle != null
&& jiggle.GetType().FullName == "GatorDragonGames.JigglePhysics.JiggleRig"
Expand All @@ -565,18 +650,18 @@ public async void LoadAvatar()
if (jigglesToReset.Count > 0)
{
BasisDebug.Log("Enabled Jiggles were found when Test in Editor was entered. We will disable the avatar in order to reset the Jiggle transforms.", BasisDebug.LogTag.Editor);
Avatar.gameObject.SetActive(false);
avatar.gameObject.SetActive(false);
// It's a bit of a hack, but waiting three frames works.
await Awaitable.NextFrameAsync();
await Awaitable.NextFrameAsync();
await Awaitable.NextFrameAsync();
inSceneItem = GameObject.Instantiate(Avatar.gameObject);
Avatar.gameObject.SetActive(true);
inSceneItem = GameObject.Instantiate(avatar.gameObject);
avatar.gameObject.SetActive(true);
inSceneItem.SetActive(true);
}
else
{
inSceneItem = GameObject.Instantiate(Avatar.gameObject);
inSceneItem = GameObject.Instantiate(avatar.gameObject);
}

BasisAssetBundlePipeline.DestroyEditorOnlyInAvatar(inSceneItem);
Expand Down
25 changes: 16 additions & 9 deletions Basis/Packages/com.cnlohr.cilbox/CilboxProxy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ public class CilboxProxy : MonoBehaviour
{
public StackElement [] fields;
public List< UnityEngine.Object > fieldsObjects; // This is generally only held during saving and loading, not in use.
[NonSerialized] private List< UnityEngine.Object > runtimeFieldsObjects;

public CilboxClass cls;
public Cilbox box;
Expand Down Expand Up @@ -219,10 +220,12 @@ public void RuntimeProxyLoad()

cls = box.GetClass( className );

runtimeFieldsObjects = fieldsObjects != null ? new List<UnityEngine.Object>(fieldsObjects) : new List<UnityEngine.Object>();

// First thing: Go through any references that are prohibited.
for( int i = 0; i < fieldsObjects.Count; i++ )
for( int i = 0; i < runtimeFieldsObjects.Count; i++ )
{
UnityEngine.Object o = fieldsObjects[i];
UnityEngine.Object o = runtimeFieldsObjects[i];
if (o == null)
{
// If it's null, there's nothing to safety-check.
Expand All @@ -232,7 +235,7 @@ public void RuntimeProxyLoad()
if(box.GetComponentTypeOverride( 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)
if(typeof(CilboxShim).IsAssignableFrom(t) && runtimeFieldsObjects[i] is Component gameObjectComponent)
{
GameObject gameObject = gameObjectComponent.gameObject;
Component component;
Expand All @@ -242,7 +245,7 @@ public void RuntimeProxyLoad()
{
component = gameObject.AddComponent(t);
}
fieldsObjects[i] = component;
runtimeFieldsObjects[i] = component;
}
}
if( t == typeof( CilboxProxy ) )
Expand All @@ -252,7 +255,7 @@ public void RuntimeProxyLoad()
else if( !box.CheckTypeAllowed( t.FullName ) )
{
Debug.LogWarning( $"Contraband found in script {className} field ID {i}: {o.GetType()}" );
fieldsObjects[i] = null;
runtimeFieldsObjects[i] = null;
}
}

Expand Down Expand Up @@ -341,6 +344,7 @@ public void RuntimeProxyLoad()


proxyWasSetup = true;
runtimeFieldsObjects = null;
if (verboseLogging)
Debug.Log( $"RuntimeProxyLoad complete for class {className}" );
}
Expand All @@ -349,6 +353,7 @@ public void RuntimeProxyLoad()
// Returns: true if is object, otherwise is primitive.
private bool LoadObjectFromSerializee( Serializee s, out object oOut, String rootFieldName, Type inType, bool root )
{
List<UnityEngine.Object> objectSlots = runtimeFieldsObjects ?? fieldsObjects;
Dictionary< String, Serializee > dict = s.AsMap();

Serializee setype;
Expand All @@ -361,7 +366,8 @@ private bool LoadObjectFromSerializee( Serializee s, out object oOut, String roo
int iFO;
if( dict.TryGetValue( "fo", out seFO ) &&
Int32.TryParse( seFO.AsString(), out iFO ) &&
iFO < fieldsObjects.Count )
objectSlots != null &&
iFO < objectSlots.Count )
{
if (dict.TryGetValue("or", out var seOr))
{
Expand All @@ -373,7 +379,7 @@ private bool LoadObjectFromSerializee( Serializee s, out object oOut, String roo
}
}

UnityEngine.Object o = fieldsObjects[iFO];
UnityEngine.Object o = objectSlots[iFO];

//Debug.Log( $"LOADING FIELD: {i} with {o}" );
if( o )
Expand All @@ -384,15 +390,16 @@ private bool LoadObjectFromSerializee( Serializee s, out object oOut, String roo
oOut = o;

// Remove reference out of the fieldsObjects array.
fieldsObjects[iFO] = null;
objectSlots[iFO] = null;

return true;
}
Debug.LogWarning( $"[CilboxProxy:{gameObject.name}] Object reference slot {iFO} for field {rootFieldName} is null/missing at load time." );
}
else
{
Debug.LogWarning( $"Failure to load object in field id:{rootFieldName} of {className} (slot parse failed or out of range, fieldsObjects count={fieldsObjects.Count})");
int objectSlotCount = objectSlots != null ? objectSlots.Count : 0;
Debug.LogWarning( $"Failure to load object in field id:{rootFieldName} of {className} (slot parse failed or out of range, fieldsObjects count={objectSlotCount})");
}
}
else if( sT[0] == 'a' )
Expand Down
Loading