Beispiel #1
0
        internal static void LinkImages(PSB psb, FreeMountContext context, IDictionary <string, string> resources,
                                        string baseDir = null)
        {
            var resList = psb.CollectResources <ImageMetadata>();

            foreach (var resxResource in resources)
            {
                //Scan for Resource
                var resMd = resList.FirstOrDefault(r =>
                                                   resxResource.Key == r.GetFriendlyName(psb.Type));
                if (resMd == null && psb.Type == PsbType.Pimg)
                {
                    resMd = resList.FirstOrDefault(r => resxResource.Key == Path.GetFileNameWithoutExtension(r.Name));
                }

                if (resMd == null && uint.TryParse(resxResource.Key, out uint rid))
                {
                    resMd = resList.FirstOrDefault(r => r.Index == rid);
                    if (resMd == null)
                    {
                        //support raw palette
                        var palResMds = resList.FindAll(r => r.Palette?.Index == rid);
                        if (palResMds.Count > 0)
                        {
                            var palFullPath = Path.IsPathRooted(resxResource.Value)
                                ? resxResource.Value
                                : Path.Combine(baseDir ?? "", resxResource.Value.Replace('/', '\\'));
                            var palRawData = File.ReadAllBytes(palFullPath);
                            foreach (var palResMd in palResMds)
                            {
                                palResMd.PalData = palRawData;
                            }

                            continue;
                        }
                    }
                }

                if (resMd == null)
                {
                    Console.WriteLine($"[WARN]{resxResource.Key} is not used.");
                    continue;
                }

                var fullPath = Path.IsPathRooted(resxResource.Value)
                    ? resxResource.Value
                    : Path.Combine(baseDir ?? "", resxResource.Value.Replace('/', '\\'));
                resMd.Link(fullPath, context);
            }
        }
Beispiel #2
0
        /// <summary>
        /// Try to measure EMT PSB Canvas Size
        /// </summary>
        /// <param name="psb"></param>
        /// <param name="width"></param>
        /// <param name="height"></param>
        /// <returns>True: The canvas size can be measured; False: can not get canvas size</returns>
        public static bool TryGetCanvasSize(this PSB psb, out int width, out int height)
        {
            //Get from CharProfile
            if (psb.Objects["metadata"] is PsbDictionary md && md["charaProfile"] is PsbDictionary cp &&
                cp["pixelMarker"] is PsbDictionary pm &&
                pm["boundsBottom"] is PsbNumber b && pm["boundsTop"] is PsbNumber t &&
                pm["boundsLeft"] is PsbNumber l && pm["boundsRight"] is PsbNumber r)
            {
                height = (int)Math.Abs(b.AsFloat - t.AsFloat);
                width  = (int)Math.Abs(r.AsFloat - l.AsFloat);
                return(true);
            }

            //not really useful
            var resList = psb.CollectResources();

            width  = resList.Max(data => data.Width);
            height = resList.Max(data => data.Height);
            return(false);
        }
Beispiel #3
0
        /// <summary>
        /// Get all resources with necessary info
        /// </summary>
        /// <param name="psb"></param>
        /// <param name="deDuplication">if true, we focus on Resource itself </param>
        /// <returns></returns>
        public static List <ResourceMetadata> CollectResources(this PSB psb, bool deDuplication = true)
        {
            List <ResourceMetadata> resourceList = psb.Resources == null
                ? new List <ResourceMetadata>()
                : new List <ResourceMetadata>(psb.Resources.Count);

            switch (psb.Type)
            {
            case PsbType.Tachie:
                FindTachieResources(resourceList, psb.Objects[TachieSourceKey]);
                break;

            case PsbType.Pimg:
            case PsbType.Scn:
                resourceList.AddRange(psb.Objects.Where(k => k.Value is PsbResource).Select(k =>
                                                                                            new ResourceMetadata()
                {
                    Name     = k.Key,
                    Resource = k.Value as PsbResource,
                    Compress = k.Key.EndsWith(".tlg", true, null) ? PsbCompressType.Tlg : PsbCompressType.ByName
                }));
                FindPimgResources(resourceList, psb.Objects[PimgSourceKey], deDuplication);
                break;

            case PsbType.Mmo:
                FindMmoResources(resourceList, psb.Objects[MmoBgSourceKey], MmoBgSourceKey, deDuplication);
                FindMmoResources(resourceList, psb.Objects[MmoSourceKey], MmoSourceKey, deDuplication);
                break;

            case PsbType.Motion:
            default:
                FindMotionResources(resourceList, psb.Objects[MotionSourceKey], deDuplication);
                //Set Spec
                resourceList.ForEach(r => r.Spec = psb.Platform);
                break;
            }

            resourceList.Sort((md1, md2) => (int)(md1.Index - md2.Index));

            return(resourceList);
        }
