public bool PatchAnimations(AnimFilePatch[] files)
        {
            if (files == null)
            {
                return(true);
            }
            uint TargetVersion = 0;

            foreach (var p in files)
            {
                if (!sarc.Files.ContainsKey(p.FileName))
                {
                    continue;                     //return bool.Fail; Don't be so strict as older firmwares may not have all the animations (?)
                }
                if (TargetVersion == 0)
                {
                    BflanFile b = new BflanFile(sarc.Files[p.FileName]);
                    TargetVersion = b.Version;
                }

                var n = BflanSerializer.FromJson(p.AnimJson);
                n.Version              = TargetVersion;
                n.byteOrder            = Syroot.BinaryData.ByteOrder.LittleEndian;
                sarc.Files[p.FileName] = n.WriteFile();
            }
            return(true);
        }
Ejemplo n.º 2
0
        public static BflanSerializer Serialize(BflanFile file)
        {
            BflanSerializer res = new BflanSerializer()
            {
                LittleEndian = file.byteOrder == Syroot.BinaryData.ByteOrder.LittleEndian,
                Version      = file.Version
            };

            Pat1Section pat1 = file.patData;

            res.pat1 = new Pat1Serializer()
            {
                AnimationOrder  = pat1.AnimationOrder,
                ChildBinding    = pat1.ChildBinding,
                Groups          = pat1.Groups,
                Name            = pat1.Name,
                Unk_EndOfFile   = pat1.Unk_EndOfFile,
                Unk_StartOfFile = pat1.Unk_StartOfFile,
                Unk_EndOfHeader = pat1.Unk_EndOfHeader
            };

            res.pai1 = Pai1Serializer.Serialize(file.paiData);

            return(res);
        }
Ejemplo n.º 3
0
        public static string ToJson(BflanFile file)
        {
            JsonSerializerSettings settings = new JsonSerializerSettings()
            {
#if WIN
                Formatting            = Formatting.None,
                ReferenceLoopHandling = ReferenceLoopHandling.Ignore
#endif
            };

            return(JsonConvert.SerializeObject(BflanSerializer.Serialize(file), settings));
        }
Ejemplo n.º 4
0
        public BflanFile Deserialize()
        {
            BflanFile res = new BflanFile();

            res.byteOrder = LittleEndian ? Syroot.BinaryData.ByteOrder.LittleEndian : Syroot.BinaryData.ByteOrder.BigEndian;
            res.Version   = Version;

            Pat1Section _pat1 = new Pat1Section()
            {
                AnimationOrder  = pat1.AnimationOrder,
                ChildBinding    = pat1.ChildBinding,
                Groups          = pat1.Groups,
                Name            = pat1.Name,
                Unk_EndOfFile   = pat1.Unk_EndOfFile,
                Unk_StartOfFile = pat1.Unk_StartOfFile,
                Unk_EndOfHeader = pat1.Unk_EndOfHeader
            };

            res.Sections.Add(_pat1);
            res.Sections.Add(pai1.Deserialize());

            return(res);
        }
