private void PlaybackSendMouse() { try { Recording rec = this.CurrentRecording; if (rec == null) { return; } MouseRecording mouseRec = null; if (this.CurrentRecording.MouseRecording != null) { mouseRec = this.CurrentRecording.MouseRecording; } else { return; } mouseRec.CurrentIndex = 0; while (this.IsRunning && this.TcpClientLocal.Connected) { if (this.threadPlaybackSend == null || !this.threadPlaybackSend.IsAlive) { return; } while (this.PlaybackSpeed <= 0) { Thread.Sleep(200); continue; } //int currentTime = mouseRec.Seek(this.CurrentRecording.TimePassed); //int mouseTime = i * mouseRec.Interval; Objects.Packet p = mouseRec.Packets[mouseRec.CurrentIndex]; p.GetPosition = 0; MouseRecording.DataType dt = (MouseRecording.DataType)p.GetByte(); switch (dt) { case MouseRecording.DataType.ClientWindowChange: break; case MouseRecording.DataType.GameWindowChange: break; case MouseRecording.DataType.MouseXY: int percentX = p.GetByte(), percentY = p.GetByte(); if (percentX == 0 && percentY == 0) { break; } if (WinApi.GetForegroundWindow() != Client.Tibia.MainWindowHandle) { break; } System.Drawing.Point point = mouseRec.CalculateScreenMouseXY(new System.Drawing.Point(percentX, percentY)); System.Windows.Forms.Cursor.Position = point; break; } p.GetPosition = 0; mouseRec.CurrentIndex++; Thread.Sleep((int)(mouseRec.Interval / this.PlaybackSpeed)); } } catch { } }
/// <summary> /// Constructor for playback. /// </summary> /// <param name="fileName">Relative or absolute path (including file name).</param> /// <param name="readMetaData">If true, will read data like Tibia version, recorder version and duration.</param> /// <param name="readPackets">If true, will buffer all packets to memory.</param> /// <param name="readMouseMovements">If true, will try to read a mouse movement file (*.kcammouse) with the same file name as the recording.</param> internal Recording(string fileName, bool readMetaData, bool readPackets, bool readMouseMovements) { this.Type = RecordingType.Playback; if (File.Exists(fileName)) { this.Packets = new List <Recording.Packet>(); if (fileName.EndsWith(".kcam")) { Recorder = Enums.Recorder.TibianicTools; } else if (fileName.EndsWith(".tmv")) { Recorder = Enums.Recorder.TibiaMovie; } else if (fileName.EndsWith(".cam")) { Recorder = Enums.Recorder.IryontCam; } else { return; } FileName = fileName; RecorderVersion = "?"; TibiaVersion = "?"; Duration = 0; //if (fileName.Contains("\\")) { FileNameShort = fileName.Substring(fileName.LastIndexOf('\\') + 1); } //else { FileNameShort = fileName; } if (readMetaData || readPackets || readMouseMovements) { switch (this.Recorder) { case Enums.Recorder.IryontCam: try { using (FileStream fstream = File.OpenRead(this.FileName)) { using (BinaryReader reader = new BinaryReader(fstream)) { if (readPackets) { uint tickFirst = 0; // add first packet tickFirst = (uint)reader.ReadUInt64(); ushort len = reader.ReadUInt16(); byte[] data = new byte[len + 2]; Array.Copy(BitConverter.GetBytes(len), data, 2); byte[] packet = reader.ReadBytes(len); Array.Copy(packet, 0, data, 2, packet.Length); this.Packets.Add(new Recording.Packet(0, data)); while (reader.BaseStream.Position < reader.BaseStream.Length) { uint tick = (uint)reader.ReadUInt64() - tickFirst; len = reader.ReadUInt16(); data = new byte[len + 2]; Array.Copy(BitConverter.GetBytes(len), data, 2); packet = reader.ReadBytes(len); Array.Copy(packet, 0, data, 2, packet.Length); this.Packets.Add(new Recording.Packet(tick, data)); } Recording.Packet lastPacket = this.Packets[this.Packets.Count - 1]; this.Duration = lastPacket.Time; } } } } catch { this.isCorrupt = true; } break; case Enums.Recorder.TibiaMovie: /*using (FileStream stream = File.OpenRead(fileName)) * { * if (readMetaData) * { * byte[] metaData = new byte[8]; * stream.Read(metaData, 0, 8); * metaData = Utils.TibiaCam.Zlib.Decompress(metaData); * RecorderVersion = BitConverter.ToUInt16(metaData, 0).ToString(); * TibiaVersion = BitConverter.ToUInt16(metaData, 2).ToString(); * Duration = BitConverter.ToUInt32(metaData, 4); * } * if (readPackets) * { * byte[] buffer = new byte[stream.Length - 8]; * if (!readMetaData) stream.Position += 8; * stream.Read(buffer, 0, buffer.Length); * Utils.TibiaCam.Zlib.Decompress(buffer); * Packets = Utils.TibiaCam.Zlib.BytesToPacket(Utils.TibiaCam.Zlib.Decompress(buffer)); * } * stream.Close(); * }*/ break; case Enums.Recorder.TibianicTools: if (readMouseMovements) { string mouseFileName = fileName + "mouse"; if (File.Exists(mouseFileName)) { try { this.MouseRecording = new MouseRecording(mouseFileName); } catch { this.MouseRecording = null; } } } try { Stream stream = Utils.TibiaCam.DecompressCamToStream(fileName); int firstByte = stream.ReadByte(); stream.Position = 0; if (firstByte == (int)'T') // true for 1.2 and older { isOld = true; List <string> strings = new List <string>(); StreamReader reader = new StreamReader(stream); TibiaVersion = reader.ReadLine().Replace("TibiaVersion=", ""); RecorderVersion = reader.ReadLine().Replace("TibiaCamVersion=", ""); Duration = (uint)double.Parse(reader.ReadLine().Replace("TotalRunningTime=", "")); if (readPackets) { while (true) { string line = reader.ReadLine(); if (line == null || line.Length == 0) { break; } strings.Add(line); } stream.Close(); stream.Dispose(); List <Recording.Packet> packets = new List <Recording.Packet>(); foreach (string line in strings) { string temp = line; uint sleep = uint.Parse(temp.Substring(0, temp.IndexOf(':'))); temp = temp.Remove(0, temp.IndexOf(':') + 1); string[] split = temp.Split(' '); Objects.Packet packet = new Objects.Packet(); for (int j = 0; j < split.Length; j++) { packet.AddByte(byte.Parse(split[j], System.Globalization.NumberStyles.AllowHexSpecifier)); } packet.GetPosition = 0; packets.Add(new Recording.Packet(sleep, packet.ToBytes())); } Packets = packets; } } else { isOld = false; BinaryReader reader = new BinaryReader(stream); byte[] metadata = new byte[8]; // 2 bytes TibiaVersion, 2 bytes CamVersion, 4 bytes RunningLength(ms) reader.Read(metadata, 0, 8); // fill metadata if (readMetaData) { TibiaVersion = metadata[0] + "." + metadata[1]; RecorderVersion = metadata[2] + "." + metadata[3]; Duration = BitConverter.ToUInt32(metadata, 4); } if (readPackets) { List <Recording.Packet> packets = new List <Recording.Packet>(); while (reader.BaseStream.Position < reader.BaseStream.Length) { uint sleep = reader.ReadUInt32(); uint len = reader.ReadUInt32(); // should be changed to UInt16 in future versions as packets never exceed 65k bytes // merge split packets ushort packetLen = reader.ReadUInt16(); if (packetLen > len - 2) { Objects.Packet p = new Objects.Packet(); reader.BaseStream.Position += 4; p.AddUInt16(packetLen); p.AddBytes(reader.ReadBytes((int)len - 2)); uint totalBytesRead = len - 2; while (totalBytesRead < packetLen) { reader.ReadUInt32(); // sleep, not needed len = reader.ReadUInt32(); p.AddBytes(reader.ReadBytes((int)len)); totalBytesRead += len; } packets.Add(new Recording.Packet(sleep, p.ToBytes())); } else { reader.BaseStream.Position -= 2; packets.Add(new Recording.Packet(sleep, reader.ReadBytes((int)len))); } } Packets = packets; // if duration is 0, get duration from last packet if (this.Duration == 0) { Recording.Packet p = this.Packets[this.Packets.Count - 1]; this.Duration = p.Time; } } reader.Close(); stream.Close(); stream.Dispose(); if (readMouseMovements) { string name = fileName.Substring(0, fileName.LastIndexOf('.')); name += ".kcammouse"; if (File.Exists(name)) { MouseRecording = new MouseRecording(name); } else { MouseRecording = null; } } } } catch { isCorrupt = true; } break; } } } }
private void PlaybackSend() { try { Recording.Packet p; this.CurrentPacket = 0; this.DoFastForward = false; uint timeOld = 0, timeNew = 0; bool hasShownInfo = false; this.CurrentRecording.TimePassed = 0; if (this.CurrentRecording.MouseRecording != null) { while (this.threadPlaybackSendMouse != null && this.threadPlaybackSendMouse.IsAlive) { this.threadPlaybackSendMouse.Abort(); Thread.Sleep(100); } this.threadPlaybackSendMouse = new Thread(new ThreadStart(this.PlaybackSendMouse)); threadPlaybackSendMouse.Start(); } try { while (this.CurrentPacket < this.CurrentRecording.Packets.Count) { if (!this.TcpClientLocal.Connected) { return; } if (this.DoFastForward) { if (TimeSpan.FromMilliseconds(this.CurrentRecording.TimePassed) > this.FastForwardTo) { this.CurrentPacket = 0; this.CurrentRecording.TimePassed = 0; } while (this.CurrentPacket < this.CurrentRecording.Packets.Count && this.CurrentRecording.TimePassed < this.FastForwardTo.TotalMilliseconds) { p = this.CurrentRecording.Packets[this.CurrentPacket].Clone(); this.CurrentRecording.TimePassed = p.Time; //if (this.CurrentRecording.Recorder == Enums.Recorder.TibianicTools) p.GetPosition += 4; //else if (this.CurrentRecording.Recorder == Enums.Recorder.TibiaMovie) p.GetPosition += 2; if (Client.TibiaVersion >= 770) { p = p.XteaEncrypt(this.XteaKey, 0); } p.Send(this.TcpClientLocal); this.CurrentPacket++; } this.DoFastForward = false; hasShownInfo = false; } else if (this.PlaybackSpeed <= 0) { Thread.Sleep(200); continue; } if (/*Client.TibiaVersion == 740 && */ !hasShownInfo && this.CurrentPacket > 3 && Client.Player.Connected) { Thread.Sleep(100); Objects.Packet packet = new Objects.Packet(); packet.AddByte(0xb4); // text message packet.AddByte(16); // orange color packet.AddString("Welcome to a Tibianic Tools recording!\nKeyboard hotkeys:\nArrow keys - change playback speed\nBackspace - rewind 1 minute"); packet.AddByte(0xb4); packet.AddByte(16); packet.AddString("Text commands:\ninfo - show recording information\ngoto hh:mm:ss - rewinds/fast forwards to given time\npause - pauses playback\nresume - resumes playback"); packet.AddLength(); if (Client.TibiaVersion >= 770) { packet.XteaEncrypt(this.XteaKey, packet.GetPosition); packet.AddLength(); } packet.Send(this.TcpClientLocal); hasShownInfo = true; Thread.Sleep(20); } p = this.CurrentRecording.Packets[this.CurrentPacket].Clone(); this.CurrentRecording.TimePassed = p.Time; timeNew = this.CurrentRecording.TimePassed; int sleep = (int)((timeNew - timeOld) / this.PlaybackSpeed); //if (this.CurrentRecording.Recorder == Enums.Recorder.TibianicTools) p.GetPosition += 4; // length, not needed //else if (this.CurrentRecording.Recorder == Enums.Recorder.TibiaMovie) p.GetPosition += 2; // -||- // try-catch because Thread.Interrupt() will throw an exception try { if (sleep > 0) { Thread.Sleep(sleep); } } catch { } if (!this.TcpClientLocal.Connected) { return; } if (Client.TibiaVersion >= 770) { p = p.XteaEncrypt(this.XteaKey, 0); } p.Send(this.TcpClientLocal); if (this.CurrentRecording.MouseRecording != null) { MouseRecording mouseRec = this.CurrentRecording.MouseRecording; //int currentTime = mouseRec.Seek(this.CurrentRecording.TimePassed); int mouseTime = mouseRec.CurrentIndex * mouseRec.Interval; int timeMarginMax = mouseTime + 200, timeMarginMin = mouseTime - 200; if (timeNew >= timeMarginMax || timeNew <= timeMarginMin) { this.CurrentRecording.MouseRecording.CurrentIndex = this.CurrentRecording.MouseRecording.Seek(timeNew); } } timeOld = timeNew; this.CurrentPacket++; } } catch { } Thread.Sleep(3000); this.PlaybackSpeed = 1; WinApi.SetWindowText(Client.Tibia.MainWindowHandle, "Tibia"); if (TcpClientLocal != null) { TcpClientLocal.Close(); } if (this.DoKillAfterPlayback && !Client.Tibia.HasExited) { Client.Tibia.Kill(); } else { this.AutoPlayback = false; } } catch (Exception ex) { /*System.Windows.Forms.MessageBox.Show(ex.Message + "\n" + ex.StackTrace);*/ } }