Beispiel #4
0
        /// <summary>
        /// Inlined PSB -> External Texture PSB. Inverse of Link
        /// </summary>
        /// <param name="psb"></param>
        /// <param name="order">To make a regular external texture PSB you should set it to <see cref="PsbLinkOrderBy.Name"/>.</param>
        /// <param name="disposeResInPsb">Whether to remove resources in PSB. To make a real external texture PSB you should set it to true.</param>
        /// <returns>Ordered textures</returns>
        public static List <Bitmap> UnlinkImages(PSB psb, PsbLinkOrderBy order = PsbLinkOrderBy.Name, bool disposeResInPsb = true)
        {
            var           resources = psb.CollectResources <ImageMetadata>();
            List <Bitmap> texs      = new List <Bitmap>();

            for (int i = 0; i < resources.Count; i++)
            {
                var resource = resources[i];
                var tex      = RL.ConvertToImage(resource.Data, resource.PalData, resource.Height, resource.Width,
                                                 resource.PixelFormat, resource.PalettePixelFormat);

                switch (order)
                {
                case PsbLinkOrderBy.Convention:
                    tex.Tag = resource.GetFriendlyName(psb.Type);
                    break;

                default:
                    var tId = resource.TextureIndex;
                    if (tId == null)
                    {
                        throw new FormatException(
                                  "Unable to unlink with texture names since they can't be recognized.");
                    }

                    tex.Tag = $"tex{tId.Value:D3}";
                    break;
                }

                texs.Add(tex);

                //Finally, dispose
                if (disposeResInPsb)
                {
                    resource.Data = null;
                }
            }

            return(texs);
        }
Beispiel #5
0
        /// <summary>
        /// Save as pure MDF
        /// </summary>
        /// <param name="psb"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        public static byte[] SaveAsMdf(this PSB psb, uint?key = null)
        {
            psb.Merge();
            var     bytes    = psb.Build();
            Adler32 adler    = new Adler32();
            uint    checksum = 0;

            if (key == null)
            {
                adler.Update(bytes);
                checksum = (uint)adler.Checksum;
            }

            MemoryStream ms = new MemoryStream(bytes);

            using (MemoryStream fs = new MemoryStream())
            {
                if (key != null)
                {
                    MemoryStream nms = new MemoryStream((int)ms.Length);
                    PsbFile.Encode(key.Value, EncodeMode.Encrypt, EncodePosition.Auto, ms, nms);
                    ms.Dispose();
                    ms = nms;
                    var pos = ms.Position;
                    adler.Update(ms);
                    checksum    = (uint)adler.Checksum;
                    ms.Position = pos;
                }

                BinaryWriter bw = new BinaryWriter(fs);
                bw.WriteStringZeroTrim(MdfFile.Signature);
                bw.Write((uint)ms.Length);
                //bw.Write(ZlibCompress.Compress(ms));
                ZlibCompress.CompressToBinaryWriter(bw, ms);
                bw.WriteBE(checksum);
                ms.Dispose();
                bw.Flush();
                return(fs.ToArray());
            }
        }
Beispiel #6
0
        public static void UnlinkImagesToFile(PSB psb, FreeMountContext context, string name, string dirPath,
                                              bool disposeResInPsb = true,
                                              PsbLinkOrderBy order = PsbLinkOrderBy.Name)
        {
            var texs = UnlinkImages(psb, order, disposeResInPsb);

            var texExt    = context.ImageFormat.DefaultExtension();
            var texFormat = context.ImageFormat.ToImageFormat();

            switch (order)
            {
            case PsbLinkOrderBy.Convention:
                foreach (var tex in texs)
                {
                    tex.Save(Path.Combine(dirPath, tex.Tag + texExt), texFormat);
                }

                break;

            case PsbLinkOrderBy.Name:
                foreach (var tex in texs)
                {
                    tex.Save(Path.Combine(dirPath, $"{name}_{tex.Tag}{texExt}"), texFormat);
                }

                break;

            case PsbLinkOrderBy.Order:
                for (var i = 0; i < texs.Count; i++)
                {
                    var tex = texs[i];
                    tex.Save(Path.Combine(dirPath, $"{i}{texExt}"), texFormat);
                }

                break;
            }

            return;
        }