Ejemplo n.º 5
0
        public static (LayoutPatch, string) Diff(SarcData original, SarcData edited, DiffOptions?opt)
        {
            List <LayoutFilePatch> Patches = new List <LayoutFilePatch>();

            if (!ScrambledEquals <string>(original.Files.Keys, edited.Files.Keys))
            {
                throw new Exception("The provided archives don't have the same files");
            }

            bool hasAtLeastAnExtraGroup = false;             //Used to detect if animations are properly implemented

            foreach (var f in original.Files.Keys.Where(x => x.EndsWith(".bflyt")))
            {
                if (original.Files[f].SequenceEqual(edited.Files[f]))
                {
                    continue;
                }
                BflytFile _or = new BflytFile(original.Files[f]);
                BflytFile _ed = new BflytFile(edited.Files[f]);

                var curFile = DiffPanes(_or, _ed, f);

                var extraGroups = DiffGroups(_or, _ed);
                if (extraGroups != null)
                {
                    hasAtLeastAnExtraGroup = true;
                }

                var materials = DiffMaterials(_or, _ed, f);

                if (curFile.Count > 0 || extraGroups?.Count > 0 || materials?.Count > 0)
                {
                    Patches.Add(new LayoutFilePatch()
                    {
                        FileName = f, Patches = curFile.ToArray(), Materials = materials?.ToArray(), AddGroups = extraGroups?.ToArray()
                    });
                }
            }

            string Message = null;

            List <AnimFilePatch> AnimPatches = new List <AnimFilePatch>();

            foreach (var f in original.Files.Keys.Where(x => x.EndsWith(".bflan")))
            {
                if (original.Files[f].SequenceEqual(edited.Files[f]))
                {
                    continue;
                }
                BflanFile anim = new BflanFile(edited.Files[f]);
                AnimPatches.Add(new AnimFilePatch()
                {
                    FileName = f, AnimJson = BflanSerializer.ToJson(anim)
                });
            }
            if (AnimPatches.Count == 0)
            {
                AnimPatches = null;
            }
            else if (!hasAtLeastAnExtraGroup)
            {
                Message = "This theme uses custom animations but doesn't have custom group in the layouts, this means that the nxtheme will work on the firmware it has been developed on but it may break on older or newer ones. It's *highly recommended* to create custom groups to handle animations";
            }

            if (AnimPatches != null && AnimPatches.Any(x => x.FileName == "anim/RdtBase_SystemAppletPos.bflan"))
            {
                if (opt == null || opt?.HideOnlineButton == null)
                {
                    opt = new DiffOptions {
                        HideOnlineButton = false
                    }
                }
                ;
                else if (opt != null && opt.Value.HideOnlineButton.Value)
                {
                    Message = "You chose to hide the 11.0+ \"Switch online\" button but manually edited the \"RdtBase_SystemAppletPos\" animation. HideOnlineButton will be disabled.";
                    opt     = new DiffOptions {
                        HideOnlineButton = false
                    };
                }
            }

            var targetPatch = DefaultTemplates.GetFor(original);

            return(new LayoutPatch()
            {
                PatchName = "diffPatch" + (targetPatch == null ? "" : " for " + targetPatch.TemplateName),
                TargetName = targetPatch?.szsName,
                AuthorName = "autoDiff",
                Files = Patches.ToArray(),
                Anims = AnimPatches?.ToArray(),
                ID = $"Generated_{Guid.NewGuid()}",
                HideOnlineBtn = targetPatch?.NXThemeName != "home" ? null : opt?.HideOnlineButton
            }, Message);
        }
