public static void ChangeDemoDir(SourceDemo demo, Stream s, string newDir) { void Write(byte[] buf) => s.Write(buf, 0, buf.Length); string old = demo.Header.GameDirectory; if (old == newDir) { // no difference Write(demo.Reader.Data); return; } int lenDiff = newDir.Length - old.Length; BitStreamReader bsr = demo.Reader; byte[] dirBytes = Encoding.ASCII.GetBytes(newDir); Write(bsr.ReadBytes(796)); Write(dirBytes); // header doesn't matter but I change it anyway Write(new byte[260 - newDir.Length]); bsr.SkipBytes(260); Write(bsr.ReadBytes(12)); byte[] tmp = BitConverter.GetBytes((uint)(bsr.ReadUInt() + lenDiff)); if (!BitConverter.IsLittleEndian) { tmp = tmp.Reverse().ToArray(); } Write(tmp); foreach (SignOn signOn in demo.FilterForPacket <SignOn>().Where(signOn => signOn.FilterForMessage <SvcServerInfo>().Any())) { // catch up to signOn packet int byteCount = (signOn.Reader.AbsoluteBitIndex - bsr.AbsoluteBitIndex) / 8; Write(bsr.ReadBytes(byteCount)); bsr.SkipBits(signOn.Reader.BitLength); BitStreamWriter bsw = new BitStreamWriter(); BitStreamReader signOnReader = signOn.Reader; bsw.WriteBits(signOnReader.ReadRemainingBits()); signOnReader = signOnReader.FromBeginning(); int bytesToMessageStreamSize = demo.DemoInfo.MaxSplitscreenPlayers * 76 + 8; signOnReader.SkipBytes(bytesToMessageStreamSize); // edit the message stream length - read uint, and edit at index before the reading of said uint bsw.EditIntAtIndex((int)(signOnReader.ReadUInt() + lenDiff), signOnReader.CurrentBitIndex - 32, 32); // actually change the game dir SvcServerInfo serverInfo = signOn.FilterForMessage <SvcServerInfo>().Single(); int editIndex = serverInfo.GameDirBitIndex - signOn.Reader.AbsoluteBitIndex; bsw.RemoveBitsAtIndex(editIndex, old.Length * 8); bsw.InsertBitsAtIndex(dirBytes, editIndex, newDir.Length * 8); Write(bsw.AsArray); } Write(bsr.ReadRemainingBits().bytes); }
// src_main/common/netmessages.cpp SVC_ServerInfo::WriteToBuffer protected override void Parse(ref BitStreamReader bsr) { NetworkProtocol = bsr.ReadUShort(); ServerCount = bsr.ReadUInt(); IsHltv = bsr.ReadBool(); IsDedicated = bsr.ReadBool(); if (DemoInfo.IsLeft4Dead() && DemoInfo.Game >= SourceGame.L4D2_2147) { UnknownBit = bsr.ReadBool(); } ClientCrc = bsr.ReadSInt(); if (DemoInfo.NewDemoProtocol) // unknown field, could be before ClientCrc { Unknown = bsr.ReadUInt(); } MaxServerClasses = bsr.ReadUShort(); if (NetworkProtocol == 24) { MapMD5 = bsr.ReadBytes(16); } else { MapCrc = bsr.ReadUInt(); // network protocol < 18 according to p2 leak, but doesn't add up for l4d2 and p2 } PlayerCount = bsr.ReadByte(); MaxClients = bsr.ReadByte(); TickInterval = bsr.ReadFloat(); Platform = (char)bsr.ReadByte(); GameDirBitIndex = bsr.AbsoluteBitIndex; GameDir = bsr.ReadNullTerminatedString(); MapName = bsr.ReadNullTerminatedString(); SkyName = bsr.ReadNullTerminatedString(); HostName = bsr.ReadNullTerminatedString(); if (DemoInfo.IsLeft4Dead() && DemoInfo.Game >= SourceGame.L4D2_2147) { MissionName = bsr.ReadNullTerminatedString(); MutationName = bsr.ReadNullTerminatedString(); } if (NetworkProtocol == 24) { HasReplay = bsr.ReadBool(); // protocol version >= 16 } // there's a good change that the first SvcServerInfo parsed is parsed correctly // prevent the interval from being overwritten by subsequent, incorrectly detected, SvcServerInfo messages // TODO: check if changing tickrate mid game sends another SvcServerInfo if (!DemoInfo.HasParsedTickInterval) { DemoInfo.TickInterval = TickInterval; DemoInfo.HasParsedTickInterval = true; } // this packet always(?) appears before the creation of any tables DemoRef.StringTablesManager.ClearCurrentTables(); // init baselines here DemoRef.EntBaseLines = new EntityBaseLines(DemoRef, MaxServerClasses); }
public void Test_ByteArray() { BitStreamWriter writer = new BitStreamWriter(stream); BitStreamReader reader = new BitStreamReader(stream); byte[] array = new byte[] { 255, 254, 251, 250 }; writer.Write(array); byte[] result = reader.ReadBytes(_fixture.index, array.Length); _fixture.index += array.Length * 8; Assert.Equal(array, result); }
protected override void Parse(ref BitStreamReader bsr) { SignOnState = (SignOnState)bsr.ReadByte(); SpawnCount = bsr.ReadSInt(); if (DemoInfo.NewDemoProtocol) { NumServerPlayers = bsr.ReadUInt(); int length = (int)bsr.ReadUInt(); if (length > 0) { PlayerNetworkIds = bsr.ReadBytes(length); } length = (int)bsr.ReadUInt(); if (length > 0) // the string still seams to be null terminated (sometimes?) { MapName = bsr.ReadStringOfLength(length).Split(new char[] { '\0' }, 2)[0]; } } if (SignOnState == SignOnState.PreSpawn) { DemoRef.ClientSoundSequence = 1; // reset sound sequence number after receiving SignOn sounds } }
protected override void Parse(ref BitStreamReader bsr) { Arr = bsr.ReadBytes((int)bsr.ReadUInt()); }