Ejemplo n.º 1
0
        /// <summary>
        /// Gets the preferred path to store the resource at if a specific file name is required.
        /// </summary>
        /// <param name="context"></param>
        /// <param name="asset"></param>
        /// <param name="fileName"></param>
        /// <returns></returns>
        public static string GetPreferredFilePathWithCustomFileName(this IAssetOrResourceLoadedContext context, UnityEngine.Object asset, string fileName)
        {
            string parentDirectory;

            if (context is AssetLoadedContext)
            {
                parentDirectory = "assets";
            }
            else if (context is ResourceLoadedContext)
            {
                parentDirectory = "resources";
            }
            else
            {
                throw new ArgumentException("context");
            }

            var path = Path.Combine(Path.Combine(Settings.RedirectedResourcesPath, parentDirectory), context.GetUniqueFileSystemAssetPath(asset));

            if (fileName != null)
            {
                path = Path.Combine(path, fileName);
            }
            return(path);
        }
Ejemplo n.º 2
0
        protected override bool ReplaceOrUpdateAsset(string calculatedModificationPath, ref T asset,
                                                     IAssetOrResourceLoadedContext context)
        {
            var defaultTranslationFile = Path.Combine(calculatedModificationPath, "translation.txt");
            var redirectedResources    = RedirectedDirectory.GetFilesInDirectory(calculatedModificationPath, ".txt");
            var streams = redirectedResources.Select(x => x.OpenStream());
            var cache   = new SimpleTextTranslationCache(
                defaultTranslationFile,
                streams,
                false,
                true);

            if (cache.IsEmpty && !DisableEmptyCacheCheck)
            {
                return(false);
            }

            var result = false;

            foreach (var entry in GetParams(asset))
            {
                if (UpdateParam(calculatedModificationPath, cache, entry))
                {
                    result = true;
                }
            }

            return(result);
        }
        protected override bool ReplaceOrUpdateAsset(string calculatedModificationPath, ref T asset,
                                                     IAssetOrResourceLoadedContext context)
        {
            var result = false;
            var start  = Time.realtimeSinceStartup;

            try
            {
                var cache = GetTranslationCache(calculatedModificationPath, asset, context);

                if (cache.IsEmpty && !DisableEmptyCacheCheck)
                {
                    return(false);
                }


                foreach (var entry in GetParams(asset))
                {
                    if (UpdateParam(calculatedModificationPath, cache, entry))
                    {
                        result = true;
                    }
                }

                return(result);
            }
            finally
            {
                Logger.DebugLogDebug("{0}.{1}: {2} => {3} ({4} seconds)", GetType(), nameof(ReplaceOrUpdateAsset),
                                     calculatedModificationPath, result, Time.realtimeSinceStartup - start);
            }
        }
