public void TestLoadMmo() { var resPath = Path.Combine(Environment.CurrentDirectory, @"..\..\Res"); var path = Path.Combine(resPath, "mmo", "template39.mmo"); var psb = new PSB(path); var content = (PsbDictionary)psb.Objects.FindByPath("objectChildren/[0]/children/[0]/layerChildren/[0]/frameList/[0]/content"); foreach (var kv in content) { var k = kv.Key; var v = kv.Value; } }
public Dictionary <string, string> OutputResources(PSB psb, FreeMountContext context, string name, string dirPath, PsbExtractOption extractOption = PsbExtractOption.Original) { var resources = psb.CollectResources <AudioMetadata>(); Dictionary <string, string> resDictionary = new Dictionary <string, string>(); if (extractOption == PsbExtractOption.Original) { for (int i = 0; i < psb.Resources.Count; i++) { var relativePath = psb.Resources[i].Index == null ? $"#{i}.raw" : $"{psb.Resources[i].Index}.raw"; File.WriteAllBytes( Path.Combine(dirPath, relativePath), psb.Resources[i].Data); resDictionary.Add(Path.GetFileNameWithoutExtension(relativePath), $"{name}/{relativePath}"); } } else { foreach (var resource in resources) { if (resource.ChannelList.Count == 1) { var bts = resource.ChannelList[0].TryToWave(context); var relativePath = resource.GetFileName(resource.ChannelList[0].WaveExtension); //WaveExtension may change after ToWave if (bts != null) { File.WriteAllBytes(Path.Combine(dirPath, relativePath), bts); resDictionary.Add(resource.Name, $"{name}/{relativePath}"); } } else if (resource.ChannelList.Count > 1) { for (var j = 0; j < resource.ChannelList.Count; j++) { var waveChannel = resource.ChannelList[j]; var bts = waveChannel.TryToWave(context); var relativePath = resource.GetFileName($"-{j}{waveChannel.WaveExtension}"); if (bts != null) { File.WriteAllBytes(Path.Combine(dirPath, relativePath), bts); resDictionary.Add(resource.Name, $"{name}/{relativePath}"); } } } } } return(resDictionary); }
public void TestConvertCommon2Krkr() { var resPath = Path.Combine(Environment.CurrentDirectory, @"..\..\Res"); var path = Path.Combine(resPath, "akira_guide-pure.psb.json"); PSB psb = PsbCompiler.LoadPsbFromJsonFile(path); Common2KrkrConverter converter = new Common2KrkrConverter(); converter.Convert(psb); psb.Merge(); File.WriteAllBytes("emote_test_front.psb", psb.Build()); File.WriteAllText("emote_test_front.json", PsbDecompiler.Decompile(psb)); }
public void TestInline() { var resPath = Path.Combine(Environment.CurrentDirectory, @"..\..\Res"); var path = Path.Combine(resPath, "2001010400_00_mid.pure.psb"); var texPath = Path.Combine(resPath, "2001010400_00_mid_tex000.png"); PSB psb = new PSB(path); psb.Link(new List <string> { texPath }, order: PsbLinkOrderBy.Order); psb.Merge(); File.WriteAllBytes("inline.psb", psb.Build()); PSB p2 = new PSB("inline.psb"); }
public bool IsThisType(PSB psb) { if (psb.Objects.ContainsKey("layers") && psb.Objects.ContainsKey("height") && psb.Objects.ContainsKey("width")) { return(true); } if (psb.Objects.Any(k => k.Key.Contains(".") && k.Value is PsbResource)) { return(true); } return(false); }
/// <summary> /// Decompile to files /// </summary> /// <param name="psb">PSB</param> /// <param name="outputPath">Output json file name, should end with .json</param> /// <param name="additionalContext">additional context used in decompilation</param> /// <param name="extractOption">whether to extract image to common format</param> /// <param name="extractFormat">if extract, what format do you want</param> /// <param name="useResx">if false, use array-based resource json (legacy)</param> /// <param name="key">PSB CryptKey</param> public static void DecompileToFile(PSB psb, string outputPath, Dictionary <string, object> additionalContext = null, PsbExtractOption extractOption = PsbExtractOption.Original, PsbImageFormat extractFormat = PsbImageFormat.png, bool useResx = true, uint?key = null) { var context = FreeMount.CreateContext(additionalContext); if (key != null) { context.Context[Consts.Context_CryptKey] = key; } File.WriteAllText(outputPath, Decompile(psb)); //MARK: breaking change for json path OutputResources(psb, context, outputPath, extractOption, extractFormat, useResx); }
public bool IsThisType(PSB psb) { if (psb.Objects.ContainsKey("scenes") && psb.Objects.ContainsKey("name")) { return(true); } if (psb.Objects.ContainsKey("list") && psb.Objects.ContainsKey("map") && psb.Resources?.Count == 0) { return(true); } return(false); }
/// <summary> /// Modify the original PSB and only replace resources (according to json) /// </summary> /// <param name="psbPath">PSB to be modified</param> /// <param name="jsonPath">PSB Json which only resources are changed</param> /// <returns></returns> public static MemoryStream InplaceReplace(string psbPath, string jsonPath) { var jsonPsb = LoadPsbFromJsonFile(jsonPath); using var psbFs = File.OpenRead(psbPath); var ctx = FreeMount.CreateContext(); using var psbStream = ctx.OpenStreamFromPsbFile(psbPath); var psb = new PSB(psbStream); if (jsonPsb.Resources.Count != psb.Resources.Count) { throw new NotSupportedException("The 2 PSBs are different (Resource count)."); } MemoryStream ms = new MemoryStream((int)psbStream.Length); psbStream.Seek(0, SeekOrigin.Begin); psbStream.CopyTo(ms); using BinaryWriter bw = new BinaryWriter(ms, Encoding.UTF8, true); for (var i = 0; i < jsonPsb.Resources.Count; i++) { var resource = jsonPsb.Resources[i]; var oriResource = psb.Resources[i]; if (resource.Data.Length > oriResource.Data.Length) { throw new NotSupportedException($"The 2 PSBs are different (Resource {i} length: {resource.Data.Length} vs {oriResource.Data.Length})."); } if (oriResource.Index == null) { Console.WriteLine($"[WARN] Resource {i} is not replaced."); continue; } var offset = psb.ChunkOffsets[(int)oriResource.Index]; var length = psb.ChunkLengths[(int)oriResource.Index]; bw.BaseStream.Seek(psb.Header.OffsetChunkData + offset, SeekOrigin.Begin); bw.Write(resource.Data); if (length > resource.Data.Length) { bw.Write(new byte[length - resource.Data.Length]); } } return(ms); }
public List <T> CollectResources <T>(PSB psb, bool deDuplication = true) where T : IResourceMetadata { List <T> resourceList = psb.Resources == null ? new List <T>() : new List <T>(psb.Resources.Count); if (psb.Resources != null) { resourceList.AddRange(psb.Resources.Select(r => new ImageMetadata { Resource = r }).Cast <T>()); } return(resourceList); }
public void TestPsbEncoding() { var resPath = Path.Combine(Environment.CurrentDirectory, @"..\..\Res"); var path = Path.Combine(resPath, "staffroll_script.txt.scn"); //Consts.PsbEncoding = Encoding.GetEncoding("SHIFT-JIS"); PSB psb = new PSB(); psb.LoadFromStream(File.OpenRead(path)); foreach (var psbString in psb.Strings) { var str = psbString; var str2 = Encoding.GetEncoding("SHIFT-JIS").GetString(Encoding.UTF8.GetBytes(str.Value)); } }
public PsbResourceJson(PSB psb, Dictionary <string, object> context = null) { PsbVersion = psb.Header.Version; PsbType = psb.Type; Platform = psb.Platform; //ExternalTextures = psb.Resources.Count <= 0; if (context != null) { CryptKey = context.ContainsKey(Consts.Context_CryptKey) ? (uint?)context[Consts.Context_CryptKey] : null; Context = context; } }
private Dictionary <string, List <string> > TranslateResources(PSB psb) { Dictionary <string, List <string> > iconInfos = new Dictionary <string, List <string> >(); var source = (PsbDictionary)psb.Objects["source"]; foreach (var tex in source) { if (tex.Value is PsbDictionary texDic) { var iconList = new List <string>(); iconInfos.Add(tex.Key, iconList); var bmps = TextureSpliter.SplitTexture(texDic, psb.Platform); var icons = (PsbDictionary)texDic["icon"]; foreach (var iconPair in icons) { iconList.Add(iconPair.Key); var icon = (PsbDictionary)iconPair.Value; var data = UseRL ? RL.CompressImage(bmps[iconPair.Key], TargetPixelFormat) : RL.GetPixelBytesFromImage(bmps[iconPair.Key], TargetPixelFormat); icon[Consts.ResourceKey] = new PsbResource { Data = data, Parents = new List <IPsbCollection> { icon } }; icon["compress"] = UseRL ? new PsbString("RL") : new PsbString(); icon.Remove("left"); icon.Remove("top"); //There is no obvious match for attr? //if (icon["attr"] is PsbNumber n && n.AsInt > 0) //{ // icon["attr"] = PsbNull.Null; //} //else //{ // icon.Remove("attr"); //} icon.Remove("attr"); } texDic.Remove("texture"); texDic["type"] = new PsbNumber(1); } } return(iconInfos); }
public List <T> CollectResources <T>(PSB psb, bool deDuplication = true) where T : IResourceMetadata { List <T> resourceList = psb.Resources == null ? new List <T>() : new List <T>(psb.Resources.Count); resourceList.AddRange(psb.Objects.Where(k => k.Value is PsbResource).Select(k => new ImageMetadata() { Name = k.Key, Resource = k.Value as PsbResource, Compress = k.Key.EndsWith(".tlg", true, null) ? PsbCompressType.Tlg : PsbCompressType.ByName }).Cast <T>()); return(resourceList); }
public void Convert(PSB psb) { if (!FromSpec.Contains(psb.Platform)) { throw new FormatException("Can not convert Spec for this PSB"); } if (ConvertOption == SpecConvertOption.Minimum) { Remove(psb); } var iconInfo = TranslateResources(psb); Travel((PsbDictionary)psb.Objects["object"], iconInfo); Add(psb); psb.Platform = ToWin ? PsbSpec.win : PsbSpec.common; }
public void TestConvertKrkr2Win() { var resPath = Path.Combine(Environment.CurrentDirectory, @"..\..\Res"); //var path = Path.Combine(resPath, "澄怜a_裸.psb-pure.psb"); var path = Path.Combine(resPath, "澄怜a_裸.psb-pure.psb.json"); //var path = Path.Combine(resPath, "e-mote38_KRKR-pure.psb.json"); //var path = Path.Combine(resPath, "e-mote38_KRKR-pure.psb"); PSB psb = PsbCompiler.LoadPsbFromJsonFile(path); //PSB psb = new PSB(path); psb.SwitchSpec(PsbSpec.win); psb.Merge(); File.WriteAllBytes("emote_krkr2win.psb", psb.Build()); File.WriteAllText("emote_krkr2win.json", PsbDecompiler.Decompile(psb)); RL.ConvertToImageFile(psb.Resources.First().Data, "tex-in-psb.png", 4096, 4096, PsbImageFormat.Png, PsbPixelFormat.WinRGBA8); }
public void AppliedToPsb(PSB psb) { if (PsbType != null) { psb.Type = PsbType.Value; } if (PsbVersion != null) { psb.Header.Version = PsbVersion.Value; } if (Platform != null && psb.Platform != PsbSpec.none) { psb.Platform = Platform.Value; } }
private void openToolStripMenuItem_Click(object sender, EventArgs e) { OpenFileDialog fd = new OpenFileDialog(); fd.Filter = "All Prototype PSB Scripts|*.psb"; if (fd.ShowDialog() != DialogResult.OK) { return; } Editor = new PSB(System.IO.File.ReadAllBytes(fd.FileName)); listBox1.Items.Clear(); foreach (string str in Editor.Import()) { listBox1.Items.Add(str); } }
public override Dictionary <string, string> OutputResources(PSB psb, FreeMountContext context, string name, string dirPath, PsbExtractOption extractOption = PsbExtractOption.Original) { //Extra Extract if (extractOption == PsbExtractOption.Extract) { if (psb.Type == PsbType.Tachie) { var bitmaps = TextureCombiner.CombineTachie(psb); foreach (var kv in bitmaps) { kv.Value.Save(Path.Combine(dirPath, $"{kv.Key}{context.ImageFormat.DefaultExtension()}"), context.ImageFormat.ToImageFormat()); } } } return(base.OutputResources(psb, context, name, dirPath, extractOption)); }
/// <summary> /// Link /// </summary> /// <param name="psb"></param> /// <param name="resx">advanced resource json(resx.jon)</param> /// <param name="baseDir"></param> internal static void Link(this PSB psb, PsbResourceJson resx, string baseDir) { if (resx.Resources == null) { return; } var context = FreeMount.CreateContext(resx.Context); if (psb.TypeHandler != null) { psb.TypeHandler.Link(psb, context, resx.Resources, baseDir); } else { PsbResHelper.LinkImages(psb, context, resx.Resources, baseDir); } }
/// <summary> /// Convert a PSB to External Texture PSB. /// </summary> /// <param name="inputPath"></param> /// <param name="outputUnlinkedPsb">output unlinked PSB; otherwise only output textures</param> /// <param name="order"></param> /// <param name="format"></param> /// <returns>The unlinked PSB path</returns> public static string UnlinkToFile(string inputPath, bool outputUnlinkedPsb = true, PsbLinkOrderBy order = PsbLinkOrderBy.Name, PsbImageFormat format = PsbImageFormat.png) { if (!File.Exists(inputPath)) { return(null); } var name = Path.GetFileNameWithoutExtension(inputPath); var dirPath = Path.Combine(Path.GetDirectoryName(inputPath), name); var psbSavePath = inputPath; if (File.Exists(dirPath)) { name += "-resources"; dirPath += "-resources"; } if (!Directory.Exists(dirPath)) //ensure there is no file with same name! { Directory.CreateDirectory(dirPath); } var context = FreeMount.CreateContext(); context.ImageFormat = format; var psb = new PSB(inputPath); if (psb.TypeHandler is BaseImageType imageType) { imageType.UnlinkToFile(psb, context, name, dirPath, outputUnlinkedPsb, order); } psb.TypeHandler.UnlinkToFile(psb, context, name, dirPath, outputUnlinkedPsb, order); if (outputUnlinkedPsb) { psb.Merge(); psbSavePath = Path.ChangeExtension(inputPath, ".unlinked.psb"); //unlink only works with motion.psb so no need for ext rename File.WriteAllBytes(psbSavePath, psb.Build()); } return(psbSavePath); }
void FixedUpdate() { float h = main.health; float mh = main.max_health; timer_smoke++; if (h / mh < .25f) { PSB.startColor = new Vector4(0, 0, 0, 255); } else { PSB.startColor = new Vector4(255, 255, 255, 255); } if (timer_smoke > h / mh * 350 && mh - h > 10) { PSB.Emit((int)(1)); timer_smoke = 0; } }
/// <summary> /// Save (most user friendly) images /// </summary> /// <param name="inputPath"></param> /// <param name="format"></param> public static void ExtractImageFiles(string inputPath, PsbImageFormat format = PsbImageFormat.png) { if (!File.Exists(inputPath)) { return; } var name = Path.GetFileNameWithoutExtension(inputPath); var dirPath = Path.Combine(Path.GetDirectoryName(inputPath), name); if (File.Exists(dirPath)) { name += "-resources"; dirPath += "-resources"; } if (!Directory.Exists(dirPath)) //ensure there is no file with same name! { Directory.CreateDirectory(dirPath); } var texExt = format == PsbImageFormat.bmp ? ".bmp" : ".png"; var texFormat = format.ToImageFormat(); var psb = new PSB(inputPath); if (psb.Type == PsbType.Tachie) { var bitmaps = TextureCombiner.CombineTachie(psb); foreach (var kv in bitmaps) { kv.Value.Save(Path.Combine(dirPath, $"{kv.Key}{texExt}"), texFormat); } return; } var texs = PsbResHelper.UnlinkImages(psb); foreach (var tex in texs) { tex.Save(Path.Combine(dirPath, tex.Tag + texExt), texFormat); } }
private static void Port(string s, PsbSpec portSpec) { var name = Path.GetFileNameWithoutExtension(s); var ext = Path.GetExtension(s); Console.WriteLine($"Converting {name} to {portSpec} platform..."); PSB psb = new PSB(s); if (psb.Platform == portSpec) { Console.WriteLine("Already at the same platform, Skip."); } else { psb.SwitchSpec(portSpec); psb.Merge(); File.WriteAllBytes(Path.ChangeExtension(s, $".{portSpec}.psb"), psb.Build()); Console.WriteLine($"Convert {name} succeed."); } }
public bool TryGetArchData(PSB psb, PsbDictionary dic, out IArchData data) { data = null; if (psb.Platform == PsbSpec.ps4 || psb.Platform == PsbSpec.vita) { if (dic.Count == 1 && dic["archData"] is PsbResource res) { data = new Atrac9ArchData { Data = res }; return(true); } return(false); } return(false); }
public void TestConvertWin2Krkr() { var resPath = Path.Combine(Environment.CurrentDirectory, @"..\..\Res"); //var path = Path.Combine(resPath, "e-mote38_win-pure.psb.json"); var path = Path.Combine(resPath, "e-mote38_win-pure.psb"); //var path = Path.Combine(resPath, "dx_e-mote3.0ショコラパジャマa-pure.psb.json"); //PSB psb = PsbCompiler.LoadPsbFromJsonFile(path); PSB psb = new PSB(path); psb.SwitchSpec(PsbSpec.krkr); //Common2KrkrConverter converter = new Common2KrkrConverter(); //converter.Convert(psb); psb.Merge(); File.WriteAllBytes("emote_test_front.psb", psb.Build()); File.WriteAllText("emote_test_front.json", PsbDecompiler.Decompile(psb)); psb.SwitchSpec(PsbSpec.win); psb.Merge(); File.WriteAllBytes("emote_2x.psb", psb.Build()); }
/// <summary> /// Link Textures /// </summary> /// <param name="psb"></param> /// <param name="resPaths">resource paths</param> /// <param name="baseDir"></param> /// <param name="order">how to arrange images</param> /// <param name="isExternal">Whether this is an external texture PSB</param> public static void Link(this PSB psb, IList <string> resPaths, string baseDir = null, PsbLinkOrderBy order = PsbLinkOrderBy.Convention, bool isExternal = false) { var context = FreeMount.CreateContext(); if (psb.Type == PsbType.Motion) { PsbResHelper.LinkImages(psb, context, resPaths, baseDir, order, isExternal); return; } if (psb.TypeHandler != null) { psb.TypeHandler.Link(psb, context, resPaths, baseDir, order); } else { PsbResHelper.LinkImages(psb, context, resPaths, baseDir, order); } }
public void Convert(PSB psb) { if (!FromSpec.Contains(psb.Platform)) { throw new FormatException("Can not convert Spec for this PSB"); } var asSpec = EmsAsCommon ? PsbSpec.ems : PsbSpec.common; var toSpec = psb.Platform == PsbSpec.win ? asSpec : PsbSpec.win; var toPixelFormat = toSpec == asSpec ? PsbPixelFormat.CommonRGBA8 : PsbPixelFormat.WinRGBA8; var resList = psb.CollectResources <ImageMetadata>(false); foreach (var resMd in resList) { var resourceData = resMd.Resource.Data; if (resourceData == null) { continue; } if (resMd.Compress == PsbCompressType.RL) { resourceData = RL.Decompress(resourceData); } if (resMd.PixelFormat == PsbPixelFormat.DXT5) { resourceData = RL.GetPixelBytesFromImage( DxtUtil.Dxt5Decode(resourceData, resMd.Width, resMd.Height), toPixelFormat); resMd.TypeString.Value = toPixelFormat.ToStringForPsb(); } else { RL.Switch_0_2(ref resourceData); if (UseRL) { resourceData = RL.Compress(resourceData); } } resMd.Resource.Data = resourceData; } psb.Platform = toSpec; }
// ReSharper disable once InvalidXmlDocComment /// <summary> /// Inlined PSB -> External Texture PSB. Inverse of <seealso cref="PsbCompiler.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> Unlink(this PSB psb, PsbLinkOrderBy order = PsbLinkOrderBy.Name, bool disposeResInPsb = true) { var resources = psb.CollectResources(); 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.Height, resource.Width, resource.PixelFormat); 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); }
public void TestGraft() { var resPath = Path.Combine(Environment.CurrentDirectory, @"..\..\Res"); //var path = Path.Combine(resPath, "澄怜a_裸.psb-pure.psb.json"); var path = Path.Combine(resPath, "e-mote38_KRKR-pure.psb.json"); var path2 = Path.Combine(resPath, "e-mote38_win-pure.psb.json"); PSB psbKrkr = PsbCompiler.LoadPsbFromJsonFile(path); PSB psbWin = PsbCompiler.LoadPsbFromJsonFile(path2); psbWin.SwitchSpec(PsbSpec.krkr); //var metadata = (PsbDictionary)psbWin.Objects["metadata"]; //metadata["attrcomp"] = psbKrkr.Objects["metadata"].Children("attrcomp"); psbWin.Merge(); ////Graft var resKrkr = psbKrkr.CollectResources(false); var resWin = psbWin.CollectResources(false); var headWin = resWin.FirstOrDefault(r => r.Height == 186 && r.Width == 122); var headKrkr = resKrkr.FirstOrDefault(r => r.Height == 186 && r.Width == 122); if (headWin != null && headKrkr != null) { headWin.Resource.Data = headKrkr.Resource.Data; } //foreach (var resourceMetadata in resWin) //{ // var sameRes = resKrkr.FirstOrDefault(r => r.Height == resourceMetadata.Height && r.Width == resourceMetadata.Width); // if (sameRes != null) // { // Console.WriteLine($"{sameRes} {sameRes.Width}x{sameRes.Height} found."); // resourceMetadata.Resource.Data = sameRes.Resource.Data; // } //} psbWin.Merge(); File.WriteAllBytes("emote_win2krkr.psb", psbWin.Build()); //File.WriteAllText("emote_krkr2win.json", PsbDecompiler.Decompile(psb2)); }
private void Remove(PSB psb) { //remove `easing` psb.Objects.Remove("easing"); //remove `/object/*/motion/*/bounds` //remove `/object/*/motion/*/layerIndexMap` var obj = (PsbDictionary)psb.Objects["object"]; foreach (var o in obj) { //var name = o.Key; foreach (var m in (PsbDictionary)((PsbDictionary)o.Value)["motion"]) { if (m.Value is PsbDictionary mDic) { mDic.Remove("bounds"); mDic.Remove("layerIndexMap"); } } } }