Beispiel #7
0
        /// <summary>
        /// Save PSB as MDF file
        /// </summary>
        /// <param name="psb"></param>
        /// <param name="path"></param>
        /// <param name="key"></param>
        public static void SaveAsMdfFile(this PSB psb, string path, uint?key = null)
        {
            psb.Merge();
            var     bytes      = psb.Build();
            Adler32 checksumer = new Adler32();
            uint    checksum   = 0;

            if (key == null)
            {
                checksumer.Update(bytes);
                checksum = (uint)checksumer.Checksum;
            }
            MemoryStream ms = new MemoryStream(bytes);

            using (Stream fs = new FileStream(path, FileMode.Create))
            {
                if (key != null)
                {
                    MemoryStream nms = new MemoryStream((int)ms.Length);
                    PsbFile.Encode(key.Value, EncodeMode.Encrypt, EncodePosition.Auto, ms, nms);
                    ms.Dispose();
                    ms = nms;
                    var pos = ms.Position;
                    checksumer.Update(ms);
                    checksum    = (uint)checksumer.Checksum;
                    ms.Position = pos;
                }

                BinaryWriter bw = new BinaryWriter(fs);
                bw.WriteStringZeroTrim(MdfFile.Signature);
                bw.Write((uint)ms.Length);
                bw.Write(ZlibCompress.Compress(ms));
                bw.WriteBE(checksum);
                ms.Dispose();
                bw.Flush();
            }
        }
Beispiel #8
0
        public static void LinkImages(PSB psb, FreeMountContext context, IList <string> resPaths, string baseDir = null,
                                      PsbLinkOrderBy order = PsbLinkOrderBy.Convention, bool isExternal = false)
        {
            if (isExternal)
            {
                MotionType.MotionResourceInstrument(psb);
            }

            var rawResList = psb.CollectResources <ImageMetadata>();

            if (order == PsbLinkOrderBy.Order)
            {
                for (int i = 0; i < rawResList.Count; i++)
                {
                    var resMd    = rawResList[i];
                    var fullPath = Path.Combine(baseDir ?? "", resPaths[i]);
                    resMd.Link(fullPath, context);
                }

                return;
            }

            var resList = rawResList.ToList();

            if (order == PsbLinkOrderBy.Name)
            {
                if (psb.Platform == PsbSpec.krkr)
                {
                    throw new InvalidOperationException(
                              $"Can not link by file name for krkr PSB. Please consider using {PsbLinkOrderBy.Convention}");
                }

                resList.Sort((md1, md2) =>
                             (int)(((ImageMetadata)md1).TextureIndex ?? 0) - (int)(((ImageMetadata)md2).TextureIndex ?? 0));
            }

            for (var i = 0; i < resPaths.Count; i++)
            {
                var resPath = resPaths[i];
                var resName = Path.GetFileNameWithoutExtension(resPath);
                //var resMd = uint.TryParse(resName, out uint rid)
                //    ? resList.FirstOrDefault(r => r.Index == rid)
                //    : resList.FirstOrDefault(r =>
                //        resName == $"{r.Part}{PsbResCollector.ResourceNameDelimiter}{r.Name}");

                //Scan for Resource
                ImageMetadata resMd = null;
                if (order == PsbLinkOrderBy.Name)
                {
                    if (resName == null)
                    {
                        continue;
                    }

                    if (resList.Count == 1 && resPaths.Count == 1)
                    {
                        //If there is only one resource and one texture, we won't care about file name.
                        resMd = resList[0];
                    }
                    else
                    {
                        var texIdx = ImageMetadata.GetTextureIndex(resName);

                        if (texIdx == null)
                        {
                            Console.WriteLine($"[WARN]{resPath} is not used since the file name cannot be recognized.");
                            continue;
                        }

                        if (resList.Count <= texIdx.Value)
                        {
                            Console.WriteLine($"[WARN]{resPath} is not used since the tex No. is too large.");
                            continue;
                        }

                        resMd = resList[(int)texIdx.Value];
                    }
                }
                else //if (order == PsbLinkOrderBy.Convention)
                {
                    resMd = resList.FirstOrDefault(r =>
                                                   resName == $"{r.Part}{Consts.ResourceNameDelimiter}{r.Name}");
                    if (resMd == null && uint.TryParse(resName, out uint rid))
                    {
                        //This Link has no support for raw palette
                        resMd = resList.FirstOrDefault(r => r.Index == rid);
                    }

                    if (resMd == null && psb.Type == PsbType.Pimg)
                    {
                        resMd = resList.FirstOrDefault(r => resName == Path.GetFileNameWithoutExtension(r.Name));
                    }
                }


                if (resMd == null)
                {
                    Console.WriteLine($"[WARN]{resPath} is not used.");
                    continue;
                }

                var fullPath = Path.Combine(baseDir ?? "", resPath.Replace('/', '\\'));
                resMd.Link(fullPath, context);
            }
        }