Ejemplo n.º 4
0
        public static bool IsPathAllowed(this IPathListBoundHandler handler, Object asset,
                                         IAssetOrResourceLoadedContext context)
        {
            var pth = PathList.Normalize(context.GetUniqueFileSystemAssetPath(asset).Replace(".unity3d", string.Empty));

            return(IsPathAllowed(handler, pth, true));
        }
        internal static bool DefaultShouldHandleAsset <THandler, TAsset>(this THandler handler, TAsset asset,
                                                                         IAssetOrResourceLoadedContext context)
            where TAsset : UnityEngine.Object
            where THandler : IRedirectorHandler <TAsset>
        {
            var logger = handler.GetLogger();

            logger?.DebugLogDebug("{0}({1}, {2}[{3}])?", nameof(DefaultShouldHandleAsset), handler.GetType(),
                                  asset.name, asset.GetType());
            var result = false;

            try
            {
                if (!handler.Enabled || !handler.ShouldHandleAssetForContext(asset, context))
                {
                    return(false);
                }
                if (handler is IPathListBoundHandler pathListBoundHandler)
                {
                    return(result = pathListBoundHandler.IsPathAllowed(asset, context));
                }

                return(result = true);
            }
            finally
            {
                logger?.DebugLogDebug("{0}({1}, {2}[{3}]) => {4}", nameof(DefaultShouldHandleAsset), handler.GetType(),
                                      asset.name, asset.GetType(), result);
            }
        }
        protected override bool DumpAsset(string calculatedModificationPath, ExcelData asset,
                                          IAssetOrResourceLoadedContext context)
        {
            var defaultTranslationFile = Path.Combine(calculatedModificationPath, "translation.txt");
            var cache = new SimpleTextTranslationCache(
                defaultTranslationFile,
                false);

            var columnsToDump =
                new HashSet <int>(TextResourceHelper.GetSupportedExcelColumns(calculatedModificationPath, asset));

            for (var i = 1; i < asset.list.Count; i++)
            {
                var row        = asset.GetRow(i);
                var rowColumns = Enumerable.Range(0, row.Count);
                if (columnsToDump.Count > 0)
                {
                    rowColumns = rowColumns.Where(columnsToDump.Contains);
                }

                foreach (var key in rowColumns.Select(j => row[j])
                         .Where(k => !k.IsNullOrEmpty() && LanguageHelper.IsTranslatable(k)))
                {
                    cache.AddTranslationToCache(key, key);
                }
            }

            return(true);
        }
        public override TextAndEncoding TranslateTextAsset(string calculatedModificationPath, TextAsset asset,
                                                           IAssetOrResourceLoadedContext context)
        {
            Logger.DebugLogDebug($"{GetType()} attempt to handle {calculatedModificationPath}");
            var defaultTranslationFile = Path.Combine(calculatedModificationPath, "translation.txt");
            var redirectedResources    = RedirectedDirectory.GetFilesInDirectory(calculatedModificationPath, ".txt");
            var streams = redirectedResources.Select(x => x.OpenStream());
            var cache   = new SimpleTextTranslationCache(
                defaultTranslationFile,
                streams,
                false,
                true);

            if (cache.IsEmpty)
            {
                Logger.DebugLogDebug($"{GetType()} unable to handle {calculatedModificationPath} (no cache)");
                return(null);
            }

            var obj = LoadFromAsset(asset);

            if (obj != null && TranslateObject(ref obj, cache, calculatedModificationPath))
            {
                Logger.DebugLogDebug($"{GetType()} handled {calculatedModificationPath}");
                return(StoreAsset(obj));
            }

            Logger.DebugLogDebug($"{GetType()} unable to handle {calculatedModificationPath}");
            return(null);
        }
Ejemplo n.º 8
0
        public override TextAndEncoding TranslateTextAsset(string calculatedModificationPath, TextAsset asset,
                                                           IAssetOrResourceLoadedContext context)
        {
            if (TextAssetMessagePackHelper.CanHandleAsset(asset, context, out var handler))
            {
                //return new TextAndEncoding(asset.bytes, null);
                var defaultTranslationFile = Path.Combine(calculatedModificationPath, "translation.txt");
                var redirectedResources    = RedirectedDirectory.GetFilesInDirectory(calculatedModificationPath, ".txt");
                var streams = redirectedResources.Select(x => x.OpenStream());
                var cache   = new SimpleTextTranslationCache(
                    defaultTranslationFile,
                    streams,
                    false,
                    true);

                if (cache.IsEmpty)
                {
                    Logger.LogDebug($"{GetType()} unable to handle {calculatedModificationPath} (no cache)");
                    return(null);
                }

                var obj = handler.Load(asset);

                if (obj != null && handler.Translate(ref obj, cache, calculatedModificationPath))
                {
                    Logger.LogDebug($"{GetType()} handled {calculatedModificationPath}");
                    return(handler.Store(obj));
                }
            }

            return(null);
        }
Ejemplo n.º 9
0
 public static ResourceMappingPath FromAssetContext(string calculatedModificationPath, UnityEngineObject asset,
                                                    IAssetOrResourceLoadedContext context)
 {
     return(new ResourceMappingPath(
                context.GetUniqueFileSystemAssetPath(asset).Replace(".unity3d", string.Empty),
                calculatedModificationPath, allPathsNormalized: true));
 }
