├── .gitattributes ├── .gitignore ├── BitSet ├── BitInfo.cs ├── BitSet.csproj ├── BitStream.cs ├── CString.cs ├── CopyBits.cs ├── Properties │ └── AssemblyInfo.cs ├── Single.cs ├── UInt.cs ├── UInt1.cs ├── UInt10.cs ├── UInt16.cs ├── UInt2.cs ├── UInt20.cs ├── UInt24.cs ├── UInt3.cs ├── UInt32.cs ├── UInt4.cs ├── UInt48.cs ├── UInt5.cs ├── UInt6.cs ├── UInt8.cs └── VarInt.cs ├── DemoLib.sln ├── DemoLib ├── Commands │ ├── DemoCommand.cs │ ├── DemoConsoleCommand.cs │ ├── DemoDataTablesCommand.cs │ ├── DemoPacketCommand.cs │ ├── DemoSignonCommand.cs │ ├── DemoStringTablesCommand.cs │ ├── DemoSyncTickCommand.cs │ ├── DemoUserCommand.cs │ └── TimestampedDemoCommand.cs ├── DemoCommandType.cs ├── DemoHeader.cs ├── DemoLib.csproj ├── DemoParseException.cs ├── DemoReader.cs ├── DemoViewpoint.cs ├── Properties │ └── AssemblyInfo.cs └── packages.config ├── Launcher ├── App.config ├── Launcher.csproj ├── Program.cs └── Properties │ └── AssemblyInfo.cs ├── PlayerPositionsTest ├── App.config ├── App.xaml ├── App.xaml.cs ├── BooleanConverter.cs ├── BooleanToVisibilityConverter.cs ├── DesignData │ ├── PlayerStatusSampleData.xaml │ └── PlayerStatusesSampleData.xaml ├── MainWindow.xaml ├── MainWindow.xaml.cs ├── PlayerPositionsTest.csproj ├── PlayerStatus.cs ├── PlayerStatusTemplate.xaml ├── PlayerStatusesList.cs ├── Properties │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ ├── Resources.resx │ ├── Settings.Designer.cs │ └── Settings.settings ├── StringToPortraitConverter.cs ├── ViewboxVerticalStretch.cs ├── class_portraits │ ├── alpha │ │ ├── all_class.png │ │ ├── demo.png │ │ ├── demo_blue.png │ │ ├── demo_blue_grey.png │ │ ├── demo_grey.png │ │ ├── engie.png │ │ ├── engie_blue.png │ │ ├── engie_blue_grey.png │ │ ├── engie_grey.png │ │ ├── heavy.png │ │ ├── heavy_blue.png │ │ ├── heavy_blue_grey.png │ │ ├── heavy_grey.png │ │ ├── medic.png │ │ ├── medic_blue.png │ │ ├── medic_blue_grey.png │ │ ├── medic_grey.png │ │ ├── pyro.png │ │ ├── pyro_blue.png │ │ ├── pyro_blue_grey.png │ │ ├── pyro_grey.png │ │ ├── scout.png │ │ ├── scout_blue.png │ │ ├── scout_blue_grey.png │ │ ├── scout_grey.png │ │ ├── silhouette.png │ │ ├── sniper.png │ │ ├── sniper_blue.png │ │ ├── sniper_blue_grey.png │ │ ├── sniper_grey.png │ │ ├── soldier.png │ │ ├── soldier_blue.png │ │ ├── soldier_blue_grey.png │ │ ├── soldier_grey.png │ │ ├── spy.png │ │ ├── spy_blue.png │ │ ├── spy_blue_grey.png │ │ └── spy_grey.png │ └── noalpha │ │ ├── all_class.png │ │ ├── demo.png │ │ ├── demo_blue.png │ │ ├── demo_blue_grey.png │ │ ├── demo_grey.png │ │ ├── engie.png │ │ ├── engie_blue.png │ │ ├── engie_blue_grey.png │ │ ├── engie_grey.png │ │ ├── heavy.png │ │ ├── heavy_blue.png │ │ ├── heavy_blue_grey.png │ │ ├── heavy_grey.png │ │ ├── medic.png │ │ ├── medic_blue.png │ │ ├── medic_blue_grey.png │ │ ├── medic_grey.png │ │ ├── pyro.png │ │ ├── pyro_blue.png │ │ ├── pyro_blue_grey.png │ │ ├── pyro_grey.png │ │ ├── scout.png │ │ ├── scout_blue.png │ │ ├── scout_blue_grey.png │ │ ├── scout_grey.png │ │ ├── sniper.png │ │ ├── sniper_blue.png │ │ ├── sniper_blue_grey.png │ │ ├── sniper_grey.png │ │ ├── soldier.png │ │ ├── soldier_blue.png │ │ ├── soldier_blue_grey.png │ │ ├── soldier_grey.png │ │ ├── spy.png │ │ ├── spy_blue.png │ │ ├── spy_blue_grey.png │ │ └── spy_grey.png ├── demos │ ├── cp_process_final.dem │ └── testdemo.dem ├── images │ ├── classicons │ │ ├── demo_blu.png │ │ ├── demo_red.png │ │ ├── engineer_blu.png │ │ ├── engineer_red.png │ │ ├── heavy_blu.png │ │ ├── heavy_red.png │ │ ├── medic_blu.png │ │ ├── medic_red.png │ │ ├── pyro_blu.png │ │ ├── pyro_red.png │ │ ├── scout_blu.png │ │ ├── scout_red.png │ │ ├── sniper_blu.png │ │ ├── sniper_red.png │ │ ├── soldier_blu.png │ │ ├── soldier_red.png │ │ ├── spy_blu.png │ │ └── spy_red.png │ ├── killicons │ │ ├── black │ │ │ ├── negative_1.png │ │ │ ├── negative_2.png │ │ │ └── negative_3.png │ │ └── white │ │ │ ├── ambassador.png │ │ │ ├── crit_bg.png │ │ │ ├── group_1.png │ │ │ ├── group_2.png │ │ │ ├── group_3.png │ │ │ ├── knife_taunt.png │ │ │ ├── natascha.png │ │ │ ├── rocket.png │ │ │ └── unknown.png │ ├── maps │ │ ├── cp_process_final.png │ │ ├── cp_process_final.xcf │ │ ├── cp_process_final_cropped.png │ │ └── cp_process_final_cropped_centered.png │ └── projectiles │ │ ├── pill_blue.png │ │ ├── pill_red.png │ │ └── rocket.png ├── images_misc │ ├── koth_sawmill.png │ ├── leaderboard_class_demo.png │ ├── leaderboard_class_engineer.png │ ├── leaderboard_class_heavy.png │ ├── leaderboard_class_medic.png │ ├── leaderboard_class_pyro.png │ ├── leaderboard_class_scout.png │ ├── leaderboard_class_sniper.png │ ├── leaderboard_class_soldier.png │ ├── leaderboard_class_spy.png │ └── leaderboard_dead.png └── packages.config └── TF2Net ├── ConditionalHashSet.cs ├── Data ├── BaselineIndex.cs ├── Class.cs ├── ClientFrame.cs ├── ConnectionState.cs ├── EHandle.cs ├── EntityData.cs ├── EntityUpdateType.cs ├── FlattenedProp.cs ├── GameEvent.cs ├── GameEventDeclaration.cs ├── IReadOnlyVector.cs ├── LifeState.cs ├── Player.cs ├── PlayerState.cs ├── SendProp.cs ├── SendPropDefinition.cs ├── SendTable.cs ├── ServerClass.cs ├── ServerInfo.cs ├── SignonState.cs ├── SourceConstants.cs ├── StringTable.cs ├── StringTableEntry.cs ├── Team.cs ├── UserInfo.cs ├── UserMessageType.cs ├── Vector.cs ├── WeaponType.cs └── WorldState.cs ├── Entities ├── Entity.cs ├── EntityWrapper.cs ├── IEntity.cs ├── IPropertySet.cs ├── Pill.cs ├── TFRocket.cs └── TempEntities │ ├── FireBullets.cs │ ├── TFBlood.cs │ └── TFExplosion.cs ├── Extensions ├── AutoDictionary.cs ├── BitStreamExtensions.cs ├── System.Collections.cs └── System.Linq.cs ├── IWorldEvents.cs ├── Monitors ├── EntityMonitor.cs ├── EntityPropertyMonitor.cs ├── IPropertyMonitor.cs └── MultiPropertyMonitor.cs ├── NetMessageCoder.cs ├── NetMessages ├── INetMessage.cs ├── NetBSPDecalMessage.cs ├── NetClassInfoMessage.cs ├── NetCreateStringTableMessage.cs ├── NetEntityMessage.cs ├── NetFileMessage.cs ├── NetFixAngleMessage.cs ├── NetGameEventListMessage.cs ├── NetGameEventMessage.cs ├── NetMessageType.cs ├── NetPacketEntitiesMessage.cs ├── NetPrefetchMessage.cs ├── NetPrintMessage.cs ├── NetServerInfoMessage.cs ├── NetSetConvarMessage.cs ├── NetSetPausedMessage.cs ├── NetSetViewMessage.cs ├── NetSignonStateMessage.cs ├── NetSoundMessage.cs ├── NetStringCmdMessage.cs ├── NetTempEntityMessage.cs ├── NetTickMessage.cs ├── NetUpdateStringTableMessage.cs ├── NetUsrMsgMessage.cs ├── NetVoiceDataMessage.cs ├── NetVoiceInitMessage.cs └── Shared │ ├── BitAngle.cs │ ├── BitCoord.cs │ ├── EntityCoder.cs │ ├── ExtMath.cs │ └── StringTableParser.cs ├── Properties └── AssemblyInfo.cs ├── SingleEvent.cs ├── TF2Net.csproj ├── WorldEvents.cs └── packages.config /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /BitSet/BitInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | 3 | namespace BitSet 4 | { 5 | public static class BitInfo 6 | { 7 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 8 | public static sbyte GetFirstBitIndex(ulong mask) 9 | { 10 | for (sbyte i = 0; i < 64; i++) 11 | { 12 | if ((mask & (1UL << i)) > 0) 13 | return i; 14 | } 15 | 16 | return -1; 17 | } 18 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 19 | public static sbyte GetFirstBitIndex(long mask) 20 | { 21 | return GetFirstBitIndex((ulong)mask); 22 | } 23 | 24 | public static ulong BitsToBytes(ulong bits) 25 | { 26 | return (bits + 7) >> 3; 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /BitSet/CString.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace BitSet 8 | { 9 | public static partial class BitReader 10 | { 11 | public static string ReadCString(byte[] buffer, ref ulong bitOffset) 12 | { 13 | StringBuilder builder = new StringBuilder(); 14 | 15 | char c; 16 | while ((c = (char)ReadUIntBits(buffer, ref bitOffset, 8)) != '\0') 17 | { 18 | builder.Append(c); 19 | } 20 | 21 | return builder.ToString(); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /BitSet/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("BitSet")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("BitSet")] 13 | [assembly: AssemblyCopyright("Copyright © 2016")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("8f8a6380-5b10-4891-ac21-3d03494b3e44")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /BitSet/Single.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.CompilerServices; 3 | 4 | namespace BitSet 5 | { 6 | public static partial class BitReader 7 | { 8 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 9 | public static float ReadSingle(byte[] buffer, int startByte = 0) 10 | { 11 | throw new NotImplementedException(); 12 | } 13 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 14 | public static float ReadSingle(byte[] buffer, int startByte, byte bitOffset) 15 | { 16 | throw new NotImplementedException(); 17 | } 18 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 19 | public unsafe static float ReadSingle(byte* buffer, int startByte = 0) 20 | { 21 | return *(float*)(&buffer[startByte]); 22 | } 23 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 24 | public unsafe static float ReadSingle(byte* buffer, int startByte, byte bitOffset) 25 | { 26 | throw new NotImplementedException(); 27 | } 28 | } 29 | public static partial class BitWriter 30 | { 31 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 32 | public static void WriteSingle(float value, byte[] buffer, int startByte = 0) 33 | { 34 | throw new NotImplementedException(); 35 | } 36 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 37 | public static void WriteSingle(float value, byte[] buffer, int startByte, byte bitOffset) 38 | { 39 | throw new NotImplementedException(); 40 | } 41 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 42 | public unsafe static void WriteSingle(float value, byte* buffer, int startByte = 0) 43 | { 44 | *(float*)(&buffer[startByte]) = value; 45 | } 46 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 47 | public unsafe static void WriteSingle(float value, byte* buffer, int startByte, byte bitOffset) 48 | { 49 | throw new NotImplementedException(); 50 | } 51 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 52 | public static void WriteSingle(double value, byte[] buffer, int startByte = 0) 53 | { 54 | WriteSingle((float)value, buffer, startByte); 55 | } 56 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 57 | public static void WriteSingle(double value, byte[] buffer, int startByte, byte bitOffset) 58 | { 59 | WriteSingle((float)value, buffer, startByte, bitOffset); 60 | } 61 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 62 | public unsafe static void WriteSingle(double value, byte* buffer, int startByte = 0) 63 | { 64 | WriteSingle((float)value, buffer, startByte); 65 | } 66 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 67 | public unsafe static void WriteSingle(double value, byte* buffer, int startByte, byte bitOffset) 68 | { 69 | WriteSingle((float)value, buffer, startByte, bitOffset); 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /BitSet/UInt.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Text; 4 | 5 | namespace BitSet 6 | { 7 | public static partial class BitReader 8 | { 9 | public static ulong ReadUIntBits(byte[] buffer, ref ulong bitOffset, byte bits) 10 | { 11 | #if false 12 | switch (bits) 13 | { 14 | case 1: return ReadUInt1(buffer, ref bitOffset); 15 | case 2: return ReadUInt2(buffer, ref bitOffset); 16 | case 3: return ReadUInt3(buffer, ref bitOffset); 17 | case 4: return ReadUInt4(buffer, ref bitOffset); 18 | case 5: return ReadUInt5(buffer, ref bitOffset); 19 | case 6: return ReadUInt6(buffer, ref bitOffset); 20 | 21 | case 16: return ReadUInt16(buffer, ref bitOffset); 22 | 23 | case 20: return ReadUInt20(buffer, ref bitOffset); 24 | 25 | case 32: return ReadUInt32(buffer, ref bitOffset); 26 | 27 | case 48: return ReadUInt48(buffer, ref bitOffset); 28 | 29 | default: throw new NotImplementedException(); 30 | } 31 | #endif 32 | 33 | byte[] temp = new byte[8]; 34 | CopyBits(buffer, bits, ref bitOffset, temp); 35 | return BitConverter.ToUInt64(temp, 0); 36 | } 37 | 38 | public static float ReadSingle(byte[] buffer, ref ulong bitOffset) 39 | { 40 | return BitConverter.ToSingle(BitConverter.GetBytes(ReadUInt(buffer, ref bitOffset)), 0); 41 | } 42 | 43 | public static ulong ReadULong(byte[] buffer, ref ulong bitOffset) 44 | { 45 | return ReadUIntBits(buffer, ref bitOffset, sizeof(ulong) << 3); 46 | } 47 | public static uint ReadUInt(byte[] buffer, ref ulong bitOffset) 48 | { 49 | return (uint)ReadUIntBits(buffer, ref bitOffset, sizeof(uint) << 3); 50 | } 51 | public static int ReadInt(byte[] buffer, ref ulong bitOffset) 52 | { 53 | return unchecked((int)ReadUIntBits(buffer, ref bitOffset, sizeof(int) << 3)); 54 | } 55 | public static ushort ReadUShort(byte[] buffer, ref ulong bitOffset) 56 | { 57 | return (ushort)ReadUIntBits(buffer, ref bitOffset, sizeof(ushort) << 3); 58 | } 59 | public static short ReadShort(byte[] buffer, ref ulong bitOffset) 60 | { 61 | return unchecked((short)ReadUIntBits(buffer, ref bitOffset, sizeof(short) << 3)); 62 | } 63 | public static char ReadChar(byte[] buffer, ref ulong bitOffset) 64 | { 65 | return Encoding.ASCII.GetChars(new byte[] { ReadByte(buffer, ref bitOffset) }).Single(); 66 | } 67 | public static byte ReadByte(byte[] buffer, ref ulong bitOffset) 68 | { 69 | return (byte)ReadUIntBits(buffer, ref bitOffset, sizeof(byte) << 3); 70 | } 71 | public static bool ReadBool(byte[] buffer, ref ulong bitOffset) 72 | { 73 | return ReadUIntBits(buffer, ref bitOffset, 1) != 0; 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /BitSet/UInt1.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.CompilerServices; 3 | 4 | namespace BitSet 5 | { 6 | public static partial class BitReader 7 | { 8 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 9 | public static byte ReadUInt1(byte[] buffer, ref ulong startBit) 10 | { 11 | var retVal = ReadUInt1(buffer, startBit); 12 | startBit++; 13 | return retVal; 14 | } 15 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 16 | public static byte ReadUInt1(byte[] buffer, ulong startBit) 17 | { 18 | return ReadUInt1(buffer, (int)(startBit / 8), (byte)(startBit % 8)); 19 | } 20 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 21 | public static byte ReadUInt1(byte[] buffer, int startByte = 0) 22 | { 23 | throw new NotImplementedException(); 24 | } 25 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 26 | public static byte ReadUInt1(byte[] buffer, int startByte, byte bitOffset) 27 | { 28 | if (bitOffset > 7) 29 | throw new ArgumentOutOfRangeException(nameof(bitOffset)); 30 | 31 | return (byte)(((buffer[startByte] & (1 << bitOffset)) != 0) ? 1 : 0); 32 | } 33 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 34 | public unsafe static byte ReadUInt1(byte* buffer, ulong startBit) 35 | { 36 | return ReadUInt1(buffer, (int)(startBit / 8), (byte)(startBit % 8)); 37 | } 38 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 39 | public unsafe static byte ReadUInt1(byte* buffer, int startByte = 0) 40 | { 41 | throw new NotImplementedException(); 42 | } 43 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 44 | public unsafe static byte ReadUInt1(byte* buffer, int startByte, byte bitOffset) 45 | { 46 | throw new NotImplementedException(); 47 | } 48 | } 49 | public static partial class BitWriter 50 | { 51 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 52 | public static void WriteUInt1(byte value, byte[] buffer, int startByte = 0) 53 | { 54 | throw new NotImplementedException(); 55 | } 56 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 57 | public static void WriteUInt1(byte value, byte[] buffer, int startByte, byte bitOffset) 58 | { 59 | throw new NotImplementedException(); 60 | } 61 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 62 | public unsafe static void WriteUInt1(byte value, byte* buffer, int startByte = 0) 63 | { 64 | throw new NotImplementedException(); 65 | } 66 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 67 | public unsafe static void WriteUInt1(byte value, byte* buffer, int startByte, byte bitOffset) 68 | { 69 | throw new NotImplementedException(); 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /BitSet/UInt10.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.CompilerServices; 3 | 4 | namespace BitSet 5 | { 6 | public static partial class BitReader 7 | { 8 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 9 | public static ushort ReadUInt10(byte[] buffer, int startByte = 0) 10 | { 11 | throw new NotImplementedException(); 12 | } 13 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 14 | public static ushort ReadUInt10(byte[] buffer, int startByte, byte bitOffset) 15 | { 16 | throw new NotImplementedException(); 17 | } 18 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 19 | public unsafe static ushort ReadUInt10(byte* buffer, int startByte = 0) 20 | { 21 | throw new NotImplementedException(); 22 | } 23 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 24 | public unsafe static ushort ReadUInt10(byte* buffer, int startByte, byte bitOffset) 25 | { 26 | throw new NotImplementedException(); 27 | } 28 | } 29 | public static partial class BitWriter 30 | { 31 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 32 | public static void WriteUInt10(ushort value, byte[] buffer, int startByte = 0) 33 | { 34 | throw new NotImplementedException(); 35 | } 36 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 37 | public static void WriteUInt10(ushort value, byte[] buffer, int startByte, byte bitOffset) 38 | { 39 | throw new NotImplementedException(); 40 | } 41 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 42 | public unsafe static void WriteUInt10(ushort value, byte* buffer, int startByte = 0) 43 | { 44 | throw new NotImplementedException(); 45 | } 46 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 47 | public unsafe static void WriteUInt10(ushort value, byte* buffer, int startByte, byte bitOffset) 48 | { 49 | throw new NotImplementedException(); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /BitSet/UInt20.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.CompilerServices; 3 | 4 | namespace BitSet 5 | { 6 | public static partial class BitReader 7 | { 8 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 9 | public static uint ReadUInt20(byte[] buffer, ref ulong startBit) 10 | { 11 | var retVal = ReadUInt20(buffer, startBit); 12 | startBit += 20; 13 | return retVal; 14 | } 15 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 16 | public static uint ReadUInt20(byte[] buffer, ulong startBit) 17 | { 18 | return ReadUInt20(buffer, (int)(startBit / 8), (byte)(startBit % 8)); 19 | } 20 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 21 | public static uint ReadUInt20(byte[] buffer, int startByte = 0) 22 | { 23 | throw new NotImplementedException(); 24 | } 25 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 26 | public static uint ReadUInt20(byte[] buffer, int startByte, byte bitOffset) 27 | { 28 | switch (bitOffset) 29 | { 30 | case 0: return ReadUInt20(buffer, startByte); 31 | 32 | case 1: 33 | case 2: 34 | case 3: 35 | case 4: 36 | return (ReadUInt24(buffer, startByte) >> bitOffset) & 0xFFFFF; 37 | 38 | case 5: 39 | case 6: 40 | case 7: 41 | return (ReadUInt32(buffer, startByte) >> bitOffset) & 0xFFFFF; 42 | } 43 | 44 | throw new ArgumentOutOfRangeException(nameof(bitOffset)); 45 | } 46 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 47 | public unsafe static uint ReadUInt20(byte* buffer, int startByte = 0) 48 | { 49 | throw new NotImplementedException(); 50 | } 51 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 52 | public unsafe static uint ReadUInt20(byte* buffer, int startByte, byte bitOffset) 53 | { 54 | throw new NotImplementedException(); 55 | } 56 | } 57 | public static partial class BitWriter 58 | { 59 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 60 | public static void WriteUInt20(uint value, byte[] buffer, int startByte = 0) 61 | { 62 | throw new NotImplementedException(); 63 | } 64 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 65 | public static void WriteUInt20(uint value, byte[] buffer, int startByte, byte bitOffset) 66 | { 67 | throw new NotImplementedException(); 68 | } 69 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 70 | public unsafe static void WriteUInt20(uint value, byte* buffer, int startByte = 0) 71 | { 72 | throw new NotImplementedException(); 73 | } 74 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 75 | public unsafe static void WriteUInt20(uint value, byte* buffer, int startByte, byte bitOffset) 76 | { 77 | throw new NotImplementedException(); 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /BitSet/UInt24.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.CompilerServices; 3 | 4 | namespace BitSet 5 | { 6 | public static partial class BitReader 7 | { 8 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 9 | public static uint ReadUInt24(byte[] buffer, ref ulong startBit) 10 | { 11 | var retVal = ReadUInt24(buffer, startBit); 12 | startBit += 24; 13 | return retVal; 14 | } 15 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 16 | public static uint ReadUInt24(byte[] buffer, ulong startBit) 17 | { 18 | return ReadUInt24(buffer, (int)(startBit / 8), (byte)(startBit % 8)); 19 | } 20 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 21 | public static uint ReadUInt24(byte[] buffer, int startByte = 0) 22 | { 23 | return (uint)(ReadUInt16(buffer, startByte) | (ReadUInt8(buffer, startByte + 2) << 16)); 24 | } 25 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 26 | public static uint ReadUInt24(byte[] buffer, int startByte, byte bitOffset) 27 | { 28 | throw new NotImplementedException(); 29 | } 30 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 31 | public unsafe static uint ReadUInt24(byte* buffer, int startByte = 0) 32 | { 33 | throw new NotImplementedException(); 34 | } 35 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 36 | public unsafe static uint ReadUInt24(byte* buffer, int startByte, byte bitOffset) 37 | { 38 | throw new NotImplementedException(); 39 | } 40 | } 41 | public static partial class BitWriter 42 | { 43 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 44 | public static void WriteUInt24(uint value, byte[] buffer, int startByte = 0) 45 | { 46 | throw new NotImplementedException(); 47 | } 48 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 49 | public static void WriteUInt24(uint value, byte[] buffer, int startByte, byte bitOffset) 50 | { 51 | throw new NotImplementedException(); 52 | } 53 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 54 | public unsafe static void WriteUInt24(uint value, byte* buffer, int startByte = 0) 55 | { 56 | throw new NotImplementedException(); 57 | } 58 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 59 | public unsafe static void WriteUInt24(uint value, byte* buffer, int startByte, byte bitOffset) 60 | { 61 | throw new NotImplementedException(); 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /BitSet/UInt3.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.CompilerServices; 3 | 4 | namespace BitSet 5 | { 6 | public static partial class BitReader 7 | { 8 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 9 | public static byte ReadUInt3(byte[] buffer, ref ulong startBit) 10 | { 11 | var retVal = ReadUInt3(buffer, startBit); 12 | startBit += 3; 13 | return retVal; 14 | } 15 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 16 | public static byte ReadUInt3(byte[] buffer, ulong startBit) 17 | { 18 | return ReadUInt3(buffer, (int)(startBit / 8), (byte)(startBit % 8)); 19 | } 20 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 21 | public static byte ReadUInt3(byte[] buffer, int startByte = 0) 22 | { 23 | throw new NotImplementedException(); 24 | } 25 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 26 | public static byte ReadUInt3(byte[] buffer, int startByte, byte bitOffset) 27 | { 28 | throw new NotImplementedException(); 29 | } 30 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 31 | public unsafe static byte ReadUInt3(byte* buffer, int startByte = 0) 32 | { 33 | throw new NotImplementedException(); 34 | } 35 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 36 | public unsafe static byte ReadUInt3(byte* buffer, int startByte, byte bitOffset) 37 | { 38 | throw new NotImplementedException(); 39 | } 40 | } 41 | public static partial class BitWriter 42 | { 43 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 44 | public static void WriteUInt3(byte value, byte[] buffer, int startByte = 0) 45 | { 46 | throw new NotImplementedException(); 47 | } 48 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 49 | public static void WriteUInt3(byte value, byte[] buffer, int startByte, byte bitOffset) 50 | { 51 | throw new NotImplementedException(); 52 | } 53 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 54 | public unsafe static void WriteUInt3(byte value, byte* buffer, int startByte = 0) 55 | { 56 | throw new NotImplementedException(); 57 | } 58 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 59 | public unsafe static void WriteUInt3(byte value, byte* buffer, int startByte, byte bitOffset) 60 | { 61 | throw new NotImplementedException(); 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /BitSet/UInt32.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.CompilerServices; 3 | 4 | namespace BitSet 5 | { 6 | public static partial class BitReader 7 | { 8 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 9 | public static uint ReadUInt32(byte[] buffer, ref ulong startBit) 10 | { 11 | var retVal = ReadUInt32(buffer, startBit); 12 | startBit += 32; 13 | return retVal; 14 | } 15 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 16 | public static uint ReadUInt32(byte[] buffer, ulong startBit) 17 | { 18 | return ReadUInt32(buffer, (int)(startBit / 8), (byte)(startBit % 8)); 19 | } 20 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 21 | public static uint ReadUInt32(byte[] buffer, int startByte = 0) 22 | { 23 | return BitConverter.ToUInt32(buffer, startByte); 24 | } 25 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 26 | public static uint ReadUInt32(byte[] buffer, int startByte, byte bitOffset) 27 | { 28 | switch (bitOffset) 29 | { 30 | case 0: return ReadUInt32(buffer, startByte); 31 | 32 | case 1: 33 | case 2: 34 | case 3: 35 | case 4: 36 | case 5: 37 | case 6: 38 | case 7: 39 | return (uint)((ReadUInt48(buffer, startByte) >> bitOffset) & 0xFFFFFFFF); 40 | } 41 | 42 | throw new ArgumentOutOfRangeException(nameof(bitOffset)); 43 | } 44 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 45 | public unsafe static uint ReadUInt32(byte* buffer, int startByte = 0) 46 | { 47 | throw new NotImplementedException(); 48 | } 49 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 50 | public unsafe static uint ReadUInt32(byte* buffer, int startByte, byte bitOffset) 51 | { 52 | throw new NotImplementedException(); 53 | } 54 | } 55 | public static partial class BitWriter 56 | { 57 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 58 | public static void WriteUInt32(uint value, byte[] buffer, int startByte = 0) 59 | { 60 | throw new NotImplementedException(); 61 | } 62 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 63 | public static void WriteUInt32(uint value, byte[] buffer, int startByte, byte bitOffset) 64 | { 65 | throw new NotImplementedException(); 66 | } 67 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 68 | public unsafe static void WriteUInt32(uint value, byte* buffer, int startByte = 0) 69 | { 70 | throw new NotImplementedException(); 71 | } 72 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 73 | public unsafe static void WriteUInt32(uint value, byte* buffer, int startByte, byte bitOffset) 74 | { 75 | throw new NotImplementedException(); 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /BitSet/UInt4.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.CompilerServices; 3 | 4 | namespace BitSet 5 | { 6 | public static partial class BitReader 7 | { 8 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 9 | public static byte ReadUInt4(byte[] buffer, ref ulong startBit) 10 | { 11 | var retVal = ReadUInt4(buffer, startBit); 12 | startBit += 4; 13 | return retVal; 14 | } 15 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 16 | public static byte ReadUInt4(byte[] buffer, ulong startBit) 17 | { 18 | return ReadUInt4(buffer, (int)(startBit / 8), (byte)(startBit % 8)); 19 | } 20 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 21 | public static byte ReadUInt4(byte[] buffer, int startByte = 0) 22 | { 23 | return (byte)(buffer[startByte] & 0xF); 24 | } 25 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 26 | public static byte ReadUInt4(byte[] buffer, int startByte, byte bitOffset) 27 | { 28 | throw new NotImplementedException(); 29 | } 30 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 31 | public unsafe static byte ReadUInt4(byte* buffer, int startByte = 0) 32 | { 33 | return (byte)(buffer[startByte] & 0xF); 34 | } 35 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 36 | public unsafe static byte ReadUInt4(byte* buffer, int startByte, byte bitOffset) 37 | { 38 | switch (bitOffset) 39 | { 40 | case 0: 41 | case 1: 42 | case 2: 43 | case 3: 44 | return (byte)((buffer[startByte] >> bitOffset) & 0xF); 45 | 46 | case 4: 47 | case 5: 48 | case 6: 49 | case 7: 50 | return (byte)((*(ushort*)(&buffer[startByte]) >> bitOffset) & 0xF); 51 | } 52 | 53 | throw new ArgumentOutOfRangeException(nameof(bitOffset)); 54 | } 55 | } 56 | public static partial class BitWriter 57 | { 58 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 59 | public static void WriteUInt4(byte value, byte[] buffer, int startByte = 0) 60 | { 61 | throw new NotImplementedException(); 62 | } 63 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 64 | public static void WriteUInt4(byte value, byte[] buffer, int startByte, byte bitOffset) 65 | { 66 | throw new NotImplementedException(); 67 | } 68 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 69 | public unsafe static void WriteUInt4(byte value, byte* buffer, int startByte = 0) 70 | { 71 | buffer[startByte] = (byte)((buffer[startByte] & ~0x0F) | (value & 0x0F)); 72 | } 73 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 74 | public unsafe static void WriteUInt4(byte value, byte* buffer, int startByte, byte bitOffset) 75 | { 76 | switch (bitOffset) 77 | { 78 | case 0: WriteUInt4(value, buffer, startByte); return; 79 | 80 | case 4: buffer[startByte] = (byte)((buffer[startByte] & 0x0F) | (value << 4)); return; 81 | 82 | case 1: 83 | case 2: 84 | case 3: 85 | case 5: 86 | case 6: 87 | case 7: 88 | throw new NotImplementedException(); 89 | } 90 | 91 | throw new ArgumentOutOfRangeException(nameof(bitOffset)); 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /BitSet/UInt48.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.CompilerServices; 3 | 4 | namespace BitSet 5 | { public static partial class BitReader 6 | { 7 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 8 | public static ulong ReadUInt48(byte[] buffer, ref ulong startBit) 9 | { 10 | var retVal = ReadUInt48(buffer, startBit); 11 | startBit += 48; 12 | return retVal; 13 | } 14 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 15 | public static ulong ReadUInt48(byte[] buffer, ulong startBit) 16 | { 17 | return ReadUInt48(buffer, (int)(startBit / 8), (byte)(startBit % 8)); 18 | } 19 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 20 | public static ulong ReadUInt48(byte[] buffer, int startByte = 0) 21 | { 22 | return ReadUInt32(buffer, startByte) | ((ulong)ReadUInt8(buffer, startByte + 4) << 32); 23 | } 24 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 25 | public static ulong ReadUInt48(byte[] buffer, int startByte, byte bitOffset) 26 | { 27 | throw new NotImplementedException(); 28 | } 29 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 30 | public unsafe static ulong ReadUInt48(byte* buffer, int startByte = 0) 31 | { 32 | throw new NotImplementedException(); 33 | } 34 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 35 | public unsafe static ulong ReadUInt48(byte* buffer, int startByte, byte bitOffset) 36 | { 37 | throw new NotImplementedException(); 38 | } 39 | } 40 | public static partial class BitWriter 41 | { 42 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 43 | public static void WriteUInt48(ulong value, byte[] buffer, int startByte = 0) 44 | { 45 | throw new NotImplementedException(); 46 | } 47 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 48 | public static void WriteUInt48(ulong value, byte[] buffer, int startByte, byte bitOffset) 49 | { 50 | throw new NotImplementedException(); 51 | } 52 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 53 | public unsafe static void WriteUInt48(ulong value, byte* buffer, int startByte = 0) 54 | { 55 | throw new NotImplementedException(); 56 | } 57 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 58 | public unsafe static void WriteUInt48(ulong value, byte* buffer, int startByte, byte bitOffset) 59 | { 60 | throw new NotImplementedException(); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /BitSet/UInt8.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.CompilerServices; 3 | 4 | namespace BitSet 5 | { 6 | public static partial class BitReader 7 | { 8 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 9 | public static byte ReadUInt8(byte[] buffer, ref ulong startBit) 10 | { 11 | var retVal = ReadUInt8(buffer, startBit); 12 | startBit += 8; 13 | return retVal; 14 | } 15 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 16 | public static byte ReadUInt8(byte[] buffer, ulong startBit) 17 | { 18 | return ReadUInt8(buffer, (int)(startBit / 8), (byte)(startBit % 8)); 19 | } 20 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 21 | public static byte ReadUInt8(byte[] buffer, int startByte = 0) 22 | { 23 | return buffer[startByte]; 24 | } 25 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 26 | public static byte ReadUInt8(byte[] buffer, int startByte, byte bitOffset) 27 | { 28 | throw new NotImplementedException(); 29 | } 30 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 31 | public unsafe static byte ReadUInt8(byte* buffer, int startByte = 0) 32 | { 33 | return buffer[startByte]; 34 | } 35 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 36 | public unsafe static byte ReadUInt8(byte* buffer, int startByte, byte bitOffset) 37 | { 38 | switch (bitOffset) 39 | { 40 | case 0: return ReadUInt8(buffer, startByte); 41 | 42 | case 1: 43 | case 2: 44 | case 3: 45 | case 4: 46 | case 5: 47 | case 6: 48 | case 7: 49 | throw new NotImplementedException(); 50 | } 51 | 52 | throw new ArgumentOutOfRangeException(nameof(bitOffset)); 53 | } 54 | } 55 | public static partial class BitWriter 56 | { 57 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 58 | public static void WriteUInt8(byte value, byte[] buffer, int startByte = 0) 59 | { 60 | buffer[startByte] = value; 61 | } 62 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 63 | public static void WriteUInt8(byte value, byte[] buffer, int startByte, byte bitOffset) 64 | { 65 | throw new NotImplementedException(); 66 | } 67 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 68 | public unsafe static void WriteUInt8(byte value, byte* buffer, int startByte = 0) 69 | { 70 | buffer[startByte] = value; 71 | } 72 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 73 | public unsafe static void WriteUInt8(byte value, byte* buffer, int startByte, byte bitOffset) 74 | { 75 | switch (bitOffset) 76 | { 77 | case 0: WriteUInt8(value, buffer, startByte); return; 78 | 79 | case 1: 80 | case 2: 81 | case 3: 82 | case 4: 83 | case 5: 84 | case 6: 85 | case 7: 86 | throw new NotImplementedException(); 87 | } 88 | 89 | throw new ArgumentOutOfRangeException(nameof(bitOffset)); 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /BitSet/VarInt.cs: -------------------------------------------------------------------------------- 1 | namespace BitSet 2 | { 3 | public static partial class BitReader 4 | { 5 | const int MAX_VARINT_BITS = 35; 6 | 7 | public static uint ReadVarInt(byte[] buffer, ref ulong bitOffset) 8 | { 9 | uint dest = 0; 10 | 11 | for (byte run = 0; run < 35; run += 7) 12 | { 13 | byte oneByte = (byte)ReadUIntBits(buffer, ref bitOffset, 8); 14 | dest |= ((oneByte & (uint)0x7F) << run); 15 | 16 | if ((oneByte >> 7) == 0) 17 | break; 18 | } 19 | 20 | return dest; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /DemoLib.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.25420.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DemoLib", "DemoLib\DemoLib.csproj", "{95495901-1A5C-47A2-BB54-8F7EE9004A77}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Launcher", "Launcher\Launcher.csproj", "{5DCD86FB-1299-4B6F-BDC1-59A57496F197}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BitSet", "BitSet\BitSet.csproj", "{8F8A6380-5B10-4891-AC21-3D03494B3E44}" 11 | EndProject 12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TF2Net", "TF2Net\TF2Net.csproj", "{2C2AF7CC-4368-4C03-B7E1-356D3BB89F4F}" 13 | EndProject 14 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PlayerPositionsTest", "PlayerPositionsTest\PlayerPositionsTest.csproj", "{B218DDCA-83BB-45DF-8958-027590F3CF65}" 15 | EndProject 16 | Global 17 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 18 | Debug|Any CPU = Debug|Any CPU 19 | Release|Any CPU = Release|Any CPU 20 | EndGlobalSection 21 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 22 | {95495901-1A5C-47A2-BB54-8F7EE9004A77}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 23 | {95495901-1A5C-47A2-BB54-8F7EE9004A77}.Debug|Any CPU.Build.0 = Debug|Any CPU 24 | {95495901-1A5C-47A2-BB54-8F7EE9004A77}.Release|Any CPU.ActiveCfg = Release|Any CPU 25 | {95495901-1A5C-47A2-BB54-8F7EE9004A77}.Release|Any CPU.Build.0 = Release|Any CPU 26 | {5DCD86FB-1299-4B6F-BDC1-59A57496F197}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 27 | {5DCD86FB-1299-4B6F-BDC1-59A57496F197}.Debug|Any CPU.Build.0 = Debug|Any CPU 28 | {5DCD86FB-1299-4B6F-BDC1-59A57496F197}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {5DCD86FB-1299-4B6F-BDC1-59A57496F197}.Release|Any CPU.Build.0 = Release|Any CPU 30 | {8F8A6380-5B10-4891-AC21-3D03494B3E44}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 31 | {8F8A6380-5B10-4891-AC21-3D03494B3E44}.Debug|Any CPU.Build.0 = Debug|Any CPU 32 | {8F8A6380-5B10-4891-AC21-3D03494B3E44}.Release|Any CPU.ActiveCfg = Release|Any CPU 33 | {8F8A6380-5B10-4891-AC21-3D03494B3E44}.Release|Any CPU.Build.0 = Release|Any CPU 34 | {2C2AF7CC-4368-4C03-B7E1-356D3BB89F4F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 35 | {2C2AF7CC-4368-4C03-B7E1-356D3BB89F4F}.Debug|Any CPU.Build.0 = Debug|Any CPU 36 | {2C2AF7CC-4368-4C03-B7E1-356D3BB89F4F}.Release|Any CPU.ActiveCfg = Release|Any CPU 37 | {2C2AF7CC-4368-4C03-B7E1-356D3BB89F4F}.Release|Any CPU.Build.0 = Release|Any CPU 38 | {B218DDCA-83BB-45DF-8958-027590F3CF65}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 39 | {B218DDCA-83BB-45DF-8958-027590F3CF65}.Debug|Any CPU.Build.0 = Debug|Any CPU 40 | {B218DDCA-83BB-45DF-8958-027590F3CF65}.Release|Any CPU.ActiveCfg = Release|Any CPU 41 | {B218DDCA-83BB-45DF-8958-027590F3CF65}.Release|Any CPU.Build.0 = Release|Any CPU 42 | EndGlobalSection 43 | GlobalSection(SolutionProperties) = preSolution 44 | HideSolutionNode = FALSE 45 | EndGlobalSection 46 | EndGlobal 47 | -------------------------------------------------------------------------------- /DemoLib/Commands/DemoCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace DemoLib.Commands 8 | { 9 | public class DemoCommand 10 | { 11 | public DemoCommandType Type { get; protected set; } = DemoCommandType.dem_invalid; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /DemoLib/Commands/DemoConsoleCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace DemoLib.Commands 10 | { 11 | [DebuggerDisplay("{DebuggerDisplayAttributeValue,nq}")] 12 | sealed class DemoConsoleCommand : TimestampedDemoCommand 13 | { 14 | public string Command { get; set; } 15 | 16 | [DebuggerBrowsable(DebuggerBrowsableState.Never)] 17 | private string DebuggerDisplayAttributeValue 18 | { 19 | get { return Command.Replace('"', '\''); } 20 | } 21 | 22 | public DemoConsoleCommand(Stream input) : base(input) 23 | { 24 | Type = DemoCommandType.dem_consolecmd; 25 | 26 | using (BinaryReader reader = new BinaryReader(input, Encoding.ASCII, true)) 27 | Command = new string(reader.ReadChars(reader.ReadInt32())).TrimEnd('\0'); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /DemoLib/Commands/DemoPacketCommand.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Diagnostics; 3 | using System.IO; 4 | using System.Text; 5 | using BitSet; 6 | using TF2Net; 7 | using TF2Net.Data; 8 | using TF2Net.NetMessages; 9 | 10 | namespace DemoLib.Commands 11 | { 12 | [DebuggerDisplay("{Tick, nq} network packet [{Data.Length, nq}]")] 13 | class DemoPacketCommand : TimestampedDemoCommand 14 | { 15 | public DemoViewpoint Viewpoint { get; set; } 16 | 17 | public int SequenceIn { get; set; } 18 | public int SequenceOut { get; set; } 19 | 20 | public IList Messages { get; set; } 21 | 22 | public DemoPacketCommand(Stream input) : base(input) 23 | { 24 | Type = DemoCommandType.dem_packet; 25 | 26 | using (BinaryReader r = new BinaryReader(input, Encoding.ASCII, true)) 27 | { 28 | Viewpoint = new DemoViewpoint(); 29 | 30 | Viewpoint.ViewpointFlags = (DemoViewpoint.Flags)r.ReadInt32(); 31 | 32 | Viewpoint.ViewOrigin1 = new Vector(r.ReadSingle(), r.ReadSingle(), r.ReadSingle()); 33 | Viewpoint.ViewAngles1 = new Vector(r.ReadSingle(), r.ReadSingle(), r.ReadSingle()); 34 | Viewpoint.LocalViewAngles1 = new Vector(r.ReadSingle(), r.ReadSingle(), r.ReadSingle()); 35 | 36 | Viewpoint.ViewOrigin2 = new Vector(r.ReadSingle(), r.ReadSingle(), r.ReadSingle()); 37 | Viewpoint.ViewAngles2 = new Vector(r.ReadSingle(), r.ReadSingle(), r.ReadSingle()); 38 | Viewpoint.LocalViewAngles2 = new Vector(r.ReadSingle(), r.ReadSingle(), r.ReadSingle()); 39 | 40 | SequenceIn = r.ReadInt32(); 41 | SequenceOut = r.ReadInt32(); 42 | 43 | BitStream data = new BitStream(r.ReadBytes((int)r.ReadUInt32())); 44 | Messages = NetMessageCoder.Decode(data).ToArray(); 45 | } 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /DemoLib/Commands/DemoSignonCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace DemoLib.Commands 9 | { 10 | sealed class DemoSignonCommand : DemoPacketCommand 11 | { 12 | public DemoSignonCommand(Stream input, ulong signonLength) : base(input) 13 | { 14 | Type = DemoCommandType.dem_signon; 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /DemoLib/Commands/DemoStringTablesCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using BitSet; 8 | 9 | namespace DemoLib.Commands 10 | { 11 | sealed class DemoStringTablesCommand : TimestampedDemoCommand 12 | { 13 | public BitStream Data { get; set; } 14 | 15 | public DemoStringTablesCommand(Stream input) : base(input) 16 | { 17 | Type = DemoCommandType.dem_stringtables; 18 | 19 | using (BinaryReader reader = new BinaryReader(input, Encoding.ASCII, true)) 20 | { 21 | int dataLength = reader.ReadInt32(); 22 | Data = new BitStream(reader.ReadBytes(dataLength)); 23 | 24 | /*while (true) 25 | { 26 | ulong startCursor = Data.Cursor; 27 | 28 | string test = Data.ReadCString(); 29 | Console.WriteLine(test); 30 | 31 | Data.Cursor = startCursor + 1; 32 | }*/ 33 | } 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /DemoLib/Commands/DemoSyncTickCommand.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using System.IO; 3 | 4 | namespace DemoLib.Commands 5 | { 6 | [DebuggerDisplay("{Tick, nq} dem_synctick")] 7 | sealed class DemoSyncTickCommand : TimestampedDemoCommand 8 | { 9 | public DemoSyncTickCommand(Stream input) : base(input) 10 | { 11 | Type = DemoCommandType.dem_synctick; 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /DemoLib/Commands/DemoUserCommand.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using System.IO; 3 | using System.Text; 4 | 5 | namespace DemoLib.Commands 6 | { 7 | [DebuggerDisplay("{Tick, nq} dem_usercmd")] 8 | sealed class DemoUserCommand : TimestampedDemoCommand 9 | { 10 | public int OutgoingSequence { get; set; } 11 | 12 | public byte[] Data { get; set; } 13 | 14 | public DemoUserCommand(Stream input) : base(input) 15 | { 16 | Type = DemoCommandType.dem_usercmd; 17 | 18 | using (BinaryReader reader = new BinaryReader(input, Encoding.ASCII, true)) 19 | { 20 | OutgoingSequence = reader.ReadInt32(); 21 | 22 | Data = reader.ReadBytes(reader.ReadInt32()); 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /DemoLib/Commands/TimestampedDemoCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace DemoLib.Commands 9 | { 10 | class TimestampedDemoCommand : DemoCommand 11 | { 12 | public int Tick { get; set; } 13 | 14 | public TimestampedDemoCommand(Stream input) 15 | { 16 | using (BinaryReader reader = new BinaryReader(input, Encoding.Default, true)) 17 | { 18 | Tick = reader.ReadInt32(); 19 | } 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /DemoLib/DemoCommandType.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace DemoLib 8 | { 9 | public enum DemoCommandType : byte 10 | { 11 | // PAZER: added 12 | dem_invalid = 0, 13 | 14 | // it's a startup message, process as fast as possible 15 | dem_signon = 1, 16 | // it's a normal network packet that we stored off 17 | dem_packet, 18 | // sync client clock to demo tick 19 | dem_synctick, 20 | // console command 21 | dem_consolecmd, 22 | // user input command 23 | dem_usercmd, 24 | // network data tables 25 | dem_datatables, 26 | // end of time. 27 | dem_stop, 28 | 29 | dem_stringtables, 30 | 31 | // Last command -- not necessary in C# 32 | //dem_lastcmd = dem_stringtables 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /DemoLib/DemoHeader.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Text; 4 | using TF2Net.Data; 5 | 6 | namespace DemoLib 7 | { 8 | public class DemoHeader 9 | { 10 | public readonly string m_MagicToken; 11 | const string EXPECTED_MAGIC_TOKEN = "HL2DEMO"; 12 | 13 | public readonly int? m_DemoProtocol; 14 | public readonly int? m_NetworkProtocol; 15 | public readonly string m_ServerName; 16 | public readonly string m_ClientName; 17 | public readonly string m_MapName; 18 | public readonly string m_GameDirectory; 19 | 20 | public readonly float? m_PlaybackTime; 21 | public readonly int? m_PlaybackTicks; 22 | public readonly int? m_PlaybackFrames; 23 | public readonly int? m_SignonLength; 24 | 25 | public DemoHeader(Stream inputStream) 26 | { 27 | using (BinaryReader reader = new BinaryReader(inputStream, Encoding.ASCII, true)) 28 | { 29 | m_MagicToken = Encoding.ASCII.GetString(reader.ReadBytes(8)).TrimEnd('\0'); 30 | if (m_MagicToken != EXPECTED_MAGIC_TOKEN) 31 | throw new FormatException(string.Format("Expected magic token: \"{0}\" Actual magic token: \"{1}\"", EXPECTED_MAGIC_TOKEN, m_MagicToken)); 32 | 33 | m_DemoProtocol = reader.ReadInt32(); 34 | m_NetworkProtocol = reader.ReadInt32(); 35 | 36 | m_ServerName = Encoding.ASCII.GetString(reader.ReadBytes(SourceConstants.MAX_OSPATH)).TrimEnd('\0'); 37 | m_ClientName = Encoding.ASCII.GetString(reader.ReadBytes(SourceConstants.MAX_OSPATH)).TrimEnd('\0'); 38 | m_MapName = Encoding.ASCII.GetString(reader.ReadBytes(SourceConstants.MAX_OSPATH)).TrimEnd('\0'); 39 | m_GameDirectory = Encoding.ASCII.GetString(reader.ReadBytes(SourceConstants.MAX_OSPATH)).TrimEnd('\0'); 40 | 41 | m_PlaybackTime = reader.ReadSingle(); 42 | m_PlaybackTicks = reader.ReadInt32(); 43 | m_PlaybackFrames = reader.ReadInt32(); 44 | m_SignonLength = reader.ReadInt32(); 45 | } 46 | } 47 | 48 | public DemoHeader(string magicToken = null, int? demoProtocol = null, int? networkProtocol = null, 49 | string serverName = null, string clientName = null, string mapName = null, string gameDirectory = null, 50 | float? playbackTime = null, int? playbackTicks = null, int? playbackFrames = null, int? signonLength = null) 51 | { 52 | m_MagicToken = magicToken; 53 | m_DemoProtocol = demoProtocol; 54 | m_NetworkProtocol = networkProtocol; 55 | m_ServerName = serverName; 56 | m_ClientName = clientName; 57 | m_MapName = mapName; 58 | m_GameDirectory = gameDirectory; 59 | m_PlaybackTime = playbackTime; 60 | m_PlaybackTicks = playbackTicks; 61 | m_PlaybackFrames = playbackFrames; 62 | m_SignonLength = signonLength; 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /DemoLib/DemoParseException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace DemoLib 8 | { 9 | 10 | [Serializable] 11 | public class DemoParseException : Exception 12 | { 13 | public DemoParseException(string message) : base(message) { } 14 | public DemoParseException(string message, Exception inner) : base(message, inner) { } 15 | protected DemoParseException( 16 | System.Runtime.Serialization.SerializationInfo info, 17 | System.Runtime.Serialization.StreamingContext context) : base(info, context) { } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /DemoLib/DemoViewpoint.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using TF2Net.Data; 7 | 8 | namespace DemoLib 9 | { 10 | class DemoViewpoint 11 | { 12 | [Flags] 13 | public enum Flags 14 | { 15 | None = 0, 16 | UseOrigin2 = (1 << 0), 17 | UseAngles2 = (1 << 1), 18 | NoInterp = (1 << 2), 19 | } 20 | 21 | public Flags ViewpointFlags { get; set; } 22 | 23 | public Vector ViewOrigin1 { get; set; } 24 | public Vector ViewAngles1 { get; set; } 25 | public Vector LocalViewAngles1 { get; set; } 26 | 27 | public Vector ViewOrigin2 { get; set; } 28 | public Vector ViewAngles2 { get; set; } 29 | public Vector LocalViewAngles2 { get; set; } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /DemoLib/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("DemoLib")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("DemoLib")] 13 | [assembly: AssemblyCopyright("Copyright © 2016")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("95495901-1a5c-47a2-bb54-8f7ee9004a77")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /DemoLib/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /Launcher/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /Launcher/Launcher.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {5DCD86FB-1299-4B6F-BDC1-59A57496F197} 8 | Exe 9 | Properties 10 | DemoLib.Launcher 11 | Launcher 12 | v4.6.1 13 | 512 14 | true 15 | 16 | 17 | 18 | AnyCPU 19 | true 20 | full 21 | false 22 | bin\Debug\ 23 | DEBUG;TRACE 24 | prompt 25 | 4 26 | false 27 | false 28 | 29 | 30 | AnyCPU 31 | pdbonly 32 | true 33 | bin\Release\ 34 | TRACE 35 | prompt 36 | 4 37 | false 38 | false 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | {95495901-1a5c-47a2-bb54-8f7ee9004a77} 60 | DemoLib 61 | 62 | 63 | {2C2AF7CC-4368-4C03-B7E1-356D3BB89F4F} 64 | TF2Net 65 | 66 | 67 | 68 | 75 | -------------------------------------------------------------------------------- /Launcher/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using DemoLib; 8 | 9 | namespace DemoLib.Launcher 10 | { 11 | class Program 12 | { 13 | static void Main(string[] args) 14 | { 15 | using (var stream = File.Open(@"D:\Steam\steamapps\common\Team Fortress 2\tf\demos\testdemo.dem", FileMode.Open, FileAccess.Read)) 16 | { 17 | Console.WriteLine("Parsing test demo file..."); 18 | 19 | DateTime start = DateTime.Now; 20 | DemoReader reader = DemoReader.FromStream(stream); 21 | DateTime end = DateTime.Now; 22 | 23 | Console.WriteLine("Finished parsing test demo file in {0:N1}ms.", (end - start).TotalMilliseconds); 24 | 25 | reader.SimulateDemo(); 26 | 27 | Console.WriteLine("Finished simulating demo."); 28 | Console.ReadLine(); 29 | } 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Launcher/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Launcher")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Launcher")] 13 | [assembly: AssemblyCopyright("Copyright © 2016")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("5dcd86fb-1299-4b6f-bdc1-59a57496f197")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /PlayerPositionsTest/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /PlayerPositionsTest/App.xaml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /PlayerPositionsTest/App.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Configuration; 4 | using System.Data; 5 | using System.Linq; 6 | using System.Threading.Tasks; 7 | using System.Windows; 8 | 9 | namespace PlayerPositionsTest 10 | { 11 | /// 12 | /// Interaction logic for App.xaml 13 | /// 14 | public partial class App : Application 15 | { 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /PlayerPositionsTest/BooleanConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Globalization; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Windows.Data; 8 | 9 | namespace PlayerPositionsTest 10 | { 11 | class BooleanConverter : IValueConverter 12 | { 13 | public T True { get; set; } 14 | public T False { get; set; } 15 | 16 | public BooleanConverter(T trueValue, T falseValue) 17 | { 18 | True = trueValue; 19 | False = falseValue; 20 | } 21 | 22 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 23 | { 24 | return value is bool && ((bool)value) ? True : False; 25 | } 26 | 27 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 28 | { 29 | return value is T && EqualityComparer.Default.Equals((T)value, True); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /PlayerPositionsTest/BooleanToVisibilityConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows; 7 | 8 | namespace PlayerPositionsTest 9 | { 10 | class BooleanToVisibilityConverter : BooleanConverter 11 | { 12 | public BooleanToVisibilityConverter() : base(Visibility.Visible, Visibility.Hidden) { } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /PlayerPositionsTest/DesignData/PlayerStatusSampleData.xaml: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /PlayerPositionsTest/DesignData/PlayerStatusesSampleData.xaml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /PlayerPositionsTest/MainWindow.xaml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 54 | 55 | -------------------------------------------------------------------------------- /PlayerPositionsTest/PlayerStatus.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using System.Runtime.CompilerServices; 3 | using TF2Net.Data; 4 | 5 | namespace PlayerPositionsTest 6 | { 7 | public class PlayerStatus : INotifyPropertyChanged 8 | { 9 | public PlayerStatus() { } 10 | 11 | public string GUID { get; set; } 12 | 13 | string m_Nickname; 14 | public string Nickname 15 | { 16 | get { return m_Nickname; } 17 | set 18 | { 19 | if (value != m_Nickname) 20 | { 21 | m_Nickname = value; 22 | NotifyPropertyChanged(); 23 | } 24 | } 25 | } 26 | 27 | bool m_IsDead; 28 | public bool IsDead 29 | { 30 | get { return m_IsDead; } 31 | set 32 | { 33 | if (value != m_IsDead) 34 | { 35 | m_IsDead = value; 36 | NotifyPropertyChanged(); 37 | } 38 | } 39 | } 40 | 41 | Team m_Team; 42 | public Team Team 43 | { 44 | get { return m_Team; } 45 | set 46 | { 47 | if (value != m_Team) 48 | { 49 | m_Team = value; 50 | NotifyPropertyChanged(); 51 | } 52 | } 53 | } 54 | 55 | int m_Health; 56 | public int Health 57 | { 58 | get { return m_Health; } 59 | set 60 | { 61 | if (value != m_Health) 62 | { 63 | m_Health = value; 64 | NotifyPropertyChanged(); 65 | } 66 | } 67 | } 68 | 69 | uint m_MaxHealth; 70 | public uint MaxHealth 71 | { 72 | get { return m_MaxHealth; } 73 | set 74 | { 75 | if (value != m_MaxHealth) 76 | { 77 | m_MaxHealth = value; 78 | NotifyPropertyChanged(); 79 | NotifyPropertyChanged(nameof(MaxOverheal)); 80 | } 81 | } 82 | } 83 | 84 | public uint MaxOverheal { get { return (uint)(m_MaxHealth * 1.5) / 5 * 5; } } 85 | 86 | string m_ClassPortrait; 87 | public string ClassPortrait 88 | { 89 | get { return m_ClassPortrait; } 90 | set 91 | { 92 | if (value != m_ClassPortrait) 93 | { 94 | m_ClassPortrait = value; 95 | NotifyPropertyChanged(); 96 | } 97 | } 98 | } 99 | 100 | public uint LastDPM { get; set; } 101 | public uint LastDamage { get; set; } 102 | 103 | double m_DPM; 104 | public double DPM 105 | { 106 | get { return m_DPM; } 107 | set 108 | { 109 | if (value != m_DPM) 110 | { 111 | m_DPM = value; 112 | NotifyPropertyChanged(); 113 | NotifyPropertyChanged(nameof(IntDPM)); 114 | } 115 | } 116 | } 117 | 118 | public uint IntDPM { get { return (uint)DPM; } } 119 | 120 | public event PropertyChangedEventHandler PropertyChanged; 121 | 122 | private void NotifyPropertyChanged([CallerMemberName] string propertyName = "") 123 | { 124 | PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 125 | } 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /PlayerPositionsTest/PlayerStatusesList.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace PlayerPositionsTest 9 | { 10 | public class PlayerStatusesList : BindingList { } 11 | } 12 | -------------------------------------------------------------------------------- /PlayerPositionsTest/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Resources; 3 | using System.Runtime.CompilerServices; 4 | using System.Runtime.InteropServices; 5 | using System.Windows; 6 | 7 | // General Information about an assembly is controlled through the following 8 | // set of attributes. Change these attribute values to modify the information 9 | // associated with an assembly. 10 | [assembly: AssemblyTitle("PlayerPositionsTest")] 11 | [assembly: AssemblyDescription("")] 12 | [assembly: AssemblyConfiguration("")] 13 | [assembly: AssemblyCompany("")] 14 | [assembly: AssemblyProduct("PlayerPositionsTest")] 15 | [assembly: AssemblyCopyright("Copyright © 2016")] 16 | [assembly: AssemblyTrademark("")] 17 | [assembly: AssemblyCulture("")] 18 | 19 | // Setting ComVisible to false makes the types in this assembly not visible 20 | // to COM components. If you need to access a type in this assembly from 21 | // COM, set the ComVisible attribute to true on that type. 22 | [assembly: ComVisible(false)] 23 | 24 | //In order to begin building localizable applications, set 25 | //CultureYouAreCodingWith in your .csproj file 26 | //inside a . For example, if you are using US english 27 | //in your source files, set the to en-US. Then uncomment 28 | //the NeutralResourceLanguage attribute below. Update the "en-US" in 29 | //the line below to match the UICulture setting in the project file. 30 | 31 | //[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] 32 | 33 | 34 | [assembly: ThemeInfo( 35 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located 36 | //(used if a resource is not found in the page, 37 | // or application resource dictionaries) 38 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located 39 | //(used if a resource is not found in the page, 40 | // app, or any theme specific resource dictionaries) 41 | )] 42 | 43 | 44 | // Version information for an assembly consists of the following four values: 45 | // 46 | // Major Version 47 | // Minor Version 48 | // Build Number 49 | // Revision 50 | // 51 | // You can specify all the values or you can default the Build and Revision Numbers 52 | // by using the '*' as shown below: 53 | // [assembly: AssemblyVersion("1.0.*")] 54 | [assembly: AssemblyVersion("1.0.0.0")] 55 | [assembly: AssemblyFileVersion("1.0.0.0")] 56 | -------------------------------------------------------------------------------- /PlayerPositionsTest/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 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 PlayerPositionsTest.Properties { 12 | using System; 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 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal Resources() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("PlayerPositionsTest.Properties.Resources", typeof(Resources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /PlayerPositionsTest/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 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 PlayerPositionsTest.Properties { 12 | 13 | 14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "14.0.0.0")] 16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { 17 | 18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 19 | 20 | public static Settings Default { 21 | get { 22 | return defaultInstance; 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /PlayerPositionsTest/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /PlayerPositionsTest/ViewboxVerticalStretch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Globalization; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Windows.Controls; 8 | using System.Windows.Data; 9 | 10 | namespace PlayerPositionsTest 11 | { 12 | class ViewboxVerticalStretch : IValueConverter 13 | { 14 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 15 | { 16 | Grid self = (Grid)value; 17 | 18 | var test = self.Parent; 19 | throw new NotImplementedException(); 20 | } 21 | 22 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 23 | { 24 | throw new NotImplementedException(); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /PlayerPositionsTest/class_portraits/alpha/all_class.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/class_portraits/alpha/all_class.png -------------------------------------------------------------------------------- /PlayerPositionsTest/class_portraits/alpha/demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/class_portraits/alpha/demo.png -------------------------------------------------------------------------------- /PlayerPositionsTest/class_portraits/alpha/demo_blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/class_portraits/alpha/demo_blue.png -------------------------------------------------------------------------------- /PlayerPositionsTest/class_portraits/alpha/demo_blue_grey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/class_portraits/alpha/demo_blue_grey.png -------------------------------------------------------------------------------- /PlayerPositionsTest/class_portraits/alpha/demo_grey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/class_portraits/alpha/demo_grey.png -------------------------------------------------------------------------------- /PlayerPositionsTest/class_portraits/alpha/engie.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/class_portraits/alpha/engie.png -------------------------------------------------------------------------------- /PlayerPositionsTest/class_portraits/alpha/engie_blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/class_portraits/alpha/engie_blue.png -------------------------------------------------------------------------------- /PlayerPositionsTest/class_portraits/alpha/engie_blue_grey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/class_portraits/alpha/engie_blue_grey.png -------------------------------------------------------------------------------- /PlayerPositionsTest/class_portraits/alpha/engie_grey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/class_portraits/alpha/engie_grey.png -------------------------------------------------------------------------------- /PlayerPositionsTest/class_portraits/alpha/heavy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/class_portraits/alpha/heavy.png -------------------------------------------------------------------------------- /PlayerPositionsTest/class_portraits/alpha/heavy_blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/class_portraits/alpha/heavy_blue.png -------------------------------------------------------------------------------- /PlayerPositionsTest/class_portraits/alpha/heavy_blue_grey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/class_portraits/alpha/heavy_blue_grey.png -------------------------------------------------------------------------------- /PlayerPositionsTest/class_portraits/alpha/heavy_grey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/class_portraits/alpha/heavy_grey.png -------------------------------------------------------------------------------- /PlayerPositionsTest/class_portraits/alpha/medic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/class_portraits/alpha/medic.png -------------------------------------------------------------------------------- /PlayerPositionsTest/class_portraits/alpha/medic_blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/class_portraits/alpha/medic_blue.png -------------------------------------------------------------------------------- /PlayerPositionsTest/class_portraits/alpha/medic_blue_grey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/class_portraits/alpha/medic_blue_grey.png -------------------------------------------------------------------------------- /PlayerPositionsTest/class_portraits/alpha/medic_grey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/class_portraits/alpha/medic_grey.png -------------------------------------------------------------------------------- /PlayerPositionsTest/class_portraits/alpha/pyro.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/class_portraits/alpha/pyro.png -------------------------------------------------------------------------------- /PlayerPositionsTest/class_portraits/alpha/pyro_blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/class_portraits/alpha/pyro_blue.png -------------------------------------------------------------------------------- /PlayerPositionsTest/class_portraits/alpha/pyro_blue_grey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/class_portraits/alpha/pyro_blue_grey.png -------------------------------------------------------------------------------- /PlayerPositionsTest/class_portraits/alpha/pyro_grey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/class_portraits/alpha/pyro_grey.png -------------------------------------------------------------------------------- /PlayerPositionsTest/class_portraits/alpha/scout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/class_portraits/alpha/scout.png -------------------------------------------------------------------------------- /PlayerPositionsTest/class_portraits/alpha/scout_blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/class_portraits/alpha/scout_blue.png -------------------------------------------------------------------------------- /PlayerPositionsTest/class_portraits/alpha/scout_blue_grey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/class_portraits/alpha/scout_blue_grey.png -------------------------------------------------------------------------------- /PlayerPositionsTest/class_portraits/alpha/scout_grey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/class_portraits/alpha/scout_grey.png -------------------------------------------------------------------------------- /PlayerPositionsTest/class_portraits/alpha/silhouette.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/class_portraits/alpha/silhouette.png -------------------------------------------------------------------------------- /PlayerPositionsTest/class_portraits/alpha/sniper.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/class_portraits/alpha/sniper.png -------------------------------------------------------------------------------- /PlayerPositionsTest/class_portraits/alpha/sniper_blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/class_portraits/alpha/sniper_blue.png -------------------------------------------------------------------------------- /PlayerPositionsTest/class_portraits/alpha/sniper_blue_grey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/class_portraits/alpha/sniper_blue_grey.png -------------------------------------------------------------------------------- /PlayerPositionsTest/class_portraits/alpha/sniper_grey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/class_portraits/alpha/sniper_grey.png -------------------------------------------------------------------------------- /PlayerPositionsTest/class_portraits/alpha/soldier.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/class_portraits/alpha/soldier.png -------------------------------------------------------------------------------- /PlayerPositionsTest/class_portraits/alpha/soldier_blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/class_portraits/alpha/soldier_blue.png -------------------------------------------------------------------------------- /PlayerPositionsTest/class_portraits/alpha/soldier_blue_grey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/class_portraits/alpha/soldier_blue_grey.png -------------------------------------------------------------------------------- /PlayerPositionsTest/class_portraits/alpha/soldier_grey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/class_portraits/alpha/soldier_grey.png -------------------------------------------------------------------------------- /PlayerPositionsTest/class_portraits/alpha/spy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/class_portraits/alpha/spy.png -------------------------------------------------------------------------------- /PlayerPositionsTest/class_portraits/alpha/spy_blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/class_portraits/alpha/spy_blue.png -------------------------------------------------------------------------------- /PlayerPositionsTest/class_portraits/alpha/spy_blue_grey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/class_portraits/alpha/spy_blue_grey.png -------------------------------------------------------------------------------- /PlayerPositionsTest/class_portraits/alpha/spy_grey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/class_portraits/alpha/spy_grey.png -------------------------------------------------------------------------------- /PlayerPositionsTest/class_portraits/noalpha/all_class.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/class_portraits/noalpha/all_class.png -------------------------------------------------------------------------------- /PlayerPositionsTest/class_portraits/noalpha/demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/class_portraits/noalpha/demo.png -------------------------------------------------------------------------------- /PlayerPositionsTest/class_portraits/noalpha/demo_blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/class_portraits/noalpha/demo_blue.png -------------------------------------------------------------------------------- /PlayerPositionsTest/class_portraits/noalpha/demo_blue_grey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/class_portraits/noalpha/demo_blue_grey.png -------------------------------------------------------------------------------- /PlayerPositionsTest/class_portraits/noalpha/demo_grey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/class_portraits/noalpha/demo_grey.png -------------------------------------------------------------------------------- /PlayerPositionsTest/class_portraits/noalpha/engie.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/class_portraits/noalpha/engie.png -------------------------------------------------------------------------------- /PlayerPositionsTest/class_portraits/noalpha/engie_blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/class_portraits/noalpha/engie_blue.png -------------------------------------------------------------------------------- /PlayerPositionsTest/class_portraits/noalpha/engie_blue_grey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/class_portraits/noalpha/engie_blue_grey.png -------------------------------------------------------------------------------- /PlayerPositionsTest/class_portraits/noalpha/engie_grey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/class_portraits/noalpha/engie_grey.png -------------------------------------------------------------------------------- /PlayerPositionsTest/class_portraits/noalpha/heavy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/class_portraits/noalpha/heavy.png -------------------------------------------------------------------------------- /PlayerPositionsTest/class_portraits/noalpha/heavy_blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/class_portraits/noalpha/heavy_blue.png -------------------------------------------------------------------------------- /PlayerPositionsTest/class_portraits/noalpha/heavy_blue_grey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/class_portraits/noalpha/heavy_blue_grey.png -------------------------------------------------------------------------------- /PlayerPositionsTest/class_portraits/noalpha/heavy_grey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/class_portraits/noalpha/heavy_grey.png -------------------------------------------------------------------------------- /PlayerPositionsTest/class_portraits/noalpha/medic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/class_portraits/noalpha/medic.png -------------------------------------------------------------------------------- /PlayerPositionsTest/class_portraits/noalpha/medic_blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/class_portraits/noalpha/medic_blue.png -------------------------------------------------------------------------------- /PlayerPositionsTest/class_portraits/noalpha/medic_blue_grey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/class_portraits/noalpha/medic_blue_grey.png -------------------------------------------------------------------------------- /PlayerPositionsTest/class_portraits/noalpha/medic_grey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/class_portraits/noalpha/medic_grey.png -------------------------------------------------------------------------------- /PlayerPositionsTest/class_portraits/noalpha/pyro.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/class_portraits/noalpha/pyro.png -------------------------------------------------------------------------------- /PlayerPositionsTest/class_portraits/noalpha/pyro_blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/class_portraits/noalpha/pyro_blue.png -------------------------------------------------------------------------------- /PlayerPositionsTest/class_portraits/noalpha/pyro_blue_grey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/class_portraits/noalpha/pyro_blue_grey.png -------------------------------------------------------------------------------- /PlayerPositionsTest/class_portraits/noalpha/pyro_grey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/class_portraits/noalpha/pyro_grey.png -------------------------------------------------------------------------------- /PlayerPositionsTest/class_portraits/noalpha/scout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/class_portraits/noalpha/scout.png -------------------------------------------------------------------------------- /PlayerPositionsTest/class_portraits/noalpha/scout_blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/class_portraits/noalpha/scout_blue.png -------------------------------------------------------------------------------- /PlayerPositionsTest/class_portraits/noalpha/scout_blue_grey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/class_portraits/noalpha/scout_blue_grey.png -------------------------------------------------------------------------------- /PlayerPositionsTest/class_portraits/noalpha/scout_grey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/class_portraits/noalpha/scout_grey.png -------------------------------------------------------------------------------- /PlayerPositionsTest/class_portraits/noalpha/sniper.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/class_portraits/noalpha/sniper.png -------------------------------------------------------------------------------- /PlayerPositionsTest/class_portraits/noalpha/sniper_blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/class_portraits/noalpha/sniper_blue.png -------------------------------------------------------------------------------- /PlayerPositionsTest/class_portraits/noalpha/sniper_blue_grey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/class_portraits/noalpha/sniper_blue_grey.png -------------------------------------------------------------------------------- /PlayerPositionsTest/class_portraits/noalpha/sniper_grey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/class_portraits/noalpha/sniper_grey.png -------------------------------------------------------------------------------- /PlayerPositionsTest/class_portraits/noalpha/soldier.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/class_portraits/noalpha/soldier.png -------------------------------------------------------------------------------- /PlayerPositionsTest/class_portraits/noalpha/soldier_blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/class_portraits/noalpha/soldier_blue.png -------------------------------------------------------------------------------- /PlayerPositionsTest/class_portraits/noalpha/soldier_blue_grey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/class_portraits/noalpha/soldier_blue_grey.png -------------------------------------------------------------------------------- /PlayerPositionsTest/class_portraits/noalpha/soldier_grey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/class_portraits/noalpha/soldier_grey.png -------------------------------------------------------------------------------- /PlayerPositionsTest/class_portraits/noalpha/spy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/class_portraits/noalpha/spy.png -------------------------------------------------------------------------------- /PlayerPositionsTest/class_portraits/noalpha/spy_blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/class_portraits/noalpha/spy_blue.png -------------------------------------------------------------------------------- /PlayerPositionsTest/class_portraits/noalpha/spy_blue_grey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/class_portraits/noalpha/spy_blue_grey.png -------------------------------------------------------------------------------- /PlayerPositionsTest/class_portraits/noalpha/spy_grey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/class_portraits/noalpha/spy_grey.png -------------------------------------------------------------------------------- /PlayerPositionsTest/demos/cp_process_final.dem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/demos/cp_process_final.dem -------------------------------------------------------------------------------- /PlayerPositionsTest/demos/testdemo.dem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/demos/testdemo.dem -------------------------------------------------------------------------------- /PlayerPositionsTest/images/classicons/demo_blu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/images/classicons/demo_blu.png -------------------------------------------------------------------------------- /PlayerPositionsTest/images/classicons/demo_red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/images/classicons/demo_red.png -------------------------------------------------------------------------------- /PlayerPositionsTest/images/classicons/engineer_blu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/images/classicons/engineer_blu.png -------------------------------------------------------------------------------- /PlayerPositionsTest/images/classicons/engineer_red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/images/classicons/engineer_red.png -------------------------------------------------------------------------------- /PlayerPositionsTest/images/classicons/heavy_blu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/images/classicons/heavy_blu.png -------------------------------------------------------------------------------- /PlayerPositionsTest/images/classicons/heavy_red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/images/classicons/heavy_red.png -------------------------------------------------------------------------------- /PlayerPositionsTest/images/classicons/medic_blu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/images/classicons/medic_blu.png -------------------------------------------------------------------------------- /PlayerPositionsTest/images/classicons/medic_red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/images/classicons/medic_red.png -------------------------------------------------------------------------------- /PlayerPositionsTest/images/classicons/pyro_blu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/images/classicons/pyro_blu.png -------------------------------------------------------------------------------- /PlayerPositionsTest/images/classicons/pyro_red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/images/classicons/pyro_red.png -------------------------------------------------------------------------------- /PlayerPositionsTest/images/classicons/scout_blu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/images/classicons/scout_blu.png -------------------------------------------------------------------------------- /PlayerPositionsTest/images/classicons/scout_red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/images/classicons/scout_red.png -------------------------------------------------------------------------------- /PlayerPositionsTest/images/classicons/sniper_blu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/images/classicons/sniper_blu.png -------------------------------------------------------------------------------- /PlayerPositionsTest/images/classicons/sniper_red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/images/classicons/sniper_red.png -------------------------------------------------------------------------------- /PlayerPositionsTest/images/classicons/soldier_blu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/images/classicons/soldier_blu.png -------------------------------------------------------------------------------- /PlayerPositionsTest/images/classicons/soldier_red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/images/classicons/soldier_red.png -------------------------------------------------------------------------------- /PlayerPositionsTest/images/classicons/spy_blu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/images/classicons/spy_blu.png -------------------------------------------------------------------------------- /PlayerPositionsTest/images/classicons/spy_red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/images/classicons/spy_red.png -------------------------------------------------------------------------------- /PlayerPositionsTest/images/killicons/black/negative_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/images/killicons/black/negative_1.png -------------------------------------------------------------------------------- /PlayerPositionsTest/images/killicons/black/negative_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/images/killicons/black/negative_2.png -------------------------------------------------------------------------------- /PlayerPositionsTest/images/killicons/black/negative_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/images/killicons/black/negative_3.png -------------------------------------------------------------------------------- /PlayerPositionsTest/images/killicons/white/ambassador.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/images/killicons/white/ambassador.png -------------------------------------------------------------------------------- /PlayerPositionsTest/images/killicons/white/crit_bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/images/killicons/white/crit_bg.png -------------------------------------------------------------------------------- /PlayerPositionsTest/images/killicons/white/group_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/images/killicons/white/group_1.png -------------------------------------------------------------------------------- /PlayerPositionsTest/images/killicons/white/group_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/images/killicons/white/group_2.png -------------------------------------------------------------------------------- /PlayerPositionsTest/images/killicons/white/group_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/images/killicons/white/group_3.png -------------------------------------------------------------------------------- /PlayerPositionsTest/images/killicons/white/knife_taunt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/images/killicons/white/knife_taunt.png -------------------------------------------------------------------------------- /PlayerPositionsTest/images/killicons/white/natascha.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/images/killicons/white/natascha.png -------------------------------------------------------------------------------- /PlayerPositionsTest/images/killicons/white/rocket.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/images/killicons/white/rocket.png -------------------------------------------------------------------------------- /PlayerPositionsTest/images/killicons/white/unknown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/images/killicons/white/unknown.png -------------------------------------------------------------------------------- /PlayerPositionsTest/images/maps/cp_process_final.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/images/maps/cp_process_final.png -------------------------------------------------------------------------------- /PlayerPositionsTest/images/maps/cp_process_final.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/images/maps/cp_process_final.xcf -------------------------------------------------------------------------------- /PlayerPositionsTest/images/maps/cp_process_final_cropped.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/images/maps/cp_process_final_cropped.png -------------------------------------------------------------------------------- /PlayerPositionsTest/images/maps/cp_process_final_cropped_centered.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/images/maps/cp_process_final_cropped_centered.png -------------------------------------------------------------------------------- /PlayerPositionsTest/images/projectiles/pill_blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/images/projectiles/pill_blue.png -------------------------------------------------------------------------------- /PlayerPositionsTest/images/projectiles/pill_red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/images/projectiles/pill_red.png -------------------------------------------------------------------------------- /PlayerPositionsTest/images/projectiles/rocket.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/images/projectiles/rocket.png -------------------------------------------------------------------------------- /PlayerPositionsTest/images_misc/koth_sawmill.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/images_misc/koth_sawmill.png -------------------------------------------------------------------------------- /PlayerPositionsTest/images_misc/leaderboard_class_demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/images_misc/leaderboard_class_demo.png -------------------------------------------------------------------------------- /PlayerPositionsTest/images_misc/leaderboard_class_engineer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/images_misc/leaderboard_class_engineer.png -------------------------------------------------------------------------------- /PlayerPositionsTest/images_misc/leaderboard_class_heavy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/images_misc/leaderboard_class_heavy.png -------------------------------------------------------------------------------- /PlayerPositionsTest/images_misc/leaderboard_class_medic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/images_misc/leaderboard_class_medic.png -------------------------------------------------------------------------------- /PlayerPositionsTest/images_misc/leaderboard_class_pyro.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/images_misc/leaderboard_class_pyro.png -------------------------------------------------------------------------------- /PlayerPositionsTest/images_misc/leaderboard_class_scout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/images_misc/leaderboard_class_scout.png -------------------------------------------------------------------------------- /PlayerPositionsTest/images_misc/leaderboard_class_sniper.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/images_misc/leaderboard_class_sniper.png -------------------------------------------------------------------------------- /PlayerPositionsTest/images_misc/leaderboard_class_soldier.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/images_misc/leaderboard_class_soldier.png -------------------------------------------------------------------------------- /PlayerPositionsTest/images_misc/leaderboard_class_spy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/images_misc/leaderboard_class_spy.png -------------------------------------------------------------------------------- /PlayerPositionsTest/images_misc/leaderboard_dead.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PazerOP/DemoLib/250ad2fc7c833962d4d1a87765ced4d536049d6a/PlayerPositionsTest/images_misc/leaderboard_dead.png -------------------------------------------------------------------------------- /PlayerPositionsTest/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /TF2Net/ConditionalHashSet.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Runtime.CompilerServices; 5 | 6 | namespace TF2Net 7 | { 8 | sealed class ConditionalHashSet where T : class 9 | { 10 | private readonly object locker = new object(); 11 | private readonly List weakList = new List(); 12 | private readonly ConditionalWeakTable weakDictionary = 13 | new ConditionalWeakTable(); 14 | 15 | public void Add(T item) 16 | { 17 | lock (locker) 18 | { 19 | var reference = new WeakReference(item); 20 | weakDictionary.Add(item, reference); 21 | weakList.Add(reference); 22 | Shrink(); 23 | } 24 | } 25 | 26 | public void Remove(T item) 27 | { 28 | lock (locker) 29 | { 30 | WeakReference reference; 31 | 32 | if (weakDictionary.TryGetValue(item, out reference)) 33 | { 34 | reference.Target = null; 35 | weakDictionary.Remove(item); 36 | } 37 | } 38 | } 39 | 40 | public T[] ToArray() 41 | { 42 | lock (locker) 43 | { 44 | return ( 45 | from weakReference in weakList 46 | let item = (T)weakReference.Target 47 | where item != null 48 | select item) 49 | .ToArray(); 50 | } 51 | } 52 | 53 | private void Shrink() 54 | { 55 | // This method prevents the List from growing indefinitely, but 56 | // might also cause a performance problem in some cases. 57 | if (weakList.Capacity == weakList.Count) 58 | { 59 | weakList.RemoveAll(weak => !weak.IsAlive); 60 | } 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /TF2Net/Data/BaselineIndex.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace TF2Net.Data 8 | { 9 | public enum BaselineIndex 10 | { 11 | Baseline0 = 0, 12 | Baseline1 = 1, 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /TF2Net/Data/Class.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace TF2Net.Data 8 | { 9 | public enum Class 10 | { 11 | Undefined = 0, 12 | 13 | Scout = 1, 14 | Sniper = 2, 15 | Soldier = 3, 16 | Demo = 4, 17 | Medic = 5, 18 | Heavy = 6, 19 | Pyro = 7, 20 | Spy = 8, 21 | Engie = 9, 22 | 23 | Civilian = 10, 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /TF2Net/Data/ClientFrame.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.Diagnostics; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace TF2Net.Data 10 | { 11 | [DebuggerDisplay("ClientFrame: tick {ServerTick,nq}")] 12 | public class ClientFrame 13 | { 14 | public ClientFrame(ulong tick) 15 | { 16 | ServerTick = tick; 17 | } 18 | 19 | public int LastEntityIndex { get; set; } 20 | public ulong ServerTick { get; } 21 | 22 | public BitArray TransmitEntity { get; } = new BitArray(SourceConstants.MAX_EDICTS); 23 | public BitArray FromBaseline { get; } = new BitArray(SourceConstants.MAX_EDICTS); 24 | public BitArray TransmitAlways { get; } = new BitArray(SourceConstants.MAX_EDICTS); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /TF2Net/Data/ConnectionState.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace TF2Net.Data 8 | { 9 | public enum ConnectionState : byte 10 | { 11 | /// 12 | /// no state yet, about to connect 13 | /// 14 | None = 0, 15 | 16 | /// 17 | /// client challenging server, all OOB packets 18 | /// 19 | Challenge = 1, 20 | 21 | /// 22 | /// client is connected to server, netchans ready 23 | /// 24 | Connected = 2, 25 | 26 | /// 27 | /// just got serverinfo and string tables 28 | /// 29 | New = 3, 30 | 31 | /// 32 | /// received signon buffers 33 | /// 34 | Prespawn = 4, 35 | 36 | /// 37 | /// ready to receive entity packets 38 | /// 39 | Spawn = 5, 40 | 41 | /// 42 | /// we are fully connected, first non-delta packet received 43 | /// 44 | Full = 6, 45 | 46 | /// 47 | /// server is changing level, please wait 48 | /// 49 | Changelevel = 7, 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /TF2Net/Data/EHandle.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using TF2Net.Entities; 8 | 9 | namespace TF2Net.Data 10 | { 11 | [DebuggerDisplay("{Entity,nq}")] 12 | public class EHandle 13 | { 14 | public WorldState World { get; } 15 | public uint EntityIndex { get; } 16 | public uint SerialNumber { get; } 17 | 18 | public Entity Entity 19 | { 20 | get 21 | { 22 | Entity potential = World.Entities[EntityIndex]; 23 | if (potential?.SerialNumber == SerialNumber) 24 | return potential; 25 | 26 | return null; 27 | } 28 | } 29 | 30 | [DebuggerBrowsable(DebuggerBrowsableState.Never)] 31 | Entity DebugEntity { get { return Entity; } } 32 | 33 | public EHandle(WorldState ws, uint handle) 34 | { 35 | World = ws; 36 | 37 | EntityIndex = handle & ((1 << SourceConstants.MAX_EDICT_BITS) - 1); 38 | SerialNumber = handle >> SourceConstants.MAX_EDICT_BITS; 39 | } 40 | 41 | public override string ToString() 42 | { 43 | return Entity?.ToString() ?? string.Format("null {0}", nameof(EHandle)); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /TF2Net/Data/EntityData.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace TF2Net.Data 8 | { 9 | public class EntityData 10 | { 11 | public uint Tick { get; } 12 | 13 | public EntityData(uint tick) 14 | { 15 | Tick = tick; 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /TF2Net/Data/EntityUpdateType.cs: -------------------------------------------------------------------------------- 1 | namespace DemoLib.DataExtraction 2 | { 3 | public enum EntityUpdateType 4 | { 5 | EnterPVS = 0, // Entity came back into pvs, create new entity if one doesn't exist 6 | 7 | LeavePVS, // Entity left pvs 8 | 9 | DeltaEnt, // There is a delta for this entity. 10 | PreserveEnt, // Entity stays alive but no delta ( could be LOD, or just unchanged ) 11 | 12 | Finished, // finished parsing entities successfully 13 | Failed, // parsing error occured while reading entities 14 | }; 15 | } 16 | -------------------------------------------------------------------------------- /TF2Net/Data/FlattenedProp.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace TF2Net.Data 9 | { 10 | [DebuggerDisplay("{ToString(),nq}")] 11 | public class FlattenedProp 12 | { 13 | public string FullName { get; set; } 14 | 15 | public SendPropDefinition Property { get; set; } 16 | 17 | public override string ToString() 18 | { 19 | string bitCount = (Property.BitCount.HasValue && Property.BitCount.Value > 0) ? string.Format("[{0}]", Property.BitCount.Value) : string.Empty; 20 | 21 | return string.Format("{0}{1} \"{2}\" ({3})", Property.Type, bitCount, FullName, Property.Flags); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /TF2Net/Data/GameEvent.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace TF2Net.Data 9 | { 10 | [DebuggerDisplay("Game event: {Declaration.Name}")] 11 | public class GameEvent 12 | { 13 | public IReadOnlyGameEventDeclaration Declaration { get; set; } 14 | public IDictionary Values { get; set; } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /TF2Net/Data/GameEventDeclaration.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Diagnostics; 3 | using System.Linq; 4 | 5 | namespace TF2Net.Data 6 | { 7 | public enum GameEventDataType 8 | { 9 | Local = 0, // not networked 10 | String, // zero terminated ASCII string 11 | Float, // float 32 bit 12 | Long, // signed int 32 bit 13 | Short, // signed int 16 bit 14 | Byte, // unsigned int 8 bit 15 | Bool, // unsigned int 1 bit 16 | }; 17 | 18 | [DebuggerDisplay("Game event declaration: {Name}")] 19 | public class GameEventDeclaration : IReadOnlyGameEventDeclaration 20 | { 21 | public int ID { get; set; } 22 | public string Name { get; set; } 23 | 24 | public IDictionary Values { get; set; } 25 | IReadOnlyDictionary IReadOnlyGameEventDeclaration.Values { get { return Values.AsReadOnly(); } } 26 | } 27 | 28 | public interface IReadOnlyGameEventDeclaration 29 | { 30 | int ID { get; } 31 | string Name { get; } 32 | 33 | IReadOnlyDictionary Values { get; } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /TF2Net/Data/IReadOnlyVector.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace TF2Net.Data 9 | { 10 | public interface IReadOnlyVector : ICloneable 11 | { 12 | double X { get; } 13 | double Y { get; } 14 | double Z { get; } 15 | } 16 | 17 | [EditorBrowsable(EditorBrowsableState.Never)] 18 | public static class IReadOnlyVectorExtensions 19 | { 20 | public static Vector Clone(this IReadOnlyVector v) 21 | { 22 | return new Vector(v.X, v.Y, v.Z); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /TF2Net/Data/LifeState.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace TF2Net.Data 8 | { 9 | public enum LifeState 10 | { 11 | Alive = 0, 12 | 13 | /// 14 | /// playing death animation or still falling off of a ledge waiting to hit ground 15 | /// 16 | Dying = 1, 17 | 18 | /// 19 | /// dead. lying still. 20 | /// 21 | Dead = 2, 22 | Respawnable = 3, 23 | DiscardBody = 4, 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /TF2Net/Data/PlayerState.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace TF2Net.Data 8 | { 9 | public enum PlayerState 10 | { 11 | /// 12 | /// Happily running around in the game. 13 | /// 14 | Active = 0, 15 | 16 | /// 17 | /// First entering the server (shows level intro screen). 18 | /// 19 | Welcome = 1, 20 | 21 | /// 22 | /// Game observer mode. 23 | /// 24 | Observer = 2, 25 | 26 | /// 27 | /// Player is dying. 28 | /// 29 | Dying = 3, 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /TF2Net/Data/SendProp.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.Linq; 4 | using TF2Net.Entities; 5 | 6 | namespace TF2Net.Data 7 | { 8 | [DebuggerDisplay("{Definition,nq} :: {Value,nq}")] 9 | public class SendProp : ICloneable, IDisposable 10 | { 11 | [DebuggerBrowsable(DebuggerBrowsableState.Never)] 12 | readonly IEntity m_Entity; 13 | public IEntity Entity 14 | { 15 | get 16 | { 17 | CheckDisposed(); 18 | return m_Entity; 19 | } 20 | } 21 | 22 | [DebuggerBrowsable(DebuggerBrowsableState.Never)] 23 | readonly SendPropDefinition m_Definition; 24 | public SendPropDefinition Definition 25 | { 26 | get 27 | { 28 | CheckDisposed(); 29 | return m_Definition; 30 | } 31 | } 32 | 33 | [DebuggerBrowsable(DebuggerBrowsableState.Never)] 34 | ulong m_LastChangedTick; 35 | public ulong LastChangedTick 36 | { 37 | get 38 | { 39 | CheckDisposed(); 40 | return m_LastChangedTick; 41 | } 42 | } 43 | 44 | public SingleEvent> ValueChanged { get; } = new SingleEvent>(); 45 | 46 | [DebuggerBrowsable(DebuggerBrowsableState.Never)] 47 | object m_Value; 48 | public object Value 49 | { 50 | get 51 | { 52 | CheckDisposed(); 53 | return m_Value; 54 | } 55 | set 56 | { 57 | CheckDisposed(); 58 | if (value?.GetHashCode() != m_Value?.GetHashCode() || !value.Equals(m_Value)) 59 | { 60 | Debug.Assert(value?.Equals(m_Value) != true); 61 | m_Value = value; 62 | m_LastChangedTick = Entity.World.Tick; 63 | ValueChanged.Invoke(this); 64 | } 65 | } 66 | } 67 | 68 | public SendProp(IEntity e, SendPropDefinition definition) 69 | { 70 | m_Entity = e; 71 | m_Definition = definition; 72 | } 73 | 74 | public SendProp Clone(IEntity forEnt) 75 | { 76 | CheckDisposed(); 77 | SendProp cloned = new SendProp(forEnt, Definition); 78 | cloned.m_Value = Value; 79 | cloned.m_LastChangedTick = LastChangedTick; 80 | return cloned; 81 | } 82 | public SendProp Clone() 83 | { 84 | CheckDisposed(); 85 | return (SendProp)MemberwiseClone(); 86 | } 87 | object ICloneable.Clone() { return Clone(); } 88 | 89 | void CheckDisposed() 90 | { 91 | if (m_Disposed) 92 | throw new ObjectDisposedException(nameof(SendProp)); 93 | } 94 | 95 | [DebuggerBrowsable(DebuggerBrowsableState.Never)] 96 | bool m_Disposed = false; 97 | public void Dispose() 98 | { 99 | CheckDisposed(); 100 | m_Disposed = true; 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /TF2Net/Data/ServerClass.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace TF2Net.Data 9 | { 10 | [DebuggerDisplay("{ToString(),nq}")] 11 | public class ServerClass 12 | { 13 | public string Classname { get; set; } 14 | public string DatatableName { get; set; } 15 | 16 | public override string ToString() 17 | { 18 | return string.Format("{0} ({1})", Classname, DatatableName); 19 | } 20 | 21 | public bool Equals(ServerClass other) 22 | { 23 | return ( 24 | Classname == other.Classname && 25 | DatatableName == other.DatatableName); 26 | } 27 | public override bool Equals(object obj) 28 | { 29 | ServerClass cast = obj as ServerClass; 30 | return (cast != null ? Equals(cast) : false); 31 | } 32 | public override int GetHashCode() 33 | { 34 | return unchecked(Classname.GetHashCode() + DatatableName.GetHashCode()); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /TF2Net/Data/ServerInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace TF2Net.Data 9 | { 10 | [DebuggerDisplay("{Hostname}: {MapName}")] 11 | public class ServerInfo 12 | { 13 | /// 14 | /// protocol version 15 | /// 16 | public short Protocol { get; set; } 17 | 18 | /// 19 | /// number of changelevels since server start 20 | /// 21 | public int ServerCount { get; set; } 22 | 23 | /// 24 | /// dedicated server? 25 | /// 26 | public bool IsDedicated { get; set; } 27 | 28 | /// 29 | /// HLTV server? 30 | /// 31 | public bool IsHLTV { get; set; } 32 | 33 | public enum OperatingSystem 34 | { 35 | Unknown, 36 | 37 | Linux, 38 | Windows, 39 | } 40 | public OperatingSystem OS { get; set; } 41 | 42 | /// 43 | /// server map CRC 44 | /// 45 | //public uint MapCRC { get; set; } 46 | 47 | /// 48 | /// client.dll CRC server is using 49 | /// 50 | public uint ClientCRC { get; set; } 51 | 52 | /// 53 | /// max number of clients on server 54 | /// 55 | public byte MaxClients { get; set; } 56 | 57 | /// 58 | /// max number of server classes 59 | /// 60 | public ushort MaxClasses { get; set; } 61 | 62 | /// 63 | /// our client slot number 64 | /// 65 | public int PlayerSlot { get; set; } 66 | 67 | /// 68 | /// server tick interval 69 | /// 70 | public double TickInterval { get; set; } 71 | 72 | /// 73 | /// game directory eg "tf2" 74 | /// 75 | public string GameDirectory { get; set; } 76 | 77 | public string MapName { get; set; } 78 | 79 | /// 80 | /// Current skybox name 81 | /// 82 | public string SkyName { get; set; } 83 | 84 | /// 85 | /// Server name 86 | /// 87 | public string Hostname { get; set; } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /TF2Net/Data/SignonState.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace TF2Net.Data 8 | { 9 | public class SignonState 10 | { 11 | public ConnectionState State { get; set; } 12 | public int SpawnCount { get; set; } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /TF2Net/Data/SourceConstants.cs: -------------------------------------------------------------------------------- 1 | namespace TF2Net.Data 2 | { 3 | public static class SourceConstants 4 | { 5 | public const int MAX_OSPATH = 260; 6 | 7 | internal const int NETMSG_TYPE_BITS = 6; 8 | 9 | internal const int EVENT_INDEX_BITS = 8; 10 | internal const int MAX_EVENT_BITS = 9; 11 | 12 | internal const int NET_MAX_PAYLOAD_BITS = 17; 13 | internal const int NET_MAX_PAYLOAD = (1 << NET_MAX_PAYLOAD_BITS); 14 | 15 | internal const int MAX_DECAL_INDEX_BITS = 9; 16 | internal const int MAX_EDICT_BITS = 11; 17 | internal const int MAX_EDICTS = (1 << MAX_EDICT_BITS); 18 | 19 | internal const int MAX_USER_MSG_LENGTH_BITS = 11; 20 | internal const int MAX_USER_MSG_LENGTH = (1 << MAX_USER_MSG_LENGTH_BITS); 21 | 22 | internal const int MAX_ENTITY_MSG_LENGTH_BITS = 11; 23 | internal const int MAX_ENTITY_MSG_LENGTH = (1 << MAX_ENTITY_MSG_LENGTH_BITS); 24 | 25 | internal const int MAX_SERVER_CLASS_BITS = 9; 26 | internal const int MAX_SERVER_CLASSES = (1 << MAX_SERVER_CLASS_BITS); 27 | 28 | internal const int MAX_SOUND_INDEX_BITS = 14; 29 | 30 | internal const int SP_MODEL_INDEX_BITS = 11; 31 | 32 | internal const int NUM_NETWORKED_EHANDLE_SERIAL_NUMBER_BITS = 10; 33 | internal const int NUM_NETWORKED_EHANDLE_BITS = (MAX_EDICT_BITS + NUM_NETWORKED_EHANDLE_SERIAL_NUMBER_BITS); 34 | internal const int INVALID_NETWORKED_EHANDLE_VALUE = ((1 << NUM_NETWORKED_EHANDLE_BITS) - 1); 35 | 36 | internal const int MAX_DATATABLES = 1024; 37 | internal const int MAX_DATATABLE_PROPS = 4096; 38 | 39 | internal const int COORD_INTEGER_BITS = 14; 40 | internal const int COORD_FRACTIONAL_BITS = 5; 41 | internal const int COORD_DENOMINATOR = 1 << COORD_FRACTIONAL_BITS; 42 | internal const double COORD_RESOLUTION = 1.0 / COORD_DENOMINATOR; 43 | 44 | internal const int COORD_INTEGER_BITS_MP = 11; 45 | internal const int COORD_FRACTIONAL_BITS_MP_LOWPRECISION = 3; 46 | internal const int COORD_DENOMINATOR_LOWPRECISION = 1 << COORD_FRACTIONAL_BITS_MP_LOWPRECISION; 47 | internal const double COORD_RESOLUTION_LOWPRECISION = 1.0 / COORD_DENOMINATOR_LOWPRECISION; 48 | 49 | internal const int SPROP_NUMFLAGBITS_NETWORKED = 16; 50 | internal const int SPROP_NUMFLAGBITS = 17; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /TF2Net/Data/StringTable.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.Diagnostics; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace TF2Net.Data 10 | { 11 | [DebuggerDisplay("Stringtable: {TableName} ({Entries.Count,nq}/{MaxEntries,nq})")] 12 | public class StringTable : IEnumerable 13 | { 14 | public WorldState World { get; } 15 | 16 | public string TableName { get; } 17 | 18 | public ushort MaxEntries { get; } 19 | 20 | [DebuggerBrowsable(DebuggerBrowsableState.Never)] 21 | readonly SortedAutoList m_Entries; 22 | public IReadOnlyList Entries { get { return m_Entries; } } 23 | 24 | public ushort? UserDataSize { get; } 25 | public byte? UserDataSizeBits { get; } 26 | 27 | public SingleEvent> StringTableUpdated { get; } = new SingleEvent>(); 28 | 29 | public StringTable(WorldState ws, string tableName, ushort maxEntries, ushort? userDataSize, byte? userDataSizeBits) 30 | { 31 | World = ws; 32 | TableName = tableName; 33 | MaxEntries = maxEntries; 34 | UserDataSize = userDataSize; 35 | UserDataSizeBits = userDataSizeBits; 36 | 37 | m_Entries = new SortedAutoList( 38 | Comparer.Create( 39 | (lhs, rhs) => 40 | { 41 | Debug.Assert(lhs.ID != rhs.ID); 42 | 43 | return Comparer.Default.Compare(lhs.ID, rhs.ID); 44 | })); 45 | } 46 | 47 | public void Add(StringTableEntry entry) 48 | { 49 | Debug.Assert(entry.Table == this); 50 | m_Entries.Add(entry); 51 | entry.EntryChanged.Add(Entry_EntryChanged); 52 | } 53 | 54 | private void Entry_EntryChanged(StringTableEntry entry) 55 | { 56 | StringTableUpdated.Invoke(this); 57 | } 58 | 59 | private class SortedAutoList : SortedSet, IList, IReadOnlyList 60 | { 61 | public T this[int index] 62 | { 63 | get 64 | { 65 | return this.ElementAt(index); 66 | } 67 | set 68 | { 69 | Remove(this.ElementAt(index)); 70 | Add(value); 71 | } 72 | } 73 | 74 | public int IndexOf(T item) 75 | { 76 | throw new NotSupportedException(); 77 | } 78 | 79 | public void Insert(int index, T item) 80 | { 81 | throw new NotSupportedException(); 82 | } 83 | 84 | public void RemoveAt(int index) 85 | { 86 | Remove(this.ElementAt(index)); 87 | } 88 | 89 | public SortedAutoList(IComparer comparer) : base(comparer) { } 90 | } 91 | 92 | public IEnumerator GetEnumerator() 93 | { 94 | return Entries.GetEnumerator(); 95 | } 96 | IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /TF2Net/Data/StringTableEntry.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using BitSet; 8 | 9 | namespace TF2Net.Data 10 | { 11 | [DebuggerDisplay("{ID,nq}: {Value}")] 12 | public class StringTableEntry 13 | { 14 | public StringTable Table { get; } 15 | 16 | public SingleEvent> EntryChanged { get; } = new SingleEvent>(); 17 | 18 | [DebuggerBrowsable(DebuggerBrowsableState.Never)] 19 | ushort m_ID; 20 | public ushort ID 21 | { 22 | get { return m_ID; } 23 | set 24 | { 25 | if (m_ID != value) 26 | { 27 | m_ID = value; 28 | EntryChanged?.Invoke(this); 29 | } 30 | } 31 | } 32 | 33 | [DebuggerBrowsable(DebuggerBrowsableState.Never)] 34 | string m_Value; 35 | public string Value 36 | { 37 | get { return m_Value; } 38 | set 39 | { 40 | if (m_Value != value) 41 | { 42 | m_Value = value; 43 | EntryChanged?.Invoke(this); 44 | } 45 | } 46 | } 47 | 48 | [DebuggerBrowsable(DebuggerBrowsableState.Never)] 49 | BitStream m_UserData; 50 | public BitStream UserData 51 | { 52 | get { return m_UserData?.Clone(); } 53 | set 54 | { 55 | if (m_UserData != value) 56 | { 57 | m_UserData = value; 58 | EntryChanged?.Invoke(this); 59 | } 60 | } 61 | } 62 | 63 | public StringTableEntry(StringTable table) 64 | { 65 | Table = table; 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /TF2Net/Data/Team.cs: -------------------------------------------------------------------------------- 1 | namespace TF2Net.Data 2 | { 3 | public enum Team 4 | { 5 | Invalid = -1, 6 | Unassigned = 0, 7 | Spectator = 1, 8 | Red = 2, 9 | Blue = 3, 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /TF2Net/Data/UserInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using BitSet; 7 | 8 | namespace TF2Net.Data 9 | { 10 | public class UserInfo 11 | { 12 | public string Name { get; set; } 13 | public int? UserID { get; set; } 14 | 15 | public string GUID { get; set; } 16 | 17 | public uint? FriendsID { get; set; } 18 | public string FriendsName { get; set; } 19 | 20 | public bool? IsFakePlayer { get; set; } 21 | public bool? IsHLTV { get; set; } 22 | 23 | public uint?[] CustomFiles { get; } = new uint?[4]; 24 | 25 | public uint? FilesDownloaded { get; set; } 26 | 27 | public UserInfo(BitStream stream) 28 | { 29 | Name = Encoding.ASCII.GetString(stream.ReadBytes(32)).TrimEnd('\0'); 30 | 31 | UserID = stream.ReadInt(); 32 | 33 | GUID = Encoding.ASCII.GetString(stream.ReadBytes(33)).TrimEnd('\0'); 34 | 35 | FriendsID = stream.ReadUInt(); 36 | 37 | FriendsName = Encoding.ASCII.GetString(stream.ReadBytes(32)).TrimEnd('\0'); 38 | 39 | IsFakePlayer = stream.ReadByte() > 0 ? true : false; 40 | IsHLTV = stream.ReadByte() > 0 ? true : false; 41 | 42 | for (byte i = 0; i < 4; i++) 43 | CustomFiles[i] = stream.ReadUInt(); 44 | 45 | FilesDownloaded = stream.ReadByte(); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /TF2Net/Data/UserMessageType.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace TF2Net.Data 8 | { 9 | public enum UserMessageType 10 | { 11 | Geiger = 0, 12 | Train = 1, 13 | HudText = 2, 14 | SayText = 3, 15 | SayText2 = 4, 16 | TextMsg = 5, 17 | ResetHUD = 6, 18 | GameTitle = 7, 19 | ItemPickup = 8, 20 | ShowMenu = 9, 21 | Shake = 10, 22 | 23 | HudNotifyCustom = 27, 24 | 25 | BreakModel = 41, 26 | CheapBreakModel = 42, 27 | 28 | MVMResetPlayerStats = 57, 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /TF2Net/Data/Vector.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | 4 | namespace TF2Net.Data 5 | { 6 | [DebuggerDisplay("{ToString(),nq}")] 7 | public class Vector : IReadOnlyVector, ICloneable 8 | { 9 | public double X { get; set; } 10 | public double Y { get; set; } 11 | public double Z { get; set; } 12 | 13 | public Vector() { } 14 | public Vector(double x, double y, double z = 0) 15 | { 16 | X = x; 17 | Y = y; 18 | Z = z; 19 | } 20 | public Vector(double[] xyz) 21 | { 22 | if (xyz == null) 23 | throw new ArgumentNullException(nameof(xyz)); 24 | if (xyz.Length != 3) 25 | throw new ArgumentException("Array is not of length 3", nameof(xyz)); 26 | 27 | X = xyz[0]; 28 | Y = xyz[1]; 29 | Z = xyz[2]; 30 | } 31 | public Vector(IReadOnlyVector v) 32 | { 33 | X = v.X; 34 | Y = v.Y; 35 | Z = v.Z; 36 | } 37 | 38 | public double this[int i] 39 | { 40 | get 41 | { 42 | switch (i) 43 | { 44 | case 0: return X; 45 | case 1: return Y; 46 | case 2: return Z; 47 | } 48 | 49 | throw new ArgumentOutOfRangeException(nameof(i)); 50 | } 51 | set 52 | { 53 | switch (i) 54 | { 55 | case 0: X = value; return; 56 | case 1: Y = value; return; 57 | case 2: Z = value; return; 58 | } 59 | 60 | throw new ArgumentOutOfRangeException(nameof(i)); 61 | } 62 | } 63 | 64 | public override string ToString() 65 | { 66 | return string.Format("{0}: ({1} {2} {3})", nameof(Vector), X, Y, Z); 67 | } 68 | 69 | public Vector Clone() 70 | { 71 | return (Vector)MemberwiseClone(); 72 | } 73 | object ICloneable.Clone() { return Clone(); } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /TF2Net/Data/WeaponType.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace TF2Net.Data 8 | { 9 | public enum WeaponType 10 | { 11 | TF_WEAPON_NONE = 0, 12 | TF_WEAPON_BAT, 13 | TF_WEAPON_BAT_WOOD, 14 | TF_WEAPON_BOTTLE, 15 | TF_WEAPON_FIREAXE, 16 | TF_WEAPON_CLUB, 17 | TF_WEAPON_CROWBAR, 18 | TF_WEAPON_KNIFE, 19 | TF_WEAPON_FISTS, 20 | TF_WEAPON_SHOVEL, 21 | TF_WEAPON_WRENCH, 22 | TF_WEAPON_BONESAW, 23 | TF_WEAPON_SHOTGUN_PRIMARY, 24 | TF_WEAPON_SHOTGUN_SOLDIER, 25 | TF_WEAPON_SHOTGUN_HWG, 26 | TF_WEAPON_SHOTGUN_PYRO, 27 | TF_WEAPON_SCATTERGUN, 28 | TF_WEAPON_SNIPERRIFLE, 29 | TF_WEAPON_MINIGUN, 30 | TF_WEAPON_SMG, 31 | TF_WEAPON_SYRINGEGUN_MEDIC, 32 | TF_WEAPON_TRANQ, 33 | TF_WEAPON_ROCKETLAUNCHER, 34 | TF_WEAPON_GRENADELAUNCHER, 35 | TF_WEAPON_PIPEBOMBLAUNCHER, 36 | TF_WEAPON_FLAMETHROWER, 37 | TF_WEAPON_GRENADE_NORMAL, 38 | TF_WEAPON_GRENADE_CONCUSSION, 39 | TF_WEAPON_GRENADE_NAIL, 40 | TF_WEAPON_GRENADE_MIRV, 41 | TF_WEAPON_GRENADE_MIRV_DEMOMAN, 42 | TF_WEAPON_GRENADE_NAPALM, 43 | TF_WEAPON_GRENADE_GAS, 44 | TF_WEAPON_GRENADE_EMP, 45 | TF_WEAPON_GRENADE_CALTROP, 46 | TF_WEAPON_GRENADE_PIPEBOMB, 47 | TF_WEAPON_GRENADE_SMOKE_BOMB, 48 | TF_WEAPON_GRENADE_HEAL, 49 | TF_WEAPON_GRENADE_STUNBALL, 50 | TF_WEAPON_GRENADE_JAR, 51 | TF_WEAPON_GRENADE_JAR_MILK, 52 | TF_WEAPON_PISTOL, 53 | TF_WEAPON_PISTOL_SCOUT, 54 | TF_WEAPON_REVOLVER, 55 | TF_WEAPON_NAILGUN, 56 | TF_WEAPON_PDA, 57 | TF_WEAPON_PDA_ENGINEER_BUILD, 58 | TF_WEAPON_PDA_ENGINEER_DESTROY, 59 | TF_WEAPON_PDA_SPY, 60 | TF_WEAPON_BUILDER, 61 | TF_WEAPON_MEDIGUN, 62 | TF_WEAPON_GRENADE_MIRVBOMB, 63 | TF_WEAPON_FLAMETHROWER_ROCKET, 64 | TF_WEAPON_GRENADE_DEMOMAN, 65 | TF_WEAPON_SENTRY_BULLET, 66 | TF_WEAPON_SENTRY_ROCKET, 67 | TF_WEAPON_DISPENSER, 68 | TF_WEAPON_INVIS, 69 | TF_WEAPON_FLAREGUN, 70 | TF_WEAPON_LUNCHBOX, 71 | TF_WEAPON_JAR, 72 | TF_WEAPON_COMPOUND_BOW, 73 | TF_WEAPON_BUFF_ITEM, 74 | TF_WEAPON_PUMPKIN_BOMB, 75 | TF_WEAPON_SWORD, 76 | TF_WEAPON_DIRECTHIT, 77 | TF_WEAPON_LIFELINE, 78 | TF_WEAPON_LASER_POINTER, 79 | TF_WEAPON_DISPENSER_GUN, 80 | TF_WEAPON_SENTRY_REVENGE, 81 | TF_WEAPON_JAR_MILK, 82 | TF_WEAPON_HANDGUN_SCOUT_PRIMARY, 83 | TF_WEAPON_BAT_FISH, 84 | TF_WEAPON_CROSSBOW, 85 | TF_WEAPON_STICKBOMB, 86 | TF_WEAPON_HANDGUN_SCOUT_SEC, 87 | TF_WEAPON_SODA_POPPER, 88 | TF_WEAPON_SNIPERRIFLE_DECAP, 89 | TF_WEAPON_RAYGUN, 90 | TF_WEAPON_PARTICLE_CANNON, 91 | TF_WEAPON_MECHANICAL_ARM, 92 | TF_WEAPON_DRG_POMSON, 93 | TF_WEAPON_BAT_GIFTWRAP, 94 | TF_WEAPON_GRENADE_ORNAMENT, 95 | TF_WEAPON_RAYGUN_REVENGE, 96 | TF_WEAPON_PEP_BRAWLER_BLASTER, 97 | TF_WEAPON_CLEAVER, 98 | TF_WEAPON_GRENADE_CLEAVER, 99 | TF_WEAPON_STICKY_BALL_LAUNCHER, 100 | TF_WEAPON_GRENADE_STICKY_BALL, 101 | TF_WEAPON_SHOTGUN_BUILDING_RESCUE, 102 | TF_WEAPON_CANNON, 103 | TF_WEAPON_THROWABLE, 104 | TF_WEAPON_GRENADE_THROWABLE, 105 | TF_WEAPON_PDA_SPY_BUILD, 106 | TF_WEAPON_GRENADE_WATERBALLOON, 107 | TF_WEAPON_HARVESTER_SAW, 108 | TF_WEAPON_SPELLBOOK, 109 | TF_WEAPON_SPELLBOOK_PROJECTILE, 110 | TF_WEAPON_SNIPERRIFLE_CLASSIC, 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /TF2Net/Entities/EntityWrapper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace TF2Net.Entities 4 | { 5 | public abstract class BaseEntityWrapper 6 | { 7 | public IBaseEntity Entity { get; } 8 | 9 | public BaseEntityWrapper(IBaseEntity e, string className) 10 | { 11 | if (e.Class.Classname != className) 12 | throw new ArgumentException(string.Format("Invalid entity class for this {0}", nameof(BaseEntityWrapper))); 13 | 14 | Entity = e; 15 | } 16 | } 17 | 18 | public abstract class AbstractEntityWrapper : BaseEntityWrapper 19 | { 20 | public new IEntity Entity { get { return (IEntity)base.Entity; } } 21 | 22 | public AbstractEntityWrapper(IEntity e, string className) : base(e, className) { } 23 | } 24 | 25 | public abstract class EntityWrapper : AbstractEntityWrapper 26 | { 27 | public new Entity Entity { get { return (Entity)base.Entity; } } 28 | 29 | public EntityWrapper(Entity e, string className) : base(e, className) { } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /TF2Net/Entities/IEntity.cs: -------------------------------------------------------------------------------- 1 | using TF2Net.Data; 2 | 3 | namespace TF2Net.Entities 4 | { 5 | public interface IBaseEntity : IStaticPropertySet 6 | { 7 | WorldState World { get; } 8 | ServerClass Class { get; } 9 | SendTable NetworkTable { get; } 10 | } 11 | public interface IEntity : IBaseEntity, IPropertySet { } 12 | } 13 | -------------------------------------------------------------------------------- /TF2Net/Entities/IPropertySet.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Diagnostics; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | using TF2Net.Data; 9 | 10 | namespace TF2Net.Entities 11 | { 12 | public interface IStaticPropertySet 13 | { 14 | IReadOnlyList Properties { get; } 15 | } 16 | public interface IPropertySet : IStaticPropertySet 17 | { 18 | SingleEvent> PropertyAdded { get; } 19 | SingleEvent> PropertiesUpdated { get; } 20 | 21 | void AddProperty(SendProp prop); 22 | } 23 | 24 | [EditorBrowsable(EditorBrowsableState.Never)] 25 | public static class IPropertySetExtensions 26 | { 27 | public static SendProp GetProperty(this IStaticPropertySet set, SendPropDefinition def) 28 | { 29 | var retVal = set.Properties.SingleOrDefault(x => x.Definition == def); 30 | Debug.Assert(retVal == null || ReferenceEquals(retVal.Definition, def)); 31 | Debug.Assert(retVal == null || ReferenceEquals(retVal.Entity, set)); 32 | return retVal; 33 | } 34 | public static SendProp GetProperty(this IStaticPropertySet set, string propName) 35 | { 36 | var retVal = set.Properties.SingleOrDefault(x => x.Definition.FullName == propName); 37 | return retVal; 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /TF2Net/Entities/Pill.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using TF2Net.Data; 7 | 8 | namespace TF2Net.Entities 9 | { 10 | public class Pill : EntityWrapper 11 | { 12 | public const string CLASSNAME = "CTFGrenadePipebombProjectile"; 13 | 14 | public Pill(Entity e) : base(e, CLASSNAME) 15 | { 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /TF2Net/Entities/TFRocket.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using TF2Net.Data; 7 | using TF2Net.Monitors; 8 | 9 | namespace TF2Net.Entities 10 | { 11 | public class TFRocket : EntityWrapper, IEquatable, IEquatable 12 | { 13 | public IEntityPropertyMonitor Position { get; } 14 | public IEntityPropertyMonitor Angle { get; } 15 | public IEntityPropertyMonitor Team { get { return Entity.Team; } } 16 | public IEntityPropertyMonitor Launcher { get; } 17 | 18 | public TFRocket(Entity e) : base(e, "CTFProjectile_Rocket") 19 | { 20 | Position = new EntityPropertyMonitor("DT_TFBaseRocket.m_vecOrigin", Entity, o => (Vector)o); 21 | Angle = new EntityPropertyMonitor("DT_TFBaseRocket.m_angRotation", Entity, o => (Vector)o); 22 | Launcher = new EntityPropertyMonitor("DT_TFBaseRocket.m_hLauncher", Entity, o => new EHandle(e.World, (uint)o)); 23 | } 24 | 25 | public bool Equals(TFRocket other) 26 | { 27 | return Entity.Equals(other?.Entity); 28 | } 29 | public override bool Equals(object obj) 30 | { 31 | // Entity 32 | { 33 | Entity e = obj as Entity; 34 | if (e != null) 35 | return Equals(e); 36 | } 37 | 38 | // TFRocket 39 | { 40 | TFRocket r = obj as TFRocket; 41 | if (r != null) 42 | return Equals(r); 43 | } 44 | 45 | return false; 46 | } 47 | public override int GetHashCode() 48 | { 49 | return Entity.GetHashCode(); 50 | } 51 | 52 | public bool Equals(Entity other) 53 | { 54 | return ((IEquatable)Entity).Equals(other); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /TF2Net/Entities/TempEntities/FireBullets.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using TF2Net.Data; 7 | 8 | namespace TF2Net.Entities.TempEntities 9 | { 10 | public class FireBullets : BaseEntityWrapper 11 | { 12 | public Player Player { get; } 13 | public WeaponType Weapon { get; } 14 | public IReadOnlyVector Origin { get; } 15 | 16 | public const string CLASSNAME = "CTEFireBullets"; 17 | public FireBullets(IBaseEntity e) : base(e, CLASSNAME) 18 | { 19 | Origin = (Vector)e.GetProperty("DT_TEFireBullets.m_vecOrigin")?.Value ?? new Vector(); 20 | 21 | { 22 | uint playerIndex = (uint)e.GetProperty("DT_TEFireBullets.m_iPlayer").Value; 23 | Player = e.World.Players.ElementAt((int)playerIndex); 24 | } 25 | 26 | Weapon = (WeaponType)(uint)e.GetProperty("DT_TEFireBullets.m_iWeaponID").Value; 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /TF2Net/Entities/TempEntities/TFBlood.cs: -------------------------------------------------------------------------------- 1 | using TF2Net.Data; 2 | 3 | namespace TF2Net.Entities.TempEntities 4 | { 5 | public class TFBlood : BaseEntityWrapper 6 | { 7 | public IReadOnlyVector Origin { get; } 8 | 9 | public uint? TargetEntityIndex { get; } 10 | public Entity TargetEntity { get { return TargetEntityIndex.HasValue ? Entity.World.Entities[TargetEntityIndex.Value] : null; } } 11 | 12 | public const string CLASSNAME = "CTETFBlood"; 13 | public TFBlood(IBaseEntity e) : base(e, CLASSNAME) 14 | { 15 | { 16 | Vector origin = new Vector(); 17 | // "DT_TETFBlood.m_vecOrigin[0]" 18 | origin.X = (double?)e.GetProperty("DT_TETFBlood.m_vecOrigin[0]")?.Value ?? 0; 19 | origin.Y = (double?)e.GetProperty("DT_TETFBlood.m_vecOrigin[1]")?.Value ?? 0; 20 | origin.Z = (double?)e.GetProperty("DT_TETFBlood.m_vecOrigin[2]")?.Value ?? 0; 21 | Origin = origin; 22 | } 23 | 24 | TargetEntityIndex = (uint?)e.GetProperty("DT_TETFBlood.entindex")?.Value; 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /TF2Net/Entities/TempEntities/TFExplosion.cs: -------------------------------------------------------------------------------- 1 | using TF2Net.Data; 2 | 3 | namespace TF2Net.Entities.TempEntities 4 | { 5 | public class TFExplosion : BaseEntityWrapper 6 | { 7 | public IReadOnlyVector Origin { get; } 8 | public IReadOnlyVector Normal { get; } 9 | 10 | public const string CLASSNAME = "CTETFExplosion"; 11 | public TFExplosion(IBaseEntity e) : base(e, CLASSNAME) 12 | { 13 | { 14 | Vector origin = new Vector(); 15 | origin.X = (double?)e.GetProperty("DT_TETFExplosion.m_vecOrigin[0]")?.Value ?? 0; 16 | origin.Y = (double?)e.GetProperty("DT_TETFExplosion.m_vecOrigin[1]")?.Value ?? 0; 17 | origin.Z = (double?)e.GetProperty("DT_TETFExplosion.m_vecOrigin[2]")?.Value ?? 0; 18 | Origin = origin; 19 | } 20 | 21 | Normal = (Vector)e.GetProperty("DT_TETFExplosion.m_vecNormal").Value; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /TF2Net/Extensions/BitStreamExtensions.cs: -------------------------------------------------------------------------------- 1 | using BitSet; 2 | using TF2Net.Data; 3 | using TF2Net.NetMessages; 4 | 5 | namespace TF2Net.Extensions 6 | { 7 | public static class BitStreamExtensions 8 | { 9 | public static Vector ReadVector(this BitStream stream) 10 | { 11 | bool flagX = stream.ReadBool(); 12 | bool flagY = stream.ReadBool(); 13 | bool flagZ = stream.ReadBool(); 14 | 15 | Vector vector = new Vector(); 16 | if (flagX) 17 | vector.X = BitCoord.Read(stream); 18 | if (flagY) 19 | vector.Y = BitCoord.Read(stream); 20 | if (flagZ) 21 | vector.Z = BitCoord.Read(stream); 22 | return vector; 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /TF2Net/Extensions/System.Collections.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace System.Collections 9 | { 10 | [EditorBrowsable(EditorBrowsableState.Never)] 11 | public static class TF2Net_Extensions 12 | { 13 | public static uint? FindNextSetBit(this BitArray source, uint startIndex = 0) 14 | { 15 | if (source == null) 16 | throw new ArgumentNullException(nameof(source)); 17 | 18 | for (uint i = startIndex; i < source.Length; i++) 19 | { 20 | if (source[(int)i]) 21 | return i; 22 | } 23 | 24 | return null; 25 | } 26 | 27 | public static IDictionary Clone(this IDictionary src) 28 | { 29 | return new Dictionary(src); 30 | } 31 | 32 | public static void AddRange(this IList input, IEnumerable range) 33 | { 34 | if (input == null) 35 | throw new ArgumentNullException(nameof(input)); 36 | if (range == null) 37 | throw new ArgumentNullException(nameof(range)); 38 | 39 | foreach (var x in range) 40 | input.Add(x); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /TF2Net/Extensions/System.Linq.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | 5 | namespace System.Linq 6 | { 7 | [EditorBrowsable(EditorBrowsableState.Never)] 8 | public static class TF2Net_Extensions 9 | { 10 | class ListWrapper : IReadOnlyList 11 | { 12 | readonly IList m_Source; 13 | public ListWrapper(IList src) 14 | { 15 | m_Source = src; 16 | } 17 | 18 | public T this[int index] { get { return m_Source[index]; } } 19 | public int Count { get { return m_Source.Count; } } 20 | public IEnumerator GetEnumerator() { return m_Source.GetEnumerator(); } 21 | IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } 22 | } 23 | 24 | public static IReadOnlyList AsReadOnly(this IList input) 25 | { 26 | if (input == null) 27 | throw new ArgumentNullException(nameof(input)); 28 | 29 | return new ListWrapper(input); 30 | } 31 | 32 | class DictionaryWrapper : IReadOnlyDictionary 33 | { 34 | readonly IDictionary m_Source; 35 | public DictionaryWrapper(IDictionary src) 36 | { 37 | m_Source = src; 38 | } 39 | 40 | public V this[K key] { get { return m_Source[key]; } } 41 | public int Count { get { return m_Source.Count; } } 42 | 43 | public IEnumerable Keys { get { return m_Source.Keys; } } 44 | public IEnumerable Values { get { return m_Source.Values; } } 45 | 46 | public bool ContainsKey(K key) 47 | { 48 | return m_Source.ContainsKey(key); 49 | } 50 | 51 | public IEnumerator> GetEnumerator() 52 | { 53 | return m_Source.GetEnumerator(); 54 | } 55 | 56 | public bool TryGetValue(K key, out V value) 57 | { 58 | return m_Source.TryGetValue(key, out value); 59 | } 60 | 61 | IEnumerator IEnumerable.GetEnumerator() 62 | { 63 | return GetEnumerator(); 64 | } 65 | } 66 | 67 | public static IReadOnlyDictionary AsReadOnly(this IDictionary input) 68 | { 69 | if (input == null) 70 | throw new ArgumentNullException(nameof(input)); 71 | 72 | return new DictionaryWrapper(input); 73 | } 74 | 75 | public static IEnumerable Except(this IEnumerable input, T without) 76 | { 77 | if (input == null) 78 | throw new ArgumentNullException(nameof(input)); 79 | 80 | foreach (var x in input) 81 | { 82 | if (x.Equals(without)) 83 | continue; 84 | 85 | yield return x; 86 | } 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /TF2Net/IWorldEvents.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using TF2Net.Data; 4 | using TF2Net.Entities; 5 | 6 | namespace TF2Net 7 | { 8 | public interface IWorldEvents 9 | { 10 | SingleEvent> GameEventsListLoaded { get; } 11 | SingleEvent> GameEvent { get; } 12 | 13 | SingleEvent> ServerClassesLoaded { get; } 14 | SingleEvent> SendTablesLoaded { get; } 15 | 16 | /// 17 | /// A "Print Message" command from the server. 18 | /// 19 | SingleEvent> ServerTextMessage { get; } 20 | 21 | SingleEvent> ServerInfoLoaded { get; } 22 | 23 | SingleEvent> NewTick { get; } 24 | 25 | SingleEvent>> ServerSetConVar { get; } 26 | SingleEvent> ServerConCommand { get; } 27 | 28 | SingleEvent> ViewEntityUpdated { get; } 29 | 30 | SingleEvent> StringTableCreated { get; } 31 | SingleEvent> StringTableUpdated { get; } 32 | 33 | SingleEvent> EntityCreated { get; } 34 | SingleEvent> EntityEnteredPVS { get; } 35 | SingleEvent> EntityLeftPVS { get; } 36 | SingleEvent> EntityDeleted { get; } 37 | 38 | SingleEvent> PlayerAdded { get; } 39 | SingleEvent> PlayerRemoved { get; } 40 | 41 | SingleEvent> TempEntityCreated { get; } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /TF2Net/Monitors/EntityMonitor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using TF2Net.Data; 7 | using TF2Net.Entities; 8 | 9 | namespace TF2Net.Monitors 10 | { 11 | public class EntityMonitor 12 | { 13 | public SingleEvent> EnteredPVS { get; } = new SingleEvent>(); 14 | public SingleEvent> LeftPVS { get; } = new SingleEvent>(); 15 | 16 | public WorldState World { get; } 17 | public string ClassName { get; } 18 | 19 | public EntityMonitor(WorldState ws, string classname) 20 | { 21 | World = ws; 22 | ClassName = classname; 23 | 24 | World.Listeners.EntityEnteredPVS.Add(Entity_EnteredPVS); 25 | World.Listeners.EntityLeftPVS.Add(Entity_LeftPVS); 26 | } 27 | 28 | void Entity_EnteredPVS(Entity e) 29 | { 30 | if (e.Class.Classname == ClassName) 31 | EnteredPVS.Invoke(this, e); 32 | } 33 | void Entity_LeftPVS(Entity e) 34 | { 35 | if (e.Class.Classname == ClassName) 36 | LeftPVS.Invoke(this, e); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /TF2Net/Monitors/EntityPropertyMonitor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using TF2Net.Data; 8 | using TF2Net.Entities; 9 | 10 | namespace TF2Net.Monitors 11 | { 12 | [DebuggerDisplay("{Value}")] 13 | internal class EntityPropertyMonitor : IEntityPropertyMonitor 14 | { 15 | public Entity Entity { get; } 16 | public string PropertyName { get; } 17 | public SendProp Property { get; private set; } 18 | 19 | Func Decoder { get; } 20 | 21 | bool m_ValueChanged; 22 | public T Value { get; private set; } 23 | object IPropertyMonitor.Value { get { return Value; } } 24 | 25 | SingleEvent> IPropertyMonitor.ValueChanged { get; } = new SingleEvent>(); 26 | SingleEvent>> IPropertyMonitor.ValueChanged { get; } = new SingleEvent>>(); 27 | SingleEvent> IEntityPropertyMonitor.ValueChanged { get; } = new SingleEvent>(); 28 | public SingleEvent>> ValueChanged { get; } = new SingleEvent>>(); 29 | 30 | public EntityPropertyMonitor(string propertyName, Entity e, Func decoder) 31 | { 32 | ValueChanged.Add((self) => ((IPropertyMonitor)self).ValueChanged.Invoke(self)); 33 | ValueChanged.Add((self) => ((IPropertyMonitor)self).ValueChanged.Invoke(self)); 34 | ValueChanged.Add((self) => ((IEntityPropertyMonitor)self).ValueChanged.Invoke(self)); 35 | 36 | PropertyName = propertyName; 37 | Entity = e; 38 | Decoder = decoder; 39 | 40 | Entity.EnteredPVS.Add(Entity_EnteredPVS); 41 | Entity.LeftPVS.Add(Entity_LeftPVS); 42 | Entity.PropertiesUpdated.Add(Entity_PropertiesUpdated); 43 | 44 | if (Entity.InPVS) 45 | Entity_EnteredPVS(Entity); 46 | } 47 | 48 | private void Entity_PropertiesUpdated(IPropertySet e) 49 | { 50 | Debug.Assert(Entity == e); 51 | if (m_ValueChanged) 52 | { 53 | ValueChanged.Invoke(this); 54 | m_ValueChanged = false; 55 | } 56 | } 57 | 58 | private void Entity_LeftPVS(Entity e) 59 | { 60 | Debug.Assert(Entity == e); 61 | e.PropertyAdded.Remove(Entity_PropertyAdded); 62 | Property = null; 63 | } 64 | 65 | private void Entity_EnteredPVS(Entity e) 66 | { 67 | Debug.Assert(Entity == e); 68 | e.PropertyAdded.Add(Entity_PropertyAdded); 69 | 70 | foreach (SendProp prop in e.Properties) 71 | Entity_PropertyAdded(prop); 72 | } 73 | 74 | private void Entity_PropertyAdded(SendProp prop) 75 | { 76 | if (prop.Definition.FullName == PropertyName) 77 | { 78 | Property = prop; 79 | 80 | if (prop.ValueChanged.Add(Prop_ValueChanged)) 81 | { 82 | // First add only 83 | if (prop.Value != null) 84 | Prop_ValueChanged(prop); 85 | } 86 | } 87 | } 88 | 89 | private void Prop_ValueChanged(SendProp prop) 90 | { 91 | Debug.Assert(ReferenceEquals(prop.Entity, Entity)); 92 | Debug.Assert((!Entity.InPVS && Property == null) || prop == Property); 93 | Value = Decoder(prop.Value); 94 | m_ValueChanged = true; 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /TF2Net/Monitors/IPropertyMonitor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using TF2Net.Data; 3 | using TF2Net.Entities; 4 | 5 | namespace TF2Net.Monitors 6 | { 7 | public interface IPlayerPropertyMonitor : IEntityPropertyMonitor, IPlayerPropertyMonitor 8 | { 9 | new SingleEvent>> ValueChanged { get; } 10 | } 11 | public interface IPlayerPropertyMonitor : IEntityPropertyMonitor 12 | { 13 | Player Player { get; } 14 | new SingleEvent> ValueChanged { get; } 15 | } 16 | 17 | public interface IEntityPropertyMonitor : IPropertyMonitor, IEntityPropertyMonitor 18 | { 19 | new SingleEvent>> ValueChanged { get; } 20 | } 21 | public interface IEntityPropertyMonitor : IPropertyMonitor 22 | { 23 | Entity Entity { get; } 24 | new SingleEvent> ValueChanged { get; } 25 | } 26 | 27 | public interface IPropertyMonitor : IPropertyMonitor 28 | { 29 | new T Value { get; } 30 | new SingleEvent>> ValueChanged { get; } 31 | } 32 | public interface IPropertyMonitor 33 | { 34 | object Value { get; } 35 | SendProp Property { get; } 36 | string PropertyName { get; } 37 | SingleEvent> ValueChanged { get; } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /TF2Net/Monitors/MultiPropertyMonitor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using TF2Net.Data; 8 | 9 | namespace TF2Net.Monitors 10 | { 11 | [DebuggerDisplay("{Value}")] 12 | class MultiPropertyMonitor : IPropertyMonitor 13 | { 14 | public string PropertyName { get { return string.Join("\n", PropertyMonitors.Select(pm => pm.PropertyName)); } } 15 | 16 | public T Value { get; private set; } 17 | object IPropertyMonitor.Value { get { return Value; } } 18 | public SendProp Property { get; private set; } 19 | 20 | SingleEvent> IPropertyMonitor.ValueChanged { get; } = new SingleEvent>(); 21 | public SingleEvent>> ValueChanged { get; } = new SingleEvent>>(); 22 | 23 | IEnumerable> PropertyMonitors { get; } 24 | 25 | public MultiPropertyMonitor(IEnumerable> propertyMonitors) 26 | { 27 | ValueChanged.Add(self => ((IPropertyMonitor)self).ValueChanged.Invoke(self)); 28 | 29 | PropertyMonitors = propertyMonitors; 30 | 31 | foreach (var prop in PropertyMonitors) 32 | prop.ValueChanged.Add(PropValueChanged); 33 | } 34 | 35 | void PropValueChanged(IPropertyMonitor propMonitor) 36 | { 37 | T newValue = propMonitor.Value; 38 | if (!Value.Equals(newValue)) 39 | { 40 | Value = newValue; 41 | Property = propMonitor.Property; 42 | 43 | if (!(Property == null || propMonitor.Property == null || propMonitor.Property.LastChangedTick >= Property.LastChangedTick)) 44 | Debugger.Break(); 45 | 46 | ValueChanged.Invoke(this); 47 | } 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /TF2Net/NetMessageCoder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using BitSet; 8 | using TF2Net.Data; 9 | using TF2Net.NetMessages; 10 | 11 | namespace TF2Net 12 | { 13 | public static class NetMessageCoder 14 | { 15 | public static List Decode(BitStream stream) 16 | { 17 | List messages = new List(); 18 | 19 | while (stream.Cursor < (stream.Length - SourceConstants.NETMSG_TYPE_BITS)) 20 | { 21 | NetMessageType type = (NetMessageType)stream.ReadByte(SourceConstants.NETMSG_TYPE_BITS); 22 | 23 | if (type == NetMessageType.NET_NOOP) 24 | continue; 25 | 26 | INetMessage newMsg = CreateNetMessage(type); 27 | newMsg.ReadMsg(stream); 28 | messages.Add(newMsg); 29 | } 30 | 31 | return messages; 32 | } 33 | 34 | static INetMessage CreateNetMessage(NetMessageType type) 35 | { 36 | switch (type) 37 | { 38 | case NetMessageType.NET_FILE: return new NetFileMessage(); 39 | case NetMessageType.NET_TICK: return new NetTickMessage(); 40 | case NetMessageType.NET_STRINGCMD: return new NetStringCmdMessage(); 41 | case NetMessageType.NET_SETCONVAR: return new NetSetConvarMessage(); 42 | case NetMessageType.NET_SIGNONSTATE: return new NetSignonStateMessage(); 43 | case NetMessageType.SVC_PRINT: return new NetPrintMessage(); 44 | case NetMessageType.SVC_SERVERINFO: return new NetServerInfoMessage(); 45 | 46 | case NetMessageType.SVC_CLASSINFO: return new NetClassInfoMessage(); 47 | case NetMessageType.SVC_SETPAUSE: return new NetSetPausedMessage(); 48 | case NetMessageType.SVC_CREATESTRINGTABLE: return new NetCreateStringTableMessage(); 49 | case NetMessageType.SVC_UPDATESTRINGTABLE: return new NetUpdateStringTableMessage(); 50 | case NetMessageType.SVC_VOICEINIT: return new NetVoiceInitMessage(); 51 | case NetMessageType.SVC_VOICEDATA: return new NetVoiceDataMessage(); 52 | 53 | case NetMessageType.SVC_SOUND: return new NetSoundMessage(); 54 | case NetMessageType.SVC_SETVIEW: return new NetSetViewMessage(); 55 | case NetMessageType.SVC_FIXANGLE: return new NetFixAngleMessage(); 56 | case NetMessageType.SVC_BSPDECAL: return new NetBspDecalMessage(); 57 | 58 | case NetMessageType.SVC_USERMESSAGE: return new NetUsrMsgMessage(); 59 | 60 | case NetMessageType.SVC_ENTITYMESSAGE: return new NetEntityMessage(); 61 | case NetMessageType.SVC_GAMEEVENT: return new NetGameEventMessage(); 62 | case NetMessageType.SVC_PACKETENTITIES: return new NetPacketEntitiesMessage(); 63 | case NetMessageType.SVC_TEMPENTITIES: return new NetTempEntityMessage(); 64 | case NetMessageType.SVC_PREFETCH: return new NetPrefetchMessage(); 65 | 66 | case NetMessageType.SVC_GAMEEVENTLIST: return new NetGameEventListMessage(); 67 | 68 | default: throw new NotImplementedException(string.Format("Unimplemented {0} \"{1}\"", typeof(NetMessageType).Name, type)); 69 | } 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /TF2Net/NetMessages/INetMessage.cs: -------------------------------------------------------------------------------- 1 | using BitSet; 2 | using TF2Net.Data; 3 | 4 | namespace TF2Net.NetMessages 5 | { 6 | public interface INetMessage 7 | { 8 | string Description { get; } 9 | 10 | void ReadMsg(BitStream stream); 11 | void ApplyWorldState(WorldState ws); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /TF2Net/NetMessages/NetBSPDecalMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using BitSet; 4 | using TF2Net.Data; 5 | using TF2Net.Extensions; 6 | 7 | namespace TF2Net.NetMessages 8 | { 9 | [DebuggerDisplay("{Description, nq}")] 10 | public class NetBspDecalMessage : INetMessage 11 | { 12 | const byte MaxDecalIndexBits = 9; 13 | const byte MaxEdictBits = 11; 14 | const byte SpModelIndexBits = 11; 15 | 16 | public string Description => string.Format("svc_bspdecal: {0} {1} {2}", Position, DecalTextureIndex, EntIndex); 17 | public Vector Position { get; set; } 18 | public ulong DecalTextureIndex { get; set; } 19 | public ulong EntIndex { get; set; } 20 | public ulong ModelIndex { get; set; } 21 | public bool LowPrioritiy { get; set; } 22 | 23 | 24 | public void ReadMsg(BitStream stream) 25 | { 26 | Position = stream.ReadVector(); 27 | DecalTextureIndex = stream.ReadULong(MaxDecalIndexBits); 28 | 29 | bool b = stream.ReadBool(); 30 | if (b) 31 | { 32 | EntIndex = stream.ReadULong(MaxEdictBits); 33 | ModelIndex = stream.ReadULong(SpModelIndexBits); 34 | } 35 | else 36 | { 37 | EntIndex = 0; 38 | ModelIndex = 0; 39 | } 40 | LowPrioritiy = stream.ReadBool(); 41 | } 42 | 43 | 44 | public void ApplyWorldState(WorldState ws) 45 | { 46 | throw new NotImplementedException(); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /TF2Net/NetMessages/NetClassInfoMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using BitSet; 5 | using TF2Net.Data; 6 | 7 | namespace TF2Net.NetMessages 8 | { 9 | [DebuggerDisplay("{Description, nq}")] 10 | public class NetClassInfoMessage : INetMessage 11 | { 12 | public short ServerClassCount { get; set; } 13 | public bool CreateOnClient { get; set; } 14 | 15 | public class ServerClass 16 | { 17 | public ushort ClassID { get; set; } 18 | public string DataTableName { get; set; } 19 | public string ClassName { get; set; } 20 | } 21 | public IList ServerClasses { get; set; } 22 | 23 | public string Description 24 | { 25 | get 26 | { 27 | return string.Format("svc_ClassInfo: num {0}, {1}", ServerClassCount, 28 | CreateOnClient ? "use client classes" : "full update"); 29 | } 30 | } 31 | 32 | public void ReadMsg(BitStream stream) 33 | { 34 | ServerClassCount = stream.ReadShort(); 35 | 36 | CreateOnClient = stream.ReadBool(); 37 | if (CreateOnClient) 38 | return; 39 | 40 | byte serverClassBits = (byte)(ExtMath.Log2(ServerClassCount) + 1); 41 | ServerClasses = new List(); 42 | for (int i = 0; i < ServerClassCount; i++) 43 | { 44 | ServerClass sc = new ServerClass(); 45 | 46 | sc.ClassID = stream.ReadUShort(serverClassBits); 47 | sc.ClassName = stream.ReadCString(); 48 | sc.DataTableName = stream.ReadCString(); 49 | 50 | ServerClasses.Add(sc); 51 | } 52 | } 53 | 54 | public void ApplyWorldState(WorldState ws) 55 | { 56 | if (!CreateOnClient) 57 | throw new NotImplementedException(); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /TF2Net/NetMessages/NetEntityMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using BitSet; 8 | using TF2Net.Data; 9 | using TF2Net.Entities; 10 | 11 | namespace TF2Net.NetMessages 12 | { 13 | [DebuggerDisplay("{Description, nq}")] 14 | public class NetEntityMessage : INetMessage 15 | { 16 | const int DATA_LENGTH_BITS = 11; 17 | 18 | public uint EntityIndex { get; set; } 19 | public uint ClassID { get; set; } 20 | 21 | public BitStream Data { get; set; } 22 | 23 | public string Description 24 | { 25 | get 26 | { 27 | return string.Format("svc_EntityMessage: entity {0}, class {1}, bytes {2}", 28 | EntityIndex, ClassID, BitInfo.BitsToBytes(Data.Length)); 29 | } 30 | } 31 | public void WriteMsg(byte[] buffer, ref ulong bitOffset) 32 | { 33 | throw new NotImplementedException(); 34 | } 35 | 36 | public void ReadMsg(BitStream stream) 37 | { 38 | EntityIndex = stream.ReadUInt(SourceConstants.MAX_EDICT_BITS); 39 | ClassID = stream.ReadUInt(SourceConstants.MAX_SERVER_CLASS_BITS); 40 | 41 | ulong bitCount = stream.ReadULong(DATA_LENGTH_BITS); 42 | Data = stream.Subsection(stream.Cursor, stream.Cursor + bitCount); 43 | stream.Seek(bitCount, System.IO.SeekOrigin.Current); 44 | } 45 | 46 | public void ApplyWorldState(WorldState ws) 47 | { 48 | Entity target = ws.Entities[EntityIndex]; 49 | Console.WriteLine("hi"); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /TF2Net/NetMessages/NetFileMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using BitSet; 8 | using TF2Net.Data; 9 | 10 | namespace TF2Net.NetMessages 11 | { 12 | [DebuggerDisplay("{Description, nq}")] 13 | public class NetFileMessage : INetMessage 14 | { 15 | public uint TransferID { get; set; } 16 | public string Filename { get; set; } 17 | 18 | public enum FileStatus 19 | { 20 | Denied = 0, 21 | Requested = 1, 22 | } 23 | 24 | public FileStatus Status { get; set; } 25 | 26 | public string Description 27 | { 28 | get 29 | { 30 | return string.Format("net_File: {0} {1}", Filename, Status); 31 | } 32 | } 33 | public void ReadMsg(BitStream stream) 34 | { 35 | TransferID = stream.ReadUInt(); 36 | Filename = stream.ReadCString(); 37 | 38 | Status = (FileStatus)stream.ReadByte(1); 39 | } 40 | 41 | public void ApplyWorldState(WorldState ws) 42 | { 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /TF2Net/NetMessages/NetFixAngleMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using BitSet; 8 | using TF2Net.Data; 9 | 10 | namespace TF2Net.NetMessages 11 | { 12 | [DebuggerDisplay("{Description, nq}")] 13 | public class NetFixAngleMessage : INetMessage 14 | { 15 | const int ANGLE_BITS = 16; 16 | 17 | public bool Relative { get; set; } 18 | public double[] Angle { get; set; } 19 | 20 | public string Description 21 | { 22 | get 23 | { 24 | return string.Format("svc_FixAngle: {0} {1:N1} {2:N1} {3:N1}", 25 | Relative ? "relative" : "absolute", 26 | Angle[0], Angle[1], Angle[2]); 27 | } 28 | } 29 | 30 | public void ReadMsg(BitStream stream) 31 | { 32 | Relative = stream.ReadBool(); 33 | 34 | Angle = new double[3]; 35 | Angle[0] = BitAngle.Read(stream, ANGLE_BITS); 36 | Angle[1] = BitAngle.Read(stream, ANGLE_BITS); 37 | Angle[2] = BitAngle.Read(stream, ANGLE_BITS); 38 | } 39 | 40 | public void ApplyWorldState(WorldState ws) 41 | { 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /TF2Net/NetMessages/NetGameEventListMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using BitSet; 5 | using TF2Net.Data; 6 | 7 | namespace TF2Net.NetMessages 8 | { 9 | [DebuggerDisplay("{Description, nq}")] 10 | public class NetGameEventListMessage : INetMessage 11 | { 12 | [DebuggerBrowsable(DebuggerBrowsableState.Never)] 13 | ulong BitCount { get; set; } 14 | //public byte[] Data { get; set; } 15 | 16 | public IList Events { get; set; } 17 | 18 | public string Description 19 | { 20 | get 21 | { 22 | return string.Format("svc_GameEventList: number {0}, bytes {1}", 23 | Events.Count, BitInfo.BitsToBytes(BitCount)); 24 | } 25 | } 26 | 27 | public void ReadMsg(BitStream stream) 28 | { 29 | ushort eventsCount = stream.ReadUShort(SourceConstants.MAX_EVENT_BITS); 30 | 31 | BitCount = stream.ReadULong(20); 32 | 33 | Events = new List(); 34 | for (int i = 0; i < eventsCount; i++) 35 | { 36 | GameEventDeclaration e = new GameEventDeclaration(); 37 | e.ID = stream.ReadInt(SourceConstants.MAX_EVENT_BITS); 38 | e.Name = stream.ReadCString(); 39 | 40 | GameEventDataType type; 41 | 42 | e.Values = new Dictionary(); 43 | while ((type = (GameEventDataType)stream.ReadUShort(3)) != GameEventDataType.Local) 44 | { 45 | string name = stream.ReadCString(); 46 | e.Values.Add(name, type); 47 | } 48 | 49 | Events.Add(e); 50 | } 51 | } 52 | 53 | public void ApplyWorldState(WorldState ws) 54 | { 55 | ws.EventDeclarations = Events; 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /TF2Net/NetMessages/NetGameEventMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.IO; 5 | using System.Linq; 6 | using BitSet; 7 | using TF2Net.Data; 8 | 9 | namespace TF2Net.NetMessages 10 | { 11 | [DebuggerDisplay("{Description, nq}")] 12 | public class NetGameEventMessage : INetMessage 13 | { 14 | const int EVENT_LENGTH_BITS = 11; 15 | 16 | public BitStream Data { get; set; } 17 | 18 | public string Description 19 | { 20 | get 21 | { 22 | return string.Format("svc_GameEvent: bytes {0}", BitInfo.BitsToBytes(Data.Length)); 23 | } 24 | } 25 | 26 | public void ReadMsg(BitStream stream) 27 | { 28 | ulong bitCount = stream.ReadULong(EVENT_LENGTH_BITS); 29 | Data = stream.Subsection(stream.Cursor, stream.Cursor + bitCount); 30 | stream.Seek(bitCount, SeekOrigin.Current); 31 | } 32 | 33 | public void ApplyWorldState(WorldState ws) 34 | { 35 | GameEvent retVal = new GameEvent(); 36 | 37 | int eventID = Data.ReadInt(SourceConstants.MAX_EVENT_BITS); 38 | 39 | retVal.Declaration = ws.EventDeclarations.Single(g => g.ID == eventID); 40 | 41 | retVal.Values = new Dictionary(); 42 | foreach (var value in retVal.Declaration.Values) 43 | { 44 | switch (value.Value) 45 | { 46 | case GameEventDataType.Local: break; 47 | case GameEventDataType.Bool: retVal.Values.Add(value.Key, Data.ReadBool()); break; 48 | case GameEventDataType.Byte: retVal.Values.Add(value.Key, Data.ReadByte()); break; 49 | case GameEventDataType.Float: retVal.Values.Add(value.Key, Data.ReadSingle()); break; 50 | case GameEventDataType.Long: retVal.Values.Add(value.Key, Data.ReadInt()); break; 51 | case GameEventDataType.Short: retVal.Values.Add(value.Key, Data.ReadShort()); break; 52 | case GameEventDataType.String: retVal.Values.Add(value.Key, Data.ReadCString()); break; 53 | 54 | default: 55 | throw new FormatException("Invalid GameEvent type"); 56 | } 57 | } 58 | 59 | ws.Listeners.GameEvent.Invoke(ws, retVal); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /TF2Net/NetMessages/NetMessageType.cs: -------------------------------------------------------------------------------- 1 | namespace TF2Net.NetMessages 2 | { 3 | enum NetMessageType : byte 4 | { 5 | NET_NOOP = 0, 6 | NET_DISCONNECT = 1, 7 | NET_FILE = 2, 8 | NET_TICK = 3, 9 | NET_STRINGCMD = 4, 10 | NET_SETCONVAR = 5, 11 | NET_SIGNONSTATE = 6, 12 | SVC_PRINT = 7, 13 | SVC_SERVERINFO = 8, 14 | SVC_SENDTABLE = 9, 15 | SVC_CLASSINFO = 10, 16 | SVC_SETPAUSE = 11, 17 | SVC_CREATESTRINGTABLE = 12, 18 | SVC_UPDATESTRINGTABLE = 13, 19 | SVC_VOICEINIT = 14, 20 | SVC_VOICEDATA = 15, 21 | // 16 22 | SVC_SOUND = 17, 23 | SVC_SETVIEW = 18, 24 | SVC_FIXANGLE = 19, 25 | SVC_CROSSHAIRANGLE = 20, 26 | SVC_BSPDECAL = 21, 27 | // 22 28 | SVC_USERMESSAGE = 23, 29 | SVC_ENTITYMESSAGE = 24, 30 | SVC_GAMEEVENT = 25, 31 | SVC_PACKETENTITIES = 26, 32 | SVC_TEMPENTITIES = 27, 33 | SVC_PREFETCH = 28, 34 | SVC_MENU = 29, 35 | SVC_GAMEEVENTLIST = 30, 36 | SVC_GETCVARVALUE = 31, 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /TF2Net/NetMessages/NetPrefetchMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using BitSet; 4 | using TF2Net.Data; 5 | 6 | namespace TF2Net.NetMessages 7 | { 8 | [DebuggerDisplay("{Description, nq}")] 9 | public class NetPrefetchMessage : INetMessage 10 | { 11 | public enum PrefetchType 12 | { 13 | Sound = 0, 14 | } 15 | 16 | public PrefetchType Type { get; set; } 17 | 18 | public int SoundIndex { get; set; } 19 | 20 | public string Description 21 | { 22 | get 23 | { 24 | return string.Format("svc_Prefetch: type {0} index {1}", Type, SoundIndex); 25 | } 26 | } 27 | 28 | public void ReadMsg(BitStream stream) 29 | { 30 | Type = PrefetchType.Sound; 31 | SoundIndex = stream.ReadInt(SourceConstants.MAX_SOUND_INDEX_BITS); 32 | } 33 | 34 | public void ApplyWorldState(WorldState ws) 35 | { 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /TF2Net/NetMessages/NetPrintMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using BitSet; 8 | using TF2Net.Data; 9 | 10 | namespace TF2Net.NetMessages 11 | { 12 | [DebuggerDisplay("{Description, nq}")] 13 | public class NetPrintMessage : INetMessage 14 | { 15 | public string Message { get; set; } 16 | 17 | public string Description 18 | { 19 | get 20 | { 21 | return string.Format("svc_Print: \"{0}\"", Message); 22 | } 23 | } 24 | 25 | public void ReadMsg(BitStream stream) 26 | { 27 | Message = stream.ReadCString(); 28 | } 29 | 30 | public void ApplyWorldState(WorldState ws) 31 | { 32 | ws.Listeners.ServerTextMessage.Invoke(ws, Message); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /TF2Net/NetMessages/NetServerInfoMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using BitSet; 8 | using TF2Net.Data; 9 | 10 | namespace TF2Net.NetMessages 11 | { 12 | [DebuggerDisplay("{Description, nq}")] 13 | public class NetServerInfoMessage : INetMessage 14 | { 15 | public ServerInfo Info { get; set; } 16 | 17 | public string Description 18 | { 19 | get 20 | { 21 | return string.Format("svc_ServerInfo: game \"{0}\", map \"{1}\", max {2}", 22 | Info.GameDirectory, Info.MapName, Info.MaxClients); 23 | } 24 | } 25 | 26 | public void ReadMsg(BitStream stream) 27 | { 28 | Info = new ServerInfo(); 29 | 30 | Info.Protocol = stream.ReadShort(); 31 | Info.ServerCount = stream.ReadInt(); 32 | Info.IsHLTV = stream.ReadBool(); 33 | Info.IsDedicated = stream.ReadBool(); 34 | Info.ClientCRC = stream.ReadUInt(); 35 | Info.MaxClasses = stream.ReadUShort(); 36 | 37 | // Unknown 38 | stream.Seek(16 * 8, System.IO.SeekOrigin.Current); 39 | 40 | Info.PlayerSlot = stream.ReadByte(); 41 | Info.MaxClients = stream.ReadByte(); 42 | Info.TickInterval = stream.ReadSingle(); 43 | 44 | switch (stream.ReadChar()) 45 | { 46 | case 'l': 47 | case 'L': 48 | Info.OS = ServerInfo.OperatingSystem.Linux; 49 | break; 50 | 51 | case 'w': 52 | case 'W': 53 | Info.OS = ServerInfo.OperatingSystem.Windows; 54 | break; 55 | 56 | default: 57 | Info.OS = ServerInfo.OperatingSystem.Unknown; 58 | break; 59 | } 60 | 61 | Info.GameDirectory = stream.ReadCString(); 62 | Info.MapName = stream.ReadCString(); 63 | Info.SkyName = stream.ReadCString(); 64 | Info.Hostname = stream.ReadCString(); 65 | 66 | // Unknown 67 | stream.Seek(1, System.IO.SeekOrigin.Current); 68 | } 69 | 70 | public void ApplyWorldState(WorldState ws) 71 | { 72 | ws.ServerInfo = Info; 73 | ws.Listeners.ServerInfoLoaded.Invoke(ws); 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /TF2Net/NetMessages/NetSetConvarMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using BitSet; 8 | using TF2Net.Data; 9 | 10 | namespace TF2Net.NetMessages 11 | { 12 | [DebuggerDisplay("{Description, nq}")] 13 | public class NetSetConvarMessage : INetMessage 14 | { 15 | public IList> Cvars { get; set; } 16 | 17 | public string Description 18 | { 19 | get 20 | { 21 | return string.Format("net_SetConVar: {0} cvars, \"{1}\"=\"{2}\"", 22 | Cvars.Count, Cvars[0].Key, Cvars[0].Value); 23 | } 24 | } 25 | 26 | public ulong Size 27 | { 28 | get 29 | { 30 | throw new NotImplementedException(); 31 | } 32 | } 33 | 34 | public void WriteMsg(byte[] buffer, ref ulong bitOffset) 35 | { 36 | throw new NotImplementedException(); 37 | } 38 | 39 | public void ReadMsg(BitStream stream) 40 | { 41 | byte count = stream.ReadByte(); 42 | 43 | Cvars = new List>(count); 44 | for (int i = 0; i < count; i++) 45 | { 46 | string name = stream.ReadCString(); 47 | string value = stream.ReadCString(); 48 | Cvars.Add(new KeyValuePair(name, value)); 49 | } 50 | } 51 | 52 | public void ApplyWorldState(WorldState ws) 53 | { 54 | foreach (var cvar in Cvars) 55 | { 56 | ws.ConVars[cvar.Key] = cvar.Value; 57 | ws.Listeners.ServerSetConVar.Invoke(ws, cvar); 58 | } 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /TF2Net/NetMessages/NetSetPausedMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using BitSet; 8 | using TF2Net.Data; 9 | 10 | namespace TF2Net.NetMessages 11 | { 12 | [DebuggerDisplay("{Description, nq}")] 13 | public class NetSetPausedMessage : INetMessage 14 | { 15 | public bool Paused { get; set; } 16 | 17 | public string Description 18 | { 19 | get 20 | { 21 | return string.Format("svc_SetPause: {0}", Paused ? "Paused" : "Unpaused"); 22 | } 23 | } 24 | 25 | public void ReadMsg(BitStream stream) 26 | { 27 | Paused = stream.ReadBool(); 28 | } 29 | 30 | public void ApplyWorldState(WorldState ws) 31 | { 32 | throw new NotImplementedException(); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /TF2Net/NetMessages/NetSetViewMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using BitSet; 8 | using TF2Net.Data; 9 | 10 | namespace TF2Net.NetMessages 11 | { 12 | [DebuggerDisplay("{Description, nq}")] 13 | public class NetSetViewMessage : INetMessage 14 | { 15 | public ushort EntityIndex { get; set; } 16 | 17 | public string Description 18 | { 19 | get 20 | { 21 | return string.Format("svc_SetView: view entity {0}", EntityIndex); 22 | } 23 | } 24 | 25 | public void ReadMsg(BitStream stream) 26 | { 27 | EntityIndex = stream.ReadUShort(SourceConstants.MAX_EDICT_BITS); 28 | } 29 | 30 | public void ApplyWorldState(WorldState ws) 31 | { 32 | ws.ViewEntity = EntityIndex; 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /TF2Net/NetMessages/NetSignonStateMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using BitSet; 8 | using TF2Net.Data; 9 | 10 | namespace TF2Net.NetMessages 11 | { 12 | [DebuggerDisplay("{Description, nq}")] 13 | public class NetSignonStateMessage : INetMessage 14 | { 15 | public SignonState State { get; set; } 16 | 17 | public string Description 18 | { 19 | get 20 | { 21 | return string.Format("net_SignonState: state {0}, count {1}", State.State, State.SpawnCount); 22 | } 23 | } 24 | 25 | public void ReadMsg(BitStream stream) 26 | { 27 | State = new SignonState(); 28 | 29 | State.State = (ConnectionState)stream.ReadByte(); 30 | State.SpawnCount = stream.ReadInt(); 31 | } 32 | 33 | public void ApplyWorldState(WorldState ws) 34 | { 35 | ws.SignonState = State; 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /TF2Net/NetMessages/NetSoundMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using BitSet; 4 | using TF2Net.Data; 5 | 6 | namespace TF2Net.NetMessages 7 | { 8 | [DebuggerDisplay("{Description, nq}")] 9 | public class NetSoundMessage : INetMessage 10 | { 11 | const int SOUND_COUNT_BITS = 8; 12 | const int RELIABLE_SIZE_BITS = 8; 13 | const int UNRELIABLE_SIZE_BITS = 16; 14 | 15 | public bool Reliable { get; set; } 16 | public int SoundCount { get; set; } 17 | 18 | public BitStream Data { get; set; } 19 | 20 | public string Description 21 | { 22 | get 23 | { 24 | return string.Format("svc_Sounds: number {0},{1} bytes {2}", 25 | SoundCount, Reliable ? " reliable," : "", BitInfo.BitsToBytes(Data.Length)); 26 | } 27 | } 28 | 29 | public void ReadMsg(BitStream stream) 30 | { 31 | Reliable = stream.ReadBool(); 32 | 33 | ulong bitCount; 34 | if (Reliable) 35 | { 36 | SoundCount = 1; 37 | bitCount = stream.ReadULong(RELIABLE_SIZE_BITS); 38 | } 39 | else 40 | { 41 | SoundCount = stream.ReadInt(SOUND_COUNT_BITS); 42 | bitCount = stream.ReadULong(UNRELIABLE_SIZE_BITS); 43 | } 44 | 45 | Data = stream.Subsection(stream.Cursor, stream.Cursor + bitCount); 46 | stream.Seek(bitCount, System.IO.SeekOrigin.Current); 47 | } 48 | 49 | public void ApplyWorldState(WorldState ws) 50 | { 51 | //throw new NotImplementedException(); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /TF2Net/NetMessages/NetStringCmdMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using BitSet; 5 | using TF2Net.Data; 6 | 7 | namespace TF2Net.NetMessages 8 | { 9 | [DebuggerDisplay("{Description, nq}")] 10 | public class NetStringCmdMessage : INetMessage 11 | { 12 | public string Command { get; set; } 13 | 14 | public string Description 15 | { 16 | get 17 | { 18 | return string.Format("net_StringCmd: \"{0}\"", Command); 19 | } 20 | } 21 | 22 | public void ReadMsg(BitStream stream) 23 | { 24 | Command = stream.ReadCString(); 25 | } 26 | 27 | public void ApplyWorldState(WorldState ws) 28 | { 29 | ws.Listeners.ServerConCommand.Invoke(ws, Command); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /TF2Net/NetMessages/NetTempEntityMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using BitSet; 8 | using TF2Net.Data; 9 | using TF2Net.Entities; 10 | 11 | namespace TF2Net.NetMessages 12 | { 13 | [DebuggerDisplay("{Description, nq}")] 14 | public class NetTempEntityMessage : INetMessage 15 | { 16 | public int EntryCount { get; set; } 17 | 18 | public BitStream Data { get; set; } 19 | 20 | public string Description 21 | { 22 | get 23 | { 24 | return string.Format("svc_TempEntities: number {0}, bytes {1}", EntryCount, BitInfo.BitsToBytes(Data.Length)); 25 | } 26 | } 27 | 28 | public void ReadMsg(BitStream stream) 29 | { 30 | EntryCount = stream.ReadInt(SourceConstants.EVENT_INDEX_BITS); 31 | 32 | ulong bitCount = stream.ReadVarUInt(); 33 | 34 | Data = stream.Subsection(stream.Cursor, stream.Cursor + bitCount); 35 | stream.Seek(bitCount, System.IO.SeekOrigin.Current); 36 | } 37 | 38 | public void ApplyWorldState(WorldState ws) 39 | { 40 | List tempents = new List(); 41 | { 42 | BitStream local = Data.Clone(); 43 | local.Cursor = 0; 44 | 45 | TempEntity e = null; 46 | for (int i = 0; i < EntryCount; i++) 47 | { 48 | double delay = 0; 49 | if (local.ReadBool()) 50 | delay = local.ReadInt(8) / 100.0; 51 | 52 | if (local.ReadBool()) 53 | { 54 | uint classID = local.ReadUInt(ws.ClassBits); 55 | 56 | ServerClass serverClass = ws.ServerClasses[(int)classID - 1]; 57 | SendTable sendTable = ws.SendTables.Single(st => st.NetTableName == serverClass.DatatableName); 58 | var flattened = sendTable.FlattenedProps; 59 | 60 | e = new TempEntity(ws, serverClass, sendTable); 61 | EntityCoder.ApplyEntityUpdate(e, local); 62 | tempents.Add(e); 63 | } 64 | else 65 | { 66 | Debug.Assert(e != null); 67 | EntityCoder.ApplyEntityUpdate(e, local); 68 | } 69 | } 70 | } 71 | 72 | foreach (IBaseEntity te in tempents) 73 | { 74 | ws.Listeners.TempEntityCreated.Invoke(te); 75 | } 76 | } 77 | 78 | [DebuggerDisplay("{Class,nq}")] 79 | class TempEntity : IEntity 80 | { 81 | readonly List m_Properties = new List(); 82 | public IReadOnlyList Properties { get { return m_Properties; } } 83 | 84 | public SingleEvent> PropertiesUpdated { get; } = new SingleEvent>(); 85 | public SingleEvent> PropertyAdded { get; } = new SingleEvent>(); 86 | 87 | public WorldState World { get; } 88 | public ServerClass Class { get; } 89 | public SendTable NetworkTable { get; } 90 | 91 | public TempEntity(WorldState ws, ServerClass sClass, SendTable table) 92 | { 93 | World = ws; 94 | Class = sClass; 95 | NetworkTable = table; 96 | } 97 | 98 | public void AddProperty(SendProp newProp) 99 | { 100 | Debug.Assert(!m_Properties.Any(p => ReferenceEquals(p.Definition, newProp.Definition))); 101 | Debug.Assert(ReferenceEquals(newProp.Entity, this)); 102 | 103 | m_Properties.Add(newProp); 104 | PropertyAdded.Invoke(newProp); 105 | } 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /TF2Net/NetMessages/NetTickMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using BitSet; 4 | using TF2Net.Data; 5 | 6 | namespace TF2Net.NetMessages 7 | { 8 | [DebuggerDisplay("{Description, nq}")] 9 | public class NetTickMessage : INetMessage 10 | { 11 | const int TICK_BITS = 32; 12 | const int FLOAT_BITS = 16; 13 | const double NET_TICK_SCALEUP = 100000.0; 14 | 15 | public uint Tick { get; set; } 16 | public double HostFrameTime { get; set; } 17 | public double HostFrameTimeStdDev { get; set; } 18 | 19 | public string Description 20 | { 21 | get 22 | { 23 | return string.Format("net_Tick: tick {0}", Tick); 24 | } 25 | } 26 | 27 | public void ReadMsg(BitStream stream) 28 | { 29 | Tick = stream.ReadUInt(TICK_BITS); 30 | 31 | HostFrameTime = stream.ReadUInt(FLOAT_BITS) / NET_TICK_SCALEUP; 32 | HostFrameTimeStdDev = stream.ReadUInt(FLOAT_BITS) / NET_TICK_SCALEUP; 33 | } 34 | 35 | public void ApplyWorldState(WorldState ws) 36 | { 37 | ws.Tick = Tick; 38 | ws.LastFrameTime = HostFrameTime; 39 | ws.LastFrameTimeStdDev = HostFrameTimeStdDev; 40 | 41 | ws.Listeners.NewTick.Invoke(ws); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /TF2Net/NetMessages/NetUpdateStringTableMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using BitSet; 4 | using TF2Net.Data; 5 | using TF2Net.NetMessages.Shared; 6 | 7 | namespace TF2Net.NetMessages 8 | { 9 | [DebuggerDisplay("{Description, nq}")] 10 | public class NetUpdateStringTableMessage : INetMessage 11 | { 12 | const int MAX_TABLE_BITS = 5; 13 | const int MAX_TABLES = (1 << MAX_TABLE_BITS); 14 | const int DATA_LENGTH_BITS = 20; 15 | const int CHANGED_ENTRIES_BITS = 16; 16 | 17 | public int TableID { get; set; } 18 | public int ChangedEntries { get; set; } 19 | 20 | public BitStream Data { get; set; } 21 | 22 | public string Description 23 | { 24 | get 25 | { 26 | return string.Format("svc_UpdateStringTable: table {0}, changed {1}, bytes {2}", 27 | TableID, ChangedEntries, BitInfo.BitsToBytes(Data.Length)); 28 | } 29 | } 30 | 31 | public void ReadMsg(BitStream stream) 32 | { 33 | TableID = stream.ReadInt(MAX_TABLE_BITS); 34 | 35 | bool multipleChanged = stream.ReadBool(); 36 | if (!multipleChanged) 37 | ChangedEntries = 1; 38 | else 39 | ChangedEntries = stream.ReadInt(CHANGED_ENTRIES_BITS); 40 | 41 | ulong bitCount = stream.ReadULong(DATA_LENGTH_BITS); 42 | Data = stream.Subsection(stream.Cursor, stream.Cursor + bitCount); 43 | stream.Seek(bitCount, System.IO.SeekOrigin.Current); 44 | } 45 | 46 | public void ApplyWorldState(WorldState ws) 47 | { 48 | StringTable found = ws.StringTables[TableID]; 49 | StringTableParser.ParseUpdate(Data, found, (ushort)ChangedEntries); 50 | 51 | ws.Listeners.StringTableUpdated.Invoke(ws, found); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /TF2Net/NetMessages/NetUsrMsgMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.Linq; 4 | using BitSet; 5 | using TF2Net.Data; 6 | 7 | namespace TF2Net.NetMessages 8 | { 9 | [DebuggerDisplay("{Description, nq}")] 10 | public class NetUsrMsgMessage : INetMessage 11 | { 12 | const int MAX_USER_MSG_TYPE_BITS = 8; 13 | 14 | public UserMessageType Type { get; set; } 15 | 16 | public BitStream Data { get; set; } 17 | 18 | public string Description 19 | { 20 | get 21 | { 22 | return string.Format("svc_UserMessage: type {0}, bytes {1}", Type, BitInfo.BitsToBytes(Data.Length)); 23 | } 24 | } 25 | 26 | public void ReadMsg(BitStream stream) 27 | { 28 | Type = (UserMessageType)stream.ReadInt(MAX_USER_MSG_TYPE_BITS); 29 | Debug.Assert(Enum.GetValues(typeof(UserMessageType)).Cast().Contains(Type)); 30 | 31 | ulong bitCount = stream.ReadULong(SourceConstants.MAX_USER_MSG_LENGTH_BITS); 32 | Data = stream.Subsection(stream.Cursor, stream.Cursor + bitCount); 33 | stream.Seek(bitCount, System.IO.SeekOrigin.Current); 34 | } 35 | 36 | public void ApplyWorldState(WorldState ws) 37 | { 38 | return; 39 | //throw new NotImplementedException(); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /TF2Net/NetMessages/NetVoiceDataMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using BitSet; 4 | using TF2Net.Data; 5 | 6 | namespace TF2Net.NetMessages 7 | { 8 | [DebuggerDisplay("{Description, nq}")] 9 | public class NetVoiceDataMessage : INetMessage 10 | { 11 | public byte ClientIndex { get; set; } 12 | public bool Proximity { get; set; } 13 | 14 | public BitStream Data { get; set; } 15 | 16 | public string Description 17 | { 18 | get 19 | { 20 | return string.Format("svc_VoiceData: client {0}, bytes {1}", 21 | ClientIndex, BitInfo.BitsToBytes(Data.Length)); 22 | } 23 | } 24 | 25 | public void ReadMsg(BitStream stream) 26 | { 27 | ClientIndex = stream.ReadByte(); 28 | Proximity = stream.ReadByte() != 0; 29 | 30 | ulong bitCount = stream.ReadULong(16); 31 | Data = stream.Subsection(stream.Cursor, stream.Cursor + bitCount); 32 | stream.Seek(bitCount, System.IO.SeekOrigin.Current); 33 | } 34 | 35 | public void ApplyWorldState(WorldState ws) 36 | { 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /TF2Net/NetMessages/NetVoiceInitMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using BitSet; 8 | using TF2Net.Data; 9 | 10 | namespace TF2Net.NetMessages 11 | { 12 | [DebuggerDisplay("{Description, nq}")] 13 | public class NetVoiceInitMessage : INetMessage 14 | { 15 | public string VoiceCodec { get; set; } 16 | public byte Quality { get; set; } 17 | 18 | public string Description 19 | { 20 | get 21 | { 22 | return string.Format("svc_VoiceInit: codec \"{0}\", qualitty {1}", 23 | VoiceCodec, Quality); 24 | } 25 | } 26 | 27 | public void ReadMsg(BitStream stream) 28 | { 29 | VoiceCodec = stream.ReadCString(); 30 | Quality = stream.ReadByte(); 31 | } 32 | 33 | public void ApplyWorldState(WorldState ws) 34 | { 35 | //throw new NotImplementedException(); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /TF2Net/NetMessages/Shared/BitAngle.cs: -------------------------------------------------------------------------------- 1 | using BitSet; 2 | 3 | namespace TF2Net.NetMessages 4 | { 5 | static class BitAngle 6 | { 7 | public static double Read(BitStream stream, byte bitCount) 8 | { 9 | double shift = (1 << bitCount); 10 | 11 | var rawValue = stream.ReadULong(bitCount); 12 | return rawValue * (360 / shift); 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /TF2Net/NetMessages/Shared/BitCoord.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using BitSet; 7 | 8 | namespace TF2Net.NetMessages 9 | { 10 | static class BitCoord 11 | { 12 | const uint COORD_INTEGER_BITS = 14; 13 | const uint COORD_FRACTIONAL_BITS = 5; 14 | const uint COORD_DENOMINATOR = (1 << (int)(COORD_FRACTIONAL_BITS)); 15 | const double COORD_RESOLUTION = (1.0 / (COORD_DENOMINATOR)); 16 | 17 | public static double Read(byte[] source, ref ulong readBitOffset) 18 | { 19 | // Read the required integer and fraction flags 20 | int intVal = BitReader.ReadUInt1(source, ref readBitOffset); 21 | int fractVal = BitReader.ReadUInt1(source, ref readBitOffset); 22 | 23 | // If we got either parse them, otherwise it's a zero. 24 | if (intVal != 0 || fractVal != 0) 25 | { 26 | // Read the sign bit 27 | var signBit = BitReader.ReadUInt1(source, ref readBitOffset); 28 | 29 | // If there's an integer, read it in 30 | if (intVal != 0) 31 | { 32 | // Adjust the integers from [0..MAX_COORD_VALUE-1] to [1..MAX_COORD_VALUE] 33 | intVal = (int)BitReader.ReadUIntBits(source, ref readBitOffset, (byte)COORD_INTEGER_BITS); 34 | intVal++; 35 | } 36 | 37 | // If there's a fraction, read it in 38 | if (fractVal != 0) 39 | { 40 | fractVal = (int)BitReader.ReadUIntBits(source, ref readBitOffset, (byte)COORD_FRACTIONAL_BITS); 41 | } 42 | 43 | // Calculate the correct floating point value 44 | double retVal = Math.Abs(intVal + ((float)fractVal * COORD_RESOLUTION)); 45 | 46 | // Fixup the sign if negative. 47 | if (signBit != 0) 48 | retVal = -retVal; 49 | 50 | return retVal; 51 | } 52 | 53 | return 0; 54 | } 55 | 56 | public static double Read(BitStream source) 57 | { 58 | // Read the required integer and fraction flags 59 | bool intFlag = source.ReadBool(); 60 | bool fractFlag = source.ReadBool(); 61 | ulong intVal = 0; 62 | ulong fractVal = 0; 63 | 64 | // If we got either parse them, otherwise it's a zero. 65 | if (intFlag || fractFlag) 66 | { 67 | // Read the sign bit 68 | var signBit = source.ReadBool(); 69 | 70 | // If there's an integer, read it in 71 | if (intFlag) 72 | { 73 | // Adjust the integers from [0..MAX_COORD_VALUE-1] to [1..MAX_COORD_VALUE] 74 | intVal = source.ReadULong((byte)COORD_INTEGER_BITS) + 1; 75 | } 76 | 77 | // If there's a fraction, read it in 78 | if (fractFlag) 79 | { 80 | fractVal = source.ReadULong((byte)COORD_FRACTIONAL_BITS); 81 | } 82 | 83 | // Calculate the correct floating point value 84 | double retVal = Math.Abs(intVal + (fractVal * COORD_RESOLUTION)); 85 | 86 | // Fixup the sign if negative. 87 | if (signBit) 88 | retVal = -retVal; 89 | 90 | return retVal; 91 | } 92 | 93 | return 0; 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /TF2Net/NetMessages/Shared/EntityCoder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using BitSet; 8 | using TF2Net.Data; 9 | using TF2Net.Entities; 10 | 11 | namespace TF2Net.NetMessages 12 | { 13 | internal static class EntityCoder 14 | { 15 | public static void ApplyEntityUpdate(IEntity e, BitStream stream) 16 | { 17 | var testGuessProps = e.NetworkTable.FlattenedProps; 18 | 19 | bool atLeastOne = false; 20 | int index = -1; 21 | while ((index = ReadFieldIndex(stream, index)) != -1) 22 | { 23 | Debug.Assert(index < testGuessProps.Length); 24 | Debug.Assert(index < SourceConstants.MAX_DATATABLE_PROPS); 25 | 26 | var prop = testGuessProps[index]; 27 | 28 | SendProp s = e.GetProperty(prop); 29 | 30 | bool wasNull = false; 31 | if (s == null) 32 | { 33 | s = new SendProp(e, prop); 34 | wasNull = true; 35 | } 36 | 37 | object newValue = prop.Decode(stream); 38 | s.Value = newValue; 39 | atLeastOne = true; 40 | 41 | if (wasNull) 42 | e.AddProperty(s); 43 | } 44 | 45 | if (atLeastOne) 46 | e.PropertiesUpdated.Invoke(e); 47 | } 48 | 49 | public static int ReadFieldIndex(BitStream stream, int lastIndex) 50 | { 51 | if (!stream.ReadBool()) 52 | return -1; 53 | 54 | var diff = ReadUBitVar(stream); 55 | return (int)(lastIndex + diff + 1); 56 | } 57 | 58 | public static uint ReadUBitVar(BitStream stream) 59 | { 60 | switch (stream.ReadByte(2)) 61 | { 62 | case 0: return stream.ReadUInt(4); 63 | case 1: return stream.ReadUInt(8); 64 | case 2: return stream.ReadUInt(12); 65 | case 3: return stream.ReadUInt(32); 66 | } 67 | 68 | throw new Exception("Should never get here..."); 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /TF2Net/NetMessages/Shared/ExtMath.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace TF2Net.NetMessages 8 | { 9 | static class ExtMath 10 | { 11 | public static int Log2(int x) 12 | { 13 | int answer = 0; 14 | while ((x >>= 1) > 0) 15 | answer++; 16 | return answer; 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /TF2Net/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("TF2Net")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("TF2Net")] 13 | [assembly: AssemblyCopyright("Copyright © 2016")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("2c2af7cc-4368-4c03-b7e1-356d3bb89f4f")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /TF2Net/SingleEvent.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Concurrent; 3 | using System.Collections.Generic; 4 | using System.Diagnostics; 5 | using System.Linq; 6 | using System.Runtime.CompilerServices; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | 10 | namespace TF2Net 11 | { 12 | public class SingleEvent where T : class 13 | { 14 | readonly List m_Keys = new List(); 15 | readonly ConditionalWeakTable> m_Delegates = new ConditionalWeakTable>(); 16 | 17 | public SingleEvent() 18 | { 19 | if (!typeof(T).IsSubclassOf(typeof(Delegate))) 20 | throw new InvalidOperationException(typeof(T).Name + " is not a delegate type"); 21 | } 22 | 23 | public bool Add(T input) 24 | { 25 | CleanKeysList(); 26 | Delegate forceCast = (Delegate)(object)input; 27 | 28 | object target = forceCast.Target; 29 | Debug.Assert(target != null); 30 | 31 | List delegates = m_Delegates.GetValue(target, key => 32 | { 33 | lock (m_Keys) 34 | { 35 | if (!m_Keys.Contains(target)) 36 | m_Keys.Add(new WeakReference(target)); 37 | } 38 | 39 | return new List(); 40 | }); 41 | 42 | lock (delegates) 43 | { 44 | if (delegates.Contains(forceCast)) 45 | return false; 46 | 47 | delegates.Add(forceCast); 48 | } 49 | 50 | return true; 51 | } 52 | public bool Remove(T input) 53 | { 54 | Delegate forceCast = (Delegate)(object)input; 55 | 56 | object target = forceCast.Target; 57 | Debug.Assert(target != null); 58 | 59 | List values; 60 | m_Delegates.TryGetValue(target, out values); 61 | 62 | lock (values) 63 | return values.Remove(forceCast); 64 | } 65 | 66 | void CleanKeysList() 67 | { 68 | lock (m_Keys) 69 | { 70 | for (int i = 0; i < m_Keys.Count; i++) 71 | { 72 | if (!m_Keys[i].IsAlive) 73 | m_Keys.RemoveAt(i--); 74 | } 75 | } 76 | } 77 | 78 | public void Invoke(params object[] args) 79 | { 80 | if (m_Keys.Count > 0) 81 | { 82 | IEnumerable all = Enumerable.Empty(); 83 | 84 | lock (m_Keys) 85 | { 86 | IEnumerable validObjects = m_Keys.Select(k => k.Target).Where(t => t != null); 87 | foreach (object o in validObjects) 88 | { 89 | List delegates; 90 | if (m_Delegates.TryGetValue(o, out delegates)) 91 | all = all.Concat(delegates); 92 | } 93 | } 94 | 95 | foreach (Delegate d in all) 96 | { 97 | var test = d.Target; 98 | d.DynamicInvoke(args); 99 | } 100 | } 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /TF2Net/WorldEvents.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using TF2Net.Data; 6 | using TF2Net.Entities; 7 | 8 | namespace TF2Net 9 | { 10 | public class WorldEvents : IWorldEvents 11 | { 12 | public SingleEvent> EntityCreated { get; } = new SingleEvent>(); 13 | public SingleEvent> EntityDeleted { get; } = new SingleEvent>(); 14 | 15 | public SingleEvent> EntityEnteredPVS { get; } = new SingleEvent>(); 16 | public SingleEvent> EntityLeftPVS { get; } = new SingleEvent>(); 17 | 18 | public SingleEvent> GameEventsListLoaded { get; } = new SingleEvent>(); 19 | public SingleEvent> GameEvent { get; } = new SingleEvent>(); 20 | 21 | public SingleEvent> NewTick { get; } = new SingleEvent>(); 22 | 23 | public SingleEvent> PlayerAdded { get; } = new SingleEvent>(); 24 | public SingleEvent> PlayerRemoved { get; } = new SingleEvent>(); 25 | 26 | public SingleEvent> SendTablesLoaded { get; } = new SingleEvent>(); 27 | 28 | public SingleEvent> ServerClassesLoaded { get; } = new SingleEvent>(); 29 | 30 | public SingleEvent> ServerInfoLoaded { get; } = new SingleEvent>(); 31 | 32 | public SingleEvent>> ServerSetConVar { get; } = new SingleEvent>>(); 33 | 34 | public SingleEvent> ServerConCommand { get; } = new SingleEvent>(); 35 | public SingleEvent> ServerTextMessage { get; } = new SingleEvent>(); 36 | 37 | public SingleEvent> StringTableCreated { get; } = new SingleEvent>(); 38 | public SingleEvent> StringTableUpdated { get; } = new SingleEvent>(); 39 | 40 | public SingleEvent> ViewEntityUpdated { get; } = new SingleEvent>(); 41 | 42 | public SingleEvent> TempEntityCreated { get; } = new SingleEvent>(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /TF2Net/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | --------------------------------------------------------------------------------