Beispiel #9
0
        public static Dictionary <string, string> OutputExtraResources(PSB psb, FreeMountContext context, string name,
                                                                       string dirPath, out Dictionary <string, float[]> flattenArrays, PsbExtractOption extractOption = PsbExtractOption.Original)
        {
            Dictionary <string, string> extraResDictionary = new Dictionary <string, string>();

            flattenArrays = null;

            if (!context.UseFlattenArray() && !Consts.FlattenArrayByDefault)
            {
                extractOption = PsbExtractOption.Original;
            }

            if (extractOption == PsbExtractOption.Original)
            {
                if (!Directory.Exists(dirPath))
                {
                    Directory.CreateDirectory(dirPath);
                }

                for (int i = 0; i < psb.ExtraResources.Count; i++)
                {
                    var relativePath = psb.ExtraResources[i].Index == null ? $"#{Consts.ExtraResourceIdentifierChar}{i}.bin" : $"{Consts.ExtraResourceIdentifierChar}{psb.ExtraResources[i].Index}.bin";

                    File.WriteAllBytes(
                        Path.Combine(dirPath, relativePath),
                        psb.ExtraResources[i].Data);
                    extraResDictionary.Add(Path.GetFileNameWithoutExtension(relativePath), $"{name}/{Consts.ExtraResourceFolderName}/{relativePath}");
                }
            }
            else //Extract
            {
                flattenArrays = new Dictionary <string, float[]>();
                //context.Context[Consts.Context_FlattenArray] = flattenArrays;
                for (int i = 0; i < psb.ExtraResources.Count; i++)
                {
                    var relativePath = psb.ExtraResources[i].Index == null ? $"#{Consts.ExtraResourceIdentifierChar}{i}.bin" : $"{Consts.ExtraResourceIdentifierChar}{psb.ExtraResources[i].Index}.bin";
                    var data         = psb.ExtraResources[i].Data;
                    var resName      = Path.GetFileNameWithoutExtension(relativePath);
                    if (data.Length % 4 == 0)
                    {
                        var floats = MemoryMarshal.Cast <byte, float>(data.AsSpan());
                        flattenArrays.Add(resName, floats.ToArray());
                        //extraResDictionary.Add(resName, "");
                    }
                    else
                    {
                        if (!Directory.Exists(dirPath))
                        {
                            Directory.CreateDirectory(dirPath);
                        }

                        File.WriteAllBytes(
                            Path.Combine(dirPath, relativePath),
                            psb.ExtraResources[i].Data);
                        extraResDictionary.Add(resName, $"{name}/{Consts.ExtraResourceFolderName}/{relativePath}");
                    }
                }
            }

            return(extraResDictionary);
        }