Ejemplo n.º 10
0
        /// <summary>
        ///     Caches forward and reverse translation of assets as they're loaded, but does not apply them.
        ///     to avoid breaking code that relies on original names being present.
        /// </summary>
        protected override bool ReplaceOrUpdateAsset(string calculatedModificationPath, ref MapInfo asset,
                                                     IAssetOrResourceLoadedContext context)
        {
            var result = false;
            var start  = Time.realtimeSinceStartup;

            try
            {
                // updating the MapInfo assets directly breaks places that are doing lookups by mapName
                // instead of id, so we just register this as a place to lookup MapInfo translations and
                // return true so it appears handled
                Hooks.Init();

                // register new translations with helper without replacing
                var cache = GetTranslationCache(calculatedModificationPath, asset, context);

                if (cache.IsEmpty)
                {
                    return(result = true);
                }

                var shouldTrack = IsTranslationRegistrationAllowed(calculatedModificationPath);

                // register with helper or dump without translating here
                foreach (var key in asset.param
                         .Select(entry => TextResourceHelper.GetSpecializedKey(entry, GetMapName(entry)))
                         .Where(k => !string.IsNullOrEmpty(k)))
                {
                    if (cache.TryGetTranslation(key, true, out var translated))
                    {
                        if (string.IsNullOrEmpty(translated))
                        {
                            continue;
                        }
                        _mapLookup[key] = translated;
                        _reverseMapLookup[translated] = key;
                        if (shouldTrack)
                        {
                            TrackReplacement(calculatedModificationPath, key, translated);
                        }
                        TranslationHelper.RegisterRedirectedResourceTextToPath(translated, calculatedModificationPath);
                    }
                    else if (AutoTranslatorSettings.IsDumpingRedirectedResourcesEnabled &&
                             !string.IsNullOrEmpty(key) && LanguageHelper.IsTranslatable(key))
                    {
                        cache.AddTranslationToCache(key, key);
                    }
                }

                GameSpecificReplaceOrUpdateAsset(calculatedModificationPath, ref asset, context, cache, shouldTrack);

                return(result = true);
            }
            finally
            {
                Logger.DebugLogDebug("{0}.{1}: {2} => {3} ({4} seconds)", GetType(), nameof(ReplaceOrUpdateAsset),
                                     calculatedModificationPath, result, Time.realtimeSinceStartup - start);
            }
        }
Ejemplo n.º 11
0
        protected override bool ShouldHandleAsset(TextAsset asset, IAssetOrResourceLoadedContext context)
        {
            Logger.DebugLogDebug($"{GetType()}.ShouldHandleAsset({asset.name}[{asset.GetType()}])?");
            var result = base.ShouldHandleAsset(asset, context) && TextAssetTableHelper.IsTable(asset);

            Logger.DebugLogDebug($"{GetType()}.ShouldHandleAsset({asset.name}[{asset.GetType()}]) => {result}");
            return(result);
        }
Ejemplo n.º 12
0
        protected override bool ShouldHandleAsset(TextAsset asset, IAssetOrResourceLoadedContext context)
        {
            var result = Enabled && TextAssetMessagePackHelper.CanHandleAsset(asset, context) &&
                         !context.HasReferenceBeenRedirectedBefore(asset);

            Logger.LogDebug($"{GetType()}.ShouldHandleAsset({asset.name}[{asset.GetType()}]) => {result}");
            return(result);
        }
Ejemplo n.º 13
0
        protected override bool ShouldHandleAsset(ScenarioData asset, IAssetOrResourceLoadedContext context)
        {
            Logger.DebugLogDebug($"{GetType()}.ShouldHandleAsset({asset.name}[{asset.GetType()}])?");
            var result = base.ShouldHandleAsset(asset, context);

            Logger.DebugLogDebug($"{GetType()}.ShouldHandleAsset({asset.name}[{asset.GetType()}]) => {result}");
            return(result);
        }
        protected override bool ShouldHandleAsset(TextAsset asset, IAssetOrResourceLoadedContext context)
        {
            Logger.DebugLogDebug($"{GetType()}.ShouldHandleAsset({asset.name}[{asset.GetType()}])?");
            var result = Enabled && !context.HasReferenceBeenRedirectedBefore(asset) &&
                         this.IsPathAllowed(asset, context) && asset.bytes != null;

            Logger.DebugLogDebug($"{GetType()}.ShouldHandleAsset({asset.name}[{asset.GetType()}]) => {result}");
            return(result);
        }
 public static bool CanHandleAsset(TextAsset textAsset, IAssetOrResourceLoadedContext context, out IHandler handler)
 {
     handler = null;
     if (textAsset.bytes?.Length > 0)
     {
         handler = GetHandler(textAsset, context);
     }
     return(handler != null);
 }
 public static bool CanHandleAsset <T>(TextAsset textAsset, IAssetOrResourceLoadedContext context, out Handler <T> handler) where T : class
 {
     handler = null;
     if (textAsset.bytes != null)
     {
         handler = GetHandler <T>(textAsset, context);
     }
     return(handler != null);
 }
