public static HighlightIntro ReadHighlightIntro32(this BinaryReader br)
        {
            HighlightIntro intro = (HighlightIntro)br.ReadUInt32();

            //Debug.Assert(Enum.IsDefined(typeof(HighlightIntro), intro));
            return(intro);
        }
        public static HighlightIntro ReadHighlightIntro64(this BinaryReader br)
        {
            const ulong HighlightIntroMask = 0x0250000000000000ul;
            ulong       value = br.ReadUInt64();

            Debug.Assert((value & 0xFFFFFFFF00000000ul) == HighlightIntroMask || value == 0);
            HighlightIntro intro = (HighlightIntro)(value & 0xFFFFFFFFu);

            //Debug.Assert(Enum.IsDefined(typeof(HighlightIntro), intro));
            return(intro);
        }
Beispiel #3
0
 private static void TraceUnlocks(Hero hero, Skin skin, WeaponSkin weapon, HighlightIntro intro, Spray[] sprays = null, Emote[] emotes = null, VoiceLine[] voiceLines = null)
 {
     if (sprays != null)
     {
         foreach (var spray in sprays)
         {
             if (!IsDefined(spray))
             {
                 Tracer.TraceNoDupe("unlocks.sprays", $"{hero}_spray_{(int)spray:X8} = 0x{(int)spray:X8},");
             }
         }
     }
     if (voiceLines != null)
     {
         foreach (var voiceLine in voiceLines)
         {
             if (!IsDefined(voiceLine))
             {
                 Tracer.TraceNoDupe("unlocks.voiceLines", $"{hero}_voiceline_{(int)voiceLine:X8} = 0x{(int)voiceLine:X8},");
             }
         }
     }
     if (emotes != null)
     {
         foreach (var emote in emotes)
         {
             if (!IsDefined(emote))
             {
                 Tracer.TraceNoDupe("unlocks.emotes", $"{hero}_emote_{(int)emote:X8} = 0x{(int)emote:X8},");
             }
         }
     }
     if (!IsDefined(skin))
     {
         Tracer.TraceNoDupe("unlocks.skins", $"{hero}_skin_{(int)skin:X8} = 0x{(int)skin:X8},");
     }
     if (!IsDefined(intro))
     {
         Tracer.TraceNoDupe("unlocks.highlightIntros", $"{hero}_intro_{(int)intro:X8} = 0x{(int)intro:X8},");
     }
     if (!IsDefined(weapon))
     {
         if (IsDefined(skin))
         {
             Tracer.TraceNoDupe("unlocks.weaponskins", $"{skin}_weapon_{(int)weapon:X8} = 0x{(int)weapon:X8},");
         }
         else
         {
             Tracer.TraceNoDupe("unlocks.weaponskins", $"{hero}_skin_{(int)skin:X8}_weapon_{(int)weapon:X8} = 0x{(int)weapon:X8},");
         }
     }
 }
Beispiel #4
0
        public static void RunForHeroWithUnlocks(Hero hero, Skin skin, WeaponSkin weapon, HighlightIntro intro, Spray[] sprays = null, Emote[] emotes = null, VoiceLine[] voiceLines = null)
        {
            if (sprays != null)
            {
                foreach (var spray in sprays)
                {
                    if (IsDefined(spray))
                    {
                        Debug.Assert(spray.ToString().StartsWith($"{hero}_") || spray.ToString().StartsWith("Common_"), $"Spray {spray} should belong to '{hero}', maybe it's a Common spray?");
                        if (spray.ToString().StartsWith($"{hero}_spray_"))
                        {
                            Debug.Assert(spray.ToString() == $"{hero}_spray_{(int)spray:X8}");
                        }
                        else if (spray.ToString().StartsWith($"Common_spray_"))
                        {
                            Debug.Assert(spray.ToString() == $"Common_spray_{(int)spray:X8}");
                        }
                    }
                }
            }
            if (voiceLines != null)
            {
                foreach (var voiceLine in voiceLines)
                {
                    if (IsDefined(voiceLine))
                    {
                        Debug.Assert(voiceLine.ToString().StartsWith($"{hero}_"));
                        if (voiceLine.ToString().StartsWith($"{hero}_voiceline_"))
                        {
                            Debug.Assert(voiceLine.ToString() == $"{hero}_voiceline_{(int)voiceLine:X8}");
                        }
                    }
                }
            }
            if (emotes != null)
            {
                foreach (var emote in emotes)
                {
                    if (IsDefined(emote))
                    {
                        Debug.Assert(emote.ToString().StartsWith($"{hero}_"));
                        if (emote.ToString().StartsWith($"{hero}_emote_"))
                        {
                            Debug.Assert(emote.ToString() == $"{hero}_emote_{(int)emote:X8}");
                        }
                    }
                }
            }
            if (IsDefined(skin))
            {
                Debug.Assert(skin.ToString().StartsWith($"{hero}_"));
                if (skin.ToString().StartsWith($"{hero}_skin_"))
                {
                    Debug.Assert(skin.ToString() == $"{hero}_skin_{(int)skin:X8}");
                }
            }
            if (IsDefined(weapon))
            {
                Debug.Assert(weapon.ToString().StartsWith($"{hero}_"));
                if (weapon.ToString().StartsWith($"{hero}_skin_"))
                {
                    Debug.Assert(weapon.ToString() == $"{hero}_skin_{(int)skin:X8}_weapon_{(int)weapon:X8}");
                }
            }
            if (IsDefined(intro) && intro != HighlightIntro.None)
            {
                Debug.Assert(intro.ToString().StartsWith($"{hero}_"));
                if (intro.ToString().StartsWith($"{hero}_intro_"))
                {
                    Debug.Assert(intro.ToString() == $"{hero}_intro_{(int)intro:X8}");
                }
            }
            if (IsDefined(skin) && IsDefined(weapon))
            {
                Debug.Assert(weapon.ToString().StartsWith(skin.ToString()));
            }
            else if (IsDefined(skin) && !IsDefined(weapon))
            {
                Debug.Assert(false, $"Defined skin {skin} but corresponding weapon {(int)weapon:X8} is not defined");
            }
            else if (!IsDefined(skin) && IsDefined(weapon))
            {
                Debug.Assert(false, $"Defined weapon {weapon} but corresponding skin {(int)skin:X8} is not defined");
            }

            TraceUnlocks(hero, skin, weapon, intro, sprays, emotes, voiceLines);
        }
