Skip to content
Draft
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
53 changes: 53 additions & 0 deletions Basis/Packages/com.basis.bundlemanagement/BasisLoadhandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,59 @@ public static async Task RequestDeIncrementOfBundle(BasisLoadableBundle loadable
}
}
}

public static async Task<UnityEngine.Object> LoadAdditionalAssetInAlreadyLoadedBundle(
BasisLoadableBundle loadableBundle,
string assetPath,
bool includeSubAssets)
{
BasisDebug.Log($"Loading additional asset {assetPath} in already loaded bundle {loadableBundle.BasisRemoteBundleEncrypted.RemoteBeeFileLocation}", BasisDebug.LogTag.Networking);

if (LoadedBundles.TryGetValue(loadableBundle.BasisRemoteBundleEncrypted.RemoteBeeFileLocation, out BasisTrackedBundleWrapper wrapper))
{
if (wrapper.AssetBundle == null)
{
BasisDebug.LogError($"{nameof(LoadAdditionalAssetInAlreadyLoadedBundle)} was called, but the wrapper was not already loaded. It is expected that calls to this method are only made while a bundle is still being used.");
return null;
}

AssetBundleRequest Request = includeSubAssets
? wrapper.AssetBundle.LoadAssetWithSubAssetsAsync<UnityEngine.Object>(assetPath)
: wrapper.AssetBundle.LoadAssetAsync<UnityEngine.Object>(assetPath);
await Request;

UnityEngine.Object result = Request.asset;
if (result == null)
{
BasisDebug.LogError("The additional asset returned null.");
return null;
}
if (result is GameObject or Transform or Component)
{
BasisDebug.LogError($"{nameof(LoadAdditionalAssetInAlreadyLoadedBundle)} was called, but an object of type {result.GetType().Name} was present instead. This is not allowed.");
return null;
}

if (result is BasisObjectReferenceContainer container)
{
if (container.references == null || container.references.Length == 0)
{
BasisDebug.LogError($"{nameof(LoadAdditionalAssetInAlreadyLoadedBundle)} was called, but the object returned by the bundle was a container with no references.");
return null;
}

return container.references[0];
}

return result;
}
else
{
BasisDebug.LogError($"{nameof(LoadAdditionalAssetInAlreadyLoadedBundle)} was called, but the bundle was not already loaded. It is expected that calls to this method are only made while a bundle is still being used.");
return null;
}
}

