Esempio n. 1
0
 protected ActorStateProperty(ActorStateProperty copyFrom)
 {
     PropertyId     = copyFrom.PropertyId;
     PropertyName   = copyFrom.PropertyName;
     Data           = copyFrom.Data;
     _classNetCache = copyFrom._classNetCache;
 }
Esempio n. 2
0
        public static ActorStateProperty Deserialize(IClassNetCache classMap, string typeName, string[] objectIndexToName, UInt32 versionMajor, UInt32 versionMinor, BitReader br)
        {
            var asp = new ActorStateProperty();

            var maxPropId = classMap.MaxPropertyId;

            var className = objectIndexToName[classMap.ObjectIndex];

            asp.PropertyId = br.ReadUInt32Max(maxPropId + 1);
#if DEBUG
            asp.MaxPropertyId = (UInt32)maxPropId;
#endif
            asp.PropertyName = objectIndexToName[classMap.GetProperty((int)asp.PropertyId).Index];

            var startPosition = br.Position;

            asp.Data = new List <object>();

            switch (asp.PropertyName)
            {
            case "TAGame.GameEvent_TA:ReplicatedStateIndex":
                asp.Data.Add(br.ReadUInt32Max(140));     // number is made up, I dont know the max yet // TODO: Revisit this. It might work well enough, but looks fishy
                asp.MarkComplete();
                break;

            case "TAGame.RBActor_TA:ReplicatedRBState":
                asp.Data.Add(RigidBodyState.Deserialize(br));
                asp.MarkComplete();
                break;

            case "TAGame.CrowdActor_TA:ReplicatedOneShotSound":
            case "TAGame.CrowdManager_TA:ReplicatedGlobalOneShotSound":
            case "Engine.GameReplicationInfo:GameClass":
            case "TAGame.CrowdManager_TA:GameEvent":
            case "TAGame.CrowdActor_TA:GameEvent":
            case "TAGame.Team_TA:LogoData":
            case "TAGame.CameraSettingsActor_TA:PRI":
            case "TAGame.PRI_TA:PersistentCamera":
            case "TAGame.GameEvent_TA:MatchTypeClass":
            case "TAGame.GameEvent_Soccar_TA:SubRulesArchetype":
                // Theres a good chance that most of these can be moved to the next section
                asp.Data.Add(br.ReadBit());
                asp.Data.Add(br.ReadUInt32());
                asp.MarkComplete();
                break;

            case "TAGame.Team_TA:GameEvent":
            case "TAGame.Ball_TA:GameEvent":
            case "Engine.PlayerReplicationInfo:Team":
            case "Engine.Pawn:PlayerReplicationInfo":
            case "TAGame.PRI_TA:ReplicatedGameEvent":
            case "TAGame.CarComponent_TA:Vehicle":
            case "TAGame.Car_TA:AttachedPickup":
            case "TAGame.SpecialPickup_Targeted_TA:Targeted":
                // TODO: Use a real class so it can be accessed normally.
                // If Active == false, ActorId will be -1
                asp.Data.Add(ActiveActor.Deserialize(br));
                asp.MarkComplete();
                break;

            case "Engine.GameReplicationInfo:ServerName":
            case "Engine.PlayerReplicationInfo:PlayerName":
            case "TAGame.Team_TA:CustomTeamName":
            case "Engine.PlayerReplicationInfo:RemoteUserData":
            case "TAGame.GRI_TA:NewDedicatedServerIP":
                asp.Data.Add(br.ReadString());
                asp.MarkComplete();
                break;

            case "TAGame.GameEvent_Soccar_TA:SecondsRemaining":
            case "TAGame.GameEvent_TA:ReplicatedGameStateTimeRemaining":
            case "TAGame.CrowdActor_TA:ReplicatedCountDownNumber":
            case "TAGame.GameEvent_Team_TA:MaxTeamSize":
            case "Engine.PlayerReplicationInfo:PlayerID":
            case "TAGame.PRI_TA:TotalXP":
            case "TAGame.PRI_TA:MatchScore":
            case "TAGame.GameEvent_Soccar_TA:RoundNum":
            case "TAGame.GameEvent_TA:BotSkill":
            case "TAGame.PRI_TA:MatchShots":
            case "TAGame.PRI_TA:MatchSaves":
            case "ProjectX.GRI_X:ReplicatedGamePlaylist":
            case "Engine.TeamInfo:Score":
            case "Engine.PlayerReplicationInfo:Score":
            case "TAGame.PRI_TA:MatchGoals":
            case "TAGame.PRI_TA:MatchAssists":
            case "ProjectX.GRI_X:ReplicatedGameMutatorIndex":
            case "TAGame.PRI_TA:Title":
            case "TAGame.GameEvent_TA:ReplicatedStateName":
            case "TAGame.Team_Soccar_TA:GameScore":
            case "TAGame.GameEvent_Soccar_TA:GameTime":
            case "TAGame.CarComponent_Boost_TA:UnlimitedBoostRefCount":
            case "TAGame.CrowdActor_TA:ReplicatedRoundCountDownNumber":
                asp.Data.Add(br.ReadUInt32());
                asp.MarkComplete();
                break;

            case "TAGame.VehiclePickup_TA:ReplicatedPickupData":
                asp.Data.Add(br.ReadBit());
                asp.Data.Add(br.ReadUInt32());
                asp.Data.Add(br.ReadBit());

                asp.MarkComplete();
                break;

            case "Engine.PlayerReplicationInfo:Ping":
            case "TAGame.Vehicle_TA:ReplicatedSteer":
            case "TAGame.Vehicle_TA:ReplicatedThrottle":     // 0: full reverse, 128: No throttle.  255 full throttle/boosting
            case "TAGame.PRI_TA:CameraYaw":
            case "TAGame.PRI_TA:CameraPitch":
            case "TAGame.Ball_TA:HitTeamNum":
            case "TAGame.GameEvent_Soccar_TA:ReplicatedScoredOnTeam":
            case "TAGame.CarComponent_Boost_TA:ReplicatedBoostAmount":                     // Always 255?
            case "TAGame.CameraSettingsActor_TA:CameraPitch":
            case "TAGame.CameraSettingsActor_TA:CameraYaw":
            case "TAGame.PRI_TA:PawnType":
                asp.Data.Add(br.ReadByte());
                asp.MarkComplete();
                break;

            case "Engine.Actor:Location":
            case "TAGame.CarComponent_Dodge_TA:DodgeTorque":
                asp.Data.Add(Vector3D.Deserialize(br));
                asp.MarkComplete();
                break;

            case "Engine.Actor:bCollideWorld":
            case "Engine.PlayerReplicationInfo:bReadyToPlay":
            case "TAGame.Vehicle_TA:bReplicatedHandbrake":
            case "TAGame.Vehicle_TA:bDriving":
            case "Engine.Actor:bNetOwner":
            case "Engine.Actor:bBlockActors":
            case "TAGame.GameEvent_TA:bHasLeaveMatchPenalty":
            case "TAGame.PRI_TA:bUsingBehindView":
            case "TAGame.PRI_TA:bUsingSecondaryCamera":
            case "TAGame.GameEvent_TA:ActivatorCar":
            case "TAGame.GameEvent_Soccar_TA:bOverTime":
            case "ProjectX.GRI_X:bGameStarted":
            case "Engine.Actor:bCollideActors":
            case "TAGame.PRI_TA:bReady":
            case "TAGame.RBActor_TA:bFrozen":
            case "Engine.Actor:bHidden":
            case "TAGame.CarComponent_FlipCar_TA:bFlipRight":
            case "Engine.PlayerReplicationInfo:bBot":
            case "Engine.PlayerReplicationInfo:bWaitingPlayer":
            case "TAGame.RBActor_TA:bReplayActor":
            case "TAGame.PRI_TA:bIsInSplitScreen":
            case "Engine.GameReplicationInfo:bMatchIsOver":
            case "TAGame.CarComponent_Boost_TA:bUnlimitedBoost":
            case "Engine.PlayerReplicationInfo:bIsSpectator":
            case "TAGame.GameEvent_Soccar_TA:bBallHasBeenHit":
            case "TAGame.CameraSettingsActor_TA:bUsingSecondaryCamera":
            case "TAGame.CameraSettingsActor_TA:bUsingBehindView":
            case "TAGame.PRI_TA:bOnlineLoadoutSet":
            case "TAGame.PRI_TA:bMatchMVP":
            case "TAGame.PRI_TA:bOnlineLoadoutsSet":
            case "TAGame.RBActor_TA:bIgnoreSyncing":
            case "TAGame.SpecialPickup_BallVelcro_TA:bHit":
            case "TAGame.GameEvent_TA:bCanVoteToForfeit":
            case "TAGame.SpecialPickup_BallVelcro_TA:bBroken":
            case "TAGame.GameEvent_Team_TA:bForfeit":
                asp.Data.Add(br.ReadBit());
                asp.MarkComplete();
                break;

            case "TAGame.CarComponent_TA:ReplicatedActive":
                // The car component is active if (ReplicatedValue%2)!=0
                // For now I am only adding that logic to the JSON serializer
                asp.Data.Add(br.ReadByte());

                asp.MarkComplete();
                break;

            case "Engine.PlayerReplicationInfo:UniqueId":
                asp.Data.Add(UniqueId.Deserialize(br));
                asp.MarkComplete();
                break;

            case "TAGame.PRI_TA:PartyLeader":
                asp.Data.Add(PartyLeader.Deserialize(br));
                asp.MarkComplete();
                break;

            case "TAGame.PRI_TA:ClientLoadout":
                asp.Data.Add(ClientLoadout.Deserialize(br));
                asp.MarkComplete();
                break;

            case "TAGame.PRI_TA:CameraSettings":
            case "TAGame.CameraSettingsActor_TA:ProfileSettings":
                asp.Data.Add(CameraSettings.Deserialize(br));
                asp.MarkComplete();
                break;

            case "TAGame.Car_TA:TeamPaint":
                asp.Data.Add(TeamPaint.Deserialize(br));
                asp.MarkComplete();
                break;

            case "ProjectX.GRI_X:GameServerID":
                asp.Data.Add(br.ReadUInt32());
                asp.Data.Add(br.ReadUInt32());
                asp.MarkComplete();
                break;

            case "ProjectX.GRI_X:Reservations":
                asp.Data.Add(Reservation.Deserialize(versionMajor, versionMinor, br));
                asp.MarkComplete();
                break;

            case "TAGame.Ball_TA:ReplicatedExplosionData":
                asp.Data.Add(br.ReadBit());
                asp.Data.Add(br.ReadUInt32());
                asp.Data.Add(Vector3D.Deserialize(br));     // Almost definitely position
                asp.MarkComplete();
                break;

            case "TAGame.Car_TA:ReplicatedDemolish":
                asp.Data.Add(ReplicatedDemolish.Deserialize(br));
                asp.MarkComplete();
                break;

            case "TAGame.GameEvent_Soccar_TA:ReplicatedMusicStinger":
                asp.Data.Add(br.ReadBit());
                asp.Data.Add(br.ReadByte());
                asp.Data.Add(br.ReadUInt32());
                asp.MarkComplete();
                break;

            case "TAGame.CarComponent_FlipCar_TA:FlipCarTime":
            case "TAGame.Ball_TA:ReplicatedBallScale":
            case "TAGame.CarComponent_Boost_TA:RechargeDelay":
            case "TAGame.CarComponent_Boost_TA:RechargeRate":
            case "TAGame.Ball_TA:ReplicatedAddedCarBounceScale":
            case "TAGame.Ball_TA:ReplicatedBallMaxLinearSpeedScale":
            case "TAGame.Ball_TA:ReplicatedWorldBounceScale":
            case "TAGame.CarComponent_Boost_TA:BoostModifier":
            case "Engine.Actor:DrawScale":
            case "TAGame.CrowdActor_TA:ModifiedNoise":
            case "TAGame.CarComponent_TA:ReplicatedActivityTime":
            case "TAGame.SpecialPickup_BallFreeze_TA:RepOrigSpeed":
            case "TAGame.SpecialPickup_BallVelcro_TA:AttachTime":
            case "TAGame.SpecialPickup_BallVelcro_TA:BreakTime":
            case "TAGame.Car_TA:AddedCarForceMultiplier":
            case "TAGame.Car_TA:AddedBallForceMultiplier":
                asp.Data.Add(br.ReadFloat());
                asp.MarkComplete();
                break;

            case "TAGame.GameEvent_SoccarPrivate_TA:MatchSettings":
                asp.Data.Add(PrivateMatchSettings.Deserialize(br));
                asp.MarkComplete();
                break;

            case "TAGame.PRI_TA:ClientLoadoutOnline":
                asp.Data.Add(ClientLoadoutOnline.Deserialize(br));
                asp.MarkComplete();
                break;

            case "TAGame.GameEvent_TA:GameMode":
                if (versionMajor >= 868 && versionMinor >= 12)
                {
                    asp.Data.Add(br.ReadByte());
                }
                else
                {
                    asp.Data.Add(br.ReadUInt32Max(4));
                }
                asp.MarkComplete();
                break;

            case "TAGame.PRI_TA:ClientLoadoutsOnline":
                asp.Data.Add(ClientLoadoutsOnline.Deserialize(br));
                asp.MarkComplete();
                break;

            case "TAGame.PRI_TA:ClientLoadouts":
                asp.Data.Add(ClientLoadouts.Deserialize(br));
                asp.MarkComplete();
                break;

            case "TAGame.Team_TA:ClubColors":
            case "TAGame.Car_TA:ClubColors":
                asp.Data.Add(br.ReadBit());
                asp.Data.Add(br.ReadByte());
                asp.Data.Add(br.ReadBit());
                asp.Data.Add(br.ReadByte());
                asp.MarkComplete();
                break;

            case "TAGame.RBActor_TA:WeldedInfo":
                asp.Data.Add(WeldedInfo.Deserialize(br));
                asp.MarkComplete();
                break;

            default:
                throw new NotSupportedException(string.Format("Unknown property {0}. Next bits in the data are {1}. Figure it out!", asp.PropertyName, br.GetBits(br.Position, Math.Min(4096, br.Length - br.Position)).ToBinaryString()));
            }

#if DEBUG
            asp.KnownDataBits = br.GetBits(startPosition, br.Position - startPosition);
#endif
            return(asp);
        }