Beispiel #10
0
        public static Dictionary <string, string> OutputImageResources(PSB psb, FreeMountContext context, string name,
                                                                       string dirPath,
                                                                       PsbExtractOption extractOption = PsbExtractOption.Original,
                                                                       PsbImageFormat extractFormat   = PsbImageFormat.png)
        {
            var resources = psb.CollectResources <ImageMetadata>();

            Dictionary <string, string> resDictionary = new Dictionary <string, string>();

            ImageFormat pixelFormat;

            switch (extractFormat)
            {
            case PsbImageFormat.png:
                pixelFormat = ImageFormat.Png;
                break;

            default:
                pixelFormat = ImageFormat.Bmp;
                break;
            }

            if (extractOption == PsbExtractOption.Original)
            {
                for (int i = 0; i < psb.Resources.Count; i++)
                {
                    var relativePath = psb.Resources[i].Index == null ? $"#{Consts.ResourceIdentifierChar}{i}.bin" : $"{psb.Resources[i].Index}.bin";

                    File.WriteAllBytes(
                        Path.Combine(dirPath, relativePath),
                        psb.Resources[i].Data);
                    resDictionary.Add(Path.GetFileNameWithoutExtension(relativePath), $"{name}/{relativePath}");
                }
            }
            else
            {
                for (int i = 0; i < resources.Count; i++)
                {
                    var resource = resources[i];
                    //Generate Friendly Name
                    var    friendlyName = resource.GetFriendlyName(psb.Type);
                    string relativePath = friendlyName;
                    if (string.IsNullOrWhiteSpace(friendlyName))
                    {
                        relativePath = resource.Resource.Index?.ToString() ?? $"({i})";
                        friendlyName = i.ToString();
                    }

                    var currentExtractOption = extractOption;
                    if (resource.Compress != PsbCompressType.Tlg && resource.Compress != PsbCompressType.ByName && (resource.Width <= 0 || resource.Height <= 0)) //impossible to extract, just keep raw
                    {
                        if (currentExtractOption == PsbExtractOption.Extract)
                        {
                            currentExtractOption = PsbExtractOption.Original;
                        }
                    }

                    switch (currentExtractOption)
                    {
                    case PsbExtractOption.Extract:
                        switch (extractFormat)
                        {
                        case PsbImageFormat.png:
                            relativePath += ".png";
                            break;

                        default:
                            relativePath += ".bmp";
                            break;
                        }

                        relativePath = CheckPath(relativePath, i);
                        if (resource.Compress == PsbCompressType.RL)
                        {
                            RL.DecompressToImageFile(resource.Data, Path.Combine(dirPath, relativePath),
                                                     resource.Height, resource.Width, extractFormat, resource.PixelFormat);
                        }
                        else if (resource.Compress == PsbCompressType.Tlg ||
                                 resource.Compress == PsbCompressType.ByName)
                        {
                            var bmp = context.ResourceToBitmap(resource.Compress == PsbCompressType.Tlg
                                    ? ".tlg"
                                    : Path.GetExtension(resource.Name), resource.Data);
                            if (bmp == null)
                            {
                                if (resource.Compress == PsbCompressType.Tlg)     //Fallback to managed TLG decoder
                                {
                                    using var ms = new MemoryStream(resource.Data);
                                    using var br = new BinaryReader(ms);
                                    bmp          = new TlgImageConverter().Read(br);
                                    bmp.Save(Path.Combine(dirPath, relativePath), pixelFormat);
                                    bmp.Dispose();
                                }

                                relativePath = Path.ChangeExtension(relativePath, Path.GetExtension(resource.Name));
                                File.WriteAllBytes(Path.Combine(dirPath, relativePath), resource.Data);
                            }
                            else
                            {
                                bmp.Save(Path.Combine(dirPath, relativePath), pixelFormat);
                                bmp.Dispose();
                            }
                        }
                        //else if (resource.Compress == PsbCompressType.ByName)
                        //{
                        //    relativePath = Path.ChangeExtension(relativePath, Path.GetExtension(resource.Name));
                        //    File.WriteAllBytes(Path.Combine(dirPath, relativePath), resource.Data);
                        //}
                        else
                        {
                            RL.ConvertToImageFile(resource.Data, Path.Combine(dirPath, relativePath),
                                                  resource.Height, resource.Width, extractFormat, resource.PixelFormat, resource.PalData,
                                                  resource.PalettePixelFormat);
                        }

                        break;

                    case PsbExtractOption.Original:
                        if (resources[i].Compress == PsbCompressType.RL)
                        {
                            relativePath += ".rl";
                            relativePath  = CheckPath(relativePath, i);
                            File.WriteAllBytes(Path.Combine(dirPath, relativePath), resource.Data);
                        }
                        else if (resource.Compress == PsbCompressType.Tlg)
                        {
                            relativePath += ".tlg";
                            relativePath  = CheckPath(relativePath, i);
                            File.WriteAllBytes(Path.Combine(dirPath, relativePath), resource.Data);
                        }
                        else
                        {
                            relativePath += ".raw";
                            relativePath  = CheckPath(relativePath, i);
                            File.WriteAllBytes(Path.Combine(dirPath, relativePath), resource.Data);
                        }

                        break;

                    //case PsbExtractOption.Decompress:
                    //    relativePath += ".raw";
                    //    relativePath = CheckPath(relativePath, i);
                    //    File.WriteAllBytes(Path.Combine(dirPath, relativePath),
                    //        resources[i].Compress == PsbCompressType.RL
                    //            ? RL.Decompress(resource.Data)
                    //            : resource.Data);
                    //    break;
                    //case PsbExtractOption.Compress:
                    //    relativePath += ".rl";
                    //    relativePath = CheckPath(relativePath, i);
                    //    File.WriteAllBytes(Path.Combine(dirPath, relativePath),
                    //        resources[i].Compress != PsbCompressType.RL
                    //            ? RL.Compress(resource.Data)
                    //            : resource.Data);
                    //    break;
                    default:
                        throw new ArgumentOutOfRangeException(nameof(currentExtractOption), currentExtractOption, null);
                    }

                    //Determine save name
                    try
                    {
                        bool indexConflict   = false;
                        uint conflictedIndex = 0;
                        if (resource.Resource.Index != null)                          //try index as name first
                        {
                            if (resDictionary.ContainsKey(resource.Index.ToString())) //index is used before
                            {
                                Console.WriteLine(
                                    $"[WARN] Resource Index {resource.Index} conflict. May be resource sharing, but may also be something wrong.");
                                //continue;
                                indexConflict           = true;
                                conflictedIndex         = resource.Resource.Index.Value;
                                resource.Resource.Index = null; //have another try on friendly name
                            }
                        }
                        if (resource.Resource.Index == null)
                        {
                            if (resDictionary.ContainsKey(friendlyName)) // friendly name is also used (most likely its the same res reused), no name can be used to save
                            {
                                Console.WriteLine(
                                    $"[WARN] Resource Name {friendlyName} conflict. May be resource sharing, but may also be something wrong.");
                                continue; //just skip
                            }

                            if (indexConflict) //index is used but friendly name is not (maybe they are different?), save using friendly name
                            {
                                Console.WriteLine($"[FIXED] Resource {friendlyName} is sharing same data with Index {conflictedIndex}");
                            }
                        }

                        resDictionary.Add(resource.Resource.Index == null ? friendlyName : resource.Index.ToString(),
                                          $"{name}/{relativePath}");
                    }
                    catch (ArgumentException e)
                    {
                        throw new PsbBadFormatException(PsbBadFormatReason.Resources,
                                                        "Resource Export Error: Name conflict, or Index is not specified. Try Raw export mode.", e);
                    }
                }
            }

            string CheckPath(string rPath, int id)
            {
                var k = Path.GetFileNameWithoutExtension(rPath);

                if (resDictionary.ContainsKey(k))
                {
                    return($"{id}{Path.GetExtension(rPath)}");
                }

                return(rPath);
            }

            return(resDictionary);
        }
