/// <summary> /// Handles a connected client. Run this method on a seperate thread. /// </summary> /// <param name="combobotClientDescriptor">A CombobotClientDescriptor object.</param> private void HandleClient(object combobotClientDescriptor) { CombobotClientDescriptor descriptor = (CombobotClientDescriptor)combobotClientDescriptor; try { TcpClient tc = descriptor.TcpClient; NetworkStream nstream = tc.GetStream(); while (this.IsRunning) { Objects.Packet p = Objects.Packet.GetNextPacket(nstream); if (p.Length == 0) { break; // disconnected } p.GetUInt16(); // length, not needed switch ((PacketType)p.GetByte()) { case PacketType.Ping: descriptor.SetRTT((ushort)descriptor.GetElapsedMilliseconds()); if (this.ClientPingReceived != null) { this.ClientPingReceived(descriptor); } break; case PacketType.PlayerInfo: descriptor.CharacterName = p.GetString(); break; } } } catch { } finally { if (descriptor.TcpClient != null) { descriptor.TcpClient.Close(); } this.ConnectedClients.Remove(descriptor); if (this.ClientDisconnected != null) { this.ClientDisconnected(descriptor); } } }
private void HandleServer() { try { this.TcpClient = new TcpClient(this.ServerIP, this.ServerPort); this.IsConnected = true; if (this.Connected != null) { this.Connected(); } Objects.Item item; Objects.Packet p = new Objects.Packet(); p.AddByte((byte)PacketType.PlayerInfo); p.AddString(this.Client.Player.Name); p.AddLength(); p.Send(this.TcpClient); while (true) { p = Objects.Packet.GetNextPacket(this.TcpClient.GetStream()); if (p.Length == 0) { break; // disconnected } p.GetUInt16(); // length, not needed switch ((PacketType)p.GetByte()) { case PacketType.Combo: if (!this.Client.Player.Connected) { continue; } uint targetid = p.GetUInt32(); Objects.Creature c = this.Client.BattleList.GetAny(targetid); if (c == null || !this.Client.Player.Location.IsOnScreen(c.Location)) { break; } switch (this.Action) { case ActionType.Say: if (string.IsNullOrEmpty(this.ActionEx)) { break; } this.Client.Packets.Say(this.ActionEx); break; case ActionType.CustomRune: ushort runeid = 0; if (!ushort.TryParse(this.ActionEx, out runeid)) { break; } item = this.Client.Inventory.GetItem(runeid); if (item != null) { item.UseOnCreature(c); } break; case ActionType.SuddenDeath: item = this.Client.Inventory.GetItem(this.Client.ItemList.Runes.SuddenDeath); if (item != null) { item.UseOnCreature(c); } break; case ActionType.HeavyMagicMissile: item = this.Client.Inventory.GetItem(this.Client.ItemList.Runes.HeavyMagicMissile); if (item != null) { item.UseOnCreature(c); } break; case ActionType.Explosion: item = this.Client.Inventory.GetItem(this.Client.ItemList.Runes.Explosion); if (item != null) { item.UseOnCreature(c); } break; case ActionType.Paralyze: item = this.Client.Inventory.GetItem(this.Client.ItemList.Runes.Paralyze); if (item != null) { item.UseOnCreature(c); } break; } break; case PacketType.Ping: p = new Objects.Packet(); p.AddByte((byte)PacketType.Ping); p.AddLength(); p.Send(this.TcpClient); break; case PacketType.PlayerInfo: p = new Objects.Packet(); p.AddByte((byte)PacketType.PlayerInfo); p.AddString(this.Client.Player.Name); p.AddLength(); p.Send(this.TcpClient); break; } } } catch { } finally { if (this.TcpClient != null) { this.TcpClient.Close(); } this.IsConnected = false; if (this.Disconnected != null) { this.Disconnected(); } } }
private void PlaybackRecv() { try { NetworkStream nstream = TcpClientLocal.GetStream(); int connection = 0; bool doLoop = true, obtainedXteaKey = false; while (doLoop) { Objects.Packet p = Objects.Packet.GetNextPacket(nstream); if (p.Length == 0) { break; } if (!obtainedXteaKey) { if (Client.TibiaVersion >= 770) { this.XteaKey = new uint[4]; for (int i = 0; i < 4; i++) { this.XteaKey[i] = Memory.ReadUInt(Addresses.Client.XTEAKey + i * 4); } } obtainedXteaKey = true; } connection = Memory.ReadByte(Addresses.Client.Connection); switch ((Enums.Connection)connection) { case Enums.Connection.WaitingForCharacterList: if (this.AutoPlayback) { p = new Objects.Packet(); p.AddByte(0x64); p.AddByte(1); p.AddString("TibiaCam"); p.AddString(CurrentRecording.TibiaVersion); p.AddBytes(IPAddress.Loopback.GetAddressBytes()); p.AddUInt16(this.ListenerPort); p.AddUInt16(0); // premium days p.AddLength(); if (Client.TibiaVersion >= 770) { p.XteaEncrypt(this.XteaKey); p.AddLength(); } p.Send(this.TcpClientLocal); doLoop = false; break; } List <string> files = new List <string>(); foreach (string kcam in System.IO.Directory.GetFiles(System.Windows.Forms.Application.StartupPath + "\\", "*.kcam")) { files.Add(kcam); } foreach (string iryontcam in System.IO.Directory.GetFiles(System.Windows.Forms.Application.StartupPath + "\\", "*.cam")) { files.Add(iryontcam); } if (Settings.Tibiacam.Playback.SupportTibiaMovies) { foreach (string tmv in System.IO.Directory.GetFiles(System.Windows.Forms.Application.StartupPath + "\\", "*.tmv")) { files.Add(tmv); } } files.Sort(); string warning = string.Empty; int count = files.Count; if (files.Count > 255) { warning = "\n\nWarning! There are " + files.Count + " recordings.\nOnly the first 255 recordings are listed."; count = 255; } p = new Objects.Packet(); p.AddByte(0x14); // motd type // motd id is 0-255, which is followed by a newline (\n) p.AddString((byte)new Random().Next(255) + "\nThank you for using Tibianic Tools.\nhttp://code.google.com/p/tibianic-tools/\nhttp://tibianic.org/" + warning); p.AddByte(0x64); // character list type List <Recording> recordings = new List <Recording>(); for (int i = 0; i < count; i++) { Recording r = new Recording(files[i], Settings.Tibiacam.Playback.ReadMetaData, false, false); if (!r.isCorrupt) { recordings.Add(r); } } p.AddByte((byte)count); // amount of characters foreach (Recording r in recordings) { p.AddString(r.FileNameShort); // character name p.AddString(r.TibiaVersion); // server name p.AddBytes(IPAddress.Loopback.GetAddressBytes()); // server ipv4 (in this case: 127.0.0.1) p.AddUInt16(this.ListenerPort); // server port } p.AddUInt16((ushort)count); // premium days p.AddLength(); if (Client.TibiaVersion >= 770) { p.XteaEncrypt(this.XteaKey); p.AddLength(); } p.Send(TcpClientLocal); doLoop = false; break; case Enums.Connection.ConnectingGameServer: if (this.AutoPlayback) { this.threadPlaybackSend = new Thread(new ThreadStart(PlaybackSend)); this.threadPlaybackSend.Start(); break; } CharacterList.Player player = CharacterList.GetPlayers()[Memory.ReadByte(Addresses.Charlist.SelectedIndex)]; if (!System.IO.File.Exists(player.Name)) { System.Windows.Forms.MessageBox.Show(player.Name + "\ndoes not exist", "Error"); doLoop = false; break; } Recording rec = new Recording(player.Name, true, true, Settings.Tibiacam.Playback.doPlayMouse); if (rec.isCorrupt || !rec.ContainsData()) { System.Windows.Forms.MessageBox.Show(player.Name + "\nappears to be corrupt or it doesn't contain any data", "Error"); doLoop = false; break; } this.CurrentRecording = rec; while (this.threadPlaybackSend != null && this.threadPlaybackSend.IsAlive) { this.threadPlaybackSend.Abort(); Thread.Sleep(100); } while (this.threadPlaybackSendMouse != null && this.threadPlaybackSendMouse.IsAlive) { this.threadPlaybackSendMouse.Abort(); Thread.Sleep(100); } this.threadPlaybackSend = new Thread(new ThreadStart(PlaybackSend)); this.threadPlaybackSend.Start(); break; case Enums.Connection.Online: ushort len = p.GetUInt16(); if (Client.TibiaVersion >= 770) { p = p.XteaDecrypt(this.XteaKey, 2); if (p == null) { break; } p.GetPosition = 2; } byte type = p.GetByte(); switch (type) { case 0x14: // logout while (this.threadPlaybackSend != null && this.threadPlaybackSend.IsAlive) { this.threadPlaybackSend.Abort(); Thread.Sleep(100); } this.TcpClientLocal.Close(); return; case 0x96: // player speech byte speechType = p.GetByte(); if (speechType < 1 || speechType > 3) { break; } string msg = p.GetString().ToLower(); string[] msgSplit = msg.Split(' '); p = new Objects.Packet(); switch (msgSplit[0]) { case "info": p.AddByte(0xb4); p.AddByte(22); p.AddString("Tibia version: " + this.CurrentRecording.TibiaVersion + "\nRecorder version: " + this.CurrentRecording.RecorderVersion + "\n# of packets: " + this.CurrentRecording.Packets.Count); p.AddLength(); if (Client.TibiaVersion >= 770) { p.XteaEncrypt(this.XteaKey, p.GetPosition); p.AddLength(); } p.Send(this.TcpClientLocal); break; case "goto": TimeSpan ts; if (!TimeSpan.TryParse(msgSplit[1], out ts)) { break; } this.FastForward(ts); break; case "pause": this.PlaybackSpeed = 0; break; case "resume": this.PlaybackSpeed = 1; break; } break; } break; } } if (TcpClientLocal != null) { TcpClientLocal.Close(); } } catch (Exception ex) { System.Windows.Forms.MessageBox.Show(ex.Message + "\n" + ex.StackTrace); if (TcpClientLocal != null) { TcpClientLocal.Close(); } } }
/// <summary> /// Handles the local Tibia client connection. Should be run on its own thread. /// </summary> private void HandleTcpLocal() { try { if (TcpClientLocal == null) { return; } NetworkStream nstream = TcpClientLocal.GetStream(); int connection = 0; bool obtainedXteaKey = false; while (true) { Objects.Packet p = Objects.Packet.GetNextPacket(nstream); if (p.Length == 0) { break; } if (!obtainedXteaKey) { if (Client.TibiaVersion >= 770) { this.XteaKey = new uint[4]; for (int i = 0; i < 4; i++) { this.XteaKey[i] = Memory.ReadUInt(Addresses.Client.XTEAKey + i * 4); } } obtainedXteaKey = true; } if (connection != 8) { connection = Memory.ReadByte(Addresses.Client.Connection); if (connection == 6) // connecting to gameserver { try { byte index = Memory.ReadByte(Addresses.Charlist.SelectedIndex); if (index < 0 || index >= this.CachedCharacterList.Count) { break; // invalid index } CharacterList.Player player = this.CachedCharacterList[index]; TcpClientServer = new TcpClient(player.IP, player.Port); Thread t = new Thread(new ThreadStart(HandleTcpServer)); t.Start(); Thread.Sleep(20); // give thread time to start } catch { break; } } else if (connection > 0 && connection < 6) // connecting to login server, not sure exactly what value it should be { try { this.TcpClientServer = new TcpClient(this.ServerInfo.IP, this.ServerInfo.Port); Thread t = new Thread(new ThreadStart(HandleTcpServer)); t.Start(); Thread.Sleep(20); // give thread time to start } catch { break; } // couldn't connect to server } } p.Send(this.TcpClientServer); try { if (Client.TibiaVersion >= 770) { p = p.XteaDecrypt(this.XteaKey, 2); } ushort len = p.GetUInt16(); byte packetType = p.GetByte(); if (!Settings.Tibiacam.Recorder.Filters.OutgoingPrivateMessages && packetType == 0x96 && Client.TibiaVersion == 740) { if (p.GetByte() != 0x04) { continue; } Objects.Packet pm = new Objects.Packet(); pm.AddByte((byte)Addresses.Enums.IncomingPacketTypes.CreatureSpeech); string recipient = p.GetString(); pm.AddString(recipient); pm.AddByte(0x04); string msg = p.GetString(); pm.AddString("ยป " + msg); pm.AddLength(); //Objects.Packet temp = new Objects.Packet(); //temp.AddUInt32((uint)this.RecordingStopwatch.ElapsedMilliseconds); //temp.AddUInt32((uint)pm.Length); //temp.AddBytes(pm.ToBytes()); CurrentRecording.Packets.Add(new Recording.Packet((uint)this.RecordingStopwatch.ElapsedMilliseconds, pm.ToBytes())); } } catch { } } if (this.TcpClientLocal != null) { this.TcpClientLocal.Close(); } if (this.TcpClientServer != null) { this.TcpClientServer.Close(); } } catch (Exception ex) { System.Windows.Forms.MessageBox.Show(ex.Message + "\n" + ex.StackTrace); } }
/// <summary> /// Loads data (waypoints, loot, targets, settings) from a file. /// </summary> /// <param name="file">The file to load.</param> /// <returns>Returns true if file is found and is valid, false if not.</returns> public bool Load(FileInfo file) { if (!file.Exists) return false; if (file.Extension.ToLower() == ".cs") { Objects.Script script = new Objects.Script(this.Client, file); this.Clear(); script.Run(); return true; } else { Objects.Packet p = new Objects.Packet(); using (FileStream fstream = file.OpenRead()) { byte[] buffer = new byte[fstream.Length]; fstream.Read(buffer, 0, buffer.Length); p = new Objects.Packet(buffer); } // read metadata ushort version = p.GetUInt16(); if (this.Load(version, p)) return true; this.RemoveAllWaypoints(); this.RemoveAllLoot(); this.RemoveAllTargets(); this.CurrentSettings.LoadDefaults(); return false; } }
/// <summary> /// Will attempt to load object properties. /// </summary> /// <exception cref="Exception"></exception> private void LoadObjectProperties() { byte itemIdOffset = 100; string localDatFile = "ObjectProperties" + this.TibiaVersion + ".dat"; string datPath = this.TibiaProcess.MainModule.FileName; datPath = datPath.Substring(0, datPath.LastIndexOf(Path.DirectorySeparatorChar) + 1) + "Tibia.dat"; if (!File.Exists(datPath)) { throw new Exception("Could not load object properties since Tibia.dat could not be found in the client's directory." + "\nWithout object properties, modules like cavebot will not function properly."); } using (BinaryReader readerDatFile = new BinaryReader(File.OpenRead(datPath))) { bool queryServer = false, queryClient = false; System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] datHash = md5.ComputeHash(readerDatFile.BaseStream); readerDatFile.BaseStream.Position = 4; // first 4 bytes is file signature if (File.Exists(localDatFile)) { using (BinaryReader readerLocalFile = new BinaryReader(File.OpenRead(localDatFile))) { if (datHash.DataEquals(readerLocalFile.ReadBytes(datHash.Length))) { ushort count = readerLocalFile.ReadUInt16(); this.ObjectProperties = new Objects.ObjectProperties[count]; for (ushort i = 0; i < count; i++) { try { Objects.ObjectProperties objProperty = new Objects.ObjectProperties((ushort)(i + itemIdOffset)); objProperty.Flags = readerLocalFile.ReadUInt32(); this.ObjectProperties[i] = objProperty; if (this.ObjectPropertyRead != null) { this.ObjectPropertyRead(i, count); } } catch { queryServer = true; break; } } if (!queryClient && !queryServer) { if (this.ObjectPropertiesFinishedReading != null) { this.ObjectPropertiesFinishedReading(count); } return; } } else { queryServer = true; } } } else { queryServer = true; } if (queryServer) { try { TcpClient tc = new TcpClient(this.ObjectPropertiesServerIP, this.ObjectPropertiesServerPort); Objects.Packet p = new Objects.Packet(); p.AddBytes(datHash); p.AddLength(); p.Send(tc); p = Objects.Packet.GetNextPacket(tc.GetStream()); if (p.Length == 0) { queryClient = true; } else { p.GetUInt16(); byte[] hash = p.GetBytes(datHash.Length); ushort count = p.GetUInt16(); byte[] data = p.GetBytes(count * 4); tc.Close(); this.ObjectProperties = new Objects.ObjectProperties[count]; for (ushort i = 0; i < count; i++) { var objProps = new Objects.ObjectProperties((ushort)(itemIdOffset + i)); objProps.Flags = BitConverter.ToUInt32(data, i * 4); this.ObjectProperties[i] = objProps; if (this.ObjectPropertyRead != null) { this.ObjectPropertyRead(i, count); } } if (this.ObjectPropertiesFinishedReading != null) { this.ObjectPropertiesFinishedReading(count); } this.SaveObjectProperties(datHash); return; } } catch { queryClient = true; } } if (queryClient) { try { ushort itemCount = (ushort)(readerDatFile.ReadUInt16() - itemIdOffset); this.ObjectProperties = new Objects.ObjectProperties[itemCount]; for (int i = 0; i < itemCount; i++) { Objects.ObjectProperties objProperties = new ObjectProperties((ushort)(i + itemIdOffset)); switch (this.TibiaVersion) { case 772: if (this.Packets.GetObjectProperty((ushort)(i + itemIdOffset), (byte)Enums.ObjectProperties772.HasAutomapColor)) { objProperties.AddFlag(Enums.ObjectPropertiesFlags.HasAutomapColor); } if (this.Packets.GetObjectProperty((ushort)(i + itemIdOffset), (byte)Enums.ObjectProperties772.HasHelpLens)) { objProperties.AddFlag(Enums.ObjectPropertiesFlags.HasHelpLens); } if (this.Packets.GetObjectProperty((ushort)(i + itemIdOffset), (byte)Enums.ObjectProperties772.IsBlocking)) { objProperties.AddFlag(Enums.ObjectPropertiesFlags.IsBlocking); } if (this.Packets.GetObjectProperty((ushort)(i + itemIdOffset), (byte)Enums.ObjectProperties772.IsContainer)) { objProperties.AddFlag(Enums.ObjectPropertiesFlags.IsContainer); } if (this.Packets.GetObjectProperty((ushort)(i + itemIdOffset), (byte)Enums.ObjectProperties772.IsFloorChange)) { objProperties.AddFlag(Enums.ObjectPropertiesFlags.IsFloorChange); } if (this.Packets.GetObjectProperty((ushort)(i + itemIdOffset), (byte)Enums.ObjectProperties772.IsFluidContainer)) { objProperties.AddFlag(Enums.ObjectPropertiesFlags.IsFluidContainer); } if (this.Packets.GetObjectProperty((ushort)(i + itemIdOffset), (byte)Enums.ObjectProperties772.IsGround)) { objProperties.AddFlag(Enums.ObjectPropertiesFlags.IsGround); } if (this.Packets.GetObjectProperty((ushort)(i + itemIdOffset), (byte)Enums.ObjectProperties772.IsHangable)) { objProperties.AddFlag(Enums.ObjectPropertiesFlags.IsHangable); } if (this.Packets.GetObjectProperty((ushort)(i + itemIdOffset), (byte)Enums.ObjectProperties772.IsImmobile)) { objProperties.AddFlag(Enums.ObjectPropertiesFlags.IsImmobile); } if (this.Packets.GetObjectProperty((ushort)(i + itemIdOffset), (byte)Enums.ObjectProperties772.IsAlwaysTopUse)) { objProperties.AddFlag(Enums.ObjectPropertiesFlags.IsAlwaysTopUse); } if (this.Packets.GetObjectProperty((ushort)(i + itemIdOffset), (byte)Enums.ObjectProperties772.IsMissileBlocking)) { objProperties.AddFlag(Enums.ObjectPropertiesFlags.IsMissileBlocking); } if (this.Packets.GetObjectProperty((ushort)(i + itemIdOffset), (byte)Enums.ObjectProperties772.IsPathBlocking)) { objProperties.AddFlag(Enums.ObjectPropertiesFlags.IsPathBlocking); } if (this.Packets.GetObjectProperty((ushort)(i + itemIdOffset), (byte)Enums.ObjectProperties772.IsPickupable)) { objProperties.AddFlag(Enums.ObjectPropertiesFlags.IsPickupable); } if (this.Packets.GetObjectProperty((ushort)(i + itemIdOffset), (byte)Enums.ObjectProperties772.IsSplash)) { objProperties.AddFlag(Enums.ObjectPropertiesFlags.IsSplash); } if (this.Packets.GetObjectProperty((ushort)(i + itemIdOffset), (byte)Enums.ObjectProperties772.IsStackable)) { objProperties.AddFlag(Enums.ObjectPropertiesFlags.IsStackable); } //if (this.Packets.GetObjectProperty((ushort)(i + itemIdOffset), (byte)Enums.ObjectProperties772.IsTopOrder1)) objProperties.AddFlag(Enums.ObjectPropertiesFlags.IsTopOrder1); if (this.Packets.GetObjectProperty((ushort)(i + itemIdOffset), (byte)Enums.ObjectProperties772.IsTopOrder2)) { objProperties.AddFlag(Enums.ObjectPropertiesFlags.IsTopUseIfOnly); } if (this.Packets.GetObjectProperty((ushort)(i + itemIdOffset), (byte)Enums.ObjectProperties772.IsTopOrder3)) { objProperties.AddFlag(Enums.ObjectPropertiesFlags.IsWalkThrough); } if (this.Packets.GetObjectProperty((ushort)(i + itemIdOffset), (byte)Enums.ObjectProperties772.IsUsable)) { objProperties.AddFlag(Enums.ObjectPropertiesFlags.IsUsable); } break; } this.ObjectProperties[i] = objProperties; if (this.ObjectPropertyRead != null) { this.ObjectPropertyRead(i + 1, itemCount); } } if (this.ObjectPropertiesFinishedReading != null) { this.ObjectPropertiesFinishedReading(itemCount); } this.SaveObjectProperties(datHash); } catch (Exception ex) { if (this.ObjectPropertiesFailed != null) { this.ObjectPropertiesFailed(ex); } } } } }