public void RuntimeProperties_CanAddValue() { AddressablesRuntimeProperties.ClearCachedPropertyValues(); AddressablesRuntimeProperties.SetPropertyValue("name", "val"); Assert.AreEqual(1, AddressablesRuntimeProperties.GetCachedValueCount()); }
/// <summary> /// Evaluate a string given a profile id. /// </summary> /// <param name="profileId">The profile id to use for evaluation.</param> /// <param name="varString">The string to evaluate. Any tokens surrounded by '[' and ']' will be replaced with matching variables.</param> /// <returns>The evaluated string.</returns> public string EvaluateString(string profileId, string varString) { Func <string, string> getVal = s => { var v = GetValueByName(profileId, s); if (string.IsNullOrEmpty(v)) { if (onProfileStringEvaluation != null) { foreach (var i in onProfileStringEvaluation.GetInvocationList()) { var del = (ProfileStringEvaluationDelegate)i; v = del(s); if (!string.IsNullOrEmpty(v)) { return(v); } } } v = AddressablesRuntimeProperties.EvaluateProperty(s); } return(v); }; return(AddressablesRuntimeProperties.EvaluateString(varString, '[', ']', getVal)); }
/// <summary> /// Build the specified data with the provided builderInput. This is the public entry point. /// Child class overrides should use <see cref="BuildDataImplementation{TResult}"/> /// </summary> /// <typeparam name="TResult">The type of data to build.</typeparam> /// <param name="builderInput">The builderInput object used in the build.</param> /// <returns>The build data result.</returns> public TResult BuildData <TResult>(AddressablesDataBuilderInput builderInput) where TResult : IDataBuilderResult { if (!CanBuildData <TResult>()) { var message = "Data builder " + Name + " cannot build requested type: " + typeof(TResult); Debug.LogError(message); return(AddressableAssetBuildResult.CreateResult <TResult>(null, 0, message)); } m_Log = (builderInput.Logger != null) ? builderInput.Logger : new BuildLog(); AddressablesRuntimeProperties.ClearCachedPropertyValues(); TResult result; // Append the file registry to the results using (m_Log.ScopedStep(LogLevel.Info, $"Building {this.Name}")) { result = BuildDataImplementation <TResult>(builderInput); if (result != null) { result.FileRegistry = builderInput.Registry; } } if (builderInput.Logger == null && m_Log != null) { WriteBuildLog((BuildLog)m_Log, Path.GetDirectoryName(Application.dataPath) + "/Library/com.unity.addressables"); } return(result); }
void CreateConfigFiles(AddressableAssetGroup group, string assetPackName, DeliveryType deliveryType, Dictionary <string, CustomAssetPackDataEntry> assetPackToDataEntry, Dictionary <string, BuildProcessorDataEntry> bundleIdToEditorDataEntry) { foreach (AddressableAssetEntry entry in group.entries) { if (bundleIdToEditorDataEntry.ContainsKey(entry.BundleFileId)) { continue; } string bundleBuildPath = AddressablesRuntimeProperties.EvaluateString(entry.BundleFileId); string bundleName = Path.GetFileNameWithoutExtension(bundleBuildPath); if (!assetPackToDataEntry.ContainsKey(assetPackName)) { // Create .androidpack directory and gradle file for the asset pack assetPackToDataEntry[assetPackName] = new CustomAssetPackDataEntry(assetPackName, deliveryType, new List <string>() { bundleName }); string androidPackDir = CreateAssetPackDirectory(assetPackName); CreateOrEditGradleFile(androidPackDir, assetPackName, deliveryType); } else { // Otherwise just save the bundle to asset pack data assetPackToDataEntry[assetPackName].AssetBundles.Add(bundleName); } // Store the bundle's build path and its corresponding .androidpack folder location string bundlePackDir = ConstructAssetPackDirectoryName(assetPackName); string assetsFolderPath = Path.Combine(bundlePackDir, Path.GetFileName(bundleBuildPath)); bundleIdToEditorDataEntry.Add(entry.BundleFileId, new BuildProcessorDataEntry(bundleBuildPath, assetsFolderPath)); } }
/// <summary> /// Build the specified data with the provided builderInput. This is the public entry point. /// Child class overrides should use <see cref="BuildDataImplementation{TResult}"/> /// </summary> /// <typeparam name="TResult">The type of data to build.</typeparam> /// <param name="builderInput">The builderInput object used in the build.</param> /// <returns>The build data result.</returns> public TResult BuildData <TResult>(AddressablesDataBuilderInput builderInput) where TResult : IDataBuilderResult { if (!CanBuildData <TResult>()) { var message = "Data builder " + Name + " cannot build requested type: " + typeof(TResult); Debug.LogError(message); return(AddressableAssetBuildResult.CreateResult <TResult>(null, 0, message)); } BuildLog log = new BuildLog(); m_Log = log; AddressablesRuntimeProperties.ClearCachedPropertyValues(); TResult result; // Append the file registry to the results using (log.ScopedStep(LogLevel.Info, $"Building {this.Name}")) { result = BuildDataImplementation <TResult>(builderInput); if (result != null) { result.FileRegistry = builderInput.Registry; } } var perfOutputDirectory = Path.GetDirectoryName(Application.dataPath) + "/Library/com.unity.addressables"; File.WriteAllText(Path.Combine(perfOutputDirectory, "AddressablesBuildTEP.json"), log.FormatAsTraceEventProfiler()); File.WriteAllText(Path.Combine(perfOutputDirectory, "AddressablesBuildLog.txt"), log.FormatAsText()); return(result); }
public void RuntimeProperties_EvaluateString_DoesNotLoopInfinitelyOnUnmatchedEndingDelimiter() { string testString = "[correct]bad]"; string expectedResult = "#ERROR-" + testString + " contains unmatched delimiters#"; string actualResult = AddressablesRuntimeProperties.EvaluateString(testString, '[', ']', s => s); Assert.AreEqual(expectedResult, actualResult, "EvaluateString encounters infinite loop with unmatched ending delimiter"); }
public void RuntimeProperties_EvaluateString_DoesNotLoopInfinitelyOnUnmatchedStartingDelimiter() { string testString = "[[correct]bad"; string expectedResult = "[correctbad"; string actualResult = AddressablesRuntimeProperties.EvaluateString(testString, '[', ']', s => s); Assert.AreEqual(expectedResult, actualResult, "EvaluateString encounters infinite loop with unmatched starting delimiter"); }
public void RuntimeProperties_CanEvaluateReflection() { AddressablesRuntimeProperties.ClearCachedPropertyValues(); string expectedResult = ReflectableStringValue; string actualResult = AddressablesRuntimeProperties.EvaluateProperty("AddrRuntimePropertiesTests.AddrRuntimePropertiesTests.ReflectableStringValue"); Assert.AreEqual(expectedResult, actualResult); }
public void RuntimeProperties_EvaluateString_DoesNotLoopInfinitelyOnImproperlyOrderedDelimiters() { string testString = "][correct][bad"; string expectedResult = "]correct[bad"; string actualResult = AddressablesRuntimeProperties.EvaluateString(testString, '[', ']', s => s); Assert.AreEqual(expectedResult, actualResult, "EvaluateString encounters infinite loop on reversed delimiters"); }
public void RuntimeProperties_EvaluateString_CreatesLocalStackOnRecursiveCall() { string testString = "[{[{correct}]bad}]"; string expectedResult = "CORRECTBAD"; string actualResult = AddressablesRuntimeProperties.EvaluateString(testString, '[', ']', s => { return(AddressablesRuntimeProperties.EvaluateString(s, '{', '}', str => str.ToUpper())); }); Assert.AreEqual(expectedResult, actualResult, "EvaluateString does not properly initialize a local stack for recursive/simultaneous calls."); }
public void RuntimeProperties_EvaluatePropertyCanEvaluateSetValue() { AddressablesRuntimeProperties.ClearCachedPropertyValues(); string expectedResult = "myVal"; string key = "myName"; AddressablesRuntimeProperties.SetPropertyValue(key, expectedResult); string actualResult = AddressablesRuntimeProperties.EvaluateProperty(key); Assert.AreEqual(expectedResult, actualResult); }
public string ResolveInternalId(string id) { var path = AddressablesRuntimeProperties.EvaluateString(id); #if UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN || UNITY_XBOXONE if (path.Length >= 260 && path.StartsWith(Application.dataPath)) { path = path.Substring(Application.dataPath.Length + 1); } #endif return(path); }
public void RuntimeProperties_EvaluateStringCanParseAutomaticTokens() { string tok1 = "cheese"; string tok2 = "cows"; string tok3 = "moo"; string toEval = tok1 + '{' + tok2 + '}' + tok3; string expectedResult = tok1 + tok2 + tok3; string actualResult = AddressablesRuntimeProperties.EvaluateString(toEval); Assert.AreEqual(expectedResult, actualResult); }
/// <summary> /// Build the specified data with the provided builderInput. This is the public entry point. /// Child class overrides should use <see cref="BuildDataImplementation{TResult}"/> /// </summary> /// <typeparam name="TResult">The type of data to build.</typeparam> /// <param name="builderInput">The builderInput object used in the build.</param> /// <returns>The build data result.</returns> public TResult BuildData <TResult>(AddressablesDataBuilderInput builderInput) where TResult : IDataBuilderResult { if (!CanBuildData <TResult>()) { var message = "Data builder " + Name + " cannot build requested type: " + typeof(TResult); Debug.LogError(message); return(AddressableAssetBuildResult.CreateResult <TResult>(null, 0, message)); } m_Log = (builderInput.Logger != null) ? builderInput.Logger : new BuildLog(); AddressablesRuntimeProperties.ClearCachedPropertyValues(); TResult result = default; // Append the file registry to the results using (m_Log.ScopedStep(LogLevel.Info, $"Building {this.Name}")) { try { result = BuildDataImplementation <TResult>(builderInput); } catch (Exception e) { string errMessage; if (e.Message == "path") { errMessage = "Invalid path detected during build. Check for unmatched brackets in your active profile's variables."; } else { errMessage = e.Message; } Debug.LogError(errMessage); return(AddressableAssetBuildResult.CreateResult <TResult>(null, 0, errMessage)); } if (result != null) { result.FileRegistry = builderInput.Registry; } } if (builderInput.Logger == null && m_Log != null) { WriteBuildLog((BuildLog)m_Log, Path.GetDirectoryName(Application.dataPath) + "/" + Addressables.LibraryPath); } return(result); }
public void RuntimeProperties_EvaluateStringCanParseInExplicitOverride() { string tok1 = "cheese"; string tok2 = "cows"; string tok3 = "moo"; string replacement = "_parsed_"; char delim = '?'; string toEval = tok1 + delim + tok2 + delim + tok3; string expectedResult = tok1 + replacement + tok3; string actualResult = AddressablesRuntimeProperties.EvaluateString(toEval, delim, delim, s => { return(replacement); }); Assert.AreEqual(expectedResult, actualResult); }
public void RuntimeProperties_CanEvaluateInnerProperties() { Dictionary <string, string> stringLookup = new Dictionary <string, string>(); stringLookup.Add("B", "inner"); stringLookup.Add("With_inner", "Success"); string toEval = "Test_[With_[B]]"; string expectedResult = "Test_Success"; string actualResult = AddressablesRuntimeProperties.EvaluateString(toEval, '[', ']', s => { if (stringLookup.TryGetValue(s, out string val)) { return(val); } return(""); }); Assert.AreEqual(expectedResult, actualResult); }
/// <summary> /// Build the specified data with the provided builderInput. This is the public entry point. /// Child class overrides should use <see cref="BuildDataImplementation{TResult}"/> /// </summary> /// <typeparam name="TResult">The type of data to build.</typeparam> /// <param name="builderInput">The builderInput object used in the build.</param> /// <returns>The build data result.</returns> public TResult BuildData <TResult>(AddressablesDataBuilderInput builderInput) where TResult : IDataBuilderResult { if (!CanBuildData <TResult>()) { var message = "Data builder " + Name + " cannot build requested type: " + typeof(TResult); Debug.LogError(message); return(AddressableAssetBuildResult.CreateResult <TResult>(null, 0, message)); } AddressablesRuntimeProperties.ClearCachedPropertyValues(); // Append the file registry to the results var result = BuildDataImplementation <TResult>(builderInput); if (result != null) { result.FileRegistry = builderInput.Registry; } return(result); }
public void RuntimeProperties_CanDetectCyclicLoops() { string a = "[B]"; string b = "[A]"; string toEval = "Test_[A]_"; string expectedResult = "Test_#ERROR-CyclicToken#_"; string actualResult = AddressablesRuntimeProperties.EvaluateString(toEval, '[', ']', s => { switch (s) { case "A": return(a); case "B": return(b); } return(""); }); Assert.AreEqual(expectedResult, actualResult); }
public void RuntimeProperties_EvaluateStringIgnoresSingleDelim() { string tok1 = "cheese"; string tok2 = "cows"; string tok3 = "moo"; string toEval = tok1 + tok2 + '}' + tok3; string expectedResult = toEval; string actualResult = AddressablesRuntimeProperties.EvaluateString(toEval); Assert.AreEqual(expectedResult, actualResult); toEval = tok1 + '{' + tok2 + tok3; expectedResult = toEval; actualResult = AddressablesRuntimeProperties.EvaluateString(toEval); Assert.AreEqual(expectedResult, actualResult); string replacement = "_parsed_"; char delim = '?'; toEval = tok1 + tok2 + delim + tok3; expectedResult = toEval; actualResult = AddressablesRuntimeProperties.EvaluateString(toEval, delim, delim, s => { return(replacement); }); Assert.AreEqual(expectedResult, actualResult); toEval = tok1 + delim + tok2 + tok3; expectedResult = toEval; actualResult = AddressablesRuntimeProperties.EvaluateString(toEval, delim, delim, s => { return(replacement); }); Assert.AreEqual(expectedResult, actualResult); }
TResult DoBuild <TResult>(AddressablesDataBuilderInput builderInput, AddressableAssetSettings aaSettings, AddressableAssetsBuildContext aaContext) where TResult : IDataBuilderResult { if (m_AllBundleInputDefinitions.Count > 0) { if (!EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo()) { return(AddressableAssetBuildResult.CreateResult <TResult>(null, 0, "Unsaved scenes")); } var buildTarget = builderInput.Target; var buildTargetGroup = builderInput.TargetGroup; var buildParams = new AddressableAssetsBundleBuildParameters(aaSettings, aaContext.bundleToAssetGroup, buildTarget, buildTargetGroup, aaSettings.buildSettings.bundleBuildPath); var builtinShaderBundleName = aaSettings.DefaultGroup.Name.ToLower().Replace(" ", "").Replace('\\', '/').Replace("//", "/") + "_unitybuiltinshaders.bundle"; var buildTasks = RuntimeDataBuildTasks(aaSettings.buildSettings.compileScriptsInVirtualMode, builtinShaderBundleName); ExtractDataTask extractData = new ExtractDataTask(); buildTasks.Add(extractData); string aaPath = aaSettings.AssetPath; IBundleBuildResults results; var exitCode = ContentPipeline.BuildAssetBundles(buildParams, new BundleBuildContent(m_AllBundleInputDefinitions), out results, buildTasks, aaContext); if (exitCode < ReturnCode.Success) { return(AddressableAssetBuildResult.CreateResult <TResult>(null, 0, "SBP Error" + exitCode)); } if (aaSettings == null && !string.IsNullOrEmpty(aaPath)) { aaSettings = AssetDatabase.LoadAssetAtPath <AddressableAssetSettings>(aaPath); } } var bundledAssets = new Dictionary <object, HashSet <string> >(); foreach (var loc in aaContext.locations) { if (loc.Dependencies != null && loc.Dependencies.Count > 0) { for (int i = 0; i < loc.Dependencies.Count; i++) { var dep = loc.Dependencies[i]; HashSet <string> assetsInBundle; if (!bundledAssets.TryGetValue(dep, out assetsInBundle)) { bundledAssets.Add(dep, assetsInBundle = new HashSet <string>()); } if (i == 0 && !assetsInBundle.Contains(loc.InternalId)) //only add the asset to the first bundle... { assetsInBundle.Add(loc.InternalId); } } } } foreach (var bd in bundledAssets) { AddressableAssetGroup group = aaSettings.DefaultGroup; string groupGuid; if (aaContext.bundleToAssetGroup.TryGetValue(bd.Key as string, out groupGuid)) { group = aaSettings.FindGroup(g => g.Guid == groupGuid); } var schema = group.GetSchema <BundledAssetGroupSchema>(); if (schema != null) { var bundleLocData = aaContext.locations.First(s => s.Keys[0] == bd.Key); var isLocalBundle = IsInternalIdLocal(bundleLocData.InternalId); uint crc = (uint)UnityEngine.Random.Range(0, int.MaxValue); var hash = Guid.NewGuid().ToString(); string originalBundleName = bd.Key as string; string newBundleName = BuildUtility.GetNameWithHashNaming(schema.BundleNaming, hash, originalBundleName); bundleLocData.InternalId = bundleLocData.InternalId.Remove(bundleLocData.InternalId.Length - originalBundleName.Length) + newBundleName; var virtualBundleName = AddressablesRuntimeProperties.EvaluateString(bundleLocData.InternalId); var bundleData = new VirtualAssetBundle(virtualBundleName, isLocalBundle, crc, hash); long dataSize = 0; long headerSize = 0; foreach (var a in bd.Value) { var size = ComputeSize(a); bundleData.Assets.Add(new VirtualAssetBundleEntry(a, size)); dataSize += size; headerSize += a.Length * 5; //assume 5x path length overhead size per item, probably much less } if (bd.Value.Count == 0) { dataSize = 100 * 1024; headerSize = 1024; } bundleData.SetSize(dataSize, headerSize); var requestOptions = new VirtualAssetBundleRequestOptions { Crc = schema.UseAssetBundleCrc ? crc : 0, Hash = schema.UseAssetBundleCache ? hash : "", ChunkedTransfer = schema.ChunkedTransfer, RedirectLimit = schema.RedirectLimit, RetryCount = schema.RetryCount, Timeout = schema.Timeout, BundleName = Path.GetFileName(bundleLocData.InternalId), BundleSize = dataSize + headerSize }; bundleLocData.Data = requestOptions; var bundleProviderId = schema.GetBundleCachedProviderId(); var virtualBundleRuntimeData = m_CreatedProviderIds[bundleProviderId]; virtualBundleRuntimeData.AssetBundles.Add(bundleData); } } foreach (var kvp in m_CreatedProviderIds) { if (kvp.Value != null) { var bundleProviderData = ObjectInitializationData.CreateSerializedInitializationData <VirtualAssetBundleProvider>(kvp.Key, kvp.Value); m_ResourceProviderData.Add(bundleProviderData); } } var contentCatalog = new ContentCatalogData(aaContext.locations, ResourceManagerRuntimeData.kCatalogAddress); contentCatalog.ResourceProviderData.AddRange(m_ResourceProviderData); foreach (var t in aaContext.providerTypes) { contentCatalog.ResourceProviderData.Add(ObjectInitializationData.CreateSerializedInitializationData(t)); } contentCatalog.InstanceProviderData = ObjectInitializationData.CreateSerializedInitializationData(instanceProviderType.Value); contentCatalog.SceneProviderData = ObjectInitializationData.CreateSerializedInitializationData(sceneProviderType.Value); //save catalog WriteFile(string.Format(m_PathFormat, "", "catalog"), JsonUtility.ToJson(contentCatalog), builderInput.Registry); foreach (var io in aaSettings.InitializationObjects) { if (io is IObjectInitializationDataProvider) { aaContext.runtimeData.InitializationObjects.Add((io as IObjectInitializationDataProvider).CreateObjectInitializationData()); } } var settingsPath = string.Format(m_PathFormat, "", "settings"); WriteFile(settingsPath, JsonUtility.ToJson(aaContext.runtimeData), builderInput.Registry); //inform runtime of the init data path var runtimeSettingsPath = string.Format(m_PathFormat, "file://{UnityEngine.Application.dataPath}/../", "settings"); PlayerPrefs.SetString(Addressables.kAddressablesRuntimeDataPath, runtimeSettingsPath); var result = AddressableAssetBuildResult.CreateResult <TResult>(settingsPath, aaContext.locations.Count); return(result); }
public IEnumerator VerifyProfileVariableEvaluation() { yield return(Init()); Assert.AreEqual(string.Format("{0}", m_Addressables.RuntimePath), AddressablesRuntimeProperties.EvaluateString("{UnityEngine.AddressableAssets.Addressables.RuntimePath}")); }