├── .gitignore ├── BitBuffer.cs ├── DataTables.cs ├── DemoFile.cs ├── MainForm.Designer.cs ├── MainForm.cs ├── MainForm.resx ├── Packet.cs ├── Program.cs ├── Properties ├── AssemblyInfo.cs ├── Resources.Designer.cs ├── Resources.resx ├── Settings.Designer.cs └── Settings.settings ├── README.md ├── netdecode.csproj └── netdecode.sln /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.sln.docstates 8 | 9 | # Build results 10 | [Dd]ebug/ 11 | [Rr]elease/ 12 | *_i.c 13 | *_p.c 14 | *.ilk 15 | *.meta 16 | *.obj 17 | *.pch 18 | *.pdb 19 | *.pgc 20 | *.pgd 21 | *.rsp 22 | *.sbr 23 | *.tlb 24 | *.tli 25 | *.tlh 26 | *.tmp 27 | *.vspscc 28 | .builds 29 | 30 | # Visual C++ cache files 31 | ipch/ 32 | *.aps 33 | *.ncb 34 | *.opensdf 35 | *.sdf 36 | 37 | # Visual Studio profiler 38 | *.psess 39 | *.vsp 40 | 41 | # ReSharper is a .NET coding add-in 42 | _ReSharper* 43 | 44 | # Installshield output folder 45 | [Ee]xpress 46 | 47 | # DocProject is a documentation generator add-in 48 | DocProject/buildhelp/ 49 | DocProject/Help/*.HxT 50 | DocProject/Help/*.HxC 51 | DocProject/Help/*.hhc 52 | DocProject/Help/*.hhk 53 | DocProject/Help/*.hhp 54 | DocProject/Help/Html2 55 | DocProject/Help/html 56 | 57 | # Click-Once directory 58 | publish 59 | 60 | # Others 61 | [Bb]in 62 | [Oo]bj 63 | sql 64 | TestResults 65 | *.Cache 66 | ClientBin 67 | stylecop.* 68 | ~$* 69 | *.dbmdl 70 | Generated_Code #added for RIA/Silverlight projects 71 | 72 | # Backup & report files from converting an old project file to a newer 73 | # Visual Studio version. Backup files are not needed, because we have git ;-) 74 | _UpgradeReport_Files/ 75 | Backup*/ 76 | UpgradeLog*.XML -------------------------------------------------------------------------------- /BitBuffer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Runtime.InteropServices; 5 | 6 | namespace netdecode 7 | { 8 | class BitBuffer 9 | { 10 | readonly byte[] _buf; 11 | uint _pos; 12 | 13 | static readonly byte[] mtbl = { 0, 1, 3, 7, 15, 31, 63, 127, 255 }; 14 | 15 | public BitBuffer(byte[] data) 16 | { 17 | _buf = data; 18 | } 19 | 20 | public void Seek(uint bits) 21 | { 22 | _pos += bits; 23 | } 24 | 25 | public uint ReadBits(uint bits) 26 | { 27 | uint ret = 0; 28 | var left = bits; 29 | 30 | while (left > 0) 31 | { 32 | var idx = _pos >> 3; 33 | var bit = _pos & 7; 34 | var toget = Math.Min(8 - bit, left); 35 | 36 | var nib = (uint)(_buf[idx] >> (int)bit & mtbl[toget]); 37 | ret |= nib << (int)(bits - left); 38 | 39 | _pos += toget; 40 | left -= toget; 41 | } 42 | 43 | return ret; 44 | } 45 | 46 | public bool ReadBool() 47 | { 48 | return ReadBits(1) != 0; 49 | } 50 | 51 | [StructLayout(LayoutKind.Explicit)] 52 | struct UIntFloat 53 | { 54 | [FieldOffset(0)] 55 | public uint intvalue; 56 | [FieldOffset(0)] 57 | public float floatvalue; 58 | } 59 | 60 | public float ReadFloat() 61 | { 62 | return new UIntFloat { intvalue = ReadBits(32) }.floatvalue; 63 | } 64 | 65 | public string ReadString() 66 | { 67 | var temp = new List(); 68 | while (true) 69 | { 70 | var c = (byte)ReadBits(8); 71 | if (c == 0) 72 | break; 73 | temp.Add(c); 74 | } 75 | return Encoding.UTF8.GetString(temp.ToArray()); 76 | } 77 | 78 | public float ReadCoord() 79 | { 80 | var hasint = ReadBool(); 81 | var hasfract = ReadBool(); 82 | float value = 0; 83 | 84 | if (hasint || hasfract) 85 | { 86 | var sign = ReadBool(); 87 | if (hasint) 88 | value += ReadBits(14) + 1; 89 | if (hasfract) 90 | value += ReadBits(5) * (1 / 32f); 91 | if (sign) 92 | value = -value; 93 | } 94 | 95 | return value; 96 | } 97 | 98 | public float[] ReadVecCoord() 99 | { 100 | var hasx = ReadBool(); 101 | var hasy = ReadBool(); 102 | var hasz = ReadBool(); 103 | 104 | return new[] { 105 | hasx ? ReadCoord() : 0, 106 | hasy ? ReadCoord() : 0, 107 | hasz ? ReadCoord() : 0 108 | }; 109 | } 110 | 111 | public uint BitsLeft() 112 | { 113 | return (uint)(_buf.Length << 3) - _pos; 114 | } 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /DataTables.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Windows.Forms; 4 | 5 | namespace netdecode 6 | { 7 | class DataTables 8 | { 9 | enum SendPropType : uint 10 | { 11 | Int = 0, 12 | Float, 13 | Vector, 14 | VectorXY, 15 | String, 16 | Array, 17 | DataTable, 18 | Int64 19 | } 20 | 21 | [Flags] 22 | enum SendPropFlags : uint 23 | { 24 | UNSIGNED = 1, 25 | COORD = 2, 26 | NOSCALE = 4, 27 | ROUNDDOWN = 8, 28 | ROUNDUP = 16, 29 | NORMAL = 32, 30 | EXCLUDE = 64, 31 | XYZE = 128, 32 | INSIDEARRAY = 256, 33 | PROXY_ALWAYS_YES = 512, 34 | CHANGES_OFTEN = 1024, 35 | IS_A_VECTOR_ELEM = 2048, 36 | COLLAPSIBLE = 4096, 37 | COORD_MP = 8192, 38 | COORD_MP_LOWPRECISION = 16384, 39 | COORD_MP_INTEGRAL = 32768 40 | } 41 | 42 | static void ParseTables(BitBuffer bb, TreeNode node) 43 | { 44 | while (bb.ReadBool()) 45 | { 46 | bool needsdecoder = bb.ReadBool(); 47 | var dtnode = node.Nodes.Add(bb.ReadString()); 48 | if (needsdecoder) dtnode.Text += "*"; 49 | 50 | var numprops = bb.ReadBits(10); 51 | dtnode.Text += " (" + numprops + " props)"; 52 | 53 | for (int i = 0; i < numprops; i++) 54 | { 55 | var type = (SendPropType)bb.ReadBits(5); 56 | var propnode = dtnode.Nodes.Add("DPT_" + type + " " + bb.ReadString()); 57 | var flags = (SendPropFlags)bb.ReadBits(16); 58 | 59 | if (type == SendPropType.DataTable || (flags & SendPropFlags.EXCLUDE) != 0) 60 | propnode.Text += " : " + bb.ReadString(); 61 | else 62 | { 63 | if (type == SendPropType.Array) 64 | propnode.Text += "[" + bb.ReadBits(10) + "]"; 65 | else 66 | { 67 | bb.Seek(64); 68 | propnode.Text += " (" + bb.ReadBits(7) + " bits)"; 69 | } 70 | } 71 | } 72 | } 73 | } 74 | 75 | static void ParseClassInfo(BitBuffer bb, TreeNode node) 76 | { 77 | var classes = bb.ReadBits(16); 78 | 79 | for (int i = 0; i < classes; i++) 80 | node.Nodes.Add("[" + bb.ReadBits(16) + "] " + bb.ReadString() + " (" + bb.ReadString() + ")"); 81 | } 82 | 83 | public static void Parse(byte[] data, TreeNode node) 84 | { 85 | var bb = new BitBuffer(data); 86 | ParseTables(bb, node.Nodes.Add("Send tables")); 87 | ParseClassInfo(bb, node.Nodes.Add("Class info")); 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /DemoFile.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.IO; 5 | using System.Windows.Forms; 6 | 7 | namespace netdecode 8 | { 9 | class DemoFile 10 | { 11 | public struct DemoInfo 12 | { 13 | public int DemoProtocol, NetProtocol, TickCount, FrameCount, SignonLength; 14 | public string ServerName, ClientName, MapName, GameDirectory; 15 | public float Seconds; 16 | } 17 | 18 | public enum MessageType 19 | { 20 | Signon = 1, 21 | Packet, 22 | SyncTick, 23 | ConsoleCmd, 24 | UserCmd, 25 | DataTables, 26 | Stop, 27 | // CustomData, // L4D2 28 | StringTables 29 | } 30 | 31 | public class DemoMessage 32 | { 33 | public MessageType Type; 34 | public int Tick; 35 | public byte[] Data; 36 | } 37 | 38 | Stream fstream; 39 | public DemoInfo Info; 40 | public List Messages; 41 | 42 | public DemoFile(Stream s) 43 | { 44 | fstream = s; 45 | Messages = new List(); 46 | Parse(); 47 | } 48 | 49 | void Parse() 50 | { 51 | var reader = new BinaryReader(fstream); 52 | var id = reader.ReadBytes(8); 53 | 54 | if (Encoding.ASCII.GetString(id) != "HL2DEMO\0") 55 | throw new Exception("Unsupported file format."); 56 | 57 | Info.DemoProtocol = reader.ReadInt32(); 58 | if (Info.DemoProtocol >> 8 > 0) 59 | throw new Exception("Demos recorded on L4D branch games are currently unsupported."); 60 | 61 | Info.NetProtocol = reader.ReadInt32(); 62 | 63 | Info.ServerName = new string(reader.ReadChars(260)).Replace("\0", ""); 64 | Info.ClientName = new string(reader.ReadChars(260)).Replace("\0", ""); 65 | Info.MapName = new string(reader.ReadChars(260)).Replace("\0", ""); 66 | Info.GameDirectory = new string(reader.ReadChars(260)).Replace("\0", ""); 67 | 68 | Info.Seconds = reader.ReadSingle(); 69 | Info.TickCount = reader.ReadInt32(); 70 | Info.FrameCount = reader.ReadInt32(); 71 | 72 | Info.SignonLength = reader.ReadInt32(); 73 | 74 | while (true) 75 | { 76 | var msg = new DemoMessage {Type = (MessageType) reader.ReadByte()}; 77 | if (msg.Type == MessageType.Stop) 78 | break; 79 | msg.Tick = reader.ReadInt32(); 80 | 81 | switch (msg.Type) 82 | { 83 | case MessageType.Signon: 84 | case MessageType.Packet: 85 | case MessageType.ConsoleCmd: 86 | case MessageType.UserCmd: 87 | case MessageType.DataTables: 88 | case MessageType.StringTables: 89 | if (msg.Type == MessageType.Packet || msg.Type == MessageType.Signon) 90 | reader.BaseStream.Seek(0x54, SeekOrigin.Current); // command/sequence info 91 | else if (msg.Type == MessageType.UserCmd) 92 | reader.BaseStream.Seek(0x4, SeekOrigin.Current); // unknown 93 | msg.Data = reader.ReadBytes(reader.ReadInt32()); 94 | break; 95 | case MessageType.SyncTick: 96 | msg.Data = new byte[0]; // lol wut 97 | break; 98 | default: 99 | throw new Exception("Unknown demo message type encountered."); 100 | } 101 | 102 | Messages.Add(msg); 103 | } 104 | } 105 | } 106 | 107 | public class UserCmd 108 | { 109 | /* 110 | static string ParseButtons(uint buttons) 111 | { 112 | string res = "(none)"; 113 | // TODO: IMPLEMENT 114 | return res; 115 | } 116 | */ 117 | 118 | public static void ParseIntoTreeNode(byte[] data, TreeNode node) 119 | { 120 | var bb = new BitBuffer(data); 121 | if (bb.ReadBool()) node.Nodes.Add("Command number: " + bb.ReadBits(32)); 122 | if (bb.ReadBool()) node.Nodes.Add("Tick count: " + bb.ReadBits(32)); 123 | if (bb.ReadBool()) node.Nodes.Add("Viewangle pitch: " + bb.ReadFloat()); 124 | if (bb.ReadBool()) node.Nodes.Add("Viewangle yaw: " + bb.ReadFloat()); 125 | if (bb.ReadBool()) node.Nodes.Add("Viewangle roll: " + bb.ReadFloat()); 126 | if (bb.ReadBool()) node.Nodes.Add("Foward move: " + bb.ReadFloat()); 127 | if (bb.ReadBool()) node.Nodes.Add("Side move: " + bb.ReadFloat()); 128 | if (bb.ReadBool()) node.Nodes.Add("Up move: " + bb.ReadFloat().ToString()); 129 | if (bb.ReadBool()) node.Nodes.Add("Buttons: 0x" + bb.ReadBits(32).ToString("X8")); 130 | if (bb.ReadBool()) node.Nodes.Add("Impulse: " + bb.ReadBits(8)); 131 | // TODO: weaponselect/weaponsubtype, mousedx/dy 132 | } 133 | } 134 | 135 | } 136 | -------------------------------------------------------------------------------- /MainForm.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace netdecode 2 | { 3 | partial class MainForm 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm)); 32 | this.mainMenuStrip = new System.Windows.Forms.MenuStrip(); 33 | this.fileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 34 | this.openToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 35 | this.propertiesToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 36 | this.splitContainer1 = new System.Windows.Forms.SplitContainer(); 37 | this.messageList = new System.Windows.Forms.ListView(); 38 | this.Tick = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); 39 | this.Type = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); 40 | this.MsgSize = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); 41 | this.messageTree = new System.Windows.Forms.TreeView(); 42 | this.mainMenuStrip.SuspendLayout(); 43 | ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit(); 44 | this.splitContainer1.Panel1.SuspendLayout(); 45 | this.splitContainer1.Panel2.SuspendLayout(); 46 | this.splitContainer1.SuspendLayout(); 47 | this.SuspendLayout(); 48 | // 49 | // mainMenuStrip 50 | // 51 | this.mainMenuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { 52 | this.fileToolStripMenuItem}); 53 | this.mainMenuStrip.Location = new System.Drawing.Point(0, 0); 54 | this.mainMenuStrip.Name = "mainMenuStrip"; 55 | this.mainMenuStrip.Size = new System.Drawing.Size(592, 24); 56 | this.mainMenuStrip.TabIndex = 0; 57 | this.mainMenuStrip.Text = "menuStrip1"; 58 | // 59 | // fileToolStripMenuItem 60 | // 61 | this.fileToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { 62 | this.openToolStripMenuItem, 63 | this.propertiesToolStripMenuItem}); 64 | this.fileToolStripMenuItem.Name = "fileToolStripMenuItem"; 65 | this.fileToolStripMenuItem.Size = new System.Drawing.Size(35, 20); 66 | this.fileToolStripMenuItem.Text = "File"; 67 | // 68 | // openToolStripMenuItem 69 | // 70 | this.openToolStripMenuItem.Image = ((System.Drawing.Image)(resources.GetObject("openToolStripMenuItem.Image"))); 71 | this.openToolStripMenuItem.Name = "openToolStripMenuItem"; 72 | this.openToolStripMenuItem.Size = new System.Drawing.Size(152, 22); 73 | this.openToolStripMenuItem.Text = "Open"; 74 | this.openToolStripMenuItem.Click += new System.EventHandler(this.openToolStripMenuItem_Click); 75 | // 76 | // propertiesToolStripMenuItem 77 | // 78 | this.propertiesToolStripMenuItem.Enabled = false; 79 | this.propertiesToolStripMenuItem.Image = ((System.Drawing.Image)(resources.GetObject("propertiesToolStripMenuItem.Image"))); 80 | this.propertiesToolStripMenuItem.Name = "propertiesToolStripMenuItem"; 81 | this.propertiesToolStripMenuItem.Size = new System.Drawing.Size(152, 22); 82 | this.propertiesToolStripMenuItem.Text = "Properties"; 83 | this.propertiesToolStripMenuItem.Click += new System.EventHandler(this.propertiesToolStripMenuItem_Click); 84 | // 85 | // splitContainer1 86 | // 87 | this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill; 88 | this.splitContainer1.Location = new System.Drawing.Point(0, 24); 89 | this.splitContainer1.Name = "splitContainer1"; 90 | this.splitContainer1.Orientation = System.Windows.Forms.Orientation.Horizontal; 91 | // 92 | // splitContainer1.Panel1 93 | // 94 | this.splitContainer1.Panel1.Controls.Add(this.messageList); 95 | // 96 | // splitContainer1.Panel2 97 | // 98 | this.splitContainer1.Panel2.Controls.Add(this.messageTree); 99 | this.splitContainer1.Size = new System.Drawing.Size(592, 549); 100 | this.splitContainer1.SplitterDistance = 197; 101 | this.splitContainer1.TabIndex = 1; 102 | // 103 | // messageList 104 | // 105 | this.messageList.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; 106 | this.messageList.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { 107 | this.Tick, 108 | this.Type, 109 | this.MsgSize}); 110 | this.messageList.Dock = System.Windows.Forms.DockStyle.Fill; 111 | this.messageList.FullRowSelect = true; 112 | this.messageList.Location = new System.Drawing.Point(0, 0); 113 | this.messageList.Name = "messageList"; 114 | this.messageList.Size = new System.Drawing.Size(592, 197); 115 | this.messageList.TabIndex = 0; 116 | this.messageList.UseCompatibleStateImageBehavior = false; 117 | this.messageList.View = System.Windows.Forms.View.Details; 118 | this.messageList.SelectedIndexChanged += new System.EventHandler(this.messageList_SelectedIndexChanged); 119 | // 120 | // Tick 121 | // 122 | this.Tick.Text = "Tick"; 123 | // 124 | // Type 125 | // 126 | this.Type.Text = "Type"; 127 | this.Type.Width = 360; 128 | // 129 | // MsgSize 130 | // 131 | this.MsgSize.Text = "Size"; 132 | // 133 | // messageTree 134 | // 135 | this.messageTree.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; 136 | this.messageTree.Dock = System.Windows.Forms.DockStyle.Fill; 137 | this.messageTree.FullRowSelect = true; 138 | this.messageTree.Location = new System.Drawing.Point(0, 0); 139 | this.messageTree.Name = "messageTree"; 140 | this.messageTree.ShowLines = false; 141 | this.messageTree.Size = new System.Drawing.Size(592, 348); 142 | this.messageTree.TabIndex = 0; 143 | // 144 | // MainForm 145 | // 146 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 147 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 148 | this.ClientSize = new System.Drawing.Size(592, 573); 149 | this.Controls.Add(this.splitContainer1); 150 | this.Controls.Add(this.mainMenuStrip); 151 | this.MainMenuStrip = this.mainMenuStrip; 152 | this.Name = "MainForm"; 153 | this.ShowIcon = false; 154 | this.Text = "netdecode"; 155 | this.mainMenuStrip.ResumeLayout(false); 156 | this.mainMenuStrip.PerformLayout(); 157 | this.splitContainer1.Panel1.ResumeLayout(false); 158 | this.splitContainer1.Panel2.ResumeLayout(false); 159 | ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).EndInit(); 160 | this.splitContainer1.ResumeLayout(false); 161 | this.ResumeLayout(false); 162 | this.PerformLayout(); 163 | 164 | } 165 | 166 | #endregion 167 | 168 | private System.Windows.Forms.MenuStrip mainMenuStrip; 169 | private System.Windows.Forms.ToolStripMenuItem fileToolStripMenuItem; 170 | private System.Windows.Forms.ToolStripMenuItem openToolStripMenuItem; 171 | private System.Windows.Forms.ToolStripMenuItem propertiesToolStripMenuItem; 172 | private System.Windows.Forms.SplitContainer splitContainer1; 173 | private System.Windows.Forms.ListView messageList; 174 | private System.Windows.Forms.ColumnHeader Tick; 175 | private System.Windows.Forms.ColumnHeader Type; 176 | private System.Windows.Forms.ColumnHeader MsgSize; 177 | private System.Windows.Forms.TreeView messageTree; 178 | } 179 | } 180 | 181 | -------------------------------------------------------------------------------- /MainForm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing; 3 | using System.Text; 4 | using System.Windows.Forms; 5 | using System.IO; 6 | 7 | namespace netdecode 8 | { 9 | public partial class MainForm : Form 10 | { 11 | DemoFile _currentFile; 12 | 13 | public MainForm() 14 | { 15 | InitializeComponent(); 16 | } 17 | 18 | private void ParseIntoTree(DemoFile.DemoMessage msg) 19 | { 20 | var node = new TreeNode(String.Format("{0}, tick {1}, {2} bytes", msg.Type, msg.Tick, msg.Data.Length)); 21 | node.Expand(); 22 | node.BackColor = DemoMessageItem.GetTypeColor(msg.Type); 23 | 24 | switch (msg.Type) 25 | { 26 | case DemoFile.MessageType.ConsoleCmd: 27 | node.Nodes.Add(Encoding.ASCII.GetString(msg.Data)); 28 | break; 29 | case DemoFile.MessageType.UserCmd: 30 | UserCmd.ParseIntoTreeNode(msg.Data, node); 31 | break; 32 | case DemoFile.MessageType.Signon: 33 | case DemoFile.MessageType.Packet: 34 | Packet.Parse(msg.Data, node); 35 | break; 36 | case DemoFile.MessageType.DataTables: 37 | DataTables.Parse(msg.Data, node); 38 | break; 39 | default: 40 | node.Nodes.Add("Unhandled demo message type."); 41 | break; 42 | } 43 | 44 | messageTree.Nodes.Add(node); 45 | } 46 | 47 | private void openToolStripMenuItem_Click(object sender, EventArgs e) 48 | { 49 | var ofd = new OpenFileDialog 50 | { 51 | Filter = "Demo files|*.dem", 52 | RestoreDirectory = true 53 | }; 54 | 55 | if (ofd.ShowDialog() == DialogResult.OK) 56 | { 57 | messageList.Items.Clear(); 58 | 59 | Stream f = ofd.OpenFile(); 60 | _currentFile = new DemoFile(f); 61 | f.Close(); 62 | 63 | foreach (var msg in _currentFile.Messages) 64 | { 65 | messageList.Items.Add(new DemoMessageItem(msg)); 66 | } 67 | } 68 | 69 | propertiesToolStripMenuItem.Enabled = true; 70 | } 71 | 72 | private void messageList_SelectedIndexChanged(object sender, EventArgs e) 73 | { 74 | messageTree.Nodes.Clear(); 75 | 76 | foreach(DemoMessageItem item in messageList.SelectedItems) { 77 | ParseIntoTree(item.Msg); 78 | } 79 | } 80 | 81 | private void propertiesToolStripMenuItem_Click(object sender, EventArgs e) 82 | { 83 | MessageBox.Show("Demo protocol: " + _currentFile.Info.DemoProtocol + "\n" 84 | + "Net protocol: " + _currentFile.Info.NetProtocol + "\n" 85 | + "Server name: " + _currentFile.Info.ServerName + "\n" 86 | + "Client name: " + _currentFile.Info.ClientName + "\n" 87 | + "Map name: " + _currentFile.Info.MapName + "\n" 88 | + "Game directory: " + _currentFile.Info.GameDirectory + "\n" 89 | + "Length in seconds: " + _currentFile.Info.Seconds + "\n" 90 | + "Tick count: " + _currentFile.Info.TickCount + "\n" 91 | + "Frame count: " + _currentFile.Info.FrameCount); 92 | } 93 | } 94 | 95 | class DemoMessageItem : ListViewItem 96 | { 97 | public DemoFile.DemoMessage Msg; 98 | 99 | public DemoMessageItem(DemoFile.DemoMessage msg) 100 | { 101 | Msg = msg; 102 | 103 | BackColor = GetTypeColor(msg.Type); 104 | Text = Msg.Tick.ToString(); 105 | SubItems.Add(Msg.Type.ToString()); 106 | SubItems.Add(Msg.Data.Length.ToString()); 107 | } 108 | 109 | public static Color GetTypeColor(DemoFile.MessageType type) 110 | { 111 | switch(type) { 112 | case DemoFile.MessageType.Signon: 113 | case DemoFile.MessageType.Packet: 114 | return Color.LightBlue; 115 | case DemoFile.MessageType.UserCmd: 116 | return Color.LightGreen; 117 | case DemoFile.MessageType.ConsoleCmd: 118 | return Color.LightPink; 119 | default: 120 | return Color.White; 121 | } 122 | } 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /MainForm.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | 17, 17 122 | 123 | 124 | 125 | 126 | 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 179 | 180 | 181 | 182 | 183 | iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAIGNIUk0AAHolAACAgwAA+f8AAIDpAAB1 184 | MAAA6mAAADqYAAAXb5JfxUYAAAAJcEhZcwAACw4AAAsOAUC+4UEAAAJESURBVDhPpZNtSFNRGMcvQQT1 185 | xSAhqIj6En6Rmt+CyPUhoqt7cWMqWmmQy4KUiaCjaJBbiJLRaCalxFqrxjKJQLICZ4bTXrQNDU03t7Vo 186 | 5spM5t7/nZ11c8NJH7zw45xzL//f8/AcLgOAWQ9p4R6TbqO5Szv1slszq26QH3t2XxW9167CXZ0KHW1K 187 | aNV1UNWWxXUtSqXEzL9K6F9VvdekNy7PaoznZUdm8P0COMJuBZY+yTH9SooWhRjNd6qhfqde3b7htiav 188 | ppjvgv8sum+VUEHIpcDyzDksjsrgH2IR7tsLo/4USAdgLnU6wWHqm4LZ0IaQ5zJuNkmQkAgP7kfgczV+ 189 | 20rgf52PuRcHMP9wK1qvi8Dv4iUFhjfA82EvDQdcV1BbycL9Xgl5RRGViA7x4XzKg7VjFwa12bh2ehvE 190 | Vfk43J6TFPSO/KJhr11Dw803HpD1OByWSpQWFgNju5G3LxubN2Uhd88GnJEJUdZQCl7rdjAW60dyi4DP 191 | 50ZT/Ul4vzjp+cPIAJVMPMrFjqwtqCg/AV2nIfGJDj6namcjYUWAWASUv080Hof5cQ8U5XzYJz3w+IGj 192 | Auk/ASdi+oeSHaQKYiQcjMSxGIjh20KUMu1bQzAwbKd5/ZNBSjxlz71LrBPeNQQWqy2tgygxBMMx/FyK 193 | 4OuPCBy+MGzuIMbc/xFw1UJkDKmVuf1bRyzzDKyjk2kdBMiJYz4EuBaA8TnARsg4xLr6i2BZAQqF0hXE 194 | MhSIJGCFRSggJFZWIM4sWM+vnMj+AaK/8f7NvIIEAAAAAElFTkSuQmCC 195 | 196 | 197 | 198 | 47 199 | 200 | -------------------------------------------------------------------------------- /Packet.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Windows.Forms; 4 | using System.Drawing; 5 | 6 | namespace netdecode 7 | { 8 | class Packet 9 | { 10 | delegate void MsgHandler(BitBuffer bb, TreeNode node); 11 | 12 | static readonly Dictionary Handlers = new Dictionary 13 | { 14 | {0, (_, node) => 15 | { node.Text = "net_nop"; node.ForeColor = Color.Gray; }}, 16 | {1, net_disconnect}, 17 | {2, net_file}, 18 | {3, net_tick}, 19 | {4, net_stringcmd}, 20 | {5, net_setconvar}, 21 | {6, net_signonstate}, 22 | 23 | {7, svc_print}, 24 | {8, svc_serverinfo}, 25 | {9, svc_sendtable}, 26 | {10, svc_classinfo}, 27 | {11, svc_setpause}, 28 | {12, svc_createstringtable}, 29 | {13, svc_updatestringtable}, 30 | {14, svc_voiceinit}, 31 | {15, svc_voicedata}, 32 | {17, svc_sounds}, 33 | {18, svc_setview}, 34 | {19, svc_fixangle}, 35 | {20, svc_crosshairangle}, 36 | {21, svc_bspdecal}, 37 | {23, svc_usermessage}, 38 | {24, svc_entitymessage}, 39 | {25, svc_gameevent}, 40 | {26, svc_packetentities}, 41 | {27, svc_tempentities}, 42 | {28, svc_prefetch}, 43 | {29, svc_menu}, 44 | {30, svc_gameeventlist}, 45 | {31, svc_getcvarvalue}, 46 | {32, svc_cmdkeyvalues} 47 | }; 48 | 49 | public static void Parse(byte[] data, TreeNode node) 50 | { 51 | var bb = new BitBuffer(data); 52 | 53 | while (bb.BitsLeft() > 6) 54 | { 55 | var type = bb.ReadBits(6); 56 | MsgHandler handler; 57 | if (Handlers.TryGetValue(type, out handler)) 58 | { 59 | var sub = new TreeNode(handler.Method.Name); 60 | node.Nodes.Add(sub); 61 | handler(bb, sub); 62 | } 63 | else 64 | { 65 | node.Nodes.Add("unknown message type " + type).ForeColor = Color.Crimson; 66 | break; 67 | } 68 | } 69 | } 70 | 71 | // do we even encounter these in demo files? 72 | static void net_disconnect(BitBuffer bb, TreeNode node) 73 | { 74 | node.Nodes.Add("Reason: " + bb.ReadString()); 75 | } 76 | 77 | static void net_file(BitBuffer bb, TreeNode node) 78 | { 79 | node.Nodes.Add("Transfer ID: " + bb.ReadBits(32)); 80 | node.Nodes.Add("Filename: " + bb.ReadString()); 81 | node.Nodes.Add("Requested: " + bb.ReadBool()); 82 | } 83 | 84 | static void net_tick(BitBuffer bb, TreeNode node) 85 | { 86 | node.Nodes.Add("Tick: " + (int)bb.ReadBits(32)); 87 | node.Nodes.Add("Host frametime: " + bb.ReadBits(16)); 88 | node.Nodes.Add("Host frametime StdDev: " + bb.ReadBits(16)); 89 | } 90 | 91 | static void net_stringcmd(BitBuffer bb, TreeNode node) 92 | { 93 | node.Nodes.Add("Command: " + bb.ReadString()); 94 | } 95 | 96 | static void net_setconvar(BitBuffer bb, TreeNode node) 97 | { 98 | var n = bb.ReadBits(8); 99 | while (n-- > 0) 100 | node.Nodes.Add(bb.ReadString() + ": " + bb.ReadString()); 101 | } 102 | 103 | static void net_signonstate(BitBuffer bb, TreeNode node) 104 | { 105 | node.Nodes.Add("Signon state: " + bb.ReadBits(8)); 106 | node.Nodes.Add("Spawn count: " + (int)bb.ReadBits(32)); 107 | } 108 | 109 | static void svc_print(BitBuffer bb, TreeNode node) 110 | { 111 | node.Nodes.Add(bb.ReadString()); 112 | } 113 | 114 | static void svc_serverinfo(BitBuffer bb, TreeNode node) 115 | { 116 | short version = (short)bb.ReadBits(16); 117 | node.Nodes.Add("Version: " + version); 118 | node.Nodes.Add("Server count: " + (int)bb.ReadBits(32)); 119 | node.Nodes.Add("SourceTV: " + bb.ReadBool()); 120 | node.Nodes.Add("Dedicated: " + bb.ReadBool()); 121 | node.Nodes.Add("Server client CRC: 0x" + bb.ReadBits(32).ToString("X8")); 122 | node.Nodes.Add("Max classes: " + bb.ReadBits(16)); 123 | if (version < 18) 124 | node.Nodes.Add("Server map CRC: 0x" + bb.ReadBits(32).ToString("X8")); 125 | else 126 | bb.Seek(128); // TODO: display out map md5 hash 127 | node.Nodes.Add("Current player count: " + bb.ReadBits(8)); 128 | node.Nodes.Add("Max player count: " + bb.ReadBits(8)); 129 | node.Nodes.Add("Interval per tick: " + bb.ReadFloat()); 130 | node.Nodes.Add("Platform: " + (char)bb.ReadBits(8)); 131 | node.Nodes.Add("Game directory: " + bb.ReadString()); 132 | node.Nodes.Add("Map name: " + bb.ReadString()); 133 | node.Nodes.Add("Skybox name: " + bb.ReadString()); 134 | node.Nodes.Add("Hostname: " + bb.ReadString()); 135 | node.Nodes.Add("Has replay: " + bb.ReadBool()); // ???: protocol version 136 | } 137 | 138 | static void svc_sendtable(BitBuffer bb, TreeNode node) 139 | { 140 | node.Nodes.Add("Needs decoder: " + bb.ReadBool()); 141 | var n = bb.ReadBits(16); 142 | node.Nodes.Add("Length in bits: " + n); 143 | bb.Seek(n); 144 | } 145 | 146 | static void svc_classinfo(BitBuffer bb, TreeNode node) 147 | { 148 | var n = bb.ReadBits(16); 149 | node.Nodes.Add("Number of server classes: " + n); 150 | var cc = bb.ReadBool(); 151 | node.Nodes.Add("Create classes on client: " + cc); 152 | if (!cc) 153 | while (n-- > 0) 154 | { 155 | node.Nodes.Add("Class ID: " + bb.ReadBits((uint)Math.Log(n, 2) + 1)); 156 | node.Nodes.Add("Class name: " + bb.ReadString()); 157 | node.Nodes.Add("Datatable name: " + bb.ReadString()); 158 | } 159 | } 160 | 161 | static void svc_setpause(BitBuffer bb, TreeNode node) 162 | { 163 | node.Nodes.Add(bb.ReadBool().ToString()); 164 | } 165 | 166 | static void svc_createstringtable(BitBuffer bb, TreeNode node) 167 | { 168 | node.Nodes.Add("Table name: " + bb.ReadString()); 169 | var m = bb.ReadBits(16); 170 | node.Nodes.Add("Max entries: " + m); 171 | node.Nodes.Add("Number of entries: " + bb.ReadBits((uint)Math.Log(m, 2) + 1)); 172 | var n = bb.ReadBits(20); 173 | node.Nodes.Add("Length in bits: " + n); 174 | var f = bb.ReadBool(); 175 | node.Nodes.Add("Userdata fixed size: " + f); 176 | if (f) 177 | { 178 | node.Nodes.Add("Userdata size: " + bb.ReadBits(12)); 179 | node.Nodes.Add("Userdata bits: " + bb.ReadBits(4)); 180 | } 181 | 182 | // ???: this is not in Source 2007 netmessages.h/cpp it seems. protocol version? 183 | node.Nodes.Add("Compressed: " + bb.ReadBool()); 184 | bb.Seek(n); 185 | } 186 | 187 | static void svc_updatestringtable(BitBuffer bb, TreeNode node) 188 | { 189 | node.Nodes.Add("Table ID: " + bb.ReadBits(5)); 190 | node.Nodes.Add("Changed entries: " + (bb.ReadBool() ? bb.ReadBits(16) : 1)); 191 | var b = bb.ReadBits(20); 192 | node.Nodes.Add("Length in bits: " + b); 193 | bb.Seek(b); 194 | } 195 | 196 | static void svc_voiceinit(BitBuffer bb, TreeNode node) 197 | { 198 | node.Nodes.Add("Codec: " + bb.ReadString()); 199 | node.Nodes.Add("Quality: " + bb.ReadBits(8)); 200 | } 201 | 202 | static void svc_voicedata(BitBuffer bb, TreeNode node) 203 | { 204 | node.Nodes.Add("Client: " + bb.ReadBits(8)); 205 | node.Nodes.Add("Proximity: " + bb.ReadBits(8)); 206 | var b = bb.ReadBits(16); 207 | node.Nodes.Add("Length in bits: " + b); 208 | bb.Seek(b); 209 | } 210 | 211 | static void svc_sounds(BitBuffer bb, TreeNode node) 212 | { 213 | var r = bb.ReadBool(); 214 | node.Nodes.Add("Reliable: " + r); 215 | node.Nodes.Add("Number of sounds: " + (r ? 1 : bb.ReadBits(8))); 216 | uint b = r ? bb.ReadBits(8) : bb.ReadBits(16); 217 | node.Nodes.Add("Length in bits: " + b); 218 | bb.Seek(b); 219 | } 220 | 221 | static void svc_setview(BitBuffer bb, TreeNode node) 222 | { 223 | node.Nodes.Add("Entity index: " + bb.ReadBits(11)); 224 | } 225 | 226 | static void svc_fixangle(BitBuffer bb, TreeNode node) 227 | { 228 | node.Nodes.Add("Relative: " + bb.ReadBool()); 229 | // TODO: handle properly 230 | bb.Seek(48); 231 | } 232 | 233 | static void svc_crosshairangle(BitBuffer bb, TreeNode node) 234 | { 235 | // TODO: see above 236 | bb.Seek(48); 237 | } 238 | 239 | static void svc_bspdecal(BitBuffer bb, TreeNode node) 240 | { 241 | node.Nodes.Add("Position: " + bb.ReadVecCoord()); 242 | node.Nodes.Add("Decal texture index: " + bb.ReadBits(9)); 243 | if (bb.ReadBool()) 244 | { 245 | node.Nodes.Add("Entity index: " + bb.ReadBits(11)); 246 | node.Nodes.Add("Model index: " + bb.ReadBits(12)); 247 | } 248 | node.Nodes.Add("Low priority: " + bb.ReadBool()); 249 | } 250 | 251 | static void svc_usermessage(BitBuffer bb, TreeNode node) 252 | { 253 | node.Nodes.Add("Message type: " + bb.ReadBits(8)); 254 | var b = bb.ReadBits(11); 255 | node.Nodes.Add("Length in bits: " + b); 256 | bb.Seek(b); 257 | } 258 | 259 | static void svc_entitymessage(BitBuffer bb, TreeNode node) 260 | { 261 | node.Nodes.Add("Entity index: " + bb.ReadBits(11)); 262 | node.Nodes.Add("Class ID: " + bb.ReadBits(9)); 263 | var b = bb.ReadBits(11); 264 | node.Nodes.Add("Length in bits: " + b); 265 | bb.Seek(b); 266 | } 267 | 268 | static void svc_gameevent(BitBuffer bb, TreeNode node) 269 | { 270 | var b = bb.ReadBits(11); 271 | node.Nodes.Add("Length in bits: " + b); 272 | bb.Seek(b); 273 | } 274 | 275 | static void svc_packetentities(BitBuffer bb, TreeNode node) 276 | { 277 | node.Nodes.Add("Max entries: " + bb.ReadBits(11)); 278 | bool d = bb.ReadBool(); 279 | node.Nodes.Add("Is delta: " + d); 280 | if (d) 281 | node.Nodes.Add("Delta from: " + bb.ReadBits(32)); 282 | node.Nodes.Add("Baseline: " + bb.ReadBool()); 283 | node.Nodes.Add("Updated entries: " + bb.ReadBits(11)); 284 | var b = bb.ReadBits(20); 285 | node.Nodes.Add("Length in bits: " + b); 286 | node.Nodes.Add("Update baseline: " + bb.ReadBool()); 287 | bb.Seek(b); 288 | } 289 | 290 | static void svc_tempentities(BitBuffer bb, TreeNode node) 291 | { 292 | node.Nodes.Add("Number of entries: " + bb.ReadBits(8)); 293 | var b = bb.ReadBits(17); 294 | node.Nodes.Add("Length in bits: " + b); 295 | bb.Seek(b); 296 | } 297 | 298 | static void svc_prefetch(BitBuffer bb, TreeNode node) 299 | { 300 | node.Nodes.Add("Sound index: " + bb.ReadBits(13)); 301 | } 302 | 303 | static void svc_menu(BitBuffer bb, TreeNode node) 304 | { 305 | node.Nodes.Add("Menu type: " + bb.ReadBits(16)); 306 | var b = bb.ReadBits(16); 307 | node.Nodes.Add("Length in bytes: " + b); 308 | bb.Seek(b << 3); 309 | } 310 | 311 | static void svc_gameeventlist(BitBuffer bb, TreeNode node) 312 | { 313 | node.Nodes.Add("Number of events: " + bb.ReadBits(9)); 314 | var b = bb.ReadBits(20); 315 | node.Nodes.Add("Length in bits: " + b); 316 | bb.Seek(b); 317 | } 318 | 319 | static void svc_getcvarvalue(BitBuffer bb, TreeNode node) 320 | { 321 | node.Nodes.Add("Cookie: 0x" + bb.ReadBits(32).ToString("X8")); 322 | node.Nodes.Add(bb.ReadString()); 323 | } 324 | 325 | static void svc_cmdkeyvalues(BitBuffer bb, TreeNode node) 326 | { 327 | var b = bb.ReadBits(32); 328 | node.Nodes.Add("Length in bits: " + b); 329 | bb.Seek(b); 330 | } 331 | } 332 | } 333 | -------------------------------------------------------------------------------- /Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows.Forms; 3 | 4 | namespace netdecode 5 | { 6 | static class Program 7 | { 8 | /// 9 | /// The main entry point for the application. 10 | /// 11 | [STAThread] 12 | static void Main() 13 | { 14 | Application.EnableVisualStyles(); 15 | Application.SetCompatibleTextRenderingDefault(false); 16 | Application.Run(new MainForm()); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyTitle("netdecode")] 8 | [assembly: AssemblyDescription("")] 9 | [assembly: AssemblyConfiguration("")] 10 | [assembly: AssemblyCompany("")] 11 | [assembly: AssemblyProduct("netdecode")] 12 | [assembly: AssemblyCopyright("Copyright © 2012")] 13 | [assembly: AssemblyTrademark("")] 14 | [assembly: AssemblyCulture("")] 15 | 16 | // Setting ComVisible to false makes the types in this assembly not visible 17 | // to COM components. If you need to access a type in this assembly from 18 | // COM, set the ComVisible attribute to true on that type. 19 | [assembly: ComVisible(false)] 20 | 21 | // The following GUID is for the ID of the typelib if this project is exposed to COM 22 | [assembly: Guid("af8281aa-63be-4413-b9f3-7490ae68b8e6")] 23 | 24 | // Version information for an assembly consists of the following four values: 25 | // 26 | // Major Version 27 | // Minor Version 28 | // Build Number 29 | // Revision 30 | // 31 | // You can specify all the values or you can default the Build and Revision Numbers 32 | // by using the '*' as shown below: 33 | // [assembly: AssemblyVersion("1.0.*")] 34 | [assembly: AssemblyVersion("1.0.0.0")] 35 | [assembly: AssemblyFileVersion("1.0.0.0")] 36 | -------------------------------------------------------------------------------- /Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.239 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace netdecode.Properties 12 | { 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources 26 | { 27 | 28 | private static global::System.Resources.ResourceManager resourceMan; 29 | 30 | private static global::System.Globalization.CultureInfo resourceCulture; 31 | 32 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 33 | internal Resources() 34 | { 35 | } 36 | 37 | /// 38 | /// Returns the cached ResourceManager instance used by this class. 39 | /// 40 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 41 | internal static global::System.Resources.ResourceManager ResourceManager 42 | { 43 | get 44 | { 45 | if ((resourceMan == null)) 46 | { 47 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("netdecode.Properties.Resources", typeof(Resources).Assembly); 48 | resourceMan = temp; 49 | } 50 | return resourceMan; 51 | } 52 | } 53 | 54 | /// 55 | /// Overrides the current thread's CurrentUICulture property for all 56 | /// resource lookups using this strongly typed resource class. 57 | /// 58 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 59 | internal static global::System.Globalization.CultureInfo Culture 60 | { 61 | get 62 | { 63 | return resourceCulture; 64 | } 65 | set 66 | { 67 | resourceCulture = value; 68 | } 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /Properties/Resources.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | text/microsoft-resx 107 | 108 | 109 | 2.0 110 | 111 | 112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 113 | 114 | 115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | -------------------------------------------------------------------------------- /Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.239 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace netdecode.Properties 12 | { 13 | 14 | 15 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 16 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "10.0.0.0")] 17 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase 18 | { 19 | 20 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 21 | 22 | public static Settings Default 23 | { 24 | get 25 | { 26 | return defaultInstance; 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Properties/Settings.settings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # netdecode 2 | 3 | ![Screenshot](http://i.imgur.com/BbEk2.png) 4 | 5 | netdecode is a utility for parsing and analysing data within demo files produced by Valve's Source engine (only the Orange Box branch for now). This is primarily a tool for testing and reference. Poorly written in C#. 6 | 7 | It can parse: 8 | 9 | * Packet/signon messages and their netmessages 10 | * DataTable messages and their sendtables and class info 11 | * UserCmd messages (mostly) 12 | 13 | For parsing Dota 2 demo files, check out Valve's [demoinfo2](https://developer.valvesoftware.com/wiki/Dota_2_Demo_Format). 14 | 15 | ## License 16 | 17 | > Copyright (C) 2012 Shane Nelson 18 | 19 | > Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 20 | 21 | > The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 22 | 23 | > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | 25 | ## Special thanks 26 | 27 | * *Chrisaster* (for netmessage research) 28 | * *asherkin* (for demo format help) 29 | * *Didrole* (extra netmessage help) 30 | 31 | ### Production babies 32 | 33 | * *VoiDeD* 34 | * *AzuiSleet* -------------------------------------------------------------------------------- /netdecode.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | x86 6 | 8.0.30703 7 | 2.0 8 | {4134BBE6-6330-4EE2-925E-9577E3C1287A} 9 | WinExe 10 | Properties 11 | netdecode 12 | netdecode 13 | v4.0 14 | Client 15 | 512 16 | 17 | 18 | x86 19 | true 20 | full 21 | false 22 | bin\Debug\ 23 | DEBUG;TRACE 24 | prompt 25 | 4 26 | 27 | 28 | x86 29 | pdbonly 30 | true 31 | bin\Release\ 32 | TRACE 33 | prompt 34 | 4 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | Form 53 | 54 | 55 | MainForm.cs 56 | 57 | 58 | 59 | 60 | 61 | 62 | MainForm.cs 63 | 64 | 65 | ResXFileCodeGenerator 66 | Resources.Designer.cs 67 | Designer 68 | 69 | 70 | True 71 | Resources.resx 72 | 73 | 74 | SettingsSingleFileGenerator 75 | Settings.Designer.cs 76 | 77 | 78 | True 79 | Settings.settings 80 | True 81 | 82 | 83 | 84 | 91 | -------------------------------------------------------------------------------- /netdecode.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 11.00 3 | # Visual Studio 2010 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "netdecode", "netdecode.csproj", "{4134BBE6-6330-4EE2-925E-9577E3C1287A}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|x86 = Debug|x86 9 | Release|x86 = Release|x86 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {4134BBE6-6330-4EE2-925E-9577E3C1287A}.Debug|x86.ActiveCfg = Debug|x86 13 | {4134BBE6-6330-4EE2-925E-9577E3C1287A}.Debug|x86.Build.0 = Debug|x86 14 | {4134BBE6-6330-4EE2-925E-9577E3C1287A}.Release|x86.ActiveCfg = Release|x86 15 | {4134BBE6-6330-4EE2-925E-9577E3C1287A}.Release|x86.Build.0 = Release|x86 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | EndGlobal 21 | --------------------------------------------------------------------------------