Beispiel #11
0
        public static void LinkExtraResources(PSB psb, FreeMountContext context, Dictionary <string, string> extraResourcesDictionary, Dictionary <string, float[]> flattenArrays = null, string baseDir = null)
        {
            foreach (var extraResource in psb.ExtraResources)
            {
                if (extraResource.Index == null)
                {
                    Console.WriteLine("[WARN] Found Extra resource without index. Skipped.");
                    continue;
                }
                var key = $"{Consts.ExtraResourceIdentifierChar}{extraResource.Index}";
                if (flattenArrays != null && (context.UseFlattenArray() || Consts.FlattenArrayByDefault))
                {
                    if (!LinkFromFlattenArray(extraResource, key))
                    {
                        if (!LinkFromFile(extraResource, key))
                        {
                            Console.WriteLine($"[WARN] Extra resource {key} cannot be linked.");
                        }
                    }
                }
                else
                {
                    if (!LinkFromFile(extraResource, key))
                    {
                        Console.WriteLine($"[WARN] Extra resource {key} cannot be linked.");
                    }
                }
            }

            bool LinkFromFile(PsbResource res, string key)
            {
                if (extraResourcesDictionary.ContainsKey(key) && !string.IsNullOrEmpty(extraResourcesDictionary[key]))
                {
                    var path     = extraResourcesDictionary[key];
                    var fullPath = Path.IsPathRooted(path)
                        ? path
                        : Path.Combine(baseDir ?? "", path.Replace('/', '\\'));
                    if (!File.Exists(fullPath))
                    {
                        return(false);
                    }
                    res.Data = File.ReadAllBytes(fullPath);
                    return(true);
                }

                return(false);
            }

            bool LinkFromFlattenArray(PsbResource res, string key)
            {
                if (flattenArrays.ContainsKey(key))
                {
                    var floats = flattenArrays[key].AsSpan();
                    var bytes  = MemoryMarshal.Cast <float, byte>(floats);
                    res.Data = bytes.ToArray();
                    return(true);
                }

                return(false);
            }
        }
Beispiel #12
0
 public PsbPainter(PSB psb)
 {
     Source = psb;
     UpdateResource();
 }