Ejemplo n.º 17
0
        private void Handle(IAssetOrResourceLoadedContext context)
        {
            if (context.Asset is TAsset castedAsset && ShouldHandleAsset(castedAsset, context))
            {
                var unqiuePath           = context.GetUniqueFileSystemAssetPath(castedAsset);
                var modificationFilePath = CalculateModificationFilePath(castedAsset, context);
                if ((CheckDirectory && Directory.Exists(modificationFilePath)) || (!CheckDirectory && File.Exists(modificationFilePath)))      // IO, ewww!
                {
                    try
                    {
                        bool handled = ReplaceOrUpdateAsset(modificationFilePath, ref castedAsset, context);
                        if (handled)
                        {
                            XuaLogger.AutoTranslator.Debug($"Replaced or updated resource file: '{unqiuePath}'.");
                        }
                        else
                        {
                            XuaLogger.AutoTranslator.Debug($"Did not replace or update resource file: '{unqiuePath}'.");
                        }

                        context.Complete(
                            skipRemainingPostfixes: handled);
                    }
                    catch (Exception e)
                    {
                        XuaLogger.AutoTranslator.Error(e, $"An error occurred while replacing or updating resource file: '{unqiuePath}'.");
                    }
                }
                else if (AutoTranslatorSettings.IsDumpingRedirectedResourcesEnabled)
                {
                    try
                    {
                        bool handled = DumpAsset(modificationFilePath, castedAsset, context);
                        if (handled)
                        {
                            XuaLogger.AutoTranslator.Debug($"Dumped resource file: '{unqiuePath}'.");
                        }
                        else
                        {
                            XuaLogger.AutoTranslator.Debug($"Did not dump resource file: '{unqiuePath}'.");
                        }

                        context.Complete(
                            skipRemainingPostfixes: handled);
                    }
                    catch (Exception e)
                    {
                        XuaLogger.AutoTranslator.Error(e, $"An error occurred while dumping resource file: '{unqiuePath}'.");
                    }
                }

                if (!ReferenceEquals(castedAsset, context.Asset))
                {
                    context.Asset = castedAsset;
                }
            }
        }
        protected override string CalculateModificationFilePath(TextAsset asset, IAssetOrResourceLoadedContext context)
        {
            var path = asset.DefaultCalculateModificationFilePath(context);

            if (AllowTranslationRegistration && TextResourceHelper.IsRandomNameListAsset(asset.name))
            {
                ExcludePathFromTranslationRegistration(path);
            }
            return(path);
        }