public static async Task<GameObject> LoadGameObjectBundle(GameObject DisabledGameobject,BasisLoadableBundle loadableBundle, bool useContentRemoval, BasisProgressReport report, CancellationToken cancellationToken, Vector3 Position, Quaternion Rotation, Vector3 Scale, bool ModifyScale, Selector Selector, Transform Parent = null, bool DestroyColliders = false,bool ChangeColidersToCorrectLayer = false, long MaxDownloadSizeInMB = 4L * 1024 * 1024 * 1024, List<BasisHeadChop.HeadChopTarget> HarvestedHeadChop = null)
{
await EnsureInitializationComplete();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,12 @@ public static GameObject GetGameObject(object o)
/// </summary>
public BasisProcessingAvatarOptions ProcessingAvatarOptions;

/// <summary>
/// Contains information used by the bundle build process. The information contained inside this is processed
/// and then altered right when the bundle is built.
/// </summary>
public BasisBundleAdditionalAssets BundleAdditionalAssets;

/// <summary>
/// the animators humanScale, Cached here to stop requesting it from the animator per frame.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using UnityEngine;

namespace Basis.Scripts.BasisSdk
{
[System.Serializable]
public class BasisObjectReferenceContainer : ScriptableObject
{
public Object[] references;
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
using UnityEngine;

namespace Basis.Scripts.BasisSdk
{
[System.Serializable]
Expand All @@ -16,4 +18,22 @@ public class BasisProcessingAvatarOptions
/// </summary>
// disabled does work just not for all avatars public bool RemoveUnusedBlendshapes = false;
}

[System.Serializable]
public class BasisBundleAdditionalAssets
{
public BasisBundleAdditionalAsset[] deferredAssets;
}

[System.Serializable]
public class BasisBundleAdditionalAsset
{
// Defined by user scripts, during the build.
public string key;
public Object asset;

// Defined by Basis, in the bundle builder.
public int indexInBundle;
public string assetPath;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ public static class BasisAssetBundlePipeline

try
{
List<string> additionalAssetPaths = new List<string>();
if (isScene)
{
if (settings.RebakeOcclusionCulling)
Expand All @@ -88,6 +89,30 @@ public static class BasisAssetBundlePipeline
OnBeforeBuildPrefab?.Invoke(prefab, settings);
PostProcessAvatar(prefab);

// This is not part of post-processing, because we don't want this running during Test In Editor.
if (prefab.TryGetComponent<BasisAvatar>(out BasisAvatar avatar))
{
// Not null, PostProcessAvatar ensures that.
for (var indexInArray = 0; indexInArray < avatar.BundleAdditionalAssets.deferredAssets.Length; indexInArray++)
{
var indexInBundle = 1 + indexInArray;

var forAvatar = avatar.BundleAdditionalAssets.deferredAssets[indexInArray];
if (forAvatar.asset == null) throw new InvalidOperationException("Cannot bundle null additional assets.");
if (forAvatar.asset is GameObject or Transform or Component) throw new InvalidOperationException("Cannot bundle GameObjects, Transforms, or Components as additional assets.");

// We cannot just use AssetDatabase.AddObjectToAsset because the asset path of a Mesh is very often the path of the .fbx, which is a GameObject.
// We're using SaveAssetToTemporaryStorage to create a container that references the asset.
var additionalAssetPath = TemporaryStorageHandler.SaveAssetToTemporaryStorage(forAvatar.asset, settings, out _);
additionalAssetPaths.Add(additionalAssetPath);

// Dereference it so that it doesn't get bundled into main.
forAvatar.asset = null;
forAvatar.indexInBundle = indexInBundle;
forAvatar.assetPath = additionalAssetPath;
}
}

assetPath = TemporaryStorageHandler.SavePrefabToTemporaryStorage(prefab, settings, ref wasModified, out uniqueID);

if (prefab != null)
Expand All @@ -99,7 +124,7 @@ public static class BasisAssetBundlePipeline
AssetBundleBuild Build = new AssetBundleBuild()
{
assetBundleName = uniqueID,
assetNames = new string[] { assetPath }
assetNames = new[] { assetPath }.Concat(additionalAssetPaths).ToArray()
};

AssetBundleBuild[] Builds = new AssetBundleBuild[] { Build };
Expand Down Expand Up @@ -174,6 +199,18 @@ public static void PostProcessAvatar(GameObject prefab)

// We do not want to keep this data at runtime.
avatar.ProcessingAvatarOptions = null;

if (avatar.BundleAdditionalAssets == null)
{
avatar.BundleAdditionalAssets = new BasisBundleAdditionalAssets
{
deferredAssets = Array.Empty<BasisBundleAdditionalAsset>()
};
}
else if (avatar.BundleAdditionalAssets.deferredAssets == null)
{
avatar.BundleAdditionalAssets.deferredAssets = Array.Empty<BasisBundleAdditionalAsset>();
}
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.IO;
using Basis.Scripts.BasisSdk;
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine;
Expand All @@ -14,6 +15,20 @@ public static string SavePrefabToTemporaryStorage(GameObject prefab, BasisAssetB
wasModified = true;
return prefabPath;
}
public static string SaveAssetToTemporaryStorage(Object asset, BasisAssetBundleObject settings, out string uniqueID)
{
if (asset is GameObject or Transform or Component) throw new InvalidDataException("Cannot save asset of type GameObject, Transform or Component.");

EnsureDirectoryExists(settings.TemporaryStorage);
uniqueID = BasisGenerateUniqueID.GenerateUniqueID();
string assetPath = Path.Combine(settings.TemporaryStorage, $"{uniqueID}.asset");
BasisObjectReferenceContainer referenceContainer = ScriptableObject.CreateInstance<BasisObjectReferenceContainer>();
referenceContainer.references = new[] { asset };

AssetDatabase.CreateAsset(referenceContainer, assetPath);

return assetPath;
}
public static string SaveScene(Scene sceneToCopy, BasisAssetBundleObject settings, out string uniqueID)
{
// Generate a unique ID
Expand Down
Loading