Esempio n. 3
0
        public static ActorStateProperty Deserialize(IClassNetCache classMap, string[] objectIndexToName, UInt32 engineVersion, UInt32 licenseeVersion, UInt32 netVersion, BitReader br)
        {
            var asp = new ActorStateProperty();

            asp._classNetCache = classMap;
            var maxPropId = classMap.MaxPropertyId;

            asp.PropertyId   = br.ReadUInt32Max(maxPropId + 1);
            asp.PropertyName = objectIndexToName[classMap.GetProperty((int)asp.PropertyId).Index];

            asp.Data = new List <object>();

            switch (asp.PropertyName)
            {
            case "TAGame.GameEvent_TA:ReplicatedStateIndex":
                asp.Data = br.ReadUInt32Max(140);     // number is made up, I dont know the max yet // TODO: Revisit this. It might work well enough, but looks fishy
                break;

            case "TAGame.RBActor_TA:ReplicatedRBState":
                asp.Data = RigidBodyState.Deserialize(br, netVersion);
                break;

            case "TAGame.Team_TA:LogoData":
                asp.Data = LogoData.Deserialize(br);
                break;

            case "TAGame.CrowdManager_TA:GameEvent":
            case "TAGame.CrowdActor_TA:GameEvent":
            case "TAGame.PRI_TA:PersistentCamera":
            case "TAGame.Team_TA:GameEvent":
            case "TAGame.Ball_TA:GameEvent":
            case "Engine.PlayerReplicationInfo:Team":
            case "Engine.Pawn:PlayerReplicationInfo":
            case "TAGame.PRI_TA:ReplicatedGameEvent":
            case "TAGame.CarComponent_TA:Vehicle":
            case "TAGame.Car_TA:AttachedPickup":
            case "TAGame.SpecialPickup_Targeted_TA:Targeted":
            case "TAGame.CameraSettingsActor_TA:PRI":
            case "TAGame.GameEvent_Soccar_TA:MVP":
            case "TAGame.GameEvent_Soccar_TA:MatchWinner":
            case "TAGame.GameEvent_Soccar_TA:GameWinner":
                asp.Data = ActiveActor.Deserialize(br);
                break;

            case "TAGame.CrowdManager_TA:ReplicatedGlobalOneShotSound":
            case "TAGame.CrowdActor_TA:ReplicatedOneShotSound":
            case "TAGame.GameEvent_TA:MatchTypeClass":
            case "Engine.GameReplicationInfo:GameClass":
            case "TAGame.GameEvent_Soccar_TA:SubRulesArchetype":
            case "TAGame.Ball_TA:ReplicatedPhysMatOverride":
                var objectTarget = ObjectTarget.Deserialize(br);
                asp.Data = objectTarget;
                ValidateObjectIndex(objectTarget.ObjectIndex, objectIndexToName);
                break;

            case "Engine.GameReplicationInfo:ServerName":
            case "Engine.PlayerReplicationInfo:PlayerName":
            case "TAGame.Team_TA:CustomTeamName":
            case "Engine.PlayerReplicationInfo:RemoteUserData":
            case "TAGame.GRI_TA:NewDedicatedServerIP":
            case "ProjectX.GRI_X:MatchGUID":
                asp.Data = br.ReadString();
                break;

            case "TAGame.GameEvent_Soccar_TA:SecondsRemaining":
            case "TAGame.GameEvent_TA:ReplicatedGameStateTimeRemaining":
            case "TAGame.CrowdActor_TA:ReplicatedCountDownNumber":
            case "TAGame.GameEvent_Team_TA:MaxTeamSize":
            case "Engine.PlayerReplicationInfo:PlayerID":
            case "TAGame.PRI_TA:TotalXP":
            case "TAGame.PRI_TA:MatchScore":
            case "TAGame.GameEvent_Soccar_TA:RoundNum":
            case "TAGame.GameEvent_TA:BotSkill":
            case "TAGame.PRI_TA:MatchShots":
            case "TAGame.PRI_TA:MatchSaves":
            case "ProjectX.GRI_X:ReplicatedGamePlaylist":
            case "Engine.TeamInfo:Score":
            case "Engine.PlayerReplicationInfo:Score":
            case "TAGame.PRI_TA:MatchGoals":
            case "TAGame.PRI_TA:MatchAssists":
            case "TAGame.PRI_TA:Title":
            case "TAGame.GameEvent_TA:ReplicatedStateName":
            case "TAGame.Team_Soccar_TA:GameScore":
            case "TAGame.GameEvent_Soccar_TA:GameTime":
            case "TAGame.CarComponent_Boost_TA:UnlimitedBoostRefCount":
            case "TAGame.CrowdActor_TA:ReplicatedRoundCountDownNumber":
            case "TAGame.Ball_Breakout_TA:DamageIndex":
            case "TAGame.PRI_TA:MatchBreakoutDamage":
            case "TAGame.PRI_TA:BotProductName":
            case "TAGame.GameEvent_TA:ReplicatedRoundCountDownNumber":
            case "TAGame.GameEvent_Soccar_TA:SeriesLength":
            case "TAGame.PRI_TA:SpectatorShortcut":
            case "Engine.Pawn:HealthMax":
                asp.Data = br.ReadUInt32();
                break;

            case "ProjectX.GRI_X:ReplicatedGameMutatorIndex":
            case "TAGame.PRI_TA:TimeTillItem":
            case "TAGame.PRI_TA:MaxTimeTillItem":
                asp.Data = br.ReadInt32();
                break;

            case "TAGame.VehiclePickup_TA:ReplicatedPickupData":
                asp.Data = ReplicatedPickupData.Deserialize(br);
                break;

            case "Engine.PlayerReplicationInfo:Ping":
            case "TAGame.Vehicle_TA:ReplicatedSteer":
            case "TAGame.Vehicle_TA:ReplicatedThrottle":     // 0: full reverse, 128: No throttle.  255 full throttle/boosting
            case "TAGame.PRI_TA:CameraYaw":
            case "TAGame.PRI_TA:CameraPitch":
            case "TAGame.Ball_TA:HitTeamNum":
            case "TAGame.GameEvent_Soccar_TA:ReplicatedScoredOnTeam":
            case "TAGame.CarComponent_Boost_TA:ReplicatedBoostAmount":
            case "TAGame.CameraSettingsActor_TA:CameraPitch":
            case "TAGame.CameraSettingsActor_TA:CameraYaw":
            case "TAGame.PRI_TA:PawnType":
            case "TAGame.Ball_Breakout_TA:LastTeamTouch":
            case "TAGame.Ball_Haunted_TA:LastTeamTouch":
            case "TAGame.PRI_TA:ReplicatedWorstNetQualityBeyondLatency":
            case "TAGame.GameEvent_Soccar_TA:ReplicatedServerPerformanceState":
            case "TAGame.Ball_Haunted_TA:TotalActiveBeams":
            case "TAGame.Ball_Haunted_TA:DeactivatedGoalIndex":
            case "TAGame.Ball_Haunted_TA:ReplicatedBeamBrokenValue":
                asp.Data = br.ReadByte();
                break;

            case "TAGame.PRI_TA:SkillTier":
                asp.Data = br.ReadUInt32Max(500);     // 9 bits. I picked a value that works, but could just be 1 bit + 1 byte instead of a single value.
                break;

            case "Engine.Actor:Location":
            case "TAGame.CarComponent_Dodge_TA:DodgeTorque":
                asp.Data = Vector3D.Deserialize(br, netVersion);
                break;

            case "Engine.Actor:bCollideWorld":
            case "Engine.PlayerReplicationInfo:bReadyToPlay":
            case "TAGame.Vehicle_TA:bReplicatedHandbrake":
            case "TAGame.Vehicle_TA:bDriving":
            case "Engine.Actor:bNetOwner":
            case "Engine.Actor:bBlockActors":
            case "TAGame.GameEvent_TA:bHasLeaveMatchPenalty":
            case "TAGame.PRI_TA:bUsingBehindView":
            case "TAGame.PRI_TA:bUsingSecondaryCamera":     // Ball cam on when true
            case "TAGame.GameEvent_TA:ActivatorCar":
            case "TAGame.GameEvent_Soccar_TA:bOverTime":
            case "ProjectX.GRI_X:bGameStarted":
            case "Engine.Actor:bCollideActors":
            case "TAGame.PRI_TA:bReady":
            case "TAGame.RBActor_TA:bFrozen":
            case "Engine.Actor:bHidden":
            case "TAGame.CarComponent_FlipCar_TA:bFlipRight":
            case "Engine.PlayerReplicationInfo:bBot":
            case "Engine.PlayerReplicationInfo:bWaitingPlayer":
            case "TAGame.RBActor_TA:bReplayActor":
            case "TAGame.PRI_TA:bIsInSplitScreen":
            case "Engine.GameReplicationInfo:bMatchIsOver":
            case "TAGame.CarComponent_Boost_TA:bUnlimitedBoost":
            case "Engine.PlayerReplicationInfo:bIsSpectator":
            case "TAGame.GameEvent_Soccar_TA:bBallHasBeenHit":
            case "TAGame.CameraSettingsActor_TA:bUsingSecondaryCamera":
            case "TAGame.CameraSettingsActor_TA:bUsingBehindView":
            case "TAGame.PRI_TA:bOnlineLoadoutSet":
            case "TAGame.PRI_TA:bMatchMVP":
            case "TAGame.PRI_TA:bOnlineLoadoutsSet":
            case "TAGame.RBActor_TA:bIgnoreSyncing":
            case "TAGame.SpecialPickup_BallVelcro_TA:bHit":
            case "TAGame.GameEvent_TA:bCanVoteToForfeit":
            case "TAGame.SpecialPickup_BallVelcro_TA:bBroken":
            case "TAGame.GameEvent_Team_TA:bForfeit":
            case "TAGame.PRI_TA:bUsingItems":
            case "TAGame.VehiclePickup_TA:bNoPickup":
            case "TAGame.CarComponent_Boost_TA:bNoBoost":
            case "TAGame.PRI_TA:PlayerHistoryValid":
            case "TAGame.GameEvent_Soccar_TA:bUnlimitedTime":
            case "TAGame.GameEvent_Soccar_TA:bClubMatch":
            case "TAGame.GameEvent_Soccar_TA:bMatchEnded":
            case "TAGame.GameEvent_TA:bAllowReadyUp":
            case "Engine.Actor:bTearOff":
            case "Engine.PlayerReplicationInfo:bTimedOut":
            case "TAGame.CameraSettingsActor_TA:bMouseCameraToggleEnabled":
            case "TAGame.CameraSettingsActor_TA:bUsingSwivel":
            case "TAGame.Ball_Haunted_TA:bIsBallBeamed":
            case "TAGame.SpecialPickup_Rugby_TA:bBallWelded":
                asp.Data = br.ReadBit();
                break;

            case "TAGame.CarComponent_TA:ReplicatedActive":
                // The car component is active if (ReplicatedValue%2)!=0
                // For now I am only adding that logic to the JSON serializer
                asp.Data = br.ReadByte();
                break;

            case "Engine.PlayerReplicationInfo:UniqueId":
                asp.Data = UniqueId.Deserialize(br, licenseeVersion, netVersion);
                break;

            case "TAGame.PRI_TA:PartyLeader":
                asp.Data = PartyLeader.Deserialize(br, licenseeVersion, netVersion);
                break;

            case "TAGame.PRI_TA:ClientLoadout":
                asp.Data = ClientLoadout.Deserialize(br);
                break;

            case "TAGame.PRI_TA:CameraSettings":
            case "TAGame.CameraSettingsActor_TA:ProfileSettings":
                asp.Data = CameraSettings.Deserialize(br, engineVersion, licenseeVersion);
                break;

            case "TAGame.Car_TA:TeamPaint":
                asp.Data = TeamPaint.Deserialize(br);
                break;

            case "ProjectX.GRI_X:GameServerID":
                asp.Data = br.ReadBytes(8);
                break;

            case "ProjectX.GRI_X:Reservations":
                asp.Data = Reservation.Deserialize(engineVersion, licenseeVersion, netVersion, br);
                break;

            case "TAGame.Car_TA:ReplicatedDemolish":
                asp.Data = ReplicatedDemolish.Deserialize(br, netVersion);
                break;

            case "TAGame.GameEvent_Soccar_TA:ReplicatedMusicStinger":
                asp.Data = ReplicatedMusicStinger.Deserialize(br);
                break;

            case "TAGame.CarComponent_FlipCar_TA:FlipCarTime":
            case "TAGame.Ball_TA:ReplicatedBallScale":
            case "TAGame.CarComponent_Boost_TA:RechargeDelay":
            case "TAGame.CarComponent_Boost_TA:RechargeRate":
            case "TAGame.Ball_TA:ReplicatedAddedCarBounceScale":
            case "TAGame.Ball_TA:ReplicatedBallMaxLinearSpeedScale":
            case "TAGame.Ball_TA:ReplicatedWorldBounceScale":
            case "TAGame.CarComponent_Boost_TA:BoostModifier":
            case "Engine.Actor:DrawScale":
            case "TAGame.CrowdActor_TA:ModifiedNoise":
            case "TAGame.CarComponent_TA:ReplicatedActivityTime":
            case "TAGame.SpecialPickup_BallFreeze_TA:RepOrigSpeed":
            case "TAGame.SpecialPickup_BallVelcro_TA:AttachTime":
            case "TAGame.SpecialPickup_BallVelcro_TA:BreakTime":
            case "TAGame.Car_TA:AddedCarForceMultiplier":
            case "TAGame.Car_TA:AddedBallForceMultiplier":
            case "TAGame.PRI_TA:SteeringSensitivity":
            case "TAGame.Car_TA:ReplicatedCarScale":
            case "Engine.WorldInfo:WorldGravityZ":
            case "Engine.WorldInfo:TimeDilation":
                asp.Data = br.ReadFloat();
                break;

            case "TAGame.GameEvent_SoccarPrivate_TA:MatchSettings":
                asp.Data = PrivateMatchSettings.Deserialize(br);
                break;

            case "TAGame.PRI_TA:ClientLoadoutOnline":
                asp.Data = ClientLoadoutOnline.Deserialize(br, engineVersion, licenseeVersion, objectIndexToName);
                break;

            case "TAGame.GameEvent_TA:GameMode":
                if (engineVersion >= 868 && licenseeVersion >= 12)
                {
                    asp.Data = br.ReadByte();
                }
                else
                {
                    asp.Data = br.ReadUInt32Max(4);
                }
                break;

            case "TAGame.PRI_TA:ClientLoadoutsOnline":
                asp.Data = ClientLoadoutsOnline.Deserialize(br, engineVersion, licenseeVersion, objectIndexToName);
                break;

            case "TAGame.PRI_TA:ClientLoadouts":
                asp.Data = ClientLoadouts.Deserialize(br);
                break;

            case "TAGame.Team_TA:ClubColors":
            case "TAGame.Car_TA:ClubColors":
                asp.Data = ClubColors.Deserialize(br);
                break;

            case "TAGame.RBActor_TA:WeldedInfo":
                asp.Data = WeldedInfo.Deserialize(br, netVersion);
                break;

            case "TAGame.BreakOutActor_Platform_TA:DamageState":
                asp.Data = DamageState.Deserialize(br, netVersion);
                break;

            case "TAGame.Ball_Breakout_TA:AppliedDamage":
                asp.Data = AppliedDamage.Deserialize(br, netVersion);
                break;

            case "TAGame.Ball_TA:ReplicatedExplosionData":
                asp.Data = ReplicatedExplosionData.Deserialize(br, netVersion);
                break;

            case "TAGame.Ball_TA:ReplicatedExplosionDataExtended":
                asp.Data = ReplicatedExplosionDataExtended.Deserialize(br, netVersion);
                break;

            case "TAGame.PRI_TA:SecondaryTitle":
            case "TAGame.PRI_TA:PrimaryTitle":
                asp.Data = Title.Deserialize(br);
                break;

            case "TAGame.PRI_TA:PlayerHistoryKey":
                // Betting ReadUInt32Max is more likely, since 14 bits is a weird number
                asp.Data = br.ReadUInt32FromBits(14);
                break;

            case "TAGame.GameEvent_Soccar_TA:ReplicatedStatEvent":
                asp.Data = ReplicatedStatEvent.Deserialize(br);
                break;

            case "TAGame.Team_TA:ClubID":
            case "TAGame.PRI_TA:ClubID":
                asp.Data = br.ReadUInt64();
                break;

            case "TAGame.PRI_TA:RepStatTitles":
                asp.Data = RepStatTitle.Deserialize(br);
                break;

            case "TAGame.VehiclePickup_TA:NewReplicatedPickupData":
                asp.Data = NewReplicatedPickupData.Deserialize(br);
                break;

            default:
                throw new NotSupportedException(string.Format("Unknown property {0}. Next bits in the data are {1}. Figure it out!", asp.PropertyName, br.GetBits(br.Position, Math.Min(4096, br.Length - br.Position)).ToBinaryString()));
            }

            return(asp);
        }
        public static ActorStateProperty Deserialize(IClassNetCache classMap, string[] objectIndexToName, BitReader br)
        {
            var asp = new ActorStateProperty();

            var maxPropId = classMap.MaxPropertyId;

            var className = objectIndexToName[classMap.ObjectIndex];

            asp.PropertyId = br.ReadInt32Max(maxPropId + 1);
#if DEBUG
            asp.MaxPropertyId = maxPropId;
#endif
            asp.PropertyName = objectIndexToName[classMap.GetProperty(asp.PropertyId).Index];

            var startPosition = br.Position;

            asp.Data = new List <object>();

            switch (asp.PropertyName)
            {
            case "TAGame.GameEvent_TA:ReplicatedStateIndex":
                asp.Data.Add(br.ReadInt32Max(140));     // number is made up, I dont know the max yet // TODO: Revisit this. It might work well enough, but looks fishy
                asp.MarkComplete();
                break;

            case "TAGame.RBActor_TA:ReplicatedRBState":
                asp.Data.Add(RigidBodyState.Deserialize(br));
                asp.MarkComplete();
                break;

            case "TAGame.Team_TA:GameEvent":
            case "TAGame.CrowdActor_TA:ReplicatedOneShotSound":
            case "TAGame.CrowdManager_TA:ReplicatedGlobalOneShotSound":
            case "Engine.Actor:Owner":
            case "Engine.GameReplicationInfo:GameClass":
            case "Engine.PlayerReplicationInfo:Team":
            case "TAGame.CrowdManager_TA:GameEvent":
            case "Engine.Pawn:PlayerReplicationInfo":     // Actor Id. Ties cars to players
            case "TAGame.PRI_TA:ReplicatedGameEvent":
            case "TAGame.Ball_TA:GameEvent":
            case "TAGame.CrowdActor_TA:GameEvent":
            case "TAGame.Team_TA:LogoData":
                asp.Data.Add(br.ReadBit());
                asp.Data.Add(br.ReadInt32());
                asp.MarkComplete();
                break;

            case "TAGame.CarComponent_TA:Vehicle":
                asp.Data.Add(br.ReadBit());
                asp.Data.Add(br.ReadInt32());
                asp.MarkComplete();
                break;

            case "Engine.GameReplicationInfo:ServerName":
            case "Engine.PlayerReplicationInfo:PlayerName":
            case "TAGame.Team_TA:CustomTeamName":
                asp.Data.Add(br.ReadString());
                asp.MarkComplete();
                break;

            case "TAGame.GameEvent_Soccar_TA:SecondsRemaining":
            case "TAGame.GameEvent_TA:ReplicatedGameStateTimeRemaining":
            case "TAGame.CrowdActor_TA:ReplicatedCountDownNumber":
            case "TAGame.GameEvent_Team_TA:MaxTeamSize":
            case "Engine.PlayerReplicationInfo:PlayerID":
            case "TAGame.PRI_TA:TotalXP":
            case "TAGame.PRI_TA:MatchScore":
            case "TAGame.GameEvent_Soccar_TA:RoundNum":
            case "TAGame.GameEvent_TA:BotSkill":
            case "TAGame.PRI_TA:MatchShots":
            case "TAGame.PRI_TA:MatchSaves":
            case "ProjectX.GRI_X:ReplicatedGamePlaylist":
            case "Engine.TeamInfo:Score":
            case "Engine.PlayerReplicationInfo:Score":
            case "TAGame.PRI_TA:MatchGoals":
            case "TAGame.PRI_TA:MatchAssists":
            case "ProjectX.GRI_X:ReplicatedGameMutatorIndex":
            case "TAGame.PRI_TA:Title":
                asp.Data.Add(br.ReadInt32());
                asp.MarkComplete();
                break;

            case "TAGame.VehiclePickup_TA:ReplicatedPickupData":
                // 1011101000000000000000000000000001
                // 0111111111111111111111111111111110
                // 1111001000000000000000000000000001
                // 1000001000000000000000000000000001
                // 1111110000000000000000000000000001
                // 1101110000000000000000000000000001

                // reverify the above data, especially the short stuff
                asp.Data.Add(br.ReadBit());
                asp.Data.Add(br.ReadInt32());
                asp.Data.Add(br.ReadBit());

                asp.MarkComplete();
                break;

            case "Engine.PlayerReplicationInfo:Ping":
            case "TAGame.Vehicle_TA:ReplicatedSteer":
            case "TAGame.Vehicle_TA:ReplicatedThrottle":     // 0: full reverse, 128: No throttle.  255 full throttle/boosting
            case "TAGame.PRI_TA:CameraYaw":
            case "TAGame.PRI_TA:CameraPitch":
            case "TAGame.Ball_TA:HitTeamNum":
            case "TAGame.GameEvent_Soccar_TA:ReplicatedScoredOnTeam":
            case "TAGame.CarComponent_Boost_TA:ReplicatedBoostAmount":                     // Always 255?
                asp.Data.Add(br.ReadByte());
                asp.MarkComplete();
                break;

            case "Engine.Actor:Location":
            case "TAGame.CarComponent_Dodge_TA:DodgeTorque":
                asp.Data.Add(Vector3D.Deserialize(br));
                asp.MarkComplete();
                break;

            case "Engine.Actor:bCollideWorld":
            case "Engine.PlayerReplicationInfo:bReadyToPlay":
            case "TAGame.Vehicle_TA:bReplicatedHandbrake":
            case "TAGame.Vehicle_TA:bDriving":
            case "Engine.Actor:bNetOwner":
            case "Engine.Actor:bBlockActors":
            case "TAGame.GameEvent_TA:bHasLeaveMatchPenalty":
            case "TAGame.PRI_TA:bUsingBehindView":
            case "TAGame.PRI_TA:bUsingSecondaryCamera":
            case "TAGame.GameEvent_TA:ActivatorCar":
            case "TAGame.GameEvent_Soccar_TA:bOverTime":
            case "ProjectX.GRI_X:bGameStarted":
            case "Engine.Actor:bCollideActors":
            case "TAGame.PRI_TA:bReady":
            case "TAGame.RBActor_TA:bFrozen":
            case "Engine.Actor:bHidden":
            case "TAGame.CarComponent_FlipCar_TA:bFlipRight":
            case "Engine.PlayerReplicationInfo:bBot":
            case "Engine.PlayerReplicationInfo:bWaitingPlayer":
            case "TAGame.RBActor_TA:bReplayActor":
            case "TAGame.PRI_TA:bIsInSplitScreen":
            case "Engine.GameReplicationInfo:bMatchIsOver":
            case "TAGame.CarComponent_Boost_TA:bUnlimitedBoost":
            case "Engine.PlayerReplicationInfo:bIsSpectator":
            case "TAGame.GameEvent_Soccar_TA:bBallHasBeenHit":
                asp.Data.Add(br.ReadBit());
                asp.MarkComplete();
                break;

            case "TAGame.CarComponent_TA:ReplicatedActive":
                // The car component is active if (ReplicatedValue%2)!=0
                // For now I am only adding that logic to the JSON serializer
                asp.Data.Add(br.ReadByte());

                asp.MarkComplete();
                break;

            case "Engine.PlayerReplicationInfo:UniqueId":
            case "TAGame.PRI_TA:PartyLeader":
                asp.Data.Add(UniqueId.Deserialize(br));
                asp.MarkComplete();
                break;

            case "TAGame.PRI_TA:ClientLoadout":
                asp.Data.Add(ClientLoadout.Deserialize(br));
                asp.MarkComplete();
                break;

            case "TAGame.PRI_TA:CameraSettings":
                asp.Data.Add(CameraSettings.Deserialize(br));
                asp.MarkComplete();
                break;

            case "TAGame.Car_TA:TeamPaint":
                asp.Data.Add(TeamPaint.Deserialize(br));
                asp.MarkComplete();
                break;

            case "ProjectX.GRI_X:GameServerID":
                asp.Data.Add(br.ReadInt32());
                asp.Data.Add(br.ReadInt32());
                asp.MarkComplete();
                break;

            case "ProjectX.GRI_X:Reservations":
                asp.Data.Add(Reservation.Deserialize(br));
                asp.MarkComplete();
                break;

            case "TAGame.Ball_TA:ReplicatedExplosionData":
                // 0 01010111000000000000000000000000 0011 01010010000001 01111010001011 00000110000001
                // 0 01110111000000000000000000000000 0011 10011110010001 11111010001011 01010110000001
                // 0 11010111000000000000000000000000 0011 00001111011110 11000110001011 10111010000001
                // 0 11010111000000000000000000000000 0011 10011000100001 00100110001011 10111010000001
                // 0 00110111000000000000000000000000 0011 00000001010001 11000110001011 00100110000001
                asp.Data.Add(br.ReadBit());
                asp.Data.Add(br.ReadInt32());
                asp.Data.Add(Vector3D.Deserialize(br));     // Almost definitely position
                asp.MarkComplete();
                break;

            case "TAGame.Car_TA:ReplicatedDemolish":
                asp.Data.Add(ReplicatedDemolish.Deserialize(br));
                asp.MarkComplete();
                break;

            case "TAGame.GameEvent_Soccar_TA:ReplicatedMusicStinger":
                asp.Data.Add(br.ReadBit());
                asp.Data.Add(br.ReadByte());
                asp.Data.Add(br.ReadInt32());
                asp.MarkComplete();
                break;

            case "TAGame.CarComponent_FlipCar_TA:FlipCarTime":
            case "TAGame.Ball_TA:ReplicatedBallScale":
            case "TAGame.CarComponent_Boost_TA:RechargeDelay":
            case "TAGame.CarComponent_Boost_TA:RechargeRate":
            case "TAGame.Ball_TA:ReplicatedAddedCarBounceScale":
            case "TAGame.Ball_TA:ReplicatedBallMaxLinearSpeedScale":
            case "TAGame.Ball_TA:ReplicatedWorldBounceScale":
            case "TAGame.CarComponent_Boost_TA:BoostModifier":
            case "Engine.Actor:DrawScale":
            case "TAGame.CrowdActor_TA:ModifiedNoise":
                asp.Data.Add(br.ReadFloat());
                asp.MarkComplete();
                break;

            case "TAGame.GameEvent_SoccarPrivate_TA:MatchSettings":
                asp.Data.Add(PrivateMatchSettings.Deserialize(br));
                asp.MarkComplete();
                break;

            case "TAGame.PRI_TA:ClientLoadoutOnline":
                asp.Data.Add(br.ReadInt32());
                asp.Data.Add(br.ReadInt32());
                asp.Data.Add(br.ReadInt32());
                asp.MarkComplete();
                break;

            default:
                throw new NotSupportedException(string.Format("Unknown property {0}. Next bits in the data are {1}. Figure it out!", asp.PropertyName, br.GetBits(br.Position, Math.Min(4096, br.Length - br.Position)).ToBinaryString()));
            }

#if DEBUG
            asp.KnownDataBits = br.GetBits(startPosition, br.Position - startPosition);
#endif
            return(asp);
        }
        public static ActorStateProperty Deserialize(IClassNetCache classMap, string typeName, string[] objectIndexToName, UInt32 versionMajor, UInt32 versionMinor, BitReader br)
        {
            var asp = new ActorStateProperty();

            var maxPropId = classMap.MaxPropertyId;

            var className = objectIndexToName[classMap.ObjectIndex];
            asp.PropertyId = br.ReadUInt32Max(maxPropId + 1);
            #if DEBUG
            asp.MaxPropertyId = (UInt32)maxPropId;
            #endif
            asp.PropertyName = objectIndexToName[classMap.GetProperty((int)asp.PropertyId).Index];

            var startPosition = br.Position;

            asp.Data = new List<object>();

            switch (asp.PropertyName)
            {
                case "TAGame.GameEvent_TA:ReplicatedStateIndex":
                    asp.Data.Add(br.ReadUInt32Max(140)); // number is made up, I dont know the max yet // TODO: Revisit this. It might work well enough, but looks fishy
                    asp.MarkComplete();
                    break;
                case "TAGame.RBActor_TA:ReplicatedRBState":
                    asp.Data.Add(RigidBodyState.Deserialize(br));
                    asp.MarkComplete();
                    break;
                case "TAGame.CrowdActor_TA:ReplicatedOneShotSound":
                case "TAGame.CrowdManager_TA:ReplicatedGlobalOneShotSound":
                case "Engine.GameReplicationInfo:GameClass":
                case "TAGame.CrowdManager_TA:GameEvent":
                case "TAGame.CrowdActor_TA:GameEvent":
                case "TAGame.Team_TA:LogoData":
                case "TAGame.CameraSettingsActor_TA:PRI":
                case "TAGame.PRI_TA:PersistentCamera":
                case "TAGame.GameEvent_TA:MatchTypeClass":
                case "TAGame.GameEvent_Soccar_TA:SubRulesArchetype":
                    // Theres a good chance that most of these can be moved to the next section
                    asp.Data.Add(br.ReadBit());
                    asp.Data.Add(br.ReadUInt32());
                    asp.MarkComplete();
                    break;
                case "TAGame.Team_TA:GameEvent":
                case "TAGame.Ball_TA:GameEvent":
                case "Engine.PlayerReplicationInfo:Team":
                case "Engine.Pawn:PlayerReplicationInfo":
                case "TAGame.PRI_TA:ReplicatedGameEvent":
                case "TAGame.CarComponent_TA:Vehicle":
                case "TAGame.Car_TA:AttachedPickup":
                case "TAGame.SpecialPickup_Targeted_TA:Targeted":
                    // TODO: Use a real class so it can be accessed normally.
                    // If Active == false, ActorId will be -1
                    asp.Data.Add(ActiveActor.Deserialize(br));
                    asp.MarkComplete();
                    break;
                case "Engine.GameReplicationInfo:ServerName":
                case "Engine.PlayerReplicationInfo:PlayerName":
                case "TAGame.Team_TA:CustomTeamName":
                case "Engine.PlayerReplicationInfo:RemoteUserData":
                case "TAGame.GRI_TA:NewDedicatedServerIP":
                    asp.Data.Add(br.ReadString());
                    asp.MarkComplete();
                    break;
                case "TAGame.GameEvent_Soccar_TA:SecondsRemaining":
                case "TAGame.GameEvent_TA:ReplicatedGameStateTimeRemaining":
                case "TAGame.CrowdActor_TA:ReplicatedCountDownNumber":
                case "TAGame.GameEvent_Team_TA:MaxTeamSize":
                case "Engine.PlayerReplicationInfo:PlayerID":
                case "TAGame.PRI_TA:TotalXP":
                case "TAGame.PRI_TA:MatchScore":
                case "TAGame.GameEvent_Soccar_TA:RoundNum":
                case "TAGame.GameEvent_TA:BotSkill":
                case "TAGame.PRI_TA:MatchShots":
                case "TAGame.PRI_TA:MatchSaves":
                case "ProjectX.GRI_X:ReplicatedGamePlaylist":
                case "Engine.TeamInfo:Score":
                case "Engine.PlayerReplicationInfo:Score":
                case "TAGame.PRI_TA:MatchGoals":
                case "TAGame.PRI_TA:MatchAssists":
                case "ProjectX.GRI_X:ReplicatedGameMutatorIndex":
                case "TAGame.PRI_TA:Title":
                case "TAGame.GameEvent_TA:ReplicatedStateName":
                case "TAGame.Team_Soccar_TA:GameScore":
                case "TAGame.GameEvent_Soccar_TA:GameTime":
                case "TAGame.CarComponent_Boost_TA:UnlimitedBoostRefCount":
                case "TAGame.CrowdActor_TA:ReplicatedRoundCountDownNumber":
                    asp.Data.Add(br.ReadUInt32());
                    asp.MarkComplete();
                    break;
                case "TAGame.VehiclePickup_TA:ReplicatedPickupData":
                    asp.Data.Add(br.ReadBit());
                    asp.Data.Add(br.ReadUInt32());
                    asp.Data.Add(br.ReadBit());

                    asp.MarkComplete();
                    break;
                case "Engine.PlayerReplicationInfo:Ping":
                case "TAGame.Vehicle_TA:ReplicatedSteer":
                case "TAGame.Vehicle_TA:ReplicatedThrottle": // 0: full reverse, 128: No throttle.  255 full throttle/boosting
                case "TAGame.PRI_TA:CameraYaw":
                case "TAGame.PRI_TA:CameraPitch":
                case "TAGame.Ball_TA:HitTeamNum":
                case "TAGame.GameEvent_Soccar_TA:ReplicatedScoredOnTeam":
                case "TAGame.CarComponent_Boost_TA:ReplicatedBoostAmount": // Always 255?
                case "TAGame.CameraSettingsActor_TA:CameraPitch":
                case "TAGame.CameraSettingsActor_TA:CameraYaw":
                case "TAGame.PRI_TA:PawnType":
                    asp.Data.Add(br.ReadByte());
                    asp.MarkComplete();
                    break;
                case "Engine.Actor:Location":
                case "TAGame.CarComponent_Dodge_TA:DodgeTorque":
                    asp.Data.Add(Vector3D.Deserialize(br));
                    asp.MarkComplete();
                    break;

                case "Engine.Actor:bCollideWorld":
                case "Engine.PlayerReplicationInfo:bReadyToPlay":
                case "TAGame.Vehicle_TA:bReplicatedHandbrake":
                case "TAGame.Vehicle_TA:bDriving":
                case "Engine.Actor:bNetOwner":
                case "Engine.Actor:bBlockActors":
                case "TAGame.GameEvent_TA:bHasLeaveMatchPenalty":
                case "TAGame.PRI_TA:bUsingBehindView":
                case "TAGame.PRI_TA:bUsingSecondaryCamera":
                case "TAGame.GameEvent_TA:ActivatorCar":
                case "TAGame.GameEvent_Soccar_TA:bOverTime":
                case "ProjectX.GRI_X:bGameStarted":
                case "Engine.Actor:bCollideActors":
                case "TAGame.PRI_TA:bReady":
                case "TAGame.RBActor_TA:bFrozen":
                case "Engine.Actor:bHidden":
                case "TAGame.CarComponent_FlipCar_TA:bFlipRight":
                case "Engine.PlayerReplicationInfo:bBot":
                case "Engine.PlayerReplicationInfo:bWaitingPlayer":
                case "TAGame.RBActor_TA:bReplayActor":
                case "TAGame.PRI_TA:bIsInSplitScreen":
                case "Engine.GameReplicationInfo:bMatchIsOver":
                case "TAGame.CarComponent_Boost_TA:bUnlimitedBoost":
                case "Engine.PlayerReplicationInfo:bIsSpectator":
                case "TAGame.GameEvent_Soccar_TA:bBallHasBeenHit":
                case "TAGame.CameraSettingsActor_TA:bUsingSecondaryCamera":
                case "TAGame.CameraSettingsActor_TA:bUsingBehindView":
                case "TAGame.PRI_TA:bOnlineLoadoutSet":
                case "TAGame.PRI_TA:bMatchMVP":
                case "TAGame.PRI_TA:bOnlineLoadoutsSet":
                case "TAGame.RBActor_TA:bIgnoreSyncing":
                case "TAGame.SpecialPickup_BallVelcro_TA:bHit":
                case "TAGame.GameEvent_TA:bCanVoteToForfeit":
                case "TAGame.SpecialPickup_BallVelcro_TA:bBroken":
                case "TAGame.GameEvent_Team_TA:bForfeit":
                    asp.Data.Add(br.ReadBit());
                    asp.MarkComplete();
                    break;
                case "TAGame.CarComponent_TA:ReplicatedActive":
                    // The car component is active if (ReplicatedValue%2)!=0
                    // For now I am only adding that logic to the JSON serializer
                    asp.Data.Add(br.ReadByte());

                    asp.MarkComplete();
                    break;
                case "Engine.PlayerReplicationInfo:UniqueId":
                    asp.Data.Add(UniqueId.Deserialize(br));
                    asp.MarkComplete();
                    break;
                case "TAGame.PRI_TA:PartyLeader":
                    asp.Data.Add(PartyLeader.Deserialize(br));
                    asp.MarkComplete();
                    break;
                case "TAGame.PRI_TA:ClientLoadout":
                    asp.Data.Add(ClientLoadout.Deserialize(br));
                    asp.MarkComplete();
                    break;
                case "TAGame.PRI_TA:CameraSettings":
                case "TAGame.CameraSettingsActor_TA:ProfileSettings":
                    asp.Data.Add(CameraSettings.Deserialize(br));
                    asp.MarkComplete();
                    break;
                case "TAGame.Car_TA:TeamPaint":
                    asp.Data.Add(TeamPaint.Deserialize(br));
                    asp.MarkComplete();
                    break;
                case "ProjectX.GRI_X:GameServerID":
                    asp.Data.Add(br.ReadUInt32());
                    asp.Data.Add(br.ReadUInt32());
                    asp.MarkComplete();
                    break;
                case "ProjectX.GRI_X:Reservations":
                    asp.Data.Add(Reservation.Deserialize(versionMajor, versionMinor, br));
                    asp.MarkComplete();
                    break;
                case "TAGame.Ball_TA:ReplicatedExplosionData":
                    asp.Data.Add(br.ReadBit());
                    asp.Data.Add(br.ReadUInt32());
                    asp.Data.Add(Vector3D.Deserialize(br)); // Almost definitely position
                    asp.MarkComplete();
                    break;
                case "TAGame.Car_TA:ReplicatedDemolish":
                    asp.Data.Add(ReplicatedDemolish.Deserialize(br));
                    asp.MarkComplete();
                    break;
                case "TAGame.GameEvent_Soccar_TA:ReplicatedMusicStinger":
                    asp.Data.Add(br.ReadBit());
                    asp.Data.Add(br.ReadByte());
                    asp.Data.Add(br.ReadUInt32());
                    asp.MarkComplete();
                    break;
                case "TAGame.CarComponent_FlipCar_TA:FlipCarTime":
                case "TAGame.Ball_TA:ReplicatedBallScale":
                case "TAGame.CarComponent_Boost_TA:RechargeDelay":
                case "TAGame.CarComponent_Boost_TA:RechargeRate":
                case "TAGame.Ball_TA:ReplicatedAddedCarBounceScale":
                case "TAGame.Ball_TA:ReplicatedBallMaxLinearSpeedScale":
                case "TAGame.Ball_TA:ReplicatedWorldBounceScale":
                case "TAGame.CarComponent_Boost_TA:BoostModifier":
                case "Engine.Actor:DrawScale":
                case "TAGame.CrowdActor_TA:ModifiedNoise":
                case "TAGame.CarComponent_TA:ReplicatedActivityTime":
                case "TAGame.SpecialPickup_BallFreeze_TA:RepOrigSpeed":
                case "TAGame.SpecialPickup_BallVelcro_TA:AttachTime":
                case "TAGame.SpecialPickup_BallVelcro_TA:BreakTime":
                case "TAGame.Car_TA:AddedCarForceMultiplier":
                case "TAGame.Car_TA:AddedBallForceMultiplier":
                    asp.Data.Add(br.ReadFloat());
                    asp.MarkComplete();
                    break;
                case "TAGame.GameEvent_SoccarPrivate_TA:MatchSettings":
                    asp.Data.Add(PrivateMatchSettings.Deserialize(br));
                    asp.MarkComplete();
                    break;
                case "TAGame.PRI_TA:ClientLoadoutOnline":
                    asp.Data.Add(ClientLoadoutOnline.Deserialize(br));
                    asp.MarkComplete();
                    break;
                case "TAGame.GameEvent_TA:GameMode":
                    if (versionMajor >= 868 && versionMinor >= 12)
                    {
                        asp.Data.Add(br.ReadByte());
                    }
                    else
                    {
                        asp.Data.Add(br.ReadUInt32Max(4));
                    }
                    asp.MarkComplete();
                    break;
                case "TAGame.PRI_TA:ClientLoadoutsOnline":
                    asp.Data.Add(ClientLoadoutsOnline.Deserialize(br));
                    asp.MarkComplete();
                    break;
                case "TAGame.PRI_TA:ClientLoadouts":
                    asp.Data.Add(ClientLoadouts.Deserialize(br));
                    asp.MarkComplete();
                    break;
                case "TAGame.Team_TA:ClubColors":
                case "TAGame.Car_TA:ClubColors":
                    asp.Data.Add(br.ReadBit());
                    asp.Data.Add(br.ReadByte());
                    asp.Data.Add(br.ReadBit());
                    asp.Data.Add(br.ReadByte());
                    asp.MarkComplete();
                    break;
                case "TAGame.RBActor_TA:WeldedInfo":
                    asp.Data.Add(WeldedInfo.Deserialize(br));
                    asp.MarkComplete();
                    break;
                default:
                    throw new NotSupportedException(string.Format("Unknown property {0}. Next bits in the data are {1}. Figure it out!", asp.PropertyName, br.GetBits(br.Position, Math.Min(4096, br.Length - br.Position)).ToBinaryString()));
            }

            #if DEBUG
            asp.KnownDataBits = br.GetBits(startPosition, br.Position - startPosition);
            #endif
            return asp;
        }
        public static ActorStateProperty Deserialize(IClassNetCache classMap, IDictionary<int, string> objectIndexToName, BitReader br)
        {
            var asp = new ActorStateProperty();
            var startPosition = br.Position;

            var maxPropId = classMap.MaxPropertyId;
            //var idBitLen = Math.Floor(Math.Log10(maxPropId) / Math.Log10(2)) + 1;

            var className = objectIndexToName[classMap.ObjectIndex];
            asp.PropertyId = br.ReadInt32Max(maxPropId + 1);// br.ReadInt32FromBits((int)idBitLen);
            asp.MaxPropertyId = maxPropId;
            asp.PropertyName = objectIndexToName[classMap.GetProperty(asp.PropertyId).Index];
            asp.Data = new List<object>();
            try
            {
                switch (asp.PropertyName)
                {
                    case "TAGame.GameEvent_TA:ReplicatedStateIndex":
                        asp.Data.Add(br.ReadInt32Max(140)); // number is made up, I dont know the max yet
                        asp.IsComplete = true;
                        break;
                    case "TAGame.RBActor_TA:ReplicatedRBState":

                        asp.Data.Add(br.ReadBit());
                        asp.Data.Add(Vector3D.Deserialize2(20, br));

                        var rot = Vector3D.DeserializeFixed(br);
                        asp.Data.Add(rot);
                        // Sometimes these two vectors are missing?
                        // Wild guess: They're momentum vectors, and only there when moving?
                        // Well, how do I know they're moving without momentum vectors... hm.
                        if (!(rot.X < -1 && rot.Y < -1 && rot.Z < -1))
                        {
                            asp.Data.Add(Vector3D.Deserialize2(20, br));
                            asp.Data.Add(Vector3D.Deserialize2(20, br));
                        }

                        asp.IsComplete = true;
                        break;
                    case "TAGame.Team_TA:GameEvent":
                    case "TAGame.CrowdActor_TA:ReplicatedOneShotSound":
                    case "TAGame.CrowdManager_TA:ReplicatedGlobalOneShotSound":
                    case "Engine.Actor:Owner":
                    case "TAGame.GameEvent_Soccar_TA:RoundNum":
                    case "Engine.GameReplicationInfo:GameClass":
                    case "TAGame.GameEvent_TA:BotSkill":
                    case "Engine.PlayerReplicationInfo:Team":
                    case "TAGame.CrowdManager_TA:GameEvent":
                    case "Engine.Pawn:PlayerReplicationInfo":
                    //case "TAGame.VehiclePickup_TA:ReplicatedPickupData":
                        asp.Data.Add(br.ReadBit());
                        asp.Data.Add(br.ReadInt32());
                        asp.IsComplete = true;
                        break;
                    case "TAGame.CarComponent_TA:Vehicle":
                        // 110101111 // TAGame.CarComponent_Jump_TA
                        // 100111111 // TAGame.CarComponent_FlipCar_TA
                        asp.Data.Add(br.ReadBit());
                        if (className == "TAGame.CarComponent_Jump_TA"
                            || className == "TAGame.CarComponent_FlipCar_TA"
                            || className == "TAGame.CarComponent_Boost_TA"
                            || className == "TAGame.CarComponent_Dodge_TA"
                            || className == "TAGame.CarComponent_DoubleJump_TA")
                        {
                            asp.Data.Add(br.ReadInt32());
                        }
                        else
                        {
                            asp.Data.Add(br.ReadByte());
                        }
                        asp.IsComplete = true;
                        break;
                    case "Engine.PlayerReplicationInfo:PlayerName":
                    case "Engine.GameReplicationInfo:ServerName":
                        asp.Data.Add(br.ReadString());
                        asp.IsComplete = true;
                        break;
                    case "TAGame.GameEvent_Soccar_TA:SecondsRemaining":
                    case "TAGame.GameEvent_TA:ReplicatedGameStateTimeRemaining":
                    case "TAGame.CrowdActor_TA:ReplicatedCountDownNumber":
                    case "TAGame.CrowdActor_TA:ModifiedNoise":
                    case "TAGame.GameEvent_Team_TA:MaxTeamSize":
                        asp.Data.Add(br.ReadInt32());
                        asp.IsComplete = true;
                        break;
                    case "TAGame.VehiclePickup_TA:ReplicatedPickupData":
                        // 1011101000000000000000000000000001
                        // 0111111111111111111111111111111110
                        // 1111001000000000000000000000000001
                        // 1000001000000000000000000000000001
                        // 1111110000000000000000000000000001
                        // 1101110000000000000000000000000001
                        // 111111111
                        // 100000001
                        // 101001111

                        var bit1 = br.ReadBit();
                        var byt = br.ReadByte();
                        var bit2 = (byt & 0x80) > 0;
                        if (bit1 == bit2)
                        {
                            asp.Data.Add(bit1);
                            asp.Data.Add(byt);
                        }
                        else
                        {
                            asp.Data.Add(bit1);
                            var bytes = new byte[4];
                            bytes[0] = byt;
                            bytes[1] = br.ReadByte();
                            bytes[2] = br.ReadByte();
                            bytes[3] = br.ReadByte();
                            asp.Data.Add(BitConverter.ToInt32(bytes, 0));
                            asp.Data.Add(br.ReadBit());
                        }
                        asp.IsComplete = true;
                        break;
                    case "Engine.Actor:bNetOwner":
                    case "Engine.Actor:bBlockActors":
                        // this doesnt look right...
                        asp.Data.Add(br.ReadBit());
                        asp.Data.Add(br.ReadBit());
                        asp.Data.Add(br.ReadBit());
                        asp.IsComplete = true;
                        break;
                    case "Engine.Pawn:DrivenVehicle":
                        asp.Data.Add(br.ReadInt32());
                        asp.Data.Add(br.ReadBit());
                        asp.Data.Add(br.ReadBit());
                        asp.IsComplete = true;
                        break;
                    case "Engine.Actor:DrawScale":

                        // Might be more properties in this sample data
                        // 100011000000000000010000000001001110010100000001000000000000000000000000000000110000000000000000000100000000010000000001000110000000000010101
                        // 1011010000000100010000000011001110010100000010000000000000000000000000000011100000000000000001001000000000010000000000100110101100000000101010
                        // 1011010000000011110000000001111111000100000010000000000000000000000000000001100000000000000000101000000000001000000000001110111111100000000101010
                        break;
                    case "Engine.PlayerReplicationInfo:Ping":
                    case "TAGame.Vehicle_TA:ReplicatedSteer":
                    case "TAGame.Vehicle_TA:ReplicatedThrottle":
                    case "TAGame.PRI_TA:CameraYaw":
                    case "TAGame.PRI_TA:CameraPitch":
                        asp.Data.Add(br.ReadByte());
                        asp.IsComplete = true;
                        break;
                    case "Engine.Actor:Location":
                    case "TAGame.CarComponent_Dodge_TA:DodgeTorque":
                        asp.Data.Add(Vector3D.Deserialize(br));
                        asp.IsComplete = true;
                        break;

                    case "Engine.Actor:bCollideWorld":
                    case "Engine.PlayerReplicationInfo:bReadyToPlay":
                    case "TAGame.Vehicle_TA:bReplicatedHandbrake":
                    case "TAGame.Vehicle_TA:bDriving":
                        //asp.Data.Add(Vector3D.Deserialize(5, br));
                        asp.Data.Add(br.ReadBit());
                        asp.IsComplete = true;
                        break;
                    case "TAGame.PRI_TA:bUsingBehindView":
                    case "TAGame.PRI_TA:bUsingSecondaryCamera":
                        asp.Data.Add(br.ReadBit());
                        asp.IsComplete = true;
                        break;
                    case "TAGame.CarComponent_TA:ReplicatedActive":
                        // example data
                        // 0111111111111111111111111111111110

                        asp.Data.Add(br.ReadByte());
                        /*
                        asp.Data.Add(br.ReadBit());
                        if ( (bool)asp.Data[0])
                        {
                            asp.Data.Add(br.ReadInt32FromBits(7));
                        }*/
                        asp.IsComplete = true;
                        break;
                    case "Engine.Actor:Role":
                        asp.Data.Add(br.ReadInt32FromBits(11));
                        asp.IsComplete = true;
                        break;
                    /*case "Engine.Actor:RelativeRotation": //SWAG
                        asp.Data.Add(br.ReadBit());
                        asp.Data.Add(br.ReadByte());
                        asp.Data.Add(br.ReadInt32());
                        asp.IsComplete = true;
                        break;*/
                    case "Engine.PlayerReplicationInfo:UniqueId":
                        asp.Data.Add(br.ReadBit());
                        asp.Data.Add(br.ReadByte());
                        asp.IsComplete = true;
                        break;
                }
            }
            catch(Exception)
            {
                asp.Data.Add("FAILED");
            }
            finally
            {
                asp.KnownBits = br.GetBits(startPosition, br.Position - startPosition);
            }

            return asp;
        }