Ejemplo n.º 19
0
        /// <summary>
        /// Gets the preferred path to store the resource at if a specific file name is required.
        /// </summary>
        /// <param name="context"></param>
        /// <param name="parentDirectory"></param>
        /// <param name="asset"></param>
        /// <param name="fileName"></param>
        /// <returns></returns>
        public static string GetPreferredFilePathWithCustomFileName(this IAssetOrResourceLoadedContext context, string parentDirectory, UnityEngine.Object asset, string fileName)
        {
            var path = Path.Combine(parentDirectory, context.GetUniqueFileSystemAssetPath(asset));

            if (fileName != null)
            {
                path = Path.Combine(path, fileName);
            }
            return(path);
        }
        /// <summary>
        ///     Caches forward and reverse translation of assets as they're loaded, but does not apply them.
        ///     to avoid breaking code that relies on original names being present.
        /// </summary>
        protected override bool ReplaceOrUpdateAsset(string calculatedModificationPath, ref MapInfo asset,
                                                     IAssetOrResourceLoadedContext context)
        {
            // updating the MapInfo assets directly breaks places that are doing lookups by mapName
            // instead of id, so we just register this as a place to lookup MapInfo translations and
            // return true so it appears handled
            Hooks.Init();

            // register new translations with helper without replacing
            var defaultTranslationFile = Path.Combine(calculatedModificationPath, "translation.txt");
            var redirectedResources    = RedirectedDirectory.GetFilesInDirectory(calculatedModificationPath, ".txt");
            var streams = redirectedResources.Select(x => x.OpenStream());
            var cache   = new SimpleTextTranslationCache(
                defaultTranslationFile,
                streams,
                false,
                true);

            if (cache.IsEmpty)
            {
                return(true);
            }

            var shouldTrack = IsTranslationRegistrationAllowed(calculatedModificationPath);

            // register with helper or dump without translating here
            foreach (var key in asset.param
                     .Select(entry => TextResourceHelper.GetSpecializedKey(entry, GetMapName(entry)))
                     .Where(k => !string.IsNullOrEmpty(k)))
            {
                if (cache.TryGetTranslation(key, true, out var translated))
                {
                    if (string.IsNullOrEmpty(translated))
                    {
                        continue;
                    }
                    _mapLookup[key] = translated;
                    _reverseMapLookup[translated] = key;
                    if (shouldTrack)
                    {
                        TrackReplacement(calculatedModificationPath, key, translated);
                    }
                    TranslationHelper.RegisterRedirectedResourceTextToPath(translated, calculatedModificationPath);
                }
                else if (AutoTranslatorSettings.IsDumpingRedirectedResourcesEnabled &&
                         !string.IsNullOrEmpty(key) && LanguageHelper.IsTranslatable(key))
                {
                    cache.AddTranslationToCache(key, key);
                }
            }

            return(true);
        }
        protected override bool DumpAsset(string calculatedModificationPath, ScenarioData asset,
                                          IAssetOrResourceLoadedContext context)
        {
            var cache = GetDumpCache(calculatedModificationPath, asset, context);

            foreach (var param in asset.list)
            {
                TextResourceHelper.DumpScenarioParam(param, cache);
            }

            return(true);
        }
        protected override bool DumpAsset(string calculatedModificationPath, TextAsset asset,
                                          IAssetOrResourceLoadedContext context)
        {
            if (asset?.bytes == null)
            {
                return(false);
            }

            var defaultFile = Path.Combine(calculatedModificationPath, "translation.bytes");

            File.WriteAllBytes(defaultFile, asset.bytes);
            return(true);
        }
        public virtual bool CanHandleAsset(TextAsset textAsset, IAssetOrResourceLoadedContext context)
        {
            var pth = context.GetUniqueFileSystemAssetPath(textAsset).Replace(".unity3d", string.Empty);

            if (ObjectMark == null || !this.IsPathAllowed(pth, true))
            {
                return(false);
            }
            var searchLength            = SearchLength != -1 ? SearchLength : ObjectMark.Count() * 3;
            IEnumerable <byte> haystack = null;

            textAsset.SafeProc(a => a.bytes.SafeProc(b => haystack = b.Take(searchLength)));
            return(haystack != null && TextResourceHelper.Helpers.ArrayContains(haystack, ObjectMark));
        }
Ejemplo n.º 24
0
        private void GetTableRules(string calculatedModificationPath, TextAsset asset,
                                   IAssetOrResourceLoadedContext context, out Predicate <int> rowAllowed, out Predicate <int> colAllowed)
        {
            Predicate <int> BuildAllowedPredicate(HashSet <int> whitelist, HashSet <int> blacklist)
            {
                var haveWhitelist = whitelist != null && whitelist.Count > 0;
                var haveBlacklist = blacklist != null && blacklist.Count > 0;


                if (haveWhitelist)
                {
                    if (!haveBlacklist)
                    {
                        return(whitelist.Contains);
                    }

                    if (blacklist.Count > whitelist.Count)
                    {
                        return(r => whitelist.Contains(r) && !blacklist.Contains(r));
                    }

                    return(r => !blacklist.Contains(r) && whitelist.Contains(r));
                }

                if (haveBlacklist)
                {
                    return(((Predicate <int>)blacklist.Contains).Not);
                }

                return(null);
            }

            foreach (var getter in TableRulesGetters)
            {
                var handled = getter(calculatedModificationPath, asset, context,
                                     out var rowWhitelist, out var rowBlacklist,
                                     out var colWhitelist, out var colBlacklist);
                if (!handled)
                {
                    continue;
                }

                rowAllowed = BuildAllowedPredicate(rowWhitelist, rowBlacklist);
                colAllowed = BuildAllowedPredicate(colWhitelist, colBlacklist);
                return;
            }

            rowAllowed = null;
            colAllowed = null;
        }