Ejemplo n.º 6
0
        public static (LayoutPatch, string) Diff(SarcData original, SarcData edited)
        {
            List <LayoutFilePatch> Patches = new List <LayoutFilePatch>();

            if (!ScrambledEquals <string>(original.Files.Keys, edited.Files.Keys))
            {
                throw new Exception("The provided archives don't have the same files");
            }

            bool hasAtLeastAnExtraGroup = false;             //Used to detect if animations are properly implemented

            foreach (var f in original.Files.Keys.Where(x => x.EndsWith(".bflyt")))
            {
                if (original.Files[f].SequenceEqual(edited.Files[f]))
                {
                    continue;
                }
                BflytFile _or = new BflytFile(original.Files[f]);
                BflytFile _ed = new BflytFile(edited.Files[f]);

                List <PanePatch> curFile = new List <PanePatch>();
                foreach (var orpane_ in _or.EnumeratePanes().Where(x => x is INamedPane))
                {
                    var edpane = _ed[((INamedPane)orpane_).PaneName];
                    if (edpane == null)
                    {
                        throw new Exception($"{f} is missing {((INamedPane)orpane_).PaneName}");
                    }
                    if (orpane_.name != edpane.name)
                    {
                        throw new Exception($"{f} : {((INamedPane)orpane_).PaneName} Two panes with the same name are of a different type");
                    }
                    if (IgnorePaneList.Contains(orpane_.name))
                    {
                        continue;
                    }

                    var edPan = (Pan1Pane)edpane;
                    var orPan = (Pan1Pane)orpane_;

                    PanePatch curPatch = new PanePatch()
                    {
                        PaneName = edPan.PaneName
                    };
                    curPatch.UsdPatches = MakeUsdPatch(edPan.UserData, orPan.UserData);
                    if (edPan.data.SequenceEqual(orPan.data))
                    {
                        if (curPatch.UsdPatches != null)
                        {
                            curFile.Add(curPatch);
                        }
                        continue;
                    }

                    if (!VecEqual(edPan.Position, orPan.Position))
                    {
                        curPatch.Position = ToNullVec(edPan.Position);
                    }
                    if (!VecEqual(edPan.Rotation, orPan.Rotation))
                    {
                        curPatch.Rotation = ToNullVec(edPan.Rotation);
                    }
                    if (!VecEqual(edPan.Scale, orPan.Scale))
                    {
                        curPatch.Scale = ToNullVec(edPan.Scale);
                    }
                    if (!VecEqual(edPan.Size, orPan.Size))
                    {
                        curPatch.Size = ToNullVec(edPan.Size);
                    }
                    if (edPan.Visible != orPan.Visible)
                    {
                        curPatch.Visible = edPan.Visible;
                    }

                    if (edPan.originX != orPan.originX)
                    {
                        curPatch.OriginX = (byte)edPan.originX;
                    }
                    if (edPan.originY != orPan.originY)
                    {
                        curPatch.OriginY = (byte)edPan.originY;
                    }
                    if (edPan.ParentOriginX != orPan.ParentOriginX)
                    {
                        curPatch.ParentOriginX = (byte)edPan.ParentOriginX;
                    }
                    if (edPan.ParentOriginY != orPan.ParentOriginY)
                    {
                        curPatch.ParentOriginY = (byte)edPan.ParentOriginY;
                    }

                    if (edPan is Pic1Pane && orPan is Pic1Pane)
                    {
                        var edPic = (Pic1Pane)edPan;
                        var orPic = (Pic1Pane)orPan;
                        if (edPic.ColorTopLeft != orPic.ColorTopLeft)
                        {
                            curPatch.PaneSpecific0 = edPic.ColorTopLeft.AsHexLEString();
                        }
                        if (edPic.ColorTopRight != orPic.ColorTopRight)
                        {
                            curPatch.PaneSpecific1 = edPic.ColorTopRight.AsHexLEString();
                        }
                        if (edPic.ColorBottomLeft != orPic.ColorBottomLeft)
                        {
                            curPatch.PaneSpecific2 = edPic.ColorBottomLeft.AsHexLEString();
                        }
                        if (edPic.ColorBottomRight != orPic.ColorBottomRight)
                        {
                            curPatch.PaneSpecific3 = edPic.ColorBottomRight.AsHexLEString();
                        }
                    }

                    if (edPan is Txt1Pane && orPan is Txt1Pane)
                    {
                        var edTxt = (Txt1Pane)edPan;
                        var orTxt = (Txt1Pane)orPan;
                        if (edTxt.FontTopColor != orTxt.FontTopColor)
                        {
                            curPatch.PaneSpecific0 = edTxt.FontTopColor.AsHexLEString();
                        }
                        if (edTxt.ShadowTopColor != orTxt.ShadowTopColor)
                        {
                            curPatch.PaneSpecific1 = edTxt.ShadowTopColor.AsHexLEString();
                        }
                        if (edTxt.FontBottomColor != orTxt.FontBottomColor)
                        {
                            curPatch.PaneSpecific2 = edTxt.FontBottomColor.AsHexLEString();
                        }
                        if (edTxt.ShadowBottomColor != orTxt.ShadowBottomColor)
                        {
                            curPatch.PaneSpecific3 = edTxt.ShadowBottomColor.AsHexLEString();
                        }
                    }
                    curFile.Add(curPatch);
                }

                List <ExtraGroup> extraGroups = new List <ExtraGroup>();
                string[]          ogPanes     = _or.EnumeratePanes(_or.RootGroup).Select(x => ((Grp1Pane)x).GroupName).ToArray();
                var edPanes = _ed.EnumeratePanes(_ed.RootGroup).Cast <Grp1Pane>();
                foreach (var p in edPanes)
                {
                    if (ogPanes.Contains(p.GroupName))
                    {
                        continue;
                    }
                    extraGroups.Add(new ExtraGroup()
                    {
                        GroupName = p.GroupName, Panes = p.Panes.ToArray()
                    });
                    hasAtLeastAnExtraGroup = true;
                }
                if (extraGroups.Count == 0)
                {
                    extraGroups = null;
                }

                List <MaterialPatch> materials = new List <MaterialPatch>();
                if (_ed.GetMat != null && _or.GetMat != null)
                {
                    var edMat = _ed.GetMat;
                    foreach (var orM in _or.GetMat.Materials)
                    {
                        var edM = edMat.Materials.Where(x => x.Name == orM.Name).FirstOrDefault();
                        if (edM == null)
                        {
                            continue;
                        }
                        if (edM.ForegroundColor == orM.ForegroundColor && edM.BackgroundColor == orM.BackgroundColor)
                        {
                            continue;
                        }
                        MaterialPatch m = new MaterialPatch()
                        {
                            MaterialName = orM.Name
                        };
                        if (edM.ForegroundColor != orM.ForegroundColor)
                        {
                            m.ForegroundColor = edM.ForegroundColor.AsHexLEString();
                        }
                        if (edM.BackgroundColor != orM.BackgroundColor)
                        {
                            m.BackgroundColor = edM.BackgroundColor.AsHexLEString();
                        }
                        materials.Add(m);
                    }
                }
                if (materials.Count == 0)
                {
                    materials = null;
                }

                if (curFile.Count > 0 || extraGroups?.Count > 0 || materials?.Count > 0)
                {
                    Patches.Add(new LayoutFilePatch()
                    {
                        FileName = f, Patches = curFile.ToArray(), Materials = materials?.ToArray(), AddGroups = extraGroups?.ToArray()
                    });
                }
            }
            if (Patches.Count == 0)             //animation edits depend on bflyt changes so this is relevant
            {
                throw new Exception("Couldn't find any difference");
            }

            string Message = null;

            List <AnimFilePatch> AnimPatches = new List <AnimFilePatch>();

            foreach (var f in original.Files.Keys.Where(x => x.EndsWith(".bflan")))
            {
                if (original.Files[f].SequenceEqual(edited.Files[f]))
                {
                    continue;
                }
                BflanFile anim = new BflanFile(edited.Files[f]);
                AnimPatches.Add(new AnimFilePatch()
                {
                    FileName = f, AnimJson = BflanSerializer.ToJson(anim)
                });
            }
            if (AnimPatches.Count == 0)
            {
                AnimPatches = null;
            }
            else if (!hasAtLeastAnExtraGroup)
            {
                Message = "This theme uses custom animations but doesn't have custom group in the layouts, this means that the nxtheme will work on the firmware it has been developed on but it may break on older or newer ones. It's *highly recommended* to create custom groups to handle animations";
            }

            var targetPatch = SzsPatcher.DetectSarc(original, DefaultTemplates.templates);

            return(new LayoutPatch()
            {
                PatchName = "diffPatch" + (targetPatch == null ? "" : " for " + targetPatch.TemplateName),
                TargetName = targetPatch?.szsName,
                AuthorName = "autoDiff",
                Files = Patches.ToArray(),
                Anims = AnimPatches?.ToArray(),
                ID = $"Generated_{Guid.NewGuid()}"
            }, Message);
        }
