private void ProcessMessage(Stream.Message message) { byte[] data; if (!message.IsCompressed) { data = message.Data; } else { data = Snappy.Sharp.Snappy.Uncompress(message.Data); Preconditions.CheckArgument(message.DecompressedLength == data.Length); } using (var stream = Bitstream.CreateWith(data)) { while (stream.HasByte()) { HandleMessage(stream); } if (!stream.Eof) { byte remain = (byte)stream.Remain; int expect = (1 << remain) - 1; Preconditions.CheckArgument(stream.ReadBits(remain) == expect); } } }
private Events?Handle(CSVCMsg_PacketEntities message) { using (var stream = Bitstream.CreateWith(message.entity_data)) { entityUpdater.Update( stream, (uint)message.baseline, message.update_baseline, (uint)message.updated_entries, message.is_delta); } if (message.update_baseline) { var ack = new CCLCMsg_BaselineAck { baseline_nr = state.Baseline, baseline_tick = (int)state.ServerTick }; var ackMsg = DotaGameConnection.ConvertProtoToMessage( (uint)CLC_Messages.clc_BaselineAck, ack); connection.SendReliably(ackMsg); return(null); } return(null); }
public Events?Handle(DotaGameConnection.Message message) { using (var stream = Bitstream.CreateWith(message.Data)) { if (message.Type == (uint)NET_Messages.net_NOP) { return(null); } if (message.Type == (uint)NET_Messages.net_Disconnect) { return(Handle(Serializer.Deserialize <CNETMsg_Disconnect>(stream))); } if (message.Type == (uint)NET_Messages.net_Tick) { return(Handle(Serializer.Deserialize <CNETMsg_Tick>(stream))); } if (message.Type == (uint)NET_Messages.net_SetConVar) { return(Handle(Serializer.Deserialize <CNETMsg_SetConVar>(stream))); } if (message.Type == (uint)NET_Messages.net_SignonState) { return(Handle(Serializer.Deserialize <CNETMsg_SignonState>(stream))); } if (message.Type == (uint)SVC_Messages.svc_ServerInfo) { return(Handle(Serializer.Deserialize <CSVCMsg_ServerInfo>(stream))); } if (message.Type == (uint)SVC_Messages.svc_SendTable) { return(Handle(Serializer.Deserialize <CSVCMsg_SendTable>(stream))); } if (message.Type == (uint)SVC_Messages.svc_ClassInfo) { return(Handle(Serializer.Deserialize <CSVCMsg_ClassInfo>(stream))); } if (message.Type == (uint)SVC_Messages.svc_PacketEntities) { return(Handle(Serializer.Deserialize <CSVCMsg_PacketEntities>(stream))); } if (message.Type == (uint)SVC_Messages.svc_CreateStringTable) { return(Handle(Serializer.Deserialize <CSVCMsg_CreateStringTable>(stream))); } if (message.Type == (uint)SVC_Messages.svc_UpdateStringTable) { return(Handle(Serializer.Deserialize <CSVCMsg_UpdateStringTable>(stream))); } if (message.Type == (uint)SVC_Messages.svc_Print) { return(Handle(Serializer.Deserialize <CSVCMsg_Print>(stream))); } if (message.Type == (uint)SVC_Messages.svc_GameEventList) { return(Handle(Serializer.Deserialize <CSVCMsg_GameEventList>(stream))); } return(null); } }
public void Update(StringTable table, int numEntries, byte[] data) { using (var stream = Bitstream.CreateWith(data)) { bool option = stream.ReadBool(); if (option) { throw new ArgumentException("Unknown option " + option); } List <string> keyHistory = new List <string>(); uint entryId = UInt32.MaxValue; uint read = 0; while (read < numEntries) { if (!stream.ReadBool()) { entryId = stream.ReadBits(table.EntryBits); } else { entryId = unchecked (entryId + 1); } Preconditions.CheckArgument(entryId < table.MaxEntries); string key = ReadKeyIfIncluded(stream, keyHistory); byte[] value = ReadValueIfIncluded(stream, table.UserDataFixedSize, table.UserDataSizeBits); if (entryId < table.Count) { StringTable.Entry entry = table.Get(entryId); if (key != null) { Preconditions.CheckArgument(key.Equals(entry.Key)); } if (value != null) { entry.Value = value; } } else { table.Put(entryId, new StringTable.Entry(key, value)); } ++read; } } }
public void Update(StringTable table, int numEntries, byte[] data) { using (var stream = Bitstream.CreateWith(data)) { var option = stream.ReadBool(); if (option) { throw new ArgumentException("Unknown option " + option); } var keyHistory = new List <string>(); var entryId = uint.MaxValue; uint read = 0; while (read < numEntries) { if (!stream.ReadBool()) { entryId = stream.ReadBits(table.EntryBits); } else { entryId = unchecked (entryId + 1); } var key = ReadKeyIfIncluded(stream, keyHistory); var value = ReadValueIfIncluded(stream, table.UserDataFixedSize, table.UserDataSizeBits); if (entryId < table.Count) { var entry = table.Get(entryId); if (value != null) { entry.Value = value; } } else { table.Put(entryId, new StringTable.Entry(key, value)); } ++read; } } }
public Events?Handle(byte[] response) { using (var stream = Bitstream.CreateWith(response)) { var type = stream.ReadByte(); if (type == S2C_CHALLENGE) { if (stream.ReadUInt32() != SOURCE_PROTOCOL) { throw new ArgumentException("Not SOURCE_PROTOCOL!"); } server_challenge = stream.ReadUInt32(); if (stream.ReadUInt32() != client_challenge) { throw new ArgumentException("Client challenge does not match!"); } if (stream.ReadUInt32() != STEAM_VERSION) { throw new ArgumentException("STEAM_VERSION mismatch!"); } server_id = stream.ReadUInt64(); stream.ReadByte(); // mystery byte return(Events.HANDSHAKE_CHALLENGE); } if (type == S2C_ACCEPT) { if (stream.ReadUInt32() != client_challenge) { throw new ArgumentException("Client challenge does not match!"); } return(Events.HANDSHAKE_COMPLETE); } if (type == S2C_REJECT) { if (stream.ReadUInt32() != client_challenge) { throw new ArgumentException("Client challenge does not match!"); } rejected_reason = stream.ReadString(); return(Events.REJECTED); } throw new ArgumentException("Unknown response type " + type); } }
private Events?Handle(CSVCMsg_UserMessage message) { if (message.msg_type == (int)EBaseUserMessages.UM_SayText2) { using (var stream = Bitstream.CreateWith(message.msg_data)) { return(Handle(Serializer.Deserialize <CUserMsg_SayText2>(stream))); } } if (message.msg_type == (int)EDotaUserMessages.DOTA_UM_ChatEvent) { using (var stream = Bitstream.CreateWith(message.msg_data)) { return(Handle(Serializer.Deserialize <CDOTAUserMsg_ChatEvent>(stream))); } } return(null); }
private void ProcessMessage(Stream.Message message) { var data = !message.IsCompressed ? message.Data : new SnappyDecompressor().Decompress(message.Data, 0, message.Data.Length); using (var stream = Bitstream.CreateWith(data)) { while (stream.HasByte()) { HandleMessage(stream); } if (!stream.Eof) { var remain = (byte)stream.Remain; var expect = (1 << remain) - 1; var expectTru = stream.ReadBits(remain) == expect; } } }
private Events?Handle(CSVCMsg_PacketEntities message) { using (var stream = Bitstream.CreateWith(message.entity_data)) { entityUpdater.Update( stream, (uint)message.baseline, message.update_baseline, (uint)message.updated_entries, message.is_delta); } if (message.update_baseline) { state.Baseline = message.baseline; return(Events.BASELINE); } return(null); }
public Events?Handle(DotaGameConnection.Message message) { using (var stream = Bitstream.CreateWith(message.Data)) { if (message.Type == (uint)NET_Messages.net_NOP) { return(null); } if (message.Type == (uint)NET_Messages.net_Disconnect) { return(Handle(Serializer.Deserialize <CNETMsg_Disconnect>(stream))); } if (message.Type == (uint)NET_Messages.net_StringCmd) { return(Handle(Serializer.Deserialize <CNETMsg_StringCmd>(stream))); } if (message.Type == (uint)NET_Messages.net_Tick) { return(Handle(Serializer.Deserialize <CNETMsg_Tick>(stream))); } if (message.Type == (uint)SVC_Messages.svc_PacketEntities) { return(Handle(Serializer.Deserialize <CSVCMsg_PacketEntities>(stream))); } if (message.Type == (uint)SVC_Messages.svc_UpdateStringTable) { return(Handle(Serializer.Deserialize <CSVCMsg_UpdateStringTable>(stream))); } if (message.Type == (uint)SVC_Messages.svc_UserMessage) { return(Handle(Serializer.Deserialize <CSVCMsg_UserMessage>(stream))); } if (message.Type == (uint)SVC_Messages.svc_GameEvent) { return(Handle(Serializer.Deserialize <CSVCMsg_GameEvent>(stream))); } return(null); } }
public void Auth() { var pb = new CMsgAuthTicket(); pb.gameid = App; pb.h_steam_pipe = 327684; using (var stream = Bitstream.CreateWith(PendingTicketForAuth.ToArray())) { pb.ticket_crc = CrcUtils.Compute32(stream); } pb.ticket = PendingTicketForAuth.ToArray(); var msg = new ClientMsgProtobuf <CMsgClientAuthList>(EMsg.ClientAuthList); msg.Body.tokens_left = Bot.TokenCount; msg.Body.app_ids.Add(App); msg.Body.tickets.Add(pb); msg.Body.message_sequence = AuthSequence++; Bot.Client.Send(msg); log.Debug("Sent auth list with crc " + msg.Body.tickets[0].ticket_crc + "/" + msg.Body.message_sequence); }
private void Create(uint id, EntityClass clazz, uint baseline) { state.Created.Add(id); if (!state.Slots.ContainsKey(id)) { state.Slots[id] = new DotaGameState.Slot(null); } var slot = state.Slots[id]; slot.Live = true; if (slot.Baselines[baseline] != null && slot.Baselines[baseline].Class.Equals(clazz)) { slot.Entity = slot.Baselines[baseline].Copy(); } else { slot.Entity = Entity.CreateWith(id, clazz, state.FlatTables[(int)clazz.Id]); var table = state.Strings[state.StringsIndex["instancebaseline"]]; using (var stream = Bitstream.CreateWith(table.Get(clazz.Id.ToString()).Value)) { ReadAndUnpackFields(slot.Entity, stream); } } foreach (var prop in slot.Entity.Properties) { var info = prop.Info; var handle = new DotaGameState.PropertyHandle { Entity = id, Table = info.Origin.NetTableName, Name = info.VarName }; state.Properties[handle] = prop; } }
private void ProcessPacket(byte[] bytes, int length) { using (var stream = Bitstream.CreateWith(bytes, length)) { var seq = stream.ReadUInt32(); var ack = stream.ReadUInt32(); var flags = stream.ReadByte(); var checksum = stream.ReadUInt16(); var at = stream.Position; var computed = CrcUtils.Compute16(stream); stream.Position = at; if (checksum != computed) { return; } var reliableState = stream.ReadByte(); if (seq < sequenceIn) { // We no longer care. return; } for (byte i = 0; i < subchannels.Length; ++i) { var channel = subchannels[i]; var mask = 1 << i; if ((reliableStateOut & mask) == (reliableState & mask)) { if (channel.Blocked) { channel.Clear(); } } else { if (channel.Blocked && channel.SentIn < ack) { reliableStateOut = Flip(reliableStateOut, i); channel.Requeue(); } } } if ((flags & (uint)PacketFlags.IsReliable) != 0) { var bit = stream.ReadBits(3); reliableStateIn = Flip(reliableStateIn, bit); for (var i = 0; i < streams.Length; ++i) { var message = streams[i].Receive(stream); if (message.HasValue) { ProcessMessage(message.Value); } } } while (stream.HasByte()) { HandleMessage(stream); } if (!stream.Eof) { var remain = (byte)stream.Remain; var expect = (1 << remain) - 1; var expectedTru = stream.ReadBits(remain) == expect; // if false then probably something wrong } lastAckRecv = ack; sequenceIn = seq; } }
private void ReceivePacket(byte[] bytes, int length) { ++receivedTotal; using (var stream = Bitstream.CreateWith(bytes, length)) { var type = stream.ReadUInt32(); if (type == COMPRESSED_PACKET) { var method = stream.ReadUInt32(); var compressed = new byte[length - 8]; stream.Read(compressed, 0, compressed.Length); var decompressed = Lzss.Decompress(compressed); ProcessPacket(decompressed, decompressed.Length); } else if (type == SPLIT_PACKET) { var request = stream.ReadUInt32(); var total = stream.ReadByte(); var index = stream.ReadByte(); var size = stream.ReadUInt16(); SplitPacket split; if (!splitPackets.ContainsKey(request)) { split = new SplitPacket { Request = request, Total = total, Received = 0, Data = new byte[total][], Present = new bool[total] }; splitPackets[request] = split; } else { split = splitPackets[request]; } var buffer = new byte[Math.Min(size, (stream.Remain + 7) / 8)]; stream.Read(buffer, 0, buffer.Length); split.Data[index] = buffer; if (!split.Present[index]) { ++split.Received; split.Present[index] = true; } if (split.Received == split.Total) { var full = split.Data.SelectMany(b => b).ToArray(); ReceivePacket(full, full.Length); splitPackets.Remove(request); } } else if (type == OOB_PACKET) { var data = new byte[stream.Length - 4]; stream.Read(data, 0, data.Length); receivedOutOfBand.Enqueue(data); } else { ProcessPacket(bytes, length); } } }
private void ProcessPacket(byte[] bytes, int length) { using (var stream = Bitstream.CreateWith(bytes, length)) { uint seq = stream.ReadUInt32(); uint ack = stream.ReadUInt32(); byte flags = stream.ReadByte(); ushort checksum = stream.ReadUInt16(); long at = stream.Position; ushort computed = CrcUtils.Compute16(stream); stream.Position = at; if (checksum != computed) { log.WarnFormat( "failed checksum:" + "recv seq {0} ack {1} flags {2:x} checksum {3:x} computed {4:x}", seq, ack, flags, checksum, computed); return; } byte reliableState = stream.ReadByte(); if ((flags & 0x10) == 0x10) { log.WarnFormat( "choke {0}: recv seq {1} ack {2} flags {3:x}", stream.ReadByte(), seq, ack, flags); } if (seq < sequenceIn) { // We no longer care. log.WarnFormat("dropped: recv seq {0} ack {1}", seq, ack); return; } for (byte i = 0; i < subchannels.Length; ++i) { Subchannel channel = subchannels[i]; int mask = 1 << i; if ((reliableStateOut & mask) == (reliableState & mask)) { if (channel.Blocked) { Preconditions.CheckArgument(ack >= channel.SentIn); channel.Clear(); } } else { if (channel.Blocked && channel.SentIn < ack) { reliableStateOut = Flip(reliableStateOut, i); channel.Requeue(); } } } if ((flags & (uint)PacketFlags.IsReliable) != 0) { uint bit = stream.ReadBits(3); //Debug.WriteLine(" reliable, flip {0}. {1} => {2}", bit, reliableStateIn, Flip(reliableStateIn, bit)); reliableStateIn = Flip(reliableStateIn, bit); for (int i = 0; i < streams.Length; ++i) { Nullable <Stream.Message> message = streams[i].Receive(stream); if (message.HasValue) { ProcessMessage(message.Value); } } } while (stream.HasByte()) { HandleMessage(stream); } if (!stream.Eof) { byte remain = (byte)stream.Remain; int expect = (1 << remain) - 1; Preconditions.CheckArgument(stream.ReadBits(remain) == expect); } lastAckRecv = ack; sequenceIn = seq; } }
/// <summary> /// Connect to the game server. Will use existing lobby on default. /// </summary> /// <param name="lobb"></param> public void Connect(CSODOTALobby lobb = null) { if (_connectDetails != null) { Disconnect(); } lobb = lobb ?? DotaGc.Lobby; if (lobb == null) { Log("No lobby so not connecting."); return; } _connectLobby = lobb; if (_appOwnershipTicket == null) { Log("Waiting for ownership ticket..."); _waitingForAuthTicket = true; FetchAppTicket(); return; } _authTicket = AuthTicket.CreateAuthTicket(_gameConnectTokens.Dequeue(), publicIP); var ver = new CMsgAuthTicket { gameid = (uint)DotaGc.GameID, h_steam_pipe = 327684, ticket = _authTicket }; using (var stream = Bitstream.CreateWith(_authTicket)) ver.ticket_crc = CrcUtils.Compute32(stream); _connectDetails = new DOTAConnectDetails { AuthTicket = _authTicket, ServerAuthTicket = AuthTicket.CreateServerTicket(DotaGc.SteamClient.SteamID, _authTicket, _appOwnershipTicket), ConnectInfo = lobb.connect, ConnectID = _connectAttempt++, AuthTicketCRC = ver.ticket_crc, Name = DotaGc.SteamClient.GetHandler <SteamFriends>().GetPersonaName(), PassKey = lobb.pass_key, SteamId = DotaGc.SteamClient.SteamID.ConvertToUInt64() }; var msg = new ClientMsgProtobuf <CMsgClientAuthList>(EMsg.ClientAuthList) { Body = { tokens_left = (uint)_gameConnectTokens.Count, app_ids = { (uint)DotaGc.GameID }, tickets = { ver }, message_sequence = 2 // Second in sequence. } }; DotaGc.SteamClient.Send(msg); Log("Sent crc ticket auth list, hash: " + ver.ticket_crc + "."); }