Ejemplo n.º 25
0
 internal static bool DefaultShouldHandleAsset <THandler, TAsset>(this THandler handler, TAsset asset,
                                                                  IAssetOrResourceLoadedContext context)
     where TAsset : UnityEngine.Object
     where THandler : IRedirectorHandler <TAsset>
 {
     if (!handler.Enabled || context.HasReferenceBeenRedirectedBefore(asset))
     {
         return(false);
     }
     if (handler is IPathListBoundHandler pathListBoundHandler)
     {
         return(pathListBoundHandler.IsPathAllowed(asset, context));
     }
     return(true);
 }
        public virtual bool CanHandleAsset(TextAsset textAsset, IAssetOrResourceLoadedContext context)
        {
            var pth = context.GetUniqueFileSystemAssetPath(textAsset).Replace(".unity3d", string.Empty);

            if (ObjectMark != null && this.IsPathAllowed(pth, true))
            {
                var searchLength = SearchLength != -1 ? SearchLength : ObjectMark.Count() * 3;
                var haystack     = textAsset?.bytes?.Take(searchLength);
                if (haystack != null)
                {
                    return(TextResourceHelper.Helpers.ArrayContains(haystack, ObjectMark));
                }
            }

            return(false);
        }
Ejemplo n.º 27
0
        protected override bool DumpAsset(string calculatedModificationPath, NickName asset,
                                          IAssetOrResourceLoadedContext context)
        {
            var cache = GetDumpCache(calculatedModificationPath, asset, context);

            foreach (var entry in asset.param)
            {
                var key = TextResourceHelper.GetSpecializedKey(entry, entry.Name);
                if (!string.IsNullOrEmpty(key) && LanguageHelper.IsTranslatable(key))
                {
                    cache.AddTranslationToCache(key, entry.Name);
                }
            }

            return(true);
        }
        protected override bool DumpAsset(string calculatedModificationPath, T asset,
                                          IAssetOrResourceLoadedContext context)
        {
            var cache = GetDumpCache(calculatedModificationPath, asset, context);

            var result = false;

            foreach (var entry in GetParams(asset))
            {
                if (DumpParam(cache, entry))
                {
                    result = true;
                }
            }

            return(result);
        }
        public override TextAndEncoding TranslateTextAsset(string calculatedModificationPath, TextAsset asset,
                                                           IAssetOrResourceLoadedContext context)
        {
            Logger.DebugLogDebug($"{GetType()} attempt to handle {calculatedModificationPath}");
            if (!Enabled || asset.bytes == null)
            {
                Logger.DebugLogDebug($"{GetType()} unable to handle {calculatedModificationPath}");
                return(null);
            }

            byte[] bytes       = null;
            var    defaultFile = Path.Combine(calculatedModificationPath, "translation.bytes");

            if (File.Exists(defaultFile))
            {
                bytes = File.ReadAllBytes(defaultFile);
            }

            if (bytes == null || bytes.Length == 0)
            {
                foreach (var entry in RedirectedDirectory.GetFilesInDirectory(calculatedModificationPath, ".bytes"))
                {
                    using (var stream = entry.OpenStream())
                    {
                        bytes = ReadBytes(stream);
                    }

                    if (bytes.Length > 0)
                    {
                        break;
                    }
                }
            }

            if (bytes == null || bytes.Length == 0)
            {
                Logger.DebugLogDebug($"{GetType()}  unable to handle {calculatedModificationPath}: no .bytes files");
                return(null);
            }

            Logger.DebugLogDebug($"{GetType()} handled {calculatedModificationPath}");
            return(new TextAndEncoding(bytes, _textResourceHelper.TableHelper.TextAssetEncoding));
        }
        /// <summary>
        /// Gets the default resource and preferred path to store the redirected resource at.
        /// </summary>
        /// <param name="context"></param>
        /// <param name="asset"></param>
        /// <param name="extension"></param>
        /// <returns></returns>
        public static string GetPreferredFilePath(this IAssetOrResourceLoadedContext context, UnityEngine.Object asset, string extension)
        {
            string parentDirectory;

            if (context is AssetLoadedContext)
            {
                parentDirectory = "assets";
            }
            else if (context is ResourceLoadedContext)
            {
                parentDirectory = "resources";
            }
            else
            {
                throw new ArgumentException("context");
            }

            return(Path.Combine(Path.Combine(Settings.RedirectedResourcesPath, parentDirectory), context.GetUniqueFileSystemAssetPath(asset)) + extension);
        }