Ejemplo n.º 7
0
        private bool PatchLayouts(LayoutPatch Patch, string PartName)
        {
            var fw = FirmwareDetection.Detect(PartName, sarc);

            if (PartName == "home" && Patch.PatchAppletColorAttrib)
            {
                PatchBntxTextureAttribs(new Tuple <string, uint>("RdtIcoPvr_00^s", 0x5050505),
                                        new Tuple <string, uint>("RdtIcoNews_00^s", 0x5050505), new Tuple <string, uint>("RdtIcoNews_01^s", 0x5050505),
                                        new Tuple <string, uint>("RdtIcoSet^s", 0x5050505), new Tuple <string, uint>("RdtIcoShop^s", 0x5050505),
                                        new Tuple <string, uint>("RdtIcoCtrl_00^s", 0x5050505), new Tuple <string, uint>("RdtIcoCtrl_01^s", 0x5050505),
                                        new Tuple <string, uint>("RdtIcoCtrl_02^s", 0x5050505), new Tuple <string, uint>("RdtIcoPwrForm^s", 0x5050505));
            }

            List <LayoutFilePatch> Files = new List <LayoutFilePatch>();

            Files.AddRange(Patch.Files);

            LayoutFilePatch[] extra;
            //Legacy fixes based on name and version
            if (fw != FirmwareDetection.Firmware.Invariant && Patch.UsesOldFixes)
            {
                extra = NewFirmFixes.GetFixLegacy(Patch.PatchName, fw, PartName);
                if (extra != null)
                {
                    Files.AddRange(extra);
                }
            }
            //Modern fixes based on layout ID
            else if (Patch.ID != null)
            {
                extra = NewFirmFixes.GetFix(PartName, Patch.ID, fw);
                if (extra != null)
                {
                    Files.AddRange(extra);
                }
            }

            foreach (var p in Files)
            {
                var res = PatchSingleLayout(p);
                if (!res)
                {
                    return(res);
                }
            }

            List <AnimFilePatch> Anims = new List <AnimFilePatch>();

            if (Patch.Anims != null)
            {
                Anims.AddRange(Patch.Anims);
            }

            if (PartName == "home")
            {
                AnimFilePatch[] animExtra = null;
                if (Patch.HideOnlineBtn ?? true)
                {
                    animExtra = NewFirmFixes.GetNoOnlineButtonFix(fw);
                }
                else if (NewFirmFixes.ShouldApplyAppletPositionFix(Anims))
                {
                    animExtra = NewFirmFixes.GetAppletsPositionFix(fw);
                }

                if (animExtra != null)
                {
                    Anims.AddRange(animExtra);
                }
            }

            if (Anims.Any())
            {
                // The bflan version varies between firmwares, load a file from the list to detect the right one
                BflanFile b             = new BflanFile(sarc.Files[Anims[0].FileName]);
                var       TargetVersion = b.Version;
                b = null;

                foreach (var p in Anims)
                {
                    if (!sarc.Files.ContainsKey(p.FileName))
                    {
                        continue;
                    }

                    var n = BflanSerializer.FromJson(p.AnimJson);
                    n.Version              = TargetVersion;
                    n.byteOrder            = Syroot.BinaryData.ByteOrder.LittleEndian;
                    sarc.Files[p.FileName] = n.WriteFile();
                }
            }

            return(true);
        }
