Add project files.

This commit is contained in:
rei-kes 2024-05-24 19:33:46 -04:00
parent 99dd64a099
commit 6decf28aaa
427 changed files with 142331 additions and 0 deletions

31
Amalgam.sln Normal file
View File

@ -0,0 +1,31 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.8.34525.116
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Amalgam", "Amalgam\Amalgam.vcxproj", "{2550C133-72A8-4AF7-B22A-A8012BD9F376}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{2550C133-72A8-4AF7-B22A-A8012BD9F376}.Debug|x64.ActiveCfg = Debug|x64
{2550C133-72A8-4AF7-B22A-A8012BD9F376}.Debug|x64.Build.0 = Debug|x64
{2550C133-72A8-4AF7-B22A-A8012BD9F376}.Debug|x86.ActiveCfg = Debug|Win32
{2550C133-72A8-4AF7-B22A-A8012BD9F376}.Debug|x86.Build.0 = Debug|Win32
{2550C133-72A8-4AF7-B22A-A8012BD9F376}.Release|x64.ActiveCfg = Release|x64
{2550C133-72A8-4AF7-B22A-A8012BD9F376}.Release|x64.Build.0 = Release|x64
{2550C133-72A8-4AF7-B22A-A8012BD9F376}.Release|x86.ActiveCfg = Release|Win32
{2550C133-72A8-4AF7-B22A-A8012BD9F376}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {5E35C5DE-7694-4637-AC86-EF5BEB5B0763}
EndGlobalSection
EndGlobal

641
Amalgam/Amalgam.vcxproj Normal file
View File

@ -0,0 +1,641 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>17.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{2550c133-72a8-4af7-b22a-a8012bd9f376}</ProjectGuid>
<RootNamespace>Amalgam</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
<WholeProgramOptimization>true</WholeProgramOptimization>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
<WholeProgramOptimization>true</WholeProgramOptimization>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<TargetName>$(ProjectName)$(Platform)$(Configuration)</TargetName>
<IntDir>$(SolutionDir)build\$(Platform)\$(Configuration)\</IntDir>
<IncludePath>$(ProjectDir)include\;$(IncludePath)</IncludePath>
<OutDir>$(SolutionDir)output\$(Platform)\$(Configuration)\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<IncludePath>$(ProjectDir)include\;$(IncludePath)</IncludePath>
<IntDir>$(SolutionDir)build\$(Platform)\$(Configuration)\</IntDir>
<TargetName>$(ProjectName)$(Platform)$(Configuration)</TargetName>
<OutDir>$(SolutionDir)output\$(Platform)\$(Configuration)\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<OutDir>$(SolutionDir)output\$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)build\$(Platform)\$(Configuration)\</IntDir>
<TargetName>$(ProjectName)$(Platform)$(Configuration)</TargetName>
<IncludePath>$(ProjectDir)include\;$(IncludePath)</IncludePath>
<ExecutablePath>$(VC_ExecutablePath_x64);$(CommonExecutablePath)</ExecutablePath>
<ReferencePath>$(VC_ReferencesPath_x64);</ReferencePath>
<LibraryPath>$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64)</LibraryPath>
<ExcludePath>$(CommonExcludePath);$(VC_ExecutablePath_x64);$(VC_LibraryPath_x64)</ExcludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<OutDir>$(SolutionDir)output\$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)build\$(Platform)\$(Configuration)\</IntDir>
<TargetName>$(ProjectName)$(Platform)$(Configuration)</TargetName>
<IncludePath>$(ProjectDir)include\;$(IncludePath)</IncludePath>
<ExecutablePath>$(VC_ExecutablePath_x64);$(CommonExecutablePath)</ExecutablePath>
<ReferencePath>$(VC_ReferencesPath_x64);</ReferencePath>
<LibraryPath>$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64)</LibraryPath>
<ExcludePath>$(CommonExcludePath);$(VC_ExecutablePath_x64);$(VC_LibraryPath_x64)</ExcludePath>
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>false</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp20</LanguageStandard>
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<Optimization>MaxSpeed</Optimization>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<IntrinsicFunctions>true</IntrinsicFunctions>
<StringPooling>true</StringPooling>
<FunctionLevelLinking>true</FunctionLevelLinking>
<EnableEnhancedInstructionSet>AdvancedVectorExtensions2</EnableEnhancedInstructionSet>
<OmitFramePointers />
<WholeProgramOptimization>true</WholeProgramOptimization>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<SupportJustMyCode>true</SupportJustMyCode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>false</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp20</LanguageStandard>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<StringPooling>true</StringPooling>
<EnableEnhancedInstructionSet>AdvancedVectorExtensions2</EnableEnhancedInstructionSet>
<OmitFramePointers />
<BufferSecurityCheck>false</BufferSecurityCheck>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>false</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp20</LanguageStandard>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<OmitFramePointers>
</OmitFramePointers>
<IntrinsicFunctions>true</IntrinsicFunctions>
<Optimization>MaxSpeed</Optimization>
<StringPooling>true</StringPooling>
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
<FunctionLevelLinking>true</FunctionLevelLinking>
<EnableEnhancedInstructionSet>AdvancedVectorExtensions2</EnableEnhancedInstructionSet>
<WholeProgramOptimization>true</WholeProgramOptimization>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<SupportJustMyCode>true</SupportJustMyCode>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>false</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp20</LanguageStandard>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<OmitFramePointers>
</OmitFramePointers>
<StringPooling>true</StringPooling>
<EnableEnhancedInstructionSet>AdvancedVectorExtensions2</EnableEnhancedInstructionSet>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<BufferSecurityCheck>false</BufferSecurityCheck>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="include\ImGui\imgui.cpp" />
<ClCompile Include="include\ImGui\imgui_draw.cpp" />
<ClCompile Include="include\ImGui\imgui_impl_dx9.cpp" />
<ClCompile Include="include\ImGui\imgui_impl_win32.cpp" />
<ClCompile Include="include\ImGui\imgui_stdlib.cpp" />
<ClCompile Include="include\ImGui\imgui_tables.cpp" />
<ClCompile Include="include\ImGui\imgui_widgets.cpp" />
<ClCompile Include="include\ImGui\TextEditor.cpp" />
<ClCompile Include="include\MinHook\buffer.c" />
<ClCompile Include="include\MinHook\hde\hde32.c" />
<ClCompile Include="include\MinHook\hde\hde64.c" />
<ClCompile Include="include\MinHook\hook.c" />
<ClCompile Include="include\MinHook\trampoline.c" />
<ClCompile Include="src\Core\Core.cpp" />
<ClCompile Include="src\DllMain.cpp" />
<ClCompile Include="src\Features\Aimbot\Aimbot.cpp" />
<ClCompile Include="src\Features\Aimbot\AimbotGlobal\AimbotGlobal.cpp" />
<ClCompile Include="src\Features\Aimbot\AimbotHitscan\AimbotHitscan.cpp" />
<ClCompile Include="src\Features\Aimbot\AimbotMelee\AimbotMelee.cpp" />
<ClCompile Include="src\Features\Aimbot\AimbotProjectile\AimbotProjectile.cpp" />
<ClCompile Include="src\Features\Aimbot\AutoAirblast\AutoAirblast.cpp" />
<ClCompile Include="src\Features\Aimbot\AutoDetonate\AutoDetonate.cpp" />
<ClCompile Include="src\Features\Aimbot\AutoRocketJump\AutoRocketJump.cpp" />
<ClCompile Include="src\Features\Aimbot\AutoUber\AutoUber.cpp" />
<ClCompile Include="src\Features\AutoQueue\AutoQueue.cpp" />
<ClCompile Include="src\Features\Backtrack\Backtrack.cpp" />
<ClCompile Include="src\Features\CameraWindow\CameraWindow.cpp" />
<ClCompile Include="src\Features\CheaterDetection\CheaterDetection.cpp" />
<ClCompile Include="src\Features\Commands\Commands.cpp" />
<ClCompile Include="src\Features\Conditions\Conditions.cpp" />
<ClCompile Include="src\Features\Configs\Configs.cpp" />
<ClCompile Include="src\Features\CritHack\CritHack.cpp" />
<ClCompile Include="src\Features\EnginePrediction\EnginePrediction.cpp" />
<ClCompile Include="src\Features\ImGui\Render.cpp" />
<ClCompile Include="src\Features\ImGui\Menu\Menu.cpp" />
<ClCompile Include="src\Features\Logs\Logs.cpp" />
<ClCompile Include="src\Features\Misc\Misc.cpp" />
<ClCompile Include="src\Features\NetworkFix\NetworkFix.cpp" />
<ClCompile Include="src\Features\NoSpread\NoSpread.cpp" />
<ClCompile Include="src\Features\NoSpread\NoSpreadHitscan\NoSpreadHitscan.cpp" />
<ClCompile Include="src\Features\NoSpread\NoSpreadProjectile\NoSpreadProjectile.cpp" />
<ClCompile Include="src\Features\PacketManip\AntiAim\AntiAim.cpp" />
<ClCompile Include="src\Features\PacketManip\FakeLag\FakeLag.cpp" />
<ClCompile Include="src\Features\PacketManip\PacketManip.cpp" />
<ClCompile Include="src\Features\Players\PlayerCore.cpp" />
<ClCompile Include="src\Features\Players\PlayerUtils.cpp" />
<ClCompile Include="src\Features\Resolver\Resolver.cpp" />
<ClCompile Include="src\Features\Simulation\MovementSimulation\MovementSimulation.cpp" />
<ClCompile Include="src\Features\Simulation\ProjectileSimulation\ProjectileSimulation.cpp" />
<ClCompile Include="src\Features\TickHandler\TickHandler.cpp" />
<ClCompile Include="src\Features\Visuals\Chams\Chams.cpp" />
<ClCompile Include="src\Features\Visuals\ESP\ESP.cpp" />
<ClCompile Include="src\Features\Visuals\FakeAngle\FakeAngle.cpp" />
<ClCompile Include="src\Features\Visuals\Glow\Glow.cpp" />
<ClCompile Include="src\Features\Visuals\LocalConditions\LocalConditions.cpp" />
<ClCompile Include="src\Features\Visuals\Materials\Materials.cpp" />
<ClCompile Include="src\Features\Visuals\Notifications\Notifications.cpp" />
<ClCompile Include="src\Features\Visuals\PlayerArrows\PlayerArrows.cpp" />
<ClCompile Include="src\Features\Visuals\Radar\Radar.cpp" />
<ClCompile Include="src\Features\Visuals\SpectatorList\SpectatorList.cpp" />
<ClCompile Include="src\Features\Visuals\Visuals.cpp" />
<ClCompile Include="src\Hooks\BaseClientDLL_DispatchUserMessage.cpp" />
<ClCompile Include="src\Hooks\BaseClientDLL_FrameStageNotify.cpp" />
<ClCompile Include="src\Hooks\BaseClientDLL_Shutdown.cpp" />
<ClCompile Include="src\Hooks\CAchievementMgr_CheckAchievementsEnabled.cpp" />
<ClCompile Include="src\Hooks\CBaseAnimating_FrameAdvance.cpp" />
<ClCompile Include="src\Hooks\CBaseAnimating_Interpolate.cpp" />
<ClCompile Include="src\Hooks\CBaseAnimating_MaintainSequenceTransitions.cpp" />
<ClCompile Include="src\Hooks\CBaseAnimating_SetupBones.cpp" />
<ClCompile Include="src\Hooks\CBaseAnimating_UpdateClientSideAnimations.cpp" />
<ClCompile Include="src\Hooks\CBaseEntity_FireBullets.cpp" />
<ClCompile Include="src\Hooks\CBaseEntity_Interpolate.cpp" />
<ClCompile Include="src\Hooks\CBaseEntity_InterpolateServerEntities.cpp" />
<ClCompile Include="src\Hooks\CBaseEntity_ResetLatched.cpp" />
<ClCompile Include="src\Hooks\CBaseEntity_SetAbsVelocity.cpp" />
<ClCompile Include="src\Hooks\CBaseHudChat_ChatPrintf.cpp" />
<ClCompile Include="src\Hooks\CBasePlayer_CalcViewModelView.cpp" />
<ClCompile Include="src\Hooks\CEconItemSchema_GetItemDefinition.cpp" />
<ClCompile Include="src\Hooks\CGameEventManager_FireEventIntern.cpp" />
<ClCompile Include="src\Hooks\CHudCrosshair_GetDrawPosition.cpp" />
<ClCompile Include="src\Hooks\CInterpolatedVarArrayBase_Interpolate.cpp" />
<ClCompile Include="src\Hooks\CInventoryManager_ShowItemsPickedUp.cpp" />
<ClCompile Include="src\Hooks\ClientModeShared_CreateMove.cpp" />
<ClCompile Include="src\Hooks\ClientModeShared_DoPostScreenSpaceEffects.cpp" />
<ClCompile Include="src\Hooks\ClientModeShared_OverrideView.cpp" />
<ClCompile Include="src\Hooks\ClientModeShared_ShouldDrawViewModel.cpp" />
<ClCompile Include="src\Hooks\ClientModeTFNormal_UpdateSteamRichPresence.cpp" />
<ClCompile Include="src\Hooks\ClientState_GetClientInterpAmount.cpp" />
<ClCompile Include="src\Hooks\ClientState_ProcessFixAngle.cpp" />
<ClCompile Include="src\Hooks\CL_CheckForPureServerWhitelist.cpp" />
<ClCompile Include="src\Hooks\CL_Move.cpp" />
<ClCompile Include="src\Hooks\CL_ReadPackets.cpp" />
<ClCompile Include="src\Hooks\CMatchInviteNotification_OnTick.cpp" />
<ClCompile Include="src\Hooks\CMaterial_Uncache.cpp" />
<ClCompile Include="src\Hooks\CNetChan_SendNetMsg.cpp" />
<ClCompile Include="src\Hooks\COPRenderSprites_RenderSpriteCard.cpp" />
<ClCompile Include="src\Hooks\CPlayerResource_GetTeamColor.cpp" />
<ClCompile Include="src\Hooks\CPrediction_RunCommand.cpp" />
<ClCompile Include="src\Hooks\CRendering3dView_EnableWorldFog.cpp" />
<ClCompile Include="src\Hooks\CSequenceTransitioner_CheckForSequenceChange.cpp" />
<ClCompile Include="src\Hooks\CSkyboxView_Enable3dSkyboxFog.cpp" />
<ClCompile Include="src\Hooks\CSoundEmitterSystem_EmitSound.cpp" />
<ClCompile Include="src\Hooks\CStaticPropMgr_ComputePropOpacity.cpp" />
<ClCompile Include="src\Hooks\CStaticPropMgr_DrawStaticProps.cpp" />
<ClCompile Include="src\Hooks\CStudioRender_DrawModelStaticProp.cpp" />
<ClCompile Include="src\Hooks\CTFPartyClient_BCanRequestToJoinPlayer.cpp" />
<ClCompile Include="src\Hooks\CTFPlayerInventory_GetMaxItemCount.cpp" />
<ClCompile Include="src\Hooks\CTFPlayerPanel_GetTeam.cpp" />
<ClCompile Include="src\Hooks\CTFPlayerShared_InCond.cpp" />
<ClCompile Include="src\Hooks\CTFPlayerShared_IsPlayerDominated.cpp" />
<ClCompile Include="src\Hooks\CTFPlayer_AvoidPlayers.cpp" />
<ClCompile Include="src\Hooks\CTFPlayer_BRenderAsZombie.cpp" />
<ClCompile Include="src\Hooks\CTFPlayer_IsPlayerClass.cpp" />
<ClCompile Include="src\Hooks\CTFRagdoll_CreateTFRagdoll.cpp" />
<ClCompile Include="src\Hooks\CTFWeaponBase_CalcIsAttackCritical.cpp" />
<ClCompile Include="src\Hooks\CTFWeaponBase_GetShootSound.cpp" />
<ClCompile Include="src\Hooks\CViewRender_DrawUnderwaterOverlay.cpp" />
<ClCompile Include="src\Hooks\Direct3DDevice9_EndScene.cpp" />
<ClCompile Include="src\Hooks\DoEnginePostProcessing.cpp" />
<ClCompile Include="src\Hooks\DSP_Process.cpp" />
<ClCompile Include="src\Hooks\EngineClient_ClientCmd_Unrestricted.cpp" />
<ClCompile Include="src\Hooks\EngineVGui_Paint.cpp" />
<ClCompile Include="src\Hooks\ISteamNetworkingUtils_GetDirectPingToPOP.cpp" />
<ClCompile Include="src\Hooks\FX_FireBullets.cpp" />
<ClCompile Include="src\Hooks\GetClientInterpAmount.cpp" />
<ClCompile Include="src\Hooks\Input_GetUserCmd.cpp" />
<ClCompile Include="src\Hooks\KeyValues_SetInt.cpp" />
<ClCompile Include="src\Hooks\ModelRender_DrawModelExecute.cpp" />
<ClCompile Include="src\Hooks\NetChannel_SendDatagram.cpp" />
<ClCompile Include="src\Hooks\NotificationQueue_Add.cpp" />
<ClCompile Include="src\Hooks\StudioRender_SetAlphaModulation.cpp" />
<ClCompile Include="src\Hooks\StudioRender_SetColorModulation.cpp" />
<ClCompile Include="src\Hooks\S_StartDynamicSound.cpp" />
<ClCompile Include="src\Hooks\VGuiMenuBuilder_AddMenuItem.cpp" />
<ClCompile Include="src\Hooks\ViewRender_LevelInit.cpp" />
<ClCompile Include="src\Hooks\ViewRender_LevelShutdown.cpp" />
<ClCompile Include="src\Hooks\ViewRender_RenderView.cpp" />
<ClCompile Include="src\SDK\Definitions\Main\CTFWeaponBase.cpp" />
<ClCompile Include="src\SDK\Definitions\Main\INetMessage.cpp" />
<ClCompile Include="src\SDK\Definitions\Main\KeyValues.cpp" />
<ClCompile Include="src\SDK\Definitions\Main\MD5.cpp" />
<ClCompile Include="src\SDK\Definitions\Misc\bitbuf.cpp" />
<ClCompile Include="src\SDK\Definitions\Misc\ChecksumCRC.cpp" />
<ClCompile Include="src\SDK\Definitions\NullInterfaces.cpp" />
<ClCompile Include="src\SDK\Helpers\Color\Color.cpp" />
<ClCompile Include="src\SDK\Helpers\Draw\Draw.cpp" />
<ClCompile Include="src\SDK\Helpers\Entities\Entities.cpp" />
<ClCompile Include="src\SDK\Helpers\Fonts\Fonts.cpp" />
<ClCompile Include="src\SDK\Helpers\TraceFilters\TraceFilters.cpp" />
<ClCompile Include="src\SDK\SDK.cpp" />
<ClCompile Include="src\Utils\ConVars\ConVars.cpp" />
<ClCompile Include="src\Utils\Hooks\Hooks.cpp" />
<ClCompile Include="src\Utils\Interfaces\Interfaces.cpp" />
<ClCompile Include="src\Utils\KeyHandler\KeyHandler.cpp" />
<ClCompile Include="src\Utils\Memory\Memory.cpp" />
<ClCompile Include="src\Utils\Minidump\Minidump.cpp" />
<ClCompile Include="src\Utils\NetVars\NetVars.cpp" />
<ClCompile Include="src\Utils\Signatures\Signatures.cpp" />
<ClCompile Include="src\Utils\Timer\Timer.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="include\ImGui\imconfig.h" />
<ClInclude Include="include\ImGui\imgui.h" />
<ClInclude Include="include\ImGui\imgui_impl_dx9.h" />
<ClInclude Include="include\ImGui\imgui_impl_win32.h" />
<ClInclude Include="include\ImGui\imgui_internal.h" />
<ClInclude Include="include\ImGui\imgui_stdlib.h" />
<ClInclude Include="include\ImGui\imstb_rectpack.h" />
<ClInclude Include="include\ImGui\imstb_textedit.h" />
<ClInclude Include="include\ImGui\imstb_truetype.h" />
<ClInclude Include="include\ImGui\TextEditor.h" />
<ClInclude Include="include\MinHook\buffer.h" />
<ClInclude Include="include\MinHook\hde\hde32.h" />
<ClInclude Include="include\MinHook\hde\hde64.h" />
<ClInclude Include="include\MinHook\hde\pstdint.h" />
<ClInclude Include="include\MinHook\hde\table32.h" />
<ClInclude Include="include\MinHook\hde\table64.h" />
<ClInclude Include="include\MinHook\MinHook.h" />
<ClInclude Include="include\MinHook\trampoline.h" />
<ClInclude Include="src\Features\Aimbot\Aimbot.h" />
<ClInclude Include="src\Features\Aimbot\AimbotGlobal\AimbotGlobal.h" />
<ClInclude Include="src\Features\Aimbot\AimbotHitscan\AimbotHitscan.h" />
<ClInclude Include="src\Features\Aimbot\AimbotMelee\AimbotMelee.h" />
<ClInclude Include="src\Features\Aimbot\AimbotProjectile\AimbotProjectile.h" />
<ClInclude Include="src\Features\Aimbot\AutoAirblast\AutoAirblast.h" />
<ClInclude Include="src\Features\Aimbot\AutoDetonate\AutoDetonate.h" />
<ClInclude Include="src\Features\Aimbot\AutoRocketJump\AutoRocketJump.h" />
<ClInclude Include="src\Features\Aimbot\AutoUber\AutoUber.h" />
<ClInclude Include="src\Features\AutoQueue\AutoQueue.h" />
<ClInclude Include="src\Features\Backtrack\Backtrack.h" />
<ClInclude Include="src\Features\CheaterDetection\CheaterDetection.h" />
<ClInclude Include="src\Features\CritHack\CritHack.h" />
<ClInclude Include="src\Features\EnginePrediction\EnginePrediction.h" />
<ClInclude Include="src\Features\Misc\Misc.h" />
<ClInclude Include="src\Features\NetworkFix\NetworkFix.h" />
<ClInclude Include="src\Features\NoSpread\NoSpread.h" />
<ClInclude Include="src\Features\NoSpread\NoSpreadHitscan\NoSpreadHitscan.h" />
<ClInclude Include="src\Features\NoSpread\NoSpreadProjectile\NoSpreadProjectile.h" />
<ClInclude Include="src\Features\PacketManip\AntiAim\AntiAim.h" />
<ClInclude Include="src\Features\PacketManip\FakeLag\FakeLag.h" />
<ClInclude Include="src\Features\PacketManip\PacketManip.h" />
<ClInclude Include="src\Features\Resolver\Resolver.h" />
<ClInclude Include="src\Features\Simulation\MovementSimulation\MovementSimulation.h" />
<ClInclude Include="src\Features\Simulation\ProjectileSimulation\ProjectileSimulation.h" />
<ClInclude Include="src\Features\TickHandler\TickHandler.h" />
<ClInclude Include="src\Features\Visuals\Chams\Chams.h" />
<ClInclude Include="src\Features\Visuals\ESP\ESP.h" />
<ClInclude Include="src\Features\Visuals\FakeAngle\FakeAngle.h" />
<ClInclude Include="src\Features\Visuals\Glow\Glow.h" />
<ClInclude Include="src\Features\Visuals\LocalConditions\LocalConditions.h" />
<ClInclude Include="src\Features\Visuals\PlayerArrows\PlayerArrows.h" />
<ClInclude Include="src\Features\Visuals\Radar\Radar.h" />
<ClInclude Include="src\Features\Visuals\SpectatorList\SpectatorList.h" />
<ClInclude Include="src\Features\Visuals\Visuals.h" />
<ClInclude Include="src\Hooks\Direct3DDevice9_EndScene.h" />
<ClInclude Include="src\SDK\Definitions\Interfaces\CTFGameRules.h" />
<ClInclude Include="src\SDK\Definitions\Interfaces\IGameMovement.h" />
<ClInclude Include="src\SDK\Definitions\Interfaces\IInput.h" />
<ClInclude Include="src\SDK\Definitions\Interfaces\IStudioRender.h" />
<ClInclude Include="src\SDK\Definitions\Interfaces\IUniformRandomStream.h" />
<ClInclude Include="src\SDK\Definitions\Interfaces\IVModelRender.h" />
<ClInclude Include="src\SDK\Definitions\Interfaces\Prediction.h" />
<ClInclude Include="src\SDK\Definitions\Interfaces\VGuiPanel.h" />
<ClInclude Include="src\SDK\Definitions\Interfaces\ViewRenderBeams.h" />
<ClInclude Include="src\SDK\Definitions\Main\CBaseObject.h" />
<ClInclude Include="src\SDK\Definitions\Main\CBaseTrace.h" />
<ClInclude Include="src\SDK\Definitions\Main\CCollisionProperty.h" />
<ClInclude Include="src\SDK\Definitions\Main\CEntitySphereQuery.h" />
<ClInclude Include="src\SDK\Definitions\Main\CGameTrace.h" />
<ClInclude Include="src\SDK\Definitions\Main\CModel.h" />
<ClInclude Include="src\SDK\Definitions\Interfaces\IEngineTrace.h" />
<ClInclude Include="src\SDK\Definitions\Main\IAchievementMgr.h" />
<ClInclude Include="src\SDK\Definitions\Main\MD5.h" />
<ClInclude Include="src\SDK\Definitions\Misc\BSPFlags.h" />
<ClInclude Include="src\SDK\Definitions\Interfaces\IMoveHelper.h" />
<ClInclude Include="src\SDK\Definitions\Misc\IMDLCache.h" />
<ClInclude Include="src\SDK\Definitions\Misc\IPrediction.h" />
<ClInclude Include="src\SDK\Definitions\Misc\ISpatialPartition.h" />
<ClInclude Include="src\SDK\Definitions\Misc\VCollide.h" />
<ClInclude Include="src\SDK\Definitions\Steam\ISteamAppList.h" />
<ClInclude Include="src\SDK\Definitions\Steam\ISteamApps.h" />
<ClInclude Include="src\SDK\Definitions\Steam\ISteamClient.h" />
<ClInclude Include="src\SDK\Definitions\Steam\ISteamController.h" />
<ClInclude Include="src\SDK\Definitions\Steam\ISteamFriends.h" />
<ClInclude Include="src\SDK\Definitions\Steam\ISteamGameServer.h" />
<ClInclude Include="src\SDK\Definitions\Steam\ISteamGameServerStats.h" />
<ClInclude Include="src\SDK\Definitions\Steam\ISteamHTMLSurface.h" />
<ClInclude Include="src\SDK\Definitions\Steam\ISteamHTTP.h" />
<ClInclude Include="src\SDK\Definitions\Steam\ISteamInput.h" />
<ClInclude Include="src\SDK\Definitions\Steam\ISteamInventory.h" />
<ClInclude Include="src\SDK\Definitions\Steam\ISteamMatchmaking.h" />
<ClInclude Include="src\SDK\Definitions\Steam\ISteamMusic.h" />
<ClInclude Include="src\SDK\Definitions\Steam\ISteamMusicRemote.h" />
<ClInclude Include="src\SDK\Definitions\Steam\ISteamNetworking.h" />
<ClInclude Include="src\SDK\Definitions\Steam\ISteamNetworkingMessages.h" />
<ClInclude Include="src\SDK\Definitions\Steam\ISteamNetworkingSockets.h" />
<ClInclude Include="src\SDK\Definitions\Steam\ISteamNetworkingUtils.h" />
<ClInclude Include="src\SDK\Definitions\Steam\ISteamParentalSettings.h" />
<ClInclude Include="src\SDK\Definitions\Steam\ISteamRemotePlay.h" />
<ClInclude Include="src\SDK\Definitions\Steam\ISteamRemoteStorage.h" />
<ClInclude Include="src\SDK\Definitions\Steam\ISteamScreenshots.h" />
<ClInclude Include="src\SDK\Definitions\Steam\ISteamUGC.h" />
<ClInclude Include="src\SDK\Definitions\Steam\ISteamUser.h" />
<ClInclude Include="src\SDK\Definitions\Steam\ISteamUserStats.h" />
<ClInclude Include="src\SDK\Definitions\Steam\ISteamUtils.h" />
<ClInclude Include="src\SDK\Definitions\Steam\ISteamVideo.h" />
<ClInclude Include="src\SDK\Definitions\Steam\MatchmakingTypes.h" />
<ClInclude Include="src\SDK\Definitions\Steam\SteamClientPublic.h" />
<ClInclude Include="src\SDK\Definitions\Steam\SteamHTTPEnums.h" />
<ClInclude Include="src\SDK\Definitions\Steam\SteamNetworkingTypes.h" />
<ClInclude Include="src\SDK\Definitions\Steam\SteamTypes.h" />
<ClInclude Include="src\SDK\Definitions\Steam\SteamUniverse.h" />
<ClInclude Include="src\SDK\Definitions\Steam\Steam_API.h" />
<ClInclude Include="src\SDK\Definitions\Steam\Steam_API_Common.h" />
<ClInclude Include="src\SDK\Definitions\Steam\Steam_API_Internal.h" />
<ClInclude Include="src\SDK\Definitions\Steam\Steam_Gameserver.h" />
<ClInclude Include="src\Core\Core.h" />
<ClInclude Include="src\Features\CameraWindow\CameraWindow.h" />
<ClInclude Include="src\Features\Commands\Commands.h" />
<ClInclude Include="src\Features\Conditions\Conditions.h" />
<ClInclude Include="src\Features\Configs\Configs.h" />
<ClInclude Include="src\Features\ImGui\Render.h" />
<ClInclude Include="src\Features\ImGui\MaterialDesign\IconDefinitions.h" />
<ClInclude Include="src\Features\ImGui\MaterialDesign\MaterialIcons.h" />
<ClInclude Include="src\Features\ImGui\Menu\Components.h" />
<ClInclude Include="src\Features\ImGui\Menu\Menu.h" />
<ClInclude Include="src\Features\Logs\Logs.h" />
<ClInclude Include="src\Features\Players\PlayerCore.h" />
<ClInclude Include="src\Features\Players\PlayerUtils.h" />
<ClInclude Include="src\Features\Visuals\Materials\Materials.h" />
<ClInclude Include="src\Features\Visuals\Notifications\Notifications.h" />
<ClInclude Include="src\SDK\Definitions\Classes.h" />
<ClInclude Include="src\SDK\Definitions\Definitions.h" />
<ClInclude Include="src\SDK\Definitions\Interfaces.h" />
<ClInclude Include="src\SDK\Definitions\Interfaces\CClientModeShared.h" />
<ClInclude Include="src\SDK\Definitions\Interfaces\CClientState.h" />
<ClInclude Include="src\SDK\Definitions\Interfaces\CGlobalVarsBase.h" />
<ClInclude Include="src\SDK\Definitions\Interfaces\CTFPartyClient.h" />
<ClInclude Include="src\SDK\Definitions\Interfaces\IClientEntityList.h" />
<ClInclude Include="src\SDK\Definitions\Interfaces\ICVar.h" />
<ClInclude Include="src\SDK\Definitions\Interfaces\IEngineVGui.h" />
<ClInclude Include="src\SDK\Definitions\Interfaces\IGameEvents.h" />
<ClInclude Include="src\SDK\Definitions\Interfaces\IInputSystem.h" />
<ClInclude Include="src\SDK\Definitions\Interfaces\IMaterialSystem.h" />
<ClInclude Include="src\SDK\Definitions\Interfaces\IMatSystemSurface.h" />
<ClInclude Include="src\SDK\Definitions\Interfaces\Interface.h" />
<ClInclude Include="src\SDK\Definitions\Interfaces\IVEngineClient.h" />
<ClInclude Include="src\SDK\Definitions\Interfaces\IViewRender.h" />
<ClInclude Include="src\SDK\Definitions\Interfaces\IVModelInfo.h" />
<ClInclude Include="src\SDK\Definitions\Interfaces\IVRenderView.h" />
<ClInclude Include="src\SDK\Definitions\Interfaces\SteamInterfaces.h" />
<ClInclude Include="src\SDK\Definitions\Interfaces\VPhysics.h" />
<ClInclude Include="src\SDK\Definitions\Main\CBaseAnimating.h" />
<ClInclude Include="src\SDK\Definitions\Main\CBaseCombatCharacter.h" />
<ClInclude Include="src\SDK\Definitions\Main\CBaseCombatWeapon.h" />
<ClInclude Include="src\SDK\Definitions\Main\CBaseEntity.h" />
<ClInclude Include="src\SDK\Definitions\Main\CBaseFlex.h" />
<ClInclude Include="src\SDK\Definitions\Main\CBaseHandle.h" />
<ClInclude Include="src\SDK\Definitions\Main\CBasePlayer.h" />
<ClInclude Include="src\SDK\Definitions\Main\CBaseProjectile.h" />
<ClInclude Include="src\SDK\Definitions\Main\CEconDefinition.h" />
<ClInclude Include="src\SDK\Definitions\Main\CHalloweenPickup.h" />
<ClInclude Include="src\SDK\Definitions\Main\CMultiPlayerAnimState.h" />
<ClInclude Include="src\SDK\Definitions\Main\CTFPlayer.h" />
<ClInclude Include="src\SDK\Definitions\Main\CTFPlayerResource.h" />
<ClInclude Include="src\SDK\Definitions\Main\CTFWeaponBase.h" />
<ClInclude Include="src\SDK\Definitions\Main\CUserCmd.h" />
<ClInclude Include="src\SDK\Definitions\Main\IClientEntity.h" />
<ClInclude Include="src\SDK\Definitions\Main\IClientNetworkable.h" />
<ClInclude Include="src\SDK\Definitions\Main\IClientRenderable.h" />
<ClInclude Include="src\SDK\Definitions\Main\IClientThinkable.h" />
<ClInclude Include="src\SDK\Definitions\Main\IClientUnknown.h" />
<ClInclude Include="src\SDK\Definitions\Main\IHandleEntity.h" />
<ClInclude Include="src\SDK\Definitions\Main\IMaterial.h" />
<ClInclude Include="src\SDK\Definitions\Main\IMaterialVar.h" />
<ClInclude Include="src\SDK\Definitions\Main\INetChannel.h" />
<ClInclude Include="src\SDK\Definitions\Main\INetChannelInfo.h" />
<ClInclude Include="src\SDK\Definitions\Main\INetMessage.h" />
<ClInclude Include="src\SDK\Definitions\Main\INetworkMessage.h" />
<ClInclude Include="src\SDK\Definitions\Main\INetworkSystem.h" />
<ClInclude Include="src\SDK\Definitions\Main\ITexture.h" />
<ClInclude Include="src\SDK\Definitions\Main\KeyValues.h" />
<ClInclude Include="src\SDK\Definitions\Main\NetChannel.h" />
<ClInclude Include="src\SDK\Definitions\Main\UtlVector.h" />
<ClInclude Include="src\SDK\Definitions\Misc\Activity.h" />
<ClInclude Include="src\SDK\Definitions\Misc\AnalogCode.h" />
<ClInclude Include="src\SDK\Definitions\Misc\BaseTypes.h" />
<ClInclude Include="src\SDK\Definitions\Misc\bitbuf.h" />
<ClInclude Include="src\SDK\Definitions\Misc\ButtonCode.h" />
<ClInclude Include="src\SDK\Definitions\Misc\CGameEventListener.h" />
<ClInclude Include="src\SDK\Definitions\Misc\ChecksumCRC.h" />
<ClInclude Include="src\SDK\Definitions\Misc\ClientClass.h" />
<ClInclude Include="src\SDK\Definitions\Misc\CommonMacros.h" />
<ClInclude Include="src\SDK\Definitions\Misc\ConVar.h" />
<ClInclude Include="src\SDK\Definitions\Misc\CPlayerResource.h" />
<ClInclude Include="src\SDK\Definitions\Misc\Cursor.h" />
<ClInclude Include="src\SDK\Definitions\Misc\CViewSetup.h" />
<ClInclude Include="src\SDK\Definitions\Misc\Datamap.h" />
<ClInclude Include="src\SDK\Definitions\Misc\Deformations.h" />
<ClInclude Include="src\SDK\Definitions\Misc\dt_common.h" />
<ClInclude Include="src\SDK\Definitions\Misc\dt_recv.h" />
<ClInclude Include="src\SDK\Definitions\Misc\IAppSystem.h" />
<ClInclude Include="src\SDK\Definitions\Misc\IClientMode.h" />
<ClInclude Include="src\SDK\Definitions\Misc\IColorCorrectionSystem.h" />
<ClInclude Include="src\SDK\Definitions\Misc\IConVar.h" />
<ClInclude Include="src\SDK\Definitions\Misc\IGameResources.h" />
<ClInclude Include="src\SDK\Definitions\Misc\IHTML.h" />
<ClInclude Include="src\SDK\Definitions\Misc\IImage.h" />
<ClInclude Include="src\SDK\Definitions\Misc\ImageFormat.h" />
<ClInclude Include="src\SDK\Definitions\Misc\IMaterialSystemHardwareConfig.h" />
<ClInclude Include="src\SDK\Definitions\Misc\InputEnums.h" />
<ClInclude Include="src\SDK\Definitions\Misc\IRefCounted.h" />
<ClInclude Include="src\SDK\Definitions\Misc\ISurface.h" />
<ClInclude Include="src\SDK\Definitions\Misc\IVguiMatInfo.h" />
<ClInclude Include="src\SDK\Definitions\Misc\IVguiMatInfoVar.h" />
<ClInclude Include="src\SDK\Definitions\Misc\KeyCode.h" />
<ClInclude Include="src\SDK\Definitions\Misc\LightDesc.h" />
<ClInclude Include="src\SDK\Definitions\Misc\LocalFlexController.h" />
<ClInclude Include="src\SDK\Definitions\Misc\Modes.h" />
<ClInclude Include="src\SDK\Definitions\Misc\MouseCode.h" />
<ClInclude Include="src\SDK\Definitions\Misc\NetAdr.h" />
<ClInclude Include="src\SDK\Definitions\Misc\SharedDefs.h" />
<ClInclude Include="src\SDK\Definitions\Misc\String.h" />
<ClInclude Include="src\SDK\Definitions\Misc\Studio.h" />
<ClInclude Include="src\SDK\Definitions\Misc\TextureGroupNames.h" />
<ClInclude Include="src\SDK\Definitions\Misc\TFSharedDefs.h" />
<ClInclude Include="src\SDK\Definitions\Misc\Const.h" />
<ClInclude Include="src\SDK\Definitions\Misc\VGUI.h" />
<ClInclude Include="src\SDK\Definitions\Misc\VPlane.h" />
<ClInclude Include="src\SDK\Definitions\Misc\VTF.h" />
<ClInclude Include="src\SDK\Definitions\Types.h" />
<ClInclude Include="src\SDK\Globals.h" />
<ClInclude Include="src\SDK\Helpers\Color\Color.h" />
<ClInclude Include="src\SDK\Helpers\Draw\Draw.h" />
<ClInclude Include="src\SDK\Helpers\Draw\Icons.h" />
<ClInclude Include="src\SDK\Helpers\Entities\Entities.h" />
<ClInclude Include="src\SDK\Helpers\Fonts\Fonts.h" />
<ClInclude Include="src\SDK\Helpers\Particles\Particles.h" />
<ClInclude Include="src\SDK\Helpers\TraceFilters\TraceFilters.h" />
<ClInclude Include="src\SDK\SDK.h" />
<ClInclude Include="src\SDK\Vars.h" />
<ClInclude Include="src\Utils\Assert\Assert.h" />
<ClInclude Include="src\Utils\ConVars\ConVars.h" />
<ClInclude Include="src\Utils\Feature\Feature.h" />
<ClInclude Include="src\Utils\Hash\FNV1A.h" />
<ClInclude Include="src\Utils\Hooks\Hooks.h" />
<ClInclude Include="src\Utils\Interfaces\Interfaces.h" />
<ClInclude Include="src\Utils\KeyHandler\KeyHandler.h" />
<ClInclude Include="src\Utils\Math\Math.h" />
<ClInclude Include="src\Utils\Memory\Memory.h" />
<ClInclude Include="src\Utils\Minidump\Minidump.h" />
<ClInclude Include="src\Utils\NetVars\NetVars.h" />
<ClInclude Include="src\Utils\Signatures\Signatures.h" />
<ClInclude Include="src\Utils\Timer\Timer.h" />
<ClInclude Include="src\Utils\UtlVector\UtlVector.h" />
</ItemGroup>
<ItemGroup>
<None Include="cpp.hint" />
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="..\packages\boost.1.84.0\build\boost.targets" Condition="Exists('..\packages\boost.1.84.0\build\boost.targets')" />
</ImportGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\boost.1.84.0\build\boost.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\boost.1.84.0\build\boost.targets'))" />
</Target>
</Project>

View File

@ -0,0 +1,424 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClCompile Include="src\Core\Core.cpp" />
<ClCompile Include="src\Features\CameraWindow\CameraWindow.cpp" />
<ClCompile Include="src\Features\Conditions\Conditions.cpp" />
<ClCompile Include="src\Features\Configs\Configs.cpp" />
<ClCompile Include="src\Features\ImGui\Menu\Menu.cpp" />
<ClCompile Include="src\Features\Logs\Logs.cpp" />
<ClCompile Include="src\Features\Players\PlayerCore.cpp" />
<ClCompile Include="src\Features\Players\PlayerUtils.cpp" />
<ClCompile Include="src\Features\Visuals\Materials\Materials.cpp" />
<ClCompile Include="src\Features\Visuals\Notifications\Notifications.cpp" />
<ClCompile Include="src\SDK\Definitions\Main\INetMessage.cpp" />
<ClCompile Include="src\SDK\Definitions\Main\KeyValues.cpp" />
<ClCompile Include="src\SDK\Definitions\Misc\bitbuf.cpp" />
<ClCompile Include="src\SDK\Definitions\NullInterfaces.cpp" />
<ClCompile Include="src\SDK\Helpers\Draw\Draw.cpp" />
<ClCompile Include="src\SDK\Helpers\Entities\Entities.cpp" />
<ClCompile Include="src\SDK\Helpers\Fonts\Fonts.cpp" />
<ClCompile Include="src\Utils\Hooks\Hooks.cpp" />
<ClCompile Include="src\Utils\Interfaces\Interfaces.cpp" />
<ClCompile Include="src\Utils\KeyHandler\KeyHandler.cpp" />
<ClCompile Include="src\Utils\Memory\Memory.cpp" />
<ClCompile Include="src\Utils\Minidump\Minidump.cpp" />
<ClCompile Include="src\Utils\NetVars\NetVars.cpp" />
<ClCompile Include="src\Utils\Signatures\Signatures.cpp" />
<ClCompile Include="src\Utils\Timer\Timer.cpp" />
<ClCompile Include="src\DllMain.cpp" />
<ClCompile Include="include\ImGui\imgui.cpp" />
<ClCompile Include="include\ImGui\imgui_draw.cpp" />
<ClCompile Include="include\ImGui\imgui_impl_dx9.cpp" />
<ClCompile Include="include\ImGui\imgui_impl_win32.cpp" />
<ClCompile Include="include\ImGui\imgui_stdlib.cpp" />
<ClCompile Include="include\ImGui\imgui_tables.cpp" />
<ClCompile Include="include\ImGui\imgui_widgets.cpp" />
<ClCompile Include="include\ImGui\TextEditor.cpp" />
<ClCompile Include="include\MinHook\hde\hde32.c" />
<ClCompile Include="include\MinHook\hde\hde64.c" />
<ClCompile Include="include\MinHook\buffer.c" />
<ClCompile Include="include\MinHook\hook.c" />
<ClCompile Include="include\MinHook\trampoline.c" />
<ClCompile Include="src\SDK\SDK.cpp" />
<ClCompile Include="src\Utils\ConVars\ConVars.cpp" />
<ClCompile Include="src\Features\Commands\Commands.cpp" />
<ClCompile Include="src\Features\ImGui\Render.cpp" />
<ClCompile Include="src\Features\Aimbot\Aimbot.cpp" />
<ClCompile Include="src\Features\Aimbot\AimbotGlobal\AimbotGlobal.cpp" />
<ClCompile Include="src\Features\Aimbot\AimbotHitscan\AimbotHitscan.cpp" />
<ClCompile Include="src\Features\Aimbot\AimbotMelee\AimbotMelee.cpp" />
<ClCompile Include="src\Features\Aimbot\AimbotProjectile\AimbotProjectile.cpp" />
<ClCompile Include="src\Features\Aimbot\AutoAirblast\AutoAirblast.cpp" />
<ClCompile Include="src\Features\Aimbot\AutoDetonate\AutoDetonate.cpp" />
<ClCompile Include="src\Features\Aimbot\AutoRocketJump\AutoRocketJump.cpp" />
<ClCompile Include="src\Features\Aimbot\AutoUber\AutoUber.cpp" />
<ClCompile Include="src\Features\AutoQueue\AutoQueue.cpp" />
<ClCompile Include="src\Features\Backtrack\Backtrack.cpp" />
<ClCompile Include="src\Features\CheaterDetection\CheaterDetection.cpp" />
<ClCompile Include="src\Features\CritHack\CritHack.cpp" />
<ClCompile Include="src\Features\EnginePrediction\EnginePrediction.cpp" />
<ClCompile Include="src\Features\Misc\Misc.cpp" />
<ClCompile Include="src\Features\NetworkFix\NetworkFix.cpp" />
<ClCompile Include="src\Features\NoSpread\NoSpread.cpp" />
<ClCompile Include="src\Features\NoSpread\NoSpreadHitscan\NoSpreadHitscan.cpp" />
<ClCompile Include="src\Features\NoSpread\NoSpreadProjectile\NoSpreadProjectile.cpp" />
<ClCompile Include="src\Features\PacketManip\AntiAim\AntiAim.cpp" />
<ClCompile Include="src\Features\PacketManip\FakeLag\FakeLag.cpp" />
<ClCompile Include="src\Features\PacketManip\PacketManip.cpp" />
<ClCompile Include="src\Features\Resolver\Resolver.cpp" />
<ClCompile Include="src\Features\Simulation\MovementSimulation\MovementSimulation.cpp" />
<ClCompile Include="src\Features\Simulation\ProjectileSimulation\ProjectileSimulation.cpp" />
<ClCompile Include="src\Features\TickHandler\TickHandler.cpp" />
<ClCompile Include="src\Features\Visuals\Chams\Chams.cpp" />
<ClCompile Include="src\Features\Visuals\ESP\ESP.cpp" />
<ClCompile Include="src\Features\Visuals\FakeAngle\FakeAngle.cpp" />
<ClCompile Include="src\Features\Visuals\Glow\Glow.cpp" />
<ClCompile Include="src\Features\Visuals\LocalConditions\LocalConditions.cpp" />
<ClCompile Include="src\Features\Visuals\PlayerArrows\PlayerArrows.cpp" />
<ClCompile Include="src\Features\Visuals\Radar\Radar.cpp" />
<ClCompile Include="src\Features\Visuals\SpectatorList\SpectatorList.cpp" />
<ClCompile Include="src\Features\Visuals\Visuals.cpp" />
<ClCompile Include="src\SDK\Definitions\Main\CTFWeaponBase.cpp" />
<ClCompile Include="src\SDK\Definitions\Main\MD5.cpp" />
<ClCompile Include="src\SDK\Helpers\Color\Color.cpp" />
<ClCompile Include="src\SDK\Helpers\TraceFilters\TraceFilters.cpp" />
<ClCompile Include="src\SDK\Definitions\Misc\ChecksumCRC.cpp" />
<ClCompile Include="src\Hooks\BaseClientDLL_Shutdown.cpp" />
<ClCompile Include="src\Hooks\CL_Move.cpp" />
<ClCompile Include="src\Hooks\ClientModeShared_CreateMove.cpp" />
<ClCompile Include="src\Hooks\ClientModeShared_DoPostScreenSpaceEffects.cpp" />
<ClCompile Include="src\Hooks\ClientModeShared_OverrideView.cpp" />
<ClCompile Include="src\Hooks\ClientState_ProcessFixAngle.cpp" />
<ClCompile Include="src\Hooks\KeyValues_SetInt.cpp" />
<ClCompile Include="src\Hooks\CTFPlayerShared_IsPlayerDominated.cpp" />
<ClCompile Include="src\Hooks\CPrediction_RunCommand.cpp" />
<ClCompile Include="src\Hooks\ModelRender_DrawModelExecute.cpp" />
<ClCompile Include="src\Hooks\ViewRender_RenderView.cpp" />
<ClCompile Include="src\Hooks\Direct3DDevice9_EndScene.cpp" />
<ClCompile Include="src\Hooks\CTFPlayerPanel_GetTeam.cpp" />
<ClCompile Include="src\Hooks\BaseClientDLL_FrameStageNotify.cpp" />
<ClCompile Include="src\Hooks\EngineVGui_Paint.cpp" />
<ClCompile Include="src\Hooks\StudioRender_SetAlphaModulation.cpp" />
<ClCompile Include="src\Hooks\StudioRender_SetColorModulation.cpp" />
<ClCompile Include="src\Hooks\DoEnginePostProcessing.cpp" />
<ClCompile Include="src\Hooks\DSP_Process.cpp" />
<ClCompile Include="src\Hooks\CStaticPropMgr_ComputePropOpacity.cpp" />
<ClCompile Include="src\Hooks\CStaticPropMgr_DrawStaticProps.cpp" />
<ClCompile Include="src\Hooks\CRendering3dView_EnableWorldFog.cpp" />
<ClCompile Include="src\Hooks\CSkyboxView_Enable3dSkyboxFog.cpp" />
<ClCompile Include="src\Hooks\COPRenderSprites_RenderSpriteCard.cpp" />
<ClCompile Include="src\Hooks\BaseClientDLL_DispatchUserMessage.cpp" />
<ClCompile Include="src\Hooks\CAchievementMgr_CheckAchievementsEnabled.cpp" />
<ClCompile Include="src\Hooks\CBaseAnimating_FrameAdvance.cpp" />
<ClCompile Include="src\Hooks\CBaseAnimating_Interpolate.cpp" />
<ClCompile Include="src\Hooks\CBaseAnimating_MaintainSequenceTransitions.cpp" />
<ClCompile Include="src\Hooks\CBaseAnimating_SetupBones.cpp" />
<ClCompile Include="src\Hooks\CBaseAnimating_UpdateClientSideAnimations.cpp" />
<ClCompile Include="src\Hooks\CBaseEntity_FireBullets.cpp" />
<ClCompile Include="src\Hooks\CBaseEntity_Interpolate.cpp" />
<ClCompile Include="src\Hooks\CBaseEntity_InterpolateServerEntities.cpp" />
<ClCompile Include="src\Hooks\CBaseEntity_ResetLatched.cpp" />
<ClCompile Include="src\Hooks\CBaseEntity_SetAbsVelocity.cpp" />
<ClCompile Include="src\Hooks\CBaseHudChat_ChatPrintf.cpp" />
<ClCompile Include="src\Hooks\CBasePlayer_CalcViewModelView.cpp" />
<ClCompile Include="src\Hooks\CEconItemSchema_GetItemDefinition.cpp" />
<ClCompile Include="src\Hooks\CGameEventManager_FireEventIntern.cpp" />
<ClCompile Include="src\Hooks\CHudCrosshair_GetDrawPosition.cpp" />
<ClCompile Include="src\Hooks\CInterpolatedVarArrayBase_Interpolate.cpp" />
<ClCompile Include="src\Hooks\CInventoryManager_ShowItemsPickedUp.cpp" />
<ClCompile Include="src\Hooks\CL_ReadPackets.cpp" />
<ClCompile Include="src\Hooks\ClientModeShared_ShouldDrawViewModel.cpp" />
<ClCompile Include="src\Hooks\ClientModeTFNormal_UpdateSteamRichPresence.cpp" />
<ClCompile Include="src\Hooks\ClientState_GetClientInterpAmount.cpp" />
<ClCompile Include="src\Hooks\CMatchInviteNotification_OnTick.cpp" />
<ClCompile Include="src\Hooks\CMaterial_Uncache.cpp" />
<ClCompile Include="src\Hooks\CNetChan_SendNetMsg.cpp" />
<ClCompile Include="src\Hooks\CPlayerResource_GetTeamColor.cpp" />
<ClCompile Include="src\Hooks\CSequenceTransitioner_CheckForSequenceChange.cpp" />
<ClCompile Include="src\Hooks\CSoundEmitterSystem_EmitSound.cpp" />
<ClCompile Include="src\Hooks\CStudioRender_DrawModelStaticProp.cpp" />
<ClCompile Include="src\Hooks\CTFPartyClient_BCanRequestToJoinPlayer.cpp" />
<ClCompile Include="src\Hooks\CTFPlayer_AvoidPlayers.cpp" />
<ClCompile Include="src\Hooks\CTFPlayer_BRenderAsZombie.cpp" />
<ClCompile Include="src\Hooks\CTFPlayerInventory_GetMaxItemCount.cpp" />
<ClCompile Include="src\Hooks\CTFPlayerShared_InCond.cpp" />
<ClCompile Include="src\Hooks\CTFRagdoll_CreateTFRagdoll.cpp" />
<ClCompile Include="src\Hooks\CTFWeaponBase_CalcIsAttackCritical.cpp" />
<ClCompile Include="src\Hooks\CTFWeaponBase_GetShootSound.cpp" />
<ClCompile Include="src\Hooks\CViewRender_DrawUnderwaterOverlay.cpp" />
<ClCompile Include="src\Hooks\EngineClient_ClientCmd_Unrestricted.cpp" />
<ClCompile Include="src\Hooks\FX_FireBullets.cpp" />
<ClCompile Include="src\Hooks\GetClientInterpAmount.cpp" />
<ClCompile Include="src\Hooks\NetChannel_SendDatagram.cpp" />
<ClCompile Include="src\Hooks\NotificationQueue_Add.cpp" />
<ClCompile Include="src\Hooks\S_StartDynamicSound.cpp" />
<ClCompile Include="src\Hooks\VGuiMenuBuilder_AddMenuItem.cpp" />
<ClCompile Include="src\Hooks\Input_GetUserCmd.cpp" />
<ClCompile Include="src\Hooks\CTFPlayer_IsPlayerClass.cpp" />
<ClCompile Include="src\Hooks\ISteamNetworkingUtils_GetDirectPingToPOP.cpp" />
<ClCompile Include="src\Hooks\CL_CheckForPureServerWhitelist.cpp" />
<ClCompile Include="src\Hooks\ViewRender_LevelInit.cpp" />
<ClCompile Include="src\Hooks\ViewRender_LevelShutdown.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="src\Utils\UtlVector\UtlVector.h" />
<ClInclude Include="src\SDK\Definitions\Misc\Const.h" />
<ClInclude Include="src\SDK\Definitions\Misc\TFSharedDefs.h" />
<ClInclude Include="src\SDK\Definitions\Misc\SharedDefs.h" />
<ClInclude Include="src\Core\Core.h" />
<ClInclude Include="src\Features\CameraWindow\CameraWindow.h" />
<ClInclude Include="src\Features\Conditions\Conditions.h" />
<ClInclude Include="src\Features\Configs\Configs.h" />
<ClInclude Include="src\Features\ImGui\MaterialDesign\IconDefinitions.h" />
<ClInclude Include="src\Features\ImGui\MaterialDesign\MaterialIcons.h" />
<ClInclude Include="src\Features\ImGui\Menu\Components.h" />
<ClInclude Include="src\Features\ImGui\Menu\Menu.h" />
<ClInclude Include="src\Features\Logs\Logs.h" />
<ClInclude Include="src\Features\Players\PlayerCore.h" />
<ClInclude Include="src\Features\Players\PlayerUtils.h" />
<ClInclude Include="src\Features\Visuals\Materials\Materials.h" />
<ClInclude Include="src\Features\Visuals\Notifications\Notifications.h" />
<ClInclude Include="src\SDK\Definitions\Interfaces\CClientModeShared.h" />
<ClInclude Include="src\SDK\Definitions\Interfaces\CClientState.h" />
<ClInclude Include="src\SDK\Definitions\Interfaces\CGlobalVarsBase.h" />
<ClInclude Include="src\SDK\Definitions\Interfaces\IClientEntityList.h" />
<ClInclude Include="src\SDK\Definitions\Interfaces\ICVar.h" />
<ClInclude Include="src\SDK\Definitions\Interfaces\IEngineVGui.h" />
<ClInclude Include="src\SDK\Definitions\Interfaces\IGameEvents.h" />
<ClInclude Include="src\SDK\Definitions\Interfaces\IInputSystem.h" />
<ClInclude Include="src\SDK\Definitions\Interfaces\IMaterialSystem.h" />
<ClInclude Include="src\SDK\Definitions\Interfaces\IMatSystemSurface.h" />
<ClInclude Include="src\SDK\Definitions\Interfaces\Interface.h" />
<ClInclude Include="src\SDK\Definitions\Interfaces\IVEngineClient.h" />
<ClInclude Include="src\SDK\Definitions\Interfaces\IViewRender.h" />
<ClInclude Include="src\SDK\Definitions\Interfaces\IVModelInfo.h" />
<ClInclude Include="src\SDK\Definitions\Interfaces\IVRenderView.h" />
<ClInclude Include="src\SDK\Definitions\Interfaces\VPhysics.h" />
<ClInclude Include="src\SDK\Definitions\Main\CBaseAnimating.h" />
<ClInclude Include="src\SDK\Definitions\Main\CBaseCombatCharacter.h" />
<ClInclude Include="src\SDK\Definitions\Main\CBaseCombatWeapon.h" />
<ClInclude Include="src\SDK\Definitions\Main\CBaseEntity.h" />
<ClInclude Include="src\SDK\Definitions\Main\CBaseFlex.h" />
<ClInclude Include="src\SDK\Definitions\Main\CBaseHandle.h" />
<ClInclude Include="src\SDK\Definitions\Main\CBasePlayer.h" />
<ClInclude Include="src\SDK\Definitions\Main\CBaseProjectile.h" />
<ClInclude Include="src\SDK\Definitions\Main\CEconDefinition.h" />
<ClInclude Include="src\SDK\Definitions\Main\CHalloweenPickup.h" />
<ClInclude Include="src\SDK\Definitions\Main\CMultiPlayerAnimState.h" />
<ClInclude Include="src\SDK\Definitions\Main\CTFPlayer.h" />
<ClInclude Include="src\SDK\Definitions\Main\CTFPlayerResource.h" />
<ClInclude Include="src\SDK\Definitions\Main\CTFWeaponBase.h" />
<ClInclude Include="src\SDK\Definitions\Main\CUserCmd.h" />
<ClInclude Include="src\SDK\Definitions\Main\IClientEntity.h" />
<ClInclude Include="src\SDK\Definitions\Main\IClientNetworkable.h" />
<ClInclude Include="src\SDK\Definitions\Main\IClientRenderable.h" />
<ClInclude Include="src\SDK\Definitions\Main\IClientThinkable.h" />
<ClInclude Include="src\SDK\Definitions\Main\IClientUnknown.h" />
<ClInclude Include="src\SDK\Definitions\Main\IHandleEntity.h" />
<ClInclude Include="src\SDK\Definitions\Main\IMaterial.h" />
<ClInclude Include="src\SDK\Definitions\Main\IMaterialVar.h" />
<ClInclude Include="src\SDK\Definitions\Main\INetChannel.h" />
<ClInclude Include="src\SDK\Definitions\Main\INetChannelInfo.h" />
<ClInclude Include="src\SDK\Definitions\Main\INetMessage.h" />
<ClInclude Include="src\SDK\Definitions\Main\INetworkMessage.h" />
<ClInclude Include="src\SDK\Definitions\Main\INetworkSystem.h" />
<ClInclude Include="src\SDK\Definitions\Main\ITexture.h" />
<ClInclude Include="src\SDK\Definitions\Main\KeyValues.h" />
<ClInclude Include="src\SDK\Definitions\Main\NetChannel.h" />
<ClInclude Include="src\SDK\Definitions\Main\UtlVector.h" />
<ClInclude Include="src\SDK\Definitions\Misc\Activity.h" />
<ClInclude Include="src\SDK\Definitions\Misc\AnalogCode.h" />
<ClInclude Include="src\SDK\Definitions\Misc\BaseTypes.h" />
<ClInclude Include="src\SDK\Definitions\Misc\bitbuf.h" />
<ClInclude Include="src\SDK\Definitions\Misc\ButtonCode.h" />
<ClInclude Include="src\SDK\Definitions\Misc\CGameEventListener.h" />
<ClInclude Include="src\SDK\Definitions\Misc\ChecksumCRC.h" />
<ClInclude Include="src\SDK\Definitions\Misc\ClientClass.h" />
<ClInclude Include="src\SDK\Definitions\Misc\CommonMacros.h" />
<ClInclude Include="src\SDK\Definitions\Misc\ConVar.h" />
<ClInclude Include="src\SDK\Definitions\Misc\CPlayerResource.h" />
<ClInclude Include="src\SDK\Definitions\Misc\Cursor.h" />
<ClInclude Include="src\SDK\Definitions\Misc\CViewSetup.h" />
<ClInclude Include="src\SDK\Definitions\Misc\Datamap.h" />
<ClInclude Include="src\SDK\Definitions\Misc\Deformations.h" />
<ClInclude Include="src\SDK\Definitions\Misc\dt_common.h" />
<ClInclude Include="src\SDK\Definitions\Misc\dt_recv.h" />
<ClInclude Include="src\SDK\Definitions\Misc\IAppSystem.h" />
<ClInclude Include="src\SDK\Definitions\Misc\IClientMode.h" />
<ClInclude Include="src\SDK\Definitions\Misc\IColorCorrectionSystem.h" />
<ClInclude Include="src\SDK\Definitions\Misc\IConVar.h" />
<ClInclude Include="src\SDK\Definitions\Misc\IGameResources.h" />
<ClInclude Include="src\SDK\Definitions\Misc\IHTML.h" />
<ClInclude Include="src\SDK\Definitions\Misc\IImage.h" />
<ClInclude Include="src\SDK\Definitions\Misc\ImageFormat.h" />
<ClInclude Include="src\SDK\Definitions\Misc\IMaterialSystemHardwareConfig.h" />
<ClInclude Include="src\SDK\Definitions\Misc\InputEnums.h" />
<ClInclude Include="src\SDK\Definitions\Misc\IRefCounted.h" />
<ClInclude Include="src\SDK\Definitions\Misc\ISurface.h" />
<ClInclude Include="src\SDK\Definitions\Misc\IVguiMatInfo.h" />
<ClInclude Include="src\SDK\Definitions\Misc\IVguiMatInfoVar.h" />
<ClInclude Include="src\SDK\Definitions\Misc\KeyCode.h" />
<ClInclude Include="src\SDK\Definitions\Misc\LightDesc.h" />
<ClInclude Include="src\SDK\Definitions\Misc\LocalFlexController.h" />
<ClInclude Include="src\SDK\Definitions\Misc\Modes.h" />
<ClInclude Include="src\SDK\Definitions\Misc\MouseCode.h" />
<ClInclude Include="src\SDK\Definitions\Misc\NetAdr.h" />
<ClInclude Include="src\SDK\Definitions\Misc\String.h" />
<ClInclude Include="src\SDK\Definitions\Misc\Studio.h" />
<ClInclude Include="src\SDK\Definitions\Misc\TextureGroupNames.h" />
<ClInclude Include="src\SDK\Definitions\Misc\VGUI.h" />
<ClInclude Include="src\SDK\Definitions\Misc\VPlane.h" />
<ClInclude Include="src\SDK\Definitions\Misc\VTF.h" />
<ClInclude Include="src\SDK\Definitions\Classes.h" />
<ClInclude Include="src\SDK\Definitions\Definitions.h" />
<ClInclude Include="src\SDK\Definitions\Interfaces.h" />
<ClInclude Include="src\SDK\Definitions\Types.h" />
<ClInclude Include="src\SDK\Helpers\Draw\Draw.h" />
<ClInclude Include="src\SDK\Helpers\Draw\Icons.h" />
<ClInclude Include="src\SDK\Helpers\Entities\Entities.h" />
<ClInclude Include="src\SDK\Helpers\Fonts\Fonts.h" />
<ClInclude Include="src\SDK\Globals.h" />
<ClInclude Include="src\SDK\SDK.h" />
<ClInclude Include="src\SDK\Vars.h" />
<ClInclude Include="src\Utils\Assert\Assert.h" />
<ClInclude Include="src\Utils\Feature\Feature.h" />
<ClInclude Include="src\Utils\Hash\FNV1A.h" />
<ClInclude Include="src\Utils\Hooks\Hooks.h" />
<ClInclude Include="src\Utils\Interfaces\Interfaces.h" />
<ClInclude Include="src\Utils\KeyHandler\KeyHandler.h" />
<ClInclude Include="src\Utils\Math\Math.h" />
<ClInclude Include="src\Utils\Memory\Memory.h" />
<ClInclude Include="src\Utils\Minidump\Minidump.h" />
<ClInclude Include="src\Utils\NetVars\NetVars.h" />
<ClInclude Include="src\Utils\Signatures\Signatures.h" />
<ClInclude Include="src\Utils\Timer\Timer.h" />
<ClInclude Include="include\ImGui\imconfig.h" />
<ClInclude Include="include\ImGui\imgui.h" />
<ClInclude Include="include\ImGui\imgui_impl_dx9.h" />
<ClInclude Include="include\ImGui\imgui_impl_win32.h" />
<ClInclude Include="include\ImGui\imgui_internal.h" />
<ClInclude Include="include\ImGui\imgui_stdlib.h" />
<ClInclude Include="include\ImGui\imstb_rectpack.h" />
<ClInclude Include="include\ImGui\imstb_textedit.h" />
<ClInclude Include="include\ImGui\imstb_truetype.h" />
<ClInclude Include="include\ImGui\TextEditor.h" />
<ClInclude Include="include\MinHook\hde\hde32.h" />
<ClInclude Include="include\MinHook\hde\hde64.h" />
<ClInclude Include="include\MinHook\hde\pstdint.h" />
<ClInclude Include="include\MinHook\hde\table32.h" />
<ClInclude Include="include\MinHook\hde\table64.h" />
<ClInclude Include="include\MinHook\buffer.h" />
<ClInclude Include="include\MinHook\MinHook.h" />
<ClInclude Include="include\MinHook\trampoline.h" />
<ClInclude Include="src\Utils\ConVars\ConVars.h" />
<ClInclude Include="src\Features\Commands\Commands.h" />
<ClInclude Include="src\SDK\Definitions\Interfaces\CTFPartyClient.h" />
<ClInclude Include="src\SDK\Definitions\Steam\ISteamController.h" />
<ClInclude Include="src\SDK\Definitions\Steam\ISteamFriends.h" />
<ClInclude Include="src\SDK\Definitions\Steam\ISteamGameServer.h" />
<ClInclude Include="src\SDK\Definitions\Steam\ISteamGameServerStats.h" />
<ClInclude Include="src\SDK\Definitions\Steam\ISteamHTMLSurface.h" />
<ClInclude Include="src\SDK\Definitions\Steam\ISteamHTTP.h" />
<ClInclude Include="src\SDK\Definitions\Steam\ISteamInput.h" />
<ClInclude Include="src\SDK\Definitions\Steam\ISteamInventory.h" />
<ClInclude Include="src\SDK\Definitions\Steam\ISteamMatchmaking.h" />
<ClInclude Include="src\SDK\Definitions\Steam\ISteamMusic.h" />
<ClInclude Include="src\SDK\Definitions\Steam\ISteamMusicRemote.h" />
<ClInclude Include="src\SDK\Definitions\Steam\ISteamNetworking.h" />
<ClInclude Include="src\SDK\Definitions\Steam\ISteamNetworkingMessages.h" />
<ClInclude Include="src\SDK\Definitions\Steam\ISteamNetworkingSockets.h" />
<ClInclude Include="src\SDK\Definitions\Steam\ISteamNetworkingUtils.h" />
<ClInclude Include="src\SDK\Definitions\Steam\ISteamParentalSettings.h" />
<ClInclude Include="src\SDK\Definitions\Steam\ISteamRemotePlay.h" />
<ClInclude Include="src\SDK\Definitions\Steam\ISteamRemoteStorage.h" />
<ClInclude Include="src\SDK\Definitions\Steam\ISteamScreenshots.h" />
<ClInclude Include="src\SDK\Definitions\Steam\ISteamUGC.h" />
<ClInclude Include="src\SDK\Definitions\Steam\ISteamUser.h" />
<ClInclude Include="src\SDK\Definitions\Steam\ISteamUserStats.h" />
<ClInclude Include="src\SDK\Definitions\Steam\ISteamUtils.h" />
<ClInclude Include="src\SDK\Definitions\Steam\ISteamVideo.h" />
<ClInclude Include="src\SDK\Definitions\Steam\MatchmakingTypes.h" />
<ClInclude Include="src\SDK\Definitions\Steam\Steam_API.h" />
<ClInclude Include="src\SDK\Definitions\Steam\Steam_API_Common.h" />
<ClInclude Include="src\SDK\Definitions\Steam\Steam_API_Internal.h" />
<ClInclude Include="src\SDK\Definitions\Steam\Steam_Gameserver.h" />
<ClInclude Include="src\SDK\Definitions\Steam\SteamClientPublic.h" />
<ClInclude Include="src\SDK\Definitions\Steam\SteamHTTPEnums.h" />
<ClInclude Include="src\SDK\Definitions\Steam\SteamNetworkingTypes.h" />
<ClInclude Include="src\SDK\Definitions\Steam\SteamTypes.h" />
<ClInclude Include="src\SDK\Definitions\Steam\SteamUniverse.h" />
<ClInclude Include="src\SDK\Definitions\Interfaces\SteamInterfaces.h" />
<ClInclude Include="src\Features\ImGui\Render.h" />
<ClInclude Include="src\Features\Aimbot\Aimbot.h" />
<ClInclude Include="src\Features\Aimbot\AimbotGlobal\AimbotGlobal.h" />
<ClInclude Include="src\Features\Aimbot\AimbotHitscan\AimbotHitscan.h" />
<ClInclude Include="src\Features\Aimbot\AimbotMelee\AimbotMelee.h" />
<ClInclude Include="src\Features\Aimbot\AimbotProjectile\AimbotProjectile.h" />
<ClInclude Include="src\Features\Aimbot\AutoAirblast\AutoAirblast.h" />
<ClInclude Include="src\Features\Aimbot\AutoDetonate\AutoDetonate.h" />
<ClInclude Include="src\Features\Aimbot\AutoRocketJump\AutoRocketJump.h" />
<ClInclude Include="src\Features\Aimbot\AutoUber\AutoUber.h" />
<ClInclude Include="src\Features\AutoQueue\AutoQueue.h" />
<ClInclude Include="src\Features\Backtrack\Backtrack.h" />
<ClInclude Include="src\Features\CheaterDetection\CheaterDetection.h" />
<ClInclude Include="src\Features\CritHack\CritHack.h" />
<ClInclude Include="src\Features\EnginePrediction\EnginePrediction.h" />
<ClInclude Include="src\Features\Misc\Misc.h" />
<ClInclude Include="src\Features\NetworkFix\NetworkFix.h" />
<ClInclude Include="src\Features\NoSpread\NoSpread.h" />
<ClInclude Include="src\Features\NoSpread\NoSpreadHitscan\NoSpreadHitscan.h" />
<ClInclude Include="src\Features\NoSpread\NoSpreadProjectile\NoSpreadProjectile.h" />
<ClInclude Include="src\Features\PacketManip\AntiAim\AntiAim.h" />
<ClInclude Include="src\Features\PacketManip\FakeLag\FakeLag.h" />
<ClInclude Include="src\Features\PacketManip\PacketManip.h" />
<ClInclude Include="src\Features\Resolver\Resolver.h" />
<ClInclude Include="src\Features\Simulation\MovementSimulation\MovementSimulation.h" />
<ClInclude Include="src\Features\Simulation\ProjectileSimulation\ProjectileSimulation.h" />
<ClInclude Include="src\Features\TickHandler\TickHandler.h" />
<ClInclude Include="src\Features\Visuals\Chams\Chams.h" />
<ClInclude Include="src\Features\Visuals\ESP\ESP.h" />
<ClInclude Include="src\Features\Visuals\FakeAngle\FakeAngle.h" />
<ClInclude Include="src\Features\Visuals\Glow\Glow.h" />
<ClInclude Include="src\Features\Visuals\LocalConditions\LocalConditions.h" />
<ClInclude Include="src\Features\Visuals\PlayerArrows\PlayerArrows.h" />
<ClInclude Include="src\Features\Visuals\Radar\Radar.h" />
<ClInclude Include="src\Features\Visuals\SpectatorList\SpectatorList.h" />
<ClInclude Include="src\Features\Visuals\Visuals.h" />
<ClInclude Include="src\SDK\Definitions\Interfaces\IGameMovement.h" />
<ClInclude Include="src\SDK\Definitions\Interfaces\IInput.h" />
<ClInclude Include="src\SDK\Definitions\Interfaces\IUniformRandomStream.h" />
<ClInclude Include="src\SDK\Definitions\Interfaces\Prediction.h" />
<ClInclude Include="src\SDK\Definitions\Interfaces\VGuiPanel.h" />
<ClInclude Include="src\SDK\Definitions\Main\CBaseObject.h" />
<ClInclude Include="src\SDK\Definitions\Main\CBaseTrace.h" />
<ClInclude Include="src\SDK\Definitions\Main\CCollisionProperty.h" />
<ClInclude Include="src\SDK\Definitions\Main\CEntitySphereQuery.h" />
<ClInclude Include="src\SDK\Definitions\Main\CGameTrace.h" />
<ClInclude Include="src\SDK\Definitions\Main\CModel.h" />
<ClInclude Include="src\SDK\Definitions\Interfaces\IEngineTrace.h" />
<ClInclude Include="src\SDK\Definitions\Main\IAchievementMgr.h" />
<ClInclude Include="src\SDK\Definitions\Main\MD5.h" />
<ClInclude Include="src\SDK\Definitions\Misc\BSPFlags.h" />
<ClInclude Include="src\SDK\Definitions\Interfaces\IMoveHelper.h" />
<ClInclude Include="src\SDK\Definitions\Misc\IPrediction.h" />
<ClInclude Include="src\SDK\Definitions\Misc\ISpatialPartition.h" />
<ClInclude Include="src\SDK\Definitions\Misc\VCollide.h" />
<ClInclude Include="src\SDK\Helpers\Color\Color.h" />
<ClInclude Include="src\SDK\Helpers\Particles\Particles.h" />
<ClInclude Include="src\SDK\Helpers\TraceFilters\TraceFilters.h" />
<ClInclude Include="src\SDK\Definitions\Interfaces\IVModelRender.h" />
<ClInclude Include="src\SDK\Definitions\Interfaces\IStudioRender.h" />
<ClInclude Include="src\SDK\Definitions\Misc\IMDLCache.h" />
<ClInclude Include="src\SDK\Definitions\Steam\ISteamApps.h" />
<ClInclude Include="src\SDK\Definitions\Steam\ISteamClient.h" />
<ClInclude Include="src\SDK\Definitions\Steam\ISteamAppList.h" />
<ClInclude Include="src\Hooks\Direct3DDevice9_EndScene.h" />
<ClInclude Include="src\SDK\Definitions\Interfaces\CTFGameRules.h" />
<ClInclude Include="src\SDK\Definitions\Interfaces\ViewRenderBeams.h" />
</ItemGroup>
<ItemGroup>
<None Include="cpp.hint" />
<None Include="packages.config" />
</ItemGroup>
</Project>

59
Amalgam/cpp.hint Normal file
View File

@ -0,0 +1,59 @@
#define MAKE_HOOK(name, address, type, callconvo, ...) namespace Hooks \
{\
namespace name\
{\
void Init(); \
inline CHook Hook(Init); \
using FN = type(callconvo *)(__VA_ARGS__); \
type callconvo Func(__VA_ARGS__); \
}\
} \
void Hooks::name::Init() { Hook.Create(reinterpret_cast<void *>(address), Func); } \
type callconvo Hooks::name::Func(__VA_ARGS__)
#define CALL_ORIGINAL Hook.Original<FN>()
#define MAKE_INTERFACE_VERSION(type, name, dll, version) namespace I { inline type *name = nullptr; } \
namespace MAKE_INTERFACE_SCOPE \
{\
inline InterfaceInit_t name##InterfaceInit_t(reinterpret_cast<void **>(&I::name), dll, version, -1, 0); \
}
#define MAKE_INTERFACE_SIGNATURE(type, name, dll, version, offset, deref) namespace I { inline type *name = nullptr; } \
namespace MAKE_INTERFACE_SCOPE \
{\
inline InterfaceInit_t name##InterfaceInit_t(reinterpret_cast<void **>(&I::name), dll, version, offset, deref); \
}
#define MAKE_INTERFACE_NULL(type, name) namespace I { inline type *name = nullptr; }
#define MAKE_INTERFACE_VERSION_SEARCH(type, name, dll, version) namespace I { inline type *name = nullptr; } \
namespace MAKE_INTERFACE_SCOPE \
{\
inline InterfaceInit_t name##InterfaceInit_t(reinterpret_cast<void **>(&I::name), dll, version, -1, 0, true); \
}
#define MAKE_INTERFACE_SIGNATURE_SEARCH(type, name, dll, signature, offset, deref) namespace I { inline type *name = nullptr; } \
namespace MAKE_INTERFACE_SCOPE \
{\
inline InterfaceInit_t name##InterfaceInit_t(reinterpret_cast<void **>(&I::name), dll, signature, offset, deref, true); \
}
#define NETVAR(_name, type, table, name) type& _name() \
{ \
static int nOffset = U::NetVars.GetNetVar(table, name); \
return *reinterpret_cast<type*>(std::uintptr_t(this) + nOffset); \
}
#define NETVAR_OFF(_name, type, table, name, offset) type& _name() \
{ \
static int nOffset = U::NetVars.GetNetVar(table, name) + offset; \
return *reinterpret_cast<type*>(std::uintptr_t(this) + nOffset); \
}
#define OFFSET(name, type, offset) type& name() \
{ \
return *reinterpret_cast<type*>(std::uintptr_t(this) + offset); \
}
#define VIRTUAL(name, type, fn, base, index) type name() \
{ \
return reinterpret_cast<fn>(U::Memory.GetVFunc(base, index))(base); \
}
#define CONDGET(name, conditions, cond) bool name() \
{ \
return (conditions & cond); \
}
#define MAKE_SIGNATURE(name, dll, sig, offset) namespace S { inline CSignature name(dll, sig, offset, #name); }
#define ADD_FEATURE_CUSTOM(type, name, scope) namespace scope { inline type name; }
#define ADD_FEATURE(type, name) ADD_FEATURE_CUSTOM(type, name, F)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,406 @@
#pragma once
#include <string>
#include <vector>
#include <array>
#include <memory>
#include <unordered_set>
#include <unordered_map>
#include <map>
#include <regex>
#include "imgui.h"
class TextEditor
{
public:
enum class PaletteIndex
{
Default,
Keyword,
Number,
String,
CharLiteral,
Punctuation,
Preprocessor,
Identifier,
KnownIdentifier,
PreprocIdentifier,
Comment,
MultiLineComment,
Background,
Cursor,
Selection,
ErrorMarker,
Breakpoint,
LineNumber,
CurrentLineFill,
CurrentLineFillInactive,
CurrentLineEdge,
Max
};
enum class SelectionMode
{
Normal,
Word,
Line
};
struct Breakpoint
{
int mLine;
bool mEnabled;
std::string mCondition;
Breakpoint()
: mLine(-1)
, mEnabled(false)
{
}
};
// Represents a character coordinate from the user's point of view,
// i. e. consider an uniform grid (assuming fixed-width font) on the
// screen as it is rendered, and each cell has its own coordinate, starting from 0.
// Tabs are counted as [1..mTabSize] count empty spaces, depending on
// how many space is necessary to reach the next tab stop.
// For example, coordinate (1, 5) represents the character 'B' in a line "\tABC", when mTabSize = 4,
// because it is rendered as " ABC" on the screen.
struct Coordinates
{
int mLine, mColumn;
Coordinates() : mLine(0), mColumn(0) {}
Coordinates(int aLine, int aColumn) : mLine(aLine), mColumn(aColumn)
{
assert(aLine >= 0);
assert(aColumn >= 0);
}
static Coordinates Invalid()
{
static Coordinates invalid(-1, -1);
return invalid;
}
bool operator ==(const Coordinates& o) const
{
return
mLine == o.mLine &&
mColumn == o.mColumn;
}
bool operator !=(const Coordinates& o) const
{
return
mLine != o.mLine ||
mColumn != o.mColumn;
}
bool operator <(const Coordinates& o) const
{
if (mLine != o.mLine)
{
return mLine < o.mLine;
}
return mColumn < o.mColumn;
}
bool operator >(const Coordinates& o) const
{
if (mLine != o.mLine)
{
return mLine > o.mLine;
}
return mColumn > o.mColumn;
}
bool operator <=(const Coordinates& o) const
{
if (mLine != o.mLine)
{
return mLine < o.mLine;
}
return mColumn <= o.mColumn;
}
bool operator >=(const Coordinates& o) const
{
if (mLine != o.mLine)
{
return mLine > o.mLine;
}
return mColumn >= o.mColumn;
}
};
struct Identifier
{
Coordinates mLocation;
std::string mDeclaration;
};
using String = std::string;
using Identifiers = std::unordered_map<std::string, Identifier>;
using Keywords = std::unordered_set<std::string>;
using ErrorMarkers = std::map<int, std::string>;
using Breakpoints = std::unordered_set<int>;
using Palette = std::array<ImU32, static_cast<unsigned>(PaletteIndex::Max)>;
using Char = uint8_t;
struct Glyph
{
Char mChar;
PaletteIndex mColorIndex = PaletteIndex::Default;
bool mComment : 1;
bool mMultiLineComment : 1;
bool mPreprocessor : 1;
Glyph(Char aChar, PaletteIndex aColorIndex) : mChar(aChar), mColorIndex(aColorIndex),
mComment(false), mMultiLineComment(false), mPreprocessor(false)
{
}
};
using Line = std::vector<Glyph>;
using Lines = std::vector<Line>;
struct LanguageDefinition
{
using TokenRegexString = std::pair<std::string, PaletteIndex>;
using TokenRegexStrings = std::vector<TokenRegexString>;
using TokenizeCallback = bool(*)(const char* in_begin, const char* in_end, const char*& out_begin, const char*& out_end, PaletteIndex& paletteIndex);
std::string mName;
Keywords mKeywords;
Identifiers mIdentifiers;
Identifiers mPreprocIdentifiers;
std::string mCommentStart, mCommentEnd, mSingleLineComment;
char mPreprocChar;
bool mAutoIndentation;
TokenizeCallback mTokenize;
TokenRegexStrings mTokenRegexStrings;
bool mCaseSensitive;
LanguageDefinition()
: mPreprocChar('#'), mAutoIndentation(true), mTokenize(nullptr), mCaseSensitive(true)
{
}
static const LanguageDefinition& CPlusPlus();
static const LanguageDefinition& HLSL();
static const LanguageDefinition& GLSL();
static const LanguageDefinition& C();
static const LanguageDefinition& SQL();
static const LanguageDefinition& AngelScript();
static const LanguageDefinition& Lua();
};
TextEditor();
~TextEditor();
void SetLanguageDefinition(const LanguageDefinition& aLanguageDef);
const LanguageDefinition& GetLanguageDefinition() const { return mLanguageDefinition; }
const Palette& GetPalette() const { return mPaletteBase; }
void SetPalette(const Palette& aValue);
void SetErrorMarkers(const ErrorMarkers& aMarkers) { mErrorMarkers = aMarkers; }
void SetBreakpoints(const Breakpoints& aMarkers) { mBreakpoints = aMarkers; }
void Render(const char* aTitle, const ImVec2& aSize = ImVec2(), bool aBorder = false);
void SetText(const std::string& aText);
std::string GetText() const;
void SetTextLines(const std::vector<std::string>& aLines);
std::vector<std::string> GetTextLines() const;
std::string GetSelectedText() const;
std::string GetCurrentLineText() const;
int GetTotalLines() const { return static_cast<int>(mLines.size()); }
bool IsOverwrite() const { return mOverwrite; }
void SetReadOnly(bool aValue);
bool IsReadOnly() const { return mReadOnly; }
bool IsTextChanged() const { return mTextChanged; }
bool IsCursorPositionChanged() const { return mCursorPositionChanged; }
bool IsColorizerEnabled() const { return mColorizerEnabled; }
void SetColorizerEnable(bool aValue);
Coordinates GetCursorPosition() const { return GetActualCursorCoordinates(); }
void SetCursorPosition(const Coordinates& aPosition);
void SetHandleMouseInputs(bool aValue) { mHandleMouseInputs = aValue; }
bool IsHandleMouseInputsEnabled() const { return mHandleKeyboardInputs; }
void SetHandleKeyboardInputs(bool aValue) { mHandleKeyboardInputs = aValue; }
bool IsHandleKeyboardInputsEnabled() const { return mHandleKeyboardInputs; }
void SetImGuiChildIgnored(bool aValue) { mIgnoreImGuiChild = aValue; }
bool IsImGuiChildIgnored() const { return mIgnoreImGuiChild; }
void SetShowWhitespaces(bool aValue) { mShowWhitespaces = aValue; }
bool IsShowingWhitespaces() const { return mShowWhitespaces; }
void SetTabSize(int aValue);
int GetTabSize() const { return mTabSize; }
void InsertText(const std::string& aValue);
void InsertText(const char* aValue);
void MoveUp(int aAmount = 1, bool aSelect = false);
void MoveDown(int aAmount = 1, bool aSelect = false);
void MoveLeft(int aAmount = 1, bool aSelect = false, bool aWordMode = false);
void MoveRight(int aAmount = 1, bool aSelect = false, bool aWordMode = false);
void MoveTop(bool aSelect = false);
void MoveBottom(bool aSelect = false);
void MoveHome(bool aSelect = false);
void MoveEnd(bool aSelect = false);
void SetSelectionStart(const Coordinates& aPosition);
void SetSelectionEnd(const Coordinates& aPosition);
void SetSelection(const Coordinates& aStart, const Coordinates& aEnd, SelectionMode aMode = SelectionMode::Normal);
void SelectWordUnderCursor();
void SelectAll();
bool HasSelection() const;
void Copy();
void Cut();
void Paste();
void Delete();
bool CanUndo() const;
bool CanRedo() const;
void Undo(int aSteps = 1);
void Redo(int aSteps = 1);
static const Palette& GetDarkPalette();
static const Palette& GetLightPalette();
static const Palette& GetRetroBluePalette();
private:
using RegexList = std::vector<std::pair<std::regex, PaletteIndex>>;
struct EditorState
{
Coordinates mSelectionStart;
Coordinates mSelectionEnd;
Coordinates mCursorPosition;
};
class UndoRecord
{
public:
UndoRecord() {}
~UndoRecord() {}
UndoRecord(
const std::string& aAdded,
Coordinates aAddedStart,
Coordinates aAddedEnd,
const std::string& aRemoved,
Coordinates aRemovedStart,
Coordinates aRemovedEnd,
EditorState& aBefore,
EditorState& aAfter);
void Undo(TextEditor* aEditor);
void Redo(TextEditor* aEditor);
std::string mAdded;
Coordinates mAddedStart;
Coordinates mAddedEnd;
std::string mRemoved;
Coordinates mRemovedStart;
Coordinates mRemovedEnd;
EditorState mBefore;
EditorState mAfter;
};
using UndoBuffer = std::vector<UndoRecord>;
void ProcessInputs();
void Colorize(int aFromLine = 0, int aCount = -1);
void ColorizeRange(int aFromLine = 0, int aToLine = 0);
void ColorizeInternal();
float TextDistanceToLineStart(const Coordinates& aFrom) const;
void EnsureCursorVisible();
int GetPageSize() const;
std::string GetText(const Coordinates& aStart, const Coordinates& aEnd) const;
Coordinates GetActualCursorCoordinates() const;
Coordinates SanitizeCoordinates(const Coordinates& aValue) const;
void Advance(Coordinates& aCoordinates) const;
void DeleteRange(const Coordinates& aStart, const Coordinates& aEnd);
int InsertTextAt(Coordinates& aWhere, const char* aValue);
void AddUndo(UndoRecord& aValue);
Coordinates ScreenPosToCoordinates(const ImVec2& aPosition) const;
Coordinates FindWordStart(const Coordinates& aFrom) const;
Coordinates FindWordEnd(const Coordinates& aFrom) const;
Coordinates FindNextWord(const Coordinates& aFrom) const;
int GetCharacterIndex(const Coordinates& aCoordinates) const;
int GetCharacterColumn(int aLine, int aIndex) const;
int GetLineCharacterCount(int aLine) const;
int GetLineMaxColumn(int aLine) const;
bool IsOnWordBoundary(const Coordinates& aAt) const;
void RemoveLine(int aStart, int aEnd);
void RemoveLine(int aIndex);
Line& InsertLine(int aIndex);
void EnterCharacter(ImWchar aChar, bool aShift);
void Backspace();
void DeleteSelection();
std::string GetWordUnderCursor() const;
std::string GetWordAt(const Coordinates& aCoords) const;
ImU32 GetGlyphColor(const Glyph& aGlyph) const;
void HandleKeyboardInputs();
void HandleMouseInputs();
void Render();
float mLineSpacing;
Lines mLines;
EditorState mState;
UndoBuffer mUndoBuffer;
int mUndoIndex;
int mTabSize;
bool mOverwrite;
bool mReadOnly;
bool mWithinRender;
bool mScrollToCursor;
bool mScrollToTop;
bool mTextChanged;
bool mColorizerEnabled;
float mTextStart; // position (in pixels) where a code line starts relative to the left of the TextEditor.
int mLeftMargin;
bool mCursorPositionChanged;
int mColorRangeMin, mColorRangeMax;
SelectionMode mSelectionMode;
bool mHandleKeyboardInputs;
bool mHandleMouseInputs;
bool mIgnoreImGuiChild;
bool mShowWhitespaces;
Palette mPaletteBase{};
Palette mPalette{};
LanguageDefinition mLanguageDefinition;
RegexList mRegexList;
bool mCheckComments;
Breakpoints mBreakpoints;
ErrorMarkers mErrorMarkers;
ImVec2 mCharAdvance;
Coordinates mInteractiveStart, mInteractiveEnd;
std::string mLineBuffer;
uint64_t mStartTime;
float mLastClick;
};

View File

@ -0,0 +1,129 @@
//-----------------------------------------------------------------------------
// DEAR IMGUI COMPILE-TIME OPTIONS
// Runtime options (clipboard callbacks, enabling various features, etc.) can generally be set via the ImGuiIO structure.
// You can use ImGui::SetAllocatorFunctions() before calling ImGui::CreateContext() to rewire memory allocation functions.
//-----------------------------------------------------------------------------
// A) You may edit imconfig.h (and not overwrite it when updating Dear ImGui, or maintain a patch/rebased branch with your modifications to it)
// B) or '#define IMGUI_USER_CONFIG "my_imgui_config.h"' in your project and then add directives in your own file without touching this template.
//-----------------------------------------------------------------------------
// You need to make sure that configuration settings are defined consistently _everywhere_ Dear ImGui is used, which include the imgui*.cpp
// files but also _any_ of your code that uses Dear ImGui. This is because some compile-time options have an affect on data structures.
// Defining those options in imconfig.h will ensure every compilation unit gets to see the same data structure layouts.
// Call IMGUI_CHECKVERSION() from your .cpp file to verify that the data structures your files are using are matching the ones imgui.cpp is using.
//-----------------------------------------------------------------------------
#pragma once
//---- Define assertion handler. Defaults to calling assert().
// If your macro uses multiple statements, make sure is enclosed in a 'do { .. } while (0)' block so it can be used as a single statement.
//#define IM_ASSERT(_EXPR) MyAssert(_EXPR)
//#define IM_ASSERT(_EXPR) ((void)(_EXPR)) // Disable asserts
//---- Define attributes of all API symbols declarations, e.g. for DLL under Windows
// Using Dear ImGui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility.
// DLL users: heaps and globals are not shared across DLL boundaries! You will need to call SetCurrentContext() + SetAllocatorFunctions()
// for each static/DLL boundary you are calling from. Read "Context and Memory Allocators" section of imgui.cpp for more details.
//#define IMGUI_API __declspec( dllexport )
//#define IMGUI_API __declspec( dllimport )
//---- Don't define obsolete functions/enums/behaviors. Consider enabling from time to time after updating to clean your code of obsolete function/names.
//#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS
//#define IMGUI_DISABLE_OBSOLETE_KEYIO // 1.87: disable legacy io.KeyMap[]+io.KeysDown[] in favor io.AddKeyEvent(). This will be folded into IMGUI_DISABLE_OBSOLETE_FUNCTIONS in a few versions.
//---- Disable all of Dear ImGui or don't implement standard windows/tools.
// It is very strongly recommended to NOT disable the demo windows and debug tool during development. They are extremely useful in day to day work. Please read comments in imgui_demo.cpp.
//#define IMGUI_DISABLE // Disable everything: all headers and source files will be empty.
//#define IMGUI_DISABLE_DEMO_WINDOWS // Disable demo windows: ShowDemoWindow()/ShowStyleEditor() will be empty.
//#define IMGUI_DISABLE_DEBUG_TOOLS // Disable metrics/debugger and other debug tools: ShowMetricsWindow(), ShowDebugLogWindow() and ShowStackToolWindow() will be empty (this was called IMGUI_DISABLE_METRICS_WINDOW before 1.88).
//---- Don't implement some functions to reduce linkage requirements.
//#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS // [Win32] Don't implement default clipboard handler. Won't use and link with OpenClipboard/GetClipboardData/CloseClipboard etc. (user32.lib/.a, kernel32.lib/.a)
//#define IMGUI_ENABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with Visual Studio] Implement default IME handler (require imm32.lib/.a, auto-link for Visual Studio, -limm32 on command-line for MinGW)
//#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with non-Visual Studio compilers] Don't implement default IME handler (won't require imm32.lib/.a)
//#define IMGUI_DISABLE_WIN32_FUNCTIONS // [Win32] Won't use and link with any Win32 function (clipboard, IME).
//#define IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS // [OSX] Implement default OSX clipboard handler (need to link with '-framework ApplicationServices', this is why this is not the default).
//#define IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself (e.g. if you don't want to link with vsnprintf)
//#define IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS // Don't implement ImFabs/ImSqrt/ImPow/ImFmod/ImCos/ImSin/ImAcos/ImAtan2 so you can implement them yourself.
//#define IMGUI_DISABLE_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle at all (replace them with dummies)
//#define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle so you can implement them yourself if you don't want to link with fopen/fclose/fread/fwrite. This will also disable the LogToTTY() function.
//#define IMGUI_DISABLE_DEFAULT_ALLOCATORS // Don't implement default allocators calling malloc()/free() to avoid linking with them. You will need to call ImGui::SetAllocatorFunctions().
//#define IMGUI_DISABLE_SSE // Disable use of SSE intrinsics even if available
//---- Include imgui_user.h at the end of imgui.h as a convenience
//#define IMGUI_INCLUDE_IMGUI_USER_H
//---- Pack colors to BGRA8 instead of RGBA8 (to avoid converting from one to another)
//#define IMGUI_USE_BGRA_PACKED_COLOR
//---- Use 32-bit for ImWchar (default is 16-bit) to support unicode planes 1-16. (e.g. point beyond 0xFFFF like emoticons, dingbats, symbols, shapes, ancient languages, etc...)
//#define IMGUI_USE_WCHAR32
//---- Avoid multiple STB libraries implementations, or redefine path/filenames to prioritize another version
// By default the embedded implementations are declared static and not available outside of Dear ImGui sources files.
//#define IMGUI_STB_TRUETYPE_FILENAME "my_folder/stb_truetype.h"
//#define IMGUI_STB_RECT_PACK_FILENAME "my_folder/stb_rect_pack.h"
//#define IMGUI_STB_SPRINTF_FILENAME "my_folder/stb_sprintf.h" // only used if IMGUI_USE_STB_SPRINTF is defined.
//#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION
//#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION
//#define IMGUI_DISABLE_STB_SPRINTF_IMPLEMENTATION // only disabled if IMGUI_USE_STB_SPRINTF is defined.
//---- Use stb_sprintf.h for a faster implementation of vsnprintf instead of the one from libc (unless IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS is defined)
// Compatibility checks of arguments and formats done by clang and GCC will be disabled in order to support the extra formats provided by stb_sprintf.h.
//#define IMGUI_USE_STB_SPRINTF
//---- Use FreeType to build and rasterize the font atlas (instead of stb_truetype which is embedded by default in Dear ImGui)
// Requires FreeType headers to be available in the include path. Requires program to be compiled with 'misc/freetype/imgui_freetype.cpp' (in this repository) + the FreeType library (not provided).
// On Windows you may use vcpkg with 'vcpkg install freetype --triplet=x64-windows' + 'vcpkg integrate install'.
//#define IMGUI_ENABLE_FREETYPE
//---- Use FreeType+lunasvg library to render OpenType SVG fonts (SVGinOT)
// Requires lunasvg headers to be available in the include path + program to be linked with the lunasvg library (not provided).
// Only works in combination with IMGUI_ENABLE_FREETYPE.
// (implementation is based on Freetype's rsvg-port.c which is licensed under CeCILL-C Free Software License Agreement)
//#define IMGUI_ENABLE_FREETYPE_LUNASVG
//---- Use stb_truetype to build and rasterize the font atlas (default)
// The only purpose of this define is if you want force compilation of the stb_truetype backend ALONG with the FreeType backend.
//#define IMGUI_ENABLE_STB_TRUETYPE
//---- Define constructor and implicit cast operators to convert back<>forth between your math types and ImVec2/ImVec4.
// This will be inlined as part of ImVec2 and ImVec4 class declarations.
/*
#define IM_VEC2_CLASS_EXTRA \
constexpr ImVec2(const MyVec2& f) : x(f.x), y(f.y) {} \
operator MyVec2() const { return MyVec2(x,y); }
#define IM_VEC4_CLASS_EXTRA \
constexpr ImVec4(const MyVec4& f) : x(f.x), y(f.y), z(f.z), w(f.w) {} \
operator MyVec4() const { return MyVec4(x,y,z,w); }
*/
//---- ...Or use Dear ImGui's own very basic math operators.
//#define IMGUI_DEFINE_MATH_OPERATORS
//---- Use 32-bit vertex indices (default is 16-bit) is one way to allow large meshes with more than 64K vertices.
// Your renderer backend will need to support it (most example renderer backends support both 16/32-bit indices).
// Another way to allow large meshes while keeping 16-bit indices is to handle ImDrawCmd::VtxOffset in your renderer.
// Read about ImGuiBackendFlags_RendererHasVtxOffset for details.
//#define ImDrawIdx unsigned int
//---- Override ImDrawCallback signature (will need to modify renderer backends accordingly)
//struct ImDrawList;
//struct ImDrawCmd;
//typedef void (*MyImDrawCallback)(const ImDrawList* draw_list, const ImDrawCmd* cmd, void* my_renderer_user_data);
//#define ImDrawCallback MyImDrawCallback
//---- Debug Tools: Macro to break in Debugger (we provide a default implementation of this in the codebase)
// (use 'Metrics->Tools->Item Picker' to pick widgets with the mouse and break into them for easy debugging.)
//#define IM_DEBUG_BREAK IM_ASSERT(0)
//#define IM_DEBUG_BREAK __debugbreak()
//---- Debug Tools: Enable slower asserts
//#define IMGUI_DEBUG_PARANOID
//---- Tip: You can add extra functions within the ImGui:: namespace from anywhere (e.g. your own sources/header files)
/*
namespace ImGui
{
void MyFunction(const char* name, MyMatrix44* mtx);
}
*/

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,385 @@
// dear imgui: Renderer Backend for DirectX9
// This needs to be used along with a Platform Backend (e.g. Win32)
// Implemented features:
// [X] Renderer: User texture binding. Use 'LPDIRECT3DTEXTURE9' as ImTextureID. Read the FAQ about ImTextureID!
// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices.
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
// Read online: https://github.com/ocornut/imgui/tree/master/docs
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11.
// 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX).
// 2021-06-25: DirectX9: Explicitly disable texture state stages after >= 1.
// 2021-05-19: DirectX9: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement)
// 2021-04-23: DirectX9: Explicitly setting up more graphics states to increase compatibility with unusual non-default states.
// 2021-03-18: DirectX9: Calling IDirect3DStateBlock9::Capture() after CreateStateBlock() as a workaround for state restoring issues (see #3857).
// 2021-03-03: DirectX9: Added support for IMGUI_USE_BGRA_PACKED_COLOR in user's imconfig file.
// 2021-02-18: DirectX9: Change blending equation to preserve alpha in output buffer.
// 2019-05-29: DirectX9: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
// 2019-04-30: DirectX9: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
// 2019-03-29: Misc: Fixed erroneous assert in ImGui_ImplDX9_InvalidateDeviceObjects().
// 2019-01-16: Misc: Disabled fog before drawing UI's. Fixes issue #2288.
// 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window.
// 2018-06-08: Misc: Extracted imgui_impl_dx9.cpp/.h away from the old combined DX9+Win32 example.
// 2018-06-08: DirectX9: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle.
// 2018-05-07: Render: Saving/restoring Transform because they don't seem to be included in the StateBlock. Setting shading mode to Gouraud.
// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplDX9_RenderDrawData() in the .h file so you can call it yourself.
// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
#include "imgui.h"
#ifndef IMGUI_DISABLE
#include "imgui_impl_dx9.h"
// DirectX
#include <d3d9.h>
// DirectX data
struct ImGui_ImplDX9_Data
{
LPDIRECT3DDEVICE9 pd3dDevice;
LPDIRECT3DVERTEXBUFFER9 pVB;
LPDIRECT3DINDEXBUFFER9 pIB;
LPDIRECT3DTEXTURE9 FontTexture;
int VertexBufferSize;
int IndexBufferSize;
ImGui_ImplDX9_Data() { memset((void*)this, 0, sizeof(*this)); VertexBufferSize = 5000; IndexBufferSize = 10000; }
};
struct CUSTOMVERTEX
{
float pos[3];
D3DCOLOR col;
float uv[2];
};
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1)
#ifdef IMGUI_USE_BGRA_PACKED_COLOR
#define IMGUI_COL_TO_DX9_ARGB(_COL) (_COL)
#else
#define IMGUI_COL_TO_DX9_ARGB(_COL) (((_COL) & 0xFF00FF00) | (((_COL) & 0xFF0000) >> 16) | (((_COL) & 0xFF) << 16))
#endif
// Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts
// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
static ImGui_ImplDX9_Data* ImGui_ImplDX9_GetBackendData()
{
return ImGui::GetCurrentContext() ? (ImGui_ImplDX9_Data*)ImGui::GetIO().BackendRendererUserData : nullptr;
}
// Functions
static void ImGui_ImplDX9_SetupRenderState(ImDrawData* draw_data)
{
ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData();
// Setup viewport
D3DVIEWPORT9 vp;
vp.X = vp.Y = 0;
vp.Width = (DWORD)draw_data->DisplaySize.x;
vp.Height = (DWORD)draw_data->DisplaySize.y;
vp.MinZ = 0.0f;
vp.MaxZ = 1.0f;
bd->pd3dDevice->SetViewport(&vp);
// Setup render state: fixed-pipeline, alpha-blending, no face culling, no depth testing, shade mode (for gradient), bilinear sampling.
bd->pd3dDevice->SetPixelShader(nullptr);
bd->pd3dDevice->SetVertexShader(nullptr);
bd->pd3dDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
bd->pd3dDevice->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD);
bd->pd3dDevice->SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
bd->pd3dDevice->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
bd->pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
bd->pd3dDevice->SetRenderState(D3DRS_ZENABLE, FALSE);
bd->pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
bd->pd3dDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
bd->pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
bd->pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
bd->pd3dDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE);
bd->pd3dDevice->SetRenderState(D3DRS_SRCBLENDALPHA, D3DBLEND_ONE);
bd->pd3dDevice->SetRenderState(D3DRS_DESTBLENDALPHA, D3DBLEND_INVSRCALPHA);
bd->pd3dDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE);
bd->pd3dDevice->SetRenderState(D3DRS_FOGENABLE, FALSE);
bd->pd3dDevice->SetRenderState(D3DRS_RANGEFOGENABLE, FALSE);
bd->pd3dDevice->SetRenderState(D3DRS_SPECULARENABLE, FALSE);
bd->pd3dDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE);
bd->pd3dDevice->SetRenderState(D3DRS_CLIPPING, TRUE);
bd->pd3dDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
bd->pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
bd->pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
bd->pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
bd->pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
bd->pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
bd->pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
bd->pd3dDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
bd->pd3dDevice->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
bd->pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
bd->pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
// Setup orthographic projection matrix
// Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps.
// Being agnostic of whether <d3dx9.h> or <DirectXMath.h> can be used, we aren't relying on D3DXMatrixIdentity()/D3DXMatrixOrthoOffCenterLH() or DirectX::XMMatrixIdentity()/DirectX::XMMatrixOrthographicOffCenterLH()
{
float L = draw_data->DisplayPos.x + 0.5f;
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x + 0.5f;
float T = draw_data->DisplayPos.y + 0.5f;
float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y + 0.5f;
D3DMATRIX mat_identity = { { { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f } } };
D3DMATRIX mat_projection =
{ { {
2.0f/(R-L), 0.0f, 0.0f, 0.0f,
0.0f, 2.0f/(T-B), 0.0f, 0.0f,
0.0f, 0.0f, 0.5f, 0.0f,
(L+R)/(L-R), (T+B)/(B-T), 0.5f, 1.0f
} } };
bd->pd3dDevice->SetTransform(D3DTS_WORLD, &mat_identity);
bd->pd3dDevice->SetTransform(D3DTS_VIEW, &mat_identity);
bd->pd3dDevice->SetTransform(D3DTS_PROJECTION, &mat_projection);
}
}
// Render function.
void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data)
{
// Avoid rendering when minimized
if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f)
return;
// Create and grow buffers if needed
ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData();
if (!bd->pVB || bd->VertexBufferSize < draw_data->TotalVtxCount)
{
if (bd->pVB) { bd->pVB->Release(); bd->pVB = nullptr; }
bd->VertexBufferSize = draw_data->TotalVtxCount + 5000;
if (bd->pd3dDevice->CreateVertexBuffer(bd->VertexBufferSize * sizeof(CUSTOMVERTEX), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &bd->pVB, nullptr) < 0)
return;
}
if (!bd->pIB || bd->IndexBufferSize < draw_data->TotalIdxCount)
{
if (bd->pIB) { bd->pIB->Release(); bd->pIB = nullptr; }
bd->IndexBufferSize = draw_data->TotalIdxCount + 10000;
if (bd->pd3dDevice->CreateIndexBuffer(bd->IndexBufferSize * sizeof(ImDrawIdx), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, sizeof(ImDrawIdx) == 2 ? D3DFMT_INDEX16 : D3DFMT_INDEX32, D3DPOOL_DEFAULT, &bd->pIB, nullptr) < 0)
return;
}
// Backup the DX9 state
IDirect3DStateBlock9* d3d9_state_block = nullptr;
if (bd->pd3dDevice->CreateStateBlock(D3DSBT_ALL, &d3d9_state_block) < 0)
return;
if (d3d9_state_block->Capture() < 0)
{
d3d9_state_block->Release();
return;
}
// Backup the DX9 transform (DX9 documentation suggests that it is included in the StateBlock but it doesn't appear to)
D3DMATRIX last_world, last_view, last_projection;
bd->pd3dDevice->GetTransform(D3DTS_WORLD, &last_world);
bd->pd3dDevice->GetTransform(D3DTS_VIEW, &last_view);
bd->pd3dDevice->GetTransform(D3DTS_PROJECTION, &last_projection);
// Allocate buffers
CUSTOMVERTEX* vtx_dst;
ImDrawIdx* idx_dst;
if (bd->pVB->Lock(0, (UINT)(draw_data->TotalVtxCount * sizeof(CUSTOMVERTEX)), (void**)&vtx_dst, D3DLOCK_DISCARD) < 0)
{
d3d9_state_block->Release();
return;
}
if (bd->pIB->Lock(0, (UINT)(draw_data->TotalIdxCount * sizeof(ImDrawIdx)), (void**)&idx_dst, D3DLOCK_DISCARD) < 0)
{
bd->pVB->Unlock();
d3d9_state_block->Release();
return;
}
// Copy and convert all vertices into a single contiguous buffer, convert colors to DX9 default format.
// FIXME-OPT: This is a minor waste of resource, the ideal is to use imconfig.h and
// 1) to avoid repacking colors: #define IMGUI_USE_BGRA_PACKED_COLOR
// 2) to avoid repacking vertices: #define IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT struct ImDrawVert { ImVec2 pos; float z; ImU32 col; ImVec2 uv; }
for (int n = 0; n < draw_data->CmdListsCount; n++)
{
const ImDrawList* cmd_list = draw_data->CmdLists[n];
const ImDrawVert* vtx_src = cmd_list->VtxBuffer.Data;
for (int i = 0; i < cmd_list->VtxBuffer.Size; i++)
{
vtx_dst->pos[0] = vtx_src->pos.x;
vtx_dst->pos[1] = vtx_src->pos.y;
vtx_dst->pos[2] = 0.0f;
vtx_dst->col = IMGUI_COL_TO_DX9_ARGB(vtx_src->col);
vtx_dst->uv[0] = vtx_src->uv.x;
vtx_dst->uv[1] = vtx_src->uv.y;
vtx_dst++;
vtx_src++;
}
memcpy(idx_dst, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx));
idx_dst += cmd_list->IdxBuffer.Size;
}
bd->pVB->Unlock();
bd->pIB->Unlock();
bd->pd3dDevice->SetStreamSource(0, bd->pVB, 0, sizeof(CUSTOMVERTEX));
bd->pd3dDevice->SetIndices(bd->pIB);
bd->pd3dDevice->SetFVF(D3DFVF_CUSTOMVERTEX);
// Setup desired DX state
ImGui_ImplDX9_SetupRenderState(draw_data);
// Render command lists
// (Because we merged all buffers into a single one, we maintain our own offset into them)
int global_vtx_offset = 0;
int global_idx_offset = 0;
ImVec2 clip_off = draw_data->DisplayPos;
for (int n = 0; n < draw_data->CmdListsCount; n++)
{
const ImDrawList* cmd_list = draw_data->CmdLists[n];
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
{
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
if (pcmd->UserCallback != nullptr)
{
// User callback, registered via ImDrawList::AddCallback()
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
ImGui_ImplDX9_SetupRenderState(draw_data);
else
pcmd->UserCallback(cmd_list, pcmd);
}
else
{
// Project scissor/clipping rectangles into framebuffer space
ImVec2 clip_min(pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y);
ImVec2 clip_max(pcmd->ClipRect.z - clip_off.x, pcmd->ClipRect.w - clip_off.y);
if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
continue;
// Apply Scissor/clipping rectangle, Bind texture, Draw
const RECT r = { (LONG)clip_min.x, (LONG)clip_min.y, (LONG)clip_max.x, (LONG)clip_max.y };
const LPDIRECT3DTEXTURE9 texture = (LPDIRECT3DTEXTURE9)pcmd->GetTexID();
bd->pd3dDevice->SetTexture(0, texture);
bd->pd3dDevice->SetScissorRect(&r);
bd->pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, pcmd->VtxOffset + global_vtx_offset, 0, (UINT)cmd_list->VtxBuffer.Size, pcmd->IdxOffset + global_idx_offset, pcmd->ElemCount / 3);
}
}
global_idx_offset += cmd_list->IdxBuffer.Size;
global_vtx_offset += cmd_list->VtxBuffer.Size;
}
// Restore the DX9 transform
bd->pd3dDevice->SetTransform(D3DTS_WORLD, &last_world);
bd->pd3dDevice->SetTransform(D3DTS_VIEW, &last_view);
bd->pd3dDevice->SetTransform(D3DTS_PROJECTION, &last_projection);
// Restore the DX9 state
d3d9_state_block->Apply();
d3d9_state_block->Release();
}
bool ImGui_ImplDX9_Init(IDirect3DDevice9* device)
{
ImGuiIO& io = ImGui::GetIO();
IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!");
// Setup backend capabilities flags
ImGui_ImplDX9_Data* bd = IM_NEW(ImGui_ImplDX9_Data)();
io.BackendRendererUserData = (void*)bd;
io.BackendRendererName = "imgui_impl_dx9";
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
bd->pd3dDevice = device;
bd->pd3dDevice->AddRef();
return true;
}
void ImGui_ImplDX9_Shutdown()
{
ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData();
IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?");
ImGuiIO& io = ImGui::GetIO();
ImGui_ImplDX9_InvalidateDeviceObjects();
if (bd->pd3dDevice) { bd->pd3dDevice->Release(); }
io.BackendRendererName = nullptr;
io.BackendRendererUserData = nullptr;
io.BackendFlags &= ~ImGuiBackendFlags_RendererHasVtxOffset;
IM_DELETE(bd);
}
static bool ImGui_ImplDX9_CreateFontsTexture()
{
// Build texture atlas
ImGuiIO& io = ImGui::GetIO();
ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData();
unsigned char* pixels;
int width, height, bytes_per_pixel;
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height, &bytes_per_pixel);
// Convert RGBA32 to BGRA32 (because RGBA32 is not well supported by DX9 devices)
#ifndef IMGUI_USE_BGRA_PACKED_COLOR
if (io.Fonts->TexPixelsUseColors)
{
ImU32* dst_start = (ImU32*)ImGui::MemAlloc((size_t)width * height * bytes_per_pixel);
for (ImU32* src = (ImU32*)pixels, *dst = dst_start, *dst_end = dst_start + (size_t)width * height; dst < dst_end; src++, dst++)
*dst = IMGUI_COL_TO_DX9_ARGB(*src);
pixels = (unsigned char*)dst_start;
}
#endif
// Upload texture to graphics system
bd->FontTexture = nullptr;
if (bd->pd3dDevice->CreateTexture(width, height, 1, D3DUSAGE_DYNAMIC, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &bd->FontTexture, nullptr) < 0)
return false;
D3DLOCKED_RECT tex_locked_rect;
if (bd->FontTexture->LockRect(0, &tex_locked_rect, nullptr, 0) != D3D_OK)
return false;
for (int y = 0; y < height; y++)
memcpy((unsigned char*)tex_locked_rect.pBits + (size_t)tex_locked_rect.Pitch * y, pixels + (size_t)width * bytes_per_pixel * y, (size_t)width * bytes_per_pixel);
bd->FontTexture->UnlockRect(0);
// Store our identifier
io.Fonts->SetTexID((ImTextureID)bd->FontTexture);
#ifndef IMGUI_USE_BGRA_PACKED_COLOR
if (io.Fonts->TexPixelsUseColors)
ImGui::MemFree(pixels);
#endif
return true;
}
bool ImGui_ImplDX9_CreateDeviceObjects()
{
ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData();
if (!bd || !bd->pd3dDevice)
return false;
if (!ImGui_ImplDX9_CreateFontsTexture())
return false;
return true;
}
void ImGui_ImplDX9_InvalidateDeviceObjects()
{
ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData();
if (!bd || !bd->pd3dDevice)
return;
if (bd->pVB) { bd->pVB->Release(); bd->pVB = nullptr; }
if (bd->pIB) { bd->pIB->Release(); bd->pIB = nullptr; }
if (bd->FontTexture) { bd->FontTexture->Release(); bd->FontTexture = nullptr; ImGui::GetIO().Fonts->SetTexID(0); } // We copied bd->pFontTextureView to io.Fonts->TexID so let's clear that as well.
}
void ImGui_ImplDX9_NewFrame()
{
ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData();
IM_ASSERT(bd != nullptr && "Did you call ImGui_ImplDX9_Init()?");
if (!bd->FontTexture)
ImGui_ImplDX9_CreateDeviceObjects();
}
//-----------------------------------------------------------------------------
#endif // #ifndef IMGUI_DISABLE

View File

@ -0,0 +1,28 @@
// dear imgui: Renderer Backend for DirectX9
// This needs to be used along with a Platform Backend (e.g. Win32)
// Implemented features:
// [X] Renderer: User texture binding. Use 'LPDIRECT3DTEXTURE9' as ImTextureID. Read the FAQ about ImTextureID!
// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices.
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
// Read online: https://github.com/ocornut/imgui/tree/master/docs
#pragma once
#include "imgui.h" // IMGUI_IMPL_API
#ifndef IMGUI_DISABLE
struct IDirect3DDevice9;
IMGUI_IMPL_API bool ImGui_ImplDX9_Init(IDirect3DDevice9* device);
IMGUI_IMPL_API void ImGui_ImplDX9_Shutdown();
IMGUI_IMPL_API void ImGui_ImplDX9_NewFrame();
IMGUI_IMPL_API void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data);
// Use if you want to reset your rendering device without losing Dear ImGui state.
IMGUI_IMPL_API bool ImGui_ImplDX9_CreateDeviceObjects();
IMGUI_IMPL_API void ImGui_ImplDX9_InvalidateDeviceObjects();
#endif // #ifndef IMGUI_DISABLE

View File

@ -0,0 +1,864 @@
// dear imgui: Platform Backend for Windows (standard windows API for 32-bits AND 64-bits applications)
// This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..)
// Implemented features:
// [X] Platform: Clipboard support (for Win32 this is actually part of core dear imgui)
// [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen/Pen.
// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy VK_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set]
// [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
// Read online: https://github.com/ocornut/imgui/tree/master/docs
#include "imgui.h"
#ifndef IMGUI_DISABLE
#include "imgui_impl_win32.h"
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#include <windowsx.h> // GET_X_LPARAM(), GET_Y_LPARAM()
#include <tchar.h>
#include <dwmapi.h>
// Configuration flags to add in your imconfig.h file:
//#define IMGUI_IMPL_WIN32_DISABLE_GAMEPAD // Disable gamepad support. This was meaningful before <1.81 but we now load XInput dynamically so the option is now less relevant.
// Using XInput for gamepad (will load DLL dynamically)
#ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
#include <xinput.h>
typedef DWORD (WINAPI *PFN_XInputGetCapabilities)(DWORD, DWORD, XINPUT_CAPABILITIES*);
typedef DWORD (WINAPI *PFN_XInputGetState)(DWORD, XINPUT_STATE*);
#endif
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2023-04-19: Added ImGui_ImplWin32_InitForOpenGL() to facilitate combining raw Win32/Winapi with OpenGL. (#3218)
// 2023-04-04: Inputs: Added support for io.AddMouseSourceEvent() to discriminate ImGuiMouseSource_Mouse/ImGuiMouseSource_TouchScreen/ImGuiMouseSource_Pen. (#2702)
// 2023-02-15: Inputs: Use WM_NCMOUSEMOVE / WM_NCMOUSELEAVE to track mouse position over non-client area (e.g. OS decorations) when app is not focused. (#6045, #6162)
// 2023-02-02: Inputs: Flipping WM_MOUSEHWHEEL (horizontal mouse-wheel) value to match other backends and offer consistent horizontal scrolling direction. (#4019, #6096, #1463)
// 2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11.
// 2022-09-28: Inputs: Convert WM_CHAR values with MultiByteToWideChar() when window class was registered as MBCS (not Unicode).
// 2022-09-26: Inputs: Renamed ImGuiKey_ModXXX introduced in 1.87 to ImGuiMod_XXX (old names still supported).
// 2022-01-26: Inputs: replaced short-lived io.AddKeyModsEvent() (added two weeks ago) with io.AddKeyEvent() using ImGuiKey_ModXXX flags. Sorry for the confusion.
// 2021-01-20: Inputs: calling new io.AddKeyAnalogEvent() for gamepad support, instead of writing directly to io.NavInputs[].
// 2022-01-17: Inputs: calling new io.AddMousePosEvent(), io.AddMouseButtonEvent(), io.AddMouseWheelEvent() API (1.87+).
// 2022-01-17: Inputs: always update key mods next and before a key event (not in NewFrame) to fix input queue with very low framerates.
// 2022-01-12: Inputs: Update mouse inputs using WM_MOUSEMOVE/WM_MOUSELEAVE + fallback to provide it when focused but not hovered/captured. More standard and will allow us to pass it to future input queue API.
// 2022-01-12: Inputs: Maintain our own copy of MouseButtonsDown mask instead of using ImGui::IsAnyMouseDown() which will be obsoleted.
// 2022-01-10: Inputs: calling new io.AddKeyEvent(), io.AddKeyModsEvent() + io.SetKeyEventNativeData() API (1.87+). Support for full ImGuiKey range.
// 2021-12-16: Inputs: Fill VK_LCONTROL/VK_RCONTROL/VK_LSHIFT/VK_RSHIFT/VK_LMENU/VK_RMENU for completeness.
// 2021-08-17: Calling io.AddFocusEvent() on WM_SETFOCUS/WM_KILLFOCUS messages.
// 2021-08-02: Inputs: Fixed keyboard modifiers being reported when host window doesn't have focus.
// 2021-07-29: Inputs: MousePos is correctly reported when the host platform window is hovered but not focused (using TrackMouseEvent() to receive WM_MOUSELEAVE events).
// 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX).
// 2021-06-08: Fixed ImGui_ImplWin32_EnableDpiAwareness() and ImGui_ImplWin32_GetDpiScaleForMonitor() to handle Windows 8.1/10 features without a manifest (per-monitor DPI, and properly calls SetProcessDpiAwareness() on 8.1).
// 2021-03-23: Inputs: Clearing keyboard down array when losing focus (WM_KILLFOCUS).
// 2021-02-18: Added ImGui_ImplWin32_EnableAlphaCompositing(). Non Visual Studio users will need to link with dwmapi.lib (MinGW/gcc: use -ldwmapi).
// 2021-02-17: Fixed ImGui_ImplWin32_EnableDpiAwareness() attempting to get SetProcessDpiAwareness from shcore.dll on Windows 8 whereas it is only supported on Windows 8.1.
// 2021-01-25: Inputs: Dynamically loading XInput DLL.
// 2020-12-04: Misc: Fixed setting of io.DisplaySize to invalid/uninitialized data when after hwnd has been closed.
// 2020-03-03: Inputs: Calling AddInputCharacterUTF16() to support surrogate pairs leading to codepoint >= 0x10000 (for more complete CJK inputs)
// 2020-02-17: Added ImGui_ImplWin32_EnableDpiAwareness(), ImGui_ImplWin32_GetDpiScaleForHwnd(), ImGui_ImplWin32_GetDpiScaleForMonitor() helper functions.
// 2020-01-14: Inputs: Added support for #define IMGUI_IMPL_WIN32_DISABLE_GAMEPAD/IMGUI_IMPL_WIN32_DISABLE_LINKING_XINPUT.
// 2019-12-05: Inputs: Added support for ImGuiMouseCursor_NotAllowed mouse cursor.
// 2019-05-11: Inputs: Don't filter value from WM_CHAR before calling AddInputCharacter().
// 2019-01-17: Misc: Using GetForegroundWindow()+IsChild() instead of GetActiveWindow() to be compatible with windows created in a different thread or parent.
// 2019-01-17: Inputs: Added support for mouse buttons 4 and 5 via WM_XBUTTON* messages.
// 2019-01-15: Inputs: Added support for XInput gamepads (if ImGuiConfigFlags_NavEnableGamepad is set by user application).
// 2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window.
// 2018-06-29: Inputs: Added support for the ImGuiMouseCursor_Hand cursor.
// 2018-06-10: Inputs: Fixed handling of mouse wheel messages to support fine position messages (typically sent by track-pads).
// 2018-06-08: Misc: Extracted imgui_impl_win32.cpp/.h away from the old combined DX9/DX10/DX11/DX12 examples.
// 2018-03-20: Misc: Setup io.BackendFlags ImGuiBackendFlags_HasMouseCursors and ImGuiBackendFlags_HasSetMousePos flags + honor ImGuiConfigFlags_NoMouseCursorChange flag.
// 2018-02-20: Inputs: Added support for mouse cursors (ImGui::GetMouseCursor() value and WM_SETCURSOR message handling).
// 2018-02-06: Inputs: Added mapping for ImGuiKey_Space.
// 2018-02-06: Inputs: Honoring the io.WantSetMousePos by repositioning the mouse (when using navigation and ImGuiConfigFlags_NavMoveMouse is set).
// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
// 2018-01-20: Inputs: Added Horizontal Mouse Wheel support.
// 2018-01-08: Inputs: Added mapping for ImGuiKey_Insert.
// 2018-01-05: Inputs: Added WM_LBUTTONDBLCLK double-click handlers for window classes with the CS_DBLCLKS flag.
// 2017-10-23: Inputs: Added WM_SYSKEYDOWN / WM_SYSKEYUP handlers so e.g. the VK_MENU key can be read.
// 2017-10-23: Inputs: Using Win32 ::SetCapture/::GetCapture() to retrieve mouse positions outside the client area when dragging.
// 2016-11-12: Inputs: Only call Win32 ::SetCursor(nullptr) when io.MouseDrawCursor is set.
struct ImGui_ImplWin32_Data
{
HWND hWnd;
HWND MouseHwnd;
int MouseTrackedArea; // 0: not tracked, 1: client are, 2: non-client area
int MouseButtonsDown;
INT64 Time;
INT64 TicksPerSecond;
ImGuiMouseCursor LastMouseCursor;
#ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
bool HasGamepad;
bool WantUpdateHasGamepad;
HMODULE XInputDLL;
PFN_XInputGetCapabilities XInputGetCapabilities;
PFN_XInputGetState XInputGetState;
#endif
ImGui_ImplWin32_Data() { memset((void*)this, 0, sizeof(*this)); }
};
// Backend data stored in io.BackendPlatformUserData to allow support for multiple Dear ImGui contexts
// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
// FIXME: multi-context support is not well tested and probably dysfunctional in this backend.
// FIXME: some shared resources (mouse cursor shape, gamepad) are mishandled when using multi-context.
static ImGui_ImplWin32_Data* ImGui_ImplWin32_GetBackendData()
{
return ImGui::GetCurrentContext() ? (ImGui_ImplWin32_Data*)ImGui::GetIO().BackendPlatformUserData : nullptr;
}
// Functions
static bool ImGui_ImplWin32_InitEx(void* hwnd, bool platform_has_own_dc)
{
ImGuiIO& io = ImGui::GetIO();
IM_ASSERT(io.BackendPlatformUserData == nullptr && "Already initialized a platform backend!");
INT64 perf_frequency, perf_counter;
if (!::QueryPerformanceFrequency((LARGE_INTEGER*)&perf_frequency))
return false;
if (!::QueryPerformanceCounter((LARGE_INTEGER*)&perf_counter))
return false;
// Setup backend capabilities flags
ImGui_ImplWin32_Data* bd = IM_NEW(ImGui_ImplWin32_Data)();
io.BackendPlatformUserData = (void*)bd;
io.BackendPlatformName = "imgui_impl_win32";
io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used)
bd->hWnd = (HWND)hwnd;
bd->TicksPerSecond = perf_frequency;
bd->Time = perf_counter;
bd->LastMouseCursor = ImGuiMouseCursor_COUNT;
// Set platform dependent data in viewport
ImGui::GetMainViewport()->PlatformHandleRaw = (void*)hwnd;
IM_UNUSED(platform_has_own_dc); // Used in 'docking' branch
// Dynamically load XInput library
#ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
bd->WantUpdateHasGamepad = true;
const char* xinput_dll_names[] =
{
"xinput1_4.dll", // Windows 8+
"xinput1_3.dll", // DirectX SDK
"xinput9_1_0.dll", // Windows Vista, Windows 7
"xinput1_2.dll", // DirectX SDK
"xinput1_1.dll" // DirectX SDK
};
for (int n = 0; n < IM_ARRAYSIZE(xinput_dll_names); n++)
if (HMODULE dll = ::LoadLibraryA(xinput_dll_names[n]))
{
bd->XInputDLL = dll;
bd->XInputGetCapabilities = (PFN_XInputGetCapabilities)::GetProcAddress(dll, "XInputGetCapabilities");
bd->XInputGetState = (PFN_XInputGetState)::GetProcAddress(dll, "XInputGetState");
break;
}
#endif // IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
return true;
}
IMGUI_IMPL_API bool ImGui_ImplWin32_Init(void* hwnd)
{
return ImGui_ImplWin32_InitEx(hwnd, false);
}
IMGUI_IMPL_API bool ImGui_ImplWin32_InitForOpenGL(void* hwnd)
{
// OpenGL needs CS_OWNDC
return ImGui_ImplWin32_InitEx(hwnd, true);
}
void ImGui_ImplWin32_Shutdown()
{
ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData();
IM_ASSERT(bd != nullptr && "No platform backend to shutdown, or already shutdown?");
ImGuiIO& io = ImGui::GetIO();
// Unload XInput library
#ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
if (bd->XInputDLL)
::FreeLibrary(bd->XInputDLL);
#endif // IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
io.BackendPlatformName = nullptr;
io.BackendPlatformUserData = nullptr;
io.BackendFlags &= ~(ImGuiBackendFlags_HasMouseCursors | ImGuiBackendFlags_HasSetMousePos | ImGuiBackendFlags_HasGamepad);
IM_DELETE(bd);
}
static bool ImGui_ImplWin32_UpdateMouseCursor()
{
ImGuiIO& io = ImGui::GetIO();
if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange)
return false;
ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor();
if (imgui_cursor == ImGuiMouseCursor_None || io.MouseDrawCursor)
{
// Hide OS mouse cursor if imgui is drawing it or if it wants no cursor
::SetCursor(nullptr);
}
else
{
// Show OS mouse cursor
LPTSTR win32_cursor = IDC_ARROW;
switch (imgui_cursor)
{
case ImGuiMouseCursor_Arrow: win32_cursor = IDC_ARROW; break;
case ImGuiMouseCursor_TextInput: win32_cursor = IDC_IBEAM; break;
case ImGuiMouseCursor_ResizeAll: win32_cursor = IDC_SIZEALL; break;
case ImGuiMouseCursor_ResizeEW: win32_cursor = IDC_SIZEWE; break;
case ImGuiMouseCursor_ResizeNS: win32_cursor = IDC_SIZENS; break;
case ImGuiMouseCursor_ResizeNESW: win32_cursor = IDC_SIZENESW; break;
case ImGuiMouseCursor_ResizeNWSE: win32_cursor = IDC_SIZENWSE; break;
case ImGuiMouseCursor_Hand: win32_cursor = IDC_HAND; break;
case ImGuiMouseCursor_NotAllowed: win32_cursor = IDC_NO; break;
}
::SetCursor(::LoadCursor(nullptr, win32_cursor));
}
return true;
}
static bool IsVkDown(int vk)
{
return (::GetKeyState(vk) & 0x8000) != 0;
}
static void ImGui_ImplWin32_AddKeyEvent(ImGuiKey key, bool down, int native_keycode, int native_scancode = -1)
{
ImGuiIO& io = ImGui::GetIO();
io.AddKeyEvent(key, down);
io.SetKeyEventNativeData(key, native_keycode, native_scancode); // To support legacy indexing (<1.87 user code)
IM_UNUSED(native_scancode);
}
static void ImGui_ImplWin32_ProcessKeyEventsWorkarounds()
{
// Left & right Shift keys: when both are pressed together, Windows tend to not generate the WM_KEYUP event for the first released one.
if (ImGui::IsKeyDown(ImGuiKey_LeftShift) && !IsVkDown(VK_LSHIFT))
ImGui_ImplWin32_AddKeyEvent(ImGuiKey_LeftShift, false, VK_LSHIFT);
if (ImGui::IsKeyDown(ImGuiKey_RightShift) && !IsVkDown(VK_RSHIFT))
ImGui_ImplWin32_AddKeyEvent(ImGuiKey_RightShift, false, VK_RSHIFT);
// Sometimes WM_KEYUP for Win key is not passed down to the app (e.g. for Win+V on some setups, according to GLFW).
if (ImGui::IsKeyDown(ImGuiKey_LeftSuper) && !IsVkDown(VK_LWIN))
ImGui_ImplWin32_AddKeyEvent(ImGuiKey_LeftSuper, false, VK_LWIN);
if (ImGui::IsKeyDown(ImGuiKey_RightSuper) && !IsVkDown(VK_RWIN))
ImGui_ImplWin32_AddKeyEvent(ImGuiKey_RightSuper, false, VK_RWIN);
}
static void ImGui_ImplWin32_UpdateKeyModifiers()
{
ImGuiIO& io = ImGui::GetIO();
io.AddKeyEvent(ImGuiMod_Ctrl, IsVkDown(VK_CONTROL));
io.AddKeyEvent(ImGuiMod_Shift, IsVkDown(VK_SHIFT));
io.AddKeyEvent(ImGuiMod_Alt, IsVkDown(VK_MENU));
io.AddKeyEvent(ImGuiMod_Super, IsVkDown(VK_APPS));
}
static void ImGui_ImplWin32_UpdateMouseData()
{
ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData();
ImGuiIO& io = ImGui::GetIO();
IM_ASSERT(bd->hWnd != 0);
HWND focused_window = ::GetForegroundWindow();
const bool is_app_focused = (focused_window == bd->hWnd);
if (is_app_focused)
{
// (Optional) Set OS mouse position from Dear ImGui if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user)
if (io.WantSetMousePos)
{
POINT pos = { (int)io.MousePos.x, (int)io.MousePos.y };
if (::ClientToScreen(bd->hWnd, &pos))
::SetCursorPos(pos.x, pos.y);
}
// (Optional) Fallback to provide mouse position when focused (WM_MOUSEMOVE already provides this when hovered or captured)
// This also fills a short gap when clicking non-client area: WM_NCMOUSELEAVE -> modal OS move -> gap -> WM_NCMOUSEMOVE
if (!io.WantSetMousePos && bd->MouseTrackedArea == 0)
{
POINT pos;
if (::GetCursorPos(&pos) && ::ScreenToClient(bd->hWnd, &pos))
io.AddMousePosEvent((float)pos.x, (float)pos.y);
}
}
}
// Gamepad navigation mapping
static void ImGui_ImplWin32_UpdateGamepads()
{
#ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
ImGuiIO& io = ImGui::GetIO();
ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData();
//if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0) // FIXME: Technically feeding gamepad shouldn't depend on this now that they are regular inputs.
// return;
// Calling XInputGetState() every frame on disconnected gamepads is unfortunately too slow.
// Instead we refresh gamepad availability by calling XInputGetCapabilities() _only_ after receiving WM_DEVICECHANGE.
if (bd->WantUpdateHasGamepad)
{
XINPUT_CAPABILITIES caps = {};
bd->HasGamepad = bd->XInputGetCapabilities ? (bd->XInputGetCapabilities(0, XINPUT_FLAG_GAMEPAD, &caps) == ERROR_SUCCESS) : false;
bd->WantUpdateHasGamepad = false;
}
io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad;
XINPUT_STATE xinput_state;
XINPUT_GAMEPAD& gamepad = xinput_state.Gamepad;
if (!bd->HasGamepad || bd->XInputGetState == nullptr || bd->XInputGetState(0, &xinput_state) != ERROR_SUCCESS)
return;
io.BackendFlags |= ImGuiBackendFlags_HasGamepad;
#define IM_SATURATE(V) (V < 0.0f ? 0.0f : V > 1.0f ? 1.0f : V)
#define MAP_BUTTON(KEY_NO, BUTTON_ENUM) { io.AddKeyEvent(KEY_NO, (gamepad.wButtons & BUTTON_ENUM) != 0); }
#define MAP_ANALOG(KEY_NO, VALUE, V0, V1) { float vn = (float)(VALUE - V0) / (float)(V1 - V0); io.AddKeyAnalogEvent(KEY_NO, vn > 0.10f, IM_SATURATE(vn)); }
MAP_BUTTON(ImGuiKey_GamepadStart, XINPUT_GAMEPAD_START);
MAP_BUTTON(ImGuiKey_GamepadBack, XINPUT_GAMEPAD_BACK);
MAP_BUTTON(ImGuiKey_GamepadFaceLeft, XINPUT_GAMEPAD_X);
MAP_BUTTON(ImGuiKey_GamepadFaceRight, XINPUT_GAMEPAD_B);
MAP_BUTTON(ImGuiKey_GamepadFaceUp, XINPUT_GAMEPAD_Y);
MAP_BUTTON(ImGuiKey_GamepadFaceDown, XINPUT_GAMEPAD_A);
MAP_BUTTON(ImGuiKey_GamepadDpadLeft, XINPUT_GAMEPAD_DPAD_LEFT);
MAP_BUTTON(ImGuiKey_GamepadDpadRight, XINPUT_GAMEPAD_DPAD_RIGHT);
MAP_BUTTON(ImGuiKey_GamepadDpadUp, XINPUT_GAMEPAD_DPAD_UP);
MAP_BUTTON(ImGuiKey_GamepadDpadDown, XINPUT_GAMEPAD_DPAD_DOWN);
MAP_BUTTON(ImGuiKey_GamepadL1, XINPUT_GAMEPAD_LEFT_SHOULDER);
MAP_BUTTON(ImGuiKey_GamepadR1, XINPUT_GAMEPAD_RIGHT_SHOULDER);
MAP_ANALOG(ImGuiKey_GamepadL2, gamepad.bLeftTrigger, XINPUT_GAMEPAD_TRIGGER_THRESHOLD, 255);
MAP_ANALOG(ImGuiKey_GamepadR2, gamepad.bRightTrigger, XINPUT_GAMEPAD_TRIGGER_THRESHOLD, 255);
MAP_BUTTON(ImGuiKey_GamepadL3, XINPUT_GAMEPAD_LEFT_THUMB);
MAP_BUTTON(ImGuiKey_GamepadR3, XINPUT_GAMEPAD_RIGHT_THUMB);
MAP_ANALOG(ImGuiKey_GamepadLStickLeft, gamepad.sThumbLX, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32768);
MAP_ANALOG(ImGuiKey_GamepadLStickRight, gamepad.sThumbLX, +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, +32767);
MAP_ANALOG(ImGuiKey_GamepadLStickUp, gamepad.sThumbLY, +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, +32767);
MAP_ANALOG(ImGuiKey_GamepadLStickDown, gamepad.sThumbLY, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32768);
MAP_ANALOG(ImGuiKey_GamepadRStickLeft, gamepad.sThumbRX, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32768);
MAP_ANALOG(ImGuiKey_GamepadRStickRight, gamepad.sThumbRX, +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, +32767);
MAP_ANALOG(ImGuiKey_GamepadRStickUp, gamepad.sThumbRY, +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, +32767);
MAP_ANALOG(ImGuiKey_GamepadRStickDown, gamepad.sThumbRY, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32768);
#undef MAP_BUTTON
#undef MAP_ANALOG
#endif // #ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
}
void ImGui_ImplWin32_NewFrame()
{
ImGuiIO& io = ImGui::GetIO();
ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData();
IM_ASSERT(bd != nullptr && "Did you call ImGui_ImplWin32_Init()?");
// Setup display size (every frame to accommodate for window resizing)
RECT rect = { 0, 0, 0, 0 };
::GetClientRect(bd->hWnd, &rect);
io.DisplaySize = ImVec2((float)(rect.right - rect.left), (float)(rect.bottom - rect.top));
// Setup time step
INT64 current_time = 0;
::QueryPerformanceCounter((LARGE_INTEGER*)&current_time);
io.DeltaTime = (float)(current_time - bd->Time) / bd->TicksPerSecond;
bd->Time = current_time;
// Update OS mouse position
ImGui_ImplWin32_UpdateMouseData();
// Process workarounds for known Windows key handling issues
ImGui_ImplWin32_ProcessKeyEventsWorkarounds();
// Update OS mouse cursor with the cursor requested by imgui
ImGuiMouseCursor mouse_cursor = io.MouseDrawCursor ? ImGuiMouseCursor_None : ImGui::GetMouseCursor();
if (bd->LastMouseCursor != mouse_cursor)
{
bd->LastMouseCursor = mouse_cursor;
ImGui_ImplWin32_UpdateMouseCursor();
}
// Update game controllers (if enabled and available)
ImGui_ImplWin32_UpdateGamepads();
}
// There is no distinct VK_xxx for keypad enter, instead it is VK_RETURN + KF_EXTENDED, we assign it an arbitrary value to make code more readable (VK_ codes go up to 255)
#define IM_VK_KEYPAD_ENTER (VK_RETURN + 256)
// Map VK_xxx to ImGuiKey_xxx.
static ImGuiKey ImGui_ImplWin32_VirtualKeyToImGuiKey(WPARAM wParam)
{
switch (wParam)
{
case VK_TAB: return ImGuiKey_Tab;
case VK_LEFT: return ImGuiKey_LeftArrow;
case VK_RIGHT: return ImGuiKey_RightArrow;
case VK_UP: return ImGuiKey_UpArrow;
case VK_DOWN: return ImGuiKey_DownArrow;
case VK_PRIOR: return ImGuiKey_PageUp;
case VK_NEXT: return ImGuiKey_PageDown;
case VK_HOME: return ImGuiKey_Home;
case VK_END: return ImGuiKey_End;
case VK_INSERT: return ImGuiKey_Insert;
case VK_DELETE: return ImGuiKey_Delete;
case VK_BACK: return ImGuiKey_Backspace;
case VK_SPACE: return ImGuiKey_Space;
case VK_RETURN: return ImGuiKey_Enter;
case VK_ESCAPE: return ImGuiKey_Escape;
case VK_OEM_7: return ImGuiKey_Apostrophe;
case VK_OEM_COMMA: return ImGuiKey_Comma;
case VK_OEM_MINUS: return ImGuiKey_Minus;
case VK_OEM_PERIOD: return ImGuiKey_Period;
case VK_OEM_2: return ImGuiKey_Slash;
case VK_OEM_1: return ImGuiKey_Semicolon;
case VK_OEM_PLUS: return ImGuiKey_Equal;
case VK_OEM_4: return ImGuiKey_LeftBracket;
case VK_OEM_5: return ImGuiKey_Backslash;
case VK_OEM_6: return ImGuiKey_RightBracket;
case VK_OEM_3: return ImGuiKey_GraveAccent;
case VK_CAPITAL: return ImGuiKey_CapsLock;
case VK_SCROLL: return ImGuiKey_ScrollLock;
case VK_NUMLOCK: return ImGuiKey_NumLock;
case VK_SNAPSHOT: return ImGuiKey_PrintScreen;
case VK_PAUSE: return ImGuiKey_Pause;
case VK_NUMPAD0: return ImGuiKey_Keypad0;
case VK_NUMPAD1: return ImGuiKey_Keypad1;
case VK_NUMPAD2: return ImGuiKey_Keypad2;
case VK_NUMPAD3: return ImGuiKey_Keypad3;
case VK_NUMPAD4: return ImGuiKey_Keypad4;
case VK_NUMPAD5: return ImGuiKey_Keypad5;
case VK_NUMPAD6: return ImGuiKey_Keypad6;
case VK_NUMPAD7: return ImGuiKey_Keypad7;
case VK_NUMPAD8: return ImGuiKey_Keypad8;
case VK_NUMPAD9: return ImGuiKey_Keypad9;
case VK_DECIMAL: return ImGuiKey_KeypadDecimal;
case VK_DIVIDE: return ImGuiKey_KeypadDivide;
case VK_MULTIPLY: return ImGuiKey_KeypadMultiply;
case VK_SUBTRACT: return ImGuiKey_KeypadSubtract;
case VK_ADD: return ImGuiKey_KeypadAdd;
case IM_VK_KEYPAD_ENTER: return ImGuiKey_KeypadEnter;
case VK_LSHIFT: return ImGuiKey_LeftShift;
case VK_LCONTROL: return ImGuiKey_LeftCtrl;
case VK_LMENU: return ImGuiKey_LeftAlt;
case VK_LWIN: return ImGuiKey_LeftSuper;
case VK_RSHIFT: return ImGuiKey_RightShift;
case VK_RCONTROL: return ImGuiKey_RightCtrl;
case VK_RMENU: return ImGuiKey_RightAlt;
case VK_RWIN: return ImGuiKey_RightSuper;
case VK_APPS: return ImGuiKey_Menu;
case '0': return ImGuiKey_0;
case '1': return ImGuiKey_1;
case '2': return ImGuiKey_2;
case '3': return ImGuiKey_3;
case '4': return ImGuiKey_4;
case '5': return ImGuiKey_5;
case '6': return ImGuiKey_6;
case '7': return ImGuiKey_7;
case '8': return ImGuiKey_8;
case '9': return ImGuiKey_9;
case 'A': return ImGuiKey_A;
case 'B': return ImGuiKey_B;
case 'C': return ImGuiKey_C;
case 'D': return ImGuiKey_D;
case 'E': return ImGuiKey_E;
case 'F': return ImGuiKey_F;
case 'G': return ImGuiKey_G;
case 'H': return ImGuiKey_H;
case 'I': return ImGuiKey_I;
case 'J': return ImGuiKey_J;
case 'K': return ImGuiKey_K;
case 'L': return ImGuiKey_L;
case 'M': return ImGuiKey_M;
case 'N': return ImGuiKey_N;
case 'O': return ImGuiKey_O;
case 'P': return ImGuiKey_P;
case 'Q': return ImGuiKey_Q;
case 'R': return ImGuiKey_R;
case 'S': return ImGuiKey_S;
case 'T': return ImGuiKey_T;
case 'U': return ImGuiKey_U;
case 'V': return ImGuiKey_V;
case 'W': return ImGuiKey_W;
case 'X': return ImGuiKey_X;
case 'Y': return ImGuiKey_Y;
case 'Z': return ImGuiKey_Z;
case VK_F1: return ImGuiKey_F1;
case VK_F2: return ImGuiKey_F2;
case VK_F3: return ImGuiKey_F3;
case VK_F4: return ImGuiKey_F4;
case VK_F5: return ImGuiKey_F5;
case VK_F6: return ImGuiKey_F6;
case VK_F7: return ImGuiKey_F7;
case VK_F8: return ImGuiKey_F8;
case VK_F9: return ImGuiKey_F9;
case VK_F10: return ImGuiKey_F10;
case VK_F11: return ImGuiKey_F11;
case VK_F12: return ImGuiKey_F12;
default: return ImGuiKey_None;
}
}
// Allow compilation with old Windows SDK. MinGW doesn't have default _WIN32_WINNT/WINVER versions.
#ifndef WM_MOUSEHWHEEL
#define WM_MOUSEHWHEEL 0x020E
#endif
#ifndef DBT_DEVNODES_CHANGED
#define DBT_DEVNODES_CHANGED 0x0007
#endif
// Win32 message handler (process Win32 mouse/keyboard inputs, etc.)
// Call from your application's message handler. Keep calling your message handler unless this function returns TRUE.
// When implementing your own backend, you can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if Dear ImGui wants to use your inputs.
// - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application, or clear/overwrite your copy of the mouse data.
// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data.
// Generally you may always pass all inputs to Dear ImGui, and hide them from your application based on those two flags.
// PS: In this Win32 handler, we use the capture API (GetCapture/SetCapture/ReleaseCapture) to be able to read mouse coordinates when dragging mouse outside of our window bounds.
// PS: We treat DBLCLK messages as regular mouse down messages, so this code will work on windows classes that have the CS_DBLCLKS flag set. Our own example app code doesn't set this flag.
#if 0
// Copy this line into your .cpp file to forward declare the function.
extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
#endif
// See https://learn.microsoft.com/en-us/windows/win32/tablet/system-events-and-mouse-messages
// Prefer to call this at the top of the message handler to avoid the possibility of other Win32 calls interfering with this.
static ImGuiMouseSource GetMouseSourceFromMessageExtraInfo()
{
LPARAM extra_info = ::GetMessageExtraInfo();
if ((extra_info & 0xFFFFFF80) == 0xFF515700)
return ImGuiMouseSource_Pen;
if ((extra_info & 0xFFFFFF80) == 0xFF515780)
return ImGuiMouseSource_TouchScreen;
return ImGuiMouseSource_Mouse;
}
IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
if (ImGui::GetCurrentContext() == nullptr)
return 0;
ImGuiIO& io = ImGui::GetIO();
ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData();
switch (msg)
{
case WM_MOUSEMOVE:
case WM_NCMOUSEMOVE:
{
// We need to call TrackMouseEvent in order to receive WM_MOUSELEAVE events
ImGuiMouseSource mouse_source = GetMouseSourceFromMessageExtraInfo();
const int area = (msg == WM_MOUSEMOVE) ? 1 : 2;
bd->MouseHwnd = hwnd;
if (bd->MouseTrackedArea != area)
{
TRACKMOUSEEVENT tme_cancel = { sizeof(tme_cancel), TME_CANCEL, hwnd, 0 };
TRACKMOUSEEVENT tme_track = { sizeof(tme_track), (DWORD)((area == 2) ? (TME_LEAVE | TME_NONCLIENT) : TME_LEAVE), hwnd, 0 };
if (bd->MouseTrackedArea != 0)
::TrackMouseEvent(&tme_cancel);
::TrackMouseEvent(&tme_track);
bd->MouseTrackedArea = area;
}
POINT mouse_pos = { (LONG)GET_X_LPARAM(lParam), (LONG)GET_Y_LPARAM(lParam) };
if (msg == WM_NCMOUSEMOVE && ::ScreenToClient(hwnd, &mouse_pos) == FALSE) // WM_NCMOUSEMOVE are provided in absolute coordinates.
break;
io.AddMouseSourceEvent(mouse_source);
io.AddMousePosEvent((float)mouse_pos.x, (float)mouse_pos.y);
break;
}
case WM_MOUSELEAVE:
case WM_NCMOUSELEAVE:
{
const int area = (msg == WM_MOUSELEAVE) ? 1 : 2;
if (bd->MouseTrackedArea == area)
{
if (bd->MouseHwnd == hwnd)
bd->MouseHwnd = nullptr;
bd->MouseTrackedArea = 0;
io.AddMousePosEvent(-FLT_MAX, -FLT_MAX);
}
break;
}
case WM_LBUTTONDOWN: case WM_LBUTTONDBLCLK:
case WM_RBUTTONDOWN: case WM_RBUTTONDBLCLK:
case WM_MBUTTONDOWN: case WM_MBUTTONDBLCLK:
case WM_XBUTTONDOWN: case WM_XBUTTONDBLCLK:
{
ImGuiMouseSource mouse_source = GetMouseSourceFromMessageExtraInfo();
int button = 0;
if (msg == WM_LBUTTONDOWN || msg == WM_LBUTTONDBLCLK) { button = 0; }
if (msg == WM_RBUTTONDOWN || msg == WM_RBUTTONDBLCLK) { button = 1; }
if (msg == WM_MBUTTONDOWN || msg == WM_MBUTTONDBLCLK) { button = 2; }
if (msg == WM_XBUTTONDOWN || msg == WM_XBUTTONDBLCLK) { button = (GET_XBUTTON_WPARAM(wParam) == XBUTTON1) ? 3 : 4; }
if (bd->MouseButtonsDown == 0 && ::GetCapture() == nullptr)
::SetCapture(hwnd);
bd->MouseButtonsDown |= 1 << button;
io.AddMouseSourceEvent(mouse_source);
io.AddMouseButtonEvent(button, true);
return 0;
}
case WM_LBUTTONUP:
case WM_RBUTTONUP:
case WM_MBUTTONUP:
case WM_XBUTTONUP:
{
ImGuiMouseSource mouse_source = GetMouseSourceFromMessageExtraInfo();
int button = 0;
if (msg == WM_LBUTTONUP) { button = 0; }
if (msg == WM_RBUTTONUP) { button = 1; }
if (msg == WM_MBUTTONUP) { button = 2; }
if (msg == WM_XBUTTONUP) { button = (GET_XBUTTON_WPARAM(wParam) == XBUTTON1) ? 3 : 4; }
bd->MouseButtonsDown &= ~(1 << button);
if (bd->MouseButtonsDown == 0 && ::GetCapture() == hwnd)
::ReleaseCapture();
io.AddMouseSourceEvent(mouse_source);
io.AddMouseButtonEvent(button, false);
return 0;
}
case WM_MOUSEWHEEL:
io.AddMouseWheelEvent(0.0f, (float)GET_WHEEL_DELTA_WPARAM(wParam) / (float)WHEEL_DELTA);
return 0;
case WM_MOUSEHWHEEL:
io.AddMouseWheelEvent(-(float)GET_WHEEL_DELTA_WPARAM(wParam) / (float)WHEEL_DELTA, 0.0f);
return 0;
case WM_KEYDOWN:
case WM_KEYUP:
case WM_SYSKEYDOWN:
case WM_SYSKEYUP:
{
const bool is_key_down = (msg == WM_KEYDOWN || msg == WM_SYSKEYDOWN);
if (wParam < 256)
{
// Submit modifiers
ImGui_ImplWin32_UpdateKeyModifiers();
// Obtain virtual key code
// (keypad enter doesn't have its own... VK_RETURN with KF_EXTENDED flag means keypad enter, see IM_VK_KEYPAD_ENTER definition for details, it is mapped to ImGuiKey_KeyPadEnter.)
int vk = (int)wParam;
if ((wParam == VK_RETURN) && (HIWORD(lParam) & KF_EXTENDED))
vk = IM_VK_KEYPAD_ENTER;
// Submit key event
const ImGuiKey key = ImGui_ImplWin32_VirtualKeyToImGuiKey(vk);
const int scancode = (int)LOBYTE(HIWORD(lParam));
if (key != ImGuiKey_None)
ImGui_ImplWin32_AddKeyEvent(key, is_key_down, vk, scancode);
// Submit individual left/right modifier events
if (vk == VK_SHIFT)
{
// Important: Shift keys tend to get stuck when pressed together, missing key-up events are corrected in ImGui_ImplWin32_ProcessKeyEventsWorkarounds()
if (IsVkDown(VK_LSHIFT) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(ImGuiKey_LeftShift, is_key_down, VK_LSHIFT, scancode); }
if (IsVkDown(VK_RSHIFT) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(ImGuiKey_RightShift, is_key_down, VK_RSHIFT, scancode); }
}
else if (vk == VK_CONTROL)
{
if (IsVkDown(VK_LCONTROL) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(ImGuiKey_LeftCtrl, is_key_down, VK_LCONTROL, scancode); }
if (IsVkDown(VK_RCONTROL) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(ImGuiKey_RightCtrl, is_key_down, VK_RCONTROL, scancode); }
}
else if (vk == VK_MENU)
{
if (IsVkDown(VK_LMENU) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(ImGuiKey_LeftAlt, is_key_down, VK_LMENU, scancode); }
if (IsVkDown(VK_RMENU) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(ImGuiKey_RightAlt, is_key_down, VK_RMENU, scancode); }
}
}
return 0;
}
case WM_SETFOCUS:
case WM_KILLFOCUS:
io.AddFocusEvent(msg == WM_SETFOCUS);
return 0;
case WM_CHAR:
if (::IsWindowUnicode(hwnd))
{
// You can also use ToAscii()+GetKeyboardState() to retrieve characters.
if (wParam > 0 && wParam < 0x10000)
io.AddInputCharacterUTF16((unsigned short)wParam);
}
else
{
wchar_t wch = 0;
::MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, (char*)&wParam, 1, &wch, 1);
io.AddInputCharacter(wch);
}
return 0;
case WM_SETCURSOR:
// This is required to restore cursor when transitioning from e.g resize borders to client area.
if (LOWORD(lParam) == HTCLIENT && ImGui_ImplWin32_UpdateMouseCursor())
return 1;
return 0;
case WM_DEVICECHANGE:
#ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
if ((UINT)wParam == DBT_DEVNODES_CHANGED)
bd->WantUpdateHasGamepad = true;
#endif
return 0;
}
return 0;
}
//--------------------------------------------------------------------------------------------------------
// DPI-related helpers (optional)
//--------------------------------------------------------------------------------------------------------
// - Use to enable DPI awareness without having to create an application manifest.
// - Your own app may already do this via a manifest or explicit calls. This is mostly useful for our examples/ apps.
// - In theory we could call simple functions from Windows SDK such as SetProcessDPIAware(), SetProcessDpiAwareness(), etc.
// but most of the functions provided by Microsoft require Windows 8.1/10+ SDK at compile time and Windows 8/10+ at runtime,
// neither we want to require the user to have. So we dynamically select and load those functions to avoid dependencies.
//---------------------------------------------------------------------------------------------------------
// This is the scheme successfully used by GLFW (from which we borrowed some of the code) and other apps aiming to be highly portable.
// ImGui_ImplWin32_EnableDpiAwareness() is just a helper called by main.cpp, we don't call it automatically.
// If you are trying to implement your own backend for your own engine, you may ignore that noise.
//---------------------------------------------------------------------------------------------------------
// Perform our own check with RtlVerifyVersionInfo() instead of using functions from <VersionHelpers.h> as they
// require a manifest to be functional for checks above 8.1. See https://github.com/ocornut/imgui/issues/4200
static BOOL _IsWindowsVersionOrGreater(WORD major, WORD minor, WORD)
{
typedef LONG(WINAPI* PFN_RtlVerifyVersionInfo)(OSVERSIONINFOEXW*, ULONG, ULONGLONG);
static PFN_RtlVerifyVersionInfo RtlVerifyVersionInfoFn = nullptr;
if (RtlVerifyVersionInfoFn == nullptr)
if (HMODULE ntdllModule = ::GetModuleHandleA("ntdll.dll"))
RtlVerifyVersionInfoFn = (PFN_RtlVerifyVersionInfo)GetProcAddress(ntdllModule, "RtlVerifyVersionInfo");
if (RtlVerifyVersionInfoFn == nullptr)
return FALSE;
RTL_OSVERSIONINFOEXW versionInfo = { };
ULONGLONG conditionMask = 0;
versionInfo.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOEXW);
versionInfo.dwMajorVersion = major;
versionInfo.dwMinorVersion = minor;
VER_SET_CONDITION(conditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL);
VER_SET_CONDITION(conditionMask, VER_MINORVERSION, VER_GREATER_EQUAL);
return (RtlVerifyVersionInfoFn(&versionInfo, VER_MAJORVERSION | VER_MINORVERSION, conditionMask) == 0) ? TRUE : FALSE;
}
#define _IsWindowsVistaOrGreater() _IsWindowsVersionOrGreater(HIBYTE(0x0600), LOBYTE(0x0600), 0) // _WIN32_WINNT_VISTA
#define _IsWindows8OrGreater() _IsWindowsVersionOrGreater(HIBYTE(0x0602), LOBYTE(0x0602), 0) // _WIN32_WINNT_WIN8
#define _IsWindows8Point1OrGreater() _IsWindowsVersionOrGreater(HIBYTE(0x0603), LOBYTE(0x0603), 0) // _WIN32_WINNT_WINBLUE
#define _IsWindows10OrGreater() _IsWindowsVersionOrGreater(HIBYTE(0x0A00), LOBYTE(0x0A00), 0) // _WIN32_WINNT_WINTHRESHOLD / _WIN32_WINNT_WIN10
#ifndef DPI_ENUMS_DECLARED
typedef enum { PROCESS_DPI_UNAWARE = 0, PROCESS_SYSTEM_DPI_AWARE = 1, PROCESS_PER_MONITOR_DPI_AWARE = 2 } PROCESS_DPI_AWARENESS;
typedef enum { MDT_EFFECTIVE_DPI = 0, MDT_ANGULAR_DPI = 1, MDT_RAW_DPI = 2, MDT_DEFAULT = MDT_EFFECTIVE_DPI } MONITOR_DPI_TYPE;
#endif
#ifndef _DPI_AWARENESS_CONTEXTS_
DECLARE_HANDLE(DPI_AWARENESS_CONTEXT);
#define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE (DPI_AWARENESS_CONTEXT)-3
#endif
#ifndef DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2
#define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 (DPI_AWARENESS_CONTEXT)-4
#endif
typedef HRESULT(WINAPI* PFN_SetProcessDpiAwareness)(PROCESS_DPI_AWARENESS); // Shcore.lib + dll, Windows 8.1+
typedef HRESULT(WINAPI* PFN_GetDpiForMonitor)(HMONITOR, MONITOR_DPI_TYPE, UINT*, UINT*); // Shcore.lib + dll, Windows 8.1+
typedef DPI_AWARENESS_CONTEXT(WINAPI* PFN_SetThreadDpiAwarenessContext)(DPI_AWARENESS_CONTEXT); // User32.lib + dll, Windows 10 v1607+ (Creators Update)
// Helper function to enable DPI awareness without setting up a manifest
void ImGui_ImplWin32_EnableDpiAwareness()
{
if (_IsWindows10OrGreater())
{
static HINSTANCE user32_dll = ::LoadLibraryA("user32.dll"); // Reference counted per-process
if (PFN_SetThreadDpiAwarenessContext SetThreadDpiAwarenessContextFn = (PFN_SetThreadDpiAwarenessContext)::GetProcAddress(user32_dll, "SetThreadDpiAwarenessContext"))
{
SetThreadDpiAwarenessContextFn(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
return;
}
}
if (_IsWindows8Point1OrGreater())
{
static HINSTANCE shcore_dll = ::LoadLibraryA("shcore.dll"); // Reference counted per-process
if (PFN_SetProcessDpiAwareness SetProcessDpiAwarenessFn = (PFN_SetProcessDpiAwareness)::GetProcAddress(shcore_dll, "SetProcessDpiAwareness"))
{
SetProcessDpiAwarenessFn(PROCESS_PER_MONITOR_DPI_AWARE);
return;
}
}
#if _WIN32_WINNT >= 0x0600
::SetProcessDPIAware();
#endif
}
#if defined(_MSC_VER) && !defined(NOGDI)
#pragma comment(lib, "gdi32") // Link with gdi32.lib for GetDeviceCaps(). MinGW will require linking with '-lgdi32'
#endif
float ImGui_ImplWin32_GetDpiScaleForMonitor(void* monitor)
{
UINT xdpi = 96, ydpi = 96;
if (_IsWindows8Point1OrGreater())
{
static HINSTANCE shcore_dll = ::LoadLibraryA("shcore.dll"); // Reference counted per-process
static PFN_GetDpiForMonitor GetDpiForMonitorFn = nullptr;
if (GetDpiForMonitorFn == nullptr && shcore_dll != nullptr)
GetDpiForMonitorFn = (PFN_GetDpiForMonitor)::GetProcAddress(shcore_dll, "GetDpiForMonitor");
if (GetDpiForMonitorFn != nullptr)
{
GetDpiForMonitorFn((HMONITOR)monitor, MDT_EFFECTIVE_DPI, &xdpi, &ydpi);
IM_ASSERT(xdpi == ydpi); // Please contact me if you hit this assert!
return xdpi / 96.0f;
}
}
#ifndef NOGDI
const HDC dc = ::GetDC(nullptr);
xdpi = ::GetDeviceCaps(dc, LOGPIXELSX);
ydpi = ::GetDeviceCaps(dc, LOGPIXELSY);
IM_ASSERT(xdpi == ydpi); // Please contact me if you hit this assert!
::ReleaseDC(nullptr, dc);
#endif
return xdpi / 96.0f;
}
float ImGui_ImplWin32_GetDpiScaleForHwnd(void* hwnd)
{
HMONITOR monitor = ::MonitorFromWindow((HWND)hwnd, MONITOR_DEFAULTTONEAREST);
return ImGui_ImplWin32_GetDpiScaleForMonitor(monitor);
}
//---------------------------------------------------------------------------------------------------------
// Transparency related helpers (optional)
//--------------------------------------------------------------------------------------------------------
#if defined(_MSC_VER)
#pragma comment(lib, "dwmapi") // Link with dwmapi.lib. MinGW will require linking with '-ldwmapi'
#endif
// [experimental]
// Borrowed from GLFW's function updateFramebufferTransparency() in src/win32_window.c
// (the Dwm* functions are Vista era functions but we are borrowing logic from GLFW)
void ImGui_ImplWin32_EnableAlphaCompositing(void* hwnd)
{
if (!_IsWindowsVistaOrGreater())
return;
BOOL composition;
if (FAILED(::DwmIsCompositionEnabled(&composition)) || !composition)
return;
BOOL opaque;
DWORD color;
if (_IsWindows8OrGreater() || (SUCCEEDED(::DwmGetColorizationColor(&color, &opaque)) && !opaque))
{
HRGN region = ::CreateRectRgn(0, 0, -1, -1);
DWM_BLURBEHIND bb = {};
bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION;
bb.hRgnBlur = region;
bb.fEnable = TRUE;
::DwmEnableBlurBehindWindow((HWND)hwnd, &bb);
::DeleteObject(region);
}
else
{
DWM_BLURBEHIND bb = {};
bb.dwFlags = DWM_BB_ENABLE;
::DwmEnableBlurBehindWindow((HWND)hwnd, &bb);
}
}
//---------------------------------------------------------------------------------------------------------
#endif // #ifndef IMGUI_DISABLE

View File

@ -0,0 +1,49 @@
// dear imgui: Platform Backend for Windows (standard windows API for 32-bits AND 64-bits applications)
// This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..)
// Implemented features:
// [X] Platform: Clipboard support (for Win32 this is actually part of core dear imgui)
// [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen/Pen.
// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy VK_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set]
// [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
// Read online: https://github.com/ocornut/imgui/tree/master/docs
#pragma once
#include "imgui.h" // IMGUI_IMPL_API
#ifndef IMGUI_DISABLE
IMGUI_IMPL_API bool ImGui_ImplWin32_Init(void* hwnd);
IMGUI_IMPL_API bool ImGui_ImplWin32_InitForOpenGL(void* hwnd);
IMGUI_IMPL_API void ImGui_ImplWin32_Shutdown();
IMGUI_IMPL_API void ImGui_ImplWin32_NewFrame();
// Win32 message handler your application need to call.
// - Intentionally commented out in a '#if 0' block to avoid dragging dependencies on <windows.h> from this helper.
// - You should COPY the line below into your .cpp code to forward declare the function and then you can call it.
// - Call from your application's message handler. Keep calling your message handler unless this function returns TRUE.
#if 0
extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
#endif
// DPI-related helpers (optional)
// - Use to enable DPI awareness without having to create an application manifest.
// - Your own app may already do this via a manifest or explicit calls. This is mostly useful for our examples/ apps.
// - In theory we could call simple functions from Windows SDK such as SetProcessDPIAware(), SetProcessDpiAwareness(), etc.
// but most of the functions provided by Microsoft require Windows 8.1/10+ SDK at compile time and Windows 8/10+ at runtime,
// neither we want to require the user to have. So we dynamically select and load those functions to avoid dependencies.
IMGUI_IMPL_API void ImGui_ImplWin32_EnableDpiAwareness();
IMGUI_IMPL_API float ImGui_ImplWin32_GetDpiScaleForHwnd(void* hwnd); // HWND hwnd
IMGUI_IMPL_API float ImGui_ImplWin32_GetDpiScaleForMonitor(void* monitor); // HMONITOR monitor
// Transparency related helpers (optional) [experimental]
// - Use to enable alpha compositing transparency with the desktop.
// - Use together with e.g. clearing your framebuffer with zero-alpha.
IMGUI_IMPL_API void ImGui_ImplWin32_EnableAlphaCompositing(void* hwnd); // HWND hwnd
#endif // #ifndef IMGUI_DISABLE

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,85 @@
// dear imgui: wrappers for C++ standard library (STL) types (std::string, etc.)
// This is also an example of how you may wrap your own similar types.
// Changelog:
// - v0.10: Initial version. Added InputText() / InputTextMultiline() calls with std::string
// See more C++ related extension (fmt, RAII, syntaxis sugar) on Wiki:
// https://github.com/ocornut/imgui/wiki/Useful-Extensions#cness
#include "imgui.h"
#include "imgui_stdlib.h"
// Clang warnings with -Weverything
#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness
#endif
struct InputTextCallback_UserData
{
std::string* Str;
ImGuiInputTextCallback ChainCallback;
void* ChainCallbackUserData;
};
static int InputTextCallback(ImGuiInputTextCallbackData* data)
{
InputTextCallback_UserData* user_data = (InputTextCallback_UserData*)data->UserData;
if (data->EventFlag == ImGuiInputTextFlags_CallbackResize)
{
// Resize string callback
// If for some reason we refuse the new length (BufTextLen) and/or capacity (BufSize) we need to set them back to what we want.
std::string* str = user_data->Str;
IM_ASSERT(data->Buf == str->c_str());
str->resize(data->BufTextLen);
data->Buf = (char*)str->c_str();
}
else if (user_data->ChainCallback)
{
// Forward to user callback, if any
data->UserData = user_data->ChainCallbackUserData;
return user_data->ChainCallback(data);
}
return 0;
}
bool ImGui::InputText(const char* label, std::string* str, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data)
{
IM_ASSERT((flags & ImGuiInputTextFlags_CallbackResize) == 0);
flags |= ImGuiInputTextFlags_CallbackResize;
InputTextCallback_UserData cb_user_data;
cb_user_data.Str = str;
cb_user_data.ChainCallback = callback;
cb_user_data.ChainCallbackUserData = user_data;
return InputText(label, (char*)str->c_str(), str->capacity() + 1, flags, InputTextCallback, &cb_user_data);
}
bool ImGui::InputTextMultiline(const char* label, std::string* str, const ImVec2& size, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data)
{
IM_ASSERT((flags & ImGuiInputTextFlags_CallbackResize) == 0);
flags |= ImGuiInputTextFlags_CallbackResize;
InputTextCallback_UserData cb_user_data;
cb_user_data.Str = str;
cb_user_data.ChainCallback = callback;
cb_user_data.ChainCallbackUserData = user_data;
return InputTextMultiline(label, (char*)str->c_str(), str->capacity() + 1, size, flags, InputTextCallback, &cb_user_data);
}
bool ImGui::InputTextWithHint(const char* label, const char* hint, std::string* str, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data)
{
IM_ASSERT((flags & ImGuiInputTextFlags_CallbackResize) == 0);
flags |= ImGuiInputTextFlags_CallbackResize;
InputTextCallback_UserData cb_user_data;
cb_user_data.Str = str;
cb_user_data.ChainCallback = callback;
cb_user_data.ChainCallbackUserData = user_data;
return InputTextWithHint(label, hint, (char*)str->c_str(), str->capacity() + 1, flags, InputTextCallback, &cb_user_data);
}
#if defined(__clang__)
#pragma clang diagnostic pop
#endif

View File

@ -0,0 +1,21 @@
// dear imgui: wrappers for C++ standard library (STL) types (std::string, etc.)
// This is also an example of how you may wrap your own similar types.
// Changelog:
// - v0.10: Initial version. Added InputText() / InputTextMultiline() calls with std::string
// See more C++ related extension (fmt, RAII, syntaxis sugar) on Wiki:
// https://github.com/ocornut/imgui/wiki/Useful-Extensions#cness
#pragma once
#include <string>
namespace ImGui
{
// ImGui::InputText() with std::string
// Because text input needs dynamic resizing, we need to setup a callback to grow the capacity
IMGUI_API bool InputText(const char* label, std::string* str, ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = nullptr, void* user_data = nullptr);
IMGUI_API bool InputTextMultiline(const char* label, std::string* str, const ImVec2& size = ImVec2(0, 0), ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = nullptr, void* user_data = nullptr);
IMGUI_API bool InputTextWithHint(const char* label, const char* hint, std::string* str, ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = nullptr, void* user_data = nullptr);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,627 @@
// [DEAR IMGUI]
// This is a slightly modified version of stb_rect_pack.h 1.01.
// Grep for [DEAR IMGUI] to find the changes.
//
// stb_rect_pack.h - v1.01 - public domain - rectangle packing
// Sean Barrett 2014
//
// Useful for e.g. packing rectangular textures into an atlas.
// Does not do rotation.
//
// Before #including,
//
// #define STB_RECT_PACK_IMPLEMENTATION
//
// in the file that you want to have the implementation.
//
// Not necessarily the awesomest packing method, but better than
// the totally naive one in stb_truetype (which is primarily what
// this is meant to replace).
//
// Has only had a few tests run, may have issues.
//
// More docs to come.
//
// No memory allocations; uses qsort() and assert() from stdlib.
// Can override those by defining STBRP_SORT and STBRP_ASSERT.
//
// This library currently uses the Skyline Bottom-Left algorithm.
//
// Please note: better rectangle packers are welcome! Please
// implement them to the same API, but with a different init
// function.
//
// Credits
//
// Library
// Sean Barrett
// Minor features
// Martins Mozeiko
// github:IntellectualKitty
//
// Bugfixes / warning fixes
// Jeremy Jaussaud
// Fabian Giesen
//
// Version history:
//
// 1.01 (2021-07-11) always use large rect mode, expose STBRP__MAXVAL in public section
// 1.00 (2019-02-25) avoid small space waste; gracefully fail too-wide rectangles
// 0.99 (2019-02-07) warning fixes
// 0.11 (2017-03-03) return packing success/fail result
// 0.10 (2016-10-25) remove cast-away-const to avoid warnings
// 0.09 (2016-08-27) fix compiler warnings
// 0.08 (2015-09-13) really fix bug with empty rects (w=0 or h=0)
// 0.07 (2015-09-13) fix bug with empty rects (w=0 or h=0)
// 0.06 (2015-04-15) added STBRP_SORT to allow replacing qsort
// 0.05: added STBRP_ASSERT to allow replacing assert
// 0.04: fixed minor bug in STBRP_LARGE_RECTS support
// 0.01: initial release
//
// LICENSE
//
// See end of file for license information.
//////////////////////////////////////////////////////////////////////////////
//
// INCLUDE SECTION
//
#ifndef STB_INCLUDE_STB_RECT_PACK_H
#define STB_INCLUDE_STB_RECT_PACK_H
#define STB_RECT_PACK_VERSION 1
#ifdef STBRP_STATIC
#define STBRP_DEF static
#else
#define STBRP_DEF extern
#endif
#ifdef __cplusplus
extern "C" {
#endif
typedef struct stbrp_context stbrp_context;
typedef struct stbrp_node stbrp_node;
typedef struct stbrp_rect stbrp_rect;
typedef int stbrp_coord;
#define STBRP__MAXVAL 0x7fffffff
// Mostly for internal use, but this is the maximum supported coordinate value.
STBRP_DEF int stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int num_rects);
// Assign packed locations to rectangles. The rectangles are of type
// 'stbrp_rect' defined below, stored in the array 'rects', and there
// are 'num_rects' many of them.
//
// Rectangles which are successfully packed have the 'was_packed' flag
// set to a non-zero value and 'x' and 'y' store the minimum location
// on each axis (i.e. bottom-left in cartesian coordinates, top-left
// if you imagine y increasing downwards). Rectangles which do not fit
// have the 'was_packed' flag set to 0.
//
// You should not try to access the 'rects' array from another thread
// while this function is running, as the function temporarily reorders
// the array while it executes.
//
// To pack into another rectangle, you need to call stbrp_init_target
// again. To continue packing into the same rectangle, you can call
// this function again. Calling this multiple times with multiple rect
// arrays will probably produce worse packing results than calling it
// a single time with the full rectangle array, but the option is
// available.
//
// The function returns 1 if all of the rectangles were successfully
// packed and 0 otherwise.
struct stbrp_rect
{
// reserved for your use:
int id;
// input:
stbrp_coord w, h;
// output:
stbrp_coord x, y;
int was_packed; // non-zero if valid packing
}; // 16 bytes, nominally
STBRP_DEF void stbrp_init_target (stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes);
// Initialize a rectangle packer to:
// pack a rectangle that is 'width' by 'height' in dimensions
// using temporary storage provided by the array 'nodes', which is 'num_nodes' long
//
// You must call this function every time you start packing into a new target.
//
// There is no "shutdown" function. The 'nodes' memory must stay valid for
// the following stbrp_pack_rects() call (or calls), but can be freed after
// the call (or calls) finish.
//
// Note: to guarantee best results, either:
// 1. make sure 'num_nodes' >= 'width'
// or 2. call stbrp_allow_out_of_mem() defined below with 'allow_out_of_mem = 1'
//
// If you don't do either of the above things, widths will be quantized to multiples
// of small integers to guarantee the algorithm doesn't run out of temporary storage.
//
// If you do #2, then the non-quantized algorithm will be used, but the algorithm
// may run out of temporary storage and be unable to pack some rectangles.
STBRP_DEF void stbrp_setup_allow_out_of_mem (stbrp_context *context, int allow_out_of_mem);
// Optionally call this function after init but before doing any packing to
// change the handling of the out-of-temp-memory scenario, described above.
// If you call init again, this will be reset to the default (false).
STBRP_DEF void stbrp_setup_heuristic (stbrp_context *context, int heuristic);
// Optionally select which packing heuristic the library should use. Different
// heuristics will produce better/worse results for different data sets.
// If you call init again, this will be reset to the default.
enum
{
STBRP_HEURISTIC_Skyline_default=0,
STBRP_HEURISTIC_Skyline_BL_sortHeight = STBRP_HEURISTIC_Skyline_default,
STBRP_HEURISTIC_Skyline_BF_sortHeight
};
//////////////////////////////////////////////////////////////////////////////
//
// the details of the following structures don't matter to you, but they must
// be visible so you can handle the memory allocations for them
struct stbrp_node
{
stbrp_coord x,y;
stbrp_node *next;
};
struct stbrp_context
{
int width;
int height;
int align;
int init_mode;
int heuristic;
int num_nodes;
stbrp_node *active_head;
stbrp_node *free_head;
stbrp_node extra[2]; // we allocate two extra nodes so optimal user-node-count is 'width' not 'width+2'
};
#ifdef __cplusplus
}
#endif
#endif
//////////////////////////////////////////////////////////////////////////////
//
// IMPLEMENTATION SECTION
//
#ifdef STB_RECT_PACK_IMPLEMENTATION
#ifndef STBRP_SORT
#include <stdlib.h>
#define STBRP_SORT qsort
#endif
#ifndef STBRP_ASSERT
#include <assert.h>
#define STBRP_ASSERT assert
#endif
#ifdef _MSC_VER
#define STBRP__NOTUSED(v) (void)(v)
#define STBRP__CDECL __cdecl
#else
#define STBRP__NOTUSED(v) (void)sizeof(v)
#define STBRP__CDECL
#endif
enum
{
STBRP__INIT_skyline = 1
};
STBRP_DEF void stbrp_setup_heuristic(stbrp_context *context, int heuristic)
{
switch (context->init_mode) {
case STBRP__INIT_skyline:
STBRP_ASSERT(heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight || heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight);
context->heuristic = heuristic;
break;
default:
STBRP_ASSERT(0);
}
}
STBRP_DEF void stbrp_setup_allow_out_of_mem(stbrp_context *context, int allow_out_of_mem)
{
if (allow_out_of_mem)
// if it's ok to run out of memory, then don't bother aligning them;
// this gives better packing, but may fail due to OOM (even though
// the rectangles easily fit). @TODO a smarter approach would be to only
// quantize once we've hit OOM, then we could get rid of this parameter.
context->align = 1;
else {
// if it's not ok to run out of memory, then quantize the widths
// so that num_nodes is always enough nodes.
//
// I.e. num_nodes * align >= width
// align >= width / num_nodes
// align = ceil(width/num_nodes)
context->align = (context->width + context->num_nodes-1) / context->num_nodes;
}
}
STBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes)
{
int i;
for (i=0; i < num_nodes-1; ++i)
nodes[i].next = &nodes[i+1];
nodes[i].next = NULL;
context->init_mode = STBRP__INIT_skyline;
context->heuristic = STBRP_HEURISTIC_Skyline_default;
context->free_head = &nodes[0];
context->active_head = &context->extra[0];
context->width = width;
context->height = height;
context->num_nodes = num_nodes;
stbrp_setup_allow_out_of_mem(context, 0);
// node 0 is the full width, node 1 is the sentinel (lets us not store width explicitly)
context->extra[0].x = 0;
context->extra[0].y = 0;
context->extra[0].next = &context->extra[1];
context->extra[1].x = (stbrp_coord) width;
context->extra[1].y = (1<<30);
context->extra[1].next = NULL;
}
// find minimum y position if it starts at x1
static int stbrp__skyline_find_min_y(stbrp_context *c, stbrp_node *first, int x0, int width, int *pwaste)
{
stbrp_node *node = first;
int x1 = x0 + width;
int min_y, visited_width, waste_area;
STBRP__NOTUSED(c);
STBRP_ASSERT(first->x <= x0);
#if 0
// skip in case we're past the node
while (node->next->x <= x0)
++node;
#else
STBRP_ASSERT(node->next->x > x0); // we ended up handling this in the caller for efficiency
#endif
STBRP_ASSERT(node->x <= x0);
min_y = 0;
waste_area = 0;
visited_width = 0;
while (node->x < x1) {
if (node->y > min_y) {
// raise min_y higher.
// we've accounted for all waste up to min_y,
// but we'll now add more waste for everything we've visted
waste_area += visited_width * (node->y - min_y);
min_y = node->y;
// the first time through, visited_width might be reduced
if (node->x < x0)
visited_width += node->next->x - x0;
else
visited_width += node->next->x - node->x;
} else {
// add waste area
int under_width = node->next->x - node->x;
if (under_width + visited_width > width)
under_width = width - visited_width;
waste_area += under_width * (min_y - node->y);
visited_width += under_width;
}
node = node->next;
}
*pwaste = waste_area;
return min_y;
}
typedef struct
{
int x,y;
stbrp_node **prev_link;
} stbrp__findresult;
static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int width, int height)
{
int best_waste = (1<<30), best_x, best_y = (1 << 30);
stbrp__findresult fr;
stbrp_node **prev, *node, *tail, **best = NULL;
// align to multiple of c->align
width = (width + c->align - 1);
width -= width % c->align;
STBRP_ASSERT(width % c->align == 0);
// if it can't possibly fit, bail immediately
if (width > c->width || height > c->height) {
fr.prev_link = NULL;
fr.x = fr.y = 0;
return fr;
}
node = c->active_head;
prev = &c->active_head;
while (node->x + width <= c->width) {
int y,waste;
y = stbrp__skyline_find_min_y(c, node, node->x, width, &waste);
if (c->heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight) { // actually just want to test BL
// bottom left
if (y < best_y) {
best_y = y;
best = prev;
}
} else {
// best-fit
if (y + height <= c->height) {
// can only use it if it first vertically
if (y < best_y || (y == best_y && waste < best_waste)) {
best_y = y;
best_waste = waste;
best = prev;
}
}
}
prev = &node->next;
node = node->next;
}
best_x = (best == NULL) ? 0 : (*best)->x;
// if doing best-fit (BF), we also have to try aligning right edge to each node position
//
// e.g, if fitting
//
// ____________________
// |____________________|
//
// into
//
// | |
// | ____________|
// |____________|
//
// then right-aligned reduces waste, but bottom-left BL is always chooses left-aligned
//
// This makes BF take about 2x the time
if (c->heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight) {
tail = c->active_head;
node = c->active_head;
prev = &c->active_head;
// find first node that's admissible
while (tail->x < width)
tail = tail->next;
while (tail) {
int xpos = tail->x - width;
int y,waste;
STBRP_ASSERT(xpos >= 0);
// find the left position that matches this
while (node->next->x <= xpos) {
prev = &node->next;
node = node->next;
}
STBRP_ASSERT(node->next->x > xpos && node->x <= xpos);
y = stbrp__skyline_find_min_y(c, node, xpos, width, &waste);
if (y + height <= c->height) {
if (y <= best_y) {
if (y < best_y || waste < best_waste || (waste==best_waste && xpos < best_x)) {
best_x = xpos;
//STBRP_ASSERT(y <= best_y); [DEAR IMGUI]
best_y = y;
best_waste = waste;
best = prev;
}
}
}
tail = tail->next;
}
}
fr.prev_link = best;
fr.x = best_x;
fr.y = best_y;
return fr;
}
static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, int width, int height)
{
// find best position according to heuristic
stbrp__findresult res = stbrp__skyline_find_best_pos(context, width, height);
stbrp_node *node, *cur;
// bail if:
// 1. it failed
// 2. the best node doesn't fit (we don't always check this)
// 3. we're out of memory
if (res.prev_link == NULL || res.y + height > context->height || context->free_head == NULL) {
res.prev_link = NULL;
return res;
}
// on success, create new node
node = context->free_head;
node->x = (stbrp_coord) res.x;
node->y = (stbrp_coord) (res.y + height);
context->free_head = node->next;
// insert the new node into the right starting point, and
// let 'cur' point to the remaining nodes needing to be
// stiched back in
cur = *res.prev_link;
if (cur->x < res.x) {
// preserve the existing one, so start testing with the next one
stbrp_node *next = cur->next;
cur->next = node;
cur = next;
} else {
*res.prev_link = node;
}
// from here, traverse cur and free the nodes, until we get to one
// that shouldn't be freed
while (cur->next && cur->next->x <= res.x + width) {
stbrp_node *next = cur->next;
// move the current node to the free list
cur->next = context->free_head;
context->free_head = cur;
cur = next;
}
// stitch the list back in
node->next = cur;
if (cur->x < res.x + width)
cur->x = (stbrp_coord) (res.x + width);
#ifdef _DEBUG
cur = context->active_head;
while (cur->x < context->width) {
STBRP_ASSERT(cur->x < cur->next->x);
cur = cur->next;
}
STBRP_ASSERT(cur->next == NULL);
{
int count=0;
cur = context->active_head;
while (cur) {
cur = cur->next;
++count;
}
cur = context->free_head;
while (cur) {
cur = cur->next;
++count;
}
STBRP_ASSERT(count == context->num_nodes+2);
}
#endif
return res;
}
static int STBRP__CDECL rect_height_compare(const void *a, const void *b)
{
const stbrp_rect *p = (const stbrp_rect *) a;
const stbrp_rect *q = (const stbrp_rect *) b;
if (p->h > q->h)
return -1;
if (p->h < q->h)
return 1;
return (p->w > q->w) ? -1 : (p->w < q->w);
}
static int STBRP__CDECL rect_original_order(const void *a, const void *b)
{
const stbrp_rect *p = (const stbrp_rect *) a;
const stbrp_rect *q = (const stbrp_rect *) b;
return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed);
}
STBRP_DEF int stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects)
{
int i, all_rects_packed = 1;
// we use the 'was_packed' field internally to allow sorting/unsorting
for (i=0; i < num_rects; ++i) {
rects[i].was_packed = i;
}
// sort according to heuristic
STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_height_compare);
for (i=0; i < num_rects; ++i) {
if (rects[i].w == 0 || rects[i].h == 0) {
rects[i].x = rects[i].y = 0; // empty rect needs no space
} else {
stbrp__findresult fr = stbrp__skyline_pack_rectangle(context, rects[i].w, rects[i].h);
if (fr.prev_link) {
rects[i].x = (stbrp_coord) fr.x;
rects[i].y = (stbrp_coord) fr.y;
} else {
rects[i].x = rects[i].y = STBRP__MAXVAL;
}
}
}
// unsort
STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_original_order);
// set was_packed flags and all_rects_packed status
for (i=0; i < num_rects; ++i) {
rects[i].was_packed = !(rects[i].x == STBRP__MAXVAL && rects[i].y == STBRP__MAXVAL);
if (!rects[i].was_packed)
all_rects_packed = 0;
}
// return the all_rects_packed status
return all_rects_packed;
}
#endif
/*
------------------------------------------------------------------------------
This software is available under 2 licenses -- choose whichever you prefer.
------------------------------------------------------------------------------
ALTERNATIVE A - MIT License
Copyright (c) 2017 Sean Barrett
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
------------------------------------------------------------------------------
ALTERNATIVE B - Public Domain (www.unlicense.org)
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
software, either in source code form or as a compiled binary, for any purpose,
commercial or non-commercial, and by any means.
In jurisdictions that recognize copyright laws, the author or authors of this
software dedicate any and all copyright interest in the software to the public
domain. We make this dedication for the benefit of the public at large and to
the detriment of our heirs and successors. We intend this dedication to be an
overt act of relinquishment in perpetuity of all present and future rights to
this software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
------------------------------------------------------------------------------
*/

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,185 @@
/*
* MinHook - The Minimalistic API Hooking Library for x64/x86
* Copyright (C) 2009-2017 Tsuda Kageyu.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#if !(defined _M_IX86) && !(defined _M_X64) && !(defined __i386__) && !(defined __x86_64__)
#error MinHook supports only x86 and x64 systems.
#endif
#include <windows.h>
// MinHook Error Codes.
typedef enum MH_STATUS
{
// Unknown error. Should not be returned.
MH_UNKNOWN = -1,
// Successful.
MH_OK = 0,
// MinHook is already initialized.
MH_ERROR_ALREADY_INITIALIZED,
// MinHook is not initialized yet, or already uninitialized.
MH_ERROR_NOT_INITIALIZED,
// The hook for the specified target function is already created.
MH_ERROR_ALREADY_CREATED,
// The hook for the specified target function is not created yet.
MH_ERROR_NOT_CREATED,
// The hook for the specified target function is already enabled.
MH_ERROR_ENABLED,
// The hook for the specified target function is not enabled yet, or already
// disabled.
MH_ERROR_DISABLED,
// The specified pointer is invalid. It points the address of non-allocated
// and/or non-executable region.
MH_ERROR_NOT_EXECUTABLE,
// The specified target function cannot be hooked.
MH_ERROR_UNSUPPORTED_FUNCTION,
// Failed to allocate memory.
MH_ERROR_MEMORY_ALLOC,
// Failed to change the memory protection.
MH_ERROR_MEMORY_PROTECT,
// The specified module is not loaded.
MH_ERROR_MODULE_NOT_FOUND,
// The specified function is not found.
MH_ERROR_FUNCTION_NOT_FOUND
}
MH_STATUS;
// Can be passed as a parameter to MH_EnableHook, MH_DisableHook,
// MH_QueueEnableHook or MH_QueueDisableHook.
#define MH_ALL_HOOKS NULL
#ifdef __cplusplus
extern "C" {
#endif
// Initialize the MinHook library. You must call this function EXACTLY ONCE
// at the beginning of your program.
MH_STATUS WINAPI MH_Initialize(VOID);
// Uninitialize the MinHook library. You must call this function EXACTLY
// ONCE at the end of your program.
MH_STATUS WINAPI MH_Uninitialize(VOID);
// Creates a hook for the specified target function, in disabled state.
// Parameters:
// pTarget [in] A pointer to the target function, which will be
// overridden by the detour function.
// pDetour [in] A pointer to the detour function, which will override
// the target function.
// ppOriginal [out] A pointer to the trampoline function, which will be
// used to call the original target function.
// This parameter can be NULL.
MH_STATUS WINAPI MH_CreateHook(LPVOID pTarget, LPVOID pDetour, LPVOID *ppOriginal);
// Creates a hook for the specified API function, in disabled state.
// Parameters:
// pszModule [in] A pointer to the loaded module name which contains the
// target function.
// pszProcName [in] A pointer to the target function name, which will be
// overridden by the detour function.
// pDetour [in] A pointer to the detour function, which will override
// the target function.
// ppOriginal [out] A pointer to the trampoline function, which will be
// used to call the original target function.
// This parameter can be NULL.
MH_STATUS WINAPI MH_CreateHookApi(
LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal);
// Creates a hook for the specified API function, in disabled state.
// Parameters:
// pszModule [in] A pointer to the loaded module name which contains the
// target function.
// pszProcName [in] A pointer to the target function name, which will be
// overridden by the detour function.
// pDetour [in] A pointer to the detour function, which will override
// the target function.
// ppOriginal [out] A pointer to the trampoline function, which will be
// used to call the original target function.
// This parameter can be NULL.
// ppTarget [out] A pointer to the target function, which will be used
// with other functions.
// This parameter can be NULL.
MH_STATUS WINAPI MH_CreateHookApiEx(
LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal, LPVOID *ppTarget);
// Removes an already created hook.
// Parameters:
// pTarget [in] A pointer to the target function.
MH_STATUS WINAPI MH_RemoveHook(LPVOID pTarget);
// Enables an already created hook.
// Parameters:
// pTarget [in] A pointer to the target function.
// If this parameter is MH_ALL_HOOKS, all created hooks are
// enabled in one go.
MH_STATUS WINAPI MH_EnableHook(LPVOID pTarget);
// Disables an already created hook.
// Parameters:
// pTarget [in] A pointer to the target function.
// If this parameter is MH_ALL_HOOKS, all created hooks are
// disabled in one go.
MH_STATUS WINAPI MH_DisableHook(LPVOID pTarget);
// Queues to enable an already created hook.
// Parameters:
// pTarget [in] A pointer to the target function.
// If this parameter is MH_ALL_HOOKS, all created hooks are
// queued to be enabled.
MH_STATUS WINAPI MH_QueueEnableHook(LPVOID pTarget);
// Queues to disable an already created hook.
// Parameters:
// pTarget [in] A pointer to the target function.
// If this parameter is MH_ALL_HOOKS, all created hooks are
// queued to be disabled.
MH_STATUS WINAPI MH_QueueDisableHook(LPVOID pTarget);
// Applies all queued changes in one go.
MH_STATUS WINAPI MH_ApplyQueued(VOID);
// Translates the MH_STATUS to its name as a string.
const char * WINAPI MH_StatusToString(MH_STATUS status);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,312 @@
/*
* MinHook - The Minimalistic API Hooking Library for x64/x86
* Copyright (C) 2009-2017 Tsuda Kageyu.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <windows.h>
#include "buffer.h"
// Size of each memory block. (= page size of VirtualAlloc)
#define MEMORY_BLOCK_SIZE 0x1000
// Max range for seeking a memory block. (= 1024MB)
#define MAX_MEMORY_RANGE 0x40000000
// Memory protection flags to check the executable address.
#define PAGE_EXECUTE_FLAGS \
(PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY)
// Memory slot.
typedef struct _MEMORY_SLOT
{
union
{
struct _MEMORY_SLOT *pNext;
UINT8 buffer[MEMORY_SLOT_SIZE];
};
} MEMORY_SLOT, *PMEMORY_SLOT;
// Memory block info. Placed at the head of each block.
typedef struct _MEMORY_BLOCK
{
struct _MEMORY_BLOCK *pNext;
PMEMORY_SLOT pFree; // First element of the free slot list.
UINT usedCount;
} MEMORY_BLOCK, *PMEMORY_BLOCK;
//-------------------------------------------------------------------------
// Global Variables:
//-------------------------------------------------------------------------
// First element of the memory block list.
PMEMORY_BLOCK g_pMemoryBlocks;
//-------------------------------------------------------------------------
VOID InitializeBuffer(VOID)
{
// Nothing to do for now.
}
//-------------------------------------------------------------------------
VOID UninitializeBuffer(VOID)
{
PMEMORY_BLOCK pBlock = g_pMemoryBlocks;
g_pMemoryBlocks = NULL;
while (pBlock)
{
PMEMORY_BLOCK pNext = pBlock->pNext;
VirtualFree(pBlock, 0, MEM_RELEASE);
pBlock = pNext;
}
}
//-------------------------------------------------------------------------
#if defined(_M_X64) || defined(__x86_64__)
static LPVOID FindPrevFreeRegion(LPVOID pAddress, LPVOID pMinAddr, DWORD dwAllocationGranularity)
{
ULONG_PTR tryAddr = (ULONG_PTR)pAddress;
// Round down to the allocation granularity.
tryAddr -= tryAddr % dwAllocationGranularity;
// Start from the previous allocation granularity multiply.
tryAddr -= dwAllocationGranularity;
while (tryAddr >= (ULONG_PTR)pMinAddr)
{
MEMORY_BASIC_INFORMATION mbi;
if (VirtualQuery((LPVOID)tryAddr, &mbi, sizeof(mbi)) == 0)
break;
if (mbi.State == MEM_FREE)
return (LPVOID)tryAddr;
if ((ULONG_PTR)mbi.AllocationBase < dwAllocationGranularity)
break;
tryAddr = (ULONG_PTR)mbi.AllocationBase - dwAllocationGranularity;
}
return NULL;
}
#endif
//-------------------------------------------------------------------------
#if defined(_M_X64) || defined(__x86_64__)
static LPVOID FindNextFreeRegion(LPVOID pAddress, LPVOID pMaxAddr, DWORD dwAllocationGranularity)
{
ULONG_PTR tryAddr = (ULONG_PTR)pAddress;
// Round down to the allocation granularity.
tryAddr -= tryAddr % dwAllocationGranularity;
// Start from the next allocation granularity multiply.
tryAddr += dwAllocationGranularity;
while (tryAddr <= (ULONG_PTR)pMaxAddr)
{
MEMORY_BASIC_INFORMATION mbi;
if (VirtualQuery((LPVOID)tryAddr, &mbi, sizeof(mbi)) == 0)
break;
if (mbi.State == MEM_FREE)
return (LPVOID)tryAddr;
tryAddr = (ULONG_PTR)mbi.BaseAddress + mbi.RegionSize;
// Round up to the next allocation granularity.
tryAddr += dwAllocationGranularity - 1;
tryAddr -= tryAddr % dwAllocationGranularity;
}
return NULL;
}
#endif
//-------------------------------------------------------------------------
static PMEMORY_BLOCK GetMemoryBlock(LPVOID pOrigin)
{
PMEMORY_BLOCK pBlock;
#if defined(_M_X64) || defined(__x86_64__)
ULONG_PTR minAddr;
ULONG_PTR maxAddr;
SYSTEM_INFO si;
GetSystemInfo(&si);
minAddr = (ULONG_PTR)si.lpMinimumApplicationAddress;
maxAddr = (ULONG_PTR)si.lpMaximumApplicationAddress;
// pOrigin ± 512MB
if ((ULONG_PTR)pOrigin > MAX_MEMORY_RANGE && minAddr < (ULONG_PTR)pOrigin - MAX_MEMORY_RANGE)
minAddr = (ULONG_PTR)pOrigin - MAX_MEMORY_RANGE;
if (maxAddr > (ULONG_PTR)pOrigin + MAX_MEMORY_RANGE)
maxAddr = (ULONG_PTR)pOrigin + MAX_MEMORY_RANGE;
// Make room for MEMORY_BLOCK_SIZE bytes.
maxAddr -= MEMORY_BLOCK_SIZE - 1;
#endif
// Look the registered blocks for a reachable one.
for (pBlock = g_pMemoryBlocks; pBlock != NULL; pBlock = pBlock->pNext)
{
#if defined(_M_X64) || defined(__x86_64__)
// Ignore the blocks too far.
if ((ULONG_PTR)pBlock < minAddr || (ULONG_PTR)pBlock >= maxAddr)
continue;
#endif
// The block has at least one unused slot.
if (pBlock->pFree != NULL)
return pBlock;
}
#if defined(_M_X64) || defined(__x86_64__)
// Alloc a new block above if not found.
{
LPVOID pAlloc = pOrigin;
while ((ULONG_PTR)pAlloc >= minAddr)
{
pAlloc = FindPrevFreeRegion(pAlloc, (LPVOID)minAddr, si.dwAllocationGranularity);
if (pAlloc == NULL)
break;
pBlock = (PMEMORY_BLOCK)VirtualAlloc(
pAlloc, MEMORY_BLOCK_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (pBlock != NULL)
break;
}
}
// Alloc a new block below if not found.
if (pBlock == NULL)
{
LPVOID pAlloc = pOrigin;
while ((ULONG_PTR)pAlloc <= maxAddr)
{
pAlloc = FindNextFreeRegion(pAlloc, (LPVOID)maxAddr, si.dwAllocationGranularity);
if (pAlloc == NULL)
break;
pBlock = (PMEMORY_BLOCK)VirtualAlloc(
pAlloc, MEMORY_BLOCK_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (pBlock != NULL)
break;
}
}
#else
// In x86 mode, a memory block can be placed anywhere.
pBlock = (PMEMORY_BLOCK)VirtualAlloc(
NULL, MEMORY_BLOCK_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
#endif
if (pBlock != NULL)
{
// Build a linked list of all the slots.
PMEMORY_SLOT pSlot = (PMEMORY_SLOT)pBlock + 1;
pBlock->pFree = NULL;
pBlock->usedCount = 0;
do
{
pSlot->pNext = pBlock->pFree;
pBlock->pFree = pSlot;
pSlot++;
} while ((ULONG_PTR)pSlot - (ULONG_PTR)pBlock <= MEMORY_BLOCK_SIZE - MEMORY_SLOT_SIZE);
pBlock->pNext = g_pMemoryBlocks;
g_pMemoryBlocks = pBlock;
}
return pBlock;
}
//-------------------------------------------------------------------------
LPVOID AllocateBuffer(LPVOID pOrigin)
{
PMEMORY_SLOT pSlot;
PMEMORY_BLOCK pBlock = GetMemoryBlock(pOrigin);
if (pBlock == NULL)
return NULL;
// Remove an unused slot from the list.
pSlot = pBlock->pFree;
pBlock->pFree = pSlot->pNext;
pBlock->usedCount++;
#ifdef _DEBUG
// Fill the slot with INT3 for debugging.
memset(pSlot, 0xCC, sizeof(MEMORY_SLOT));
#endif
return pSlot;
}
//-------------------------------------------------------------------------
VOID FreeBuffer(LPVOID pBuffer)
{
PMEMORY_BLOCK pBlock = g_pMemoryBlocks;
PMEMORY_BLOCK pPrev = NULL;
ULONG_PTR pTargetBlock = ((ULONG_PTR)pBuffer / MEMORY_BLOCK_SIZE) * MEMORY_BLOCK_SIZE;
while (pBlock != NULL)
{
if ((ULONG_PTR)pBlock == pTargetBlock)
{
PMEMORY_SLOT pSlot = (PMEMORY_SLOT)pBuffer;
#ifdef _DEBUG
// Clear the released slot for debugging.
memset(pSlot, 0x00, sizeof(MEMORY_SLOT));
#endif
// Restore the released slot to the list.
pSlot->pNext = pBlock->pFree;
pBlock->pFree = pSlot;
pBlock->usedCount--;
// Free if unused.
if (pBlock->usedCount == 0)
{
if (pPrev)
pPrev->pNext = pBlock->pNext;
else
g_pMemoryBlocks = pBlock->pNext;
VirtualFree(pBlock, 0, MEM_RELEASE);
}
break;
}
pPrev = pBlock;
pBlock = pBlock->pNext;
}
}
//-------------------------------------------------------------------------
BOOL IsExecutableAddress(LPVOID pAddress)
{
MEMORY_BASIC_INFORMATION mi;
VirtualQuery(pAddress, &mi, sizeof(mi));
return (mi.State == MEM_COMMIT && (mi.Protect & PAGE_EXECUTE_FLAGS));
}

View File

@ -0,0 +1,42 @@
/*
* MinHook - The Minimalistic API Hooking Library for x64/x86
* Copyright (C) 2009-2017 Tsuda Kageyu.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
// Size of each memory slot.
#if defined(_M_X64) || defined(__x86_64__)
#define MEMORY_SLOT_SIZE 64
#else
#define MEMORY_SLOT_SIZE 32
#endif
VOID InitializeBuffer(VOID);
VOID UninitializeBuffer(VOID);
LPVOID AllocateBuffer(LPVOID pOrigin);
VOID FreeBuffer(LPVOID pBuffer);
BOOL IsExecutableAddress(LPVOID pAddress);

View File

@ -0,0 +1,324 @@
/*
* Hacker Disassembler Engine 32 C
* Copyright (c) 2008-2009, Vyacheslav Patkov.
* All rights reserved.
*
*/
#if defined(_M_IX86) || defined(__i386__)
#include <string.h>
#include "hde32.h"
#include "table32.h"
unsigned int hde32_disasm(const void *code, hde32s *hs)
{
uint8_t x, c, *p = (uint8_t *)code, cflags, opcode, pref = 0;
uint8_t *ht = hde32_table, m_mod, m_reg, m_rm, disp_size = 0;
memset(hs, 0, sizeof(hde32s));
for (x = 16; x; x--)
switch (c = *p++) {
case 0xf3:
hs->p_rep = c;
pref |= PRE_F3;
break;
case 0xf2:
hs->p_rep = c;
pref |= PRE_F2;
break;
case 0xf0:
hs->p_lock = c;
pref |= PRE_LOCK;
break;
case 0x26: case 0x2e: case 0x36:
case 0x3e: case 0x64: case 0x65:
hs->p_seg = c;
pref |= PRE_SEG;
break;
case 0x66:
hs->p_66 = c;
pref |= PRE_66;
break;
case 0x67:
hs->p_67 = c;
pref |= PRE_67;
break;
default:
goto pref_done;
}
pref_done:
hs->flags = (uint32_t)pref << 23;
if (!pref)
pref |= PRE_NONE;
if ((hs->opcode = c) == 0x0f) {
hs->opcode2 = c = *p++;
ht += DELTA_OPCODES;
} else if (c >= 0xa0 && c <= 0xa3) {
if (pref & PRE_67)
pref |= PRE_66;
else
pref &= ~PRE_66;
}
opcode = c;
cflags = ht[ht[opcode / 4] + (opcode % 4)];
if (cflags == C_ERROR) {
hs->flags |= F_ERROR | F_ERROR_OPCODE;
cflags = 0;
if ((opcode & -3) == 0x24)
cflags++;
}
x = 0;
if (cflags & C_GROUP) {
uint16_t t;
t = *(uint16_t *)(ht + (cflags & 0x7f));
cflags = (uint8_t)t;
x = (uint8_t)(t >> 8);
}
if (hs->opcode2) {
ht = hde32_table + DELTA_PREFIXES;
if (ht[ht[opcode / 4] + (opcode % 4)] & pref)
hs->flags |= F_ERROR | F_ERROR_OPCODE;
}
if (cflags & C_MODRM) {
hs->flags |= F_MODRM;
hs->modrm = c = *p++;
hs->modrm_mod = m_mod = c >> 6;
hs->modrm_rm = m_rm = c & 7;
hs->modrm_reg = m_reg = (c & 0x3f) >> 3;
if (x && ((x << m_reg) & 0x80))
hs->flags |= F_ERROR | F_ERROR_OPCODE;
if (!hs->opcode2 && opcode >= 0xd9 && opcode <= 0xdf) {
uint8_t t = opcode - 0xd9;
if (m_mod == 3) {
ht = hde32_table + DELTA_FPU_MODRM + t*8;
t = ht[m_reg] << m_rm;
} else {
ht = hde32_table + DELTA_FPU_REG;
t = ht[t] << m_reg;
}
if (t & 0x80)
hs->flags |= F_ERROR | F_ERROR_OPCODE;
}
if (pref & PRE_LOCK) {
if (m_mod == 3) {
hs->flags |= F_ERROR | F_ERROR_LOCK;
} else {
uint8_t *table_end, op = opcode;
if (hs->opcode2) {
ht = hde32_table + DELTA_OP2_LOCK_OK;
table_end = ht + DELTA_OP_ONLY_MEM - DELTA_OP2_LOCK_OK;
} else {
ht = hde32_table + DELTA_OP_LOCK_OK;
table_end = ht + DELTA_OP2_LOCK_OK - DELTA_OP_LOCK_OK;
op &= -2;
}
for (; ht != table_end; ht++)
if (*ht++ == op) {
if (!((*ht << m_reg) & 0x80))
goto no_lock_error;
else
break;
}
hs->flags |= F_ERROR | F_ERROR_LOCK;
no_lock_error:
;
}
}
if (hs->opcode2) {
switch (opcode) {
case 0x20: case 0x22:
m_mod = 3;
if (m_reg > 4 || m_reg == 1)
goto error_operand;
else
goto no_error_operand;
case 0x21: case 0x23:
m_mod = 3;
if (m_reg == 4 || m_reg == 5)
goto error_operand;
else
goto no_error_operand;
}
} else {
switch (opcode) {
case 0x8c:
if (m_reg > 5)
goto error_operand;
else
goto no_error_operand;
case 0x8e:
if (m_reg == 1 || m_reg > 5)
goto error_operand;
else
goto no_error_operand;
}
}
if (m_mod == 3) {
uint8_t *table_end;
if (hs->opcode2) {
ht = hde32_table + DELTA_OP2_ONLY_MEM;
table_end = ht + sizeof(hde32_table) - DELTA_OP2_ONLY_MEM;
} else {
ht = hde32_table + DELTA_OP_ONLY_MEM;
table_end = ht + DELTA_OP2_ONLY_MEM - DELTA_OP_ONLY_MEM;
}
for (; ht != table_end; ht += 2)
if (*ht++ == opcode) {
if ((*ht++ & pref) && !((*ht << m_reg) & 0x80))
goto error_operand;
else
break;
}
goto no_error_operand;
} else if (hs->opcode2) {
switch (opcode) {
case 0x50: case 0xd7: case 0xf7:
if (pref & (PRE_NONE | PRE_66))
goto error_operand;
break;
case 0xd6:
if (pref & (PRE_F2 | PRE_F3))
goto error_operand;
break;
case 0xc5:
goto error_operand;
}
goto no_error_operand;
} else
goto no_error_operand;
error_operand:
hs->flags |= F_ERROR | F_ERROR_OPERAND;
no_error_operand:
c = *p++;
if (m_reg <= 1) {
if (opcode == 0xf6)
cflags |= C_IMM8;
else if (opcode == 0xf7)
cflags |= C_IMM_P66;
}
switch (m_mod) {
case 0:
if (pref & PRE_67) {
if (m_rm == 6)
disp_size = 2;
} else
if (m_rm == 5)
disp_size = 4;
break;
case 1:
disp_size = 1;
break;
case 2:
disp_size = 2;
if (!(pref & PRE_67))
disp_size <<= 1;
break;
}
if (m_mod != 3 && m_rm == 4 && !(pref & PRE_67)) {
hs->flags |= F_SIB;
p++;
hs->sib = c;
hs->sib_scale = c >> 6;
hs->sib_index = (c & 0x3f) >> 3;
if ((hs->sib_base = c & 7) == 5 && !(m_mod & 1))
disp_size = 4;
}
p--;
switch (disp_size) {
case 1:
hs->flags |= F_DISP8;
hs->disp.disp8 = *p;
break;
case 2:
hs->flags |= F_DISP16;
hs->disp.disp16 = *(uint16_t *)p;
break;
case 4:
hs->flags |= F_DISP32;
hs->disp.disp32 = *(uint32_t *)p;
break;
}
p += disp_size;
} else if (pref & PRE_LOCK)
hs->flags |= F_ERROR | F_ERROR_LOCK;
if (cflags & C_IMM_P66) {
if (cflags & C_REL32) {
if (pref & PRE_66) {
hs->flags |= F_IMM16 | F_RELATIVE;
hs->imm.imm16 = *(uint16_t *)p;
p += 2;
goto disasm_done;
}
goto rel32_ok;
}
if (pref & PRE_66) {
hs->flags |= F_IMM16;
hs->imm.imm16 = *(uint16_t *)p;
p += 2;
} else {
hs->flags |= F_IMM32;
hs->imm.imm32 = *(uint32_t *)p;
p += 4;
}
}
if (cflags & C_IMM16) {
if (hs->flags & F_IMM32) {
hs->flags |= F_IMM16;
hs->disp.disp16 = *(uint16_t *)p;
} else if (hs->flags & F_IMM16) {
hs->flags |= F_2IMM16;
hs->disp.disp16 = *(uint16_t *)p;
} else {
hs->flags |= F_IMM16;
hs->imm.imm16 = *(uint16_t *)p;
}
p += 2;
}
if (cflags & C_IMM8) {
hs->flags |= F_IMM8;
hs->imm.imm8 = *p++;
}
if (cflags & C_REL32) {
rel32_ok:
hs->flags |= F_IMM32 | F_RELATIVE;
hs->imm.imm32 = *(uint32_t *)p;
p += 4;
} else if (cflags & C_REL8) {
hs->flags |= F_IMM8 | F_RELATIVE;
hs->imm.imm8 = *p++;
}
disasm_done:
if ((hs->len = (uint8_t)(p-(uint8_t *)code)) > 15) {
hs->flags |= F_ERROR | F_ERROR_LENGTH;
hs->len = 15;
}
return (unsigned int)hs->len;
}
#endif // defined(_M_IX86) || defined(__i386__)

View File

@ -0,0 +1,105 @@
/*
* Hacker Disassembler Engine 32
* Copyright (c) 2006-2009, Vyacheslav Patkov.
* All rights reserved.
*
* hde32.h: C/C++ header file
*
*/
#ifndef _HDE32_H_
#define _HDE32_H_
/* stdint.h - C99 standard header
* http://en.wikipedia.org/wiki/stdint.h
*
* if your compiler doesn't contain "stdint.h" header (for
* example, Microsoft Visual C++), you can download file:
* http://www.azillionmonkeys.com/qed/pstdint.h
* and change next line to:
* #include "pstdint.h"
*/
#include "pstdint.h"
#define F_MODRM 0x00000001
#define F_SIB 0x00000002
#define F_IMM8 0x00000004
#define F_IMM16 0x00000008
#define F_IMM32 0x00000010
#define F_DISP8 0x00000020
#define F_DISP16 0x00000040
#define F_DISP32 0x00000080
#define F_RELATIVE 0x00000100
#define F_2IMM16 0x00000800
#define F_ERROR 0x00001000
#define F_ERROR_OPCODE 0x00002000
#define F_ERROR_LENGTH 0x00004000
#define F_ERROR_LOCK 0x00008000
#define F_ERROR_OPERAND 0x00010000
#define F_PREFIX_REPNZ 0x01000000
#define F_PREFIX_REPX 0x02000000
#define F_PREFIX_REP 0x03000000
#define F_PREFIX_66 0x04000000
#define F_PREFIX_67 0x08000000
#define F_PREFIX_LOCK 0x10000000
#define F_PREFIX_SEG 0x20000000
#define F_PREFIX_ANY 0x3f000000
#define PREFIX_SEGMENT_CS 0x2e
#define PREFIX_SEGMENT_SS 0x36
#define PREFIX_SEGMENT_DS 0x3e
#define PREFIX_SEGMENT_ES 0x26
#define PREFIX_SEGMENT_FS 0x64
#define PREFIX_SEGMENT_GS 0x65
#define PREFIX_LOCK 0xf0
#define PREFIX_REPNZ 0xf2
#define PREFIX_REPX 0xf3
#define PREFIX_OPERAND_SIZE 0x66
#define PREFIX_ADDRESS_SIZE 0x67
#pragma pack(push,1)
typedef struct {
uint8_t len;
uint8_t p_rep;
uint8_t p_lock;
uint8_t p_seg;
uint8_t p_66;
uint8_t p_67;
uint8_t opcode;
uint8_t opcode2;
uint8_t modrm;
uint8_t modrm_mod;
uint8_t modrm_reg;
uint8_t modrm_rm;
uint8_t sib;
uint8_t sib_scale;
uint8_t sib_index;
uint8_t sib_base;
union {
uint8_t imm8;
uint16_t imm16;
uint32_t imm32;
} imm;
union {
uint8_t disp8;
uint16_t disp16;
uint32_t disp32;
} disp;
uint32_t flags;
} hde32s;
#pragma pack(pop)
#ifdef __cplusplus
extern "C" {
#endif
/* __cdecl */
unsigned int hde32_disasm(const void *code, hde32s *hs);
#ifdef __cplusplus
}
#endif
#endif /* _HDE32_H_ */

View File

@ -0,0 +1,333 @@
/*
* Hacker Disassembler Engine 64 C
* Copyright (c) 2008-2009, Vyacheslav Patkov.
* All rights reserved.
*
*/
#if defined(_M_X64) || defined(__x86_64__)
#include <string.h>
#include "hde64.h"
#include "table64.h"
unsigned int hde64_disasm(const void *code, hde64s *hs)
{
uint8_t x, c, *p = (uint8_t *)code, cflags, opcode, pref = 0;
uint8_t *ht = hde64_table, m_mod, m_reg, m_rm, disp_size = 0;
uint8_t op64 = 0;
memset(hs, 0, sizeof(hde64s));
for (x = 16; x; x--)
switch (c = *p++) {
case 0xf3:
hs->p_rep = c;
pref |= PRE_F3;
break;
case 0xf2:
hs->p_rep = c;
pref |= PRE_F2;
break;
case 0xf0:
hs->p_lock = c;
pref |= PRE_LOCK;
break;
case 0x26: case 0x2e: case 0x36:
case 0x3e: case 0x64: case 0x65:
hs->p_seg = c;
pref |= PRE_SEG;
break;
case 0x66:
hs->p_66 = c;
pref |= PRE_66;
break;
case 0x67:
hs->p_67 = c;
pref |= PRE_67;
break;
default:
goto pref_done;
}
pref_done:
hs->flags = (uint32_t)pref << 23;
if (!pref)
pref |= PRE_NONE;
if ((c & 0xf0) == 0x40) {
hs->flags |= F_PREFIX_REX;
if ((hs->rex_w = (c & 0xf) >> 3) && (*p & 0xf8) == 0xb8)
op64++;
hs->rex_r = (c & 7) >> 2;
hs->rex_x = (c & 3) >> 1;
hs->rex_b = c & 1;
if (((c = *p++) & 0xf0) == 0x40) {
opcode = c;
goto error_opcode;
}
}
if ((hs->opcode = c) == 0x0f) {
hs->opcode2 = c = *p++;
ht += DELTA_OPCODES;
} else if (c >= 0xa0 && c <= 0xa3) {
op64++;
if (pref & PRE_67)
pref |= PRE_66;
else
pref &= ~PRE_66;
}
opcode = c;
cflags = ht[ht[opcode / 4] + (opcode % 4)];
if (cflags == C_ERROR) {
error_opcode:
hs->flags |= F_ERROR | F_ERROR_OPCODE;
cflags = 0;
if ((opcode & -3) == 0x24)
cflags++;
}
x = 0;
if (cflags & C_GROUP) {
uint16_t t;
t = *(uint16_t *)(ht + (cflags & 0x7f));
cflags = (uint8_t)t;
x = (uint8_t)(t >> 8);
}
if (hs->opcode2) {
ht = hde64_table + DELTA_PREFIXES;
if (ht[ht[opcode / 4] + (opcode % 4)] & pref)
hs->flags |= F_ERROR | F_ERROR_OPCODE;
}
if (cflags & C_MODRM) {
hs->flags |= F_MODRM;
hs->modrm = c = *p++;
hs->modrm_mod = m_mod = c >> 6;
hs->modrm_rm = m_rm = c & 7;
hs->modrm_reg = m_reg = (c & 0x3f) >> 3;
if (x && ((x << m_reg) & 0x80))
hs->flags |= F_ERROR | F_ERROR_OPCODE;
if (!hs->opcode2 && opcode >= 0xd9 && opcode <= 0xdf) {
uint8_t t = opcode - 0xd9;
if (m_mod == 3) {
ht = hde64_table + DELTA_FPU_MODRM + t*8;
t = ht[m_reg] << m_rm;
} else {
ht = hde64_table + DELTA_FPU_REG;
t = ht[t] << m_reg;
}
if (t & 0x80)
hs->flags |= F_ERROR | F_ERROR_OPCODE;
}
if (pref & PRE_LOCK) {
if (m_mod == 3) {
hs->flags |= F_ERROR | F_ERROR_LOCK;
} else {
uint8_t *table_end, op = opcode;
if (hs->opcode2) {
ht = hde64_table + DELTA_OP2_LOCK_OK;
table_end = ht + DELTA_OP_ONLY_MEM - DELTA_OP2_LOCK_OK;
} else {
ht = hde64_table + DELTA_OP_LOCK_OK;
table_end = ht + DELTA_OP2_LOCK_OK - DELTA_OP_LOCK_OK;
op &= -2;
}
for (; ht != table_end; ht++)
if (*ht++ == op) {
if (!((*ht << m_reg) & 0x80))
goto no_lock_error;
else
break;
}
hs->flags |= F_ERROR | F_ERROR_LOCK;
no_lock_error:
;
}
}
if (hs->opcode2) {
switch (opcode) {
case 0x20: case 0x22:
m_mod = 3;
if (m_reg > 4 || m_reg == 1)
goto error_operand;
else
goto no_error_operand;
case 0x21: case 0x23:
m_mod = 3;
if (m_reg == 4 || m_reg == 5)
goto error_operand;
else
goto no_error_operand;
}
} else {
switch (opcode) {
case 0x8c:
if (m_reg > 5)
goto error_operand;
else
goto no_error_operand;
case 0x8e:
if (m_reg == 1 || m_reg > 5)
goto error_operand;
else
goto no_error_operand;
}
}
if (m_mod == 3) {
uint8_t *table_end;
if (hs->opcode2) {
ht = hde64_table + DELTA_OP2_ONLY_MEM;
table_end = ht + sizeof(hde64_table) - DELTA_OP2_ONLY_MEM;
} else {
ht = hde64_table + DELTA_OP_ONLY_MEM;
table_end = ht + DELTA_OP2_ONLY_MEM - DELTA_OP_ONLY_MEM;
}
for (; ht != table_end; ht += 2)
if (*ht++ == opcode) {
if (*ht++ & pref && !((*ht << m_reg) & 0x80))
goto error_operand;
else
break;
}
goto no_error_operand;
} else if (hs->opcode2) {
switch (opcode) {
case 0x50: case 0xd7: case 0xf7:
if (pref & (PRE_NONE | PRE_66))
goto error_operand;
break;
case 0xd6:
if (pref & (PRE_F2 | PRE_F3))
goto error_operand;
break;
case 0xc5:
goto error_operand;
}
goto no_error_operand;
} else
goto no_error_operand;
error_operand:
hs->flags |= F_ERROR | F_ERROR_OPERAND;
no_error_operand:
c = *p++;
if (m_reg <= 1) {
if (opcode == 0xf6)
cflags |= C_IMM8;
else if (opcode == 0xf7)
cflags |= C_IMM_P66;
}
switch (m_mod) {
case 0:
if (pref & PRE_67) {
if (m_rm == 6)
disp_size = 2;
} else
if (m_rm == 5)
disp_size = 4;
break;
case 1:
disp_size = 1;
break;
case 2:
disp_size = 2;
if (!(pref & PRE_67))
disp_size <<= 1;
}
if (m_mod != 3 && m_rm == 4) {
hs->flags |= F_SIB;
p++;
hs->sib = c;
hs->sib_scale = c >> 6;
hs->sib_index = (c & 0x3f) >> 3;
if ((hs->sib_base = c & 7) == 5 && !(m_mod & 1))
disp_size = 4;
}
p--;
switch (disp_size) {
case 1:
hs->flags |= F_DISP8;
hs->disp.disp8 = *p;
break;
case 2:
hs->flags |= F_DISP16;
hs->disp.disp16 = *(uint16_t *)p;
break;
case 4:
hs->flags |= F_DISP32;
hs->disp.disp32 = *(uint32_t *)p;
}
p += disp_size;
} else if (pref & PRE_LOCK)
hs->flags |= F_ERROR | F_ERROR_LOCK;
if (cflags & C_IMM_P66) {
if (cflags & C_REL32) {
if (pref & PRE_66) {
hs->flags |= F_IMM16 | F_RELATIVE;
hs->imm.imm16 = *(uint16_t *)p;
p += 2;
goto disasm_done;
}
goto rel32_ok;
}
if (op64) {
hs->flags |= F_IMM64;
hs->imm.imm64 = *(uint64_t *)p;
p += 8;
} else if (!(pref & PRE_66)) {
hs->flags |= F_IMM32;
hs->imm.imm32 = *(uint32_t *)p;
p += 4;
} else
goto imm16_ok;
}
if (cflags & C_IMM16) {
imm16_ok:
hs->flags |= F_IMM16;
hs->imm.imm16 = *(uint16_t *)p;
p += 2;
}
if (cflags & C_IMM8) {
hs->flags |= F_IMM8;
hs->imm.imm8 = *p++;
}
if (cflags & C_REL32) {
rel32_ok:
hs->flags |= F_IMM32 | F_RELATIVE;
hs->imm.imm32 = *(uint32_t *)p;
p += 4;
} else if (cflags & C_REL8) {
hs->flags |= F_IMM8 | F_RELATIVE;
hs->imm.imm8 = *p++;
}
disasm_done:
if ((hs->len = (uint8_t)(p-(uint8_t *)code)) > 15) {
hs->flags |= F_ERROR | F_ERROR_LENGTH;
hs->len = 15;
}
return (unsigned int)hs->len;
}
#endif // defined(_M_X64) || defined(__x86_64__)

View File

@ -0,0 +1,112 @@
/*
* Hacker Disassembler Engine 64
* Copyright (c) 2008-2009, Vyacheslav Patkov.
* All rights reserved.
*
* hde64.h: C/C++ header file
*
*/
#ifndef _HDE64_H_
#define _HDE64_H_
/* stdint.h - C99 standard header
* http://en.wikipedia.org/wiki/stdint.h
*
* if your compiler doesn't contain "stdint.h" header (for
* example, Microsoft Visual C++), you can download file:
* http://www.azillionmonkeys.com/qed/pstdint.h
* and change next line to:
* #include "pstdint.h"
*/
#include "pstdint.h"
#define F_MODRM 0x00000001
#define F_SIB 0x00000002
#define F_IMM8 0x00000004
#define F_IMM16 0x00000008
#define F_IMM32 0x00000010
#define F_IMM64 0x00000020
#define F_DISP8 0x00000040
#define F_DISP16 0x00000080
#define F_DISP32 0x00000100
#define F_RELATIVE 0x00000200
#define F_ERROR 0x00001000
#define F_ERROR_OPCODE 0x00002000
#define F_ERROR_LENGTH 0x00004000
#define F_ERROR_LOCK 0x00008000
#define F_ERROR_OPERAND 0x00010000
#define F_PREFIX_REPNZ 0x01000000
#define F_PREFIX_REPX 0x02000000
#define F_PREFIX_REP 0x03000000
#define F_PREFIX_66 0x04000000
#define F_PREFIX_67 0x08000000
#define F_PREFIX_LOCK 0x10000000
#define F_PREFIX_SEG 0x20000000
#define F_PREFIX_REX 0x40000000
#define F_PREFIX_ANY 0x7f000000
#define PREFIX_SEGMENT_CS 0x2e
#define PREFIX_SEGMENT_SS 0x36
#define PREFIX_SEGMENT_DS 0x3e
#define PREFIX_SEGMENT_ES 0x26
#define PREFIX_SEGMENT_FS 0x64
#define PREFIX_SEGMENT_GS 0x65
#define PREFIX_LOCK 0xf0
#define PREFIX_REPNZ 0xf2
#define PREFIX_REPX 0xf3
#define PREFIX_OPERAND_SIZE 0x66
#define PREFIX_ADDRESS_SIZE 0x67
#pragma pack(push,1)
typedef struct {
uint8_t len;
uint8_t p_rep;
uint8_t p_lock;
uint8_t p_seg;
uint8_t p_66;
uint8_t p_67;
uint8_t rex;
uint8_t rex_w;
uint8_t rex_r;
uint8_t rex_x;
uint8_t rex_b;
uint8_t opcode;
uint8_t opcode2;
uint8_t modrm;
uint8_t modrm_mod;
uint8_t modrm_reg;
uint8_t modrm_rm;
uint8_t sib;
uint8_t sib_scale;
uint8_t sib_index;
uint8_t sib_base;
union {
uint8_t imm8;
uint16_t imm16;
uint32_t imm32;
uint64_t imm64;
} imm;
union {
uint8_t disp8;
uint16_t disp16;
uint32_t disp32;
} disp;
uint32_t flags;
} hde64s;
#pragma pack(pop)
#ifdef __cplusplus
extern "C" {
#endif
/* __cdecl */
unsigned int hde64_disasm(const void *code, hde64s *hs);
#ifdef __cplusplus
}
#endif
#endif /* _HDE64_H_ */

View File

@ -0,0 +1,39 @@
/*
* MinHook - The Minimalistic API Hooking Library for x64/x86
* Copyright (C) 2009-2017 Tsuda Kageyu. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include <windows.h>
// Integer types for HDE.
typedef INT8 int8_t;
typedef INT16 int16_t;
typedef INT32 int32_t;
typedef INT64 int64_t;
typedef UINT8 uint8_t;
typedef UINT16 uint16_t;
typedef UINT32 uint32_t;
typedef UINT64 uint64_t;

View File

@ -0,0 +1,73 @@
/*
* Hacker Disassembler Engine 32 C
* Copyright (c) 2008-2009, Vyacheslav Patkov.
* All rights reserved.
*
*/
#define C_NONE 0x00
#define C_MODRM 0x01
#define C_IMM8 0x02
#define C_IMM16 0x04
#define C_IMM_P66 0x10
#define C_REL8 0x20
#define C_REL32 0x40
#define C_GROUP 0x80
#define C_ERROR 0xff
#define PRE_ANY 0x00
#define PRE_NONE 0x01
#define PRE_F2 0x02
#define PRE_F3 0x04
#define PRE_66 0x08
#define PRE_67 0x10
#define PRE_LOCK 0x20
#define PRE_SEG 0x40
#define PRE_ALL 0xff
#define DELTA_OPCODES 0x4a
#define DELTA_FPU_REG 0xf1
#define DELTA_FPU_MODRM 0xf8
#define DELTA_PREFIXES 0x130
#define DELTA_OP_LOCK_OK 0x1a1
#define DELTA_OP2_LOCK_OK 0x1b9
#define DELTA_OP_ONLY_MEM 0x1cb
#define DELTA_OP2_ONLY_MEM 0x1da
unsigned char hde32_table[] = {
0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,
0xa8,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xac,0xaa,0xb2,0xaa,0x9f,0x9f,
0x9f,0x9f,0xb5,0xa3,0xa3,0xa4,0xaa,0xaa,0xba,0xaa,0x96,0xaa,0xa8,0xaa,0xc3,
0xc3,0x96,0x96,0xb7,0xae,0xd6,0xbd,0xa3,0xc5,0xa3,0xa3,0x9f,0xc3,0x9c,0xaa,
0xaa,0xac,0xaa,0xbf,0x03,0x7f,0x11,0x7f,0x01,0x7f,0x01,0x3f,0x01,0x01,0x90,
0x82,0x7d,0x97,0x59,0x59,0x59,0x59,0x59,0x7f,0x59,0x59,0x60,0x7d,0x7f,0x7f,
0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x9a,0x88,0x7d,
0x59,0x50,0x50,0x50,0x50,0x59,0x59,0x59,0x59,0x61,0x94,0x61,0x9e,0x59,0x59,
0x85,0x59,0x92,0xa3,0x60,0x60,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,
0x59,0x59,0x9f,0x01,0x03,0x01,0x04,0x03,0xd5,0x03,0xcc,0x01,0xbc,0x03,0xf0,
0x10,0x10,0x10,0x10,0x50,0x50,0x50,0x50,0x14,0x20,0x20,0x20,0x20,0x01,0x01,
0x01,0x01,0xc4,0x02,0x10,0x00,0x00,0x00,0x00,0x01,0x01,0xc0,0xc2,0x10,0x11,
0x02,0x03,0x11,0x03,0x03,0x04,0x00,0x00,0x14,0x00,0x02,0x00,0x00,0xc6,0xc8,
0x02,0x02,0x02,0x02,0x00,0x00,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0xff,0xca,
0x01,0x01,0x01,0x00,0x06,0x00,0x04,0x00,0xc0,0xc2,0x01,0x01,0x03,0x01,0xff,
0xff,0x01,0x00,0x03,0xc4,0xc4,0xc6,0x03,0x01,0x01,0x01,0xff,0x03,0x03,0x03,
0xc8,0x40,0x00,0x0a,0x00,0x04,0x00,0x00,0x00,0x00,0x7f,0x00,0x33,0x01,0x00,
0x00,0x00,0x00,0x00,0x00,0xff,0xbf,0xff,0xff,0x00,0x00,0x00,0x00,0x07,0x00,
0x00,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0xff,0xff,0x00,0x00,0x00,0xbf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x7f,0x00,0x00,0xff,0x4a,0x4a,0x4a,0x4a,0x4b,0x52,0x4a,0x4a,0x4a,0x4a,0x4f,
0x4c,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x55,0x45,0x40,0x4a,0x4a,0x4a,
0x45,0x59,0x4d,0x46,0x4a,0x5d,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,
0x4a,0x4a,0x4a,0x4a,0x4a,0x61,0x63,0x67,0x4e,0x4a,0x4a,0x6b,0x6d,0x4a,0x4a,
0x45,0x6d,0x4a,0x4a,0x44,0x45,0x4a,0x4a,0x00,0x00,0x00,0x02,0x0d,0x06,0x06,
0x06,0x06,0x0e,0x00,0x00,0x00,0x00,0x06,0x06,0x06,0x00,0x06,0x06,0x02,0x06,
0x00,0x0a,0x0a,0x07,0x07,0x06,0x02,0x05,0x05,0x02,0x02,0x00,0x00,0x04,0x04,
0x04,0x04,0x00,0x00,0x00,0x0e,0x05,0x06,0x06,0x06,0x01,0x06,0x00,0x00,0x08,
0x00,0x10,0x00,0x18,0x00,0x20,0x00,0x28,0x00,0x30,0x00,0x80,0x01,0x82,0x01,
0x86,0x00,0xf6,0xcf,0xfe,0x3f,0xab,0x00,0xb0,0x00,0xb1,0x00,0xb3,0x00,0xba,
0xf8,0xbb,0x00,0xc0,0x00,0xc1,0x00,0xc7,0xbf,0x62,0xff,0x00,0x8d,0xff,0x00,
0xc4,0xff,0x00,0xc5,0xff,0x00,0xff,0xff,0xeb,0x01,0xff,0x0e,0x12,0x08,0x00,
0x13,0x09,0x00,0x16,0x08,0x00,0x17,0x09,0x00,0x2b,0x09,0x00,0xae,0xff,0x07,
0xb2,0xff,0x00,0xb4,0xff,0x00,0xb5,0xff,0x00,0xc3,0x01,0x00,0xc7,0xff,0xbf,
0xe7,0x08,0x00,0xf0,0x02,0x00
};

View File

@ -0,0 +1,74 @@
/*
* Hacker Disassembler Engine 64 C
* Copyright (c) 2008-2009, Vyacheslav Patkov.
* All rights reserved.
*
*/
#define C_NONE 0x00
#define C_MODRM 0x01
#define C_IMM8 0x02
#define C_IMM16 0x04
#define C_IMM_P66 0x10
#define C_REL8 0x20
#define C_REL32 0x40
#define C_GROUP 0x80
#define C_ERROR 0xff
#define PRE_ANY 0x00
#define PRE_NONE 0x01
#define PRE_F2 0x02
#define PRE_F3 0x04
#define PRE_66 0x08
#define PRE_67 0x10
#define PRE_LOCK 0x20
#define PRE_SEG 0x40
#define PRE_ALL 0xff
#define DELTA_OPCODES 0x4a
#define DELTA_FPU_REG 0xfd
#define DELTA_FPU_MODRM 0x104
#define DELTA_PREFIXES 0x13c
#define DELTA_OP_LOCK_OK 0x1ae
#define DELTA_OP2_LOCK_OK 0x1c6
#define DELTA_OP_ONLY_MEM 0x1d8
#define DELTA_OP2_ONLY_MEM 0x1e7
unsigned char hde64_table[] = {
0xa5,0xaa,0xa5,0xb8,0xa5,0xaa,0xa5,0xaa,0xa5,0xb8,0xa5,0xb8,0xa5,0xb8,0xa5,
0xb8,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xac,0xc0,0xcc,0xc0,0xa1,0xa1,
0xa1,0xa1,0xb1,0xa5,0xa5,0xa6,0xc0,0xc0,0xd7,0xda,0xe0,0xc0,0xe4,0xc0,0xea,
0xea,0xe0,0xe0,0x98,0xc8,0xee,0xf1,0xa5,0xd3,0xa5,0xa5,0xa1,0xea,0x9e,0xc0,
0xc0,0xc2,0xc0,0xe6,0x03,0x7f,0x11,0x7f,0x01,0x7f,0x01,0x3f,0x01,0x01,0xab,
0x8b,0x90,0x64,0x5b,0x5b,0x5b,0x5b,0x5b,0x92,0x5b,0x5b,0x76,0x90,0x92,0x92,
0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x6a,0x73,0x90,
0x5b,0x52,0x52,0x52,0x52,0x5b,0x5b,0x5b,0x5b,0x77,0x7c,0x77,0x85,0x5b,0x5b,
0x70,0x5b,0x7a,0xaf,0x76,0x76,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,
0x5b,0x5b,0x86,0x01,0x03,0x01,0x04,0x03,0xd5,0x03,0xd5,0x03,0xcc,0x01,0xbc,
0x03,0xf0,0x03,0x03,0x04,0x00,0x50,0x50,0x50,0x50,0xff,0x20,0x20,0x20,0x20,
0x01,0x01,0x01,0x01,0xc4,0x02,0x10,0xff,0xff,0xff,0x01,0x00,0x03,0x11,0xff,
0x03,0xc4,0xc6,0xc8,0x02,0x10,0x00,0xff,0xcc,0x01,0x01,0x01,0x00,0x00,0x00,
0x00,0x01,0x01,0x03,0x01,0xff,0xff,0xc0,0xc2,0x10,0x11,0x02,0x03,0x01,0x01,
0x01,0xff,0xff,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0xff,0xff,0xff,0xff,0x10,
0x10,0x10,0x10,0x02,0x10,0x00,0x00,0xc6,0xc8,0x02,0x02,0x02,0x02,0x06,0x00,
0x04,0x00,0x02,0xff,0x00,0xc0,0xc2,0x01,0x01,0x03,0x03,0x03,0xca,0x40,0x00,
0x0a,0x00,0x04,0x00,0x00,0x00,0x00,0x7f,0x00,0x33,0x01,0x00,0x00,0x00,0x00,
0x00,0x00,0xff,0xbf,0xff,0xff,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0xff,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,
0x00,0x00,0x00,0xbf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7f,0x00,0x00,
0xff,0x40,0x40,0x40,0x40,0x41,0x49,0x40,0x40,0x40,0x40,0x4c,0x42,0x40,0x40,
0x40,0x40,0x40,0x40,0x40,0x40,0x4f,0x44,0x53,0x40,0x40,0x40,0x44,0x57,0x43,
0x5c,0x40,0x60,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
0x40,0x40,0x64,0x66,0x6e,0x6b,0x40,0x40,0x6a,0x46,0x40,0x40,0x44,0x46,0x40,
0x40,0x5b,0x44,0x40,0x40,0x00,0x00,0x00,0x00,0x06,0x06,0x06,0x06,0x01,0x06,
0x06,0x02,0x06,0x06,0x00,0x06,0x00,0x0a,0x0a,0x00,0x00,0x00,0x02,0x07,0x07,
0x06,0x02,0x0d,0x06,0x06,0x06,0x0e,0x05,0x05,0x02,0x02,0x00,0x00,0x04,0x04,
0x04,0x04,0x05,0x06,0x06,0x06,0x00,0x00,0x00,0x0e,0x00,0x00,0x08,0x00,0x10,
0x00,0x18,0x00,0x20,0x00,0x28,0x00,0x30,0x00,0x80,0x01,0x82,0x01,0x86,0x00,
0xf6,0xcf,0xfe,0x3f,0xab,0x00,0xb0,0x00,0xb1,0x00,0xb3,0x00,0xba,0xf8,0xbb,
0x00,0xc0,0x00,0xc1,0x00,0xc7,0xbf,0x62,0xff,0x00,0x8d,0xff,0x00,0xc4,0xff,
0x00,0xc5,0xff,0x00,0xff,0xff,0xeb,0x01,0xff,0x0e,0x12,0x08,0x00,0x13,0x09,
0x00,0x16,0x08,0x00,0x17,0x09,0x00,0x2b,0x09,0x00,0xae,0xff,0x07,0xb2,0xff,
0x00,0xb4,0xff,0x00,0xb5,0xff,0x00,0xc3,0x01,0x00,0xc7,0xff,0xbf,0xe7,0x08,
0x00,0xf0,0x02,0x00
};

View File

@ -0,0 +1,923 @@
/*
* MinHook - The Minimalistic API Hooking Library for x64/x86
* Copyright (C) 2009-2017 Tsuda Kageyu.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <windows.h>
#include <tlhelp32.h>
#include <limits.h>
#include "MinHook.h"
#include "buffer.h"
#include "trampoline.h"
#ifndef ARRAYSIZE
#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
#endif
// Initial capacity of the HOOK_ENTRY buffer.
#define INITIAL_HOOK_CAPACITY 32
// Initial capacity of the thread IDs buffer.
#define INITIAL_THREAD_CAPACITY 128
// Special hook position values.
#define INVALID_HOOK_POS UINT_MAX
#define ALL_HOOKS_POS UINT_MAX
// Freeze() action argument defines.
#define ACTION_DISABLE 0
#define ACTION_ENABLE 1
#define ACTION_APPLY_QUEUED 2
// Thread access rights for suspending/resuming threads.
#define THREAD_ACCESS \
(THREAD_SUSPEND_RESUME | THREAD_GET_CONTEXT | THREAD_QUERY_INFORMATION | THREAD_SET_CONTEXT)
// Hook information.
typedef struct _HOOK_ENTRY
{
LPVOID pTarget; // Address of the target function.
LPVOID pDetour; // Address of the detour or relay function.
LPVOID pTrampoline; // Address of the trampoline function.
UINT8 backup[8]; // Original prologue of the target function.
UINT8 patchAbove : 1; // Uses the hot patch area.
UINT8 isEnabled : 1; // Enabled.
UINT8 queueEnable : 1; // Queued for enabling/disabling when != isEnabled.
UINT nIP : 4; // Count of the instruction boundaries.
UINT8 oldIPs[8]; // Instruction boundaries of the target function.
UINT8 newIPs[8]; // Instruction boundaries of the trampoline function.
} HOOK_ENTRY, *PHOOK_ENTRY;
// Suspended threads for Freeze()/Unfreeze().
typedef struct _FROZEN_THREADS
{
LPDWORD pItems; // Data heap
UINT capacity; // Size of allocated data heap, items
UINT size; // Actual number of data items
} FROZEN_THREADS, *PFROZEN_THREADS;
//-------------------------------------------------------------------------
// Global Variables:
//-------------------------------------------------------------------------
// Spin lock flag for EnterSpinLock()/LeaveSpinLock().
volatile LONG g_isLocked = FALSE;
// Private heap handle. If not NULL, this library is initialized.
HANDLE g_hHeap = NULL;
// Hook entries.
struct
{
PHOOK_ENTRY pItems; // Data heap
UINT capacity; // Size of allocated data heap, items
UINT size; // Actual number of data items
} g_hooks;
//-------------------------------------------------------------------------
// Returns INVALID_HOOK_POS if not found.
static UINT FindHookEntry(LPVOID pTarget)
{
UINT i;
for (i = 0; i < g_hooks.size; ++i)
{
if ((ULONG_PTR)pTarget == (ULONG_PTR)g_hooks.pItems[i].pTarget)
return i;
}
return INVALID_HOOK_POS;
}
//-------------------------------------------------------------------------
static PHOOK_ENTRY AddHookEntry()
{
if (g_hooks.pItems == NULL)
{
g_hooks.capacity = INITIAL_HOOK_CAPACITY;
g_hooks.pItems = (PHOOK_ENTRY)HeapAlloc(
g_hHeap, 0, g_hooks.capacity * sizeof(HOOK_ENTRY));
if (g_hooks.pItems == NULL)
return NULL;
}
else if (g_hooks.size >= g_hooks.capacity)
{
PHOOK_ENTRY p = (PHOOK_ENTRY)HeapReAlloc(
g_hHeap, 0, g_hooks.pItems, (g_hooks.capacity * 2) * sizeof(HOOK_ENTRY));
if (p == NULL)
return NULL;
g_hooks.capacity *= 2;
g_hooks.pItems = p;
}
return &g_hooks.pItems[g_hooks.size++];
}
//-------------------------------------------------------------------------
static VOID DeleteHookEntry(UINT pos)
{
if (pos < g_hooks.size - 1)
g_hooks.pItems[pos] = g_hooks.pItems[g_hooks.size - 1];
g_hooks.size--;
if (g_hooks.capacity / 2 >= INITIAL_HOOK_CAPACITY && g_hooks.capacity / 2 >= g_hooks.size)
{
PHOOK_ENTRY p = (PHOOK_ENTRY)HeapReAlloc(
g_hHeap, 0, g_hooks.pItems, (g_hooks.capacity / 2) * sizeof(HOOK_ENTRY));
if (p == NULL)
return;
g_hooks.capacity /= 2;
g_hooks.pItems = p;
}
}
//-------------------------------------------------------------------------
static DWORD_PTR FindOldIP(PHOOK_ENTRY pHook, DWORD_PTR ip)
{
UINT i;
if (pHook->patchAbove && ip == ((DWORD_PTR)pHook->pTarget - sizeof(JMP_REL)))
return (DWORD_PTR)pHook->pTarget;
for (i = 0; i < pHook->nIP; ++i)
{
if (ip == ((DWORD_PTR)pHook->pTrampoline + pHook->newIPs[i]))
return (DWORD_PTR)pHook->pTarget + pHook->oldIPs[i];
}
#if defined(_M_X64) || defined(__x86_64__)
// Check relay function.
if (ip == (DWORD_PTR)pHook->pDetour)
return (DWORD_PTR)pHook->pTarget;
#endif
return 0;
}
//-------------------------------------------------------------------------
static DWORD_PTR FindNewIP(PHOOK_ENTRY pHook, DWORD_PTR ip)
{
UINT i;
for (i = 0; i < pHook->nIP; ++i)
{
if (ip == ((DWORD_PTR)pHook->pTarget + pHook->oldIPs[i]))
return (DWORD_PTR)pHook->pTrampoline + pHook->newIPs[i];
}
return 0;
}
//-------------------------------------------------------------------------
static VOID ProcessThreadIPs(HANDLE hThread, UINT pos, UINT action)
{
// If the thread suspended in the overwritten area,
// move IP to the proper address.
CONTEXT c;
#if defined(_M_X64) || defined(__x86_64__)
DWORD64 *pIP = &c.Rip;
#else
DWORD *pIP = &c.Eip;
#endif
UINT count;
c.ContextFlags = CONTEXT_CONTROL;
if (!GetThreadContext(hThread, &c))
return;
if (pos == ALL_HOOKS_POS)
{
pos = 0;
count = g_hooks.size;
}
else
{
count = pos + 1;
}
for (; pos < count; ++pos)
{
PHOOK_ENTRY pHook = &g_hooks.pItems[pos];
BOOL enable;
DWORD_PTR ip;
switch (action)
{
case ACTION_DISABLE:
enable = FALSE;
break;
case ACTION_ENABLE:
enable = TRUE;
break;
default: // ACTION_APPLY_QUEUED
enable = pHook->queueEnable;
break;
}
if (pHook->isEnabled == enable)
continue;
if (enable)
ip = FindNewIP(pHook, *pIP);
else
ip = FindOldIP(pHook, *pIP);
if (ip != 0)
{
*pIP = ip;
SetThreadContext(hThread, &c);
}
}
}
//-------------------------------------------------------------------------
static BOOL EnumerateThreads(PFROZEN_THREADS pThreads)
{
BOOL succeeded = FALSE;
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
if (hSnapshot != INVALID_HANDLE_VALUE)
{
THREADENTRY32 te;
te.dwSize = sizeof(THREADENTRY32);
if (Thread32First(hSnapshot, &te))
{
succeeded = TRUE;
do
{
if (te.dwSize >= (FIELD_OFFSET(THREADENTRY32, th32OwnerProcessID) + sizeof(DWORD))
&& te.th32OwnerProcessID == GetCurrentProcessId()
&& te.th32ThreadID != GetCurrentThreadId())
{
if (pThreads->pItems == NULL)
{
pThreads->capacity = INITIAL_THREAD_CAPACITY;
pThreads->pItems
= (LPDWORD)HeapAlloc(g_hHeap, 0, pThreads->capacity * sizeof(DWORD));
if (pThreads->pItems == NULL)
{
succeeded = FALSE;
break;
}
}
else if (pThreads->size >= pThreads->capacity)
{
pThreads->capacity *= 2;
LPDWORD p = (LPDWORD)HeapReAlloc(
g_hHeap, 0, pThreads->pItems, pThreads->capacity * sizeof(DWORD));
if (p == NULL)
{
succeeded = FALSE;
break;
}
pThreads->pItems = p;
}
pThreads->pItems[pThreads->size++] = te.th32ThreadID;
}
te.dwSize = sizeof(THREADENTRY32);
} while (Thread32Next(hSnapshot, &te));
if (succeeded && GetLastError() != ERROR_NO_MORE_FILES)
succeeded = FALSE;
if (!succeeded && pThreads->pItems != NULL)
{
HeapFree(g_hHeap, 0, pThreads->pItems);
pThreads->pItems = NULL;
}
}
CloseHandle(hSnapshot);
}
return succeeded;
}
//-------------------------------------------------------------------------
static MH_STATUS Freeze(PFROZEN_THREADS pThreads, UINT pos, UINT action)
{
MH_STATUS status = MH_OK;
pThreads->pItems = NULL;
pThreads->capacity = 0;
pThreads->size = 0;
if (!EnumerateThreads(pThreads))
{
status = MH_ERROR_MEMORY_ALLOC;
}
else if (pThreads->pItems != NULL)
{
UINT i;
for (i = 0; i < pThreads->size; ++i)
{
HANDLE hThread = OpenThread(THREAD_ACCESS, FALSE, pThreads->pItems[i]);
if (hThread != NULL)
{
SuspendThread(hThread);
ProcessThreadIPs(hThread, pos, action);
CloseHandle(hThread);
}
}
}
return status;
}
//-------------------------------------------------------------------------
static VOID Unfreeze(PFROZEN_THREADS pThreads)
{
if (pThreads->pItems != NULL)
{
UINT i;
for (i = 0; i < pThreads->size; ++i)
{
HANDLE hThread = OpenThread(THREAD_ACCESS, FALSE, pThreads->pItems[i]);
if (hThread != NULL)
{
ResumeThread(hThread);
CloseHandle(hThread);
}
}
HeapFree(g_hHeap, 0, pThreads->pItems);
}
}
//-------------------------------------------------------------------------
static MH_STATUS EnableHookLL(UINT pos, BOOL enable)
{
PHOOK_ENTRY pHook = &g_hooks.pItems[pos];
DWORD oldProtect;
SIZE_T patchSize = sizeof(JMP_REL);
LPBYTE pPatchTarget = (LPBYTE)pHook->pTarget;
if (pHook->patchAbove)
{
pPatchTarget -= sizeof(JMP_REL);
patchSize += sizeof(JMP_REL_SHORT);
}
if (!VirtualProtect(pPatchTarget, patchSize, PAGE_EXECUTE_READWRITE, &oldProtect))
return MH_ERROR_MEMORY_PROTECT;
if (enable)
{
PJMP_REL pJmp = (PJMP_REL)pPatchTarget;
pJmp->opcode = 0xE9;
pJmp->operand = (UINT32)((LPBYTE)pHook->pDetour - (pPatchTarget + sizeof(JMP_REL)));
if (pHook->patchAbove)
{
PJMP_REL_SHORT pShortJmp = (PJMP_REL_SHORT)pHook->pTarget;
pShortJmp->opcode = 0xEB;
pShortJmp->operand = (UINT8)(0 - (sizeof(JMP_REL_SHORT) + sizeof(JMP_REL)));
}
}
else
{
if (pHook->patchAbove)
memcpy(pPatchTarget, pHook->backup, sizeof(JMP_REL) + sizeof(JMP_REL_SHORT));
else
memcpy(pPatchTarget, pHook->backup, sizeof(JMP_REL));
}
VirtualProtect(pPatchTarget, patchSize, oldProtect, &oldProtect);
// Just-in-case measure.
FlushInstructionCache(GetCurrentProcess(), pPatchTarget, patchSize);
pHook->isEnabled = enable;
pHook->queueEnable = enable;
return MH_OK;
}
//-------------------------------------------------------------------------
static MH_STATUS EnableAllHooksLL(BOOL enable)
{
MH_STATUS status = MH_OK;
UINT i, first = INVALID_HOOK_POS;
for (i = 0; i < g_hooks.size; ++i)
{
if (g_hooks.pItems[i].isEnabled != enable)
{
first = i;
break;
}
}
if (first != INVALID_HOOK_POS)
{
FROZEN_THREADS threads;
status = Freeze(&threads, ALL_HOOKS_POS, enable ? ACTION_ENABLE : ACTION_DISABLE);
if (status == MH_OK)
{
for (i = first; i < g_hooks.size; ++i)
{
if (g_hooks.pItems[i].isEnabled != enable)
{
status = EnableHookLL(i, enable);
if (status != MH_OK)
break;
}
}
Unfreeze(&threads);
}
}
return status;
}
//-------------------------------------------------------------------------
static VOID EnterSpinLock(VOID)
{
SIZE_T spinCount = 0;
// Wait until the flag is FALSE.
while (InterlockedCompareExchange(&g_isLocked, TRUE, FALSE) != FALSE)
{
// No need to generate a memory barrier here, since InterlockedCompareExchange()
// generates a full memory barrier itself.
// Prevent the loop from being too busy.
if (spinCount < 32)
Sleep(0);
else
Sleep(1);
spinCount++;
}
}
//-------------------------------------------------------------------------
static VOID LeaveSpinLock(VOID)
{
// No need to generate a memory barrier here, since InterlockedExchange()
// generates a full memory barrier itself.
InterlockedExchange(&g_isLocked, FALSE);
}
//-------------------------------------------------------------------------
MH_STATUS WINAPI MH_Initialize(VOID)
{
MH_STATUS status = MH_OK;
EnterSpinLock();
if (g_hHeap == NULL)
{
g_hHeap = HeapCreate(0, 0, 0);
if (g_hHeap != NULL)
{
// Initialize the internal function buffer.
InitializeBuffer();
}
else
{
status = MH_ERROR_MEMORY_ALLOC;
}
}
else
{
status = MH_ERROR_ALREADY_INITIALIZED;
}
LeaveSpinLock();
return status;
}
//-------------------------------------------------------------------------
MH_STATUS WINAPI MH_Uninitialize(VOID)
{
MH_STATUS status = MH_OK;
EnterSpinLock();
if (g_hHeap != NULL)
{
status = EnableAllHooksLL(FALSE);
if (status == MH_OK)
{
// Free the internal function buffer.
// HeapFree is actually not required, but some tools detect a false
// memory leak without HeapFree.
UninitializeBuffer();
HeapFree(g_hHeap, 0, g_hooks.pItems);
HeapDestroy(g_hHeap);
g_hHeap = NULL;
g_hooks.pItems = NULL;
g_hooks.capacity = 0;
g_hooks.size = 0;
}
}
else
{
status = MH_ERROR_NOT_INITIALIZED;
}
LeaveSpinLock();
return status;
}
//-------------------------------------------------------------------------
MH_STATUS WINAPI MH_CreateHook(LPVOID pTarget, LPVOID pDetour, LPVOID *ppOriginal)
{
MH_STATUS status = MH_OK;
EnterSpinLock();
if (g_hHeap != NULL)
{
if (IsExecutableAddress(pTarget) && IsExecutableAddress(pDetour))
{
UINT pos = FindHookEntry(pTarget);
if (pos == INVALID_HOOK_POS)
{
LPVOID pBuffer = AllocateBuffer(pTarget);
if (pBuffer != NULL)
{
TRAMPOLINE ct;
ct.pTarget = pTarget;
ct.pDetour = pDetour;
ct.pTrampoline = pBuffer;
if (CreateTrampolineFunction(&ct))
{
PHOOK_ENTRY pHook = AddHookEntry();
if (pHook != NULL)
{
pHook->pTarget = ct.pTarget;
#if defined(_M_X64) || defined(__x86_64__)
pHook->pDetour = ct.pRelay;
#else
pHook->pDetour = ct.pDetour;
#endif
pHook->pTrampoline = ct.pTrampoline;
pHook->patchAbove = ct.patchAbove;
pHook->isEnabled = FALSE;
pHook->queueEnable = FALSE;
pHook->nIP = ct.nIP;
memcpy(pHook->oldIPs, ct.oldIPs, ARRAYSIZE(ct.oldIPs));
memcpy(pHook->newIPs, ct.newIPs, ARRAYSIZE(ct.newIPs));
// Back up the target function.
if (ct.patchAbove)
{
memcpy(
pHook->backup,
(LPBYTE)pTarget - sizeof(JMP_REL),
sizeof(JMP_REL) + sizeof(JMP_REL_SHORT));
}
else
{
memcpy(pHook->backup, pTarget, sizeof(JMP_REL));
}
if (ppOriginal != NULL)
*ppOriginal = pHook->pTrampoline;
}
else
{
status = MH_ERROR_MEMORY_ALLOC;
}
}
else
{
status = MH_ERROR_UNSUPPORTED_FUNCTION;
}
if (status != MH_OK)
{
FreeBuffer(pBuffer);
}
}
else
{
status = MH_ERROR_MEMORY_ALLOC;
}
}
else
{
status = MH_ERROR_ALREADY_CREATED;
}
}
else
{
status = MH_ERROR_NOT_EXECUTABLE;
}
}
else
{
status = MH_ERROR_NOT_INITIALIZED;
}
LeaveSpinLock();
return status;
}
//-------------------------------------------------------------------------
MH_STATUS WINAPI MH_RemoveHook(LPVOID pTarget)
{
MH_STATUS status = MH_OK;
EnterSpinLock();
if (g_hHeap != NULL)
{
UINT pos = FindHookEntry(pTarget);
if (pos != INVALID_HOOK_POS)
{
if (g_hooks.pItems[pos].isEnabled)
{
FROZEN_THREADS threads;
status = Freeze(&threads, pos, ACTION_DISABLE);
if (status == MH_OK)
{
status = EnableHookLL(pos, FALSE);
Unfreeze(&threads);
}
}
if (status == MH_OK)
{
FreeBuffer(g_hooks.pItems[pos].pTrampoline);
DeleteHookEntry(pos);
}
}
else
{
status = MH_ERROR_NOT_CREATED;
}
}
else
{
status = MH_ERROR_NOT_INITIALIZED;
}
LeaveSpinLock();
return status;
}
//-------------------------------------------------------------------------
static MH_STATUS EnableHook(LPVOID pTarget, BOOL enable)
{
MH_STATUS status = MH_OK;
EnterSpinLock();
if (g_hHeap != NULL)
{
if (pTarget == MH_ALL_HOOKS)
{
status = EnableAllHooksLL(enable);
}
else
{
UINT pos = FindHookEntry(pTarget);
if (pos != INVALID_HOOK_POS)
{
if (g_hooks.pItems[pos].isEnabled != enable)
{
FROZEN_THREADS threads;
status = Freeze(&threads, pos, ACTION_ENABLE);
if (status == MH_OK)
{
status = EnableHookLL(pos, enable);
Unfreeze(&threads);
}
}
else
{
status = enable ? MH_ERROR_ENABLED : MH_ERROR_DISABLED;
}
}
else
{
status = MH_ERROR_NOT_CREATED;
}
}
}
else
{
status = MH_ERROR_NOT_INITIALIZED;
}
LeaveSpinLock();
return status;
}
//-------------------------------------------------------------------------
MH_STATUS WINAPI MH_EnableHook(LPVOID pTarget)
{
return EnableHook(pTarget, TRUE);
}
//-------------------------------------------------------------------------
MH_STATUS WINAPI MH_DisableHook(LPVOID pTarget)
{
return EnableHook(pTarget, FALSE);
}
//-------------------------------------------------------------------------
static MH_STATUS QueueHook(LPVOID pTarget, BOOL queueEnable)
{
MH_STATUS status = MH_OK;
EnterSpinLock();
if (g_hHeap != NULL)
{
if (pTarget == MH_ALL_HOOKS)
{
UINT i;
for (i = 0; i < g_hooks.size; ++i)
g_hooks.pItems[i].queueEnable = queueEnable;
}
else
{
UINT pos = FindHookEntry(pTarget);
if (pos != INVALID_HOOK_POS)
{
g_hooks.pItems[pos].queueEnable = queueEnable;
}
else
{
status = MH_ERROR_NOT_CREATED;
}
}
}
else
{
status = MH_ERROR_NOT_INITIALIZED;
}
LeaveSpinLock();
return status;
}
//-------------------------------------------------------------------------
MH_STATUS WINAPI MH_QueueEnableHook(LPVOID pTarget)
{
return QueueHook(pTarget, TRUE);
}
//-------------------------------------------------------------------------
MH_STATUS WINAPI MH_QueueDisableHook(LPVOID pTarget)
{
return QueueHook(pTarget, FALSE);
}
//-------------------------------------------------------------------------
MH_STATUS WINAPI MH_ApplyQueued(VOID)
{
MH_STATUS status = MH_OK;
UINT i, first = INVALID_HOOK_POS;
EnterSpinLock();
if (g_hHeap != NULL)
{
for (i = 0; i < g_hooks.size; ++i)
{
if (g_hooks.pItems[i].isEnabled != g_hooks.pItems[i].queueEnable)
{
first = i;
break;
}
}
if (first != INVALID_HOOK_POS)
{
FROZEN_THREADS threads;
status = Freeze(&threads, ALL_HOOKS_POS, ACTION_APPLY_QUEUED);
if (status == MH_OK)
{
for (i = first; i < g_hooks.size; ++i)
{
PHOOK_ENTRY pHook = &g_hooks.pItems[i];
if (pHook->isEnabled != pHook->queueEnable)
{
status = EnableHookLL(i, pHook->queueEnable);
if (status != MH_OK)
break;
}
}
Unfreeze(&threads);
}
}
}
else
{
status = MH_ERROR_NOT_INITIALIZED;
}
LeaveSpinLock();
return status;
}
//-------------------------------------------------------------------------
MH_STATUS WINAPI MH_CreateHookApiEx(
LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour,
LPVOID *ppOriginal, LPVOID *ppTarget)
{
HMODULE hModule;
LPVOID pTarget;
hModule = GetModuleHandleW(pszModule);
if (hModule == NULL)
return MH_ERROR_MODULE_NOT_FOUND;
pTarget = (LPVOID)GetProcAddress(hModule, pszProcName);
if (pTarget == NULL)
return MH_ERROR_FUNCTION_NOT_FOUND;
if(ppTarget != NULL)
*ppTarget = pTarget;
return MH_CreateHook(pTarget, pDetour, ppOriginal);
}
//-------------------------------------------------------------------------
MH_STATUS WINAPI MH_CreateHookApi(
LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal)
{
return MH_CreateHookApiEx(pszModule, pszProcName, pDetour, ppOriginal, NULL);
}
//-------------------------------------------------------------------------
const char * WINAPI MH_StatusToString(MH_STATUS status)
{
#define MH_ST2STR(x) \
case x: \
return #x;
switch (status) {
MH_ST2STR(MH_UNKNOWN)
MH_ST2STR(MH_OK)
MH_ST2STR(MH_ERROR_ALREADY_INITIALIZED)
MH_ST2STR(MH_ERROR_NOT_INITIALIZED)
MH_ST2STR(MH_ERROR_ALREADY_CREATED)
MH_ST2STR(MH_ERROR_NOT_CREATED)
MH_ST2STR(MH_ERROR_ENABLED)
MH_ST2STR(MH_ERROR_DISABLED)
MH_ST2STR(MH_ERROR_NOT_EXECUTABLE)
MH_ST2STR(MH_ERROR_UNSUPPORTED_FUNCTION)
MH_ST2STR(MH_ERROR_MEMORY_ALLOC)
MH_ST2STR(MH_ERROR_MEMORY_PROTECT)
MH_ST2STR(MH_ERROR_MODULE_NOT_FOUND)
MH_ST2STR(MH_ERROR_FUNCTION_NOT_FOUND)
}
#undef MH_ST2STR
return "(unknown)";
}

View File

@ -0,0 +1,320 @@
/*
* MinHook - The Minimalistic API Hooking Library for x64/x86
* Copyright (C) 2009-2017 Tsuda Kageyu.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <windows.h>
#ifdef _MSC_VER
#include <intrin.h>
#endif
#ifndef ARRAYSIZE
#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
#endif
#if defined(_M_X64) || defined(__x86_64__)
#include "./hde/hde64.h"
typedef hde64s HDE;
#define HDE_DISASM(code, hs) hde64_disasm(code, hs)
#else
#include "./hde/hde32.h"
typedef hde32s HDE;
#define HDE_DISASM(code, hs) hde32_disasm(code, hs)
#endif
#include "trampoline.h"
#include "buffer.h"
// Maximum size of a trampoline function.
#if defined(_M_X64) || defined(__x86_64__)
#define TRAMPOLINE_MAX_SIZE (MEMORY_SLOT_SIZE - sizeof(JMP_ABS))
#else
#define TRAMPOLINE_MAX_SIZE MEMORY_SLOT_SIZE
#endif
//-------------------------------------------------------------------------
static BOOL IsCodePadding(LPBYTE pInst, UINT size)
{
UINT i;
if (pInst[0] != 0x00 && pInst[0] != 0x90 && pInst[0] != 0xCC)
return FALSE;
for (i = 1; i < size; ++i)
{
if (pInst[i] != pInst[0])
return FALSE;
}
return TRUE;
}
//-------------------------------------------------------------------------
BOOL CreateTrampolineFunction(PTRAMPOLINE ct)
{
#if defined(_M_X64) || defined(__x86_64__)
CALL_ABS call = {
0xFF, 0x15, 0x00000002, // FF15 00000002: CALL [RIP+8]
0xEB, 0x08, // EB 08: JMP +10
0x0000000000000000ULL // Absolute destination address
};
JMP_ABS jmp = {
0xFF, 0x25, 0x00000000, // FF25 00000000: JMP [RIP+6]
0x0000000000000000ULL // Absolute destination address
};
JCC_ABS jcc = {
0x70, 0x0E, // 7* 0E: J** +16
0xFF, 0x25, 0x00000000, // FF25 00000000: JMP [RIP+6]
0x0000000000000000ULL // Absolute destination address
};
#else
CALL_REL call = {
0xE8, // E8 xxxxxxxx: CALL +5+xxxxxxxx
0x00000000 // Relative destination address
};
JMP_REL jmp = {
0xE9, // E9 xxxxxxxx: JMP +5+xxxxxxxx
0x00000000 // Relative destination address
};
JCC_REL jcc = {
0x0F, 0x80, // 0F8* xxxxxxxx: J** +6+xxxxxxxx
0x00000000 // Relative destination address
};
#endif
UINT8 oldPos = 0;
UINT8 newPos = 0;
ULONG_PTR jmpDest = 0; // Destination address of an internal jump.
BOOL finished = FALSE; // Is the function completed?
#if defined(_M_X64) || defined(__x86_64__)
UINT8 instBuf[16];
#endif
ct->patchAbove = FALSE;
ct->nIP = 0;
do
{
HDE hs;
UINT copySize;
LPVOID pCopySrc;
ULONG_PTR pOldInst = (ULONG_PTR)ct->pTarget + oldPos;
ULONG_PTR pNewInst = (ULONG_PTR)ct->pTrampoline + newPos;
copySize = HDE_DISASM((LPVOID)pOldInst, &hs);
if (hs.flags & F_ERROR)
return FALSE;
pCopySrc = (LPVOID)pOldInst;
if (oldPos >= sizeof(JMP_REL))
{
// The trampoline function is long enough.
// Complete the function with the jump to the target function.
#if defined(_M_X64) || defined(__x86_64__)
jmp.address = pOldInst;
#else
jmp.operand = (UINT32)(pOldInst - (pNewInst + sizeof(jmp)));
#endif
pCopySrc = &jmp;
copySize = sizeof(jmp);
finished = TRUE;
}
#if defined(_M_X64) || defined(__x86_64__)
else if ((hs.modrm & 0xC7) == 0x05)
{
// Instructions using RIP relative addressing. (ModR/M = 00???101B)
// Modify the RIP relative address.
PUINT32 pRelAddr;
// Avoid using memcpy to reduce the footprint.
#ifndef _MSC_VER
memcpy(instBuf, (LPBYTE)pOldInst, copySize);
#else
__movsb(instBuf, (LPBYTE)pOldInst, copySize);
#endif
pCopySrc = instBuf;
// Relative address is stored at (instruction length - immediate value length - 4).
pRelAddr = (PUINT32)(instBuf + hs.len - ((hs.flags & 0x3C) >> 2) - 4);
*pRelAddr
= (UINT32)((pOldInst + hs.len + (INT32)hs.disp.disp32) - (pNewInst + hs.len));
// Complete the function if JMP (FF /4).
if (hs.opcode == 0xFF && hs.modrm_reg == 4)
finished = TRUE;
}
#endif
else if (hs.opcode == 0xE8)
{
// Direct relative CALL
ULONG_PTR dest = pOldInst + hs.len + (INT32)hs.imm.imm32;
#if defined(_M_X64) || defined(__x86_64__)
call.address = dest;
#else
call.operand = (UINT32)(dest - (pNewInst + sizeof(call)));
#endif
pCopySrc = &call;
copySize = sizeof(call);
}
else if ((hs.opcode & 0xFD) == 0xE9)
{
// Direct relative JMP (EB or E9)
ULONG_PTR dest = pOldInst + hs.len;
if (hs.opcode == 0xEB) // isShort jmp
dest += (INT8)hs.imm.imm8;
else
dest += (INT32)hs.imm.imm32;
// Simply copy an internal jump.
if ((ULONG_PTR)ct->pTarget <= dest
&& dest < ((ULONG_PTR)ct->pTarget + sizeof(JMP_REL)))
{
if (jmpDest < dest)
jmpDest = dest;
}
else
{
#if defined(_M_X64) || defined(__x86_64__)
jmp.address = dest;
#else
jmp.operand = (UINT32)(dest - (pNewInst + sizeof(jmp)));
#endif
pCopySrc = &jmp;
copySize = sizeof(jmp);
// Exit the function if it is not in the branch.
finished = (pOldInst >= jmpDest);
}
}
else if ((hs.opcode & 0xF0) == 0x70
|| (hs.opcode & 0xFC) == 0xE0
|| (hs.opcode2 & 0xF0) == 0x80)
{
// Direct relative Jcc
ULONG_PTR dest = pOldInst + hs.len;
if ((hs.opcode & 0xF0) == 0x70 // Jcc
|| (hs.opcode & 0xFC) == 0xE0) // LOOPNZ/LOOPZ/LOOP/JECXZ
dest += (INT8)hs.imm.imm8;
else
dest += (INT32)hs.imm.imm32;
// Simply copy an internal jump.
if ((ULONG_PTR)ct->pTarget <= dest
&& dest < ((ULONG_PTR)ct->pTarget + sizeof(JMP_REL)))
{
if (jmpDest < dest)
jmpDest = dest;
}
else if ((hs.opcode & 0xFC) == 0xE0)
{
// LOOPNZ/LOOPZ/LOOP/JCXZ/JECXZ to the outside are not supported.
return FALSE;
}
else
{
UINT8 cond = ((hs.opcode != 0x0F ? hs.opcode : hs.opcode2) & 0x0F);
#if defined(_M_X64) || defined(__x86_64__)
// Invert the condition in x64 mode to simplify the conditional jump logic.
jcc.opcode = 0x71 ^ cond;
jcc.address = dest;
#else
jcc.opcode1 = 0x80 | cond;
jcc.operand = (UINT32)(dest - (pNewInst + sizeof(jcc)));
#endif
pCopySrc = &jcc;
copySize = sizeof(jcc);
}
}
else if ((hs.opcode & 0xFE) == 0xC2)
{
// RET (C2 or C3)
// Complete the function if not in a branch.
finished = (pOldInst >= jmpDest);
}
// Can't alter the instruction length in a branch.
if (pOldInst < jmpDest && copySize != hs.len)
return FALSE;
// Trampoline function is too large.
if ((newPos + copySize) > TRAMPOLINE_MAX_SIZE)
return FALSE;
// Trampoline function has too many instructions.
if (ct->nIP >= ARRAYSIZE(ct->oldIPs))
return FALSE;
ct->oldIPs[ct->nIP] = oldPos;
ct->newIPs[ct->nIP] = newPos;
ct->nIP++;
// Avoid using memcpy to reduce the footprint.
#ifndef _MSC_VER
memcpy((LPBYTE)ct->pTrampoline + newPos, pCopySrc, copySize);
#else
__movsb((LPBYTE)ct->pTrampoline + newPos, (LPBYTE)pCopySrc, copySize);
#endif
newPos += copySize;
oldPos += hs.len;
}
while (!finished);
// Is there enough place for a long jump?
if (oldPos < sizeof(JMP_REL)
&& !IsCodePadding((LPBYTE)ct->pTarget + oldPos, sizeof(JMP_REL) - oldPos))
{
// Is there enough place for a short jump?
if (oldPos < sizeof(JMP_REL_SHORT)
&& !IsCodePadding((LPBYTE)ct->pTarget + oldPos, sizeof(JMP_REL_SHORT) - oldPos))
{
return FALSE;
}
// Can we place the long jump above the function?
if (!IsExecutableAddress((LPBYTE)ct->pTarget - sizeof(JMP_REL)))
return FALSE;
if (!IsCodePadding((LPBYTE)ct->pTarget - sizeof(JMP_REL), sizeof(JMP_REL)))
return FALSE;
ct->patchAbove = TRUE;
}
#if defined(_M_X64) || defined(__x86_64__)
// Create a relay function.
jmp.address = (ULONG_PTR)ct->pDetour;
ct->pRelay = (LPBYTE)ct->pTrampoline + newPos;
memcpy(ct->pRelay, &jmp, sizeof(jmp));
#endif
return TRUE;
}

View File

@ -0,0 +1,105 @@
/*
* MinHook - The Minimalistic API Hooking Library for x64/x86
* Copyright (C) 2009-2017 Tsuda Kageyu.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#pragma pack(push, 1)
// Structs for writing x86/x64 instructions.
// 8-bit relative jump.
typedef struct _JMP_REL_SHORT
{
UINT8 opcode; // EB xx: JMP +2+xx
UINT8 operand;
} JMP_REL_SHORT, *PJMP_REL_SHORT;
// 32-bit direct relative jump/call.
typedef struct _JMP_REL
{
UINT8 opcode; // E9/E8 xxxxxxxx: JMP/CALL +5+xxxxxxxx
UINT32 operand; // Relative destination address
} JMP_REL, *PJMP_REL, CALL_REL;
// 64-bit indirect absolute jump.
typedef struct _JMP_ABS
{
UINT8 opcode0; // FF25 00000000: JMP [+6]
UINT8 opcode1;
UINT32 dummy;
UINT64 address; // Absolute destination address
} JMP_ABS, *PJMP_ABS;
// 64-bit indirect absolute call.
typedef struct _CALL_ABS
{
UINT8 opcode0; // FF15 00000002: CALL [+6]
UINT8 opcode1;
UINT32 dummy0;
UINT8 dummy1; // EB 08: JMP +10
UINT8 dummy2;
UINT64 address; // Absolute destination address
} CALL_ABS;
// 32-bit direct relative conditional jumps.
typedef struct _JCC_REL
{
UINT8 opcode0; // 0F8* xxxxxxxx: J** +6+xxxxxxxx
UINT8 opcode1;
UINT32 operand; // Relative destination address
} JCC_REL;
// 64bit indirect absolute conditional jumps that x64 lacks.
typedef struct _JCC_ABS
{
UINT8 opcode; // 7* 0E: J** +16
UINT8 dummy0;
UINT8 dummy1; // FF25 00000000: JMP [+6]
UINT8 dummy2;
UINT32 dummy3;
UINT64 address; // Absolute destination address
} JCC_ABS;
#pragma pack(pop)
typedef struct _TRAMPOLINE
{
LPVOID pTarget; // [In] Address of the target function.
LPVOID pDetour; // [In] Address of the detour function.
LPVOID pTrampoline; // [In] Buffer address for the trampoline and relay function.
#if defined(_M_X64) || defined(__x86_64__)
LPVOID pRelay; // [Out] Address of the relay function.
#endif
BOOL patchAbove; // [Out] Should use the hot patch area?
UINT nIP; // [Out] Number of the instruction boundaries.
UINT8 oldIPs[8]; // [Out] Instruction boundaries of the target function.
UINT8 newIPs[8]; // [Out] Instruction boundaries of the trampoline function.
} TRAMPOLINE, *PTRAMPOLINE;
BOOL CreateTrampolineFunction(PTRAMPOLINE ct);

4
Amalgam/packages.config Normal file
View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="boost" version="1.84.0" targetFramework="native" />
</packages>

59
Amalgam/src/Core/Core.cpp Normal file
View File

@ -0,0 +1,59 @@
#include "Core.h"
#include "../SDK/SDK.h"
#include "../Features/Visuals/Materials/Materials.h"
#include "../Features/Configs/Configs.h"
#include "../Features/Commands/Commands.h"
#include "../Features/ImGui/Menu/Menu.h"
#include "../Features/Visuals/Visuals.h"
void CCore::Load()
{
// Check the DirectX version
U::Signatures.Initialize();
U::Interfaces.Initialize();
U::Hooks.Initialize();
U::ConVars.Initialize();
F::Materials.LoadMaterials();
F::Commands.Initialize();
F::Configs.LoadConfig(F::Configs.sCurrentConfig, false);
F::Menu.ConfigLoaded = true;
SDK::Output("Amalgam", "Loaded", { 175, 150, 255, 255 });
}
void CCore::Unload()
{
G::Unload = true;
U::Hooks.Unload();
U::ConVars.Unload();
F::Materials.UnloadMaterials();
F::Visuals.RestoreWorldModulation();
Vars::Visuals::World::SkyboxChanger.Value = "Off"; // hooks won't run, remove here
if (I::Input->CAM_IsThirdPerson())
{
auto pLocal = H::Entities.GetLocal();
if (pLocal)
{
I::Input->CAM_ToFirstPerson();
pLocal->ThirdPersonSwitch();
}
}
if (auto cl_wpn_sway_interp = U::ConVars.FindVar("cl_wpn_sway_interp"))
cl_wpn_sway_interp->SetValue(0.f);
if (auto cl_wpn_sway_scale = U::ConVars.FindVar("cl_wpn_sway_scale"))
cl_wpn_sway_scale->SetValue(0.f);
Sleep(250);
SDK::Output("Amalgam", "Unloaded", { 175, 150, 255, 255 });
}
bool CCore::ShouldUnload()
{
return SDK::IsGameWindowInFocus() && GetAsyncKeyState(VK_F11) & 0x8000 || bUnload;
}

14
Amalgam/src/Core/Core.h Normal file
View File

@ -0,0 +1,14 @@
#pragma once
#include "../Utils/Feature/Feature.h"
class CCore
{
public:
void Load();
void Unload();
bool ShouldUnload();
bool bUnload = false;
};
ADD_FEATURE_CUSTOM(CCore, Core, U);

36
Amalgam/src/DllMain.cpp Normal file
View File

@ -0,0 +1,36 @@
#include <Windows.h>
#include "Core/Core.h"
#include "Utils/Minidump/Minidump.h"
DWORD WINAPI MainThread(LPVOID lpParam)
{
while (!GetModuleHandleA("XAudio2_7.dll"))
Sleep(2000);
U::Core.Load();
while (!U::Core.ShouldUnload())
Sleep(50);
U::Core.Unload();
#ifndef _DEBUG
SetUnhandledExceptionFilter(nullptr);
#endif
FreeLibraryAndExitThread(static_cast<HMODULE>(lpParam), EXIT_SUCCESS);
}
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
if (fdwReason == DLL_PROCESS_ATTACH)
{
#ifndef _DEBUG
SetUnhandledExceptionFilter(Minidump::ExceptionFilter);
#endif
DisableThreadLibraryCalls(hinstDLL);
if (const auto hMainThread = CreateThread(nullptr, 0, MainThread, hinstDLL, 0, nullptr))
CloseHandle(hMainThread);
}
return TRUE;
}

View File

@ -0,0 +1,71 @@
#include "Aimbot.h"
#include "AimbotHitscan/AimbotHitscan.h"
#include "AimbotProjectile/AimbotProjectile.h"
#include "AimbotMelee/AimbotMelee.h"
#include "AutoDetonate/AutoDetonate.h"
#include "AutoAirblast/AutoAirblast.h"
#include "AutoUber/AutoUber.h"
#include "AutoRocketJump/AutoRocketJump.h"
#include "../Misc/Misc.h"
bool CAimbot::ShouldRun(CTFPlayer* pLocal, CTFWeaponBase* pWeapon)
{
if (!pLocal || !pWeapon
|| !pLocal->IsAlive()
|| pLocal->IsTaunting()
|| pLocal->IsBonked()
|| pLocal->m_bFeignDeathReady()
|| pLocal->IsCloaked()
|| pLocal->IsInBumperKart()
|| pLocal->IsAGhost())
return false;
switch (G::WeaponDefIndex)
{
case Soldier_m_RocketJumper:
case Demoman_s_StickyJumper:
return false;
}
if (I::EngineVGui->IsGameUIVisible() || I::MatSystemSurface->IsCursorVisible())
return false;
return true;
}
bool CAimbot::Run(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCmd* pCmd)
{
G::AimPosition = Vec3();
if (pCmd->weaponselect)
return false;
F::AutoRocketJump.Run(pLocal, pWeapon, pCmd);
if (!ShouldRun(pLocal, pWeapon))
return false;
F::AutoDetonate.Run(pLocal, pWeapon, pCmd);
F::AutoAirblast.Run(pLocal, pWeapon, pCmd);
F::AutoUber.Run(pLocal, pWeapon, pCmd);
const bool bAttacking = G::IsAttacking;
switch (G::WeaponType)
{
case EWeaponType::HITSCAN: F::AimbotHitscan.Run(pLocal, pWeapon, pCmd); break;
case EWeaponType::PROJECTILE: F::AimbotProjectile.Run(pLocal, pWeapon, pCmd); break;
case EWeaponType::MELEE: F::AimbotMelee.Run(pLocal, pWeapon, pCmd); break;
}
switch (pWeapon->m_iWeaponID())
{
case TF_WEAPON_COMPOUND_BOW:
case TF_WEAPON_PIPEBOMBLAUNCHER:
case TF_WEAPON_STICKY_BALL_LAUNCHER:
case TF_WEAPON_GRENADE_STICKY_BALL:
case TF_WEAPON_CANNON:
if (!(G::Buttons & IN_ATTACK) && pCmd->buttons & IN_ATTACK)
return true;
}
return bAttacking != G::IsAttacking;
}

View File

@ -0,0 +1,13 @@
#pragma once
#include "../../SDK/SDK.h"
class CAimbot
{
private:
bool ShouldRun(CTFPlayer* pLocal, CTFWeaponBase* pWeapon);
public:
bool Run(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCmd* pCmd);
};
ADD_FEATURE(CAimbot, Aimbot)

View File

@ -0,0 +1,124 @@
#include "AimbotGlobal.h"
#include "../../Players/PlayerUtils.h"
void CAimbotGlobal::SortTargets(std::vector<Target_t>* targets, const ESortMethod& method)
{ // Sort by preference
std::sort((*targets).begin(), (*targets).end(), [&](const Target_t& a, const Target_t& b) -> bool
{
switch (method)
{
case ESortMethod::FOV: return a.m_flFOVTo < b.m_flFOVTo;
case ESortMethod::DISTANCE: return a.m_flDistTo < b.m_flDistTo;
default: return false;
}
});
}
void CAimbotGlobal::SortPriority(std::vector<Target_t>* targets)
{ // Sort by priority
std::sort((*targets).begin(), (*targets).end(), [&](const Target_t& a, const Target_t& b) -> bool
{
return a.m_nPriority > b.m_nPriority;
});
}
bool CAimbotGlobal::ShouldIgnore(CTFPlayer* pTarget, CTFPlayer* pLocal, CTFWeaponBase* pWeapon, bool bMedigun)
{
PlayerInfo_t pi{};
if (!pTarget || pTarget == pLocal || pTarget->IsDormant())
return true;
if (!I::EngineClient->GetPlayerInfo(pTarget->entindex(), &pi))
return true;
if (pLocal->m_iTeamNum() == pTarget->m_iTeamNum())
{
if (bMedigun)
return pTarget->IsInvisible();
return false;
}
if (Vars::Aimbot::General::Ignore.Value & INVUL && pTarget->IsInvulnerable())
{
if (G::WeaponDefIndex != Heavy_t_TheHolidayPunch)
return true;
}
if (Vars::Aimbot::General::Ignore.Value & CLOAKED && pTarget->IsInvisible())
{
if (pTarget->GetInvisPercentage() >= Vars::Aimbot::General::IgnoreCloakPercentage.Value)
return true;
}
if (Vars::Aimbot::General::Ignore.Value & DEADRINGER && pTarget->m_bFeignDeathReady())
return true;
if (Vars::Aimbot::General::Ignore.Value & TAUNTING && pTarget->IsTaunting())
return true;
if (Vars::Aimbot::General::Ignore.Value & VACCINATOR)
{
switch (G::WeaponType)
{
case EWeaponType::HITSCAN:
if (pTarget->IsBulletResist() && G::WeaponDefIndex != Spy_m_TheEnforcer)
return true;
break;
case EWeaponType::PROJECTILE:
if (pTarget->IsFireResist() && (pWeapon->m_iWeaponID() == TF_WEAPON_FLAMETHROWER || pWeapon->m_iWeaponID() == TF_WEAPON_FLAREGUN))
return true;
else if (pTarget->IsBulletResist() && pWeapon->m_iWeaponID() == TF_WEAPON_COMPOUND_BOW)
return true;
else if (pTarget->IsBlastResist())
return true;
}
}
if (Vars::Aimbot::General::Ignore.Value & DISGUISED && pTarget->IsDisguised())
return true;
if (F::PlayerUtils.IsIgnored(pi.friendsID))
return true;
return false;
}
int CAimbotGlobal::GetPriority(int targetIdx)
{
return F::PlayerUtils.GetPriority(targetIdx);
}
// will not predict for projectile weapons
bool CAimbotGlobal::ValidBomb(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CBaseEntity* pBomb)
{
if (G::WeaponType == EWeaponType::PROJECTILE)
return false;
Vec3 vOrigin = pBomb->m_vecOrigin();
CBaseEntity* pEntity;
for (CEntitySphereQuery sphere(vOrigin, 300.f);
(pEntity = sphere.GetCurrentEntity()) != nullptr;
sphere.NextEntity())
{
if (!pEntity || pEntity == pLocal || pEntity->IsPlayer() && (!pEntity->As<CTFPlayer>()->IsAlive() || pEntity->As<CTFPlayer>()->IsAGhost()) || pEntity->m_iTeamNum() == pLocal->m_iTeamNum())
continue;
Vec3 vPos = {}; reinterpret_cast<CCollisionProperty*>(pEntity->GetCollideable())->CalcNearestPoint(vOrigin, &vPos);
if (vOrigin.DistTo(vPos) > 300.f)
continue;
bool isPlayer = Vars::Aimbot::General::Target.Value & PLAYER && pEntity->IsPlayer();
bool isSentry = Vars::Aimbot::General::Target.Value & SENTRY && pEntity->IsSentrygun();
bool isDispenser = Vars::Aimbot::General::Target.Value & DISPENSER && pEntity->IsDispenser();
bool isTeleporter = Vars::Aimbot::General::Target.Value & TELEPORTER && pEntity->IsTeleporter();
bool isNPC = Vars::Aimbot::General::Target.Value & NPC && pEntity->IsNPC();
if (isPlayer || isSentry || isDispenser || isTeleporter || isNPC)
{
if (isPlayer && ShouldIgnore(pEntity->As<CTFPlayer>(), pLocal, pWeapon))
continue;
if (!SDK::VisPosProjectile(pBomb, pEntity, vOrigin, isPlayer ? pEntity->m_vecOrigin() + pEntity->As<CTFPlayer>()->GetViewOffset() : pEntity->GetCenter(), MASK_SHOT))
continue;
return true;
}
}
return false;
}

View File

@ -0,0 +1,70 @@
#pragma once
#include "../../../SDK/SDK.h"
#include "../../Backtrack/Backtrack.h"
enum struct ETargetType
{
UNKNOWN,
PLAYER,
SENTRY,
DISPENSER,
TELEPORTER,
STICKY,
NPC,
BOMBS
};
enum struct ESortMethod
{
FOV,
DISTANCE
};
enum Target
{
PLAYER = 1 << 0,
SENTRY = 1 << 1,
DISPENSER = 1 << 2,
TELEPORTER = 1 << 3,
STICKY = 1 << 4,
NPC = 1 << 5,
BOMB = 1 << 6
};
enum Ignored
{
INVUL = 1 << 0,
CLOAKED = 1 << 1,
DEADRINGER = 1 << 2,
VACCINATOR = 1 << 3,
UNSIMULATED = 1 << 4,
DISGUISED = 1 << 5,
TAUNTING = 1 << 6
};
struct Target_t
{
CBaseEntity* m_pEntity = nullptr;
ETargetType m_TargetType = ETargetType::UNKNOWN;
Vec3 m_vPos = {};
Vec3 m_vAngleTo = {};
float m_flFOVTo = std::numeric_limits<float>::max();
float m_flDistTo = std::numeric_limits<float>::max();
int m_nPriority = 0;
int m_nAimedHitbox = -1;
TickRecord m_Tick = {};
bool m_bBacktrack = false;
};
class CAimbotGlobal
{
public:
void SortTargets(std::vector<Target_t>*, const ESortMethod& method);
void SortPriority(std::vector<Target_t>*);
bool ShouldIgnore(CTFPlayer* pTarget, CTFPlayer* pLocal, CTFWeaponBase* pWeapon, bool bMedigun = false);
int GetPriority(int targetIdx);
bool ValidBomb(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CBaseEntity* pBomb);
};
ADD_FEATURE(CAimbotGlobal, AimbotGlobal)

View File

@ -0,0 +1,786 @@
#include "AimbotHitscan.h"
#include "../../Backtrack/Backtrack.h"
#include "../../Resolver/Resolver.h"
#include "../../Visuals/Visuals.h"
bool CAimbotHitscan::PlayerBoneInFOV(CTFPlayer* pTarget, Vec3 vLocalPos, Vec3 vLocalAngles, float& flFOVTo, Vec3& vPos, Vec3& vAngleTo) // this won't prevent shooting bones outside of fov
{
bool bReturn = false;
float flMinFOV = 180.f;
for (int nHitbox = 0; nHitbox < pTarget->GetNumOfHitboxes(); nHitbox++)
{
if (!IsHitboxValid(nHitbox))
continue;
Vec3 vCurPos = pTarget->GetHitboxPos(nHitbox);
Vec3 vCurAngleTo = Math::CalcAngle(vLocalPos, vCurPos);
float flCurFOVTo = Math::CalcFov(vLocalAngles, vCurAngleTo);
if (flCurFOVTo < flMinFOV && flCurFOVTo < Vars::Aimbot::General::AimFOV.Value)
{
bReturn = true;
vPos = vCurPos;
vAngleTo = vCurAngleTo;
flFOVTo = flMinFOV = flCurFOVTo;
}
}
return bReturn;
}
std::vector<Target_t> CAimbotHitscan::GetTargets(CTFPlayer* pLocal, CTFWeaponBase* pWeapon)
{
std::vector<Target_t> validTargets;
const auto sortMethod = static_cast<ESortMethod>(Vars::Aimbot::General::TargetSelection.Value);
const Vec3 vLocalPos = pLocal->GetShootPos();
const Vec3 vLocalAngles = I::EngineClient->GetViewAngles();
const bool bIsMedigun = pWeapon->m_iWeaponID() == TF_WEAPON_MEDIGUN;
if (Vars::Aimbot::General::Target.Value & PLAYER)
{
const bool bPissRifle = G::WeaponDefIndex == Sniper_m_TheSydneySleeper;
EGroupType groupType = EGroupType::PLAYERS_ENEMIES;
if (bIsMedigun)
groupType = EGroupType::PLAYERS_TEAMMATES;
else if (bPissRifle)
groupType = EGroupType::PLAYERS_ALL;
for (auto pEntity : H::Entities.GetGroup(groupType))
{
auto pPlayer = pEntity->As<CTFPlayer>();
if (pPlayer == pLocal || !pPlayer->IsAlive() || pPlayer->IsAGhost())
continue;
// Can we extinguish a teammate using the piss rifle?
if (bPissRifle && (pPlayer->m_iTeamNum() == pLocal->m_iTeamNum()))
{
if (!(Vars::Aimbot::Hitscan::Modifiers.Value & (1 << 6)) || !pPlayer->IsOnFire())
continue;
}
if (F::AimbotGlobal.ShouldIgnore(pPlayer, pLocal, pWeapon, bIsMedigun))
continue;
float flFOVTo; Vec3 vPos, vAngleTo;
if (!PlayerBoneInFOV(pPlayer, vLocalPos, vLocalAngles, flFOVTo, vPos, vAngleTo))
continue;
const float flDistTo = vLocalPos.DistTo(vPos);
const int priority = F::AimbotGlobal.GetPriority(pPlayer->entindex());
validTargets.push_back({ pPlayer, ETargetType::PLAYER, vPos, vAngleTo, flFOVTo, flDistTo, priority });
}
}
if (bIsMedigun) // do not attempt to heal buildings or other
return validTargets;
if (Vars::Aimbot::General::Target.Value)
{
for (auto pEntity : H::Entities.GetGroup(EGroupType::BUILDINGS_ENEMIES))
{
auto pBuilding = pEntity->As<CBaseObject>();
bool isSentry = pBuilding->IsSentrygun(), isDispenser = pBuilding->IsDispenser(), isTeleporter = pBuilding->IsTeleporter();
if (!(Vars::Aimbot::General::Target.Value & SENTRY) && isSentry)
continue;
if (!(Vars::Aimbot::General::Target.Value & DISPENSER) && isDispenser)
continue;
if (!(Vars::Aimbot::General::Target.Value & TELEPORTER) && isTeleporter)
continue;
Vec3 vPos = pBuilding->GetCenter();
Vec3 vAngleTo = Math::CalcAngle(vLocalPos, vPos);
const float flFOVTo = Math::CalcFov(vLocalAngles, vAngleTo);
if (flFOVTo > Vars::Aimbot::General::AimFOV.Value)
continue;
const float flDistTo = vLocalPos.DistTo(vPos);
validTargets.push_back({ pBuilding, isSentry ? ETargetType::SENTRY : (isDispenser ? ETargetType::DISPENSER : ETargetType::TELEPORTER), vPos, vAngleTo, flFOVTo, flDistTo });
}
}
if (Vars::Aimbot::General::Target.Value & STICKY)
{
for (auto pEntity : H::Entities.GetGroup(EGroupType::WORLD_PROJECTILES))
{
if (pEntity->GetClassID() != ETFClassID::CTFGrenadePipebombProjectile)
continue;
auto pProjectile = pEntity->As<CTFGrenadePipebombProjectile>();
if (pProjectile->m_iType() != TF_GL_MODE_REMOTE_DETONATE || !pProjectile->m_bTouched())
continue;
auto pOwner = pProjectile->m_hThrower().Get();
if (!pOwner || pOwner->m_iTeamNum() == pLocal->m_iTeamNum())
continue;
Vec3 vPos = pProjectile->GetCenter();
Vec3 vAngleTo = Math::CalcAngle(vLocalPos, vPos);
const float flFOVTo = Math::CalcFov(vLocalAngles, vAngleTo);
if (flFOVTo > Vars::Aimbot::General::AimFOV.Value)
continue;
const float flDistTo = vLocalPos.DistTo(vPos);
validTargets.push_back({ pProjectile, ETargetType::STICKY, vPos, vAngleTo, flFOVTo, flDistTo });
}
}
if (Vars::Aimbot::General::Target.Value & NPC)
{
for (auto pNPC : H::Entities.GetGroup(EGroupType::WORLD_NPC))
{
Vec3 vPos = pNPC->GetCenter();
Vec3 vAngleTo = Math::CalcAngle(vLocalPos, vPos);
const float flFOVTo = Math::CalcFov(vLocalAngles, vAngleTo);
if (flFOVTo > Vars::Aimbot::General::AimFOV.Value)
continue;
const float flDistTo = vLocalPos.DistTo(vPos);
validTargets.push_back({ pNPC, ETargetType::NPC, vPos, vAngleTo, flFOVTo, flDistTo });
}
}
if (Vars::Aimbot::General::Target.Value & BOMB)
{
for (auto pBomb : H::Entities.GetGroup(EGroupType::WORLD_BOMBS))
{
Vec3 vPos = pBomb->GetCenter();
Vec3 vAngleTo = Math::CalcAngle(vLocalPos, vPos);
const float flFOVTo = Math::CalcFov(vLocalAngles, vAngleTo);
const float flDistTo = sortMethod == ESortMethod::DISTANCE ? vLocalPos.DistTo(vPos) : 0.0f;
if (flFOVTo > Vars::Aimbot::General::AimFOV.Value)
continue;
if (!F::AimbotGlobal.ValidBomb(pLocal, pWeapon, pBomb))
continue;
validTargets.push_back({ pBomb, ETargetType::BOMBS, vPos, vAngleTo, flFOVTo, flDistTo });
}
}
return validTargets;
}
std::vector<Target_t> CAimbotHitscan::SortTargets(CTFPlayer* pLocal, CTFWeaponBase* pWeapon)
{
auto validTargets = GetTargets(pLocal, pWeapon);
const auto& sortMethod = static_cast<ESortMethod>(Vars::Aimbot::General::TargetSelection.Value);
F::AimbotGlobal.SortTargets(&validTargets, sortMethod);
std::vector<Target_t> sortedTargets = {};
int i = 0; for (auto& target : validTargets)
{
i++; if (i > Vars::Aimbot::General::MaxTargets.Value) break;
sortedTargets.push_back(target);
}
F::AimbotGlobal.SortPriority(&sortedTargets);
return sortedTargets;
}
bool CAimbotHitscan::IsHitboxValid(int nHitbox) // check that this & all other uses are right
{
const int iHitboxes = Vars::Aimbot::Hitscan::Hitboxes.Value;
switch (nHitbox)
{
case -1: return true;
case HITBOX_HEAD: return iHitboxes & (1 << 0);
case HITBOX_NECK: return iHitboxes & (1 << 1);
case HITBOX_LOWER_NECK:
case HITBOX_PELVIS:
case HITBOX_BODY:
case HITBOX_THORAX: return iHitboxes & (1 << 2);
case HITBOX_CHEST:
case HITBOX_UPPER_CHEST:
case HITBOX_RIGHT_THIGH:
case HITBOX_LEFT_THIGH:
case HITBOX_RIGHT_CALF:
case HITBOX_LEFT_CALF: return iHitboxes & (1 << 3);
case HITBOX_RIGHT_FOOT:
case HITBOX_LEFT_FOOT:
case HITBOX_RIGHT_HAND:
case HITBOX_LEFT_HAND:
case HITBOX_RIGHT_UPPER_ARM:
case HITBOX_RIGHT_FOREARM:
case HITBOX_LEFT_UPPER_ARM:
case HITBOX_LEFT_FOREARM: return iHitboxes & (1 << 4);
}
return false;
}
int CAimbotHitscan::GetHitboxPriority(int nHitbox, CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CBaseEntity* pTarget)
{
bool bHeadshot = false;
{
const int nClassNum = pLocal->m_iClass();
if (nClassNum == TF_CLASS_SNIPER)
{
if (G::WeaponDefIndex != Sniper_m_TheClassic && pLocal->IsScoped() ||
G::WeaponDefIndex == Sniper_m_TheClassic && pWeapon->As<CTFSniperRifle>()->m_flChargedDamage() > 149.9f)
bHeadshot = true;
}
if (nClassNum == TF_CLASS_SPY)
{
if ((G::WeaponDefIndex == Spy_m_TheAmbassador || G::WeaponDefIndex == Spy_m_FestiveAmbassador) && pWeapon->AmbassadorCanHeadshot())
bHeadshot = true;
}
if (Vars::Aimbot::Hitscan::Modifiers.Value & (1 << 5) && bHeadshot && pTarget->IsPlayer())
{
{
float flBodyMult = 1.f;
switch (G::WeaponDefIndex)
{
case Sniper_m_TheClassic: flBodyMult = 0.9f; break;
case Sniper_m_TheHitmansHeatmaker: flBodyMult = 0.8f; break;
case Sniper_m_TheMachina:
case Sniper_m_ShootingStar: if (pWeapon->As<CTFSniperRifle>()->m_flChargedDamage() > 149.9f) flBodyMult = 1.15f;
}
if (pWeapon->As<CTFSniperRifle>()->m_flChargedDamage() * flBodyMult >= pTarget->As<CTFPlayer>()->m_iHealth())
bHeadshot = false;
}
if (G::WeaponDefIndex == Spy_m_TheAmbassador || G::WeaponDefIndex == Spy_m_FestiveAmbassador)
{
const float flDistTo = pTarget->m_vecOrigin().DistTo(pLocal->m_vecOrigin());
const int nAmbassadorBodyshotDamage = Math::RemapValClamped(flDistTo, 90, 900, 51, 18);
if (pTarget->As<CTFPlayer>()->m_iHealth() < (nAmbassadorBodyshotDamage + 2)) // whatever
bHeadshot = false;
}
}
}
switch (nHitbox)
{
case -1: return 2;
case HITBOX_HEAD: return bHeadshot ? 0 : 2;
case HITBOX_NECK: return 2;
case HITBOX_LOWER_NECK:
case HITBOX_PELVIS:
case HITBOX_BODY:
case HITBOX_THORAX: return bHeadshot ? 1 : 0;
case HITBOX_CHEST:
case HITBOX_UPPER_CHEST:
case HITBOX_RIGHT_THIGH:
case HITBOX_LEFT_THIGH:
case HITBOX_RIGHT_CALF:
case HITBOX_LEFT_CALF: return 2;
case HITBOX_RIGHT_FOOT:
case HITBOX_LEFT_FOOT:
case HITBOX_RIGHT_HAND:
case HITBOX_LEFT_HAND:
case HITBOX_RIGHT_UPPER_ARM:
case HITBOX_RIGHT_FOREARM:
case HITBOX_LEFT_UPPER_ARM:
case HITBOX_LEFT_FOREARM: return 2;
}
return 2;
};
float CAimbotHitscan::GetMaxRange(CTFWeaponBase* pWeapon)
{
switch (pWeapon->m_iWeaponID())
{
case TF_WEAPON_MEDIGUN: return 450.f;
case TF_WEAPON_MECHANICAL_ARM: return 256.f;
}
auto tfWeaponInfo = pWeapon->GetWeaponInfo();
return tfWeaponInfo ? tfWeaponInfo->GetWeaponData(0).m_flRange : 8192.f;
}
int CAimbotHitscan::CanHit(Target_t& target, CTFPlayer* pLocal, CTFWeaponBase* pWeapon)
{
if (Vars::Aimbot::General::Ignore.Value & UNSIMULATED && G::ChokeMap[target.m_pEntity->entindex()] > Vars::Aimbot::General::TickTolerance.Value)
return false;
Vec3 vEyePos = pLocal->GetShootPos();
const float flMaxRange = powf(GetMaxRange(pWeapon), 2.f);
auto pModel = target.m_pEntity->GetModel();
if (!pModel) return false;
auto pHDR = I::ModelInfoClient->GetStudiomodel(pModel);
if (!pHDR) return false;
auto pSet = pHDR->pHitboxSet(target.m_pEntity->As<CBaseAnimating>()->m_nHitboxSet());
if (!pSet) return false;
std::deque<TickRecord> vRecords;
{
auto pRecords = F::Backtrack.GetRecords(target.m_pEntity);
if (pRecords && target.m_TargetType == ETargetType::PLAYER)
{
vRecords = F::Backtrack.GetValidRecords(pRecords, pLocal);
if (!Vars::Backtrack::Enabled.Value && !vRecords.empty())
vRecords = { vRecords.front() };
}
else
{
matrix3x4 bones[128];
if (!target.m_pEntity->SetupBones(bones, 128, BONE_USED_BY_ANYTHING, target.m_pEntity->m_flSimulationTime()))
return false;
vRecords.push_front({
target.m_pEntity->m_flSimulationTime(),
I::GlobalVars->curtime,
I::GlobalVars->tickcount,
false,
*reinterpret_cast<BoneMatrixes*>(&bones),
target.m_pEntity->m_vecOrigin()
});
}
}
auto RayToOBB = [](const Vec3& origin, const Vec3& direction, const Vec3& position, const Vec3& min, const Vec3& max, const matrix3x4 orientation) -> bool
{
if (Vars::Aimbot::General::AimType.Value != 2)
return true;
return Math::RayToOBB(origin, direction, position, min, max, orientation);
};
int iReturn = false;
for (auto& pTick : vRecords)
{
if (target.m_TargetType == ETargetType::PLAYER || target.m_TargetType == ETargetType::SENTRY)
{
auto boneMatrix = (matrix3x4*)(&pTick.BoneMatrix.BoneMatrix);
if (!boneMatrix)
continue;
std::vector<std::pair<const mstudiobbox_t*, int>> hitboxes;
{
if (target.m_TargetType != ETargetType::SENTRY)
{
std::vector<std::pair<const mstudiobbox_t*, int>> primary, secondary, tertiary; // dumb
for (int nHitbox = 0; nHitbox < target.m_pEntity->As<CTFPlayer>()->GetNumOfHitboxes(); nHitbox++)
{
if (!IsHitboxValid(nHitbox))
continue;
auto pBox = pSet->pHitbox(nHitbox);
if (!pBox) continue;
switch (GetHitboxPriority(nHitbox, pLocal, pWeapon, target.m_pEntity))
{
case 0: primary.push_back({ pBox, nHitbox }); break;
case 1: secondary.push_back({ pBox, nHitbox }); break;
case 2: tertiary.push_back({ pBox, nHitbox }); break;
}
}
for (auto& pair : primary) hitboxes.push_back(pair);
for (auto& pair : secondary) hitboxes.push_back(pair);
for (auto& pair : tertiary) hitboxes.push_back(pair);
}
else
{
for (int nHitbox = 0; nHitbox < target.m_pEntity->As<CObjectSentrygun>()->GetNumOfHitboxes(); nHitbox++)
{
const mstudiobbox_t* pBox = pSet->pHitbox(nHitbox);
if (!pBox) continue;
hitboxes.push_back({ pBox, nHitbox });
}
std::sort(hitboxes.begin(), hitboxes.end(), [&](const auto& a, const auto& b) -> bool
{
Vec3 aCenter = {}, bCenter = {}, vCenter = target.m_pEntity->GetCenter();
Math::VectorTransform({}, boneMatrix[a.first->bone], aCenter);
Math::VectorTransform({}, boneMatrix[b.first->bone], bCenter);
return vCenter.DistTo(aCenter) < vCenter.DistTo(bCenter);
});
}
}
for (auto& pair : hitboxes)
{
const float flScale = Vars::Aimbot::Hitscan::PointScale.Value / 100;
const Vec3 vMins = pair.first->bbmin, vMinsS = vMins * flScale;
const Vec3 vMaxs = pair.first->bbmax, vMaxsS = vMaxs * flScale;
std::vector<Vec3> vecPoints = { Vec3() };
if (flScale > 0.f)
{
vecPoints = {
Vec3(),
Vec3(vMinsS.x, vMinsS.y, vMaxsS.z),
Vec3(vMaxsS.x, vMinsS.y, vMaxsS.z),
Vec3(vMinsS.x, vMaxsS.y, vMaxsS.z),
Vec3(vMaxsS.x, vMaxsS.y, vMaxsS.z),
Vec3(vMinsS.x, vMinsS.y, vMinsS.z),
Vec3(vMaxsS.x, vMinsS.y, vMinsS.z),
Vec3(vMinsS.x, vMaxsS.y, vMinsS.z),
Vec3(vMaxsS.x, vMaxsS.y, vMinsS.z)
};
}
for (const auto& point : vecPoints)
{
Vec3 vCenter = {}, vTransformed = {};
Math::VectorTransform({}, boneMatrix[pair.first->bone], vCenter);
Math::VectorTransform(point, boneMatrix[pair.first->bone], vTransformed);
if (vEyePos.DistToSqr(vTransformed) > flMaxRange)
continue;
auto vAngles = Aim(G::CurrentUserCmd->viewangles, Math::CalcAngle(pLocal->GetShootPos(), vTransformed));
Vec3 vForward = {};
Math::AngleVectors(vAngles, &vForward);
if (SDK::VisPos(pLocal, target.m_pEntity, vEyePos, vTransformed))
{
target.m_vAngleTo = vAngles;
if (RayToOBB(vEyePos, vForward, vCenter, vMins, vMaxs, boneMatrix[pair.first->bone])) // for the time being, no vischecks against other hitboxes
{
bool bWillHit = true;
if (target.m_TargetType == ETargetType::SENTRY) // point of hit for sentries needs to be within bbox
{
const matrix3x4& transform = target.m_pEntity->RenderableToWorldTransform();
const Vec3 vMin = target.m_pEntity->m_vecMins(), vMax = target.m_pEntity->m_vecMaxs();
bWillHit = RayToOBB(vEyePos, vForward, target.m_pEntity->m_vecOrigin(), vMin, vMax, transform);
}
if (bWillHit)
{
target.m_Tick = pTick;
target.m_vPos = vTransformed;
if (target.m_TargetType == ETargetType::PLAYER)
{
//if (Vars::Backtrack::Enabled.Value)
target.m_bBacktrack = target.m_TargetType == ETargetType::PLAYER;
target.m_nAimedHitbox = pair.second;
}
return true;
}
}
iReturn = 2;
}
}
}
}
else
{
const float flScale = Vars::Aimbot::Hitscan::PointScale.Value / 100;
const Vec3 vMins = target.m_pEntity->m_vecMins(), vMinsS = vMins * flScale;
const Vec3 vMaxs = target.m_pEntity->m_vecMaxs(), vMaxsS = vMaxs * flScale;
std::vector<Vec3> vecPoints = { Vec3() };
if (flScale > 0.f)
{
vecPoints = {
Vec3(),
Vec3(vMinsS.x, vMinsS.y, vMaxsS.z),
Vec3(vMaxsS.x, vMinsS.y, vMaxsS.z),
Vec3(vMinsS.x, vMaxsS.y, vMaxsS.z),
Vec3(vMaxsS.x, vMaxsS.y, vMaxsS.z),
Vec3(vMinsS.x, vMinsS.y, vMinsS.z),
Vec3(vMaxsS.x, vMinsS.y, vMinsS.z),
Vec3(vMinsS.x, vMaxsS.y, vMinsS.z),
Vec3(vMaxsS.x, vMaxsS.y, vMinsS.z)
};
}
const matrix3x4& transform = target.m_pEntity->RenderableToWorldTransform();
for (const auto& point : vecPoints)
{
Vec3 vTransformed = target.m_pEntity->GetCenter() + point;
if (vEyePos.DistToSqr(vTransformed) > flMaxRange)
continue;
auto vAngles = Aim(G::CurrentUserCmd->viewangles, Math::CalcAngle(pLocal->GetShootPos(), vTransformed));
Vec3 vForward = {};
Math::AngleVectors(vAngles, &vForward);
if (SDK::VisPos(pLocal, target.m_pEntity, vEyePos, vTransformed))
{
target.m_vAngleTo = vAngles;
if (RayToOBB(vEyePos, vForward, target.m_pEntity->m_vecOrigin(), vMins, vMaxs, transform)) // for the time being, no vischecks against other hitboxes
{
target.m_Tick = pTick;
target.m_vPos = vTransformed;
return true;
}
iReturn = 2;
}
}
}
}
return iReturn;
}
/* Returns whether AutoShoot should fire */
bool CAimbotHitscan::ShouldFire(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCmd* pCmd, const Target_t& target)
{
if (!Vars::Aimbot::General::AutoShoot.Value) return false;
switch (pLocal->m_iClass())
{
case TF_CLASS_SNIPER:
{
const bool bIsScoped = pLocal->IsScoped();
if (Vars::Aimbot::Hitscan::Modifiers.Value & (1 << 1))
{
if (G::WeaponDefIndex != Sniper_m_TheClassic
&& G::WeaponDefIndex != Sniper_m_TheSydneySleeper
&& !G::CanHeadshot && bIsScoped)
{
return false;
}
}
if (Vars::Aimbot::Hitscan::Modifiers.Value & (1 << 2) && (bIsScoped || G::WeaponDefIndex == Sniper_m_TheClassic))
{
auto pPlayer = target.m_pEntity->As<CTFPlayer>();
auto pSniperRifle = pWeapon->As<CTFSniperRifle>();
const int nHealth = pPlayer->m_iHealth();
const bool bIsCritBoosted = pLocal->IsCritBoosted();
if (target.m_nAimedHitbox == HITBOX_HEAD && G::WeaponDefIndex != Sniper_m_TheSydneySleeper && (G::WeaponDefIndex != Sniper_m_TheClassic || G::WeaponDefIndex == Sniper_m_TheClassic && pSniperRifle->m_flChargedDamage() > 149.9f))
{
if (nHealth > 150)
{
const float flDamage = Math::RemapValClamped(pSniperRifle->m_flChargedDamage(), 0.0f, 150.0f, 0.0f, 450.0f);
const int nDamage = static_cast<int>(flDamage);
if (nDamage < nHealth && nDamage != 450)
return false;
}
else if (!bIsCritBoosted && !G::CanHeadshot)
return false;
}
else
{
if (nHealth > (bIsCritBoosted ? 150 : 50))
{
float flCritMult = pPlayer->IsInJarate() ? 1.36f : 1.0f;
if (bIsCritBoosted)
flCritMult = 3.0f;
float flBodyMult = 1.f;
switch (G::WeaponDefIndex)
{
case Sniper_m_TheClassic: flBodyMult = 0.9f; break;
case Sniper_m_TheHitmansHeatmaker: flBodyMult = 0.8f; break;
case Sniper_m_TheMachina:
case Sniper_m_ShootingStar: if (pSniperRifle->m_flChargedDamage() > 149.9f) flBodyMult = 1.15f;
}
const float flMax = 150.0f * flCritMult * flBodyMult;
const int nDamage = static_cast<int>(pSniperRifle->m_flChargedDamage() * flCritMult * flBodyMult);
if (nDamage < pPlayer->m_iHealth() && nDamage != static_cast<int>(flMax))
return false;
}
}
}
break;
}
case TF_CLASS_SPY:
if (Vars::Aimbot::Hitscan::Modifiers.Value & (1 << 1) && !pWeapon->AmbassadorCanHeadshot())
return false;
break;
}
return true;
}
// assume angle calculated outside with other overload
void CAimbotHitscan::Aim(CUserCmd* pCmd, Vec3& vAngle)
{
if (Vars::Aimbot::General::AimType.Value != 3)
{
pCmd->viewangles = vAngle;
I::EngineClient->SetViewAngles(pCmd->viewangles); // remove these if uncommenting l124 of createmove
}
else if (G::IsAttacking)
{
SDK::FixMovement(pCmd, vAngle);
pCmd->viewangles = vAngle;
G::SilentAngles = true;
}
}
Vec3 CAimbotHitscan::Aim(Vec3 vCurAngle, Vec3 vToAngle, int iMethod)
{
Vec3 vReturn = {};
vToAngle -= G::PunchAngles;
Math::ClampAngles(vToAngle);
switch (iMethod)
{
case 1: // Plain
case 3: // Silent
vReturn = vToAngle;
break;
case 2: //Smooth
{
auto shortDist = [](const float flAngleA, const float flAngleB)
{
const float flDelta = fmodf((flAngleA - flAngleB), 360.f);
return fmodf(2 * flDelta, 360.f) - flDelta;
};
const float t = 1.f - Vars::Aimbot::General::Smoothing.Value / 100.f;
vReturn.x = vCurAngle.x - shortDist(vCurAngle.x, vToAngle.x) * t;
vReturn.y = vCurAngle.y - shortDist(vCurAngle.y, vToAngle.y) * t;
break;
}
}
return vReturn;
}
void CAimbotHitscan::Run(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCmd* pCmd)
{
static int iStaticAimType = Vars::Aimbot::General::AimType.Value;
const int iRealAimType = Vars::Aimbot::General::AimType.Value;
const int iLastAimType = iStaticAimType;
iStaticAimType = iRealAimType;
const int nWeaponID = pWeapon->m_iWeaponID();
const bool bAutomatic = pWeapon->IsStreamingWeapon(), bKeepFiring = bAutomatic && G::LastUserCmd->buttons & IN_ATTACK;
if (bKeepFiring && !G::CanPrimaryAttack && Vars::Aimbot::General::AimType.Value)
pCmd->buttons |= IN_ATTACK;
switch (nWeaponID)
{
case TF_WEAPON_SNIPERRIFLE_CLASSIC:
if (!iRealAimType && iLastAimType && G::IsAttacking)
Vars::Aimbot::General::AimType.Value = iLastAimType;
}
if (!Vars::Aimbot::General::AimType.Value || !G::CanPrimaryAttack && Vars::Aimbot::General::AimType.Value == 3 && (nWeaponID == TF_WEAPON_MINIGUN ? pWeapon->As<CTFMinigun>()->m_iWeaponState() == AC_STATE_FIRING || pWeapon->As<CTFMinigun>()->m_iWeaponState() == AC_STATE_SPINNING : true))
return;
switch (nWeaponID)
{
case TF_WEAPON_MINIGUN:
pCmd->buttons |= IN_ATTACK2;
if (pWeapon->As<CTFMinigun>()->m_iWeaponState() != AC_STATE_FIRING && pWeapon->As<CTFMinigun>()->m_iWeaponState() != AC_STATE_SPINNING)
return;
break;
case TF_WEAPON_SNIPERRIFLE:
case TF_WEAPON_SNIPERRIFLE_DECAP:
{
const bool bScoped = pLocal->IsScoped();
if (Vars::Aimbot::Hitscan::Modifiers.Value & (1 << 4) && !bScoped)
{
pCmd->buttons |= IN_ATTACK2;
return;
}
if ((Vars::Aimbot::Hitscan::Modifiers.Value & (1 << 3) || G::WeaponDefIndex == Sniper_m_TheMachina || G::WeaponDefIndex == Sniper_m_ShootingStar) && !bScoped)
return;
break;
}
case TF_WEAPON_SNIPERRIFLE_CLASSIC:
if (iRealAimType)
pCmd->buttons |= IN_ATTACK;
}
auto targets = SortTargets(pLocal, pWeapon);
if (targets.empty())
return;
for (auto& target : targets)
{
const auto iResult = CanHit(target, pLocal, pWeapon);
if (!iResult) continue;
if (iResult == 2)
{
Aim(pCmd, target.m_vAngleTo);
break;
}
G::Target = { target.m_pEntity->entindex(), I::GlobalVars->tickcount };
if (Vars::Aimbot::General::AimType.Value == 3)
G::AimPosition = target.m_vPos;
bool bShouldFire = ShouldFire(pLocal, pWeapon, pCmd, target);
if (bShouldFire)
{
pCmd->buttons |= IN_ATTACK;
if (nWeaponID == TF_WEAPON_SNIPERRIFLE_CLASSIC && pWeapon->As<CTFSniperRifle>()->m_flChargedDamage())
pCmd->buttons &= ~IN_ATTACK;
if (G::WeaponDefIndex == Engi_s_TheWrangler || G::WeaponDefIndex == Engi_s_FestiveWrangler)
pCmd->buttons |= IN_ATTACK2;
if (Vars::Aimbot::Hitscan::Modifiers.Value & (1 << 0) && nWeaponID == TF_WEAPON_MINIGUN && !pLocal->IsPrecisionRune())
{
if (pLocal->GetShootPos().DistTo(target.m_vPos) > Vars::Aimbot::Hitscan::TapFireDist.Value && pWeapon->GetWeaponSpread() != 0.f)
{
const float flTimeSinceLastShot = (pLocal->m_nTickBase() * TICK_INTERVAL) - pWeapon->m_flLastFireTime();
auto tfWeaponInfo = pWeapon->GetWeaponInfo();
if (tfWeaponInfo && tfWeaponInfo->GetWeaponData(0).m_nBulletsPerShot > 1)
{
if (flTimeSinceLastShot <= 0.25f)
pCmd->buttons &= ~IN_ATTACK;
}
else if (flTimeSinceLastShot <= 1.25f)
pCmd->buttons &= ~IN_ATTACK;
}
}
}
G::IsAttacking = SDK::IsAttacking(pLocal, pWeapon, pCmd);
if (G::IsAttacking)
{
if (target.m_pEntity->IsPlayer())
F::Resolver.Aimbot(target.m_pEntity->As<CTFPlayer>(), target.m_nAimedHitbox == 0);
if (target.m_bBacktrack)
pCmd->tick_count = TIME_TO_TICKS(target.m_Tick.flSimTime) + TIME_TO_TICKS(F::Backtrack.flFakeInterp);
if (!pWeapon->IsInReload())
{
if (Vars::Visuals::Bullet::BulletTracer.Value)
{
G::BulletsStorage.clear();
G::BulletsStorage.push_back({ {pLocal->GetShootPos(), target.m_vPos}, I::GlobalVars->curtime + 5.f, Vars::Colors::BulletTracer.Value, true });
}
if (Vars::Visuals::Hitbox::ShowHitboxes.Value)
{
G::BoxesStorage.clear();
auto vBoxes = F::Visuals.GetHitboxes((matrix3x4*)(&target.m_Tick.BoneMatrix.BoneMatrix), target.m_pEntity->As<CBaseAnimating>());
G::BoxesStorage.insert(G::BoxesStorage.end(), vBoxes.begin(), vBoxes.end());
}
}
}
Aim(pCmd, target.m_vAngleTo);
break;
}
}

View File

@ -0,0 +1,25 @@
#pragma once
#include "../../../SDK/SDK.h"
#include "../AimbotGlobal/AimbotGlobal.h"
class CAimbotHitscan
{
bool PlayerBoneInFOV(CTFPlayer* pTarget, Vec3 vLocalPos, Vec3 vLocalAngles, float& flFOVTo, Vec3& vPos, Vec3& vAngleTo);
std::vector<Target_t> GetTargets(CTFPlayer* pLocal, CTFWeaponBase* pWeapon);
std::vector<Target_t> SortTargets(CTFPlayer* pLocal, CTFWeaponBase* pWeapon);
bool IsHitboxValid(int nHitbox);
int GetHitboxPriority(int nHitbox, CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CBaseEntity* pTarget);
float GetMaxRange(CTFWeaponBase* pWeapon);
int CanHit(Target_t& target, CTFPlayer* pLocal, CTFWeaponBase* pWeapon);
void Aim(CUserCmd* pCmd, Vec3& vAngle);
Vec3 Aim(Vec3 vCurAngle, Vec3 vToAngle, int iMethod = Vars::Aimbot::General::AimType.Value);
bool ShouldFire(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCmd* pCmd, const Target_t& target);
public:
void Run(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCmd* pCmd);
};
ADD_FEATURE(CAimbotHitscan, AimbotHitscan)

View File

@ -0,0 +1,662 @@
#include "AimbotMelee.h"
#include "../../Simulation/MovementSimulation/MovementSimulation.h"
#include "../../TickHandler/TickHandler.h"
#include "../../Backtrack/Backtrack.h"
#include "../../Visuals/Visuals.h"
#include "../../EnginePrediction/EnginePrediction.h"
std::vector<Target_t> CAimbotMelee::GetTargets(CTFPlayer* pLocal, CTFWeaponBase* pWeapon)
{
std::vector<Target_t> validTargets;
const Vec3 vLocalPos = pLocal->GetShootPos();
const Vec3 vLocalAngles = I::EngineClient->GetViewAngles();
if (lockedTarget.m_pEntity)
{
auto pPlayer = lockedTarget.m_pEntity->As<CTFPlayer>();
if (!pPlayer->IsAlive() || pPlayer->IsAGhost())
lockedTarget.m_pEntity = nullptr;
else
{
Vec3 vPos = pPlayer->GetCenter();
Vec3 vAngleTo = Math::CalcAngle(vLocalPos, vPos);
const float flDistTo = vLocalPos.DistTo(vPos);
validTargets.push_back({ lockedTarget.m_pEntity, lockedTarget.m_TargetType, vPos, vAngleTo, lockedTarget.m_flFOVTo, flDistTo, lockedTarget.m_nPriority });
return validTargets;
}
}
if (Vars::Aimbot::General::Target.Value & PLAYER)
{
const bool bDisciplinary = Vars::Aimbot::Melee::WhipTeam.Value && pWeapon->m_iItemDefinitionIndex() == Soldier_t_TheDisciplinaryAction;
for (auto pEntity : H::Entities.GetGroup(bDisciplinary ? EGroupType::PLAYERS_ALL : EGroupType::PLAYERS_ENEMIES))
{
auto pPlayer = pEntity->As<CTFPlayer>();
if (pPlayer == pLocal || !pPlayer->IsAlive() || pPlayer->IsAGhost())
continue;
if (F::AimbotGlobal.ShouldIgnore(pPlayer, pLocal, pWeapon))
continue;
Vec3 vPos = pPlayer->GetCenter();
Vec3 vAngleTo = Math::CalcAngle(vLocalPos, vPos);
const float flFOVTo = Math::CalcFov(vLocalAngles, vAngleTo);
if (flFOVTo > Vars::Aimbot::General::AimFOV.Value)
continue;
const float flDistTo = vLocalPos.DistTo(vPos);
const int priority = F::AimbotGlobal.GetPriority(pPlayer->entindex());
validTargets.push_back({ pPlayer, ETargetType::PLAYER, vPos, vAngleTo, flFOVTo, flDistTo, priority });
}
}
if (Vars::Aimbot::General::Target.Value)
{
const bool hasWrench = (pWeapon->m_iWeaponID() == TF_WEAPON_WRENCH);
const bool canDestroySapper = (G::WeaponDefIndex == Pyro_t_Homewrecker ||
G::WeaponDefIndex == Pyro_t_TheMaul ||
G::WeaponDefIndex == Pyro_t_NeonAnnihilator ||
G::WeaponDefIndex == Pyro_t_NeonAnnihilatorG);
for (auto pEntity : H::Entities.GetGroup(hasWrench || canDestroySapper ? EGroupType::BUILDINGS_ALL : EGroupType::BUILDINGS_ENEMIES))
{
auto pBuilding = pEntity->As<CBaseObject>();
bool isSentry = pBuilding->IsSentrygun(), isDispenser = pBuilding->IsDispenser(), isTeleporter = pBuilding->IsTeleporter();
if (!(Vars::Aimbot::General::Target.Value & SENTRY) && isSentry)
continue;
if (!(Vars::Aimbot::General::Target.Value & DISPENSER) && isDispenser)
continue;
if (!(Vars::Aimbot::General::Target.Value & TELEPORTER) && isTeleporter)
continue;
if (pBuilding->m_iTeamNum() == pLocal->m_iTeamNum())
{
if (hasWrench)
{
if (!AimFriendlyBuilding(pBuilding))
continue;
}
if (canDestroySapper)
{
if (!pBuilding->m_bHasSapper())
continue;
}
}
Vec3 vPos = pBuilding->GetCenter();
Vec3 vAngleTo = Math::CalcAngle(vLocalPos, vPos);
const float flFOVTo = Math::CalcFov(vLocalAngles, vAngleTo);
const float flDistTo = vLocalPos.DistTo(vPos);
if (flFOVTo > Vars::Aimbot::General::AimFOV.Value)
continue;
validTargets.push_back({ pBuilding, isSentry ? ETargetType::SENTRY : (isDispenser ? ETargetType::DISPENSER : ETargetType::TELEPORTER), vPos, vAngleTo, flFOVTo, flDistTo });
}
}
if (Vars::Aimbot::General::Target.Value & NPC)
{
for (auto pNPC : H::Entities.GetGroup(EGroupType::WORLD_NPC))
{
Vec3 vPos = pNPC->GetCenter();
Vec3 vAngleTo = Math::CalcAngle(vLocalPos, vPos);
const float flFOVTo = Math::CalcFov(vLocalAngles, vAngleTo);
const float flDistTo = vLocalPos.DistTo(vPos);
if (flFOVTo > Vars::Aimbot::General::AimFOV.Value)
continue;
validTargets.push_back({ pNPC, ETargetType::NPC, vPos, vAngleTo, flFOVTo, flDistTo });
}
}
return validTargets;
}
bool CAimbotMelee::AimFriendlyBuilding(CBaseObject* pBuilding)
{
if (!pBuilding->m_bMiniBuilding() && pBuilding->m_iUpgradeLevel() != 3 || pBuilding->m_bHasSapper() || pBuilding->m_iHealth() < pBuilding->m_iMaxHealth())
return true;
if (pBuilding->IsSentrygun())
{
auto pSentry = pBuilding->As<CObjectSentrygun>();
int iShells, iMaxShells, iRockets, iMaxRockets;
pSentry->GetAmmoCount(iShells, iMaxShells, iRockets, iMaxRockets);
if (iShells < iMaxShells || iRockets < iMaxRockets)
return true;
}
return false;
}
std::vector<Target_t> CAimbotMelee::SortTargets(CTFPlayer* pLocal, CTFWeaponBase* pWeapon)
{
if (lockedTarget.m_pEntity)
return { lockedTarget };
auto validTargets = GetTargets(pLocal, pWeapon);
const auto& sortMethod = ESortMethod::DISTANCE; //static_cast<ESortMethod>(Vars::Aimbot::Melee::SortMethod.Value);
F::AimbotGlobal.SortTargets(&validTargets, sortMethod);
std::vector<Target_t> sortedTargets = {};
int i = 0; for (auto& target : validTargets)
{
i++; if (i > Vars::Aimbot::General::MaxTargets.Value) break;
sortedTargets.push_back(target);
}
F::AimbotGlobal.SortPriority(&sortedTargets);
return sortedTargets;
}
int CAimbotMelee::GetSwingTime(CTFWeaponBase* pWeapon)
{
if (pWeapon->m_iWeaponID() == TF_WEAPON_KNIFE)
return 0;
return Vars::Aimbot::Melee::SwingTicks.Value;
}
void CAimbotMelee::SimulatePlayers(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, std::vector<Target_t> targets,
Vec3& vEyePos, std::unordered_map<CBaseEntity*, std::deque<TickRecord>>& pRecordMap,
std::unordered_map<CBaseEntity*, std::deque<std::pair<Vec3, Vec3>>>& simLines)
{
if (lockedTarget.m_pEntity)
return;
// swing prediction / auto warp
const int iSwingTicks = GetSwingTime(pWeapon);
int iMax = (iDoubletapTicks && Vars::CL_Move::Doubletap::AntiWarp.Value && pLocal->OnSolid())
? std::max(iSwingTicks - Vars::CL_Move::Doubletap::TickLimit.Value - 1, 0)
: std::max(iSwingTicks, iDoubletapTicks);
if ((Vars::Aimbot::Melee::SwingPrediction.Value || iDoubletapTicks) && pWeapon->m_flSmackTime() < 0.f && iMax)
{
PlayerStorage localStorage;
std::unordered_map<CBaseEntity*, PlayerStorage> targetStorage;
F::MoveSim.Initialize(pLocal, localStorage, false, iDoubletapTicks);
if (pLocal->OnSolid()) // lol
{
localStorage.m_MoveData.m_flForwardMove = G::CurrentUserCmd->forwardmove;
localStorage.m_MoveData.m_flSideMove = G::CurrentUserCmd->sidemove;
localStorage.m_MoveData.m_flUpMove = G::CurrentUserCmd->upmove;
localStorage.m_MoveData.m_vecAngles.y = localStorage.m_MoveData.m_vecOldAngles.y = localStorage.m_MoveData.m_vecViewAngles.y = G::CurrentUserCmd->viewangles.y;
}
for (auto& target : targets)
F::MoveSim.Initialize(target.m_pEntity, targetStorage[target.m_pEntity], false);
for (int i = 0; i < iMax; i++) // intended for plocal to collide with targets
{
if (i < iMax)
{
if (pLocal->IsCharging() && iMax - i <= GetSwingTime(pWeapon)) // demo charge fix for swing pred
{
localStorage.m_MoveData.m_flMaxSpeed = pLocal->TeamFortress_CalculateMaxSpeed(true);
localStorage.m_MoveData.m_flClientMaxSpeed = localStorage.m_MoveData.m_flMaxSpeed;
}
F::MoveSim.RunTick(localStorage);
}
if (i < iSwingTicks - iDoubletapTicks)
{
for (auto& target : targets)
{
F::MoveSim.RunTick(targetStorage[target.m_pEntity]);
if (!targetStorage[target.m_pEntity].m_bFailed)
pRecordMap[target.m_pEntity].push_front({
target.m_pEntity->m_flSimulationTime() + TICKS_TO_TIME(i + 1),
I::GlobalVars->curtime + TICKS_TO_TIME(i + 1),
I::GlobalVars->tickcount + i + 1,
false,
BoneMatrixes{},
targetStorage[target.m_pEntity].m_MoveData.m_vecAbsOrigin
});
}
}
}
vEyePos = localStorage.m_MoveData.m_vecAbsOrigin + pLocal->m_vecViewOffset();
if (Vars::Visuals::Simulation::SwingLines.Value)
{
const bool bAlwaysDraw = !Vars::Aimbot::General::AutoShoot.Value || Vars::Debug::Info.Value;
if (!bAlwaysDraw)
{
simLines[pLocal] = localStorage.PredictionLines;
for (auto& target : targets)
simLines[target.m_pEntity] = targetStorage[target.m_pEntity].PredictionLines;
}
else
{
G::LinesStorage.clear();
G::LinesStorage.push_back({ localStorage.PredictionLines, I::GlobalVars->curtime + 5.f, Vars::Colors::ProjectileColor.Value });
for (auto& target : targets)
G::LinesStorage.push_back({ targetStorage[target.m_pEntity].PredictionLines, I::GlobalVars->curtime + 5.f, Vars::Colors::PredictionColor.Value });
}
}
F::MoveSim.Restore(localStorage);
for (auto& target : targets)
F::MoveSim.Restore(targetStorage[target.m_pEntity]);
}
}
bool CAimbotMelee::CanBackstab(CBaseEntity* pTarget, CTFPlayer* pLocal, Vec3 eyeAngles)
{
if (!pLocal || !pTarget)
return false;
if (Vars::Aimbot::Melee::IgnoreRazorback.Value)
{
CUtlVector<CBaseEntity*> itemList;
int iBackstabShield = SDK::AttribHookValue(0, "set_blockbackstab_once", pTarget, &itemList);
if (iBackstabShield && itemList.Count())
{
CBaseEntity* pEntity = itemList.Element(0);
if (pEntity && pEntity->ShouldDraw())
return false;
}
}
Vector vToTarget;
vToTarget = pTarget->GetAbsOrigin() - pLocal->m_vecOrigin();
vToTarget.z = 0.f;
const float flDist = vToTarget.Length();
vToTarget.Normalize();
Vector vOwnerForward;
Math::AngleVectors(eyeAngles, &vOwnerForward);
vOwnerForward.z = 0.f;
vOwnerForward.Normalize();
Vector vTargetForward;
Math::AngleVectors(F::Backtrack.mEyeAngles[pTarget], &vTargetForward);
vTargetForward.z = 0.f;
vTargetForward.Normalize();
const float flPosVsTargetViewDot = vToTarget.Dot(vTargetForward); // Behind?
const float flPosVsOwnerViewDot = vToTarget.Dot(vOwnerForward); // Facing?
const float flViewAnglesDot = vTargetForward.Dot(vOwnerForward); // Facestab?
return flDist > 0.1f && flPosVsTargetViewDot > (0.f + 0.0031f) && flPosVsOwnerViewDot > 0.5f && flViewAnglesDot > (-0.3f + 0.0031f); // 0.00306795676297 ?
}
int CAimbotMelee::CanHit(Target_t& target, CTFPlayer* pLocal, CTFWeaponBase* pWeapon, Vec3 vEyePos, std::deque<TickRecord> newRecords)
{
float flHull = SDK::AttribHookValue(18, "melee_bounds_multiplier", pWeapon);
float flRange = pWeapon->GetSwingRange(pLocal);
if (pLocal->m_flModelScale() > 1.0f)
{
flRange *= pLocal->m_flModelScale();
flRange *= pLocal->m_flModelScale();
flRange *= pLocal->m_flModelScale();
}
flRange = SDK::AttribHookValue(flRange, "melee_range_multiplier", pWeapon);
if (flHull <= 0.f || flRange <= 0.f)
return false;
static Vec3 vecSwingMins = { -flHull, -flHull, -flHull };
static Vec3 vecSwingMaxs = { flHull, flHull, flHull };
CGameTrace trace;
CTraceFilterHitscan filter;
filter.pSkip = pLocal;
matrix3x4 bones[128];
target.m_pEntity->SetupBones(bones, 128, BONE_USED_BY_ANYTHING, target.m_pEntity->m_flSimulationTime());
std::deque<TickRecord> vRecords;
{
auto pRecords = F::Backtrack.GetRecords(target.m_pEntity);
if (pRecords && target.m_TargetType == ETargetType::PLAYER)
vRecords = *pRecords;
else
{
matrix3x4 bones[128];
if (!target.m_pEntity->SetupBones(bones, 128, BONE_USED_BY_ANYTHING, target.m_pEntity->m_flSimulationTime()))
return false;
vRecords.push_front({
target.m_pEntity->m_flSimulationTime(),
I::GlobalVars->curtime,
I::GlobalVars->tickcount,
false,
*reinterpret_cast<BoneMatrixes*>(&bones),
target.m_pEntity->m_vecOrigin()
});
}
}
if (!newRecords.empty())
{
for (TickRecord& pTick : newRecords)
{
vRecords.pop_back(); vRecords.push_front({ pTick.flSimTime, pTick.flCreateTime, pTick.iTickCount, false, *reinterpret_cast<BoneMatrixes*>(&bones), pTick.vOrigin });
}
for (TickRecord& pTick : vRecords)
{
pTick.flSimTime -= TICKS_TO_TIME(newRecords.size());
pTick.flCreateTime -= TICKS_TO_TIME(newRecords.size());
pTick.iTickCount -= int(newRecords.size());
}
}
std::deque<TickRecord> validRecords = target.m_TargetType == ETargetType::PLAYER ? F::Backtrack.GetValidRecords(&vRecords, pLocal, true) : vRecords;
if (!Vars::Backtrack::Enabled.Value && !validRecords.empty())
validRecords = { validRecords.front() };
// this might be retarded
const float flTargetPos = (target.m_pEntity->m_vecMaxs().z - target.m_pEntity->m_vecMins().z) * 65.f / 82.f;
const float flLocalPos = (pLocal->m_vecMaxs().z - pLocal->m_vecMins().z) * 65.f / 82.f;
const Vec3 vecDiff = { 0, 0, std::min(flTargetPos, flLocalPos) };
for (auto& pTick : validRecords)
{
const Vec3 vRestore = target.m_pEntity->GetAbsOrigin();
target.m_pEntity->SetAbsOrigin(pTick.vOrigin);
target.m_vPos = pTick.vOrigin + vecDiff;
target.m_vAngleTo = Aim(G::CurrentUserCmd->viewangles, Math::CalcAngle(vEyePos, target.m_vPos), iAimType);
Vec3 vecForward = Vec3();
Math::AngleVectors(target.m_vAngleTo, &vecForward);
Vec3 vecTraceEnd = vEyePos + (vecForward * flRange);
SDK::Trace(vEyePos, vecTraceEnd, MASK_SHOT | CONTENTS_GRATE, &filter, &trace);
bool bReturn = trace.m_pEnt && trace.m_pEnt == target.m_pEntity;
if (!bReturn)
{
SDK::TraceHull(vEyePos, vecTraceEnd, vecSwingMins, vecSwingMaxs, MASK_SHOT | CONTENTS_GRATE, &filter, &trace);
bReturn = trace.m_pEnt && trace.m_pEnt == target.m_pEntity;
}
if (bReturn && Vars::Aimbot::Melee::AutoBackstab.Value && pWeapon->m_iWeaponID() == TF_WEAPON_KNIFE)
{
if (target.m_TargetType == ETargetType::PLAYER)
bReturn = CanBackstab(target.m_pEntity, pLocal, target.m_vAngleTo);
else
bReturn = false;
}
target.m_pEntity->SetAbsOrigin(vRestore);
if (bReturn)
{
target.m_Tick = pTick;
if (target.m_TargetType == ETargetType::PLAYER) // && Vars::Backtrack::Enabled.Value
target.m_bBacktrack = true;
return true;
}
else if (iAimType == 2)
{
auto vAngle = Math::CalcAngle(vEyePos, target.m_vPos);
Vec3 vecForward = Vec3();
Math::AngleVectors(vAngle, &vecForward);
Vec3 vecTraceEnd = vEyePos + (vecForward * flRange);
SDK::Trace(vEyePos, vecTraceEnd, MASK_SHOT | CONTENTS_GRATE, &filter, &trace);
if (trace.m_pEnt && trace.m_pEnt == target.m_pEntity)
return 2;
}
}
return false;
}
bool CAimbotMelee::IsAttacking(const CUserCmd* pCmd, CTFWeaponBase* pWeapon)
{
if (pWeapon->m_iWeaponID() == TF_WEAPON_KNIFE)
return pCmd->buttons & IN_ATTACK;
return TIME_TO_TICKS(pWeapon->m_flSmackTime()) == I::GlobalVars->tickcount - 1; // seems to work most (?) of the time
}
// assume angle calculated outside with other overload
void CAimbotMelee::Aim(CUserCmd* pCmd, Vec3& vAngle)
{
if (iAimType != 3)
{
pCmd->viewangles = vAngle;
I::EngineClient->SetViewAngles(pCmd->viewangles);
}
else if (G::IsAttacking)
{
SDK::FixMovement(pCmd, vAngle);
pCmd->viewangles = vAngle;
G::PSilentAngles = true;
}
}
Vec3 CAimbotMelee::Aim(Vec3 vCurAngle, Vec3 vToAngle, int iMethod)
{
Vec3 vReturn = {};
Math::ClampAngles(vToAngle);
switch (iMethod)
{
case 1: // Plain
case 3: // Silent
vReturn = vToAngle;
break;
case 2: // Smooth
{
auto shortDist = [](const float flAngleA, const float flAngleB)
{
const float flDelta = fmodf((flAngleA - flAngleB), 360.f);
return fmodf(2 * flDelta, 360.f) - flDelta;
};
const float t = 1.f - Vars::Aimbot::General::Smoothing.Value / 100.f;
vReturn.x = vCurAngle.x - shortDist(vCurAngle.x, vToAngle.x) * t;
vReturn.y = vCurAngle.y - shortDist(vCurAngle.y, vToAngle.y) * t;
break;
}
}
return vReturn;
}
void CAimbotMelee::Run(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCmd* pCmd)
{
if (lockedTarget.m_pEntity && pWeapon->m_flSmackTime() < 0.f)
lockedTarget.m_pEntity = nullptr;
if (!Vars::Aimbot::General::AimType.Value && !lockedTarget.m_pEntity || (!G::CanPrimaryAttack || !Vars::Aimbot::General::AutoShoot.Value) && pWeapon->m_flSmackTime() < 0.f)
return;
else if (!lockedTarget.m_pEntity)
iAimType = Vars::Aimbot::General::AimType.Value;
if (RunSapper(pLocal, pWeapon, pCmd))
return;
auto targets = SortTargets(pLocal, pWeapon);
if (targets.empty())
return;
iDoubletapTicks = F::Ticks.GetTicks(pLocal);
const bool bShouldSwing = iDoubletapTicks <= (GetSwingTime(pWeapon) ? 14 : 0) || Vars::CL_Move::Doubletap::AntiWarp.Value && pLocal->OnSolid();
Vec3 vEyePos = pLocal->GetShootPos();
std::unordered_map<CBaseEntity*, std::deque<TickRecord>> pRecordMap;
std::unordered_map<CBaseEntity*, std::deque<std::pair<Vec3, Vec3>>> simLines;
SimulatePlayers(pLocal, pWeapon, targets, vEyePos, pRecordMap, simLines);
for (auto& target : targets)
{
const auto iResult = CanHit(target, pLocal, pWeapon, vEyePos, pRecordMap[target.m_pEntity]);
if (!iResult) continue;
if (iResult == 2)
{
Aim(pCmd, target.m_vAngleTo);
break;
}
G::Target = { target.m_pEntity->entindex(), I::GlobalVars->tickcount };
if (!pRecordMap[target.m_pEntity].empty() && !lockedTarget.m_pEntity)
lockedTarget = target;
if (iAimType == 3)
G::AimPosition = target.m_vPos;
if (Vars::Aimbot::General::AutoShoot.Value && pWeapon->m_flSmackTime() < 0.f)
{
if (bShouldSwing)
pCmd->buttons |= IN_ATTACK;
if (iDoubletapTicks)
G::DoubleTap = true;
}
/*
// game will not manage this while shifting w/o prediction, force its hand
if (!Vars::Misc::Game::NetworkFix.Value && !Vars::Misc::Game::PredictionFix.Value
&& G::DoubleTap && pWeapon->m_iWeaponID() != TF_WEAPON_KNIFE)
{
if (pCmd->buttons & IN_ATTACK && pWeapon->m_flSmackTime() < 0.f)
pWeapon->m_flSmackTime() = TICKS_TO_TIME(I::GlobalVars->tickcount + 13);
I::Prediction->Update(I::ClientState->m_nDeltaTick, I::ClientState->m_nDeltaTick > 0, I::ClientState->last_command_ack, I::ClientState->lastoutgoingcommand + I::ClientState->chokedcommands);
}
*/
const bool bAttacking = IsAttacking(pCmd, pWeapon);
G::IsAttacking = bAttacking || bShouldSwing && G::DoubleTap; // dumb but works
if (G::IsAttacking)
{
if (target.m_bBacktrack)
pCmd->tick_count = TIME_TO_TICKS(target.m_Tick.flSimTime) + TIME_TO_TICKS(F::Backtrack.flFakeInterp);
// bug: fast old records seem to be progressively more unreliable ?
if (Vars::Visuals::Bullet::BulletTracer.Value)
{
G::BulletsStorage.clear();
G::BulletsStorage.push_back({ {vEyePos, target.m_vPos}, I::GlobalVars->curtime + 5.f, Vars::Colors::BulletTracer.Value, true });
}
if (Vars::Visuals::Simulation::SwingLines.Value)
{
const bool bAlwaysDraw = !Vars::Aimbot::General::AutoShoot.Value || Vars::Debug::Info.Value;
if (!bAlwaysDraw)
{
G::LinesStorage.clear();
G::LinesStorage.push_back({ simLines[pLocal], I::GlobalVars->curtime + 5.f, Vars::Colors::ProjectileColor.Value });
G::LinesStorage.push_back({ simLines[target.m_pEntity], I::GlobalVars->curtime + 5.f, Vars::Colors::PredictionColor.Value });
}
}
if (Vars::Visuals::Hitbox::ShowHitboxes.Value)
{
G::BoxesStorage.clear();
auto vBoxes = F::Visuals.GetHitboxes((matrix3x4*)(&target.m_Tick.BoneMatrix.BoneMatrix), target.m_pEntity->As<CBaseAnimating>());
G::BoxesStorage.insert(G::BoxesStorage.end(), vBoxes.begin(), vBoxes.end());
}
}
Aim(pCmd, target.m_vAngleTo);
G::IsAttacking = bAttacking;
break;
}
}
int GetAttachment(CBaseObject* pBuilding, int i)
{
int iAttachment = pBuilding->GetBuildPointAttachmentIndex(i);
if (pBuilding->IsSentrygun() && pBuilding->m_iUpgradeLevel() > 1) // idk why i need this
iAttachment = 3;
return iAttachment;
}
bool CAimbotMelee::FindNearestBuildPoint(CBaseObject* pBuilding, CTFPlayer* pLocal, Vec3& vPoint)
{
bool bFoundPoint = false;
static auto tf_obj_max_attach_dist = U::ConVars.FindVar("tf_obj_max_attach_dist");
float flNearestPoint = tf_obj_max_attach_dist ? tf_obj_max_attach_dist->GetFloat() : 160.f;
for (int i = 0; i < pBuilding->GetNumBuildPoints(); i++)
{
int v = GetAttachment(pBuilding, i);
Vec3 vOrigin;
if (pBuilding->GetAttachment(v, vOrigin)) // issues using pBuilding->GetBuildPoint i on sentries above level 1 for some reason
{
if (!SDK::VisPos(pLocal, pBuilding, pLocal->GetShootPos(), vOrigin))
continue;
float flDist = (vOrigin - pLocal->GetAbsOrigin()).Length();
if (flDist < flNearestPoint)
{
flNearestPoint = flDist;
vPoint = vOrigin;
bFoundPoint = true;
}
}
}
return bFoundPoint;
}
bool CAimbotMelee::RunSapper(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCmd* pCmd)
{
if (pWeapon->m_iWeaponID() != TF_WEAPON_BUILDER)
return false;
std::vector<Target_t> validTargets;
const Vec3 vLocalPos = pLocal->GetShootPos();
const Vec3 vLocalAngles = I::EngineClient->GetViewAngles();
for (auto pEntity : H::Entities.GetGroup(EGroupType::BUILDINGS_ENEMIES))
{
auto pBuilding = pEntity->As<CBaseObject>();
if (pBuilding->m_bHasSapper() || pBuilding->m_iTeamNum() != 2 && pBuilding->m_iTeamNum() != 3)
continue;
Vec3 vPoint;
if (!FindNearestBuildPoint(pBuilding, pLocal, vPoint))
continue;
Vec3 vAngleTo = Math::CalcAngle(vLocalPos, vPoint);
const float flFOVTo = Math::CalcFov(vLocalAngles, vAngleTo);
const float flDistTo = vLocalPos.DistTo(vPoint);
if (flFOVTo > Vars::Aimbot::General::AimFOV.Value)
continue;
validTargets.push_back({ pBuilding, ETargetType::UNKNOWN, vPoint, vAngleTo, flFOVTo, flDistTo });
}
F::AimbotGlobal.SortTargets(&validTargets, ESortMethod::DISTANCE);
for (auto& target : validTargets)
{
static int iLastRun = 0;
if ((Vars::Aimbot::General::AimType.Value == 3 ? iLastRun != I::GlobalVars->tickcount - 1 || G::PSilentAngles && G::ShiftedTicks == G::MaxShift : true) && Vars::Aimbot::General::AutoShoot.Value)
pCmd->buttons |= IN_ATTACK;
if (pCmd->buttons & IN_ATTACK)
{
target.m_vAngleTo = Aim(pCmd->viewangles, Math::CalcAngle(vLocalPos, target.m_vPos));
target.m_vAngleTo.x = pCmd->viewangles.x; // we don't need to care about pitch
Aim(pCmd, target.m_vAngleTo);
iLastRun = I::GlobalVars->tickcount;
}
break;
}
return true;
}

View File

@ -0,0 +1,34 @@
#pragma once
#include "../../../SDK/SDK.h"
#include "../AimbotGlobal/AimbotGlobal.h"
class CAimbotMelee
{
std::vector<Target_t> GetTargets(CTFPlayer* pLocal, CTFWeaponBase* pWeapon);
bool AimFriendlyBuilding(CBaseObject* pBuilding);
std::vector<Target_t> SortTargets(CTFPlayer* pLocal, CTFWeaponBase* pWeapon);
int GetSwingTime(CTFWeaponBase* pWeapon);
void SimulatePlayers(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, std::vector<Target_t> targets, Vec3& vEyePos,
std::unordered_map<CBaseEntity*, std::deque<TickRecord>>& pRecordMap,
std::unordered_map<CBaseEntity*, std::deque<std::pair<Vec3, Vec3>>>& simLines);
bool CanBackstab(CBaseEntity* pTarget, CTFPlayer* pLocal, Vec3 eyeAngles);
int CanHit(Target_t& target, CTFPlayer* pLocal, CTFWeaponBase* pWeapon, Vec3 vEyePos, std::deque<TickRecord> newRecords);
bool IsAttacking(const CUserCmd* pCmd, CTFWeaponBase* pWeapon);
void Aim(CUserCmd* pCmd, Vec3& vAngle);
Vec3 Aim(Vec3 vCurAngle, Vec3 vToAngle, int iMethod = Vars::Aimbot::General::AimType.Value);
bool FindNearestBuildPoint(CBaseObject* pBuilding, CTFPlayer* pLocal, Vec3& vPoint);
bool RunSapper(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCmd* pCmd);
Target_t lockedTarget;
int iAimType = 0;
int iDoubletapTicks = 0;
int iDoubletapMax = 0;
public:
void Run(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCmd* pCmd);
};
ADD_FEATURE(CAimbotMelee, AimbotMelee)

View File

@ -0,0 +1,974 @@
#include "AimbotProjectile.h"
#include "../../Simulation/MovementSimulation/MovementSimulation.h"
#include "../../Simulation/ProjectileSimulation/ProjectileSimulation.h"
#include "../../Backtrack/Backtrack.h"
#include "../../Visuals/Visuals.h"
std::vector<Target_t> CAimbotProjectile::GetTargets(CTFPlayer* pLocal, CTFWeaponBase* pWeapon)
{
std::vector<Target_t> validTargets;
const auto sortMethod = static_cast<ESortMethod>(Vars::Aimbot::General::TargetSelection.Value);
const Vec3 vLocalPos = pLocal->GetShootPos();
const Vec3 vLocalAngles = I::EngineClient->GetViewAngles();
if (Vars::Aimbot::General::Target.Value & PLAYER)
{
EGroupType groupType = EGroupType::PLAYERS_ENEMIES;
switch (pWeapon->m_iWeaponID())
{
case TF_WEAPON_CROSSBOW: groupType = EGroupType::PLAYERS_ALL; break;
case TF_WEAPON_LUNCHBOX: groupType = EGroupType::PLAYERS_TEAMMATES; break;
}
for (auto pEntity : H::Entities.GetGroup(groupType))
{
auto pPlayer = pEntity->As<CTFPlayer>();
if (pPlayer == pLocal || !pPlayer->IsAlive() || pPlayer->IsAGhost())
continue;
// Check if weapon should shoot at friendly players
if ((groupType == EGroupType::PLAYERS_ALL || groupType == EGroupType::PLAYERS_TEAMMATES) &&
pPlayer->m_iTeamNum() == pLocal->m_iTeamNum())
{
if (pPlayer->m_iHealth() >= pPlayer->m_iMaxHealth())
continue;
}
if (F::AimbotGlobal.ShouldIgnore(pPlayer, pLocal, pWeapon))
continue;
Vec3 vPos = pPlayer->GetCenter();
Vec3 vAngleTo = Math::CalcAngle(vLocalPos, vPos);
const float flFOVTo = Math::CalcFov(vLocalAngles, vAngleTo);
if (flFOVTo > Vars::Aimbot::General::AimFOV.Value)
continue;
const float flDistTo = (sortMethod == ESortMethod::DISTANCE) ? vLocalPos.DistTo(vPos) : 0.0f;
const int priority = F::AimbotGlobal.GetPriority(pPlayer->entindex());
validTargets.push_back({ pPlayer, ETargetType::PLAYER, vPos, vAngleTo, flFOVTo, flDistTo, priority });
}
}
const bool bIsRescueRanger = pWeapon->m_iWeaponID() == TF_WEAPON_SHOTGUN_BUILDING_RESCUE;
for (auto pEntity : H::Entities.GetGroup(bIsRescueRanger ? EGroupType::BUILDINGS_ALL : EGroupType::BUILDINGS_ENEMIES))
{
auto pBuilding = pEntity->As<CBaseObject>();
bool isSentry = pBuilding->IsSentrygun(), isDispenser = pBuilding->IsDispenser(), isTeleporter = pBuilding->IsTeleporter();
if (!(Vars::Aimbot::General::Target.Value & SENTRY) && isSentry)
continue;
if (!(Vars::Aimbot::General::Target.Value & DISPENSER) && isDispenser)
continue;
if (!(Vars::Aimbot::General::Target.Value & TELEPORTER) && isTeleporter)
continue;
// Check if the Rescue Ranger should shoot at friendly buildings
if (bIsRescueRanger && (pBuilding->m_iTeamNum() == pLocal->m_iTeamNum()))
{
if (pBuilding->m_iHealth() >= pBuilding->m_iMaxHealth())
continue;
}
Vec3 vPos = pBuilding->GetCenter();
Vec3 vAngleTo = Math::CalcAngle(vLocalPos, vPos);
const float flFOVTo = Math::CalcFov(vLocalAngles, vAngleTo);
if (flFOVTo > Vars::Aimbot::General::AimFOV.Value)
continue;
const float flDistTo = sortMethod == ESortMethod::DISTANCE ? vLocalPos.DistTo(vPos) : 0.0f;
validTargets.push_back({ pBuilding, isSentry ? ETargetType::SENTRY : (isDispenser ? ETargetType::DISPENSER : ETargetType::TELEPORTER), vPos, vAngleTo, flFOVTo, flDistTo });
}
if (Vars::Aimbot::General::Target.Value & NPC)
{
for (auto pNPC : H::Entities.GetGroup(EGroupType::WORLD_NPC))
{
Vec3 vPos = pNPC->GetCenter();
Vec3 vAngleTo = Math::CalcAngle(vLocalPos, vPos);
const float flFOVTo = Math::CalcFov(vLocalAngles, vAngleTo);
const float flDistTo = sortMethod == ESortMethod::DISTANCE ? vLocalPos.DistTo(vPos) : 0.0f;
if (flFOVTo > Vars::Aimbot::General::AimFOV.Value)
continue;
validTargets.push_back({ pNPC, ETargetType::NPC, vPos, vAngleTo, flFOVTo, flDistTo });
}
}
return validTargets;
}
std::vector<Target_t> CAimbotProjectile::SortTargets(CTFPlayer* pLocal, CTFWeaponBase* pWeapon)
{
auto validTargets = GetTargets(pLocal, pWeapon);
const auto& sortMethod = static_cast<ESortMethod>(Vars::Aimbot::General::TargetSelection.Value);
F::AimbotGlobal.SortTargets(&validTargets, sortMethod);
std::vector<Target_t> sortedTargets = {};
int i = 0; for (auto& target : validTargets)
{
i++; if (i > Vars::Aimbot::General::MaxTargets.Value) break;
sortedTargets.push_back(target);
}
F::AimbotGlobal.SortPriority(&sortedTargets);
return sortedTargets;
}
float GetSplashRadius(CTFWeaponBase* pWeapon, CTFPlayer* pLocal = nullptr)
{
float flRadius = 0.f;
switch (pWeapon->m_iWeaponID())
{
case TF_WEAPON_PARTICLE_CANNON:
case TF_WEAPON_ROCKETLAUNCHER_DIRECTHIT:
case TF_WEAPON_ROCKETLAUNCHER:
case TF_WEAPON_PIPEBOMBLAUNCHER:
flRadius = 146.f;
}
if (G::WeaponDefIndex == Pyro_s_TheScorchShot)
flRadius = 110.f;
if (!flRadius)
return 0.f;
flRadius = SDK::AttribHookValue(flRadius, "mult_explosion_radius", pWeapon);
if (pLocal && pLocal->InCond(TF_COND_BLASTJUMPING) && SDK::AttribHookValue(1.f, "rocketjump_attackrate_bonus", pWeapon) != 1.f)
{
switch (pWeapon->m_iWeaponID())
{
case TF_WEAPON_PARTICLE_CANNON:
case TF_WEAPON_ROCKETLAUNCHER_DIRECTHIT:
case TF_WEAPON_ROCKETLAUNCHER:
flRadius *= 0.8f;
}
}
return flRadius * Vars::Aimbot::Projectile::SplashRadius.Value / 100;
}
float PrimeTime(CTFWeaponBase* pWeapon)
{
if (pWeapon->m_iWeaponID() == TF_WEAPON_PIPEBOMBLAUNCHER)
{
static auto tf_grenadelauncher_livetime = U::ConVars.FindVar("tf_grenadelauncher_livetime");
const float flLiveTime = tf_grenadelauncher_livetime ? tf_grenadelauncher_livetime->GetFloat() : 0.8f;
return SDK::AttribHookValue(flLiveTime, "sticky_arm_time", pWeapon);
}
return 0.f;
}
int CAimbotProjectile::GetHitboxPriority(int nHitbox, CTFPlayer* pLocal, CTFWeaponBase* pWeapon, Target_t& target)
{
bool bHeadshot = target.m_TargetType == ETargetType::PLAYER && pWeapon->m_iWeaponID() == TF_WEAPON_COMPOUND_BOW;
if (Vars::Aimbot::Projectile::Modifiers.Value & (1 << 2) && bHeadshot)
{
float charge = I::GlobalVars->curtime - pWeapon->As<CTFPipebombLauncher>()->m_flChargeBeginTime();
float damage = Math::RemapValClamped(charge, 0.f, 1.f, 50.f, 120.f);
if (pLocal->IsMiniCritBoosted())
damage *= 1.36f;
if (damage >= target.m_pEntity->As<CTFPlayer>()->m_iHealth())
bHeadshot = false;
if (pLocal->IsCritBoosted()) // for reliability
bHeadshot = false;
}
const bool bLower = target.m_TargetType == ETargetType::PLAYER && target.m_pEntity->As<CTFPlayer>()->IsOnGround() && GetSplashRadius(pWeapon);
if (bHeadshot)
target.m_nAimedHitbox = HITBOX_HEAD;
switch (nHitbox)
{
case 0: return bHeadshot ? 0 : 2; // head
case 1: return bHeadshot ? 3 : (bLower ? 1 : 0); // body
case 2: return bHeadshot ? 3 : (bLower ? 0 : 1); // feet
}
return 3;
};
std::unordered_map<int, Vec3> CAimbotProjectile::GetDirectPoints(Target_t& target, bool bPlayer, CTFPlayer* pLocal, CTFWeaponBase* pWeapon)
{
std::unordered_map<int, Vec3> mPoints = {};
const Vec3 vMins = target.m_pEntity->m_vecMins(), vMaxs = target.m_pEntity->m_vecMaxs();
for (int i = 0; i < 3; i++)
{
const int iPriority = GetHitboxPriority(i, pLocal, pWeapon, target);
if (iPriority == 3)
continue;
switch (i)
{
case 0:
if (bPlayer && target.m_nAimedHitbox == HITBOX_HEAD)
{
//const Vec3 vOff = target.m_pEntity->As<CBaseAnimating>()->GetHitboxPos(HITBOX_HEAD) - target.m_pEntity->GetAbsOrigin(); // uncomment if https://www.youtube.com/watch?v=_PSGD-pJUrM is fixed
Vec3 vCenter, vBBoxMins, vBBoxMaxs; target.m_pEntity->As<CBaseAnimating>()->GetHitboxInfo(HITBOX_HEAD, &vCenter, &vBBoxMins, &vBBoxMaxs);
Vec3 vOff = vCenter + (vBBoxMins + vBBoxMaxs) / 2 - target.m_pEntity->GetAbsOrigin();
const float flHeight = vOff.z + (vMaxs.z - vOff.z) * (Vars::Aimbot::Projectile::HuntermanLerp.Value / 100.f);
const float flMax = vMaxs.z - Vars::Aimbot::Projectile::VerticalShift.Value;
mPoints[iPriority] = Vec3(vOff.x, vOff.y, std::min(flHeight, flMax));
}
else
mPoints[iPriority] = Vec3(0, 0, vMaxs.z - Vars::Aimbot::Projectile::VerticalShift.Value);
break;
case 1: mPoints[iPriority] = Vec3(0, 0, (vMaxs.z - vMins.z) / 2); break;
case 2: mPoints[iPriority] = Vec3(0, 0, vMins.z + Vars::Aimbot::Projectile::VerticalShift.Value); break;
}
}
return mPoints;
}
// seode
std::vector<Vec3> ComputeSphere(float flRadius, int iSamples)
{
std::vector<Vec3> vPoints;
vPoints.reserve(iSamples);
for (int n = 0; n < iSamples; n++)
{
float a1 = acosf(1.f - 2.f * n / iSamples);
float a2 = PI * (3.f - sqrtf(5.f)) * n;
Vec3 point = Vec3(sinf(a1) * cosf(a2), sinf(a1) * sinf(a2), -cosf(a1)) * flRadius;
vPoints.push_back(point);
}
return vPoints;
};
std::vector<Point_t> CAimbotProjectile::GetSplashPoints(Target_t& target, std::vector<Vec3>& vSpherePoints, CTFPlayer* pLocal, CTFWeaponBase* pWeapon, Info_t& tInfo, int iSimTime) // possibly add air splash for autodet weapons
{
std::vector<Point_t> vPoints = {};
const Vec3 vLocalEye = pLocal->GetShootPos(), vTargetEye = target.m_vPos + target.m_pEntity->As<CTFPlayer>()->GetViewOffset();
auto checkPoint = [&](CGameTrace& trace, Vec3 vNormal, bool& bErase, bool bGrate = false)
{
bErase = true;
if (!trace.DidHit() || !trace.m_pEnt || !trace.m_pEnt->GetAbsVelocity().IsZero() || trace.surface.flags & 0x0004 /*SURF_SKY*/)
return false;
bErase = false;
Point_t tPoint = { trace.endpos, {} };
CalculateAngle(vLocalEye, tPoint.m_vPoint, tInfo, iSimTime, pLocal, pWeapon, tPoint.m_Solution);
if (tPoint.m_Solution.m_iCalculated == 1)
{
bErase = true;
if (int(tPoint.m_Solution.m_flTime / TICK_INTERVAL) == iSimTime - 1)
{
Vec3 vForward; Math::AngleVectors({ tPoint.m_Solution.m_flPitch, tPoint.m_Solution.m_flYaw, 0.f }, &vForward);
if (vForward.Dot(vNormal) < 0)
vPoints.push_back(tPoint);
}
}
return true;
};
for (auto it = vSpherePoints.begin(); it != vSpherePoints.end();)
{
bool bErase = false;
Vec3 vPoint = *it + vTargetEye;
Solution_t solution; CalculateAngle(pLocal->GetShootPos(), vPoint, tInfo, iSimTime, pLocal, pWeapon, solution, false);
if (solution.m_iCalculated != 3 && abs(solution.m_flTime - TICKS_TO_TIME(iSimTime)) < tInfo.flRadius / tInfo.flVelocity)
{
bErase = true;
CGameTrace trace = {};
CTraceFilterWorldAndPropsOnly filter = {};
SDK::Trace(vTargetEye, vPoint, MASK_SOLID, &filter, &trace);
if (checkPoint(trace, trace.plane.normal, bErase) && !bErase) // regular
{
SDK::Trace(vPoint, vTargetEye, MASK_SHOT, &filter, &trace);
if (!trace.DidHit())
{
SDK::Trace(vPoint, vTargetEye, MASK_SOLID, &filter, &trace);
checkPoint(trace, trace.plane.normal, bErase, true); // grate
}
}
}
if (bErase)
it = vSpherePoints.erase(it);
else
++it;
}
std::sort(vPoints.begin(), vPoints.end(), [&](const auto& a, const auto& b) -> bool
{
return a.m_vPoint.DistTo(target.m_vPos) < b.m_vPoint.DistTo(target.m_vPos);
});
vPoints.resize(Vars::Aimbot::Projectile::SplashCount.Value);
const Vec3 vOriginal = target.m_pEntity->GetAbsOrigin();
target.m_pEntity->SetAbsOrigin(target.m_vPos);
for (auto it = vPoints.begin(); it != vPoints.end();)
{
auto& vPoint = *it;
bool bValid = vPoint.m_Solution.m_iCalculated;
if (bValid)
{
Vec3 vPos = {}; reinterpret_cast<CCollisionProperty*>(target.m_pEntity->GetCollideable())->CalcNearestPoint(vPoint.m_vPoint, &vPos);
bValid = vPoint.m_vPoint.DistTo(vPos) < tInfo.flRadius;
}
if (bValid)
++it;
else
it = vPoints.erase(it);
}
target.m_pEntity->SetAbsOrigin(vOriginal);
return vPoints;
}
void SolveProjectileSpeed(CTFWeaponBase* pWeapon, const Vec3& vLocalPos, const Vec3& vTargetPos, float& flVelocity, float& flDragTime, const float flGravity)
{
if (F::ProjSim.obj->m_dragBasis.IsZero())
return;
const float flGrav = flGravity * 800.0f;
const Vec3 vDelta = vTargetPos - vLocalPos;
const float flDist = vDelta.Length2D();
const float flRoot = pow(flVelocity, 4) - flGrav * (flGrav * pow(flDist, 2) + 2.f * vDelta.z * pow(flVelocity, 2));
if (flRoot < 0.f)
return;
const float flPitch = atan((pow(flVelocity, 2) - sqrt(flRoot)) / (flGrav * flDist));
const float flTime = flDist / (cos(flPitch) * flVelocity);
float flDrag = 0.f;
if (Vars::Aimbot::Projectile::DragOverride.Value)
flDrag = Vars::Aimbot::Projectile::DragOverride.Value;
else
{
switch (pWeapon->m_iItemDefinitionIndex()) // the remaps are dumb but they work so /shrug
{
case Demoman_m_GrenadeLauncher:
case Demoman_m_GrenadeLauncherR:
case Demoman_m_FestiveGrenadeLauncher:
case Demoman_m_Autumn:
case Demoman_m_MacabreWeb:
case Demoman_m_Rainbow:
case Demoman_m_SweetDreams:
case Demoman_m_CoffinNail:
case Demoman_m_TopShelf:
case Demoman_m_Warhawk:
case Demoman_m_ButcherBird:
case Demoman_m_TheIronBomber: flDrag = Math::RemapValClamped(flVelocity, 1217.f, k_flMaxVelocity, 0.120f, 0.200f); break; // 0.120 normal, 0.200 capped, 0.300 v3000
case Demoman_m_TheLochnLoad: flDrag = Math::RemapValClamped(flVelocity, 1504.f, k_flMaxVelocity, 0.070f, 0.085f); break; // 0.070 normal, 0.085 capped, 0.120 v3000
case Demoman_m_TheLooseCannon: flDrag = Math::RemapValClamped(flVelocity, 1454.f, k_flMaxVelocity, 0.385f, 0.530f); break; // 0.385 normal, 0.530 capped, 0.790 v3000
case Demoman_s_StickybombLauncher:
case Demoman_s_StickybombLauncherR:
case Demoman_s_FestiveStickybombLauncher:
case Demoman_s_TheQuickiebombLauncher:
case Demoman_s_TheScottishResistance: flDrag = Math::RemapValClamped(flVelocity, 922.f, k_flMaxVelocity, 0.085f, 0.190f); break; // 0.085 low, 0.190 capped, 0.230 v2400
}
}
flDragTime = powf(flTime, 2) * flDrag / 1.5f; // rough estimate to prevent m_flTime being too low
flVelocity = flVelocity - flVelocity * flTime * flDrag;
if (Vars::Aimbot::Projectile::TimeOverride.Value)
flDragTime = Vars::Aimbot::Projectile::TimeOverride.Value;
}
void CAimbotProjectile::CalculateAngle(const Vec3& vLocalPos, const Vec3& vTargetPos, Info_t& tInfo, int iSimTime, CTFPlayer* pLocal, CTFWeaponBase* pWeapon, Solution_t& out, bool bAccuracy)
{
if (out.m_iCalculated)
return;
const float flGrav = tInfo.flGravity * 800.f; //U::ConVars.FindVar("sv_gravity")->GetFloat()
float flPitch, flYaw;
{ // basic trajectory pass
const Vec3 vDelta = vTargetPos - vLocalPos;
const float flDist = vDelta.Length2D();
if (!flGrav)
{
const Vec3 vAngleTo = Math::CalcAngle(vLocalPos, vTargetPos);
flPitch = -DEG2RAD(vAngleTo.x);
flYaw = DEG2RAD(vAngleTo.y);
}
else
{ // arch
const float flRoot = pow(tInfo.flVelocity, 4) - flGrav * (flGrav * pow(flDist, 2) + 2.f * vDelta.z * pow(tInfo.flVelocity, 2));
if (flRoot < 0.f)
{ out.m_iCalculated = 3; return; }
flPitch = atan((pow(tInfo.flVelocity, 2) - sqrt(flRoot)) / (flGrav * flDist));
flYaw = atan2(vDelta.y, vDelta.x);
}
out.m_flTime = flDist / (cos(flPitch) * tInfo.flVelocity) - tInfo.flOffset;
flPitch = -RAD2DEG(flPitch) - tInfo.flUpFix, flYaw = RAD2DEG(flYaw);
}
if (int(out.m_flTime / TICK_INTERVAL) >= iSimTime)
{ out.m_iCalculated = 2; return; }
ProjectileInfo projInfo = {};
if (!F::ProjSim.GetInfo(pLocal, pWeapon, { flPitch, flYaw, 0 }, projInfo, bAccuracy))
{ out.m_iCalculated = 3; return; }
{ // correct angles
Vec3 vAngle; Math::VectorAngles(vTargetPos - projInfo.m_vPos, vAngle);
flPitch -= projInfo.m_vAng.x;
out.m_flYaw = flYaw + vAngle.y - projInfo.m_vAng.y;
}
{ // calculate trajectory from projectile origin
float flNewVel = tInfo.flVelocity, flDragTime = 0.f;
SolveProjectileSpeed(pWeapon, projInfo.m_vPos, vTargetPos, flNewVel, flDragTime, tInfo.flGravity);
const Vec3 vDelta = vTargetPos - projInfo.m_vPos;
const float flDist = vDelta.Length2D();
if (!flGrav)
{
const Vec3 vAngleTo = Math::CalcAngle(projInfo.m_vPos, vTargetPos);
out.m_flPitch = -DEG2RAD(vAngleTo.x);
}
else
{ // arch
const float flRoot = pow(flNewVel, 4) - flGrav * (flGrav * pow(flDist, 2) + 2.f * vDelta.z * pow(flNewVel, 2));
if (flRoot < 0.f)
{ out.m_iCalculated = 3; return; }
out.m_flPitch = atan((pow(flNewVel, 2) - sqrt(flRoot)) / (flGrav * flDist));
}
out.m_flTime = flDist / (cos(out.m_flPitch) * flNewVel) + flDragTime;
out.m_flPitch = -RAD2DEG(out.m_flPitch) + flPitch - tInfo.flUpFix;
}
out.m_iCalculated = int(out.m_flTime / TICK_INTERVAL) < iSimTime ? 1 : 2;
}
bool CAimbotProjectile::TestAngle(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, Target_t& target, Vec3& vPoint, Vec3& vAngles, int iSimTime, bool bSplash, std::deque<std::pair<Vec3, Vec3>>* pProjLines)
{
ProjectileInfo projInfo = {};
if (!F::ProjSim.GetInfo(pLocal, pWeapon, vAngles, projInfo) || !F::ProjSim.Initialize(projInfo))
return false;
int bDidHit = 0;
CGameTrace trace = {};
CTraceFilterProjectile filter = {}; filter.pSkip = pLocal;
CTraceFilterWorldAndPropsOnly filterWorld = {};
//if (!projInfo.m_flGravity && !SDK::VisPosWorld(pLocal, target.m_pEntity, projInfo.m_vPos, vPoint, MASK_SOLID))
// return false;
if (!projInfo.m_flGravity)
{
SDK::TraceHull(projInfo.m_vPos, vPoint, projInfo.m_vHull * -1, projInfo.m_vHull, MASK_SOLID, &filterWorld, &trace);
if (trace.fraction < 0.999f)
return false;
}
if (Vars::Aimbot::General::AimType.Value != 2)
projInfo.m_vHull += Vec3(Vars::Aimbot::Projectile::HullInc.Value, Vars::Aimbot::Projectile::HullInc.Value, Vars::Aimbot::Projectile::HullInc.Value);
const Vec3 vOriginal = target.m_pEntity->GetAbsOrigin();
target.m_pEntity->SetAbsOrigin(target.m_vPos);
for (int n = -1; n < iSimTime; n++)
{
Vec3 Old = F::ProjSim.GetOrigin();
F::ProjSim.RunTick(projInfo);
Vec3 New = F::ProjSim.GetOrigin();
if (bDidHit)
{
trace.endpos = New;
continue;
}
if (!bSplash)
SDK::TraceHull(Old, New, projInfo.m_vHull * -1, projInfo.m_vHull, MASK_SOLID, &filter, &trace);
else
SDK::TraceHull(Old, New, projInfo.m_vHull * -1, projInfo.m_vHull, MASK_SOLID, &filterWorld, &trace);
if (trace.DidHit())
{
const bool bTarget = trace.m_pEnt == target.m_pEntity;
const bool bTime = iSimTime - n < 5;
bool bValid = (bTarget || bSplash) && bTime;
bValid = bValid && (bSplash ? SDK::VisPosWorld(nullptr, target.m_pEntity, trace.endpos, vPoint, MASK_SOLID) : true);
if (bValid)
{
if (Vars::Aimbot::General::AimType.Value == 2)
{
// attempted to have a headshot check though this seems more detrimental than useful outside of smooth aimbot
if (target.m_nAimedHitbox == HITBOX_HEAD)
{ // i think this is accurate? nope, 218
const Vec3 vOffset = (trace.endpos - New) + (vOriginal - target.m_vPos);
Vec3 vOld = F::ProjSim.GetOrigin() + vOffset;
F::ProjSim.RunTick(projInfo);
Vec3 vNew = F::ProjSim.GetOrigin() + vOffset;
CGameTrace trace = {};
SDK::Trace(vOld, vNew, MASK_SHOT, &filter, &trace);
trace.endpos -= vOffset;
if (trace.DidHit() && (trace.m_pEnt != target.m_pEntity || trace.hitbox != HITBOX_HEAD))
{ bDidHit = 2; continue; }
if (!trace.DidHit()) // loop and see if closest hitbox is head
{
auto pModel = target.m_pEntity->GetModel();
if (!pModel) { bDidHit = 2; continue; }
auto pHDR = I::ModelInfoClient->GetStudiomodel(pModel);
if (!pHDR) { bDidHit = 2; continue; }
auto pSet = pHDR->pHitboxSet(target.m_pEntity->As<CTFPlayer>()->m_nHitboxSet());
if (!pSet) { bDidHit = 2; continue; }
matrix3x4 BoneMatrix[128];
if (!target.m_pEntity->SetupBones(BoneMatrix, 128, BONE_USED_BY_ANYTHING, target.m_pEntity->m_flSimulationTime()))
{ bDidHit = 2; continue; }
QAngle direction; Vector forward;
Math::VectorAngles(Old - New, direction);
Math::AngleVectors(direction, &forward);
const Vec3 vPos = trace.endpos + forward * 16 + vOriginal - target.m_vPos;
//G::BulletsStorage.clear();
//G::BulletsStorage.push_back({ {pLocal->GetShootPos(), vPos}, I::GlobalVars->curtime + 5.f, Vars::Colors::PredictionColor.Value });
float closestDist; int closestId = -1;
for (int i = 0; i < pSet->numhitboxes; ++i)
{
auto bbox = pSet->pHitbox(i);
if (!bbox)
continue;
matrix3x4 rotMatrix;
Math::AngleMatrix(bbox->angle, rotMatrix);
matrix3x4 matrix;
Math::ConcatTransforms(BoneMatrix[bbox->bone], rotMatrix, matrix);
Vec3 mOrigin;
Math::GetMatrixOrigin(matrix, mOrigin);
const float flDist = vPos.DistTo(mOrigin);
if (closestId != -1 && flDist < closestDist || closestId == -1)
{
closestDist = flDist;
closestId = i;
}
}
bDidHit = closestId == 0 ? true : 2; continue;
}
}
if (bSplash && trace.endpos.DistTo(vPoint) > projInfo.m_flVelocity * TICK_INTERVAL)
{ bDidHit = 2; continue; }
}
bDidHit = true;
}
else
bDidHit = 2;
if (!bSplash)
trace.endpos = New;
if (!bTarget)
break;
}
}
target.m_pEntity->SetAbsOrigin(vOriginal);
if (bDidHit == 1)
{
projInfo.PredictionLines.push_back({ trace.endpos, Math::GetRotatedPosition(trace.endpos, Math::VelocityToAngles(F::ProjSim.GetVelocity() * Vec3(1, 1, 0)).Length2D() + 90, Vars::Visuals::Simulation::SeparatorLength.Value) });
*pProjLines = projInfo.PredictionLines;
}
return bDidHit == 1;
}
int CAimbotProjectile::CanHit(Target_t& target, CTFPlayer* pLocal, CTFWeaponBase* pWeapon, std::deque<std::pair<Vec3, Vec3>>* pMoveLines, std::deque<std::pair<Vec3, Vec3>>* pProjLines, std::vector<DrawBox>* pBoxes, float* pTimeTo)
{
if (Vars::Aimbot::General::Ignore.Value & UNSIMULATED && G::ChokeMap[target.m_pEntity->entindex()] > Vars::Aimbot::General::TickTolerance.Value)
return false;
PlayerStorage storage;
F::MoveSim.Initialize(target.m_pEntity, storage);
target.m_vPos = target.m_pEntity->m_vecOrigin();
const float flSize = target.m_pEntity->m_vecMins().DistTo(target.m_pEntity->m_vecMaxs());
int iMaxTime; Info_t tInfo = {};
ProjectileInfo projInfo = {};
{
if (!F::ProjSim.GetInfo(pLocal, pWeapon, {}, projInfo, false) || !F::ProjSim.Initialize(projInfo, false))
{
F::MoveSim.Restore(storage);
return false;
}
iMaxTime = TIME_TO_TICKS(std::min(projInfo.m_flLifetime, Vars::Aimbot::Projectile::PredictionTime.Value));
Vec3 vVelocity = F::ProjSim.GetVelocity();
tInfo.flVelocity = vVelocity.Length(); // account for up velocity & capped velocity
Vec3 vBadAngle = {}; Math::VectorAngles(vVelocity, vBadAngle); tInfo.flUpFix = vBadAngle.x; // account for up velocity
tInfo.vOffset = projInfo.m_vPos - pLocal->GetShootPos(); tInfo.vOffset.y *= -1;
tInfo.flOffset = tInfo.vOffset.Length() / tInfo.flVelocity; // silly
tInfo.flGravity = projInfo.m_flGravity;
tInfo.flRadius = GetSplashRadius(pWeapon, pLocal);
tInfo.flSphere = (tInfo.flRadius + flSize) / tInfo.flVelocity;
tInfo.iPrimeTime = TIME_TO_TICKS(PrimeTime(pWeapon));
}
const float flLatency = F::Backtrack.GetReal() + TICKS_TO_TIME(G::AnticipatedChoke - 1 + Vars::Aimbot::Projectile::LatOff.Value);
const bool bCanSplash = Vars::Aimbot::Projectile::SplashPrediction.Value && tInfo.flRadius;
const int iSplash = bCanSplash ? Vars::Aimbot::Projectile::SplashPrediction.Value : 0;
auto mDirectPoints = iSplash == 3 ? std::unordered_map<int, Vec3> {} : GetDirectPoints(target, target.m_TargetType == ETargetType::PLAYER, pLocal, pWeapon);
auto vSpherePoints = !iSplash ? std::vector<Vec3> {} : ComputeSphere(tInfo.flRadius + flSize, Vars::Aimbot::Projectile::SplashPoints.Value);
Vec3 vAngleTo, vPredicted, vTarget;
int iLowestPriority = std::numeric_limits<int>::max(); float flLowestDist = std::numeric_limits<float>::max();
for (int i = 0; i < iMaxTime; i++)
{
const int iSimTime = i - TIME_TO_TICKS(flLatency);
if (!storage.m_bFailed)
{
F::MoveSim.RunTick(storage);
target.m_vPos = storage.m_MoveData.m_vecAbsOrigin;
}
std::vector<Point_t> vSplashPoints = {};
if (iSplash)
{
Solution_t solution; CalculateAngle(pLocal->GetShootPos(), target.m_vPos, tInfo, iSimTime, pLocal, pWeapon, solution, false);
if (solution.m_iCalculated != 3)
{
const float flTimeTo = solution.m_flTime - TICKS_TO_TIME(iSimTime);
if (flTimeTo < -tInfo.flSphere || vSpherePoints.empty())
break;
else if (abs(flTimeTo) < tInfo.flSphere)
vSplashPoints = GetSplashPoints(target, vSpherePoints, pLocal, pWeapon, tInfo, iSimTime);
}
}
else if (mDirectPoints.empty())
break;
std::vector<std::tuple<Point_t, int, int>> vPoints = {};
for (const auto& [iIndex, vPoint] : mDirectPoints)
vPoints.push_back({ { target.m_vPos + vPoint, {}}, iIndex + (iSplash == 2 ? Vars::Aimbot::Projectile::SplashCount.Value : 0), iIndex });
for (const auto& vPoint : vSplashPoints)
vPoints.push_back({ vPoint, iSplash == 1 ? 3 : 0, -1 });
for (auto& [vPoint, iPriority, iIndex] : vPoints) // get most ideal point
{
const bool bSplash = iIndex == -1;
float flDist = bSplash ? target.m_vPos.DistTo(vPoint.m_vPoint) : flLowestDist;
if (!bSplash
? (iPriority >= iLowestPriority || !iLowestPriority || tInfo.iPrimeTime > iSimTime && !storage.m_MoveData.m_vecVelocity.IsZero())
: (iPriority > iLowestPriority || flDist > flLowestDist))
{
continue;
}
CalculateAngle(pLocal->GetShootPos(), vPoint.m_vPoint, tInfo, iSimTime, pLocal, pWeapon, vPoint.m_Solution);
if (!bSplash && (vPoint.m_Solution.m_iCalculated == 1 || vPoint.m_Solution.m_iCalculated == 3))
mDirectPoints.erase(iIndex);
if (vPoint.m_Solution.m_iCalculated != 1)
continue;
Vec3 vAngles = Aim(G::CurrentUserCmd->viewangles, { vPoint.m_Solution.m_flPitch, vPoint.m_Solution.m_flYaw, 0.f });
std::deque<std::pair<Vec3, Vec3>> vProjLines;
if (TestAngle(pLocal, pWeapon, target, vPoint.m_vPoint, vAngles, iSimTime, bSplash, &vProjLines))
{
iLowestPriority = iPriority; flLowestDist = flDist;
vAngleTo = vAngles, vPredicted = target.m_vPos, vTarget = vPoint.m_vPoint;
*pTimeTo = vPoint.m_Solution.m_flTime + flLatency;
*pMoveLines = storage.PredictionLines;
if (!pMoveLines->empty())
pMoveLines->push_back({ storage.m_MoveData.m_vecAbsOrigin, Math::GetRotatedPosition(storage.m_MoveData.m_vecAbsOrigin, Math::VelocityToAngles(storage.m_MoveData.m_vecVelocity * Vec3(1, 1, 0)).Length2D() + 90, Vars::Visuals::Simulation::SeparatorLength.Value) });
*pProjLines = vProjLines;
}
}
}
F::MoveSim.Restore(storage);
const float flTime = TICKS_TO_TIME(pProjLines->size());
target.m_vPos = vTarget;
if (iLowestPriority != std::numeric_limits<int>::max() &&
(target.m_TargetType == ETargetType::PLAYER ? !storage.m_bFailed : true)) // don't attempt to aim at players when movesim fails
{
target.m_vAngleTo = vAngleTo;
if (Vars::Visuals::Hitbox::ShowHitboxes.Value)
{
pBoxes->push_back({ vPredicted, target.m_pEntity->m_vecMins(), target.m_pEntity->m_vecMaxs(), Vec3(), I::GlobalVars->curtime + (Vars::Visuals::Simulation::Timed.Value ? flTime : 5.f), Vars::Colors::HitboxEdge.Value, Vars::Colors::HitboxFace.Value, true });
const float flSize = std::clamp(projInfo.m_vHull.x, 1.f, 3.f);
const Vec3 vSize = { flSize, flSize, flSize };
pBoxes->push_back({ vTarget, vSize * -1, vSize, Vec3(), I::GlobalVars->curtime + (Vars::Visuals::Simulation::Timed.Value ? flTime : 5.f), Vars::Colors::HitboxEdge.Value, Vars::Colors::HitboxFace.Value, true });
if (Vars::Debug::Info.Value && target.m_nAimedHitbox == HITBOX_HEAD) // huntsman head
{
const Vec3 vOriginOffset = target.m_pEntity->GetAbsOrigin() - vPredicted;
matrix3x4 BoneMatrix[128];
if (!target.m_pEntity->SetupBones(BoneMatrix, 128, BONE_USED_BY_ANYTHING, target.m_pEntity->m_flSimulationTime()))
return true;
auto vBoxes = F::Visuals.GetHitboxes((matrix3x4*)BoneMatrix, target.m_pEntity->As<CTFPlayer>(), HITBOX_HEAD);
for (auto& bBox : vBoxes)
{
bBox.m_vecPos -= vOriginOffset;
bBox.m_flTime = I::GlobalVars->curtime + (Vars::Visuals::Simulation::Timed.Value ? flTime : 5.f);
pBoxes->push_back(bBox);
}
}
if (Vars::Debug::Info.Value && target.m_nAimedHitbox == HITBOX_HEAD) // huntsman head, broken; removeme once 218 is fixed
{
const Vec3 vOriginOffset = target.m_pEntity->GetAbsOrigin() - vPredicted;
matrix3x4 BoneMatrix[128];
if (!target.m_pEntity->SetupBones(BoneMatrix, 128, BONE_USED_BY_ANYTHING, target.m_pEntity->m_flSimulationTime()))
return true;
auto vBoxes = F::Visuals.GetHitboxes((matrix3x4*)BoneMatrix, target.m_pEntity->As<CTFPlayer>(), HITBOX_HEAD);
for (auto& bBox : vBoxes)
{
bBox.m_vecPos -= vOriginOffset;
bBox.m_flTime = I::GlobalVars->curtime + (Vars::Visuals::Simulation::Timed.Value ? flTime : 5.f);
bBox.m_vecOrientation = Vec3();
pBoxes->push_back(bBox);
}
}
}
return true;
}
return false;
}
// assume angle calculated outside with other overload
void CAimbotProjectile::Aim(CUserCmd* pCmd, Vec3& vAngle)
{
if (Vars::Aimbot::General::AimType.Value != 3)
{
pCmd->viewangles = vAngle;
I::EngineClient->SetViewAngles(pCmd->viewangles);
}
else if (G::IsAttacking)
{
SDK::FixMovement(pCmd, vAngle);
pCmd->viewangles = vAngle;
G::PSilentAngles = true;
}
}
Vec3 CAimbotProjectile::Aim(Vec3 vCurAngle, Vec3 vToAngle, int iMethod)
{
Vec3 vReturn = {};
Math::ClampAngles(vToAngle);
switch (iMethod)
{
case 1: // Plain
case 3: // Silent
vReturn = vToAngle;
break;
case 2: // Smooth
{
auto shortDist = [](const float flAngleA, const float flAngleB)
{
const float flDelta = fmodf((flAngleA - flAngleB), 360.f);
return fmodf(2 * flDelta, 360.f) - flDelta;
};
const float t = 1.f - Vars::Aimbot::General::Smoothing.Value / 100.f;
vReturn.x = vCurAngle.x - shortDist(vCurAngle.x, vToAngle.x) * t;
vReturn.y = vCurAngle.y - shortDist(vCurAngle.y, vToAngle.y) * t;
break;
}
}
return vReturn;
}
bool CAimbotProjectile::RunMain(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCmd* pCmd)
{
static int iStaticAimType = Vars::Aimbot::General::AimType.Value;
const int iRealAimType = Vars::Aimbot::General::AimType.Value;
const int iLastAimType = iStaticAimType;
iStaticAimType = iRealAimType;
const int nWeaponID = pWeapon->m_iWeaponID();
const bool bAutomatic = pWeapon->IsStreamingWeapon(), bKeepFiring = bAutomatic && G::LastUserCmd->buttons & IN_ATTACK;
if (bKeepFiring && !G::CanPrimaryAttack)
pCmd->buttons |= IN_ATTACK;
switch (nWeaponID)
{
case TF_WEAPON_COMPOUND_BOW:
case TF_WEAPON_PIPEBOMBLAUNCHER:
case TF_WEAPON_CANNON:
if (!Vars::Aimbot::General::AutoShoot.Value && !iRealAimType && iLastAimType && G::IsAttacking)
Vars::Aimbot::General::AimType.Value = iLastAimType;
}
if (!Vars::Aimbot::General::AimType.Value || !G::CanPrimaryAttack && Vars::Aimbot::General::AimType.Value == 3 && nWeaponID != TF_WEAPON_PIPEBOMBLAUNCHER && nWeaponID != TF_WEAPON_CANNON)
return true;
auto targets = SortTargets(pLocal, pWeapon);
if (targets.empty())
return true;
if (Vars::Aimbot::Projectile::Modifiers.Value & (1 << 0) && iRealAimType
&& (nWeaponID == TF_WEAPON_COMPOUND_BOW || nWeaponID == TF_WEAPON_PIPEBOMBLAUNCHER || nWeaponID == TF_WEAPON_CANNON))
{
pCmd->buttons |= IN_ATTACK;
if (!G::CanPrimaryAttack && Vars::Aimbot::General::AimType.Value == 3)
return true;
}
for (auto& target : targets)
{
float flTimeTo = 0.f; std::deque<std::pair<Vec3, Vec3>> vMoveLines, vProjLines; std::vector<DrawBox> vBoxes = {};
const int result = CanHit(target, pLocal, pWeapon, &vMoveLines, &vProjLines, &vBoxes, &flTimeTo);
if (!result) continue;
G::Target = { target.m_pEntity->entindex(), I::GlobalVars->tickcount };
if (Vars::Aimbot::General::AimType.Value == 3)
G::AimPosition = target.m_vPos;
if (Vars::Aimbot::General::AutoShoot.Value)
{
pCmd->buttons |= IN_ATTACK;
if (G::WeaponDefIndex == Soldier_m_TheBeggarsBazooka)
{
if (pWeapon->m_iClip1() > 0)
pCmd->buttons &= ~IN_ATTACK;
}
else
{
if ((nWeaponID == TF_WEAPON_COMPOUND_BOW || nWeaponID == TF_WEAPON_PIPEBOMBLAUNCHER) && pWeapon->As<CTFPipebombLauncher>()->m_flChargeBeginTime() > 0.f)
pCmd->buttons &= ~IN_ATTACK;
else if (nWeaponID == TF_WEAPON_CANNON && pWeapon->As<CTFGrenadeLauncher>()->m_flDetonateTime() > 0.f)
{
bool bHealth = target.m_pEntity->IsPlayer() && target.m_pEntity->As<CTFPlayer>()->m_iHealth() > 50 || target.m_pEntity->IsBuilding() && target.m_pEntity->As<CBaseObject>()->m_iHealth() > 50;
if (Vars::Aimbot::Projectile::Modifiers.Value & (1 << 0) && bHealth)
{
float flCharge = pWeapon->As<CTFGrenadeLauncher>()->m_flDetonateTime() - I::GlobalVars->curtime;
if (std::clamp(flCharge - 0.05f, 0.f, 1.f) < flTimeTo)
pCmd->buttons &= ~IN_ATTACK;
}
else
pCmd->buttons &= ~IN_ATTACK;
}
}
}
G::IsAttacking = SDK::IsAttacking(pLocal, pWeapon, pCmd);
if ((G::IsAttacking || !Vars::Aimbot::General::AutoShoot.Value) && (!pWeapon->IsInReload() || pWeapon->m_iWeaponID() == TF_WEAPON_CROSSBOW))
{
if (Vars::Visuals::Simulation::Enabled.Value)
{
G::LinesStorage.clear();
G::LinesStorage.push_back({ vMoveLines, Vars::Visuals::Simulation::Timed.Value ? -int(vMoveLines.size()) : I::GlobalVars->curtime + 5.f, Vars::Colors::PredictionColor.Value });
if (G::IsAttacking)
G::LinesStorage.push_back({ vProjLines, Vars::Visuals::Simulation::Timed.Value ? -int(vProjLines.size()) - TIME_TO_TICKS(F::Backtrack.GetReal()) : I::GlobalVars->curtime + 5.f, Vars::Colors::ProjectileColor.Value });
}
if (Vars::Visuals::Hitbox::ShowHitboxes.Value)
{
G::BoxesStorage.clear();
G::BoxesStorage.insert(G::BoxesStorage.end(), vBoxes.begin(), vBoxes.end());
}
if (Vars::Visuals::Simulation::Enabled.Value || Vars::Visuals::Hitbox::ShowHitboxes.Value)
G::BulletsStorage.clear();
}
Aim(pCmd, target.m_vAngleTo);
if (G::PSilentAngles && pWeapon->m_iWeaponID() == TF_WEAPON_FLAMETHROWER)
G::PSilentAngles = false, G::SilentAngles = true;
break;
}
return false;
}
void CAimbotProjectile::Run(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCmd* pCmd)
{
const bool bEarly = RunMain(pLocal, pWeapon, pCmd);
float flAmount = 0.f;
if (pWeapon->m_iWeaponID() == TF_WEAPON_PIPEBOMBLAUNCHER)
{
const float flCharge = pWeapon->As<CTFPipebombLauncher>()->m_flChargeBeginTime() > 0.f ? I::GlobalVars->curtime - pWeapon->As<CTFPipebombLauncher>()->m_flChargeBeginTime() : 0.f;
flAmount = Math::RemapValClamped(flCharge, 0.f, SDK::AttribHookValue(4.f, "stickybomb_charge_rate", pWeapon), 0.f, 1.f);
}
else if (pWeapon->m_iWeaponID() == TF_WEAPON_CANNON)
{
const float flMortar = SDK::AttribHookValue(0.f, "grenade_launcher_mortar_mode", pWeapon);
const float flCharge = pWeapon->As<CTFGrenadeLauncher>()->m_flDetonateTime() > 0.f ? I::GlobalVars->curtime - pWeapon->As<CTFGrenadeLauncher>()->m_flDetonateTime() : -flMortar;
flAmount = flMortar ? Math::RemapValClamped(flCharge, -flMortar, 0.f, 0.f, 1.f) : 0.f;
}
if (pWeapon->m_iWeaponID() == TF_WEAPON_PIPEBOMBLAUNCHER && Vars::Aimbot::Projectile::AutoRelease.Value && flAmount > Vars::Aimbot::Projectile::AutoRelease.Value / 100)
pCmd->buttons &= ~IN_ATTACK;
else if (G::CanPrimaryAttack && Vars::Aimbot::Projectile::Modifiers.Value & (1 << 1))
{
if (bLastTickHeld && (!Vars::Aimbot::General::AimType.Value && G::LastUserCmd->buttons & IN_ATTACK && !(pCmd->buttons & IN_ATTACK) || flAmount > 0.95f))
{
switch (pWeapon->m_iWeaponID())
{
case TF_WEAPON_COMPOUND_BOW:
pCmd->buttons |= IN_ATTACK2;
pCmd->buttons &= ~IN_ATTACK;
break;
case TF_WEAPON_CANNON:
if (auto pSwap = pLocal->GetWeaponFromSlot(SLOT_SECONDARY))
{
pCmd->weaponselect = pSwap->entindex();
bLastTickCancel = pWeapon->entindex();
}
break;
case TF_WEAPON_PIPEBOMBLAUNCHER:
if (auto pSwap = pLocal->GetWeaponFromSlot(SLOT_PRIMARY))
{
pCmd->weaponselect = pSwap->entindex();
bLastTickCancel = pWeapon->entindex();
}
}
}
}
bLastTickHeld = Vars::Aimbot::General::AimType.Value;
}

View File

@ -0,0 +1,56 @@
#pragma once
#include "../../../SDK/SDK.h"
#include "../AimbotGlobal/AimbotGlobal.h"
struct Solution_t
{
float m_flPitch = 0.f;
float m_flYaw = 0.f;
float m_flTime = 0.f;
int m_iCalculated = 0;
};
struct Point_t
{
Vec3 m_vPoint = {};
Solution_t m_Solution = {};
};
struct Info_t
{
Vec3 vOffset = {};
float flVelocity = 0.f;
float flGravity = 0.f;
float flRadius = 0.f;
float flSphere = 0.f;
float flUpFix = 0.f;
float flOffset = 0.f;
int iPrimeTime = 0;
};
class CAimbotProjectile
{
std::vector<Target_t> GetTargets(CTFPlayer* pLocal, CTFWeaponBase* pWeapon);
std::vector<Target_t> SortTargets(CTFPlayer* pLocal, CTFWeaponBase* pWeapon);
int GetHitboxPriority(int nHitbox, CTFPlayer* pLocal, CTFWeaponBase* pWeapon, Target_t& target);
std::unordered_map<int, Vec3> GetDirectPoints(Target_t& target, bool bPlayer, CTFPlayer* pLocal, CTFWeaponBase* pWeapon);
std::vector<Point_t> GetSplashPoints(Target_t& target, std::vector<Vec3>& vSpherePoints, CTFPlayer* pLocal, CTFWeaponBase* pWeapon, Info_t& tInfo, int iSimTime);
void CalculateAngle(const Vec3& vLocalPos, const Vec3& vTargetPos, Info_t& tInfo, int iSimTime, CTFPlayer* pLocal, CTFWeaponBase* pWeapon, Solution_t& out, bool bAccuracy = true);
bool TestAngle(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, Target_t& target, Vec3& vPoint, Vec3& vAngles, int iSimTime, bool bSplash, std::deque<std::pair<Vec3, Vec3>>* pProjLines);
int CanHit(Target_t& target, CTFPlayer* pLocal, CTFWeaponBase* pWeapon, std::deque<std::pair<Vec3, Vec3>>* pMoveLines, std::deque<std::pair<Vec3, Vec3>>* pProjLines, std::vector<DrawBox>* pBoxes, float* pTimeTo);
bool RunMain(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCmd* pCmd);
void Aim(CUserCmd* pCmd, Vec3& vAngle);
Vec3 Aim(Vec3 vCurAngle, Vec3 vToAngle, int iMethod = Vars::Aimbot::General::AimType.Value);
bool bLastTickHeld = false;
public:
void Run(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCmd* pCmd);
int bLastTickCancel = 0;
};
ADD_FEATURE(CAimbotProjectile, AimbotProjectile)

View File

@ -0,0 +1,114 @@
#include "AutoAirblast.h"
bool CAutoAirblast::CanAirblastEntity(CTFPlayer* pLocal, CBaseEntity* pEntity, Vec3& vAngle, Vec3& vPos)
{
Vec3 vForward = {}; Math::AngleVectors(vAngle, &vForward);
const Vec3 vOrigin = pLocal->GetShootPos() + (vForward * 128.f);
CBaseEntity* pTarget;
for (CEntitySphereQuery sphere(vOrigin, 128.f);
(pTarget = sphere.GetCurrentEntity()) != nullptr;
sphere.NextEntity())
{
if (pTarget == pEntity)
break;
}
return pTarget == pEntity && SDK::VisPos(pLocal, pEntity, pLocal->GetShootPos(), vPos);
}
void CAutoAirblast::Run(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCmd* pCmd)
{
if (!Vars::Aimbot::Projectile::AutoAirblast.Value || !G::CanSecondaryAttack /*|| Vars::Auto::Airblast::DisableOnAttack.Value && pCmd->buttons & IN_ATTACK*/)
return;
const int iWeaponID = pWeapon->m_iWeaponID();
if (iWeaponID != TF_WEAPON_FLAMETHROWER && iWeaponID != TF_WEAPON_FLAME_BALL || G::WeaponDefIndex == Pyro_m_ThePhlogistinator)
return;
const Vec3 vEyePos = pLocal->GetShootPos();
bool bShouldBlast = false;
for (auto pProjectile : H::Entities.GetGroup(EGroupType::WORLD_PROJECTILES))
{
if (pProjectile->m_iTeamNum() == pLocal->m_iTeamNum())
continue;
switch (pProjectile->GetClassID())
{
case ETFClassID::CTFGrenadePipebombProjectile:
case ETFClassID::CTFStunBall:
{
if (pProjectile->As<CTFGrenadePipebombProjectile>()->m_bTouched())
continue; // Ignore landed stickies and sandman balls
break;
}
case ETFClassID::CTFProjectile_Arrow:
{
if (pProjectile->GetAbsVelocity().IsZero())
continue; // Ignore arrows with no velocity / not moving
}
}
Vec3 vPos = pProjectile->m_vecOrigin();
if (Math::GetFov(I::EngineClient->GetViewAngles(), vEyePos, vPos) > Vars::Aimbot::General::AimFOV.Value)
continue;
if (CanAirblastEntity(pLocal, pProjectile, pCmd->viewangles, vPos))
{
bShouldBlast = true;
break;
}
if (!bShouldBlast && Vars::Aimbot::Projectile::AutoAirblast.Value == 2) // possibly implement proj aimbot somehow ?
{
Vec3 vAngle = Math::CalcAngle(vEyePos, vPos);
if (CanAirblastEntity(pLocal, pProjectile, vAngle, vPos))
{
SDK::FixMovement(pCmd, vAngle);
pCmd->viewangles = vAngle;
G::PSilentAngles = true;
bShouldBlast = true;
break;
}
}
}
/*
if (!bShouldBlast && Vars::Auto::Airblast::ExtinguishPlayers.Value)
{
for (auto pPlayer : H::Entities.GetGroup(EGroupType::PLAYERS_TEAMMATES))
{
if (!pPlayer->IsOnFire() || !pPlayer->IsAlive() || pPlayer->IsAGhost())
continue;
Vec3 vPos = pPlayer->m_vecOrigin() + pPlayer->GetViewOffset(); // this seems to like to overpredict ?
if (Math::GetFov(I::EngineClient->GetViewAngles(), vEyePos, vPos) > Vars::Aimbot::General::AimFOV.Value)
continue;
if (CanAirblastEntity(pLocal, pPlayer, pCmd->viewangles, vPos))
{
bShouldBlast = true;
break;
}
if (!bShouldBlast && Vars::Aimbot::Projectile::AutoAirblast.Value == 2)
{
Vec3 vAngle = Math::CalcAngle(vEyePos, pPlayer->GetCenter());
if (CanAirblastEntity(pLocal, pPlayer, vAngle, vPos))
{
SDK::FixMovement(pCmd, vAngle);
pCmd->viewangles = vAngle;
G::PSilentAngles = true;
bShouldBlast = true;
break;
}
}
}
}
*/
if (bShouldBlast)
{
G::IsAttacking = true;
pCmd->buttons |= IN_ATTACK2;
}
}

View File

@ -0,0 +1,12 @@
#pragma once
#include "../../../SDK/SDK.h"
class CAutoAirblast
{
bool CanAirblastEntity(CTFPlayer* pLocal, CBaseEntity* pEntity, Vec3& vAngle, Vec3& vPos);
public:
void Run(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCmd* pCmd);
};
ADD_FEATURE(CAutoAirblast, AutoAirblast)

View File

@ -0,0 +1,80 @@
#include "AutoDetonate.h"
bool CAutoDetonate::CheckDetonation(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, EGroupType entityGroup, float flRadiusScale, CUserCmd* pCmd)
{
for (auto pEntity : H::Entities.GetGroup(entityGroup))
{
auto pExplosive = pEntity->As<CTFGrenadePipebombProjectile>();
if (pExplosive->m_iType() == TF_GL_MODE_REMOTE_DETONATE_PRACTICE || !pExplosive->m_bPulsed())
continue;
const Vec3 vOrigin = pExplosive->GetCenter();
if (entityGroup == EGroupType::MISC_LOCAL_STICKIES)
{
if (pExplosive->m_iType() == TF_GL_MODE_REMOTE_DETONATE && !pExplosive->m_bTouched())
{
static auto tf_grenadelauncher_livetime = U::ConVars.FindVar("tf_grenadelauncher_livetime");
static auto tf_sticky_radius_ramp_time = U::ConVars.FindVar("tf_sticky_radius_ramp_time");
static auto tf_sticky_airdet_radius = U::ConVars.FindVar("tf_sticky_airdet_radius");
float flLiveTime = tf_grenadelauncher_livetime ? tf_grenadelauncher_livetime->GetFloat() : 0.8f;
float flRampTime = tf_sticky_radius_ramp_time ? tf_sticky_radius_ramp_time->GetFloat() : 2.f;
float flAirdetRadius = tf_sticky_airdet_radius ? tf_sticky_airdet_radius->GetFloat() : 0.85f;
flRadiusScale *= Math::RemapValClamped(I::GlobalVars->curtime - pExplosive->m_flCreationTime(), flLiveTime, flLiveTime + flRampTime, flAirdetRadius, 1.f);
}
}
float flRadius = (entityGroup == EGroupType::MISC_LOCAL_STICKIES ? 146.f : 110.f) * flRadiusScale;
// Iterate through entities in sphere radius
CBaseEntity* pEntity;
for (CEntitySphereQuery sphere(vOrigin, flRadius);
(pEntity = sphere.GetCurrentEntity()) != nullptr;
sphere.NextEntity())
{
if (!pEntity || pEntity == pLocal || pEntity->IsPlayer() && (!pEntity->As<CTFPlayer>()->IsAlive() || pEntity->As<CTFPlayer>()->IsAGhost()) || pEntity->m_iTeamNum() == pLocal->m_iTeamNum())
continue;
// CEntitySphereQuery actually does a box test so we need to make sure the distance is less than the radius first
Vec3 vPos = {}; reinterpret_cast<CCollisionProperty*>(pEntity->GetCollideable())->CalcNearestPoint(vOrigin, &vPos);
if (vOrigin.DistTo(vPos) > flRadius)
continue;
const bool isPlayer = pEntity->IsPlayer() && Vars::Aimbot::General::Target.Value & PLAYER && !F::AimbotGlobal.ShouldIgnore(pEntity->As<CTFPlayer>(), pLocal, pWeapon);
const bool isSentry = Vars::Aimbot::General::Target.Value & SENTRY && pEntity->IsSentrygun();
const bool isDispenser = Vars::Aimbot::General::Target.Value & DISPENSER && pEntity->IsDispenser();
const bool isTeleporter = Vars::Aimbot::General::Target.Value & TELEPORTER && pEntity->IsTeleporter();
const bool isSticky = Vars::Aimbot::General::Target.Value & STICKY && pEntity->GetClassID() == ETFClassID::CTFGrenadePipebombProjectile && pEntity->As<CTFGrenadePipebombProjectile>()->m_iType() == TF_GL_MODE_REMOTE_DETONATE && (G::WeaponDefIndex == Demoman_s_TheQuickiebombLauncher || G::WeaponDefIndex == Demoman_s_TheScottishResistance);
const bool isNPC = Vars::Aimbot::General::Target.Value & NPC && pEntity->IsNPC();
const bool isBomb = Vars::Aimbot::General::Target.Value & BOMB && pEntity->IsBomb();
if (isPlayer || isSentry || isDispenser || isTeleporter || isNPC || isBomb || isSticky)
{
if (!SDK::VisPosProjectile(pExplosive, pEntity, vOrigin, isPlayer ? pEntity->m_vecOrigin() + pEntity->As<CTFPlayer>()->GetViewOffset() : pEntity->GetCenter(), MASK_SHOT))
continue;
if (G::WeaponDefIndex == Demoman_s_TheScottishResistance)
{
Vec3 vAngleTo = Math::CalcAngle(pLocal->GetShootPos(), vOrigin);
SDK::FixMovement(pCmd, vAngleTo);
pCmd->viewangles = vAngleTo;
G::PSilentAngles = true;
}
return true;
}
}
}
return false;
}
void CAutoDetonate::Run(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCmd* pCmd)
{
if (!Vars::Aimbot::Projectile::AutoDetonate.Value)
return;
// Check sticky detonation
if (Vars::Aimbot::Projectile::AutoDetonate.Value & (1 << 0) && CheckDetonation(pLocal, pWeapon, EGroupType::MISC_LOCAL_STICKIES, Vars::Aimbot::Projectile::AutodetRadius.Value / 100, pCmd))
pCmd->buttons |= IN_ATTACK2;
// Check flare detonation
if (Vars::Aimbot::Projectile::AutoDetonate.Value & (1 << 1) && CheckDetonation(pLocal, pWeapon, EGroupType::MISC_LOCAL_FLARES, Vars::Aimbot::Projectile::AutodetRadius.Value / 100, pCmd))
pCmd->buttons |= IN_ATTACK2;
}

View File

@ -0,0 +1,14 @@
#pragma once
#include "../../../SDK/SDK.h"
#include "../AimbotGlobal/AimbotGlobal.h"
class CAutoDetonate
{
bool CheckDetonation(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, EGroupType entityGroup, float flRadiusScale, CUserCmd* pCmd);
public:
void Run(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCmd* pCmd);
};
ADD_FEATURE(CAutoDetonate, AutoDetonate)

View File

@ -0,0 +1,192 @@
#include "AutoRocketJump.h"
#include "../../Simulation/ProjectileSimulation/ProjectileSimulation.h"
#include "../../Simulation/MovementSimulation/MovementSimulation.h"
void CAutoRocketJump::ManageAngle(CTFWeaponBase* pWeapon, CUserCmd* pCmd, Vec3& viewAngles)
{
Vec3 wishVel = { pCmd->forwardmove, pCmd->sidemove, 0.f }, wishAng;
Math::VectorAngles(wishVel, wishAng);
const bool bMoving = wishVel.Length2D() > 200.f;
float v_x = 0.f;
float v_y = bMoving ? viewAngles.y - wishAng.y : viewAngles.y;
if (pWeapon->m_iItemDefinitionIndex() == Soldier_m_TheOriginal)
{
v_x = bMoving ? 70.f : 89.f;
v_y -= 180.f;
}
else
{
v_x = bMoving ? 75.f : 89.f;
v_y -= bMoving ? 133.f : 81.5f;
}
viewAngles = { v_x, v_y, 0 };
}
void CAutoRocketJump::Run(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCmd* pCmd)
{
if (!pLocal || !pWeapon || !pCmd || !pLocal->IsAlive() || pLocal->IsAGhost() || I::EngineVGui->IsGameUIVisible() || I::MatSystemSurface->IsCursorVisible())
{
iFrame = -1;
return;
}
bool bValidWeapon = false;
{
switch (pWeapon->m_iWeaponID())
{
case TF_WEAPON_ROCKETLAUNCHER:
case TF_WEAPON_ROCKETLAUNCHER_DIRECTHIT:
case TF_WEAPON_PARTICLE_CANNON: bValidWeapon = true;
}
}
if (bValidWeapon && (Vars::Misc::Movement::AutoRocketJump.Value || Vars::Misc::Movement::AutoCTap.Value))
pCmd->buttons &= ~IN_ATTACK2; // fix for retarded issue
if (!bValidWeapon)
{
iFrame = -1;
return;
}
const bool bCurrGrounded = pLocal->OnSolid();
// doesn't seem 100% consistent, unsure if it's fps related, user error, or what
if (iFrame == -1 && (pWeapon->m_iItemDefinitionIndex() == Soldier_m_TheBeggarsBazooka ? G::IsAttacking : G::CanPrimaryAttack))
{
const bool bReloading = pWeapon->IsInReload();
Vec3 viewAngles = pCmd->viewangles;
if (Vars::Misc::Movement::AutoRocketJump.Value)
ManageAngle(pWeapon, pCmd, viewAngles);
bool bWillHit = false;
if (Vars::Misc::Movement::AutoRocketJump.Value || Vars::Misc::Movement::AutoCTap.Value)
{
PlayerStorage localStorage;
ProjectileInfo projInfo = {};
if (F::MoveSim.Initialize(pLocal, localStorage, false) && F::ProjSim.GetInfo(pLocal, pWeapon, viewAngles, projInfo) && F::ProjSim.Initialize(projInfo))
{
F::ProjSim.RunTick(projInfo); // run an initial time because dumb
for (int n = 1; n < 10; n++)
{
Vec3 Old = F::ProjSim.GetOrigin();
F::ProjSim.RunTick(projInfo);
Vec3 New = F::ProjSim.GetOrigin();
F::MoveSim.RunTick(localStorage);
CGameTrace trace = {};
CTraceFilterProjectile filter = {};
filter.pSkip = pLocal;
SDK::Trace(Old, New, MASK_SOLID, &filter, &trace);
if (trace.DidHit())
{
auto WillHit = [](CTFPlayer* pLocal, const Vec3& vOrigin, const Vec3& vPoint)
{
const Vec3 vOriginal = pLocal->GetAbsOrigin();
pLocal->SetAbsOrigin(vOrigin);
Vec3 vPos = {}; reinterpret_cast<CCollisionProperty*>(pLocal->GetCollideable())->CalcNearestPoint(vPoint, &vPos);
pLocal->SetAbsOrigin(vOriginal);
return vPoint.DistTo(vPos) < 120.f && SDK::VisPos(pLocal, pLocal, vPoint, vOrigin + pLocal->m_vecViewOffset(), MASK_SHOT);
};
bWillHit = WillHit(pLocal, localStorage.m_MoveData.m_vecAbsOrigin, trace.endpos);
iDelay = std::max(n + (n > Vars::Misc::Movement::ApplyAbove.Value ? Vars::Misc::Movement::TimingOffset.Value : 0), 0);
if (bWillHit)
{
SDK::Output("Auto jump", std::format("Ticks to hit: {} ({})", iDelay, n).c_str(), { 255, 0, 0, 255 }, Vars::Debug::Logging.Value);
if (Vars::Debug::Info.Value)
{
G::LinesStorage.clear(); G::BoxesStorage.clear();
G::LinesStorage.push_back({ {{ pLocal->GetShootPos(), {} }, { trace.endpos, {} }}, I::GlobalVars->curtime + 5.f, Vars::Colors::ProjectileColor.Value, true });
Vec3 angles; Math::VectorAngles(trace.plane.normal, angles);
G::BoxesStorage.push_back({ trace.endpos, { -1.f, -1.f, -1.f }, { 1.f, 1.f, 1.f }, angles, I::GlobalVars->curtime + 5.f, Vars::Colors::ProjectileColor.Value, {}, true });
}
}
break;
}
}
}
F::MoveSim.Restore(localStorage);
}
if (bWillHit)
{
if (bCurrGrounded && bCurrGrounded == bLastGrounded && !pLocal->IsDucking())
{
if (Vars::Misc::Movement::AutoRocketJump.Value)
{
iFrame = 0;
bFull = true;
}
else if (Vars::Misc::Movement::AutoCTap.Value)
iFrame = 0;
}
else if (!bCurrGrounded && pCmd->buttons & IN_DUCK)
{
if (pWeapon->m_iItemDefinitionIndex() != Soldier_m_TheBeggarsBazooka)
pCmd->buttons |= IN_ATTACK;
if (Vars::Misc::Movement::AutoRocketJump.Value && !bReloading)
{
G::SilentAngles = true; // would use G::PSilentAngles but that would mess with timing
pCmd->viewangles = viewAngles;
}
}
if (iFrame != -1 && bReloading && pWeapon->m_iItemDefinitionIndex() != Soldier_m_TheBeggarsBazooka)
{
iFrame = -1;
bFull = false;
pCmd->buttons |= IN_ATTACK;
}
}
if (iFrame == -1 && pWeapon->m_iWeaponID() == TF_WEAPON_PARTICLE_CANNON && G::Buttons & IN_ATTACK2)
pCmd->buttons |= IN_ATTACK2;
}
if (iFrame != -1)
{
iFrame++;
G::IsAttacking = true; // even if we aren't attacking, prevent other stuff from messing with timing, e.g. antiaim
if (iFrame == 1)
{
if (pWeapon->m_iItemDefinitionIndex() != Soldier_m_TheBeggarsBazooka)
pCmd->buttons |= IN_ATTACK;
if (bFull)
{
G::SilentAngles = true; // would use G::PSilentAngles but that would mess with timing
ManageAngle(pWeapon, pCmd, pCmd->viewangles);
}
}
if (iDelay > 1)
{
switch (iFrame - iDelay + 1)
{
case 0:
pCmd->buttons |= IN_DUCK;
break;
case 1:
pCmd->buttons |= IN_JUMP;
}
}
else // won't ctap in time
pCmd->buttons |= IN_DUCK | IN_JUMP;
if (iFrame == iDelay + (iDelay > 1 ? 1 : 3))
{
iFrame = -1;
bFull = false;
}
}
bLastGrounded = bCurrGrounded;
}

View File

@ -0,0 +1,19 @@
#pragma once
#include "../../../SDK/SDK.h"
class CAutoRocketJump
{
void ManageAngle(CTFWeaponBase* pWeapon, CUserCmd* pCmd, Vec3& viewAngles);
bool bLastGrounded = false;
bool bFull = false;
int iDelay = 0;
public:
void Run(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCmd* pCmd);
int iFrame = -1;
};
ADD_FEATURE(CAutoRocketJump, AutoRocketJump)

View File

@ -0,0 +1,10 @@
#include "AutoUber.h"
#include "../../Players/PlayerUtils.h"
// this will be rewritten soon
void CAutoUber::Run(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCmd* pCmd)
{
}

View File

@ -0,0 +1,12 @@
#pragma once
#include "../../../SDK/SDK.h"
#include "../AimbotGlobal/AimbotGlobal.h"
class CAutoUber
{
public:
void Run(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCmd* pCmd);
};
ADD_FEATURE(CAutoUber, AutoUber)

View File

@ -0,0 +1,10 @@
#include "AutoQueue.h"
void CAutoQueue::Run()
{
if (Vars::Misc::Queueing::AutoCasualQueue.Value && !I::TFPartyClient->BInQueueForMatchGroup(k_eTFMatchGroup_Casual_Default))
{
I::TFPartyClient->LoadSavedCasualCriteria();
I::TFPartyClient->RequestQueueForMatch(k_eTFMatchGroup_Casual_Default);
}
}

View File

@ -0,0 +1,10 @@
#pragma once
#include "../../SDK/SDK.h"
class CAutoQueue
{
public:
void Run();
};
ADD_FEATURE(CAutoQueue, AutoQueue);

View File

@ -0,0 +1,325 @@
#include "Backtrack.h"
//#include "../Simulation/MovementSimulation/MovementSimulation.h"
#define ROUND_TO_TICKS(t) (TICKS_TO_TIME(TIME_TO_TICKS(t)))
void CBacktrack::Restart()
{
mRecords.clear();
dSequences.clear();
iLastInSequence = 0;
}
// Returns the wish cl_interp
float CBacktrack::GetLerp()
{
return Vars::Backtrack::Enabled.Value ? std::clamp(static_cast<float>(Vars::Backtrack::Interp.Value), G::Lerp * 1000.f, flMaxUnlag * 1000.f) / 1000.f : G::Lerp;
}
// Returns the current (custom) backtrack latency
float CBacktrack::GetFake()
{
return bFakeLatency ? std::clamp(static_cast<float>(Vars::Backtrack::Latency.Value), 0.f, flMaxUnlag * 1000.f) / 1000.f : 0.f;
}
// Returns the current real latency
float CBacktrack::GetReal(int iFlow)
{
auto pNetChan = I::EngineClient->GetNetChannelInfo();
if (!pNetChan)
return 0.f;
if (iFlow != -1)
return pNetChan->GetLatency(iFlow) - (iFlow == FLOW_INCOMING ? GetFake() : 0.f);
return pNetChan->GetLatency(FLOW_INCOMING) - GetFake() + pNetChan->GetLatency(FLOW_OUTGOING);
}
void CBacktrack::SendLerp()
{
auto pNetChan = reinterpret_cast<CNetChannel*>(I::EngineClient->GetNetChannelInfo());
if (!pNetChan)
return;
static Timer interpTimer{};
if (interpTimer.Run(100))
{
float flTarget = GetLerp();
if (flTarget == flWishInterp) return;
flWishInterp = flTarget;
SDK::Output("SendNetMsg", std::format("cl_interp: {}", flTarget).c_str(), { 224, 255, 131, 255 }, Vars::Debug::Logging.Value);
NET_SetConVar cl_interp("cl_interp", std::to_string(flTarget).c_str());
pNetChan->SendNetMsg(cl_interp);
NET_SetConVar cl_interp_ratio("cl_interp_ratio", "1.0");
pNetChan->SendNetMsg(cl_interp_ratio);
NET_SetConVar cl_interpolate("cl_interpolate", "1");
pNetChan->SendNetMsg(cl_interpolate);
}
}
// Manages cl_interp client value
void CBacktrack::SetLerp(IGameEvent* pEvent)
{
const bool bLocal = I::EngineClient->GetPlayerForUserID(pEvent->GetInt("userid")) == I::EngineClient->GetLocalPlayer();
if (bLocal)
flFakeInterp = flWishInterp;
}
// Store the last 2048 sequences
void CBacktrack::UpdateDatagram()
{
auto pNetChan = static_cast<CNetChannel*>(I::EngineClient->GetNetChannelInfo());
if (!pNetChan)
return;
if (pNetChan->m_nInSequenceNr > iLastInSequence)
{
iLastInSequence = pNetChan->m_nInSequenceNr;
dSequences.push_front(CIncomingSequence(pNetChan->m_nInReliableState, pNetChan->m_nInSequenceNr, I::GlobalVars->realtime));
}
if (dSequences.size() > 2048)
dSequences.pop_back();
}
bool CBacktrack::WithinRewind(const TickRecord& record)
{
auto pNetChan = I::EngineClient->GetNetChannelInfo();
if (!pNetChan)
return false;
const float flCorrect = std::clamp(pNetChan->GetLatency(FLOW_OUTGOING) + ROUND_TO_TICKS(flFakeInterp) + GetFake(), 0.f, flMaxUnlag) - pNetChan->GetLatency(FLOW_OUTGOING);
const int iServerTick = iTickCount + (Vars::Misc::Game::NetworkFix.Value ? 1 : 0) + G::AnticipatedChoke + Vars::Backtrack::Offset.Value;
const float flDelta = flCorrect - TICKS_TO_TIME(iServerTick - TIME_TO_TICKS(record.flSimTime));
return fabsf(flDelta) < float(Vars::Backtrack::Window.Value) / 1000;
}
std::deque<TickRecord>* CBacktrack::GetRecords(CBaseEntity* pEntity)
{
if (mRecords[pEntity].empty())
return nullptr;
return &mRecords[pEntity];
}
std::deque<TickRecord> CBacktrack::GetValidRecords(std::deque<TickRecord>* pRecords, CTFPlayer* pLocal, bool bDistance)
{
std::deque<TickRecord> validRecords = {};
if (!pRecords)
return validRecords;
for (auto& pTick : *pRecords)
{
if (!WithinRewind(pTick))
continue;
validRecords.push_back(pTick);
}
if (pLocal)
{
if (bDistance)
std::sort(validRecords.begin(), validRecords.end(), [&](const TickRecord& a, const TickRecord& b) -> bool
{
if (Vars::Backtrack::PreferOnShot.Value && a.bOnShot != b.bOnShot)
return a.bOnShot > b.bOnShot;
return pLocal->m_vecOrigin().DistTo(a.vOrigin) < pLocal->m_vecOrigin().DistTo(b.vOrigin);
});
else
{
auto pNetChan = I::EngineClient->GetNetChannelInfo();
if (!pNetChan)
return validRecords;
const float flCorrect = std::clamp(pNetChan->GetLatency(FLOW_OUTGOING) + ROUND_TO_TICKS(flFakeInterp) + GetFake(), 0.f, flMaxUnlag) - pNetChan->GetLatency(FLOW_OUTGOING);
const int iServerTick = iTickCount + (Vars::Misc::Game::NetworkFix.Value ? 1 : 0) + G::AnticipatedChoke + Vars::Backtrack::Offset.Value;
std::sort(validRecords.begin(), validRecords.end(), [&](const TickRecord& a, const TickRecord& b) -> bool
{
if (Vars::Backtrack::PreferOnShot.Value && a.bOnShot != b.bOnShot)
return a.bOnShot > b.bOnShot;
const float flADelta = flCorrect - TICKS_TO_TIME(iServerTick - TIME_TO_TICKS(a.flSimTime));
const float flBDelta = flCorrect - TICKS_TO_TIME(iServerTick - TIME_TO_TICKS(b.flSimTime));
return fabsf(flADelta) < fabsf(flBDelta);
});
}
}
return validRecords;
}
void CBacktrack::StoreNolerp()
{
for (auto& pEntity : H::Entities.GetGroup(EGroupType::PLAYERS_ALL))
{
if (pEntity->entindex() == I::EngineClient->GetLocalPlayer())
continue;
// more of a placeholder, still interpolated iirc
bSettingUpBones = true;
mBones[pEntity].first = pEntity->SetupBones(mBones[pEntity].second, 128, BONE_USED_BY_ANYTHING, pEntity->m_flSimulationTime());
bSettingUpBones = false;
mEyeAngles[pEntity] = pEntity->As<CTFPlayer>()->GetEyeAngles();
}
}
void CBacktrack::MakeRecords()
{
if (iLastCreationTick == I::GlobalVars->tickcount)
return;
iLastCreationTick = I::GlobalVars->tickcount;
for (auto& pEntity : H::Entities.GetGroup(EGroupType::PLAYERS_ALL))
{
if (pEntity->entindex() == I::EngineClient->GetLocalPlayer() || !mBones[pEntity].first)
continue;
const float flSimTime = pEntity->m_flSimulationTime(), flOldSimTime = pEntity->m_flOldSimulationTime();
if (TIME_TO_TICKS(flSimTime - flOldSimTime) <= 0)
continue;
const TickRecord curRecord = {
flSimTime,
I::GlobalVars->curtime,
I::GlobalVars->tickcount,
mDidShoot[pEntity->entindex()],
*reinterpret_cast<BoneMatrixes*>(&mBones[pEntity].second),
pEntity->m_vecOrigin()
};
bool bLagComp = false;
if (!mRecords[pEntity].empty()) // check for lagcomp breaking here
{
const Vec3 vDelta = curRecord.vOrigin - mRecords[pEntity].front().vOrigin;
static auto sv_lagcompensation_teleport_dist = U::ConVars.FindVar("sv_lagcompensation_teleport_dist");
const float flDist = powf(sv_lagcompensation_teleport_dist ? sv_lagcompensation_teleport_dist->GetFloat() : 64.f, 2.f);
if (vDelta.Length2DSqr() > flDist)
{
bLagComp = true;
for (auto& pRecord : mRecords[pEntity])
pRecord.bInvalid = true;
}
for (auto& pRecord : mRecords[pEntity])
{
if (!pRecord.bInvalid)
continue;
pRecord.bOnShot = curRecord.bOnShot;
pRecord.BoneMatrix = curRecord.BoneMatrix;
pRecord.vOrigin = curRecord.vOrigin;
}
}
mRecords[pEntity].push_front(curRecord);
mLagCompensation[pEntity] = bLagComp;
mDidShoot[pEntity->entindex()] = false;
}
}
void CBacktrack::CleanRecords()
{
for (auto& pEntity : H::Entities.GetGroup(EGroupType::PLAYERS_ALL))
{
auto pPlayer = pEntity->As<CTFPlayer>();
if (pEntity->entindex() == I::EngineClient->GetLocalPlayer())
continue;
if (!pEntity->IsPlayer() || pEntity->IsDormant() || !pPlayer->IsAlive() || pPlayer->IsAGhost())
{
mRecords[pEntity].clear();
continue;
}
//const int iOldSize = pRecords.size();
const int flDeadtime = I::GlobalVars->curtime + GetReal() - flMaxUnlag; // int ???
while (!mRecords[pEntity].empty())
{
if (mRecords[pEntity].back().flSimTime >= flDeadtime)
break;
mRecords[pEntity].pop_back();
}
//const int iNewSize = pRecords.size();
//if (iOldSize != iNewSize)
// SDK::Output("Clear", std::format("{} -> {}", iOldSize, iNewSize).c_str(), { 255, 0, 200, 255 }, Vars::Debug::Logging.Value);
}
}
void CBacktrack::FrameStageNotify()
{
UpdateDatagram();
if (!I::EngineClient->IsInGame())
return Restart();
static auto sv_maxunlag = U::ConVars.FindVar("sv_maxunlag");
flMaxUnlag = sv_maxunlag ? sv_maxunlag->GetFloat() : 1.f;
StoreNolerp();
MakeRecords();
CleanRecords();
}
void CBacktrack::Run(CUserCmd* pCmd)
{
SendLerp();
// might not even be necessary
G::AnticipatedChoke = 0;
if (G::ShiftedTicks != G::MaxShift && G::WeaponType != EWeaponType::HITSCAN && Vars::Aimbot::General::AimType.Value == 3)
G::AnticipatedChoke = 1;
if (G::ChokeAmount && !Vars::CL_Move::Fakelag::UnchokeOnAttack.Value && G::ShiftedTicks == G::ShiftedGoal && !G::DoubleTap)
G::AnticipatedChoke = G::ChokeGoal - G::ChokeAmount; // iffy, unsure if there is a good way to get it to work well without unchoking
}
void CBacktrack::ResolverUpdate(CBaseEntity* pEntity)
{
mRecords[pEntity].clear(); // TODO: eventually remake records and rotate them or smthn idk, maybe just rotate them
}
void CBacktrack::ReportShot(int iIndex)
{
if (!Vars::Backtrack::PreferOnShot.Value)
return;
auto pEntity = I::ClientEntityList->GetClientEntity(iIndex);
if (!pEntity || SDK::GetWeaponType(pEntity->As<CTFPlayer>()->m_hActiveWeapon().Get()->As<CTFWeaponBase>()) != EWeaponType::HITSCAN)
return;
mDidShoot[pEntity->entindex()] = true;
}
// Adjusts the fake latency ping
void CBacktrack::AdjustPing(CNetChannel* netChannel)
{
for (const auto& cSequence : dSequences)
{
if (I::GlobalVars->realtime - cSequence.CurTime >= GetFake())
{
netChannel->m_nInReliableState = cSequence.InReliableState;
netChannel->m_nInSequenceNr = cSequence.SequenceNr;
break;
}
}
}

View File

@ -0,0 +1,89 @@
#pragma once
#include "../../SDK/SDK.h"
#pragma warning ( disable : 4091 )
class CIncomingSequence
{
public:
int InReliableState;
int SequenceNr;
float CurTime;
CIncomingSequence(int inState, int seqNr, float time)
{
InReliableState = inState;
SequenceNr = seqNr;
CurTime = time;
}
};
using BoneMatrixes = struct
{
float BoneMatrix[128][3][4];
};
struct TickRecord
{
float flSimTime = 0.f;
float flCreateTime = 0.f;
int iTickCount = 0;
bool bOnShot = false;
BoneMatrixes BoneMatrix{};
Vec3 vOrigin = {};
bool bInvalid = false;
};
class CBacktrack
{
// logic
bool WithinRewind(const TickRecord& record);
// utils
void SendLerp();
void UpdateDatagram();
void StoreNolerp();
void MakeRecords();
void CleanRecords();
// data
std::unordered_map<int, bool> mDidShoot;
int iLastCreationTick = 0;
// data - fake latency
std::deque<CIncomingSequence> dSequences;
int iLastInSequence = 0;
bool bLastTickHeld = false;
public:
float GetLerp();
float GetFake();
float GetReal(int iFlow = -1);
std::deque<TickRecord>* GetRecords(CBaseEntity* pEntity);
std::deque<TickRecord> GetValidRecords(std::deque<TickRecord>* pRecords, CTFPlayer* pLocal = nullptr, bool bDistance = false);
void Restart();
void FrameStageNotify();
void Run(CUserCmd* pCmd);
void SetLerp(IGameEvent* pEvent);
void ResolverUpdate(CBaseEntity* pEntity);
void ReportShot(int iIndex);
void AdjustPing(CNetChannel* netChannel);
bool bFakeLatency = false;
float flWishInterp = 0.015f;
float flFakeInterp = 0.015f;
std::unordered_map<CBaseEntity*, std::deque<TickRecord>> mRecords;
std::unordered_map<CBaseEntity*, std::pair<int, matrix3x4[128]>> mBones;
std::unordered_map<CBaseEntity*, Vec3> mEyeAngles;
std::unordered_map<CBaseEntity*, bool> mLagCompensation;
bool bSettingUpBones = false;
int iTickCount = 0;
float flMaxUnlag = 1.f;
};
ADD_FEATURE(CBacktrack, Backtrack)

View File

@ -0,0 +1,70 @@
#include "CameraWindow.h"
void CCameraWindow::Init()
{
// Create camera texture
CameraTex = I::MaterialSystem->CreateNamedRenderTargetTextureEx("mirrorcam_rt", 1, 1, RT_SIZE_FULL_FRAME_BUFFER, IMAGE_FORMAT_RGB888, MATERIAL_RT_DEPTH_SHARED, TEXTUREFLAGS_CLAMPS | TEXTUREFLAGS_CLAMPT, CREATERENDERTARGETFLAGS_HDR);
// Create camera material
static auto* kv = new KeyValues("UnlitGeneric");
kv->SetString("$basetexture", "mirrorcam_rt");
CameraMat = I::MaterialSystem->CreateMaterial("m_cameraMat", kv);
}
// Draws camera to the screen
void CCameraWindow::Draw()
{
if (!ShouldDraw || !CameraMat || !I::EngineClient->IsInGame())
return;
const WindowBox_t& info = Vars::Visuals::Simulation::ProjectileWindow.Value;
// Draw to screen
const auto renderCtx = I::MaterialSystem->GetRenderContext();
renderCtx->DrawScreenSpaceRectangle(
CameraMat,
info.x, info.y, info.w, info.h,
0, 0, info.w, info.h,
CameraTex->GetActualWidth(), CameraTex->GetActualHeight(),
nullptr, 1, 1
);
renderCtx->Release();
}
// Renders another view onto a texture
void CCameraWindow::RenderView(void* ecx, const CViewSetup& pViewSetup)
{
if (!ShouldDraw || !CameraTex)
return;
const WindowBox_t& info = Vars::Visuals::Simulation::ProjectileWindow.Value;
CViewSetup viewSetup = pViewSetup;
viewSetup.x = 0;
viewSetup.y = 0;
viewSetup.origin = CameraOrigin;
viewSetup.angles = CameraAngles;
viewSetup.width = info.w + 1;
viewSetup.height = info.h + 1;
viewSetup.m_flAspectRatio = static_cast<float>(viewSetup.width) / static_cast<float>(viewSetup.height);
viewSetup.fov = 90;
RenderCustomView(ecx, viewSetup, CameraTex);
}
void CCameraWindow::RenderCustomView(void* ecx, const CViewSetup& pViewSetup, ITexture* pTexture)
{
const auto renderCtx = I::MaterialSystem->GetRenderContext();
renderCtx->PushRenderTargetAndViewport();
renderCtx->SetRenderTarget(pTexture);
static auto ViewRender_RenderView = U::Hooks.m_mHooks["ViewRender_RenderView"];
if (ViewRender_RenderView)
ViewRender_RenderView->Original<void(__fastcall*)(void*, const CViewSetup&, int, int)>()(ecx, pViewSetup, VIEW_CLEAR_COLOR | VIEW_CLEAR_DEPTH, RENDERVIEW_UNSPECIFIED);
renderCtx->PopRenderTargetAndViewport();
renderCtx->Release();
}

View File

@ -0,0 +1,21 @@
#pragma once
#include "../../SDK/SDK.h"
using RenderViewFN = void(__fastcall*)(void* ecx, const CViewSetup& view, ClearFlags_t nClearFlags, RenderViewInfo_t whatToDraw);
class CCameraWindow
{
public:
IMaterial* CameraMat;
ITexture* CameraTex;
Vec3 CameraOrigin;
Vec3 CameraAngles;
bool ShouldDraw = false;
void Init();
void Draw();
void RenderView(void* ecx, const CViewSetup& pViewSetup);
void RenderCustomView(void* ecx, const CViewSetup& pViewSetup, ITexture* pTexture);
};
ADD_FEATURE(CCameraWindow, CameraWindow)

View File

@ -0,0 +1,197 @@
#include "CheaterDetection.h"
#include "../Players/PlayerUtils.h"
#include "../Logs/Logs.h"
bool CCheaterDetection::ShouldScan()
{
if (!Vars::CheaterDetection::Methods.Value || I::EngineClient->IsPlayingTimeDemo())
return false;
static float flOldTime = I::GlobalVars->curtime;
const float flCurTime = I::GlobalVars->curtime;
const bool bShouldSkip = TIME_TO_TICKS(flCurTime - flOldTime) != 1;
flOldTime = flCurTime;
if (bShouldSkip)
return false;
auto pNetChan = I::EngineClient->GetNetChannelInfo();
if (pNetChan && (pNetChan->GetTimeSinceLastReceived() > TICK_INTERVAL * 2 || pNetChan->IsTimingOut()))
return false;
return true;
}
bool CCheaterDetection::InvalidPitch(CTFPlayer* pEntity)
{
return Vars::CheaterDetection::Methods.Value & (1 << 0) && fabsf(pEntity->m_angEyeAnglesX()) > 89.9f;
}
bool CCheaterDetection::IsChoking(CTFPlayer* pEntity)
{
const bool bReturn = mData[pEntity].bChoke;
mData[pEntity].bChoke = false;
return Vars::CheaterDetection::Methods.Value & (1 << 1) && bReturn;
}
bool CCheaterDetection::IsFlicking(CTFPlayer* pEntity) // this is aggravating
{
auto& vAngles = mData[pEntity].vAngles;
if (!(Vars::CheaterDetection::Methods.Value & (1 << 2)))
{
vAngles.clear();
return false;
}
if (vAngles.size() != 3 || !vAngles[0].second && !vAngles[1].second && !vAngles[2].second)
return false;
if (Math::CalcFov(vAngles[0].first, vAngles[1].first) < Vars::CheaterDetection::MinimumFlick.Value)
return false;
if (Math::CalcFov(vAngles[0].first, vAngles[2].first) > Vars::CheaterDetection::MaximumNoise.Value * (TICK_INTERVAL / 0.015f))
return false;
vAngles.clear();
return true;
}
bool CCheaterDetection::IsDuckSpeed(CTFPlayer* pEntity)
{
if (!(Vars::CheaterDetection::Methods.Value & (1 << 3))
|| !pEntity->IsDucking() || !pEntity->OnSolid() // this may break on movement sim
|| pEntity->m_vecVelocity().Length2D() < pEntity->m_flMaxspeed() * 0.5f)
{
mData[pEntity].iDuckSpeed = 0;
return false;
}
mData[pEntity].iDuckSpeed++;
if (mData[pEntity].iDuckSpeed > 20)
{
mData[pEntity].iDuckSpeed = 0;
return true;
}
return false;
}
void CCheaterDetection::Infract(CTFPlayer* pEntity, std::string sReason)
{
mData[pEntity].iDetections++;
const bool bMark = mData[pEntity].iDetections >= Vars::CheaterDetection::DetectionsRequired.Value;
F::Logs.CheatDetection(mData[pEntity].sName, bMark ? "marked" : "infracted", sReason);
if (bMark)
{
mData[pEntity].iDetections = 0;
F::PlayerUtils.AddTag(mData[pEntity].friendsID, "Cheater", true, mData[pEntity].sName);
}
}
void CCheaterDetection::Run()
{
if (!ShouldScan() || !I::EngineClient->IsConnected())
return;
for (auto& pEntity : H::Entities.GetGroup(EGroupType::PLAYERS_ALL))
{
auto pPlayer = pEntity->As<CTFPlayer>();
if (!mData[pPlayer].bShouldScan)
continue;
mData[pPlayer].bShouldScan = false;
if (InvalidPitch(pPlayer))
Infract(pPlayer, "invalid pitch");
if (IsChoking(pPlayer))
Infract(pPlayer, "choking packets");
if (IsFlicking(pPlayer))
Infract(pPlayer, "flicking");
if (IsDuckSpeed(pPlayer))
Infract(pPlayer, "duck speed");
}
}
void CCheaterDetection::Fill() // maybe just run here
{
if (!Vars::CheaterDetection::Methods.Value || I::EngineClient->IsPlayingTimeDemo())
return;
for (auto& pEntity : H::Entities.GetGroup(EGroupType::PLAYERS_ALL))
{
auto pPlayer = pEntity->As<CTFPlayer>();
mData[pPlayer].bShouldScan = false;
PlayerInfo_t pi{};
if (pPlayer->entindex() == I::EngineClient->GetLocalPlayer() || !pPlayer->IsAlive() || pPlayer->IsAGhost() || pPlayer->IsDormant()
|| !I::EngineClient->GetPlayerInfo(pPlayer->entindex(), &pi) || pi.fakeplayer || F::PlayerUtils.HasTag(pi.friendsID, "Cheater"))
{
mData[pPlayer].vChokes.clear();
mData[pPlayer].bChoke = false;
mData[pPlayer].vAngles.clear();
mData[pPlayer].iDuckSpeed = 0;
continue;
}
if (pPlayer->m_flSimulationTime() == pPlayer->m_flOldSimulationTime())
continue;
mData[pPlayer].bShouldScan = true;
mData[pPlayer].friendsID = pi.friendsID;
mData[pPlayer].sName = pi.name;
mData[pPlayer].vAngles.push_back({ pPlayer->GetEyeAngles(), mData[pPlayer].bDamage });
mData[pPlayer].bDamage = false;
if (mData[pPlayer].vAngles.size() > 3)
mData[pPlayer].vAngles.pop_front();
}
}
void CCheaterDetection::Reset()
{
mData.clear();
}
void CCheaterDetection::ReportChoke(CTFPlayer* pEntity, int iChoke)
{
if (Vars::CheaterDetection::Methods.Value & (1 << 1))
{
mData[pEntity].vChokes.push_back(iChoke);
if (mData[pEntity].vChokes.size() == 3)
{
mData[pEntity].bChoke = true; // check for last 3 choke amounts
for (auto& iChoke : mData[pEntity].vChokes)
{
if (iChoke < Vars::CheaterDetection::MinimumChoking.Value)
mData[pEntity].bChoke = false;
}
mData[pEntity].vChokes.clear();
}
}
else
mData[pEntity].vChokes.clear();
}
void CCheaterDetection::ReportDamage(IGameEvent* pEvent)
{
if (!(Vars::CheaterDetection::Methods.Value & (1 << 2)))
return;
const int iIndex = I::EngineClient->GetPlayerForUserID(pEvent->GetInt("userid"));
if (iIndex == I::EngineClient->GetLocalPlayer())
return;
auto pEntity = I::ClientEntityList->GetClientEntity(iIndex);
if (!pEntity || pEntity->IsDormant())
return;
switch (SDK::GetWeaponType(pEntity->As<CTFPlayer>()->m_hActiveWeapon().Get()->As<CTFWeaponBase>()))
{
case EWeaponType::UNKNOWN:
case EWeaponType::PROJECTILE:
return;
}
mData[pEntity->As<CTFPlayer>()].bDamage = true;
}

View File

@ -0,0 +1,42 @@
#pragma once
#include "../../SDK/SDK.h"
#include "../Backtrack/Backtrack.h"
struct PlayerInfo
{
bool bShouldScan = false;
uint32_t friendsID = 0;
std::string sName = "";
int iDetections = 0;
std::deque<int> vChokes = {}; // store last 3 choke counts
bool bChoke = false; // infract the user for choking?
std::deque<std::pair<Vec3, bool>> vAngles = {}; // store last 3 angles & if damage was dealt
bool bDamage = false;
int iDuckSpeed = 0; // how many times in a row a user has been detected for duck speed
};
class CCheaterDetection
{
bool ShouldScan();
bool InvalidPitch(CTFPlayer* pEntity);
bool IsChoking(CTFPlayer* pEntity);
bool IsFlicking(CTFPlayer* pEntity);
bool IsDuckSpeed(CTFPlayer* pEntity);
void Infract(CTFPlayer* pEntity, std::string sReason);
std::unordered_map<CTFPlayer*, PlayerInfo> mData;
public:
void Run();
void Fill();
void ReportChoke(CTFPlayer* pEntity, int iChoke);
void ReportDamage(IGameEvent* pEvent);
void Reset();
};
ADD_FEATURE(CCheaterDetection, CheaterDetection)

View File

@ -0,0 +1,83 @@
#include "Commands.h"
#include "../../Core/Core.h"
#include "../ImGui/Menu/Menu.h"
#include <utility>
#include <boost/algorithm/string/replace.hpp>
#include <boost/algorithm/string/join.hpp>
bool CCommands::Run(const std::string& cmd, std::deque<std::string>& args)
{
if (!CommandMap.contains(cmd))
return false;
CommandMap[cmd](args);
return true;
}
void CCommands::Register(const std::string& name, CommandCallback callback)
{
CommandMap[name] = std::move(callback);
}
void CCommands::Initialize()
{
Register("queue", [](const std::deque<std::string>& args)
{
I::TFPartyClient->LoadSavedCasualCriteria();
I::TFPartyClient->RequestQueueForMatch(k_eTFMatchGroup_Casual_Default);
});
Register("setcvar", [](std::deque<std::string> args)
{
// Check if the user provided at least 2 args
if (args.size() < 2)
{
I::CVar->ConsoleColorPrintf({ 255, 255, 255, 255 }, "Usage: setcvar <cvar> <value>\n");
return;
}
// Find the given CVar
const auto foundCVar = I::CVar->FindVar(args[0].c_str());
const std::string cvarName = args[0];
if (!foundCVar)
{
I::CVar->ConsoleColorPrintf({ 255, 255, 255, 255 }, "Could not find %s\n", cvarName.c_str());
return;
}
// Set the CVar to the given value
args.pop_front();
std::string newValue = boost::algorithm::join(args, " ");
boost::replace_all(newValue, "\"", "");
foundCVar->SetValue(newValue.c_str());
I::CVar->ConsoleColorPrintf({ 255, 255, 255, 255 }, "Set %s to: %s\n", cvarName.c_str(), newValue.c_str());
});
Register("getcvar", [](std::deque<std::string> args)
{
// Check if the user provided 1 arg
if (args.size() != 1)
{
I::CVar->ConsoleColorPrintf({ 255, 255, 255, 255 }, "Usage: getcvar <cvar>\n");
return;
}
const auto foundCVar = I::CVar->FindVar(args[0].c_str());
const std::string cvarName = args[0];
if (!foundCVar)
{
I::CVar->ConsoleColorPrintf({ 255, 255, 255, 255 }, "Could not find %s\n", cvarName.c_str());
return;
}
I::CVar->ConsoleColorPrintf({ 255, 255, 255, 255 }, "Value of %s is: %s\n", cvarName.c_str(), foundCVar->GetString());
});
Register("unload", [](std::deque<std::string> args)
{
if (F::Menu.IsOpen)
I::MatSystemSurface->SetCursorAlwaysVisible(F::Menu.IsOpen = false);
U::Core.bUnload = true;
});
}

View File

@ -0,0 +1,18 @@
#pragma once
#include "../../SDK/SDK.h"
#include <functional>
using CommandCallback = std::function<void(std::deque<std::string>)>;
class CCommands
{
private:
std::unordered_map<std::string, CommandCallback> CommandMap;
public:
void Initialize();
bool Run(const std::string& cmd, std::deque<std::string>& args);
void Register(const std::string& name, CommandCallback callback);
};
ADD_FEATURE(CCommands, Commands)

View File

@ -0,0 +1,205 @@
#include "Conditions.h"
#include <functional>
#define IsType(type) var->m_iType == typeid(type).hash_code()
#define SetType(type, cond)\
{\
if (var->GetVar<type>()->Map.contains(cond))\
var->GetVar<type>()->Value = var->GetVar<type>()->Map[cond];\
}
#define SetT(type, cond) if (IsType(type)) SetType(type, cond)
void CConditions::Run(CTFPlayer* pLocal, CTFWeaponBase* pWeapon)
{
if (G::Unload)
return;
auto setVars = [](std::string sCond)
{
const bool bDefault = FNV1A::Hash(sCond.c_str()) == FNV1A::HashConst("default");
for (const auto var : g_Vars)
{
if (var->m_iFlags & (NOSAVE | NOCOND) && !bDefault)
continue;
SetT(bool, sCond)
else SetT(int, sCond)
else SetT(float, sCond)
else SetT(IntRange_t, sCond)
else SetT(FloatRange_t, sCond)
else SetT(std::string, sCond)
else SetT(std::vector<std::string>, sCond)
else SetT(Color_t, sCond)
else SetT(Gradient_t, sCond)
else SetT(Vec3, sCond)
else SetT(DragBox_t, sCond)
else SetT(WindowBox_t, sCond)
}
};
setVars("default");
std::function<void(std::string)> getConds = [&](std::string sParent)
{
auto uHash = FNV1A::Hash(sParent.c_str());
for (auto& sCond : vConditions)
{
auto& tCond = mConditions[sCond];
if (uHash != FNV1A::Hash(tCond.Parent.c_str()))
continue;
switch (tCond.Type)
{
// key
case 0:
{
bool bKey = false;
switch (tCond.Info)
{
case 0: bKey = U::KeyHandler.Down(tCond.Key, true, &tCond.Storage); break;
case 1: bKey = U::KeyHandler.Pressed(tCond.Key, true, &tCond.Storage); break;
case 2: bKey = U::KeyHandler.Double(tCond.Key, true, &tCond.Storage); break;
}
const bool bUIOpen = I::EngineVGui->IsGameUIVisible() || I::MatSystemSurface->IsCursorVisible();
bKey = !bUIOpen && bKey;
if (tCond.Not)
bKey = !bKey;
switch (tCond.Info)
{
case 0: tCond.Active = bKey; break;
case 1:
case 2: if (bKey) tCond.Active = !tCond.Active;
}
break;
}
// class
case 1:
{
const int iClass = pLocal ? pLocal->m_iClass() : 0;
switch (tCond.Info)
{
case 0: { tCond.Active = iClass == 1; break; }
case 1: { tCond.Active = iClass == 3; break; }
case 2: { tCond.Active = iClass == 7; break; }
case 3: { tCond.Active = iClass == 4; break; }
case 4: { tCond.Active = iClass == 6; break; }
case 5: { tCond.Active = iClass == 9; break; }
case 6: { tCond.Active = iClass == 5; break; }
case 7: { tCond.Active = iClass == 2; break; }
case 8: { tCond.Active = iClass == 8; break; }
}
if (tCond.Not)
tCond.Active = !tCond.Active;
break;
}
// weapon type
case 2:
{
tCond.Active = tCond.Info + 1 == int(SDK::GetWeaponType(pWeapon));
if (tCond.Not)
tCond.Active = !tCond.Active;
}
}
if (tCond.Active)
{
setVars(sCond);
getConds(sCond);
}
}
};
getConds("");
}
bool CConditions::HasChildren(std::string sCondition)
{
auto uHash = FNV1A::Hash(sCondition.c_str());
auto it = std::ranges::find_if(vConditions, [this, uHash](const auto& sCond) { return uHash == FNV1A::Hash(mConditions[sCond].Parent.c_str()); });
return it != vConditions.end();
}
std::string CConditions::GetParent(std::string sCondition)
{
if (mConditions.contains(sCondition) && mConditions[sCondition].Parent.length())
return mConditions[sCondition].Parent;
return "default";
}
void CConditions::AddCondition(std::string sCondition, Condition_t tCond)
{
if (!mConditions.contains(sCondition))
vConditions.push_back(sCondition);
mConditions[sCondition] = tCond;
}
// fun!
#define RemoveType(type, cond)\
{\
if (var->GetVar<type>()->Map.contains(cond))\
{\
auto uHash = FNV1A::Hash(cond.c_str());\
for (auto it = var->GetVar<type>()->Map.begin(); it != var->GetVar<type>()->Map.end();)\
{\
if (uHash == FNV1A::Hash(it->first.c_str()))\
it = var->GetVar<type>()->Map.erase(it);\
else\
++it;\
}\
}\
}
#define RemoveT(type, cond) if (IsType(type)) RemoveType(type, cond)
void CConditions::RemoveCondition(std::string sCondition)
{
for (const auto var : g_Vars)
{
RemoveT(bool, sCondition)
else RemoveT(int, sCondition)
else RemoveT(float, sCondition)
else RemoveT(IntRange_t, sCondition)
else RemoveT(FloatRange_t, sCondition)
else RemoveT(std::string, sCondition)
else RemoveT(std::vector<std::string>, sCondition)
else RemoveT(Color_t, sCondition)
else RemoveT(Gradient_t, sCondition)
else RemoveT(Vec3, sCondition)
else RemoveT(DragBox_t, sCondition)
else RemoveT(WindowBox_t, sCondition)
}
auto removeCond = [&](std::string sCond)
{
auto uHash = FNV1A::Hash(sCond.c_str());
for (auto it = vConditions.begin(); it != vConditions.end();)
{
if (uHash == FNV1A::Hash(it->c_str()))
it = vConditions.erase(it);
else
++it;
}
for (auto it = mConditions.begin(); it != mConditions.end();)
{
if (uHash == FNV1A::Hash(it->first.c_str()))
it = mConditions.erase(it);
else
++it;
}
};
removeCond(sCondition);
std::function<void(std::string)> removeChildren = [&](std::string sParent)
{
auto uHash = FNV1A::Hash(sParent.c_str());
for (auto& sCond : vConditions)
{
auto& cCond = mConditions[sCond];
if (uHash != FNV1A::Hash(cCond.Parent.c_str()))
continue;
removeCond(sCond);
removeChildren(sCond);
}
};
removeChildren(sCondition);
}

View File

@ -0,0 +1,34 @@
#pragma once
#include "../../SDK/SDK.h"
struct Condition_t
{
int Type = 0; // Key, Class, Weapon type
int Info = 0; // Key: Hold, Toggle, Double click
// Class: Scout, Soldier, Pyro, Demoman, Heavy, Engineer, Medic, Sniper, Spy
// Weapon type: Hitscan, Projectile, Melee
int Key = 0;
bool Not = false;
bool Active = false;
bool Visible = true;
KeyStorage Storage = {};
std::string Parent = "";
};
class CConditions
{
public:
void Run(CTFPlayer* pLocal, CTFWeaponBase* pWeapon);
bool HasChildren(std::string sCondition);
std::string GetParent(std::string sCondition);
void AddCondition(std::string sCondition, Condition_t tCond);
void RemoveCondition(std::string sCondition);
std::unordered_map<std::string, Condition_t> mConditions = {};
std::vector<std::string> vConditions = {}; // retain order
};
ADD_FEATURE(CConditions, Conditions)

View File

@ -0,0 +1,540 @@
#include "Configs.h"
#include "../Conditions/Conditions.h"
#include "../Visuals/Notifications/Notifications.h"
#include "../Visuals/Materials/Materials.h"
boost::property_tree::ptree CConfigs::ColorToTree(const Color_t& color)
{
boost::property_tree::ptree colorTree;
colorTree.put("r", color.r);
colorTree.put("g", color.g);
colorTree.put("b", color.b);
colorTree.put("a", color.a);
return colorTree;
}
void CConfigs::TreeToColor(const boost::property_tree::ptree& tree, Color_t& out)
{
if (auto v = tree.get_optional<byte>("r")) { out.r = *v; }
if (auto v = tree.get_optional<byte>("g")) { out.g = *v; }
if (auto v = tree.get_optional<byte>("b")) { out.b = *v; }
if (auto v = tree.get_optional<byte>("a")) { out.a = *v; }
}
void CConfigs::SaveJson(boost::property_tree::ptree& mapTree, const char* name, bool val)
{
mapTree.put(name, val);
}
void CConfigs::SaveJson(boost::property_tree::ptree& mapTree, const char* name, int val)
{
mapTree.put(name, val);
}
void CConfigs::SaveJson(boost::property_tree::ptree& mapTree, const char* name, float val)
{
mapTree.put(name, val);
}
void CConfigs::SaveJson(boost::property_tree::ptree& mapTree, const char* name, const IntRange_t& val)
{
boost::property_tree::ptree rangeTree;
rangeTree.put("Min", val.Min);
rangeTree.put("Max", val.Max);
mapTree.put_child(name, rangeTree);
}
void CConfigs::SaveJson(boost::property_tree::ptree& mapTree, const char* name, const FloatRange_t& val)
{
boost::property_tree::ptree rangeTree;
rangeTree.put("Min", val.Min);
rangeTree.put("Max", val.Max);
mapTree.put_child(name, rangeTree);
}
void CConfigs::SaveJson(boost::property_tree::ptree& mapTree, const char* name, const std::string& val)
{
mapTree.put(name, val);
}
void CConfigs::SaveJson(boost::property_tree::ptree& mapTree, const char* name, const std::vector<std::string>& val)
{
boost::property_tree::ptree vectorTree;
for (const auto& sMat : val)
{
boost::property_tree::ptree child; child.put("", sMat);
vectorTree.push_back(std::make_pair("", child));
}
mapTree.put_child(name, vectorTree);
}
void CConfigs::SaveJson(boost::property_tree::ptree& mapTree, const char* name, const Color_t& val)
{
mapTree.put_child(name, ColorToTree(val));
}
void CConfigs::SaveJson(boost::property_tree::ptree& mapTree, const char* name, const Gradient_t& val)
{
boost::property_tree::ptree gradientTree;
gradientTree.put_child("StartColor", ColorToTree(val.StartColor));
gradientTree.put_child("EndColor", ColorToTree(val.EndColor));
mapTree.put_child(name, gradientTree);
}
void CConfigs::SaveJson(boost::property_tree::ptree& mapTree, const char* name, const DragBox_t& val)
{
boost::property_tree::ptree dragBoxTree;
dragBoxTree.put("x", val.x);
dragBoxTree.put("y", val.y);
mapTree.put_child(name, dragBoxTree);
}
void CConfigs::SaveJson(boost::property_tree::ptree& mapTree, const char* name, const WindowBox_t& val)
{
boost::property_tree::ptree dragBoxTree;
dragBoxTree.put("x", val.x);
dragBoxTree.put("y", val.y);
dragBoxTree.put("w", val.w);
dragBoxTree.put("h", val.h);
mapTree.put_child(name, dragBoxTree);
}
void CConfigs::LoadJson(boost::property_tree::ptree& mapTree, const char* name, bool& val)
{
if (auto getValue = mapTree.get_optional<bool>(name))
{
val = *getValue;
}
}
void CConfigs::LoadJson(boost::property_tree::ptree& mapTree, const char* name, int& val)
{
if (auto getValue = mapTree.get_optional<int>(name))
{
val = *getValue;
}
}
void CConfigs::LoadJson(boost::property_tree::ptree& mapTree, const char* name, float& val)
{
if (auto getValue = mapTree.get_optional<float>(name))
{
val = *getValue;
}
}
void CConfigs::LoadJson(boost::property_tree::ptree& mapTree, const char* name, IntRange_t& val)
{
if (const auto getChild = mapTree.get_child_optional(name))
{
if (auto getValue = getChild->get_optional<int>("Min")) { val.Min = *getValue; }
if (auto getValue = getChild->get_optional<int>("Max")) { val.Max = *getValue; }
}
}
void CConfigs::LoadJson(boost::property_tree::ptree& mapTree, const char* name, FloatRange_t& val)
{
if (const auto getChild = mapTree.get_child_optional(name))
{
if (auto getValue = getChild->get_optional<int>("Min")) { val.Min = *getValue; }
if (auto getValue = getChild->get_optional<int>("Max")) { val.Max = *getValue; }
}
}
void CConfigs::LoadJson(boost::property_tree::ptree& mapTree, const char* name, std::string& val)
{
if (auto getValue = mapTree.get_optional<std::string>(name))
{
val = *getValue;
}
}
void CConfigs::LoadJson(boost::property_tree::ptree& mapTree, const char* name, std::vector<std::string>& val)
{
auto getMaterials = [](std::vector<std::string>& val, const boost::optional<boost::property_tree::ptree&> getVector)
{
if (!getVector)
return;
val.clear();
for (auto& [_, mat] : *getVector)
{
std::string sMat = mat.data();
bool bFound = false; // ensure no duplicates are assigned
for (auto& str : val)
{
if (str == sMat)
{
bFound = true;
break;
}
}
if (!bFound)
val.push_back(mat.data());
}
// remove invalid materials
for (auto it = val.begin(); it != val.end();)
{
if (FNV1A::Hash(it->c_str()) == FNV1A::HashConst("None") || FNV1A::Hash(it->c_str()) != FNV1A::HashConst("Original") && !F::Materials.mChamMaterials.contains(*it))
it = val.erase(it);
else
++it;
}
};
getMaterials(val, mapTree.get_child_optional(name));
}
void CConfigs::LoadJson(boost::property_tree::ptree& mapTree, const char* name, Color_t& val)
{
if (const auto getChild = mapTree.get_child_optional(name))
{
TreeToColor(*getChild, val);
}
}
void CConfigs::LoadJson(boost::property_tree::ptree& mapTree, const char* name, Gradient_t& val)
{
if (const auto getChild = mapTree.get_child_optional(name))
{
if (const auto getStartColor = getChild->get_child_optional("StartColor"))
TreeToColor(*getStartColor, val.StartColor);
if (const auto endColor = getChild->get_child_optional("EndColor"))
TreeToColor(*endColor, val.EndColor);
}
}
void CConfigs::LoadJson(boost::property_tree::ptree& mapTree, const char* name, DragBox_t& val)
{
if (const auto getChild = mapTree.get_child_optional(name))
{
if (auto getValue = getChild->get_optional<int>("x")) { val.x = *getValue; }
if (auto getValue = getChild->get_optional<int>("y")) { val.y = *getValue; }
}
}
void CConfigs::LoadJson(boost::property_tree::ptree& mapTree, const char* name, WindowBox_t& val)
{
if (const auto getChild = mapTree.get_child_optional(name))
{
if (auto getValue = getChild->get_optional<int>("x")) { val.x = *getValue; }
if (auto getValue = getChild->get_optional<int>("y")) { val.y = *getValue; }
if (auto getValue = getChild->get_optional<int>("w")) { val.w = *getValue; }
if (auto getValue = getChild->get_optional<int>("h")) { val.h = *getValue; }
}
}
CConfigs::CConfigs()
{
sConfigPath = std::filesystem::current_path().string() + "\\Amalgam";
sVisualsPath = sConfigPath + "\\Visuals";
if (!std::filesystem::exists(sConfigPath))
std::filesystem::create_directory(sConfigPath);
if (!std::filesystem::exists(sVisualsPath))
std::filesystem::create_directory(sVisualsPath);
// Create 'Core' folder for Attribute-Changer & Playerlist
if (!std::filesystem::exists(sConfigPath + "\\Core"))
std::filesystem::create_directory(sConfigPath + "\\Core");
// Create 'Materials' folder for custom materials
if (!std::filesystem::exists(sConfigPath + "\\Materials"))
std::filesystem::create_directory(sConfigPath + "\\Materials");
}
#define IsType(type) var->m_iType == typeid(type).hash_code()
#define SaveType(type, tree)\
{\
boost::property_tree::ptree mapTree;\
for (const auto& [cond, value] : var->GetVar<type>()->Map)\
SaveJson(mapTree, cond.c_str(), value);\
tree.put_child(var->m_sName.c_str(), mapTree);\
}
#define SaveT(type, tree) if (IsType(type)) SaveType(type, tree)
#define LoadType(type, tree)\
{\
var->GetVar<type>()->Map = { { "default", var->GetVar<type>()->Default } };\
if (const auto mapTree = tree.get_child_optional(var->m_sName.c_str()))\
{\
for (auto& it : *mapTree)\
{\
if ((!F::Conditions.mConditions.contains(it.first) || var->GetVar<type>()->m_iFlags & NOCOND) && FNV1A::Hash(it.first.c_str()) != FNV1A::HashConst("default"))\
continue;\
LoadJson(*mapTree, it.first.c_str(), var->GetVar<type>()->Map[it.first]);\
}\
}\
}
#define LoadT(type, tree) if (IsType(type)) LoadType(type, tree)
bool CConfigs::SaveConfig(const std::string& configName, bool bNotify)
{
try
{
boost::property_tree::ptree writeTree;
boost::property_tree::ptree condTree;
for (const auto& sCond : F::Conditions.vConditions)
{
auto& tCond = F::Conditions.mConditions[sCond];
boost::property_tree::ptree condTree2;
condTree2.put("Type", tCond.Type);
condTree2.put("Info", tCond.Info);
condTree2.put("Key", tCond.Key);
condTree2.put("Not", tCond.Not);
condTree2.put("Active", tCond.Active);
condTree2.put("Visible", tCond.Visible);
condTree2.put("Parent", tCond.Parent);
condTree.put_child(sCond, condTree2);
}
writeTree.put_child("Conditions", condTree);
boost::property_tree::ptree varTree;
for (const auto var : g_Vars)
{
if (var->m_iFlags & NOSAVE)
continue;
SaveT(bool, varTree)
else SaveT(int, varTree)
else SaveT(float, varTree)
else SaveT(IntRange_t, varTree)
else SaveT(FloatRange_t, varTree)
else SaveT(std::string, varTree)
else SaveT(std::vector<std::string>, varTree)
else SaveT(Color_t, varTree)
else SaveT(Gradient_t, varTree)
else SaveT(DragBox_t, varTree)
else SaveT(WindowBox_t, varTree)
}
writeTree.put_child("ConVars", varTree);
write_json(sConfigPath + "\\" + configName + sConfigExtension, writeTree);
sCurrentConfig = configName; sCurrentVisuals = "";
if (bNotify)
F::Notifications.Add("Config " + configName + " saved");
}
catch (...)
{
SDK::Output("F::Configs::SaveConfig()", "Failed", { 175, 150, 255, 255 });
return false;
}
return true;
}
bool CConfigs::LoadConfig(const std::string& configName, bool bNotify)
{
// Check if the config exists
if (!std::filesystem::exists(sConfigPath + "\\" + configName + sConfigExtension))
{
// Save default config if one doesn't yet exist
if (configName == std::string("default"))
SaveConfig("default", false);
return false;
}
// Read ptree from json
try
{
boost::property_tree::ptree readTree;
read_json(sConfigPath + "\\" + configName + sConfigExtension, readTree);
if (const auto condTree = readTree.get_child_optional("Conditions"))
{
F::Conditions.mConditions.clear();
F::Conditions.vConditions.clear();
for (auto& it : *condTree)
{
if (FNV1A::Hash(it.first.c_str()) == FNV1A::HashConst("default"))
continue;
Condition_t tCond = {};
if (auto getValue = it.second.get_optional<int>("Type")) { tCond.Type = *getValue; }
if (auto getValue = it.second.get_optional<int>("Info")) { tCond.Info = *getValue; }
if (auto getValue = it.second.get_optional<int>("Key")) { tCond.Key = *getValue; }
if (auto getValue = it.second.get_optional<bool>("Not")) { tCond.Not = *getValue; }
if (auto getValue = it.second.get_optional<bool>("Active")) { tCond.Active = *getValue; }
if (auto getValue = it.second.get_optional<bool>("Visible")) { tCond.Visible = *getValue; }
if (auto getValue = it.second.get_optional<std::string>("Parent")) { tCond.Parent = *getValue; }
F::Conditions.mConditions[it.first] = tCond;
F::Conditions.vConditions.push_back(it.first);
}
}
if (const auto conVars = readTree.get_child_optional("ConVars"))
{
auto& varTree = *conVars;
for (const auto var : g_Vars)
{
if (var->m_iFlags & NOSAVE)
continue;
LoadT(bool, varTree)
else LoadT(int, varTree)
else LoadT(float, varTree)
else LoadT(IntRange_t, varTree)
else LoadT(FloatRange_t, varTree)
else LoadT(std::string, varTree)
else LoadT(std::vector<std::string>, varTree)
else LoadT(Color_t, varTree)
else LoadT(Gradient_t, varTree)
else LoadT(DragBox_t, varTree)
else LoadT(WindowBox_t, varTree)
}
}
H::Fonts.Reload();
sCurrentConfig = configName; sCurrentVisuals = "";
if (bNotify)
F::Notifications.Add("Config " + configName + " loaded");
}
catch (...)
{
SDK::Output("F::Configs::LoadConfig()", "Failed", { 175, 150, 255, 255 });
return false;
}
return true;
}
bool CConfigs::SaveVisual(const std::string& configName, bool bNotify)
{
try
{
boost::property_tree::ptree writeTree;
for (const auto var : g_Vars)
{
if (!(var->m_iFlags & VISUAL) || var->m_iFlags & NOSAVE)
continue;
SaveT(bool, writeTree)
else SaveT(int, writeTree)
else SaveT(float, writeTree)
else SaveT(IntRange_t, writeTree)
else SaveT(FloatRange_t, writeTree)
else SaveT(std::string, writeTree)
else SaveT(std::vector<std::string>, writeTree)
else SaveT(Color_t, writeTree)
else SaveT(Gradient_t, writeTree)
else SaveT(DragBox_t, writeTree)
else SaveT(WindowBox_t, writeTree)
}
write_json(sConfigPath + "\\Visuals\\" + configName + sConfigExtension, writeTree);
if (bNotify)
F::Notifications.Add("Visual config " + configName + " saved");
}
catch (...)
{
SDK::Output("F::Configs::SaveVisual()", "Failed", { 175, 150, 255, 255 });
return false;
}
return true;
}
bool CConfigs::LoadVisual(const std::string& configName, bool bNotify)
{
// Check if the visual config exists
if (!std::filesystem::exists(sVisualsPath + "\\" + configName + sConfigExtension))
{
//if (configName == std::string("default"))
// SaveVisual("default");
return false;
}
try
{
boost::property_tree::ptree readTree;
read_json(sConfigPath + "\\Visuals\\" + configName + sConfigExtension, readTree);
for (const auto var : g_Vars)
{
if (!(var->m_iFlags & VISUAL) || var->m_iFlags & NOSAVE)
continue;
LoadT(bool, readTree)
else LoadT(int, readTree)
else LoadT(float, readTree)
else LoadT(IntRange_t, readTree)
else LoadT(FloatRange_t, readTree)
else LoadT(std::string, readTree)
else LoadT(std::vector<std::string>, readTree)
else LoadT(Color_t, readTree)
else LoadT(Gradient_t, readTree)
else LoadT(DragBox_t, readTree)
else LoadT(WindowBox_t, readTree)
}
H::Fonts.Reload();
sCurrentVisuals = configName;
if (bNotify)
F::Notifications.Add("Visual config " + configName + " loaded");
}
catch (...)
{
SDK::Output("F::Configs::LoadVisual()", "Failed", { 175, 150, 255, 255 });
return false;
}
return true;
}
#define ResetType(type) var->GetVar<type>()->Map = { { "default", var->GetVar<type>()->Default } };
#define ResetT(type) if (IsType(type)) ResetType(type)
void CConfigs::RemoveConfig(const std::string& configName)
{
if (FNV1A::Hash(configName.c_str()) != FNV1A::HashConst("default"))
std::filesystem::remove(sConfigPath + "\\" + configName + sConfigExtension);
else
{
F::Conditions.mConditions.clear();
F::Conditions.vConditions.clear();
for (const auto var : g_Vars)
{
if (var->m_iFlags & NOSAVE)
continue;
ResetT(bool)
else ResetT(int)
else ResetT(float)
else ResetT(IntRange_t)
else ResetT(FloatRange_t)
else ResetT(std::string)
else ResetT(std::vector<std::string>)
else ResetT(Color_t)
else ResetT(Gradient_t)
else ResetT(DragBox_t)
else ResetT(WindowBox_t)
}
SaveConfig("default", false);
}
}
void CConfigs::RemoveVisual(const std::string& configName)
{
std::filesystem::remove(sVisualsPath + "\\" + configName + sConfigExtension);
}

View File

@ -0,0 +1,54 @@
#pragma once
#include "../../SDK/SDK.h"
#include <filesystem>
#include <boost/property_tree/json_parser.hpp>
#include <boost/property_tree/ptree.hpp>
class CConfigs
{
void SaveJson(boost::property_tree::ptree& mapTree, const char* name, bool val);
void SaveJson(boost::property_tree::ptree& mapTree, const char* name, int val);
void SaveJson(boost::property_tree::ptree& mapTree, const char* name, float val);
void SaveJson(boost::property_tree::ptree& mapTree, const char* name, const IntRange_t& val);
void SaveJson(boost::property_tree::ptree& mapTree, const char* name, const FloatRange_t& val);
void SaveJson(boost::property_tree::ptree& mapTree, const char* name, const std::string& val);
void SaveJson(boost::property_tree::ptree& mapTree, const char* name, const std::vector<std::string>& val);
void SaveJson(boost::property_tree::ptree& mapTree, const char* name, const Color_t& val);
void SaveJson(boost::property_tree::ptree& mapTree, const char* name, const Gradient_t& val);
void SaveJson(boost::property_tree::ptree& mapTree, const char* name, const DragBox_t& val);
void SaveJson(boost::property_tree::ptree& mapTree, const char* name, const WindowBox_t& val);
void LoadJson(boost::property_tree::ptree& mapTree, const char* name, bool& val);
void LoadJson(boost::property_tree::ptree& mapTree, const char* name, int& val);
void LoadJson(boost::property_tree::ptree& mapTree, const char* name, float& val);
void LoadJson(boost::property_tree::ptree& mapTree, const char* name, IntRange_t& val);
void LoadJson(boost::property_tree::ptree& mapTree, const char* name, FloatRange_t& val);
void LoadJson(boost::property_tree::ptree& mapTree, const char* name, std::string& val);
void LoadJson(boost::property_tree::ptree& mapTree, const char* name, std::vector<std::string>& val);
void LoadJson(boost::property_tree::ptree& mapTree, const char* name, Color_t& val);
void LoadJson(boost::property_tree::ptree& mapTree, const char* name, Gradient_t& val);
void LoadJson(boost::property_tree::ptree& mapTree, const char* name, DragBox_t& val);
void LoadJson(boost::property_tree::ptree& mapTree, const char* name, WindowBox_t& val);
public:
CConfigs();
bool SaveConfig(const std::string& configName, bool bNotify = true);
bool LoadConfig(const std::string& configName, bool bNotify = true);
bool SaveVisual(const std::string& configName, bool bNotify = true);
bool LoadVisual(const std::string& configName, bool bNotify = true);
void RemoveConfig(const std::string& configName);
void RemoveVisual(const std::string& configName);
boost::property_tree::ptree ColorToTree(const Color_t& color);
void TreeToColor(const boost::property_tree::ptree& tree, Color_t& out);
std::string sCurrentConfig = "default";
std::string sCurrentVisuals = "default";
std::string sConfigPath;
std::string sVisualsPath;
const std::string sConfigExtension = ".json";
};
ADD_FEATURE(CConfigs, Configs);

View File

@ -0,0 +1,530 @@
#include "CritHack.h"
#include "../Aimbot/AutoRocketJump/AutoRocketJump.h"
#define WEAPON_RANDOM_RANGE 10000
#define TF_DAMAGE_CRIT_MULTIPLIER 3.0f
#define TF_DAMAGE_CRIT_CHANCE 0.02f
#define TF_DAMAGE_CRIT_CHANCE_RAPID 0.02f
#define TF_DAMAGE_CRIT_CHANCE_MELEE 0.15f
#define TF_DAMAGE_CRIT_DURATION_RAPID 2.0f
void CCritHack::Fill(const CUserCmd* pCmd, int n)
{
static int iStart = pCmd->command_number;
for (auto& [iSlot, tStorage] : Storage)
{
for (auto it = tStorage.CritCommands.begin(); it != tStorage.CritCommands.end();)
{
if (*it <= pCmd->command_number)
it = tStorage.CritCommands.erase(it);
else
++it;
}
for (auto it = tStorage.SkipCommands.begin(); it != tStorage.SkipCommands.end();)
{
if (*it <= pCmd->command_number)
it = tStorage.SkipCommands.erase(it);
else
++it;
}
for (int i = 0; i < n; i++)
{
if (tStorage.CritCommands.size() >= unsigned(n))
break;
const int iCmdNum = iStart + i;
if (IsCritCommand(iSlot, tStorage.EntIndex, iCmdNum))
tStorage.CritCommands.push_back(iCmdNum);
}
for (int i = 0; i < n; i++)
{
if (tStorage.SkipCommands.size() >= unsigned(n))
break;
const int iCmdNum = iStart + i;
if (IsCritCommand(iSlot, tStorage.EntIndex, iCmdNum, false))
tStorage.SkipCommands.push_back(iCmdNum);
}
}
iStart += n;
}
bool CCritHack::IsCritCommand(int iSlot, int iIndex, const i32 command_number, const bool bCrit, const bool bSafe)
{
const auto uSeed = MD5_PseudoRandom(command_number) & 0x7FFFFFFF;
SDK::RandomSeed(DecryptOrEncryptSeed(iSlot, iIndex, uSeed));
const int iRandom = SDK::RandomInt(0, WEAPON_RANDOM_RANGE - 1);
if (bSafe)
return bCrit ? iRandom < 100 : !(iRandom < 6000);
else
{
const int iRange = (CritChance - 0.1f) * WEAPON_RANDOM_RANGE;
return bCrit ? iRandom < iRange : !(iRandom < iRange);
}
}
u32 CCritHack::DecryptOrEncryptSeed(int iSlot, int iIndex, u32 uSeed)
{
int iLeft = iSlot == SLOT_MELEE ? 8 : 0;
unsigned int iMask = iIndex << (iLeft + 8) | I::EngineClient->GetLocalPlayer() << iLeft;
return iMask ^ uSeed;
}
void CCritHack::GetTotalCrits(CTFPlayer* pLocal, CTFWeaponBase* pWeapon)
{
const int iSlot = pWeapon->m_iSlot();
static float flOldBucket = 0.f; static int iOldID = 0, iOldCritChecks = 0, iOldCritSeedRequests = 0;
const float flBucket = pWeapon->m_flCritTokenBucket(); const int iID = pWeapon->m_iWeaponID(), iCritChecks = pWeapon->m_nCritChecks(), iCritSeedRequests = pWeapon->m_nCritSeedRequests();
const bool bMatch = Storage[iSlot].Damage > 0 && flOldBucket == flBucket && iOldID == iID && iOldCritChecks == iCritChecks && iOldCritSeedRequests == iCritSeedRequests;
auto tfWeaponInfo = pWeapon->GetWeaponInfo();
if (bMatch || !tfWeaponInfo)
return;
flOldBucket = flBucket; iOldID = iID, iOldCritChecks = iCritChecks, iOldCritSeedRequests = iCritSeedRequests;
static auto bucketCap = U::ConVars.FindVar("tf_weapon_criticals_bucket_cap");
const float flBucketCap = bucketCap ? bucketCap->GetFloat() : 1000.f;
auto& tWeaponData = tfWeaponInfo->GetWeaponData(0);
float flDamage = tWeaponData.m_nDamage;
flDamage = SDK::AttribHookValue(flDamage, "mult_dmg", pWeapon);
int nProjectilesPerShot = tWeaponData.m_nBulletsPerShot;
if (nProjectilesPerShot >= 1)
nProjectilesPerShot = SDK::AttribHookValue(nProjectilesPerShot, "mult_bullets_per_shot", pWeapon);
else
nProjectilesPerShot = 1;
Storage[iSlot].Damage = flDamage *= nProjectilesPerShot;
if (pWeapon->IsStreamingWeapon())
{
flDamage *= TF_DAMAGE_CRIT_DURATION_RAPID / tWeaponData.m_flTimeFireDelay;
if (flDamage * TF_DAMAGE_CRIT_MULTIPLIER > flBucketCap)
flDamage = flBucketCap / TF_DAMAGE_CRIT_MULTIPLIER;
}
float flMult = iSlot == SLOT_MELEE ? 0.5f : Math::RemapValClamped(float(iCritSeedRequests + 1) / (iCritChecks + 1), 0.1f, 1.f, 1.f, 3.f);
Storage[iSlot].Cost = flDamage * TF_DAMAGE_CRIT_MULTIPLIER * flMult;
if (flBucketCap)
Storage[iSlot].PotentialCrits = (flBucketCap - Storage[iSlot].Damage) / (3 * flDamage / (iSlot == SLOT_MELEE ? 2 : 1) - Storage[iSlot].Damage);
int iCrits = 0;
{
int shots = iCritChecks, crits = iCritSeedRequests;
float bucket = flBucket, flCost = flDamage * TF_DAMAGE_CRIT_MULTIPLIER;
const int iAttempts = std::min(Storage[iSlot].PotentialCrits + 1, 100);
for (int i = 0; i < iAttempts; i++)
{
shots++; crits++;
flMult = iSlot == SLOT_MELEE ? 0.5f : Math::RemapValClamped(float(crits) / shots, 0.1f, 1.f, 1.f, 3.f);
bucket = std::min(bucket + Storage[iSlot].Damage, flBucketCap) - flCost * flMult;
if (bucket < 0.f)
break;
iCrits++;
}
}
if (!iCrits)
{
int shots = iCritChecks + 1, crits = iCritSeedRequests + 1;
float bucket = std::min(flBucket + Storage[iSlot].Damage, flBucketCap), flCost = flDamage * TF_DAMAGE_CRIT_MULTIPLIER;
for (int i = 0; i < 100; i++)
{
iCrits--;
if (!pWeapon->IsStreamingWeapon() || !(i % int(tWeaponData.m_flTimeFireDelay / TICK_INTERVAL)))
shots++;
flMult = iSlot == SLOT_MELEE ? 0.5f : Math::RemapValClamped(float(crits) / shots, 0.1f, 1.f, 1.f, 3.f);
bucket = std::min(bucket + Storage[iSlot].Damage, flBucketCap);
if (bucket >= flCost * flMult)
break;
}
}
Storage[iSlot].AvailableCrits = iCrits;
}
void CCritHack::CanFireCritical(CTFPlayer* pLocal, CTFWeaponBase* pWeapon)
{
CritBanned = false;
DamageTilUnban = 0;
if (pWeapon->m_iSlot() == SLOT_MELEE)
CritChance = TF_DAMAGE_CRIT_CHANCE_MELEE * pLocal->GetCritMult();
else if (pWeapon->IsStreamingWeapon())
{
CritChance = TF_DAMAGE_CRIT_CHANCE_RAPID * pLocal->GetCritMult();
float flNonCritDuration = (TF_DAMAGE_CRIT_DURATION_RAPID / CritChance) - TF_DAMAGE_CRIT_DURATION_RAPID;
CritChance = 1.f / flNonCritDuration;
}
else
CritChance = TF_DAMAGE_CRIT_CHANCE * pLocal->GetCritMult();
CritChance = SDK::AttribHookValue(CritChance, "mult_crit_chance", pWeapon) + 0.1f;
if (!AllDamage || !CritDamage || pWeapon->m_iSlot() == SLOT_MELEE)
return;
const float flNormalizedDamage = (float)CritDamage / TF_DAMAGE_CRIT_MULTIPLIER;
const float flObservedCritChance = flNormalizedDamage / (flNormalizedDamage + AllDamage - CritDamage);
if (CritBanned = flObservedCritChance > CritChance)
DamageTilUnban = flNormalizedDamage / CritChance + CritDamage - flNormalizedDamage - AllDamage;
}
bool CCritHack::WeaponCanCrit(CTFWeaponBase* pWeapon)
{
static auto tf_weapon_criticals = U::ConVars.FindVar("tf_weapon_criticals");
if (!tf_weapon_criticals || !tf_weapon_criticals->GetBool())
return false;
if (SDK::AttribHookValue(1.f, "mult_crit_chance", pWeapon) <= 0.f)
return false;
switch (pWeapon->m_iWeaponID())
{
case TF_WEAPON_PDA:
case TF_WEAPON_PDA_ENGINEER_BUILD:
case TF_WEAPON_PDA_ENGINEER_DESTROY:
case TF_WEAPON_PDA_SPY:
case TF_WEAPON_PDA_SPY_BUILD:
case TF_WEAPON_BUILDER:
case TF_WEAPON_INVIS:
case TF_WEAPON_GRAPPLINGHOOK:
case TF_WEAPON_JAR_MILK:
case TF_WEAPON_LUNCHBOX:
case TF_WEAPON_BUFF_ITEM:
case TF_WEAPON_FLAME_BALL:
case TF_WEAPON_ROCKETPACK:
case TF_WEAPON_JAR_GAS:
case TF_WEAPON_LASER_POINTER:
case TF_WEAPON_MEDIGUN:
case TF_WEAPON_SNIPERRIFLE:
case TF_WEAPON_SNIPERRIFLE_DECAP:
case TF_WEAPON_SNIPERRIFLE_CLASSIC:
case TF_WEAPON_COMPOUND_BOW:
case TF_WEAPON_JAR:
case TF_WEAPON_KNIFE:
return false;
}
return true;
}
void CCritHack::ResetWeapons(CTFPlayer* pLocal)
{
std::unordered_map<int, bool> mWeapons = {};
auto hWeapons = pLocal->GetMyWeapons();
if (!hWeapons)
return;
for (size_t i = 0; hWeapons[i]; i++)
{
if (SDK::HandleToIDX(unsigned(hWeapons[i])) < 0 || SDK::HandleToIDX(unsigned(hWeapons[i])) >= 2048)
continue;
if (const auto pWeapon = I::ClientEntityList->GetClientEntityFromHandle(unsigned(hWeapons[i]))->As<CTFWeaponBase>())
{
const int iSlot = pWeapon->m_iSlot();
const int iDefIndex = pWeapon->m_iItemDefinitionIndex();
mWeapons[iSlot] = true;
if (Storage[iSlot].DefIndex == iDefIndex)
continue;
Storage[iSlot] = {};
Storage[iSlot].EntIndex = pWeapon->entindex();
Storage[iSlot].DefIndex = iDefIndex;
SDK::Output("Crithack", std::format("Resetting weapon {}", iDefIndex).c_str(), { 0, 255, 255, 255 }, Vars::Debug::Logging.Value);
}
}
for (auto& [iSlot, _] : Storage)
{
if (!mWeapons[iSlot])
Storage[iSlot] = {};
}
}
void CCritHack::Reset()
{
Storage = {};
CritDamage = 0;
AllDamage = 0;
CritBanned = false;
DamageTilUnban = 0;
CritChance = 0.f;
SDK::Output("Crithack", "Resetting all", { 0, 255, 255, 255 }, Vars::Debug::Logging.Value);
}
void CCritHack::Run(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCmd* pCmd)
{
if (!pLocal || !pWeapon || !pLocal->IsAlive() || !I::EngineClient->IsInGame())
return;
ResetWeapons(pLocal);
Fill(pCmd, 15);
GetTotalCrits(pLocal, pWeapon);
CanFireCritical(pLocal, pWeapon);
if (pLocal->IsCritBoosted() || !WeaponCanCrit(pWeapon))
return;
if (pWeapon->m_iWeaponID() == TF_WEAPON_MINIGUN && pCmd->buttons & IN_ATTACK)
pCmd->buttons &= ~IN_ATTACK2;
bool bAttacking = G::IsAttacking;
if (G::WeaponType == EWeaponType::MELEE)
{
bAttacking = G::CanPrimaryAttack && pCmd->buttons & IN_ATTACK;
if (!bAttacking && pWeapon->m_iWeaponID() == TF_WEAPON_FISTS)
bAttacking = G::CanPrimaryAttack && pCmd->buttons & IN_ATTACK2;
}
if (pWeapon->m_iWeaponID() == TF_WEAPON_PIPEBOMBLAUNCHER || pWeapon->m_iWeaponID() == TF_WEAPON_STICKY_BALL_LAUNCHER || pWeapon->m_iWeaponID() == TF_WEAPON_GRENADE_STICKY_BALL
|| pWeapon->m_iWeaponID() == TF_WEAPON_CANNON)
{
static float flBegin = -1.f;
if (pCmd->buttons& IN_ATTACK&& flBegin < 0.f && G::CanPrimaryAttack)
flBegin = I::GlobalVars->curtime;
const float flCharge = flBegin > 0.f ? I::GlobalVars->curtime - flBegin : 0.f;
const float flAmount = pWeapon->m_iWeaponID() != TF_WEAPON_CANNON
? Math::RemapValClamped(flCharge, 0.f, SDK::AttribHookValue(4.f, "stickybomb_charge_rate", pWeapon), 0.f, 1.f)
: Math::RemapValClamped(flCharge, 0.f, SDK::AttribHookValue(0.f, "grenade_launcher_mortar_mode", pWeapon), 0.f, 1.f);
const bool bUnheld = !(pCmd->buttons & IN_ATTACK) && flAmount > 0.f;
const bool bSwapping = pCmd->weaponselect;
const bool bFull = flAmount == 1.f; // possibly add exception to skip when full with cannon
bAttacking = (bUnheld || bFull) && !bSwapping;
if (bAttacking || !G::CanPrimaryAttack || bSwapping)
flBegin = -1.f;
}
if ((pWeapon->m_iWeaponID() == TF_WEAPON_MINIGUN || pWeapon->m_iWeaponID() == TF_WEAPON_FLAMETHROWER) && !(G::LastUserCmd->buttons & IN_ATTACK)) // silly
bAttacking = false;
const int iSlot = pWeapon->m_iSlot();
if (Storage[iSlot].StreamWait <= I::GlobalVars->tickcount - 1)
Storage[pWeapon->m_iSlot()].StreamWait = -1;
const bool bRapidFire = pWeapon->IsStreamingWeapon();
const bool bStreamWait = Storage[iSlot].StreamWait > 0;
//const bool bStreamWait = pWeapon->IsStreamingWeapon() && pWeapon->LastRapidfireCritCheckTime() + 1.f > TICK_INTERVAL * pLocal->m_nTickBase();
const int closestCrit = !Storage[iSlot].CritCommands.empty() ? Storage[iSlot].CritCommands.front() : 0;
const int closestSkip = !Storage[iSlot].SkipCommands.empty() ? Storage[iSlot].SkipCommands.front() : 0;
static bool bFirstTimePredicted = false;
if (!I::ClientState->chokedcommands)
bFirstTimePredicted = false;
if (bAttacking && !pWeapon->IsInReload() && !bFirstTimePredicted)
{
bFirstTimePredicted = true;
const bool bCanCrit = Storage[pWeapon->m_iSlot()].AvailableCrits > 0 && (!CritBanned || pWeapon->m_iSlot() == SLOT_MELEE) && !bStreamWait;
const bool bPressed = Vars::CritHack::ForceCrits.Value || pWeapon->m_iSlot() == SLOT_MELEE && Vars::CritHack::AlwaysMelee.Value;
if (bCanCrit && bPressed && closestCrit)
pCmd->command_number = closestCrit;
else if (Vars::CritHack::AvoidRandom.Value && closestSkip)
pCmd->command_number = closestSkip;
if (bRapidFire && !bStreamWait)
Storage[pWeapon->m_iSlot()].StreamWait = I::GlobalVars->tickcount + 1 / TICK_INTERVAL;
}
//else if (Vars::CritHack::AvoidRandom.Value && closestSkip)
// pCmd->command_number = closestSkip;
//if (pCmd->command_number == closestCrit || pCmd->command_number == closestSkip)
WishRandomSeed = MD5_PseudoRandom(pCmd->command_number) & 0x7FFFFFFF;
if (pCmd->command_number == closestCrit)
Storage[iSlot].CritCommands.pop_front();
else if (pCmd->command_number == closestSkip)
Storage[iSlot].SkipCommands.pop_front();
}
bool CCritHack::CalcIsAttackCriticalHandler(CTFPlayer* pLocal, CTFWeaponBase* pWeapon)
{
if (!I::Prediction->m_bFirstTimePredicted || !pLocal || !pWeapon)
return false;
if (pWeapon->m_iWeaponID() == TF_WEAPON_MINIGUN || pWeapon->m_iWeaponID() == TF_WEAPON_FLAMETHROWER)
{
static int iOldAmmo = pLocal->GetAmmoCount(pWeapon->m_iPrimaryAmmoType());
const int iNewAmmo = pLocal->GetAmmoCount(pWeapon->m_iPrimaryAmmoType());
const bool bFired = iOldAmmo != iNewAmmo;
iOldAmmo = iNewAmmo;
if (!bFired)
return false;
}
if (WishRandomSeed)
{
*G::RandomSeed() = WishRandomSeed;
WishRandomSeed = 0;
}
return true;
}
void CCritHack::Event(IGameEvent* pEvent, FNV1A_t uHash, CTFPlayer* pLocal)
{
switch (uHash)
{
case FNV1A::HashConst("player_hurt"):
{
auto pWeapon = H::Entities.GetWeapon();
if (!pLocal || !pWeapon)
return;
const int iVictim = I::EngineClient->GetPlayerForUserID(pEvent->GetInt("userid"));
const int iAttacker = I::EngineClient->GetPlayerForUserID(pEvent->GetInt("attacker"));
const bool bCrit = pEvent->GetBool("crit") || pEvent->GetBool("minicrit");
int iDamage = pEvent->GetInt("damageamount");
if (mHealthStorage.contains(iVictim))
iDamage = std::min(iDamage, mHealthStorage[iVictim]);
const auto iWeaponID = pEvent->GetInt("weaponid");
if (iVictim == iAttacker || iAttacker != pLocal->entindex() || iWeaponID != pWeapon->m_iWeaponID() || pWeapon->m_iSlot() == SLOT_MELEE) // weapon id stuff is dumb simplification
return;
AllDamage += iDamage;
if (bCrit && !pLocal->IsCritBoosted())
CritDamage += iDamage;
return;
}
case FNV1A::HashConst("teamplay_round_start"):
AllDamage = CritDamage = 0;
return;
case FNV1A::HashConst("client_beginconnect"):
case FNV1A::HashConst("client_disconnect"):
case FNV1A::HashConst("game_newmap"):
Reset();
}
}
void CCritHack::Store()
{
auto pResource = H::Entities.GetPR();
if (!pResource)
return;
for (auto it = mHealthStorage.begin(); it != mHealthStorage.end();)
{
if (I::ClientEntityList->GetClientEntity(it->first))
++it;
else
it = mHealthStorage.erase(it);
}
for (auto& pEntity : H::Entities.GetGroup(EGroupType::PLAYERS_ALL))
{
auto pPlayer = pEntity->As<CTFPlayer>();
if (pPlayer->IsAlive() && !pPlayer->IsAGhost())
mHealthStorage[pPlayer->entindex()] = pPlayer->IsDormant() ? pResource->GetHealth(pPlayer->entindex()) : pPlayer->m_iHealth();
}
}
void CCritHack::Draw(CTFPlayer* pLocal)
{
static auto tf_weapon_criticals = U::ConVars.FindVar("tf_weapon_criticals");
const bool bWeaponCriticals = tf_weapon_criticals ? tf_weapon_criticals->GetBool() : true;
if (!(Vars::Menu::Indicators.Value & (1 << 1)) || !I::EngineClient->IsInGame() || !bWeaponCriticals || !G::CurrentUserCmd)
return;
auto pWeapon = H::Entities.GetWeapon();
if (!pWeapon || !pLocal->IsAlive() || pLocal->IsAGhost())
return;
int x = Vars::Menu::CritsDisplay.Value.x;
int y = Vars::Menu::CritsDisplay.Value.y + 8;
const auto& fFont = H::Fonts.GetFont(FONT_INDICATORS);
EAlign align = ALIGN_TOP;
if (x <= (100 + 50 * Vars::Menu::DPI.Value))
{
x -= 42 * Vars::Menu::DPI.Value;
align = ALIGN_TOPLEFT;
}
else if (x >= H::Draw.m_nScreenW - (100 + 50 * Vars::Menu::DPI.Value))
{
x += 42 * Vars::Menu::DPI.Value;
align = ALIGN_TOPRIGHT;
}
if (WeaponCanCrit(pWeapon))
{
const auto iSlot = pWeapon->m_iSlot();
const auto bRapidFire = pWeapon->IsStreamingWeapon();
if (Storage[iSlot].Damage > 0)
{
if (pLocal->IsCritBoosted())
H::Draw.String(fFont, x, y, { 100, 255, 255, 255 }, align, "Crit Boosted");
else if (pWeapon->m_flCritTime() > TICK_INTERVAL * pLocal->m_nTickBase())
{
const float flTime = pWeapon->m_flCritTime() - TICK_INTERVAL * pLocal->m_nTickBase();
H::Draw.String(fFont, x, y, { 100, 255, 255, 255 }, align, std::format("Streaming crits {:.1f}s", flTime).c_str());
}
else if (!CritBanned)
{
if (Storage[iSlot].AvailableCrits > 0)
{
if (bRapidFire && Storage[iSlot].StreamWait > 0)
{
//const float flTime = std::max((TICKS_TO_TIME(Storage[iSlot].StreamWait - pLocal->m_nTickBase())), 0.f);
const float flTime = pWeapon->m_flLastRapidFireCritCheckTime() + 1.f - TICK_INTERVAL * pLocal->m_nTickBase();
H::Draw.String(fFont, x, y, Vars::Menu::Theme::Active.Value, align, std::format("Wait {:.1f}s", flTime).c_str());
}
else
H::Draw.String(fFont, x, y, { 150, 255, 150, 255 }, align, "Crit Ready");
}
else
{
const int shots = -Storage[iSlot].AvailableCrits;
H::Draw.String(fFont, x, y, { 255, 150, 150, 255 }, align, shots == 1 ? std::format("Crit in {} shot", shots).c_str() : std::format("Crit in {}{} shots", shots, shots == 100 ? "+" : "").c_str());
}
}
else
H::Draw.String(fFont, x, y, { 255, 150, 150, 255 }, align, std::format("Deal {} damage", DamageTilUnban).c_str());
H::Draw.String(fFont, x, y + fFont.m_nTall + 1, Vars::Menu::Theme::Active.Value, align, std::format("{} / {} potential crits", std::max(Storage[iSlot].AvailableCrits, 0), Storage[iSlot].PotentialCrits).c_str());
}
else
H::Draw.String(fFont, x, y, Vars::Menu::Theme::Active.Value, align, "Calculating");
if (Vars::Debug::Info.Value)
{
H::Draw.String(fFont, x, y + fFont.m_nTall * 3, { 255, 255, 255, 255 }, align, std::format("AllDamage: {}, CritDamage: {}", AllDamage, CritDamage).c_str());
H::Draw.String(fFont, x, y + fFont.m_nTall * 4, { 255, 255, 255, 255 }, align, std::format("Bucket: {}", pWeapon->m_flCritTokenBucket()).c_str());
H::Draw.String(fFont, x, y + fFont.m_nTall * 5, { 255, 255, 255, 255 }, align, std::format("Damage: {}, Cost: {}", Storage[iSlot].Damage, Storage[iSlot].Cost).c_str());
H::Draw.String(fFont, x, y + fFont.m_nTall * 6, { 255, 255, 255, 255 }, align, std::format("Shots: {}, Crits: {}", pWeapon->m_nCritChecks(), pWeapon->m_nCritSeedRequests()).c_str());
H::Draw.String(fFont, x, y + fFont.m_nTall * 7, { 255, 255, 255, 255 }, align, std::format("CritBanned: {}, DamageTilUnban: {}", CritBanned, DamageTilUnban).c_str());
H::Draw.String(fFont, x, y + fFont.m_nTall * 8, { 255, 255, 255, 255 }, align, std::format("CritChance: {:.2f} ({:.2f})", CritChance, CritChance - 0.1f).c_str());
H::Draw.String(fFont, x, y + fFont.m_nTall * 9, { 255, 255, 255, 255 }, align, std::format("Force: {}, Skip: {}", Storage[iSlot].CritCommands.size(), Storage[iSlot].SkipCommands.size()).c_str());
}
}
}

View File

@ -0,0 +1,56 @@
#pragma once
#include "../../SDK/SDK.h"
typedef int i32;
typedef unsigned int u32;
struct WeaponStorage
{
float Damage = 0.f;
float Cost = 0.f;
int AvailableCrits = 0;
int PotentialCrits = 0;
int StreamWait = -1;
int EntIndex = -1;
int DefIndex = -1;
std::deque<int> CritCommands = {};
std::deque<int> SkipCommands = {};
};
class CCritHack
{
private:
void Fill(const CUserCmd* pCmd, int n = 10);
bool IsCritCommand(int iSlot, int iIndex, const i32 command_number, const bool bCrit = true, const bool bSafe = true);
u32 DecryptOrEncryptSeed(int iSlot, int iIndex, const u32 uSeed);
void GetTotalCrits(CTFPlayer* pLocal, CTFWeaponBase* pWeapon);
void CanFireCritical(CTFPlayer* pLocal, CTFWeaponBase* pWeapon);
bool WeaponCanCrit(CTFWeaponBase* pWeapon);
void ResetWeapons(CTFPlayer* pLocal);
void Reset();
int CritDamage = 0.f;
int AllDamage = 0.f;
std::unordered_map<int, int> mHealthStorage = {};
bool CritBanned = false;
int DamageTilUnban = 0;
float CritChance = 0.f;
int WishRandomSeed = 0;
public:
void Run(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCmd* pCmd);
bool CalcIsAttackCriticalHandler(CTFPlayer* pLocal, CTFWeaponBase* pWeapon);
void Event(IGameEvent* pEvent, FNV1A_t uHash, CTFPlayer* pLocal);
void Store();
void Draw(CTFPlayer* pLocal);
std::unordered_map<int, WeaponStorage> Storage = {};
};
ADD_FEATURE(CCritHack, CritHack)

View File

@ -0,0 +1,85 @@
#include "EnginePrediction.h"
#include "../TickHandler/TickHandler.h"
int CEnginePrediction::GetTickbase(CUserCmd* pCmd, CTFPlayer* pLocal)
{
static int nTick = 0;
static CUserCmd* pLastCmd = nullptr;
if (pCmd)
{
if (!pLastCmd || pLastCmd->hasbeenpredicted)
nTick = pLocal->m_nTickBase();
else
nTick++;
pLastCmd = pCmd;
}
return nTick;
}
void CEnginePrediction::Simulate(CTFPlayer* pLocal, CUserCmd* pCmd)
{
if (!pLocal || !pLocal->IsAlive() || !I::MoveHelper)
return;
pLocal->SetCurrentCmd(pCmd);
*G::RandomSeed() = MD5_PseudoRandom(pCmd->command_number) & std::numeric_limits<int>::max();
const int nOldTickBase = pLocal->m_nTickBase();
const bool bOldIsFirstPrediction = I::Prediction->m_bFirstTimePredicted;
const bool bOldInPrediction = I::Prediction->m_bInPrediction;
I::Prediction->m_bFirstTimePredicted = false;
I::Prediction->m_bInPrediction = true;
I::Prediction->SetLocalViewAngles(pCmd->viewangles);
I::Prediction->SetupMove(pLocal, pCmd, I::MoveHelper, &m_MoveData);
I::GameMovement->ProcessMovement(pLocal, &m_MoveData);
I::Prediction->FinishMove(pLocal, pCmd, &m_MoveData);
pLocal->m_nTickBase() = nOldTickBase;
I::Prediction->m_bFirstTimePredicted = bOldIsFirstPrediction;
I::Prediction->m_bInPrediction = bOldInPrediction;
}
void CEnginePrediction::Start(CTFPlayer* pLocal, CUserCmd* pCmd)
{
if (!pLocal || !pLocal->IsAlive())
return;
m_nOldTickCount = I::GlobalVars->tickcount;
m_fOldCurrentTime = I::GlobalVars->curtime;
m_fOldFrameTime = I::GlobalVars->frametime;
I::GlobalVars->tickcount = GetTickbase(pCmd, pLocal);
I::GlobalVars->curtime = TICKS_TO_TIME(I::GlobalVars->tickcount);
I::GlobalVars->frametime = I::Prediction->m_bEnginePaused ? 0.0f : TICK_INTERVAL;
bSimulated = false;
if (F::Ticks.GetTicks(pLocal) && Vars::CL_Move::Doubletap::AntiWarp.Value && pLocal->OnSolid())
return; // hopefully more accurate eyepos while dting
bSimulated = true;
Simulate(pLocal, pCmd);
}
void CEnginePrediction::End(CTFPlayer* pLocal, CUserCmd* pCmd)
{
if (!pLocal || !pLocal->IsAlive())
return;
I::GlobalVars->tickcount = m_nOldTickCount;
I::GlobalVars->curtime = m_fOldCurrentTime;
I::GlobalVars->frametime = m_fOldFrameTime;
pLocal->SetCurrentCmd(nullptr);
*G::RandomSeed() = -1;
if (!bSimulated)
Simulate(pLocal, pCmd);
}

View File

@ -0,0 +1,24 @@
#pragma once
#include "../../SDK/SDK.h"
class CEnginePrediction
{
private:
CMoveData m_MoveData = {};
private:
int GetTickbase(CUserCmd* pCmd, CTFPlayer* pLocal);
void Simulate(CTFPlayer* pLocal, CUserCmd* pCmd);
int m_nOldTickCount = 0;
float m_fOldCurrentTime = 0.f;
float m_fOldFrameTime = 0.f;
bool bSimulated = false;
public:
void Start(CTFPlayer* pLocal, CUserCmd* pCmd);
void End(CTFPlayer* pLocal, CUserCmd* pCmd);
};
ADD_FEATURE(CEnginePrediction, EnginePrediction)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,45 @@
#pragma once
#include "../../../SDK/SDK.h"
#include "../Render.h"
#include <ImGui/TextEditor.h>
class CMenu
{
void DrawMenu();
void MenuAimbot();
void MenuVisuals();
void MenuMisc();
void MenuLogs();
void MenuSettings();
void AddDraggable(const char* szTitle, ConfigVar<DragBox_t>& info, bool bShouldDraw);
void DrawBinds();
void DrawCameraWindow();
void DrawRadar();
int CurrentTab = 0;
int CurrentAimbotTab = 0;
int CurrentVisualsTab = 0;
int CurrentLogsTab = 0;
int CurrentConfigTab = 0;
int CurrentConfigType = 0;
ImVec2 TabSize = { 65, 72 };
ImVec2 SubTabSize = { 90, 48 };
// material editor stuff
TextEditor TextEditor;
std::string CurrentMaterial;
bool LockedMaterial;
public:
void Render();
bool IsOpen = false;
bool ConfigLoaded = false;
bool InKeybind = false;
};
ADD_FEATURE(CMenu, Menu);

View File

@ -0,0 +1,152 @@
#include "Render.h"
#include "../../Hooks/Direct3DDevice9_EndScene.h"
#include <ImGui/imgui_impl_win32.h>
#include "MaterialDesign/MaterialIcons.h"
#include "MaterialDesign/IconDefinitions.h"
#include "Menu/Menu.h"
#include "../Visuals/Visuals.h"
void CRender::Render(IDirect3DDevice9* pDevice)
{
using namespace ImGui;
static std::once_flag initFlag;
std::call_once(initFlag, [&]
{
Initialize(pDevice);
});
pDevice->SetRenderState(D3DRS_COLORWRITEENABLE, 0xFFFFFFFF);
pDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
pDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
pDevice->SetRenderState(D3DRS_SRGBWRITEENABLE, false);
ImGui_ImplDX9_NewFrame();
ImGui_ImplWin32_NewFrame();
NewFrame();
LoadColors();
PushFont(FontRegular);
F::Visuals.DrawTickbaseBars();
F::Menu.Render();
PopFont();
EndFrame();
ImGui::Render();
ImGui_ImplDX9_RenderDrawData(GetDrawData());
pDevice->SetRenderState(D3DRS_SRGBWRITEENABLE, true);
}
void CRender::LoadColors()
{
using namespace ImGui;
auto ColorToVec = [](Color_t color) -> ImColor
{
return { float(color.r) / 255.f, float(color.g) / 255.f, float(color.b) / 255.f, float(color.a) / 255.f };
};
Accent = ColorToVec(Vars::Menu::Theme::Accent.Value);
AccentLight = ImColor(Accent.Value.x * 1.1f, Accent.Value.y * 1.1f, Accent.Value.z * 1.1f, Accent.Value.w);
Background = ColorToVec(Vars::Menu::Theme::Background.Value);
Foreground = ColorToVec(Vars::Menu::Theme::Foreground.Value);
Foremost = ColorToVec(Vars::Menu::Theme::Foremost.Value);
ForemostLight = ImColor(Foremost.Value.x * 1.1f, Foremost.Value.y * 1.1f, Foremost.Value.z * 1.1f, Foremost.Value.w);
Inactive = ColorToVec(Vars::Menu::Theme::Inactive.Value);
Active = ColorToVec(Vars::Menu::Theme::Active.Value);
ImVec4* colors = GetStyle().Colors;
colors[ImGuiCol_Button] = {};
colors[ImGuiCol_ButtonHovered] = {};
colors[ImGuiCol_ButtonActive] = {};
colors[ImGuiCol_FrameBg] = Foremost;
colors[ImGuiCol_FrameBgHovered] = ForemostLight;
colors[ImGuiCol_FrameBgActive] = Foremost;
colors[ImGuiCol_Header] = {};
colors[ImGuiCol_HeaderHovered] = ForemostLight;
colors[ImGuiCol_HeaderActive] = {};
colors[ImGuiCol_ModalWindowDimBg] = { Background.Value.x, Background.Value.y, Background.Value.z, 0.4f };
colors[ImGuiCol_PopupBg] = ForemostLight;
colors[ImGuiCol_ResizeGrip] = {};
colors[ImGuiCol_ResizeGripActive] = {};
colors[ImGuiCol_ResizeGripHovered] = {};
colors[ImGuiCol_ScrollbarBg] = {};
colors[ImGuiCol_SliderGrab] = Accent;
colors[ImGuiCol_SliderGrabActive] = AccentLight;
colors[ImGuiCol_Text] = Active;
colors[ImGuiCol_WindowBg] = Background;
}
void CRender::LoadStyle()
{
using namespace ImGui;
auto& style = GetStyle();
style.ButtonTextAlign = { 0.5f, 0.5f }; // Center button text
style.CellPadding = { 4, 0 };
style.ChildBorderSize = 0.f;
style.ChildRounding = 0.f;
style.FrameBorderSize = 0.f;
style.FramePadding = { 0, 0 };
style.FrameRounding = 3.f;
style.ItemInnerSpacing = { 0, 0 };
style.ItemSpacing = { 8, 8 };
style.PopupBorderSize = 0.f;
style.PopupRounding = 3.f;
style.ScrollbarSize = 9.f;
style.ScrollbarRounding = 0.f;
style.WindowBorderSize = 0.f;
style.WindowMinSize = { 100, 100 };
style.WindowPadding = { 0, 0 };
style.WindowRounding = 3.f;
}
void CRender::Initialize(IDirect3DDevice9* pDevice)
{
while (!WndProc::hwWindow)
WndProc::hwWindow = SDK::GetTeamFortressWindow();
// Initialize ImGui and device
ImGui::CreateContext();
ImGui_ImplWin32_Init(WndProc::hwWindow);
ImGui_ImplDX9_Init(pDevice);
// Fonts
{
const auto& io = ImGui::GetIO();
ImFontConfig fontConfig;
fontConfig.OversampleH = 2;
constexpr ImWchar fontRange[]{ 0x0020, 0x00FF, 0x0400, 0x044F, 0 }; // Basic Latin, Latin Supplement and Cyrillic
FontSmall = io.Fonts->AddFontFromFileTTF(R"(C:\Windows\Fonts\verdana.ttf)", 11.f, &fontConfig, fontRange);
FontRegular = io.Fonts->AddFontFromFileTTF(R"(C:\Windows\Fonts\verdana.ttf)", 13.f, &fontConfig, fontRange);
FontBold = io.Fonts->AddFontFromFileTTF(R"(C:\Windows\Fonts\verdana.ttf)", 13.f, &fontConfig, fontRange);
FontLarge = io.Fonts->AddFontFromFileTTF(R"(C:\Windows\Fonts\verdana.ttf)", 15.f, &fontConfig, fontRange);
FontBlack = io.Fonts->AddFontFromFileTTF(R"(C:\Windows\Fonts\verdana.ttf)", 15.f, &fontConfig, fontRange);
FontTitle = io.Fonts->AddFontFromFileTTF(R"(C:\Windows\Fonts\verdana.ttf)", 20.f, &fontConfig, fontRange);
FontMono = io.Fonts->AddFontFromFileTTF(R"(C:\Windows\Fonts\verdana.ttf)", 15.f, &fontConfig, fontRange);
//FontSmall = io.Fonts->AddFontFromMemoryCompressedTTF(RobotoMedium_compressed_data, RobotoMedium_compressed_size, 11.f, &fontConfig, fontRange);
//FontRegular = io.Fonts->AddFontFromMemoryCompressedTTF(RobotoMedium_compressed_data, RobotoMedium_compressed_size, 13.f, &fontConfig, fontRange);
//FontBold = io.Fonts->AddFontFromMemoryCompressedTTF(RobotoBold_compressed_data, RobotoBold_compressed_size, 13.f, &fontConfig, fontRange);
//FontLarge = io.Fonts->AddFontFromMemoryCompressedTTF(RobotoMedium_compressed_data, RobotoMedium_compressed_size, 15.f, &fontConfig, fontRange);
//FontBlack = io.Fonts->AddFontFromMemoryCompressedTTF(RobotoBlack_compressed_data, RobotoBlack_compressed_size, 15.f, &fontConfig, fontRange);
//FontTitle = io.Fonts->AddFontFromMemoryCompressedTTF(RobotoMedium_compressed_data, RobotoMedium_compressed_size, 20.f, &fontConfig, fontRange);
//FontMono = io.Fonts->AddFontFromMemoryCompressedTTF(CascadiaMono_compressed_data, CascadiaMono_compressed_size, 15.f, &fontConfig, fontRange);
ImFontConfig iconConfig;
iconConfig.PixelSnapH = true;
constexpr ImWchar iconRange[]{ short(ICON_MIN_MD), short(ICON_MAX_MD), 0 };
IconFontRegular = io.Fonts->AddFontFromMemoryCompressedTTF(MaterialIcons_compressed_data, MaterialIcons_compressed_size, 15.f, &iconConfig, iconRange);
IconFontLarge = io.Fonts->AddFontFromMemoryCompressedTTF(MaterialIcons_compressed_data, MaterialIcons_compressed_size, 16.f, &iconConfig, iconRange);
io.Fonts->Build();
}
LoadStyle();
}

View File

@ -0,0 +1,40 @@
#pragma once
#include "../../SDK/SDK.h"
#include <ImGui/imgui_impl_dx9.h>
#include <ImGui/imgui.h>
class CRender
{
public:
void Render(IDirect3DDevice9* pDevice);
void Initialize(IDirect3DDevice9* pDevice);
void LoadColors();
void LoadStyle();
int Cursor = 2;
// Colors
ImColor Accent = { 255, 101, 101 };
ImColor AccentLight = { 255, 111, 111 };
ImColor Background = { 23, 23, 23, 250 };
ImColor Foreground = { 11, 11, 11, 250 };
ImColor Foremost = { 23, 23, 23, 250 };
ImColor ForemostLight = { 25, 25, 25, 250 };
ImColor Inactive = { 150, 150, 150 };
ImColor Active = { 255, 255, 255 };
// Fonts
ImFont* FontSmall = nullptr;
ImFont* FontRegular = nullptr;
ImFont* FontBold = nullptr;
ImFont* FontLarge = nullptr;
ImFont* FontBlack = nullptr;
ImFont* FontTitle = nullptr;
ImFont* FontMono = nullptr;
ImFont* IconFontRegular = nullptr;
ImFont* IconFontLarge = nullptr;
};
ADD_FEATURE(CRender, Render);

View File

@ -0,0 +1,662 @@
#include "Misc.h"
#include "../Backtrack/Backtrack.h"
#include "../CheaterDetection/CheaterDetection.h"
#include "../PacketManip/AntiAim/AntiAim.h"
#include "../TickHandler/TickHandler.h"
#include "../Players/PlayerUtils.h"
void CMisc::RunPre(CTFPlayer* pLocal, CUserCmd* pCmd)
{
CheatsBypass();
PingReducer();
WeaponSway();
if (!pLocal)
return;
AntiAFK(pLocal, pCmd);
InstantRespawnMVM(pLocal);
if (!pLocal->IsAlive() || pLocal->IsAGhost() || pLocal->m_MoveType() != MOVETYPE_WALK || pLocal->IsSwimming() || pLocal->IsCharging() || pLocal->IsInBumperKart())
return;
AutoJump(pLocal, pCmd);
AutoJumpbug(pLocal, pCmd);
AutoStrafe(pLocal, pCmd);
AntiBackstab(pLocal, pCmd);
AutoPeek(pLocal, pCmd);
}
void CMisc::RunPost(CTFPlayer* pLocal, CUserCmd* pCmd, bool pSendPacket)
{
if (!pLocal || !pLocal->IsAlive() || pLocal->IsAGhost() || pLocal->m_MoveType() != MOVETYPE_WALK || pLocal->IsSwimming() || pLocal->IsCharging())
return;
TauntKartControl(pLocal, pCmd);
FastMovement(pLocal, pCmd);
AntiWarp(pLocal, pCmd);
LegJitter(pLocal, pCmd, pSendPacket);
}
void CMisc::AutoJump(CTFPlayer* pLocal, CUserCmd* pCmd)
{
if (!Vars::Misc::Movement::Bunnyhop.Value)
return;
static bool bStaticJump = false, bStaticGrounded = false, bLastAttempted = false;
const bool bLastJump = bStaticJump, bLastGrounded = bStaticGrounded;
const bool bCurJump = bStaticJump = pCmd->buttons & IN_JUMP, bCurGrounded = bStaticGrounded = pLocal->OnSolid();
if (bCurJump && bLastJump)
{
if (!(bCurGrounded && !bLastGrounded))
pCmd->buttons &= ~IN_JUMP;
if (!(pCmd->buttons & IN_JUMP) && bCurGrounded && !bLastAttempted)
pCmd->buttons |= IN_JUMP;
}
bLastAttempted = pCmd->buttons & IN_JUMP;
}
void CMisc::AutoJumpbug(CTFPlayer* pLocal, CUserCmd* pCmd)
{
if (!Vars::Misc::Movement::AutoJumpbug.Value || !(pCmd->buttons & IN_DUCK) || pLocal->OnSolid() || pLocal->m_vecVelocity().z > -650.f)
return;
CGameTrace trace;
CTraceFilterWorldAndPropsOnly filter = {};
filter.pSkip = pLocal;
Vec3 origin = pLocal->m_vecOrigin();
SDK::TraceHull(origin, origin - Vec3(0, 0, 22), pLocal->m_vecMins(), pLocal->m_vecMaxs(), MASK_PLAYERSOLID, &filter, &trace);
if (!trace.DidHit()) // don't try if we aren't in range to unduck
return;
const float flDist = origin.DistTo(trace.endpos);
if (20.f < flDist /*&& flDist < 22.f*/) // this seems to be the range where this works
{
pCmd->buttons &= ~IN_DUCK;
pCmd->buttons |= IN_JUMP;
}
}
void CMisc::AutoStrafe(CTFPlayer* pLocal, CUserCmd* pCmd)
{
if (!Vars::Misc::Movement::AutoStrafe.Value || pLocal->OnSolid() || !(pLocal->m_afButtonLast() & IN_JUMP) && (pCmd->buttons & IN_JUMP))
return;
switch (Vars::Misc::Movement::AutoStrafe.Value)
{
case 1:
{
static auto cl_sidespeed = U::ConVars.FindVar("cl_sidespeed");
const float flSideSpeed = cl_sidespeed ? cl_sidespeed->GetFloat() : 450.f;
if (pCmd->mousedx)
{
pCmd->forwardmove = 0.f;
pCmd->sidemove = pCmd->mousedx > 0 ? flSideSpeed : -flSideSpeed;
}
break;
}
case 2:
{
//credits: KGB
if (!(pCmd->buttons & (IN_FORWARD | IN_BACK | IN_MOVELEFT | IN_MOVERIGHT)))
break;
float flForwardMove = pCmd->forwardmove;
float flSideMove = pCmd->sidemove;
Vec3 vForward = {}, vRight = {};
Math::AngleVectors(pCmd->viewangles, &vForward, &vRight, nullptr);
vForward.z = vRight.z = 0.f;
vForward.Normalize();
vRight.Normalize();
Vec3 vWishDir = {};
Math::VectorAngles({ (vForward.x * flForwardMove) + (vRight.x * flSideMove), (vForward.y * flForwardMove) + (vRight.y * flSideMove), 0.f }, vWishDir);
Vec3 vCurDir = {};
Math::VectorAngles(pLocal->m_vecVelocity(), vCurDir);
float flDirDelta = Math::NormalizeAngle(vWishDir.y - vCurDir.y);
float flTurnScale = Math::RemapValClamped(Vars::Misc::Movement::AutoStrafeTurnScale.Value, 0.f, 1.f, 0.9f, 1.f);
float flRotation = DEG2RAD((flDirDelta > 0.f ? -90.f : 90.f) + (flDirDelta * flTurnScale));
float flCosRot = cosf(flRotation);
float flSinRot = sinf(flRotation);
pCmd->forwardmove = (flCosRot * flForwardMove) - (flSinRot * flSideMove);
pCmd->sidemove = (flSinRot * flForwardMove) + (flCosRot * flSideMove);
}
}
}
void CMisc::AntiBackstab(CTFPlayer* pLocal, CUserCmd* pCmd)
{
G::Busy = false;
if (!Vars::Misc::Automation::AntiBackstab.Value || G::IsAttacking || pLocal->IsInBumperKart() || !Vars::Misc::Automation::AntiBackstab.Value)
return;
std::vector<Vec3> vTargets = {};
for (auto pEntity : H::Entities.GetGroup(EGroupType::PLAYERS_ENEMIES))
{
auto pPlayer = pEntity->As<CTFPlayer>();
if (!pPlayer->IsAlive() || pPlayer->IsAGhost() || pPlayer->IsCloaked() || pPlayer->m_bFeignDeathReady())
continue;
if (auto pWeapon = pPlayer->m_hActiveWeapon().Get()->As<CTFWeaponBase>())
{
if (pWeapon->m_iWeaponID() != TF_WEAPON_KNIFE)
continue;
}
PlayerInfo_t pi{};
if (I::EngineClient->GetPlayerInfo(pPlayer->entindex(), &pi) && F::PlayerUtils.IsIgnored(pi.friendsID))
continue;
Vec3 vTargetPos = pPlayer->m_vecOrigin() + pPlayer->m_vecVelocity() * F::Backtrack.GetReal();
if (pLocal->m_vecOrigin().DistTo(vTargetPos) > 200.f || !SDK::VisPos(pLocal, pPlayer, pLocal->m_vecOrigin(), vTargetPos))
continue;
vTargets.push_back(vTargetPos);
}
std::sort(vTargets.begin(), vTargets.end(), [&](const auto& a, const auto& b) -> bool
{
return pLocal->m_vecOrigin().DistTo(a) < pLocal->m_vecOrigin().DistTo(b);
});
auto vTargetPos = vTargets.begin();
if (vTargetPos != vTargets.end())
{
const Vec3 vAngleTo = Math::CalcAngle(pLocal->m_vecOrigin(), *vTargetPos);
G::Busy = true;
SDK::FixMovement(pCmd, vAngleTo);
pCmd->viewangles.y = vAngleTo.y;
}
}
void CMisc::AutoPeek(CTFPlayer* pLocal, CUserCmd* pCmd)
{
static bool bPosPlaced = false;
static bool bReturning = false;
if (Vars::CL_Move::AutoPeek.Value)
{
const Vec3 localPos = pLocal->GetAbsOrigin();
// We just started peeking. Save the return position!
if (!bPosPlaced)
{
if (pLocal->OnSolid())
{
vPeekReturnPos = localPos;
bPosPlaced = true;
}
}
else
{
static Timer particleTimer{};
if (particleTimer.Run(700))
H::Particles.DispatchParticleEffect("ping_circle", vPeekReturnPos, {});
}
// We've just attacked. Let's return!
if (G::LastUserCmd->buttons & IN_ATTACK || G::IsAttacking)
bReturning = true;
if (bReturning)
{
if (localPos.DistTo(vPeekReturnPos) < 7.f)
{
bReturning = false;
return;
}
SDK::WalkTo(pCmd, pLocal, vPeekReturnPos);
}
}
else
{
bPosPlaced = bReturning = false;
vPeekReturnPos = Vec3();
}
}
void CMisc::AntiAFK(CTFPlayer* pLocal, CUserCmd* pCmd)
{
static Timer afkTimer{};
static auto mp_idledealmethod = U::ConVars.FindVar("mp_idledealmethod");
static auto mp_idlemaxtime = U::ConVars.FindVar("mp_idlemaxtime");
const int iIdleMethod = mp_idledealmethod ? mp_idledealmethod->GetInt() : 1;
const float flMaxIdleTime = mp_idlemaxtime ? mp_idlemaxtime->GetFloat() : 3.f;
if (pCmd->buttons & (IN_MOVELEFT | IN_MOVERIGHT | IN_FORWARD | IN_BACK) || !pLocal->IsAlive())
afkTimer.Update();
// Trigger 10 seconds before kick
else if (Vars::Misc::Automation::AntiAFK.Value && iIdleMethod && afkTimer.Check(flMaxIdleTime * 60 * 1000 - 10000))
pCmd->buttons |= pCmd->command_number % 2 ? IN_FORWARD : IN_BACK;
}
void CMisc::InstantRespawnMVM(CTFPlayer* pLocal)
{
if (Vars::Misc::MannVsMachine::InstantRespawn.Value && I::EngineClient->IsInGame() && !pLocal->IsAlive())
{
auto kv = new KeyValues("MVM_Revive_Response");
kv->SetInt("accepted", 1);
I::EngineClient->ServerCmdKeyValues(kv);
}
}
void CMisc::CheatsBypass()
{
static bool bCheatSet = false;
static auto sv_cheats = U::ConVars.FindVar("sv_cheats");
if (sv_cheats)
{
if (Vars::Misc::Exploits::CheatsBypass.Value)
{
sv_cheats->m_nValue = 1;
bCheatSet = true;
}
else if (bCheatSet)
{
sv_cheats->m_nValue = 0;
bCheatSet = false;
}
}
}
void CMisc::PingReducer()
{
auto pNetChan = reinterpret_cast<CNetChannel*>(I::EngineClient->GetNetChannelInfo());
if (!pNetChan)
return;
static auto cl_cmdrate = U::ConVars.FindVar("cl_cmdrate");
const int iCmdRate = cl_cmdrate ? cl_cmdrate->GetInt() : 66;
static Timer updateRateTimer{};
if (updateRateTimer.Run(100))
{
const int iTarget = Vars::Misc::Exploits::PingReducer.Value ? Vars::Misc::Exploits::PingTarget.Value : iCmdRate;
if (iTarget == iLastCmdrate)
return;
iLastCmdrate = iTarget;
SDK::Output("SendNetMsg", std::format("cl_cmdrate: {}", iTarget).c_str(), { 224, 255, 131, 255 }, Vars::Debug::Logging.Value);
NET_SetConVar cmd("cl_cmdrate", std::to_string(iTarget).c_str());
pNetChan->SendNetMsg(cmd);
}
}
void CMisc::WeaponSway()
{
static auto cl_wpn_sway_interp = U::ConVars.FindVar("cl_wpn_sway_interp");
static auto cl_wpn_sway_scale = U::ConVars.FindVar("cl_wpn_sway_scale");
if (cl_wpn_sway_interp)
cl_wpn_sway_interp->SetValue(Vars::Visuals::Viewmodel::Sway.Value ? Vars::Visuals::Viewmodel::SwayInterp.Value : 0.f);
if (cl_wpn_sway_scale)
cl_wpn_sway_scale->SetValue(Vars::Visuals::Viewmodel::Sway.Value ? Vars::Visuals::Viewmodel::SwayScale.Value : 0.f);
}
void CMisc::TauntKartControl(CTFPlayer* pLocal, CUserCmd* pCmd)
{
// Handle Taunt Slide
if (Vars::Misc::Automation::TauntControl.Value && pLocal->IsTaunting())
{
if (pCmd->buttons & IN_FORWARD)
{
pCmd->forwardmove = 450.f;
pCmd->viewangles.x = 0.f;
}
if (pCmd->buttons & IN_BACK)
{
pCmd->forwardmove = 450.f;
pCmd->viewangles.x = 91.f;
}
if (pCmd->buttons & IN_MOVELEFT)
pCmd->sidemove = -450.f;
if (pCmd->buttons & IN_MOVERIGHT)
pCmd->sidemove = 450.f;
if (!(pCmd->buttons & (IN_FORWARD | IN_BACK | IN_MOVELEFT | IN_MOVERIGHT)))
pCmd->viewangles.x = 90.f;
Vec3 vAngle = I::EngineClient->GetViewAngles();
pCmd->viewangles.y = vAngle.y;
G::SilentAngles = true;
}
else if (Vars::Misc::Automation::KartControl.Value && pLocal->IsInBumperKart())
{
const bool bForward = pCmd->buttons & IN_FORWARD;
const bool bBack = pCmd->buttons & IN_BACK;
const bool bLeft = pCmd->buttons & IN_MOVELEFT;
const bool bRight = pCmd->buttons & IN_MOVERIGHT;
const bool flipVar = pCmd->command_number % 2;
if (bForward && (!bLeft && !bRight || !flipVar))
{
pCmd->forwardmove = 450.f;
pCmd->viewangles.x = 0.f;
}
else if (bBack && (!bLeft && !bRight || !flipVar))
{
pCmd->forwardmove = 450.f;
pCmd->viewangles.x = 91.f;
}
else if (pCmd->buttons & (IN_FORWARD | IN_BACK | IN_MOVELEFT | IN_MOVERIGHT))
{
if (flipVar)
{ // you could just do this if you didn't care about viewangles
const Vec3 vecMove(pCmd->forwardmove, pCmd->sidemove, 0.f);
const float flLength = vecMove.Length();
Vec3 angMoveReverse;
Math::VectorAngles(vecMove * -1.f, angMoveReverse);
pCmd->forwardmove = -flLength;
pCmd->sidemove = 0.f;
pCmd->viewangles.y = fmodf(pCmd->viewangles.y - angMoveReverse.y, 360.f);
pCmd->viewangles.z = 270.f;
G::PSilentAngles = true;
}
}
else
pCmd->viewangles.x = 90.f;
G::SilentAngles = true;
}
}
void CMisc::FastMovement(CTFPlayer* pLocal, CUserCmd* pCmd)
{
if (!pLocal->OnSolid() || pLocal->IsInBumperKart())
return;
const float flSpeed = pLocal->m_vecVelocity().Length2D();
const int flMaxSpeed = std::min(pLocal->m_flMaxspeed() * 0.9f, 520.f) - 10.f;
const int iRun = !pCmd->forwardmove && !pCmd->sidemove ? 0 : flSpeed < flMaxSpeed ? 1 : 2;
switch (iRun)
{
case 0:
{
if (!Vars::Misc::Movement::FastStop.Value || !flSpeed)
return;
if (G::ShiftedTicks != G::MaxShift && !G::IsAttacking && !G::AntiAim)
{
if (!SDK::StopMovement(pLocal, pCmd))
return;
if (!G::Recharge && !G::DoubleTap)
G::PSilentAngles = true;
else
G::SilentAngles = true;
}
else
{
Vec3 direction = pLocal->m_vecVelocity().toAngle();
direction.y = pCmd->viewangles.y - direction.y;
const Vec3 negatedDirection = direction.fromAngle() * -flSpeed;
pCmd->forwardmove = negatedDirection.x;
pCmd->sidemove = negatedDirection.y;
}
break;
}
case 1:
{
if ((pLocal->IsDucking() ? !Vars::Misc::Movement::CrouchSpeed.Value : !Vars::Misc::Movement::FastAccel.Value) || G::IsAttacking || G::DoubleTap || G::Recharge || G::AntiAim || pCmd->command_number % 2)
return;
if (!(pCmd->buttons & (IN_FORWARD | IN_BACK | IN_MOVELEFT | IN_MOVERIGHT)))
return;
const Vec3 vecMove(pCmd->forwardmove, pCmd->sidemove, 0.f);
const float flLength = vecMove.Length();
Vec3 angMoveReverse;
Math::VectorAngles(vecMove * -1.f, angMoveReverse);
pCmd->forwardmove = -flLength;
pCmd->sidemove = 0.f;
pCmd->viewangles.y = fmodf(pCmd->viewangles.y - angMoveReverse.y, 360.f);
pCmd->viewangles.z = 270.f;
G::PSilentAngles = true;
break;
}
case 2:
{
if (!Vars::Misc::Movement::FastStrafe.Value || G::IsAttacking)
return;
static bool bFwd = pCmd->forwardmove > 0;
static bool bSde = pCmd->sidemove > 0;
const bool bCurFwd = pCmd->forwardmove > 0;
const bool bCurSde = pCmd->sidemove > 0;
bool bChanged = false;
if (fabsf(pCmd->sidemove) > 400)
{
if (bSde != bCurSde)
{
pCmd->viewangles.x = 90.f;
pCmd->viewangles.y += bSde ? -90.f : 90.f;
pCmd->sidemove = bSde ? -pCmd->forwardmove : pCmd->forwardmove;
G::PSilentAngles = bChanged = true;
}
bSde = bCurSde;
if (bChanged)
return;
}
if (fabsf(pCmd->forwardmove) > 400)
{
if (bFwd != bCurFwd)
{
pCmd->viewangles.x = 90.f;
pCmd->viewangles.y += bFwd ? 0.f : 180.f;
pCmd->sidemove *= bFwd ? 1 : -1;
G::PSilentAngles = bChanged = true;
}
bFwd = bCurFwd;
if (bChanged)
return;
}
}
}
}
void CMisc::AntiWarp(CTFPlayer* pLocal, CUserCmd* pCmd)
{
static Vec3 vVelocity = {};
if (G::AntiWarp)
{
const int iDoubletapTicks = F::Ticks.GetTicks(pLocal);
Vec3 angles = {}; Math::VectorAngles(vVelocity, angles);
angles.y = pCmd->viewangles.y - angles.y;
Vec3 forward = {}; Math::AngleVectors(angles, &forward);
forward *= vVelocity.Length();
if (iDoubletapTicks > std::max(Vars::CL_Move::Doubletap::TickLimit.Value - 8, 3))
{
pCmd->forwardmove = -forward.x;
pCmd->sidemove = -forward.y;
}
else if (iDoubletapTicks > 3)
{
pCmd->forwardmove = pCmd->sidemove = 0.f;
pCmd->buttons &= ~(IN_FORWARD | IN_BACK | IN_MOVELEFT | IN_MOVERIGHT);
}
else
{
pCmd->forwardmove = forward.x;
pCmd->sidemove = forward.y;
}
}
else
vVelocity = pLocal->m_vecVelocity();
}
void CMisc::LegJitter(CTFPlayer* pLocal, CUserCmd* pCmd, bool pSendPacket)
{
if (!Vars::AntiHack::AntiAim::MinWalk.Value || !F::AntiAim.YawOn() || G::IsAttacking || G::DoubleTap || pSendPacket || !pLocal->OnSolid() || pLocal->IsInBumperKart())
return;
static bool pos = true;
const float scale = pLocal->IsDucking() ? 14.f : 1.f;
if (pCmd->forwardmove == 0.f && pCmd->sidemove == 0.f && pLocal->m_vecVelocity().Length2D() < 10.f)
{
pos ? pCmd->forwardmove = scale : pCmd->forwardmove = -scale;
pos ? pCmd->sidemove = scale : pCmd->sidemove = -scale;
pos = !pos;
}
}
void CMisc::Event(IGameEvent* pEvent, FNV1A_t uHash)
{
switch (uHash)
{
case FNV1A::HashConst("teamplay_round_start"):
case FNV1A::HashConst("client_disconnect"):
case FNV1A::HashConst("client_beginconnect"):
case FNV1A::HashConst("game_newmap"):
iLastCmdrate = -1;
F::Backtrack.flWishInterp = 0.f;
G::BulletsStorage.clear();
G::BoxesStorage.clear();
G::LinesStorage.clear();
}
}
void CMisc::DoubletapPacket(CUserCmd* pCmd, bool* pSendPacket)
{
if (G::DoubleTap || G::Warp)
{
*pSendPacket = G::ShiftedGoal == G::ShiftedTicks;
if ((G::DoubleTap || pCmd->buttons & IN_ATTACK) && I::ClientState->chokedcommands >= 21)
*pSendPacket = true;
}
}
void CMisc::DetectChoke()
{
for (auto pEntity : H::Entities.GetGroup(EGroupType::PLAYERS_ALL))
{
if (!pEntity->As<CTFPlayer>()->IsAlive() || pEntity->IsDormant())
{
G::ChokeMap[pEntity->entindex()] = 0;
continue;
}
if (pEntity->m_flSimulationTime() == pEntity->m_flOldSimulationTime())
G::ChokeMap[pEntity->entindex()]++;
else
{
F::CheaterDetection.ReportChoke(pEntity->As<CTFPlayer>(), G::ChokeMap[pEntity->entindex()]);
G::ChokeMap[pEntity->entindex()] = 0;
}
}
}
void CMisc::UnlockAchievements()
{
const auto achievementmgr = reinterpret_cast<IAchievementMgr*(*)(void)>(U::Memory.GetVFunc(I::EngineClient, 114))();
if (achievementmgr)
{
I::SteamUserStats->RequestCurrentStats();
for (int i = 0; i < achievementmgr->GetAchievementCount(); i++)
achievementmgr->AwardAchievement(achievementmgr->GetAchievementByIndex(i)->GetAchievementID());
I::SteamUserStats->StoreStats();
I::SteamUserStats->RequestCurrentStats();
}
}
void CMisc::LockAchievements()
{
const auto achievementmgr = reinterpret_cast<IAchievementMgr * (*)(void)>(U::Memory.GetVFunc(I::EngineClient, 114))();
if (achievementmgr)
{
I::SteamUserStats->RequestCurrentStats();
for (int i = 0; i < achievementmgr->GetAchievementCount(); i++)
I::SteamUserStats->ClearAchievement(achievementmgr->GetAchievementByIndex(i)->GetName());
I::SteamUserStats->StoreStats();
I::SteamUserStats->RequestCurrentStats();
}
}
bool CMisc::SteamRPC()
{
/*
if (!Vars::Misc::Steam::EnableRPC.Value)
{
if (!bSteamCleared) // stupid way to return back to normal rpc
{
I::SteamFriends->SetRichPresence("steam_display", ""); // this will only make it say "Team Fortress 2" until the player leaves/joins some server. its bad but its better than making 1000 checks to recreate the original
bSteamCleared = true;
}
return false;
}
bSteamCleared = false;
*/
if (!Vars::Misc::Steam::EnableRPC.Value)
return false;
I::SteamFriends->SetRichPresence("steam_display", "#TF_RichPresence_Display");
if (!I::EngineClient->IsInGame() && !Vars::Misc::Steam::OverrideMenu.Value)
I::SteamFriends->SetRichPresence("state", "MainMenu");
else
{
I::SteamFriends->SetRichPresence("state", "PlayingMatchGroup");
switch (Vars::Misc::Steam::MatchGroup.Value)
{
case 0: I::SteamFriends->SetRichPresence("matchgrouploc", "SpecialEvent"); break;
case 1: I::SteamFriends->SetRichPresence("matchgrouploc", "MannUp"); break;
case 2: I::SteamFriends->SetRichPresence("matchgrouploc", "Competitive6v6"); break;
case 3: I::SteamFriends->SetRichPresence("matchgrouploc", "Casual"); break;
case 4: I::SteamFriends->SetRichPresence("matchgrouploc", "BootCamp"); break;
default: I::SteamFriends->SetRichPresence("matchgrouploc", "SpecialEvent"); break;
}
}
I::SteamFriends->SetRichPresence("currentmap", Vars::Misc::Steam::MapText.Value.empty() ? "Fedoraware" : Vars::Misc::Steam::MapText.Value.c_str());
I::SteamFriends->SetRichPresence("steam_player_group_size", std::to_string(Vars::Misc::Steam::GroupSize.Value).c_str());
return true;
}
#ifdef DEBUG
void CMisc::DumpClassIDS() {
std::ofstream fDump("CLASSIDDUMP.txt");
fDump << "enum struct ETFClassID\n{\n";
CClientClass* ClientClass = I::BaseClientDLL->GetAllClasses();
while (ClientClass) {
fDump << " " << ClientClass->GetName() << " = " << ClientClass->m_ClassID << ",\n";
ClientClass = ClientClass->m_pNext;
}
fDump << "}";
fDump.close();
}
#endif

View File

@ -0,0 +1,48 @@
#pragma once
#include "../../SDK/SDK.h"
#ifdef DEBUG
#include <iostream>
#include <fstream>
#endif
class CMisc
{
void AutoJump(CTFPlayer* pLocal, CUserCmd* pCmd);
void AutoJumpbug(CTFPlayer* pLocal, CUserCmd* pCmd);
void AutoStrafe(CTFPlayer* pLocal, CUserCmd* pCmd);
void AntiBackstab(CTFPlayer* pLocal, CUserCmd* pCmd);
void AutoPeek(CTFPlayer* pLocal, CUserCmd* pCmd);
void AntiAFK(CTFPlayer* pLocal, CUserCmd* pCmd);
void InstantRespawnMVM(CTFPlayer* pLocal);
void CheatsBypass();
void PingReducer();
void WeaponSway();
void TauntKartControl(CTFPlayer* pLocal, CUserCmd* pCmd);
void FastMovement(CTFPlayer* pLocal, CUserCmd* pCmd);
void AntiWarp(CTFPlayer* pLocal, CUserCmd* pCmd);
void LegJitter(CTFPlayer* pLocal, CUserCmd* pCmd, bool pSendPacket);
int iLastCmdrate = -1;
Vec3 vPeekReturnPos = {};
//bool bSteamCleared = false;
public:
void RunPre(CTFPlayer* pLocal, CUserCmd* pCmd);
void RunPost(CTFPlayer* pLocal, CUserCmd* pCmd, bool pSendPacket);
void Event(IGameEvent* pEvent, FNV1A_t uNameHash);
void DoubletapPacket(CUserCmd* pCmd, bool* pSendPacket);
void DetectChoke();
void UnlockAchievements();
void LockAchievements();
bool SteamRPC();
#ifdef DEBUG
void DumpClassIDS();
#endif
};
ADD_FEATURE(CMisc, Misc)

View File

@ -0,0 +1,52 @@
#include "NetworkFix.h"
void CReadPacketState::Store()
{
m_flFrameTimeClientState = I::ClientState->m_frameTime;
m_flFrameTime = I::GlobalVars->frametime;
m_flCurTime = I::GlobalVars->curtime;
m_nTickCount = I::GlobalVars->tickcount;
}
void CReadPacketState::Restore()
{
I::ClientState->m_frameTime = m_flFrameTimeClientState;
I::GlobalVars->frametime = m_flFrameTime;
I::GlobalVars->curtime = m_flCurTime;
I::GlobalVars->tickcount = m_nTickCount;
}
void CNetworkFix::FixInputDelay(bool bFinalTick)
{
static auto CL_ReadPackets = U::Hooks.m_mHooks["CL_ReadPackets"];
if (!I::EngineClient->IsInGame() || !Vars::Misc::Game::NetworkFix.Value || !CL_ReadPackets)
return;
auto pNetChan = I::EngineClient->GetNetChannelInfo();
if (pNetChan && pNetChan->IsLoopback())
return;
CReadPacketState Backup = {};
Backup.Store();
CL_ReadPackets->Original<void(__cdecl*)(bool)>()(bFinalTick);
m_State.Store();
Backup.Restore();
}
bool CNetworkFix::ShouldReadPackets()
{
if (!I::EngineClient->IsInGame() || !Vars::Misc::Game::NetworkFix.Value)
return true;
auto pNetChan = I::EngineClient->GetNetChannelInfo();
if (pNetChan && pNetChan->IsLoopback())
return true;
m_State.Restore();
return false;
}

View File

@ -0,0 +1,27 @@
#pragma once
#include "../../SDK/SDK.h"
class CReadPacketState
{
private:
float m_flFrameTimeClientState = 0.f;
float m_flFrameTime = 0.f;
float m_flCurTime = 0.f;
int m_nTickCount = 0;
public:
void Store();
void Restore();
};
class CNetworkFix
{
private:
CReadPacketState m_State = {};
public:
void FixInputDelay(bool bFinalTick);
bool ShouldReadPackets();
};
ADD_FEATURE(CNetworkFix, NetworkFix);

View File

@ -0,0 +1,33 @@
#include "NoSpread.h"
#include "NoSpreadProjectile/NoSpreadProjectile.h"
#include "NoSpreadHitscan/NoSpreadHitscan.h"
bool CNoSpread::ShouldRun(CTFPlayer* pLocal, CTFWeaponBase* pWeapon)
{
if (!Vars::Aimbot::General::NoSpread.Value)
return false;
if (!pLocal || !pWeapon
|| !pLocal->IsAlive()
|| pLocal->IsTaunting()
|| pLocal->IsBonked()
|| pLocal->m_bFeignDeathReady()
|| pLocal->IsCloaked()
|| pLocal->IsInBumperKart()
|| pLocal->IsAGhost())
{
return false;
}
return true;
}
void CNoSpread::Run(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCmd* pCmd)
{
if (!ShouldRun(pLocal, pWeapon))
return;
F::NoSpreadHitscan.Run(pLocal, pWeapon, pCmd);
F::NoSpreadProjectile.Run(pLocal, pWeapon, pCmd);
}

View File

@ -0,0 +1,13 @@
#pragma once
#include "../../SDK/SDK.h"
class CNoSpread
{
private:
bool ShouldRun(CTFPlayer* pLocal, CTFWeaponBase* pWeapon);
public:
void Run(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCmd* pCmd);
};
ADD_FEATURE(CNoSpread, NoSpread)

View File

@ -0,0 +1,197 @@
#include "NoSpreadHitscan.h"
#include "../../TickHandler/TickHandler.h"
#include <regex>
#include <numeric>
void CNoSpreadHitscan::Reset(bool bResetPrint)
{
bWaitingForPlayerPerf = false;
flServerTime = 0.f;
flFloatTimeDelta = 0.f;
iSeed = 0;
flMantissaStep = 0;
bSynced = false;
if (bResetPrint)
iBestSync = 0;
}
bool CNoSpreadHitscan::ShouldRun(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, bool bCreateMove)
{
if (G::WeaponType != EWeaponType::HITSCAN)
return false;
if (pWeapon->GetWeaponSpread() <= 0.f)
return false;
return bCreateMove ? G::IsAttacking : true;
}
int CNoSpreadHitscan::GetSeed(CUserCmd* pCmd)
{
static auto sv_usercmd_custom_random_seed = U::ConVars.FindVar("sv_usercmd_custom_random_seed");
if (sv_usercmd_custom_random_seed ? sv_usercmd_custom_random_seed->GetBool() : true)
{
const float flFloatTime = float(SDK::PlatFloatTime()) + flFloatTimeDelta;
//SDK::Output("Seed Prediction", std::format("{}\n", flFloatTime).c_str());
const float flTime = (flFloatTime) * 1000;
return std::bit_cast<int32_t>(flTime) & 255;
}
else
return pCmd->random_seed; // i don't think this is right
}
float CNoSpreadHitscan::CalcMantissaStep(float val)
{
// Calculate the delta to the next representable value
const float nextValue = std::nextafter(val, std::numeric_limits<float>::infinity());
const float mantissaStep = (nextValue - val) * 1000;
// Get the closest mantissa (next power of 2)
return powf(2, ceilf(logf(mantissaStep) / logf(2)));
}
std::string CNoSpreadHitscan::GetFormat(int m_ServerTime)
{
const int iDays = m_ServerTime / 86400;
const int iHours = m_ServerTime / 3600 % 24;
const int iMinutes = m_ServerTime / 60 % 60;
const int iSeconds = m_ServerTime % 60;
if (iDays)
return std::format("{}d {}h", iDays, iHours);
else if (iHours)
return std::format("{}h {}m", iHours, iMinutes);
else
return std::format("{}m {}s", iMinutes, iSeconds);
}
void CNoSpreadHitscan::AskForPlayerPerf()
{
if (!Vars::Aimbot::General::NoSpread.Value)
return Reset();
static Timer playerperfTimer{};
if (playerperfTimer.Run(50) && !bWaitingForPlayerPerf && I::EngineClient->IsInGame())
{
I::EngineClient->ClientCmd_Unrestricted("playerperf");
bWaitingForPlayerPerf = true;
}
}
bool CNoSpreadHitscan::ParsePlayerPerf(bf_read& msgData)
{
if (!Vars::Aimbot::General::NoSpread.Value)
return false;
char rawMsg[256] = {};
msgData.ReadString(rawMsg, sizeof(rawMsg), true);
msgData.Seek(0);
std::string msg(rawMsg);
msg.erase(msg.begin());
std::smatch matches = {};
std::regex_match(msg, matches, std::regex(R"((\d+.\d+)\s\d+\s\d+\s\d+.\d+\s\d+.\d+\svel\s\d+.\d+)"));
if (matches.size() == 2)
{
bWaitingForPlayerPerf = false;
// credits to kgb for idea
const float flNewServerTime = std::stof(matches[1].str());
if (flNewServerTime < flServerTime)
return true;
flServerTime = flNewServerTime;
flFloatTimeDelta = flServerTime - float(SDK::PlatFloatTime());
flMantissaStep = CalcMantissaStep(flServerTime);
const int iSynced = flMantissaStep < 4.f ? 2 : 1;
bSynced = iSynced == 1;
if (!iBestSync || iBestSync == 2 && bSynced)
{
iBestSync = iSynced;
SDK::Output("Seed Prediction", bSynced ? std::format("Synced ({})", flFloatTimeDelta).c_str() : "Not synced, step too low", Vars::Menu::Theme::Accent.Value);
SDK::Output("Seed Prediction", std::format("Age {}; Step {}", GetFormat(flServerTime), CalcMantissaStep(flServerTime)).c_str(), Vars::Menu::Theme::Accent.Value);
}
return true;
}
return std::regex_match(msg, std::regex(R"(\d+.\d+\s\d+\s\d+)"));
}
void CNoSpreadHitscan::Run(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCmd* pCmd)
{
iSeed = GetSeed(pCmd);
if (!bSynced || !ShouldRun(pLocal, pWeapon, true))
return;
// credits to cathook for average spread stuff
const float flSpread = pWeapon->GetWeaponSpread();
auto tfWeaponInfo = pWeapon->GetWeaponInfo();
int iBulletsPerShot = tfWeaponInfo ? tfWeaponInfo->GetWeaponData(0).m_nBulletsPerShot : 1;
iBulletsPerShot = static_cast<int>(SDK::AttribHookValue(static_cast<float>(iBulletsPerShot), "mult_bullets_per_shot", pWeapon));
std::vector<Vec3> vBulletCorrections = {};
Vec3 vAverageSpread = {};
for (int iBullet = 0; iBullet < iBulletsPerShot; iBullet++)
{
SDK::RandomSeed(iSeed + iBullet);
if (!iBullet) // Check if we'll get a guaranteed perfect shot
{
bool bDoubletap = false; // if we are doubletapping and firerate fast enough, prioritize later bullets
int iTicks = F::Ticks.GetTicks(pLocal);
if (iTicks && tfWeaponInfo)
{
float flDoubletapTime = TICKS_TO_TIME(iTicks);
float flFireRate = tfWeaponInfo->GetWeaponData(0).m_flTimeFireDelay;
bDoubletap = flDoubletapTime > flFireRate * 2;
}
if (!bDoubletap)
{
const float flTimeSinceLastShot = (pLocal->m_nTickBase() * TICK_INTERVAL) - pWeapon->m_flLastFireTime();
if ((iBulletsPerShot == 1 && flTimeSinceLastShot > 1.25f) || (iBulletsPerShot > 1 && flTimeSinceLastShot > 0.25f))
return;
}
}
const float x = SDK::RandomFloat(-0.5f, 0.5f) + SDK::RandomFloat(-0.5f, 0.5f);
const float y = SDK::RandomFloat(-0.5f, 0.5f) + SDK::RandomFloat(-0.5f, 0.5f);
Vec3 forward, right, up;
Math::AngleVectors(pCmd->viewangles, &forward, &right, &up);
Vec3 vFixedSpread = forward + (right * x * flSpread) + (up * y * flSpread);
vFixedSpread.Normalize();
vAverageSpread += vFixedSpread;
vBulletCorrections.push_back(vFixedSpread);
}
vAverageSpread /= static_cast<float>(iBulletsPerShot);
const auto cFixedSpread = std::ranges::min_element(vBulletCorrections,
[&](const Vec3& lhs, const Vec3& rhs)
{
return lhs.DistTo(vAverageSpread) < rhs.DistTo(vAverageSpread);
});
if (cFixedSpread == vBulletCorrections.end())
return;
Vec3 vFixedAngles{};
Math::VectorAngles(*cFixedSpread, vFixedAngles);
pCmd->viewangles += pCmd->viewangles - vFixedAngles;
Math::ClampAngles(pCmd->viewangles);
G::SilentAngles = true;
}

View File

@ -0,0 +1,30 @@
#pragma once
#include "../../../SDK/SDK.h"
class CNoSpreadHitscan
{
private:
int GetSeed(CUserCmd* pCmd);
float CalcMantissaStep(float val);
public:
void Reset(bool bResetPrint = false);
bool ShouldRun(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, bool bCreateMove = false);
void AskForPlayerPerf();
bool ParsePlayerPerf(bf_read& msgData);
void Run(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCmd* pCmd);
std::string GetFormat(int m_ServerTime);
bool bWaitingForPlayerPerf = false;
int bSynced = 0, iBestSync = 0;
float flServerTime = 0.f;
float flFloatTimeDelta = 0.f;
int iSeed = 0;
float flMantissaStep = 0;
};
ADD_FEATURE(CNoSpreadHitscan, NoSpreadHitscan)

View File

@ -0,0 +1,60 @@
#include "NoSpreadProjectile.h"
bool CNoSpreadProjectile::ShouldRun(CTFPlayer* pLocal, CTFWeaponBase* pWeapon)
{
if (G::WeaponType != EWeaponType::PROJECTILE)
return false;
switch (G::WeaponDefIndex)
{
case Soldier_m_RocketJumper:
case Demoman_s_StickyJumper:
return false;
}
return G::IsAttacking;
}
void CNoSpreadProjectile::Run(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCmd* pCmd)
{
if (!ShouldRun(pLocal, pWeapon))
return;
SDK::RandomSeed(SDK::SeedFileLineHash(MD5_PseudoRandom(pCmd->command_number) & 0x7FFFFFFF, "SelectWeightedSequence", 0));
for (int i = 0; i < 6; ++i)
SDK::RandomFloat();
switch (pWeapon->m_iWeaponID())
{
case TF_WEAPON_SYRINGEGUN_MEDIC:
{
// don't let the _local_ syringes fool you (is there a way to fix or sync them?)
pCmd->viewangles.x -= SDK::RandomFloat(-1.5f, 1.5f);
pCmd->viewangles.y -= SDK::RandomFloat(-1.5f, 1.5f);
G::PSilentAngles = true;
return;
}
case TF_WEAPON_COMPOUND_BOW:
{
// ShouldRun huntsman
if (pWeapon->As<CTFPipebombLauncher>()->m_flChargeBeginTime() > 0.f && I::GlobalVars->curtime - pWeapon->As<CTFPipebombLauncher>()->m_flChargeBeginTime() <= 5.0f)
return;
float flRand = float(SDK::RandomInt()) / 0x7FFF;
pCmd->viewangles.x -= -6 + flRand * 12.f;
flRand = float(SDK::RandomInt()) / 0x7FFF;
pCmd->viewangles.y -= -6 + flRand * 12.f;
G::PSilentAngles = true;
return;
}
}
if (G::WeaponDefIndex == Soldier_m_TheBeggarsBazooka)
{
pCmd->viewangles -= pWeapon->GetSpreadAngles() - I::EngineClient->GetViewAngles();
G::PSilentAngles = true;
}
}

View File

@ -0,0 +1,13 @@
#pragma once
#include "../../../SDK/SDK.h"
class CNoSpreadProjectile
{
private:
bool ShouldRun(CTFPlayer* pLocal, CTFWeaponBase* pWeapon);
public:
void Run(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCmd* pCmd);
};
ADD_FEATURE(CNoSpreadProjectile, NoSpreadProjectile)

View File

@ -0,0 +1,185 @@
#include "AntiAim.h"
#include "../../Players/PlayerUtils.h"
bool CAntiAim::AntiAimOn()
{
return Vars::AntiHack::AntiAim::Enabled.Value
&& (Vars::AntiHack::AntiAim::PitchReal.Value
|| Vars::AntiHack::AntiAim::PitchFake.Value
|| Vars::AntiHack::AntiAim::YawReal.Value
|| Vars::AntiHack::AntiAim::YawFake.Value
|| Vars::AntiHack::AntiAim::RealYawMode.Value
|| Vars::AntiHack::AntiAim::FakeYawMode.Value
|| Vars::AntiHack::AntiAim::RealYawOffset.Value
|| Vars::AntiHack::AntiAim::FakeYawOffset.Value);
}
bool CAntiAim::YawOn()
{
return Vars::AntiHack::AntiAim::Enabled.Value
&& (Vars::AntiHack::AntiAim::YawReal.Value
|| Vars::AntiHack::AntiAim::YawFake.Value
|| Vars::AntiHack::AntiAim::RealYawMode.Value
|| Vars::AntiHack::AntiAim::FakeYawMode.Value
|| Vars::AntiHack::AntiAim::RealYawOffset.Value
|| Vars::AntiHack::AntiAim::FakeYawOffset.Value);
}
bool CAntiAim::ShouldRun(CTFPlayer* pLocal)
{
const bool bPlayerReady = pLocal->IsAlive() && !pLocal->IsTaunting() && !pLocal->IsInBumperKart() && !pLocal->IsAGhost() && !G::IsAttacking;
const bool bMovementReady = pLocal->m_MoveType() <= 5 && !pLocal->IsCharging();
return bPlayerReady && bMovementReady && !G::Busy;
}
void CAntiAim::FakeShotAngles(CUserCmd* pCmd)
{
if (!Vars::AntiHack::AntiAim::InvalidShootPitch.Value || !G::IsAttacking || G::WeaponType != EWeaponType::HITSCAN)
return;
G::SilentAngles = true;
pCmd->viewangles.x = CalculateCustomRealPitch(-pCmd->viewangles.x, false) + 180;
pCmd->viewangles.y += 180;
}
float CAntiAim::EdgeDistance(CTFPlayer* pEntity, float flEdgeRayYaw, float flOffset)
{
// Main ray tracing area
Vec3 forward, right;
Math::AngleVectors({ 0, flEdgeRayYaw, 0 }, &forward, &right, nullptr);
Vec3 vCenter = pEntity->GetCenter() + right * flOffset;
Vec3 vEndPos = vCenter + forward * 300.f;
CGameTrace trace;
CTraceFilterWorldAndPropsOnly filter = {};
SDK::Trace(vCenter, vEndPos, MASK_SHOT | CONTENTS_GRATE, &filter, &trace);
vEdgeTrace.push_back({ vCenter, trace.endpos });
return (trace.startpos - trace.endpos).Length2D();
}
bool CAntiAim::GetEdge(CTFPlayer* pEntity, const float flEdgeOrigYaw, bool bUpPitch)
{
float flSize = pEntity->m_vecMaxs().y - pEntity->m_vecMins().y;
float flEdgeLeftDist = EdgeDistance(pEntity, flEdgeOrigYaw, -flSize);
float flEdgeRightDist = EdgeDistance(pEntity, flEdgeOrigYaw, flSize);
if (flEdgeLeftDist > 299.f && flEdgeRightDist > 299.f)
return bUpPitch;
return bUpPitch ? flEdgeLeftDist > flEdgeRightDist : flEdgeLeftDist < flEdgeRightDist;
}
void CAntiAim::RunOverlapping(CTFPlayer* pEntity, CUserCmd* pCmd, float& flRealYaw, bool bFake, float flEpsilon)
{
if (!Vars::AntiHack::AntiAim::AntiOverlap.Value || bFake)
return;
float flFakeYaw = GetBaseYaw(pEntity, pCmd, true) + GetYawOffset(pEntity, true);
const float flYawDiff = RAD2DEG(Math::AngleDiffRad(DEG2RAD(flRealYaw), DEG2RAD(flFakeYaw)));
if (fabsf(flYawDiff) < flEpsilon)
flRealYaw += flYawDiff > 0 ? flEpsilon : -flEpsilon;
}
float CAntiAim::GetYawOffset(CTFPlayer* pEntity, bool bFake)
{
const int iMode = bFake ? Vars::AntiHack::AntiAim::YawFake.Value : Vars::AntiHack::AntiAim::YawReal.Value;
const bool bUpPitch = bFake ? Vars::AntiHack::AntiAim::PitchFake.Value == 1 : Vars::AntiHack::AntiAim::PitchReal.Value == 1;
switch (iMode)
{
case 0: return 0.f;
case 1: return 90.f;
case 2: return -90.f;
case 3: return 180.f;
case 4: return fmod(I::GlobalVars->tickcount * Vars::AntiHack::AntiAim::SpinSpeed.Value + 180.f, 360.f) - 180.f;
case 5: return (GetEdge(pEntity, I::EngineClient->GetViewAngles().y, bUpPitch) ? 1 : -1) * (bFake ? -90 : 90);
}
return 0.f;
}
float CAntiAim::GetBaseYaw(CTFPlayer* pLocal, CUserCmd* pCmd, bool bFake)
{
const int iMode = bFake ? Vars::AntiHack::AntiAim::FakeYawMode.Value : Vars::AntiHack::AntiAim::RealYawMode.Value;
const float flOffset = bFake ? Vars::AntiHack::AntiAim::FakeYawOffset.Value : Vars::AntiHack::AntiAim::RealYawOffset.Value;
switch (iMode) // 0 offset, 1 at player
{
case 0: return pCmd->viewangles.y + flOffset;
case 1:
{
float flSmallestAngleTo = 0.f; float flSmallestFovTo = 360.f;
for (auto pEntity : H::Entities.GetGroup(EGroupType::PLAYERS_ENEMIES))
{
auto pPlayer = pEntity->As<CTFPlayer>();
if (!pPlayer->IsAlive() || pPlayer->IsDormant())
continue;
PlayerInfo_t pi{};
if (I::EngineClient->GetPlayerInfo(pPlayer->entindex(), &pi) && F::PlayerUtils.IsIgnored(pi.friendsID))
continue;
const Vec3 vAngleTo = Math::CalcAngle(pLocal->GetAbsOrigin(), pPlayer->GetAbsOrigin());
const float flFOVTo = Math::CalcFov(I::EngineClient->GetViewAngles(), vAngleTo);
if (flFOVTo < flSmallestFovTo) { flSmallestAngleTo = vAngleTo.y; flSmallestFovTo = flFOVTo; }
}
return (flSmallestFovTo == 360.f ? pCmd->viewangles.y + flOffset : flSmallestAngleTo + flOffset);
}
}
return pCmd->viewangles.y;
}
float CAntiAim::GetYaw(CTFPlayer* pLocal, CUserCmd* pCmd, bool bFake)
{
float flYaw = GetBaseYaw(pLocal, pCmd, bFake) + GetYawOffset(pLocal, bFake);
RunOverlapping(pLocal, pCmd, flYaw, bFake);
return flYaw;
}
float CAntiAim::CalculateCustomRealPitch(float flWishPitch, bool bFakeDown)
{
return bFakeDown ? 720 + flWishPitch : -720 + flWishPitch;
}
float CAntiAim::GetPitch(float flCurPitch)
{
const int iFake = Vars::AntiHack::AntiAim::PitchFake.Value, iReal = Vars::AntiHack::AntiAim::PitchReal.Value;
switch (iReal)
{
case 1: return iFake ? CalculateCustomRealPitch(-89.f, iFake - 1) : -89.f;
case 2: return iFake ? CalculateCustomRealPitch(89.f, iFake - 1) : 89.f;
case 3: return iFake ? CalculateCustomRealPitch(0.f, iFake - 1) : 0.f;
}
return iFake ? -89.f + (89.f * (iFake - 1)) : flCurPitch;
}
void CAntiAim::Run(CTFPlayer* pLocal, CUserCmd* pCmd, bool* pSendPacket)
{
vEdgeTrace.clear();
G::AntiAim = pLocal && AntiAimOn() && ShouldRun(pLocal);
FakeShotAngles(pCmd);
if (!G::AntiAim)
{
vRealAngles = { pCmd->viewangles.x, pCmd->viewangles.y };
vFakeAngles = { pCmd->viewangles.x, pCmd->viewangles.y };
return;
}
Vec2& vAngles = *pSendPacket ? vFakeAngles : vRealAngles;
vAngles = {
GetPitch(pCmd->viewangles.x),
GetYaw(pLocal, pCmd, *pSendPacket)
};
SDK::FixMovement(pCmd, vAngles);
pCmd->viewangles.x = vAngles.x;
pCmd->viewangles.y = vAngles.y;
}

View File

@ -0,0 +1,31 @@
#pragma once
#include "../../../SDK/SDK.h"
class CAntiAim
{
private:
void FakeShotAngles(CUserCmd* pCmd);
float EdgeDistance(CTFPlayer* pEntity, float flEdgeRayYaw, float flOffset);
void RunOverlapping(CTFPlayer* pEntity, CUserCmd* pCmd, float& flRealYaw, bool bFake, float flEpsilon = 45.f);
float GetYawOffset(CTFPlayer* pEntity, bool bFake);
float GetBaseYaw(CTFPlayer* pLocal, CUserCmd* pCmd, bool bFake);
float GetYaw(CTFPlayer* pLocal, CUserCmd* pCmd, bool bFake);
float CalculateCustomRealPitch(float flWishPitch, bool bFakeDown);
float GetPitch(float flCurPitch);
public:
bool AntiAimOn();
bool YawOn();
bool ShouldRun(CTFPlayer* pLocal);
bool GetEdge(CTFPlayer* pEntity, float flEdgeOrigYaw, bool bUpPitch);
void Run(CTFPlayer* pLocal, CUserCmd* pCmd, bool* pSendPacket);
Vec2 vFakeAngles = {};
Vec2 vRealAngles = {};
std::vector<std::pair<Vec3, Vec3>> vEdgeTrace = {};
};
ADD_FEATURE(CAntiAim, AntiAim)

View File

@ -0,0 +1,96 @@
#include "FakeLag.h"
bool CFakeLag::IsAllowed(CTFPlayer* pLocal)
{
const int iMaxSend = std::min(24 - G::ShiftedTicks, 22);
const bool bVar = Vars::CL_Move::Fakelag::Fakelag.Value || bPreservingBlast || bUnducking;
const bool bChargePrio = (iMaxSend > 0 && G::ChokeAmount < iMaxSend) || !G::ShiftedTicks;
const bool bAttacking = G::IsAttacking && Vars::CL_Move::Fakelag::UnchokeOnAttack.Value;
const bool bNotAir = Vars::CL_Move::Fakelag::Options.Value & (1 << 2) && !pLocal->OnSolid();
if (!bVar || !bChargePrio || bAttacking || bNotAir)
return false;
if (bPreservingBlast || bUnducking)
return true;
if (G::ShiftedGoal != G::ShiftedTicks)
return false;
const bool bMoving = !(Vars::CL_Move::Fakelag::Options.Value & (1 << 0)) || pLocal->m_vecVelocity().Length2D() > 10.f;
if (!bMoving)
return false;
switch (Vars::CL_Move::Fakelag::Fakelag.Value)
{
case 1:
case 2:
return G::ChokeAmount < G::ChokeGoal;
case 3:
{
const Vec3 vDelta = vLastPosition - pLocal->m_vecOrigin();
return vDelta.Length2DSqr() < 4096.f;
}
}
return false;
}
void CFakeLag::PreserveBlastJump(CTFPlayer* pLocal)
{
bPreservingBlast = false;
if (!pLocal || !pLocal->IsAlive() || pLocal->IsAGhost() || !pLocal->IsPlayer() || G::ShiftedTicks == G::MaxShift)
return;
const bool bVar = Vars::CL_Move::Fakelag::RetainBlastJump.Value && Vars::Misc::Movement::Bunnyhop.Value;
static bool bOldSolid = false; const bool bPlayerReady = pLocal->OnSolid() || bOldSolid; bOldSolid = pLocal->OnSolid();
const bool bCanPreserve = pLocal->m_iClass() == TF_CLASS_SOLDIER && pLocal->InCond(TF_COND_BLASTJUMPING);
const bool bValid = G::Buttons & IN_JUMP && !pLocal->IsDucking();
bPreservingBlast = bVar && bPlayerReady && bCanPreserve && bValid;
}
void CFakeLag::Unduck(CTFPlayer* pLocal, CUserCmd* pCmd)
{
if (!pLocal || !pLocal->IsAlive() || pLocal->IsAGhost())
return;
const bool bVar = Vars::CL_Move::Fakelag::Options.Value & (1 << 1);
const bool bPlayerReady = pLocal->IsPlayer() && pLocal->OnSolid() && pLocal->IsDucking() && !(pCmd->buttons & IN_DUCK);
bUnducking = bVar && bPlayerReady;
}
void CFakeLag::Prediction(CTFPlayer* pLocal, CUserCmd* pCmd)
{
PreserveBlastJump(pLocal);
Unduck(pLocal, pCmd);
}
void CFakeLag::Run(CTFPlayer* pLocal, CUserCmd* pCmd, bool* pSendPacket)
{
if (!pLocal)
return;
Prediction(pLocal, pCmd);
// Set the selected choke amount (if not random)
switch (Vars::CL_Move::Fakelag::Fakelag.Value)
{
case 1: G::ChokeGoal = Vars::CL_Move::Fakelag::PlainTicks.Value; break;
case 2: if (!G::ChokeGoal) G::ChokeGoal = SDK::StdRandomInt(Vars::CL_Move::Fakelag::RandomTicks.Value.Min, Vars::CL_Move::Fakelag::RandomTicks.Value.Max); break;
case 3: G::ChokeGoal = 22; break;
}
// Are we even allowed to choke?
if (!IsAllowed(pLocal))
{
vLastPosition = pLocal->m_vecOrigin();
G::ChokeAmount = G::ChokeGoal = 0;
bUnducking = false;
return;
}
*pSendPacket = false;
G::ChokeAmount++;
}

View File

@ -0,0 +1,19 @@
#pragma once
#include "../../../SDK/SDK.h"
class CFakeLag
{
Vec3 vLastPosition;
bool bPreservingBlast = false;
bool bUnducking = false;
bool IsAllowed(CTFPlayer* pLocal);
void Prediction(CTFPlayer* pLocal, CUserCmd* pCmd);
void PreserveBlastJump(CTFPlayer* pLocal);
void Unduck(CTFPlayer* pLocal, CUserCmd* pCmd);
public:
void Run(CTFPlayer* pLocal, CUserCmd* pCmd, bool* pSendPacket);
};
ADD_FEATURE(CFakeLag, FakeLag)

View File

@ -0,0 +1,29 @@
#include "PacketManip.h"
#include "../Visuals/FakeAngle/FakeAngle.h"
bool CPacketManip::WillTimeOut()
{
return I::ClientState->chokedcommands >= 21;
}
bool CPacketManip::AntiAimCheck(CTFPlayer* pLocal)
{
return F::AntiAim.YawOn() && pLocal && F::AntiAim.ShouldRun(pLocal) && I::ClientState->chokedcommands < 3 && !((G::DoubleTap || G::Warp) && G::ShiftedTicks == G::ShiftedGoal);
}
void CPacketManip::Run(CTFPlayer* pLocal, CUserCmd* pCmd, bool* pSendPacket)
{
F::FakeAngle.DrawChams = Vars::CL_Move::Fakelag::Fakelag.Value || F::AntiAim.AntiAimOn();
*pSendPacket = true;
const bool bTimeout = WillTimeOut(); // prevent overchoking by just not running anything below if we believe it will cause us to time out
if (!bTimeout)
F::FakeLag.Run(pLocal, pCmd, pSendPacket);
else
G::ChokeAmount = 0;
if (!bTimeout && AntiAimCheck(pLocal) && !G::PSilentAngles)
*pSendPacket = false;
}

View File

@ -0,0 +1,15 @@
#pragma once
#include "../../SDK/SDK.h"
#include "FakeLag/FakeLag.h"
#include "AntiAim/AntiAim.h"
class CPacketManip
{
bool WillTimeOut();
bool AntiAimCheck(CTFPlayer* pLocal);
public:
void Run(CTFPlayer* pLocal, CUserCmd* pCmd, bool* pSendPacket);
};
ADD_FEATURE(CPacketManip, PacketManip)

View File

@ -0,0 +1,170 @@
#include "PlayerCore.h"
#include "PlayerUtils.h"
#include "../Configs/Configs.h"
void CPlayerlistCore::Run()
{
static Timer saveTimer{ };
if (saveTimer.Run(1000))
{
LoadTags();
SaveTags();
LoadPlayers();
SavePlayers();
}
}
void CPlayerlistCore::SavePlayers()
{
if (!F::PlayerUtils.bSavePlayers)
return;
try
{
boost::property_tree::ptree writeTree;
// Put map entries into ptree
for (const auto& [friendsID, vTags] : F::PlayerUtils.mPlayerTags)
{
// don't fill with pointless info
if (!vTags.size())
continue;
boost::property_tree::ptree tagTree;
for (const auto& sTag : vTags)
{
boost::property_tree::ptree child; child.put("", sTag);
tagTree.push_back(std::make_pair("", child));
}
writeTree.put_child(std::to_string(friendsID), tagTree);
}
// Save the file
write_json(F::Configs.sConfigPath + "\\Core\\Players.json", writeTree);
F::PlayerUtils.bSavePlayers = false;
}
catch (...) {}
}
void CPlayerlistCore::LoadPlayers()
{
if (!F::PlayerUtils.bLoadPlayers)
return;
try
{
if (std::filesystem::exists(F::Configs.sConfigPath + "\\Core\\Players.json"))
{
boost::property_tree::ptree readTree;
read_json(F::Configs.sConfigPath + "\\Core\\Players.json", readTree);
F::PlayerUtils.mPlayerTags.clear();
for (auto& player : readTree)
{
uint32_t friendsID = std::stoi(player.first);
for (auto& tag : player.second)
{
std::string sTag = std::string(tag.first.data()).empty() ? tag.second.data() : tag.first.data(); // account for dumb old format
PriorityLabel_t plTag;
if (F::PlayerUtils.GetTag(sTag, &plTag) && !plTag.Assignable)
continue;
if (!F::PlayerUtils.HasTag(friendsID, sTag))
F::PlayerUtils.AddTag(friendsID, sTag, false);
}
}
}
// support legacy format & convert over
if (std::filesystem::exists(F::Configs.sConfigPath + "\\Core\\Playerlist.json"))
{
boost::property_tree::ptree readTree;
read_json(F::Configs.sConfigPath + "\\Core\\Playerlist.json", readTree);
for (auto& it : readTree)
{
uint32_t friendsID = std::stoi(it.first);
int iPriority = 2;
if (auto getValue = it.second.get_optional<int>("Mode")) { iPriority = std::max(*getValue, 0); }
if (iPriority == 4)
F::PlayerUtils.AddTag(friendsID, "Cheater", false);
if (iPriority == 1)
F::PlayerUtils.AddTag(friendsID, "Ignored", false);
}
}
F::PlayerUtils.bLoadPlayers = false;
}
catch (...) {}
}
void CPlayerlistCore::SaveTags()
{
if (!F::PlayerUtils.bSaveTags)
return;
try
{
boost::property_tree::ptree writeTree;
// Put map entries into ptree
for (const auto& [sTag, plTag] : F::PlayerUtils.mTags)
{
boost::property_tree::ptree tagTree;
tagTree.put_child("Color", F::Configs.ColorToTree(plTag.Color));
tagTree.put("Priority", plTag.Priority);
tagTree.put("Label", plTag.Label);
writeTree.put_child(sTag, tagTree);
}
// Save the file
write_json(F::Configs.sConfigPath + "\\Core\\Tags.json", writeTree);
F::PlayerUtils.bSaveTags = false;
}
catch (...) {}
}
void CPlayerlistCore::LoadTags()
{
if (!F::PlayerUtils.bLoadTags)
return;
try
{
if (std::filesystem::exists(F::Configs.sConfigPath + "\\Core\\Tags.json"))
{
boost::property_tree::ptree readTree;
read_json(F::Configs.sConfigPath + "\\Core\\Tags.json", readTree);
F::PlayerUtils.mTags = {
{ "Default", { { 200, 200, 200, 255 }, 0, false, false, true } },
{ "Ignored", { { 200, 200, 200, 255 }, -1, false, true, true } },
{ "Cheater", { { 255, 100, 100, 255 }, 1, false, true, true } },
{ "Friend", { { 100, 255, 100, 255 }, 0, true, false, true } }
};
for (auto& it : readTree)
{
PriorityLabel_t plTag = {};
if (const auto getChild = it.second.get_child_optional("Color")) { F::Configs.TreeToColor(*getChild, plTag.Color); }
if (auto getValue = it.second.get_optional<int>("Priority")) { plTag.Priority = *getValue; }
if (auto getValue = it.second.get_optional<bool>("Label")) { plTag.Label = *getValue; }
std::string sTag = it.first;
F::PlayerUtils.mTags[sTag].Color = plTag.Color;
F::PlayerUtils.mTags[sTag].Priority = plTag.Priority;
F::PlayerUtils.mTags[sTag].Label = plTag.Label;
}
}
F::PlayerUtils.bLoadTags = false;
}
catch (...) {}
}

View File

@ -0,0 +1,15 @@
#pragma once
#include "../../SDK/SDK.h"
class CPlayerlistCore
{
void SavePlayers();
void LoadPlayers();
void SaveTags();
void LoadTags();
public:
void Run();
};
ADD_FEATURE(CPlayerlistCore, PlayerCore)

Some files were not shown because too many files have changed in this diff Show More