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);
        }
Beispiel #6
0
        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");
        }
Beispiel #7
0
        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);
        }
Beispiel #9
0
        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");
        }
Beispiel #10
0
        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);
        }
Beispiel #16
0
        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);
        }
Beispiel #18
0
        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);
        }
Beispiel #20
0
        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);
        }
Beispiel #21
0
        public IEnumerator VerifyProfileVariableEvaluation()
        {
            yield return(Init());

            Assert.AreEqual(string.Format("{0}", m_Addressables.RuntimePath), AddressablesRuntimeProperties.EvaluateString("{UnityEngine.AddressableAssets.Addressables.RuntimePath}"));
        }