Ejemplo n.º 8
0
        public static (LayoutPatch, string) Diff(SarcData original, SarcData edited)
        {
            List <LayoutFilePatch> Patches = new List <LayoutFilePatch>();

            if (!ScrambledEquals <string>(original.Files.Keys, edited.Files.Keys))
            {
                throw new Exception("The provided archives don't have the same files");
            }

            bool hasAtLeastAnExtraGroup = false;             //Used to detect if animations are properly implemented

            foreach (var f in original.Files.Keys.Where(x => x.EndsWith(".bflyt")))
            {
                if (original.Files[f].SequenceEqual(edited.Files[f]))
                {
                    continue;
                }
                BflytFile _or = new BflytFile(original.Files[f]);
                BflytFile _ed = new BflytFile(edited.Files[f]);

                var curFile = DiffPanes(_or, _ed, f);

                var extraGroups = DiffGroups(_or, _ed);
                if (extraGroups != null)
                {
                    hasAtLeastAnExtraGroup = true;
                }

                var materials = DiffMaterials(_or, _ed, f);

                if (curFile.Count > 0 || extraGroups?.Count > 0 || materials?.Count > 0)
                {
                    Patches.Add(new LayoutFilePatch()
                    {
                        FileName = f, Patches = curFile.ToArray(), Materials = materials?.ToArray(), AddGroups = extraGroups?.ToArray()
                    });
                }
            }
            if (Patches.Count == 0)             //animation edits depend on bflyt changes so this is relevant
            {
                throw new Exception("Couldn't find any difference");
            }

            string Message = null;

            List <AnimFilePatch> AnimPatches = new List <AnimFilePatch>();

            foreach (var f in original.Files.Keys.Where(x => x.EndsWith(".bflan")))
            {
                if (original.Files[f].SequenceEqual(edited.Files[f]))
                {
                    continue;
                }
                BflanFile anim = new BflanFile(edited.Files[f]);
                AnimPatches.Add(new AnimFilePatch()
                {
                    FileName = f, AnimJson = BflanSerializer.ToJson(anim)
                });
            }
            if (AnimPatches.Count == 0)
            {
                AnimPatches = null;
            }
            else if (!hasAtLeastAnExtraGroup)
            {
                Message = "This theme uses custom animations but doesn't have custom group in the layouts, this means that the nxtheme will work on the firmware it has been developed on but it may break on older or newer ones. It's *highly recommended* to create custom groups to handle animations";
            }

            var targetPatch = SzsPatcher.DetectSarc(original, DefaultTemplates.templates);

            return(new LayoutPatch()
            {
                PatchName = "diffPatch" + (targetPatch == null ? "" : " for " + targetPatch.TemplateName),
                TargetName = targetPatch?.szsName,
                AuthorName = "autoDiff",
                Files = Patches.ToArray(),
                Anims = AnimPatches?.ToArray(),
                ID = $"Generated_{Guid.NewGuid()}"
            }, Message);
        }