Beispiel #5
0
        public HighlightInfo(BinaryReader br, MajorVersion gameMajorVersion)
        {
            // player name of the highlight protagonist (will differ for other people's POTGs)
            this.playerName = br.ReadNullPaddedUTF8();

            // wheeeeeeee
            if (gameMajorVersion >= new MajorVersion(1, 16, VersionBranch.None))
            {
                byte unknown1 = br.ReadByte();
                Debug.Assert(unknown1 == 0);
            }

            // 1 for potg, 0 for top5 highlight, 4 for manual highlight
            this.typeFlags = (HighlightTypeFlag)br.ReadByte();
            Debug.Assert(Extensions.AreAllFlagsDefined(typeFlags));

            this.unknown2 = br.ReadUInt32();
            Debug.Assert((unknown2 & 0x80000000u) == 0x80000000u);
            Debug.Assert((unknown2 & 0x7FFFFFFFu) <= 0x0000FFFFu);

            this.unknown3 = br.ReadUInt32();
            Debug.Assert((unknown3 & 0x80000000u) == 0x80000000u);
            Debug.Assert((unknown3 & 0x7FFFFFFFu) <= 0x0000FFFFu);

            Debug.Assert(unknown3 >= unknown2);

            this.unknown4 = br.ReadSingle();
            Debug.Assert(!float.IsInfinity(unknown4) && !float.IsNaN(unknown4));

            this.unknown5 = br.ReadSingle();
            Debug.Assert(!float.IsInfinity(unknown5) && !float.IsNaN(unknown5));

            // seems to be nonzero if the player starts the highlight in the air - elevation?
            this.unknown6 = br.ReadUInt32();

            if (gameMajorVersion >= new MajorVersion(1, 17, VersionBranch.None))
            {
                // 0 for defense team, 1 for attack team. not sure how this handles oasis/nepal/ilios/lijiangtower yet
                this.unknown7 = br.ReadUInt32();
                Debug.Assert(unknown7 == 0 || unknown7 == 1 || unknown7 == 4);
            }

            this.highlightIntroPosition = br.ReadVec3();
            Debug.Assert(highlightIntroPosition.IsFinite());

            this.highlightIntroDirection = br.ReadVec3();
            Debug.Assert(highlightIntroDirection.IsFinite());
            Debug.Assert(highlightIntroDirection.IsUnitVector());

            this.upVector = br.ReadVec3();
            Debug.Assert(upVector.IsFinite());
            Debug.Assert(upVector.IsUnitVector());
            Debug.Assert(Math.Round(upVector.x) == 0);
            Debug.Assert(Math.Round(upVector.y) == 1);
            Debug.Assert(Math.Round(upVector.z) == 0);

            this.hero       = br.ReadHero64();
            this.skin       = br.ReadSkin64();
            this.weaponSkin = br.ReadWeaponSkin64();

            // at a hazy guess these might be to do with the new country-specific skins for the world cup?
            if (gameMajorVersion >= new MajorVersion(1, 17, VersionBranch.None))
            {
                this.unknown8 = br.ReadUInt64();
                Debug.Assert(unknown8 == 0);
                this.unknown9 = br.ReadUInt64();
                Debug.Assert(unknown9 == 0);
            }

            this.highlightIntro = br.ReadHighlightIntro64();

            this.category = br.ReadHighlightCategory64();

            this.timestamp = br.ReadUInt64();
            this.uuid      = new HighlightUUID(br);

            UnlockValidator.RunForHeroWithUnlocks(hero, skin, weaponSkin, highlightIntro);

            Debug.Assert(this.unknown3 >= this.unknown2);
        }
        public HeroWithUnlockables(BinaryReader br, MajorVersion gameMajorVersion)
        {
            this.skin       = br.ReadSkin32();
            this.weaponSkin = br.ReadWeaponSkin32();

            this.highlightIntro = br.ReadHighlightIntro32();

            int numSprays = br.ReadInt32();

            this.sprays = br.ReadSpray32s(numSprays);

            int numVoiceLines = br.ReadInt32();

            this.voiceLines = br.ReadVoiceLine32s(numVoiceLines);

            int numEmotes = br.ReadInt32();

            this.emotes = br.ReadEmote32s(numEmotes);

            // might be to do with team affiliation? seems to be either 0 or 1 depending on team - not sure about -1??
            if (gameMajorVersion >= new MajorVersion(1, 17, VersionBranch.None))
            {
                this.unknownInV17 = br.ReadInt32();
                Debug.Assert(unknownInV17 == -1 || unknownInV17 == 0 || unknownInV17 == 1 || unknownInV17 == 4);
            }

            this.hero = br.ReadHero64();

            // AI players in custom matches have no HighlightIntro, no unlocks, and always use classic skins
            // Bots in the Junkenstein/Uprising modes sometimes use non-classic skins.
            if (highlightIntro == HighlightIntro.None)
            {
                Debug.Assert(this.sprays.Length == 0);
                Debug.Assert(this.voiceLines.Length == 0);
                Debug.Assert(this.emotes.Length == 0);
                Debug.Assert(
                    ($"{skin}" == $"{hero}_Classic") ||
                    (hero == Hero.Junkrat && skin == Skin.Junkrat_DrJunkenstein) ||
                    (hero == Hero.Mercy && skin == Skin.Mercy_Witch) ||
                    (hero == Hero.Reaper && skin == Skin.Reaper_Dracula) ||
                    (hero == Hero.Roadhog && skin == Skin.Roadhog_JunkensteinsMonster) ||
                    (hero == Hero.Orisa && skin == Skin.Orisa_NullSector) ||
                    (hero == Hero.UprisingEvent_00000173 && skin == Skin.UprisingEvent_00000173_Classic) ||
                    (hero == Hero.UprisingEvent_00000178 && skin == Skin.UprisingEvent_00000178_Classic) ||
                    (hero == Hero.UprisingEvent_00000179 && skin == Skin.UprisingEvent_00000179_Classic) ||
                    (hero == Hero.RetributionEvent_000001AC && skin == Skin.RetributionEvent_000001AC_Classic) ||
                    (hero == Hero.RetributionEvent_000001B8 && skin == Skin.RetributionEvent_000001B8_Classic) ||
                    (hero == Hero.RetributionEvent_000001BA && skin == Skin.RetributionEvent_000001BA_Classic) ||
                    (hero == Hero.RetributionEvent_000001BB && skin == Skin.RetributionEvent_000001BB_Classic) ||
                    (hero == Hero.RetributionEvent_000001CE && skin == Skin.RetributionEvent_000001CE_Classic)
                    );
                Debug.Assert(
                    ($"{weaponSkin}" == $"{hero}_Classic") ||
                    (hero == Hero.Junkrat && weaponSkin == WeaponSkin.Junkrat_DrJunkenstein) ||
                    (hero == Hero.Mercy && weaponSkin == WeaponSkin.Mercy_Witch) ||
                    (hero == Hero.Reaper && weaponSkin == WeaponSkin.Reaper_Dracula) ||
                    (hero == Hero.Roadhog && weaponSkin == WeaponSkin.Roadhog_JunkensteinsMonster) ||
                    (hero == Hero.Orisa && weaponSkin == WeaponSkin.Orisa_NullSector) ||
                    (hero == Hero.UprisingEvent_00000173 && weaponSkin == WeaponSkin.UprisingEvent_00000173_Classic) ||
                    (hero == Hero.UprisingEvent_00000178 && weaponSkin == WeaponSkin.UprisingEvent_00000178_Classic) ||
                    (hero == Hero.UprisingEvent_00000179 && weaponSkin == WeaponSkin.UprisingEvent_00000179_Classic) ||
                    (hero == Hero.RetributionEvent_000001AC && weaponSkin == WeaponSkin.RetributionEvent_000001AC_Classic) ||
                    (hero == Hero.RetributionEvent_000001B8 && weaponSkin == WeaponSkin.RetributionEvent_000001B8_Classic) ||
                    (hero == Hero.RetributionEvent_000001BA && weaponSkin == WeaponSkin.RetributionEvent_000001BA_Classic) ||
                    (hero == Hero.RetributionEvent_000001BB && weaponSkin == WeaponSkin.RetributionEvent_000001BB_Classic) ||
                    (hero == Hero.RetributionEvent_000001CE && weaponSkin == WeaponSkin.RetributionEvent_000001CE_Classic)
                    );
            }

            // Ensure that unlocks are correctly mapped to heroes
            UnlockValidator.RunForHeroWithUnlocks(hero, skin, weaponSkin, highlightIntro, sprays, emotes, voiceLines);
        }