public static Vector3D Deserialize2(int maxBits, BitReader br) { var v = new Vector3D(); // From ReadPackedVector v.NumBits = br.ReadInt32Max(maxBits); Int32 Bias = 1 << (v.NumBits + 1); Int32 Max = v.NumBits + 2; v.DX = br.ReadInt32FromBits(Max); v.DY = br.ReadInt32FromBits(Max); v.DZ = br.ReadInt32FromBits(Max); //float fact = 1; //(float)ScaleFactor; // 1 in our case, doesnt matter //v.X = (float)(static_cast<int32>(DX)-Bias) / fact; // Why bother with the static_cast? Why not make DX an int32 instead of uint32 in the first place? // always integers, hey? v.X = v.DX-Bias; v.Y = v.DY-Bias; v.Z = v.DZ-Bias; return v; }
public static string Deserialize(BitReader br) { var length = br.ReadInt32(); if (length > 0) { var bytes = br.ReadBytes(length); return Encoding.GetEncoding(1252).GetString(bytes, 0, length - 1); } else if (length < 0) { var bytes = br.ReadBytes(length * -2); return Encoding.Unicode.GetString(bytes, 0, (length * -2) - 2); } return ""; }
public static ActorState Deserialize(List<ActorState> existingActorStates, List<ActorState> frameActorStates, IDictionary<int, string> objectIndexToName, IEnumerable<ClassNetCache> classNetCache, BitReader br) { //var a = new ActorState(); var startPosition = br.Position; var actorId = br.ReadInt32FromBits(10); ActorState a = new ActorState(); a.Id = actorId; try { /* var maxId = existingActorStates.Any() ? existingActorStates.Max(x => x.Id) : -1; if (actorId > (maxId + 20)) { // we're probably lost. Awwww. a.KnownBits = br.GetBits(startPosition, br.Position - startPosition); return a; } */ frameActorStates.Add(a); if (br.ReadBit()) { if (br.ReadBit()) { a.State = "New"; a.Unknown1 = br.ReadBit(); a.TypeId = br.ReadInt32(); a.TypeName = objectIndexToName[(int)a.TypeId.Value]; var classMap = ObjectNameToClassNetCache(a.TypeName, objectIndexToName, classNetCache); a.ClassName = objectIndexToName[classMap.ObjectIndex]; // Come up with something more foolproof for this /* if ( a.TypeName.Contains(":")) { // Nope, we think we're a property type. We're lost! a.Failed = true; return a; } * */ if (a.ClassName == "TAGame.CrowdActor_TA" || a.ClassName == "TAGame.CrowdManager_TA" || a.ClassName == "TAGame.VehiclePickup_Boost_TA" || a.ClassName == "Core.Object") { a.KnownBits = br.GetBits(startPosition, br.Position - startPosition); a.Complete = true; return a; } a.Position = Vector3D.Deserialize(br); if (a.ClassName == "Engine.GameReplicationInfo" || a.ClassName == "TAGame.GameEvent_SoccarSplitscreen_TA" || a.ClassName == "TAGame.CarComponent_Boost_TA" || a.ClassName == "TAGame.CarComponent_Jump_TA" || a.ClassName == "TAGame.CarComponent_DoubleJump_TA" || a.ClassName == "TAGame.CarComponent_Dodge_TA" || a.ClassName == "TAGame.CarComponent_FlipCar_TA" || a.ClassName == "TAGame.Team_TA" || a.ClassName == "TAGame.PRI_TA" || a.ClassName == "TAGame.GameEvent_Soccar_TA") { a.Complete = true; } else if (a.ClassName == "TAGame.Ball_TA" || a.ClassName == "TAGame.Car_TA") { if (br.ReadBit()) { br.ReadByte(); } if (br.ReadBit()) { br.ReadByte(); } if (br.ReadBit()) { br.ReadByte(); } a.Complete = true; } } else { a.State = "Existing"; a.TypeId = existingActorStates.Where(x => x.Id == a.Id).Single().TypeId; a.TypeName = objectIndexToName[(int)a.TypeId.Value]; var classMap = ObjectNameToClassNetCache(a.TypeName, objectIndexToName, classNetCache); a.ClassName = objectIndexToName[classMap.ObjectIndex]; a.Properties = new List<ActorStateProperty>(); ActorStateProperty lastProp = null; while ((lastProp == null || lastProp.IsComplete) && br.ReadBit()) { lastProp = ActorStateProperty.Deserialize(classMap, objectIndexToName, br); a.Properties.Add(lastProp); } a.Complete = lastProp.IsComplete; if ( lastProp.Data.Count > 0 && lastProp.Data.Last().ToString() == "FAILED") { a.Failed = true; } var endPosition = br.Position; } } else { a.State = "Deleted"; var actor = existingActorStates.Where(x => x.Id == a.Id).SingleOrDefault(); if (actor != null) // TODO remove this someday. Only here because we might be deleting objects we havent figured out how to parse yet { a.TypeId = actor.TypeId; a.TypeName = objectIndexToName[(int)a.TypeId.Value]; var classMap = ObjectNameToClassNetCache(a.TypeName, objectIndexToName, classNetCache); a.ClassName = objectIndexToName[classMap.ObjectIndex]; } a.Complete = true; var endPosition = br.Position; } } catch(Exception) { // eat exceptions for now int g = 56; a.Failed = true; } finally { a.KnownBits = br.GetBits(startPosition, br.Position - startPosition); } return a; }
public static Frame Deserialize(ref List<ActorState> existingActorStates, IDictionary<int, string> objectIdToName, IEnumerable<ClassNetCache> classNetCache, int filePosition, bool[] bits) { var f = new Frame(); f.Position = filePosition; f.BitLength = bits.Length; f.RawData = new byte[(int)Math.Ceiling(f.BitLength / 8.0)]; var ba = new BitArray(bits); ba.CopyTo(f.RawData, 0); f.Time = BitConverter.ToSingle(f.RawData, 0); f.Delta = BitConverter.ToSingle(f.RawData, 4); var br = new BitReader(bits); br.ReadBitsAsBytes(64); // we already read the time and delta f.ActorStates = new List<ActorState>(); try { ActorState lastActorState = null; while ((lastActorState == null || lastActorState.Complete || lastActorState.ForcedComplete) && br.ReadBit()) { lastActorState = ActorState.Deserialize(existingActorStates, f.ActorStates, objectIdToName, classNetCache, br); var existingActor = existingActorStates.Where(x => x.Id == lastActorState.Id).SingleOrDefault(); if (lastActorState.State != "Deleted") { if (existingActor == null) { existingActorStates.Add(lastActorState); } } else { existingActorStates = existingActorStates.Where(x => x.Id != lastActorState.Id).ToList(); } if( !lastActorState.Complete || (!br.PeekBit() && ((br.Length - br.Position) > 1) ) ) // 0 bit, signalling end of frame, but too many bits left to be truly complete { lastActorState.Complete = false; // Try to find the next ActorState // Always deleted first, then new, then existing // Within those states id always increases // ^ Nope thats not true // Will be stuck in New or Existing land, since Deleted states are easy. // If last was New, next ActorState will look like 1XXXXXXXXXX1 // If last was Existing, next ActorState will look like 01XXXXXXXXXX1 (0 prefix from the end of last state (no more properties) var startPosition = br.Position; for(var p = br.Position; p < br.Length - 20; p++ ) // I think the smallest non-deleted actor state will be 20 bits (1 0000000000 10 1 0000 0 0) { br.Seek(p); Int32 potentialId = -1; if (br.ReadBit()) { potentialId = br.ReadInt32FromBits(10); if (br.ReadBit()) // 1 for New/Existing { var newActor = br.ReadBit(); if (newActor && lastActorState.State == "Existing") { // Nope, cant have a new actor after an existing actor continue; } if (newActor && (lastActorState.State == "New") && (potentialId > lastActorState.Id) // id is increasing && (potentialId < lastActorState.Id + 100) // id isnt crazy && ((br.Length - br.Position) > 33) // have enough bits left for the typeid and unknown bit ) { // Heck, lets give it a shot. lastActorState.ForcedComplete = true; lastActorState.UnknownBits = br.GetBits(startPosition, p - startPosition); br.Seek(p); break; } if (!newActor && (lastActorState.State == "New") //&& (potentialId <= lastActorState.Id) // Potentially first existing actor after a new actor. Id can be at most equal to last actor id // I think... We could get lucky enough to have only a New actor that doesnt need extra data, and then Existing data for something else... && (existingActorStates.Where(x => x.Id == potentialId).Any()) // We have a match in our list && br.ReadBit() // Must have a 1 here for "new property && ((br.Length - br.Position) > 6) // have enough bits lefts for the smallest prop (4 bits for id, 1 for bool value, 1 bit for 'no more properties' ) { // Heck, lets give it a shot. lastActorState.ForcedComplete = true; lastActorState.UnknownBits = br.GetBits(startPosition, p - startPosition); br.Seek(p); break; } if (!newActor && (lastActorState.State == "Existing") //&& (potentialId > lastActorState.Id) // Id is increasing && (existingActorStates.Where(x => x.Id == potentialId).Any()) // We have a match in our list && br.ReadBit() // Must have a 1 here for "new property && ((br.Length - br.Position) > 6) // have enough bits lefts for the smallest prop (4 bits for id, 1 for bool value, 1 bit for 'no more properties' ) { // Heck, lets give it a shot. // This same code is in here 3 times, silly. Make it better. lastActorState.ForcedComplete = true; lastActorState.UnknownBits = br.GetBits(startPosition, p - startPosition); br.Seek(p); break; } } } } if ( !lastActorState.Complete && !lastActorState.ForcedComplete ) { // Didnt find anything. Reset position so unknown bits get recorded properly br.Seek(startPosition); } } //f.ActorStates.Add(lastActorState); } if (br.EndOfStream && (lastActorState == null || lastActorState.Complete)) { f.Complete = true; } if ( lastActorState != null &&lastActorState.Failed ) { f.Failed = true; } } catch (Exception) { } while (!br.EndOfStream) { f.UnknownBits.Add(br.ReadBit()); } return f; }
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; }
private static List<object> ReadData(int numBytes, int numBits, BitReader br) { List<object> data = new List<object>(); for (int i = 0; i < numBytes; ++i) { data.Add(br.ReadByte()); } for (int i = 0; i < numBits; ++i) { data.Add(br.ReadBit()); } return data; }
public static Vector3D DeserializeFixed(BitReader br) { var v = new Vector3D(); v.X = ReadFixedCompressedFloat(1, 16, br); v.Y = ReadFixedCompressedFloat(1, 16, br); v.Z = ReadFixedCompressedFloat(1, 16, br); return v; }
public static Vector3D Deserialize(BitReader br) { return Deserialize2(20, br); }
// This probably belongs in BitReader. This is the only calss that uses it though. static float ReadFixedCompressedFloat(Int32 maxValue, Int32 numBits, BitReader br) { float value = 0; // NumBits = 8: var maxBitValue = (1 << (numBits - 1)) - 1; // 0111 1111 - Max abs value we will serialize var bias = (1 << (numBits - 1)) ; // 1000 0000 - Bias to pivot around (in order to support signed values) var serIntMax = (1 << (numBits - 0)) ; // 1 0000 0000 - What we pass into SerializeInt var maxDelta = (1 << (numBits - 0)) - 1; // 1111 1111 - Max delta is Int32 delta = br.ReadInt32Max(serIntMax); // Could just read 16 bits always, since numBits will always be 16 float unscaledValue = delta - bias; if ( maxValue > maxBitValue ) { // We have to scale down, scale needs to be a float: float invScale = maxValue / (float)maxBitValue; value = unscaledValue * invScale; } else { var scale = maxBitValue / maxValue; float invScale = 1.0f / (float)scale; value = unscaledValue * invScale; } return value; }