diff --git a/AMBuilder b/AMBuilder
index 1322ba33..25750102 100644
--- a/AMBuilder
+++ b/AMBuilder
@@ -7,6 +7,7 @@ projectName = 'sigsegv'
sourceFiles = [
# 'src/common.h',
'libs/lz4/lib/lz4.c',
+ 'libs/lodepng/lodepng.cpp',
os.path.join(Extension.sm_root, 'public', 'asm', 'asm.c'),
'src/sm/MemoryUtils.cpp',
'src/se2007/meshutils.cpp',
@@ -39,6 +40,7 @@ sourceFiles = [
'src/util/firehose_base.cpp',
'src/util/firehose_send.cpp',
'src/util/firehose_recv.cpp',
+ 'src/util/vgui.cpp',
'src/stub/baseentity.cpp',
'src/stub/gamerules.cpp',
'src/stub/misc.cpp',
@@ -63,6 +65,7 @@ sourceFiles = [
'src/stub/upgrades.cpp',
'src/stub/lagcompensation.cpp',
'src/stub/fonts.cpp',
+ 'src/stub/vgui.cpp',
'src/link/link.cpp',
'src/link/nextbot1.cpp',
'src/link/nextbot2.cpp',
@@ -78,26 +81,26 @@ sourceFiles = [
'src/mod/ai/rocketjump.cpp',
'src/mod/ai/wrapassassin_altfire.cpp',
'src/mod/ai/nextboteventresponder_hooks.cpp',
- 'src/mod/ai/mvm_defender_bots.cpp',
- 'src/mod/ai/mvm_defender_bots/quirks/isfakeclient.cpp',
- 'src/mod/ai/mvm_defender_bots/quirks/isbot.cpp',
- 'src/mod/ai/mvm_defender_bots/quirks/isbotoftype.cpp',
- 'src/mod/ai/mvm_defender_bots/quirks/getlastknownarea.cpp',
- 'src/mod/ai/mvm_defender_bots/quirks/mannvsmachinemode.cpp',
- 'src/mod/ai/mvm_defender_bots/quirks/steamid.cpp',
- 'src/mod/ai/mvm_defender_bots/trackers.cpp',
- 'src/mod/ai/mvm_defender_bots/trackers/credits.cpp',
- 'src/mod/ai/mvm_defender_bots/trackers/flags.cpp',
- 'src/mod/ai/mvm_defender_bots/trackers/gates.cpp',
- 'src/mod/ai/mvm_defender_bots/trackers/tanks.cpp',
- 'src/mod/ai/mvm_defender_bots/actions/defender.cpp',
- 'src/mod/ai/mvm_defender_bots/actions/attack_tank.cpp',
- 'src/mod/ai/mvm_defender_bots/actions/defend_gate.cpp',
- 'src/mod/ai/mvm_defender_bots/actions/collect_money.cpp',
- 'src/mod/ai/mvm_defender_bots/actions/mark_giant.cpp',
- 'src/mod/ai/mvm_defender_bots/actions/goto_upgrade_station.cpp',
- 'src/mod/ai/mvm_defender_bots/actions/purchase_upgrades.cpp',
- 'src/mod/ai/mvm_defender_bots/actions/prewave.cpp',
+# 'src/mod/ai/mvm_defender_bots.cpp',
+# 'src/mod/ai/mvm_defender_bots/quirks/isfakeclient.cpp',
+# 'src/mod/ai/mvm_defender_bots/quirks/isbot.cpp',
+# 'src/mod/ai/mvm_defender_bots/quirks/isbotoftype.cpp',
+# 'src/mod/ai/mvm_defender_bots/quirks/getlastknownarea.cpp',
+# 'src/mod/ai/mvm_defender_bots/quirks/mannvsmachinemode.cpp',
+# 'src/mod/ai/mvm_defender_bots/quirks/steamid.cpp',
+# 'src/mod/ai/mvm_defender_bots/trackers.cpp',
+# 'src/mod/ai/mvm_defender_bots/trackers/credits.cpp',
+# 'src/mod/ai/mvm_defender_bots/trackers/flags.cpp',
+# 'src/mod/ai/mvm_defender_bots/trackers/gates.cpp',
+# 'src/mod/ai/mvm_defender_bots/trackers/tanks.cpp',
+# 'src/mod/ai/mvm_defender_bots/actions/defender.cpp',
+# 'src/mod/ai/mvm_defender_bots/actions/attack_tank.cpp',
+# 'src/mod/ai/mvm_defender_bots/actions/defend_gate.cpp',
+# 'src/mod/ai/mvm_defender_bots/actions/collect_money.cpp',
+# 'src/mod/ai/mvm_defender_bots/actions/mark_giant.cpp',
+# 'src/mod/ai/mvm_defender_bots/actions/goto_upgrade_station.cpp',
+# 'src/mod/ai/mvm_defender_bots/actions/purchase_upgrades.cpp',
+# 'src/mod/ai/mvm_defender_bots/actions/prewave.cpp',
'src/mod/attr/undocumented.cpp',
'src/mod/bot/kill_before_forcespec.cpp',
'src/mod/bot/medieval_nonmelee.cpp',
@@ -106,6 +109,7 @@ sourceFiles = [
'src/mod/bot/isspacetospawnhere_scale.cpp',
'src/mod/canteen/share_recall_canteen.cpp',
'src/mod/cond/reprogrammed.cpp',
+ 'src/mod/cond/enhanced_cmds.cpp',
'src/mod/credits/spawn_autocollect.cpp',
# 'src/mod/credits/magnet_disable.cpp',
'src/mod/debug/backtrace.cpp',
@@ -146,7 +150,8 @@ sourceFiles = [
'src/mod/debug/tele_autodetonate.cpp',
'src/mod/debug/scale_rate.cpp',
'src/mod/debug/melee_trace.cpp',
- 'src/mod/debug/console_scramble.cpp',
+ 'src/mod/debug/console_scramble_v1.cpp',
+ 'src/mod/debug/console_scramble_v2.cpp',
'src/mod/debug/sound_leak.cpp',
'src/mod/debug/nextbot_input.cpp',
'src/mod/debug/static_props.cpp',
@@ -165,6 +170,8 @@ sourceFiles = [
'src/mod/debug/upgrade_tiers.cpp',
'src/mod/debug/mvm_shield_fps.cpp',
'src/mod/debug/rage.cpp',
+ 'src/mod/debug/ctfbotproxy.cpp',
+ 'src/mod/debug/sentrybuster_mannhattan.cpp',
# 'src/mod/debug/scheme_load.cpp',
# 'src/mod/debug/override_step_sound.cpp',
'src/mod/demo/stringtable_limit.cpp',
@@ -175,6 +182,7 @@ sourceFiles = [
'src/mod/etc/laserdot_fix.cpp',
'src/mod/etc/instant_scaling.cpp',
'src/mod/etc/mm_spoof.cpp',
+ 'src/mod/etc/melee_ignore_teammates.cpp',
'src/mod/mvm/changeclass_anytime.cpp',
'src/mod/mvm/disposable_dispenser.cpp',
'src/mod/mvm/explosive_headshot_on_everything.cpp',
@@ -184,8 +192,11 @@ sourceFiles = [
'src/mod/mvm/dominations.cpp',
'src/mod/mvm/friendlyfire.cpp',
'src/mod/mvm/gib_improvements.cpp',
+ 'src/mod/mvm/no_halloween_souls.cpp',
+ 'src/mod/mvm/robosapper_override.cpp',
'src/mod/perf/flame_breakable_collision.cpp',
'src/mod/perf/medigun_shield_damage_events.cpp',
+ 'src/mod/perf/medigun_shield_damage_interval.cpp',
'src/mod/pop/eventpopfile_improvements.cpp',
# 'src/mod/pop/extattr/parse.cpp',
# 'src/mod/pop/extattr/alwaysfireweaponalt.cpp',
@@ -228,7 +239,14 @@ sourceFiles = [
'src/mod/util/debugoverlay_font_v3.cpp',
'src/mod/util/override_vertex_limit.cpp',
'src/mod/util/entity_overlays.cpp',
+ 'src/mod/util/serialize_spew.cpp',
+ 'src/mod/util/screenshot_png.cpp',
+ 'src/mod/util/dtwatch.cpp',
+ 'src/mod/util/confilter.cpp',
+# 'src/mod/util/netmsg_server.cpp',
+# 'src/mod/util/netmsg_client.cpp',
# 'src/mod/util/client_cmds.cpp',
+ 'src/mod/vgui/test.cpp',
'src/mod/visualize/airblast_box.cpp',
'src/mod/visualize/airblast_cone.cpp',
'src/mod/visualize/airblast_vectors.cpp',
@@ -246,6 +264,8 @@ sourceFiles = [
'src/mod/visualize/sapper_range.cpp',
'src/mod/visualize/huntsman.cpp',
'src/mod/visualize/ammo_counts.cpp',
+ 'src/mod/visualize/backstab.cpp',
+ 'src/mod/visualize/conds.cpp',
]
###############
@@ -292,7 +312,9 @@ binary.compiler.linkflags += [
binary.compiler.includes += [
os.path.join(builder.buildPath), # for autogen.h
os.path.join(builder.currentSourcePath, 'libs', 'lz4', 'lib'),
+ os.path.join(builder.currentSourcePath, 'libs', 'lodepng'),
os.path.join(builder.currentSourcePath, 'libs', 'capstone', 'include'),
+# os.path.join(builder.currentSourcePath, 'libs', 'cccapstone', 'cppbindings'),
os.path.join(builder.currentSourcePath, 'libs', 'ann', 'include'),
]
diff --git a/MSVC14/sigsegv.sln b/MSVC14/sigsegv.sln
index 31f8d9c5..270a2837 100755
--- a/MSVC14/sigsegv.sln
+++ b/MSVC14/sigsegv.sln
@@ -1,6 +1,6 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
-VisualStudioVersion = 14.0.24720.0
+VisualStudioVersion = 14.0.25420.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sigsegv", "sigsegv.vcxproj", "{B3E797CF-4E77-4C9D-B8A8-7589B6902206}"
EndProject
@@ -18,7 +18,15 @@ Project("{911E67C6-3D85-4FCE-B560-20A9C3E3FF48}") = "hl2", "C:\Program Files (x8
AttachLaunchAction = No
EndProjectSection
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{C2774530-5E69-42AA-AA01-6EC3173D8E14}"
+ ProjectSection(SolutionItems) = preProject
+ Performance1.psess = Performance1.psess
+ EndProjectSection
+EndProject
Global
+ GlobalSection(Performance) = preSolution
+ HasPerformanceSessions = true
+ EndGlobalSection
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
diff --git a/MSVC14/sigsegv.vcxproj b/MSVC14/sigsegv.vcxproj
old mode 100644
new mode 100755
index 30dc347e..595e3f20
--- a/MSVC14/sigsegv.vcxproj
+++ b/MSVC14/sigsegv.vcxproj
@@ -68,12 +68,13 @@
- /D SE_EPISODEONE=1 /D SE_DARKMESSIAH=2 /D SE_ORANGEBOX=3 /D SE_BLOODYGOODTIME=4 /D SE_EYE=5 /D SE_CSS=6 /D SE_ORANGEBOXVALVE=7 /D SE_LEFT4DEAD=8 /D SE_LEFT4DEAD2=9 /D SE_ALIENSWARM=10 /D SE_PORTAL2=11 /D SE_CSGO=12
+
+
Disabled
- ..\src;..\src\sdk;$(SOURCEMOD18);$(SOURCEMOD18)\public;$(SOURCEMOD18)\public\amtl;$(SOURCEMOD18)\public\extensions;$(SOURCEMOD18)\sourcepawn\include;$(HL2SDKOBVALVE)\common;$(HL2SDKOBVALVE)\game\shared;$(HL2SDKOBVALVE)\public;$(HL2SDKOBVALVE)\public\engine;$(HL2SDKOBVALVE)\public\game\server;$(HL2SDKOBVALVE)\public\tier0;$(HL2SDKOBVALVE)\public\tier1;$(HL2SDKOBVALVE)\public\toolframework;$(HL2SDKOBVALVE)\public\vstdlib;$(MMSOURCE110)\core;$(MMSOURCE110)\core\sourcehook;..\libs\boost_1_62_0_b2;..\libs\lz4\lib;..\libs\distorm\include;..\libs\capstone\include;..\libs\udis86;..\libs\ann\include;%(AdditionalIncludeDirectories)
- WIN32;_DEBUG;_WINDOWS;_USRDLL;SDK_EXPORTS;_CRT_SECURE_NO_DEPRECATE;SOURCEMOD_BUILD;SOURCE_ENGINE=7;%(PreprocessorDefinitions)
+ ..\src;..\src\sdk;$(SOURCEMOD18);$(SOURCEMOD18)\public;$(SOURCEMOD18)\public\amtl;$(SOURCEMOD18)\public\extensions;$(SOURCEMOD18)\sourcepawn\include;$(HL2SDKOBVALVE)\common;$(HL2SDKOBVALVE)\game\shared;$(HL2SDKOBVALVE)\public;$(HL2SDKOBVALVE)\public\engine;$(HL2SDKOBVALVE)\public\game\server;$(HL2SDKOBVALVE)\public\tier0;$(HL2SDKOBVALVE)\public\tier1;$(HL2SDKOBVALVE)\public\toolframework;$(HL2SDKOBVALVE)\public\vstdlib;$(MMSOURCE110)\core;$(MMSOURCE110)\core\sourcehook;..\libs\boost_1_62_0_b2;..\libs\lz4\lib;..\libs\lodepng;..\libs\distorm\include;..\libs\capstone\include;..\libs\cccapstone\cppbindings;..\libs\udis86;..\libs\ann\include;%(AdditionalIncludeDirectories)
+ WIN32;_DEBUG;_WINDOWS;_USRDLL;SDK_EXPORTS;_CRT_SECURE_NO_DEPRECATE;SOURCEMOD_BUILD;SOURCE_ENGINE=7;SE_EPISODEONE=1;SE_DARKMESSIAH=2;SE_ORANGEBOX=3;SE_BLOODYGOODTIME=4;SE_EYE=5;SE_CSS=6;SE_ORANGEBOXVALVE=7;SE_LEFT4DEAD=8;SE_LEFT4DEAD2=9;SE_ALIENSWARM=10;SE_PORTAL2=11;SE_CSGO=12;%(PreprocessorDefinitions)
false
- UninitializedLocalUsageCheck
+ EnableFastChecks
MultiThreadedDebug
NotSet
true
@@ -87,6 +88,7 @@
$(IntDir)\%(Directory)\
+ 4594
$(HL2SDKOBVALVE)\lib\public\tier0.lib;$(HL2SDKOBVALVE)\lib\public\tier1.lib;$(HL2SDKOBVALVE)\lib\public\vstdlib.lib;$(HL2SDKOBVALVE)\lib\public\mathlib.lib;legacy_stdio_definitions.lib;dbghelp.lib;ws2_32.lib;..\libs\distorm\distorm.lib;..\libs\capstone\msvc\Release\capstone.lib;..\libs\udis86\BuildVS2010\Build\Lib\x86\libudis86.lib;%(AdditionalDependencies)
@@ -118,10 +120,10 @@
- /MP /D SE_EPISODEONE=1 /D SE_DARKMESSIAH=2 /D SE_ORANGEBOX=3 /D SE_BLOODYGOODTIME=4 /D SE_EYE=5 /D SE_CSS=6 /D SE_ORANGEBOXVALVE=7 /D SE_LEFT4DEAD=8 /D SE_LEFT4DEAD2=9 /D SE_ALIENSWARM=10 /D SE_PORTAL2=11 /D SE_CSGO=12
+ /MP
Speed
- ..\src;..\src\sdk;$(SOURCEMOD18);$(SOURCEMOD18)\public;$(SOURCEMOD18)\public\amtl;$(SOURCEMOD18)\public\extensions;$(SOURCEMOD18)\sourcepawn\include;$(HL2SDKOBVALVE)\common;$(HL2SDKOBVALVE)\game\shared;$(HL2SDKOBVALVE)\public;$(HL2SDKOBVALVE)\public\engine;$(HL2SDKOBVALVE)\public\game\server;$(HL2SDKOBVALVE)\public\tier0;$(HL2SDKOBVALVE)\public\tier1;$(HL2SDKOBVALVE)\public\toolframework;$(HL2SDKOBVALVE)\public\vstdlib;$(MMSOURCE110)\core;$(MMSOURCE110)\core\sourcehook;..\libs\boost_1_62_0_b2;..\libs\lz4\lib;..\libs\distorm\include;..\libs\capstone\include;..\libs\udis86;..\libs\ann\include;%(AdditionalIncludeDirectories)
- WIN32;_WINDOWS;_USRDLL;SDK_EXPORTS;_CRT_SECURE_NO_DEPRECATE;SOURCEMOD_BUILD;SOURCE_ENGINE=7;%(PreprocessorDefinitions)
+ ..\src;..\src\sdk;$(SOURCEMOD18);$(SOURCEMOD18)\public;$(SOURCEMOD18)\public\amtl;$(SOURCEMOD18)\public\extensions;$(SOURCEMOD18)\sourcepawn\include;$(HL2SDKOBVALVE)\common;$(HL2SDKOBVALVE)\game\shared;$(HL2SDKOBVALVE)\public;$(HL2SDKOBVALVE)\public\engine;$(HL2SDKOBVALVE)\public\game\server;$(HL2SDKOBVALVE)\public\tier0;$(HL2SDKOBVALVE)\public\tier1;$(HL2SDKOBVALVE)\public\toolframework;$(HL2SDKOBVALVE)\public\vstdlib;$(MMSOURCE110)\core;$(MMSOURCE110)\core\sourcehook;..\libs\boost_1_62_0_b2;..\libs\lz4\lib;..\libs\lodepng;..\libs\distorm\include;..\libs\capstone\include;..\libs\cccapstone\cppbindings;..\libs\udis86;..\libs\ann\include;%(AdditionalIncludeDirectories)
+ WIN32;_WINDOWS;_USRDLL;SDK_EXPORTS;_CRT_SECURE_NO_DEPRECATE;SOURCEMOD_BUILD;SOURCE_ENGINE=7;SE_EPISODEONE=1;SE_DARKMESSIAH=2;SE_ORANGEBOX=3;SE_BLOODYGOODTIME=4;SE_EYE=5;SE_CSS=6;SE_ORANGEBOXVALVE=7;SE_LEFT4DEAD=8;SE_LEFT4DEAD2=9;SE_ALIENSWARM=10;SE_PORTAL2=11;SE_CSGO=12;%(PreprocessorDefinitions)
MultiThreaded
NotSet
true
@@ -136,6 +138,7 @@
true
+ 4594
$(HL2SDKOBVALVE)\lib\public\tier0.lib;$(HL2SDKOBVALVE)\lib\public\tier1.lib;$(HL2SDKOBVALVE)\lib\public\vstdlib.lib;$(HL2SDKOBVALVE)\lib\public\mathlib.lib;legacy_stdio_definitions.lib;dbghelp.lib;ws2_32.lib;..\libs\distorm\distorm.lib;..\libs\capstone\msvc\Release\capstone.lib;..\libs\udis86\BuildVS2010\Build\Lib\x86\libudis86.lib;%(AdditionalDependencies)
@@ -173,6 +176,7 @@
NotUsing
NotUsing
+
NotUsing
NotUsing
@@ -210,7 +214,8 @@
-
+
+
@@ -249,6 +254,8 @@
+
+
@@ -290,12 +297,16 @@
+
NotUsing
NotUsing
-
-
+
+
+
+
+
@@ -316,4 +327,4 @@
-
+
\ No newline at end of file
diff --git a/MSVC14/sigsegv.vcxproj.filters b/MSVC14/sigsegv.vcxproj.filters
old mode 100644
new mode 100755
index c646eb53..8707cea2
--- a/MSVC14/sigsegv.vcxproj.filters
+++ b/MSVC14/sigsegv.vcxproj.filters
@@ -332,9 +332,6 @@
Source Files
-
- Source Files
-
Source Files
@@ -350,13 +347,40 @@
Source Files
-
+
+ Source Files
+
+
Source Files
-
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
Source Files
-
+
Source Files
diff --git a/PackageScript b/PackageScript
index e81e3e46..e16652a5 100644
--- a/PackageScript
+++ b/PackageScript
@@ -71,6 +71,7 @@ CopyFiles('gamedata/sigsegv', 'addons/sourcemod/gamedata/sigsegv',
'misc.txt',
'debugoverlay.txt',
'client.txt',
+ 'convars.txt',
]
)
diff --git a/gamedata/sigsegv/client.txt b/gamedata/sigsegv/client.txt
index 81d0a092..9ce5b285 100644
--- a/gamedata/sigsegv/client.txt
+++ b/gamedata/sigsegv/client.txt
@@ -78,7 +78,7 @@
type "pattern"
sym "_ZN13CDebugOverlay15DrawAllOverlaysEv"
lib "engine"
- seg ".text"
+ seg "text"
seek "558beca1c43c491083ec20837830000f840601000053576a0168e5030000689417311068d41731108d45e068043d491050e84aa0ffff8b3da03c491083c41833db85ff0f8493000000f30f100db01e2f1056"
mask "ffffffff00000000ffffffffffffffffff00000000ffffff00ff00000000ff00000000ff00000000ffffffff00000000ffff00000000ffff00000000ffffffffffffffffff00000000ffffffff00000000ff"
}
@@ -87,7 +87,7 @@
type "pattern"
sym "_ZN13CDebugOverlay11DrawOverlayEPNS_13OverlayBase_tE"
lib "engine"
- seg ".text"
+ seg "text"
seek "558bec83ec348d45cc566a016863030000684c173110688c17311068043d491050e86a9bffff8b750883c4188b0683f8050f87b5010000"
mask "ffffffffffffffffffffffffff00000000ff00000000ff00000000ff00000000ffff00000000ffffffffffffffffffffffffff00000000"
}
@@ -97,7 +97,7 @@
type "pattern"
sym "_Z21RenderWireframeSphereRK6Vectorfii5Colorb"
lib "client"
- seg ".text"
+ seg "text"
seek "558bec81ec18020000535657e8dff6ffff8b5d108b4514438bfb895d100faff8488945f88d0c9dfcffffff8945dc0fafc8894dfc8b0da04ad7108b01ff90880100008bf08975e885f674078b068bceff5008"
mask "ffffffffffffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000ffffffff00000000ffffffffffffffff00ffffffffffff00"
}
@@ -106,7 +106,7 @@
// type "pattern"
// sym ""
// lib "engine"
- // seg ".text"
+ // seg "text"
// seek ""
// mask ""
// }
@@ -115,7 +115,7 @@
type "pattern"
sym "_Z12RenderSphereRK6Vectorfii5ColorP9IMaterial"
lib "engine"
- seg ".text"
+ seg "text"
seek "538bdc83ec0883e4f083c404558b6b04896c24048bec81ec680200005657e81df7ffff8b0d7ccf67108b018b8088010000ffd08bf08975e085f67407"
mask "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000ffff00000000ffffffff00000000ffffffffffffffffffff00"
}
@@ -124,7 +124,7 @@
type "pattern"
sym "_Z18RenderWireframeBoxRK6VectorRK6QAngleS1_S1_5Colorb"
lib "engine"
- seg ".text"
+ seg "text"
seek "558bec81ec5802000056e801edffff8b0d04f067108b01ff90880100008bf08975fc85f674078b068bceff5008a138f067108bce807d1c008b160f450534f0671053576a0050ff5224"
mask "ffffffffffffffffffffff00000000ffff00000000ffffffffffffffffffffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffff00000000ffffffffffffffff"
}
@@ -133,7 +133,7 @@
type "pattern"
sym "_Z23RenderWireframeSweptBoxRK6VectorS1_RK6QAngleS1_S1_5Colorb"
lib "engine"
- seg ".text"
+ seg "text"
seek "558bec81ecc40200008b0d08f06710578b01ff90880100008bf8897df085ff74078b078bcfff5008a138f067108bcf807d20008b170f450534f0671053566a0050ff5224"
mask "ffffffffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffff00000000ffffffffffffffff"
}
@@ -142,7 +142,7 @@
type "pattern"
sym "_Z9RenderBoxRK6VectorRK6QAngleS1_S1_5Colorbb"
lib "engine"
- seg ".text"
+ seg "text"
seek ""
mask ""
}
@@ -151,7 +151,7 @@
type "pattern"
sym "_Z9RenderBoxRK6VectorRK6QAngleS1_S1_5ColorP9IMaterialb"
lib "engine"
- seg ".text"
+ seg "text"
seek "558bec81ec7002000056e871feffff8b0d04f067108b01ff90880100008bf08975dc85f674078b068bceff50088b068bce53576a00ff751cff5024"
mask "ffffffffffffffffffffff00000000ffff00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
}
@@ -160,7 +160,7 @@
// type "pattern"
// sym ""
// lib "engine"
- // seg ".text"
+ // seg "text"
// seek ""
// mask ""
// }
@@ -169,7 +169,7 @@
// type "pattern"
// sym ""
// lib "engine"
- // seg ".text"
+ // seg "text"
// seek ""
// mask ""
// }
@@ -178,7 +178,7 @@
type "pattern"
sym "_Z10RenderLineRK6VectorS1_5Colorb"
lib "engine"
- seg ".text"
+ seg "text"
seek "558bec81ecf401000056e8b1f9ffff8b0d04f067108b01ff90880100008bf085f674078b068bceff5008a138f067108bce807d14008b160f450534f0671053576a0050ff5224"
mask "ffffffffffffffffffffff00000000ffff00000000ffffffffffffffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffff00000000ffffffffffffffff"
}
@@ -187,7 +187,7 @@
type "pattern"
sym "_Z14RenderTriangleRK6VectorS1_S1_5Colorb"
lib "engine"
- seg ".text"
+ seg "text"
seek ""
mask ""
}
@@ -196,7 +196,7 @@
type "pattern"
sym "_Z14RenderTriangleRK6VectorS1_S1_5ColorP9IMaterial"
lib "engine"
- seg ".text"
+ seg "text"
seek "558bec81ec0402000056e881f1ffff8b0d04f067108b018b8088010000ffd08bf085f674078b068bceff50088b068bce576a00ff7518ff5024"
mask "ffffffffffffffffffffff00000000ffff00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
}
@@ -205,7 +205,7 @@
// type "pattern"
// sym ""
// lib "engine"
- // seg ".text"
+ // seg "text"
// seek ""
// mask ""
// }
@@ -214,7 +214,7 @@
// type "pattern"
// sym "_Z24DrawScreenSpaceRectangleP9IMaterialiiiiffffiiPviif"
// lib "engine"
- // seg ".text"
+ // seg "text"
// seek ""
// mask ""
// }
@@ -278,7 +278,7 @@
{
type "pattern"
sym "_ZN15CTFGameMovement15ProcessMovementEP12C_BasePlayerP9CMoveData"
- seg ".text"
+ seg "text"
seek "558bec56578b7d088bf185ff746f538b5d0c85db7466e85586dcffc7868806000000000000"
mask "ffffffffffffffffffffffffffffffffffffffffffffff00000000ffff0000000000000000"
lib "client"
@@ -297,7 +297,7 @@
{
type "pattern"
sym "TODO"
- seg ".text"
+ seg "text"
seek "558bec81ec000c000056ff75108bf1ff750c8b06ff5050ff75208b068bceff751cff7518ff7514ff504cff75288d8500fcffffff7524680004000050"
mask "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
lib "vguimatsurface"
@@ -307,7 +307,7 @@
{
type "pattern"
sym "TODO"
- seg ".text"
+ seg "text"
seek "558bec83ec1c53568bf18b0d20d3cd1057e8da33e9ff84c00f84b6010000"
mask "ffffffffffffffffffffffff00000000ffff00000000ffffffffffffffff"
lib "client"
@@ -317,7 +317,7 @@
{
type "pattern"
sym "TODO"
- seg ".text"
+ seg "text"
seek "558bec81ec5c0100008d85a4feffff568b750868000100005650e8da021e006a2e56e8f9d1250083c41485c0751b6aff68000100008d85a4feffff"
mask "ffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000ffffffffff00000000ffffffffffffffffffffffffffffffffffffff"
lib "engine"
@@ -327,7 +327,7 @@
{
type "pattern"
sym "TODO"
- seg ".text"
+ seg "text"
seek "558bec56ff75088bf1e802f0ffffc7463084842f108bc6c7068c842f10c74630d8842f10c7863c40000000000000"
mask "ffffffffffffffffffff00000000ffffff00000000ffffffff00000000ffffff00000000ffffffffffffffffffff"
lib "engine"
@@ -336,7 +336,7 @@
{
type "pattern"
sym "TODO"
- seg ".text"
+ seg "text"
seek "558bec568bf18b4e34c7068c842f10c74630d8842f1085c974068b016a01ff108bcee8c9effffff6450801740956e8dda7130083c4048bc65e5dc20400"
mask "ffffffffffffffffffffff00000000ffffff00000000ffffffffffffffffffffffffff00000000ffffffffffffffff00000000ffffffffffffffffffff"
lib "engine"
@@ -362,7 +362,7 @@
{
type "pattern"
sym "TODO"
- seg ".text"
+ seg "text"
seek "558bec81ec84000000538bd98b4d0c895df856578b7d0885c9751357b910cb1310e81aa3000033c984c00f95c141"
mask "ffffffffff00ffffffffffffffffffffff00ffffffffffffffffffffff00000000ff00000000ffffffffffffffff"
lib "vguimatsurface"
@@ -376,7 +376,7 @@
{
type "pattern"
sym "TODO"
- seg ".text"
+ seg "text"
seek "558bec8b451483ec1485c00f84fb0000008b550c5733ff897df885d20f8ee90000008b4d1053568b750883c103"
mask "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
lib "vguimatsurface"
@@ -385,7 +385,7 @@
{
type "pattern"
sym "TODO"
- seg ".text"
+ seg "text"
seek "558bec83ec34538b5d14565785db0f84d20200008d04dd1300000083e0f0e8bd650600db45148d041b8bfc897dfc8945dc"
mask "ffffffffffffffffffffffffffffffffffffffffffffff00000000ffffffff00000000ffffffffffffffffffffffffffff"
lib "vguimatsurface"
@@ -426,7 +426,7 @@
{
type "func ebpprologue unistr"
sym "TODO"
- seg ".text"
+ seg "text"
unistr "attacker_player"
// also: "patient"
lib "client"
@@ -437,7 +437,7 @@
{
type "func ebpprologue unistr"
sym "TODO"
- seg ".text"
+ seg "text"
unistr "DamagedPlayer"
lib "client"
}
@@ -447,7 +447,7 @@
{
type "pattern"
sym "TODO"
- seg ".text"
+ seg "text"
seek "558bec56ff750c8bf1ff75088b06ff9098000000508bcee814ffffff5e5dc20800cc"
mask "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
lib "client"
@@ -458,11 +458,69 @@
{
type "pattern"
sym "TODO"
- seg ".text"
+ seg "text"
seek "558bec51568bf15780be5b010000007405e87aedffffff750c8d450eb9bccedc1050e8f982fdff0fb738b8ffff0000"
mask "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffffffff"
lib "client"
}
+
+ "[client] CBuildFactoryHelper::GetFactoryNames"
+ {
+ type "pattern"
+ sym "_ZN4vgui19CBuildFactoryHelper15GetFactoryNamesER10CUtlVectorIPKc10CUtlMemoryIS3_iEE"
+ seg "text"
+ seek "558bec568b750857c7460c000000008b3dd0fbdc1085ff7462538d9b000000008b5e0c8b470c8b4e048945088d43013bc1"
+ mask "ffffffffffffffffffffffffffffffffff00000000ffffff00ffffffffffffffffffffffffffffffffffffffffffffffff"
+ lib "client"
+ }
+
+ "[client] CBuildFactoryHelper::InstancePanel"
+ {
+ type "pattern"
+ sym "_ZN4vgui19CBuildFactoryHelper13InstancePanelEPKc"
+ seg "text"
+ seek "558bec568b35d0fbdc105785f674198b7d08ff760c57e8058dfbff83c40885c0740c8b3685f675ea5f33c05e5dc3"
+ mask "ffffffffffff00000000ffffffffffffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffff"
+ lib "client"
+ }
+
+ "[client] GetClientModeNormal"
+ {
+ type "pattern"
+ sym "_Z19GetClientModeNormalv"
+ seg "text"
+ seek "a130d3d610a801751f83c801b998d2d610a330d3d610e855e2ffff68a0039810e839c73d0083c404b898d2d610c3"
+ mask "ff00000000ffffffffffffffff00000000ff00000000ff00000000ff00000000ff00000000ffffffff00000000ff"
+ lib "client"
+ }
+
+ "[client] CTFModeManager::LevelInit"
+ {
+ type "func ebpprologue unistr"
+ sym "_ZN14CTFModeManager9LevelInitEPKc"
+ seg "text"
+ unistr "voice_steal"
+ lib "client"
+ }
+
+ "[client] vgui::Frame::Frame"
+ {
+ type "func ebpprologue unistr"
+ sym "_ZN4vgui5FrameC2EPNS_5PanelEPKcbb"
+ seg "text"
+ unistr "#Frame_Untitled"
+ lib "client"
+ }
+
+ // "[client] MySpewOutputFunc"
+ // {
+ // type "pattern"
+ // sym "_ZL16MySpewOutputFunc10SpewType_tPKc"
+ // seg "text"
+ // seek ""
+ // mask ""
+ // lib "materialsystem"
+ // }
}
}
}
diff --git a/gamedata/sigsegv/convars.txt b/gamedata/sigsegv/convars.txt
new file mode 100644
index 00000000..12d2e849
--- /dev/null
+++ b/gamedata/sigsegv/convars.txt
@@ -0,0 +1,37 @@
+// convars
+
+"Games"
+{
+ "#default"
+ {
+ "#supported"
+ {
+ engine "tf2"
+ }
+
+ "sigsegv"
+ {
+ "addrs"
+ {
+ "con_filter_enable"
+ {
+ type "convar"
+ name "con_filter_enable"
+ lib "engine"
+ }
+ "con_filter_text"
+ {
+ type "convar"
+ name "con_filter_text"
+ lib "engine"
+ }
+ "con_filter_text_out"
+ {
+ type "convar"
+ name "con_filter_text_out"
+ lib "engine"
+ }
+ }
+ }
+ }
+}
diff --git a/gamedata/sigsegv/datamaps.txt b/gamedata/sigsegv/datamaps.txt
index 62fe2fa0..48ae6420 100644
--- a/gamedata/sigsegv/datamaps.txt
+++ b/gamedata/sigsegv/datamaps.txt
@@ -55,6 +55,18 @@
sym "_ZN12CFuncNavCost9m_DataMapE"
class "CFuncNavCost"
}
+ "CFuncNavPrerequisite::m_DataMap"
+ {
+ type "datamap"
+ sym "_ZN20CFuncNavPrerequisite9m_DataMapE"
+ class "CFuncNavPrerequisite"
+ }
+ "CFilterTFBotHasTag::m_DataMap"
+ {
+ type "datamap"
+ sym "_ZN18CFilterTFBotHasTag9m_DataMapE"
+ class "CFilterTFBotHasTag"
+ }
}
}
}
diff --git a/gamedata/sigsegv/globals.txt b/gamedata/sigsegv/globals.txt
index 635ff114..9f6097cf 100644
--- a/gamedata/sigsegv/globals.txt
+++ b/gamedata/sigsegv/globals.txt
@@ -83,6 +83,23 @@
type "sym"
sym "lagcompensation"
}
+
+ "s_pTokenBuf"
+ {
+ type "sym"
+ sym "_ZL11s_pTokenBuf"
+ }
+
+ "s_TankModel"
+ {
+ type "sym"
+ sym "_ZL11s_TankModel"
+ }
+ "s_TankModelRome"
+ {
+ type "sym"
+ sym "_ZL15s_TankModelRome"
+ }
}
}
}
diff --git a/gamedata/sigsegv/misc.txt b/gamedata/sigsegv/misc.txt
index 5718f073..308d9ac8 100644
--- a/gamedata/sigsegv/misc.txt
+++ b/gamedata/sigsegv/misc.txt
@@ -115,11 +115,12 @@
"CCurrencyPack::ComeToRest"
{
- type "func datamap vthunk"
- sym "_ZN13CCurrencyPack10ComeToRestEv"
- datamap "CItem::m_DataMap"
- func "CItemComeToRest"
- vtable ".?AVCCurrencyPack@@"
+ type "func datamap vthunk"
+ sym "_ZN13CCurrencyPack10ComeToRestEv"
+ // classname "item_currencypack_custom"
+ datamap "CItem::m_DataMap"
+ func "CItemComeToRest"
+ vtable ".?AVCCurrencyPack@@"
}
"CCurrencyPack::MyTouch"
{
@@ -182,7 +183,7 @@
{
type "pattern"
sym "_ZN17CAttributeManager15AttribHookValueIiEET_S1_PKcPK11CBaseEntityP10CUtlVectorIPS4_10CUtlMemoryIS8_iEEb"
- seg ".text"
+ seg "text"
seek "558bec83ec248b0d8cc26a105333db895ddc895de08b4108895df0895df45785c0743e6894106f1068b8106f106890806c10683c1e92106a7768c8106f10535353538d4ddc5150"
mask "ffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff00000000ff00000000ff00000000ff00000000ffffff00000000ffffffffffffffffff"
}
@@ -190,7 +191,7 @@
{
type "pattern"
sym "_ZN17CAttributeManager15AttribHookValueIfEET_S1_PKcPK11CBaseEntityP10CUtlVectorIPS4_10CUtlMemoryIS8_iEEb"
- seg ".text"
+ seg "text"
seek "558bec83ec288b0d8cc26a105333db895dd8895ddc8b4108895dec895df05685c0743e6894106f1068b8106f106890806c1068481e92106a7768c8106f10535353538d4dd85150"
mask "ffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff00000000ff00000000ff00000000ff00000000ffffff00000000ffffffffffffffffff"
}
@@ -608,7 +609,7 @@
{
type "pattern"
sym "_ZN11IGameSystem3AddEPS_"
- seg ".text"
+ seg "text"
seek "558bec518b1514d58b108b0d0cd58b10568bf28d42013bc17e142bd1b908d58b104252e8d89c1c008b1514d58b10a108d58b1042891514d58b102bd64aa318d58b1085d27e1d8d0cb08d04950000000050518d410450e8055b4200a108d58b1083c40c8d04b08b750885c0740289306a0068b0de8f1068c4dd8f106a0056e81170420083c41485c074118d45fc8975fc50b91cd58b10e835981c005e8be55dc3"
mask "ffffffffffff00000000ffff00000000ffffffffffffffffff00ffffff00000000ffffff00000000ffff00000000ff00000000ffffff00000000ffffffff00000000ffffff00ffffffffffffffffffffffffffffffffff00000000ff00000000ffffffffffffffffffffffff00ffffffffff00000000ff00000000ffffffff00000000ffffffffffff00ffffffffffffffff00000000ff00000000ffffffffff"
}
@@ -616,7 +617,7 @@
{
type "pattern"
sym "_ZN11IGameSystem6RemoveEPS_"
- seg ".text"
+ seg "text"
seek "558bec51568d4508b9b8148c1050e81dbb0a008b75086a00689020901068a41f90106a0056e84aed420083c41485c074118d45fc8975fc50b9cc148c10e8eeba0a005e8be55dc3"
mask "ffffffffffffffffff00000000ffff00000000ffffffffffff00000000ff00000000ffffffff00000000ffffffffffffffffffffffffffffff00000000ff00000000ffffffffff"
// seek "558bec51568bf18d45fc50b908d58b108975fcc706387a6d10e8a29708006a0068b0de8f1068c4dd8f106a0056e8f271420083c41485c074118d45fc8975fc50b91cd58b10e8769708005e8be55dc3"
@@ -909,7 +910,7 @@
{
type "pattern"
sym "_ZN17CGlobalEntityList21FindEntityByClassnameEP11CBaseEntityPKc"
- seg ".text"
+ seg "text"
seek "558bec5356578bf98b4d0885c974158b01ff50088b3081e6ff0f00004603f68b34f7eb068bb70400010085f674318b5d0c8b3e85ff75106880a47010ff1574f26a1083c404eb11395f5c741c538bcfe8ac9ffaff84c075108b760c85f675d25f5e33c05b5dc208008bc75f5e5b5dc20800"
mask "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffffffff00000000ffff00000000ffffffffffffffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
}
@@ -1036,7 +1037,7 @@
// {
// type "pattern"
// sym "_ZN11CRConClient7SendCmdEPKc"
-// seg ".text"
+// seg "text"
// seek "558bec83ec30538bd956578d4b34e8dd86fdff85c07f336a018d7b5c578d4b34e84baf070085c079216a008bcf"
// mask "ffffffffffffffffffffffffffffff00000000ffffff00ffffffffffffffffffff00000000ffffff00ffffffff"
// lib "engine"
@@ -1046,7 +1047,7 @@
{
type "pattern"
sym "_ZN11CRConClient12SendResponseER10CUtlBufferb"
- seg ".text"
+ seg "text"
seek "558bec807d0c00538bd9742f807b70007529e819e9ffff8d4b34e8118dfdff85c07e5c8b45088d8ba4000000ff701cff30e8ba0019005b5dc20800"
mask "ffffffffffffffffffffff00ffffffffff00ff00000000ffffffff00000000ffffff00ffffffffffffffffffffffffffffff00000000ffffffffff"
lib "engine"
@@ -1055,7 +1056,7 @@
{
type "pattern"
sym "_ZN11CRConClient13BuildResponseER10CUtlBuffer23ServerDataRequestType_tPKcS4_"
- seg ".text"
+ seg "text"
seek "558bec568b7508578bf96a00f646150175098bcee867f31100eb0e682c652f1056e84a15190083c40c"
mask "ffffffffffffffffffffffffffffffffff00ffffff00000000ff00ff00000000ffff00000000ffffff"
lib "engine"
@@ -1111,7 +1112,7 @@
{
type "pattern"
sym "_Z20VProfRecord_Snapshotv"
- seg ".text"
+ seg "text"
seek "a19cf3651083f801750ab9a0d96510e9dcfaffff83f8027517803dc4f3651000750e6a006affb9a0d96510e8c0f1ffffc3"
mask "ff00000000ffffffffffff00000000ff00000000ffffffffffffff00000000ffffffffffffffff00000000ff00000000ff"
lib "engine"
@@ -1121,7 +1122,7 @@
{
type "pattern"
sym "_Z23VProfRecord_StartOrStopv"
- seg ".text"
+ seg "text"
seek "803d04913c100074288b0d60052f10ff810c10000083b90c10000001750c81c118100000ff1544062f10c60504913c1000803d05913c100074218b0d60052f10ff890c100000750c81c118100000ff1540062f10c60505913c1000c3"
mask "ffff00000000ffffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffff00000000ffff00000000ffffff00000000ffffffffff00000000ffffffffffffffffffffffffffffffff00000000ffff00000000ffff"
lib "engine"
@@ -1166,7 +1167,7 @@
{
type "pattern"
sym "_Z14V_vsnprintfRetPciPKcS_Pb"
- seg ".text"
+ seg "text"
seek "558bec568b750c57ff75148b7d08ff75105657e8003601008b551883c41085d2741385c078083bc67d0433c9eb05b901000000880a85c078043bc67c07c64437ff008bc65f5e5dc3"
mask "ffffffffffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
}
@@ -1543,6 +1544,208 @@
type "sym"
sym "_ZN19CTFSniperRifleDecap24SniperRifleChargeRateModEv"
}
+
+ "MapEntity_ParseAllEntities"
+ {
+ type "sym"
+ sym "_Z26MapEntity_ParseAllEntitiesPKcP16IMapEntityFilterb"
+ }
+ "MapEntity_ParseEntity"
+ {
+ type "sym"
+ sym "_Z21MapEntity_ParseEntityRP11CBaseEntityPKcP16IMapEntityFilter"
+ }
+ "MapEntity_ParseToken"
+ {
+ type "sym"
+ sym "_Z20MapEntity_ParseTokenPKcPc"
+ }
+
+ "CTFBotProxy::CTFBotProxy [C1]"
+ {
+ type "sym"
+ sym "_ZN11CTFBotProxyC1Ev"
+ }
+
+ "CTFKnife::CanPerformBackstabAgainstTarget"
+ {
+ type "sym"
+ sym "_ZN8CTFKnife31CanPerformBackstabAgainstTargetEP9CTFPlayer"
+ }
+
+ "CTFKnife::IsBehindAndFacingTarget"
+ {
+ type "sym"
+ sym "_ZN8CTFKnife23IsBehindAndFacingTargetEP9CTFPlayer"
+ }
+
+ "CTFWeaponBaseMelee::DoSwingTrace"
+ {
+ type "sym"
+ sym "_ZN18CTFWeaponBaseMelee12DoSwingTraceER10CGameTrace"
+ }
+
+ "CTFGameRules::DropHalloweenSoulPack"
+ {
+ type "sym"
+ sym "_ZN12CTFGameRules21DropHalloweenSoulPackEiRK6VectorP11CBaseEntityi"
+ }
+
+ "SVC_CmdKeyValues::Process"
+ {
+ type "func knownvtidx"
+ sym "_ZN16SVC_CmdKeyValues7ProcessEv"
+ vtable ".?AVSVC_CmdKeyValues@@"
+ idx "0x03"
+ lib "engine"
+ }
+
+ "CBaseTrigger::PassesTriggerFilters"
+ {
+ type "sym regex"
+ sym ".*CBaseTrigger.*PassesTriggerFilters.*"
+ }
+
+ "CL_TakeSnapshotAndSwap"
+ {
+ type "func ebpprologue unistr"
+ sym "_Z22CL_TakeSnapshotAndSwapv"
+ unistr "CL_TakeSnapshotAndSwap"
+ lib "engine"
+ }
+
+ "CVideoMode_Common::TakeSnapshotTGA"
+ {
+ type "func ebpprologue nonunistr knownvtidx"
+ sym "_ZN17CVideoMode_Common15TakeSnapshotTGAEPKc"
+ str "Couldn't write bitmap data snapshot to file %s.\n"
+ vtable ".?AVCVideoMode_Common@@"
+ idx "0x18"
+ lib "engine"
+ }
+
+ "CBaseCombatWeapon::HasAmmo"
+ {
+ type "sym"
+ sym "_ZN17CBaseCombatWeapon7HasAmmoEv"
+ }
+
+ "CObjectSapper::IsValidRoboSapperTarget"
+ {
+ type "sym"
+ sym "_ZN13CObjectSapper23IsValidRoboSapperTargetEP9CTFPlayer"
+ }
+
+ "CObjectSapper::ApplyRoboSapper"
+ {
+ type "sym"
+ sym "_ZN13CObjectSapper15ApplyRoboSapperEP9CTFPlayerfi"
+ }
+
+ "CObjectSapper::ApplyRoboSapperEffects"
+ {
+ type "sym"
+ sym "_ZN13CObjectSapper22ApplyRoboSapperEffectsEP9CTFPlayerf"
+ }
+
+ "CTFSniperRifle::CreateSniperDot"
+ {
+ type "sym"
+ sym "_ZN14CTFSniperRifle15CreateSniperDotEv"
+ }
+
+ "CTFSniperRifle::CanFireCriticalShot"
+ {
+ type "sym"
+ sym "_ZN14CTFSniperRifle19CanFireCriticalShotEb"
+ }
+
+ "CTFWeaponBase::CanFireCriticalShot"
+ {
+ type "sym"
+ sym "_ZN13CTFWeaponBase19CanFireCriticalShotEb"
+ }
+
+ "CTFProjectile_Arrow::StrikeTarget"
+ {
+ type "sym"
+ sym "_ZN19CTFProjectile_Arrow12StrikeTargetEP13mstudiobbox_tP11CBaseEntity"
+ }
+
+ "CTFGameRules::IsPVEModeControlled"
+ {
+ type "sym"
+ sym "_ZNK12CTFGameRules19IsPVEModeControlledEP11CBaseEntity"
+ }
+
+ "CBaseEntity::ChangeTeam"
+ {
+ type "sym"
+ sym "_ZN11CBaseEntity10ChangeTeamEi"
+ }
+
+ "SendProxy_LengthTable"
+ {
+ type "sym"
+ sym "_Z21SendProxy_LengthTablePK8SendPropPKvS3_P20CSendProxyRecipientsi"
+ }
+
+ "CBaseEntity::SetModelIndexOverride"
+ {
+ type "sym"
+ sym "_ZN11CBaseEntity21SetModelIndexOverrideEii"
+ }
+
+ "CBaseEntity::SetModelIndex"
+ {
+ type "sym"
+ sym "_ZN11CBaseEntity13SetModelIndexEi"
+ }
+
+ "CBaseEntity::GetModelName"
+ {
+ type "sym"
+ sym "_ZNK11CBaseEntity12GetModelNameEv"
+ }
+
+ "Con_ColorPrint"
+ {
+ type "sym"
+ sym "_Z15Con_ColorPrintfRK5ColorPKcz"
+ lib "engine"
+ }
+
+ "AllocPooledString"
+ {
+ type "sym"
+ sym "_Z17AllocPooledStringPKc"
+ }
+
+ "CEventQueue::AddEvent [EventQueuePrioritizedEvent_t *]"
+ {
+ type "sym"
+ sym "_ZN11CEventQueue8AddEventEP28EventQueuePrioritizedEvent_t"
+ }
+
+ "CEventQueue::ServiceEvents"
+ {
+ type "sym"
+ sym "_ZN11CEventQueue13ServiceEventsEv"
+ }
+
+ "CBaseEntity::GetDataDescMap"
+ {
+ type "func knownvtidx"
+ sym "_ZN11CBaseEntity14GetDataDescMapEv"
+ vtable ".?AVCBaseEntity@@"
+ idx "0x0b"
+ }
+
+ "CUpgrades::UpgradeTouch"
+ {
+ type "sym"
+ sym "_ZN9CUpgrades12UpgradeTouchEP11CBaseEntity"
+ }
}
}
}
diff --git a/gamedata/sigsegv/tfbot_behavior.txt b/gamedata/sigsegv/tfbot_behavior.txt
index 5c49c126..eaee838f 100644
--- a/gamedata/sigsegv/tfbot_behavior.txt
+++ b/gamedata/sigsegv/tfbot_behavior.txt
@@ -268,6 +268,11 @@
type "sym"
sym "_ZN21CTFBotTacticalMonitor22InitialContainedActionEP6CTFBot"
}
+ "CTFBotTacticalMonitor::OnNavAreaChanged"
+ {
+ type "sym"
+ sym "_ZN21CTFBotTacticalMonitor16OnNavAreaChangedEP6CTFBotP8CNavAreaS3_"
+ }
"CTFBotSpyAttack::Update"
{
@@ -281,6 +286,11 @@
sym "_ZN25CTFBotStickybombSentrygun6UpdateEP6CTFBotf"
}
+ "CTFBotFetchFlag::CTFBotFetchFlag [C1]"
+ {
+ type "sym"
+ sym "_ZN15CTFBotFetchFlagC1Eb"
+ }
"CTFBotFetchFlag::OnStart"
{
type "sym"
@@ -310,11 +320,22 @@
sym "_ZN12CTFBotAttackC1Ev"
}
+ "CTFBotPushToCapturePoint::CTFBotPushToCapturePoint [C1]"
+ {
+ type "sym"
+ sym "_ZN24CTFBotPushToCapturePointC1EP6ActionI6CTFBotE"
+ }
"CTFBotPushToCapturePoint::Update"
{
type "sym"
sym "_ZN24CTFBotPushToCapturePoint6UpdateEP6CTFBotf"
}
+
+ "CTFBotDead::OnStart"
+ {
+ type "sym"
+ sym "_ZN10CTFBotDead7OnStartEP6CTFBotP6ActionIS0_E"
+ }
}
}
}
diff --git a/gamedata/sigsegv/tfplayer.txt b/gamedata/sigsegv/tfplayer.txt
index 0a6550e6..d1134648 100644
--- a/gamedata/sigsegv/tfplayer.txt
+++ b/gamedata/sigsegv/tfplayer.txt
@@ -301,6 +301,12 @@
sym "_ZN9CTFPlayer19CreateRagdollEntityEbbbbbbbbib"
}
+ "CTFPlayer::ClientCommand"
+ {
+ type "sym"
+ sym "_ZN9CTFPlayer13ClientCommandERK8CCommand"
+ }
+
"CTFPlayerShared::AddCond"
{
type "sym"
@@ -346,29 +352,44 @@
type "sym"
sym "_ZN15CTFPlayerShared12SetRageMeterEf"
}
-
- "CTFPlayerClassShared::SetCustomModel"
+ "CTFPlayerShared::GetConditionsBits"
+ {
+ type "sym regex"
+ sym "_ZNK15CTFPlayerShared17GetConditionsBitsER7CBitVecILi[[:digit:]]{3}EE"
+ }
+ "CTFPlayerShared::GetConditionDuration"
{
type "sym"
- sym "_ZN20CTFPlayerClassShared14SetCustomModelEPKcb"
+ sym "_ZNK15CTFPlayerShared20GetConditionDurationE7ETFCond"
}
-
- "CTFPlayerSharedUtils::GetEconItemViewByLoadoutSlot"
+ "CTFPlayerShared::GetConditionProvider"
{
type "sym"
- sym "_ZN20CTFPlayerSharedUtils28GetEconItemViewByLoadoutSlotEP9CTFPlayeriPP11CEconEntity"
+ sym "_ZNK15CTFPlayerShared20GetConditionProviderE7ETFCond"
}
- "GetTFConditionName"
+ "CTFPlayerClassShared::SetCustomModel"
{
type "sym"
- sym "_Z18GetTFConditionName7ETFCond"
+ sym "_ZN20CTFPlayerClassShared14SetCustomModelEPKcb"
}
- "GetTFConditionFromName"
+
+ "CTFPlayerSharedUtils::GetEconItemViewByLoadoutSlot"
{
type "sym"
- sym "_Z22GetTFConditionFromNamePKc"
+ sym "_ZN20CTFPlayerSharedUtils28GetEconItemViewByLoadoutSlotEP9CTFPlayeriPP11CEconEntity"
}
+
+ // "GetTFConditionName"
+ // {
+ // type "sym"
+ // sym "_Z18GetTFConditionName7ETFCond"
+ // }
+ // "GetTFConditionFromName"
+ // {
+ // type "sym"
+ // sym "_Z22GetTFConditionFromNamePKc"
+ // }
}
}
}
diff --git a/src/addr/addr.cpp b/src/addr/addr.cpp
index 1ad3a865..c8b6afe1 100644
--- a/src/addr/addr.cpp
+++ b/src/addr/addr.cpp
@@ -125,19 +125,19 @@ void AddrManager::CC_ListAddrs(const CCommand& cmd)
}
std::sort(addrs_sorted.begin(), addrs_sorted.end(), CompareAddrsForSorting);
- size_t max_libname_len = LibMgr::MaxStringLen();
+ size_t max_libname_len = LibMgr::Lib_MaxStringLen();
MAT_SINGLE_THREAD_BLOCK {
for (auto addr : addrs_sorted) {
switch (addr->GetState()) {
case IAddr::State::INITIAL:
- Msg("%-*s %-8s %s\n", max_libname_len, LibMgr::ToString(addr->GetLibrary()), "INITIAL", addr->GetName());
+ Msg("%-*s %-8s %s\n", max_libname_len, LibMgr::Lib_ToString(addr->GetLibrary()), "INITIAL", addr->GetName());
break;
case IAddr::State::OK:
- Msg("%-*s %08x %s\n", max_libname_len, LibMgr::ToString(addr->GetLibrary()), (uintptr_t)addr->GetAddr(), addr->GetName());
+ Msg("%-*s %08x %s\n", max_libname_len, LibMgr::Lib_ToString(addr->GetLibrary()), (uintptr_t)addr->GetAddr(), addr->GetName());
break;
case IAddr::State::FAIL:
- Msg("%-*s %-8s %s\n", max_libname_len, LibMgr::ToString(addr->GetLibrary()), "FAIL", addr->GetName());
+ Msg("%-*s %-8s %s\n", max_libname_len, LibMgr::Lib_ToString(addr->GetLibrary()), "FAIL", addr->GetName());
break;
}
}
diff --git a/src/addr/misc.cpp b/src/addr/misc.cpp
index 126aac18..a1c6bb0e 100644
--- a/src/addr/misc.cpp
+++ b/src/addr/misc.cpp
@@ -4,6 +4,7 @@
#include "stub/gamerules.h"
#include "util/rtti.h"
#include "addr/standard.h"
+#include "disasm/disasm.h"
static constexpr uint8_t s_Buf_g_pGameRules[] = {
@@ -88,11 +89,11 @@ class CAddr_pszWpnEntTranslationList : public IAddr_Sym
// +0x24 ptr: ""
// +0x28 ptr: "tf_weapon_shotgun_primary"
- auto strscan1 = new StrScanner(CLibSegBounds(Library::SERVER, ".rdata"), "tf_weapon_shotgun");
- auto strscan2 = new StrScanner(CLibSegBounds(Library::SERVER, ".rdata"), "tf_weapon_shotgun_soldier");
- auto strscan3 = new StrScanner(CLibSegBounds(Library::SERVER, ".rdata"), "tf_weapon_shotgun_hwg");
- auto strscan4 = new StrScanner(CLibSegBounds(Library::SERVER, ".rdata"), "tf_weapon_shotgun_pyro");
- auto strscan5 = new StrScanner(CLibSegBounds(Library::SERVER, ".rdata"), "tf_weapon_shotgun_primary");
+ auto strscan1 = new StrScanner(CLibSegBounds(Library::SERVER, Segment::RODATA), "tf_weapon_shotgun");
+ auto strscan2 = new StrScanner(CLibSegBounds(Library::SERVER, Segment::RODATA), "tf_weapon_shotgun_soldier");
+ auto strscan3 = new StrScanner(CLibSegBounds(Library::SERVER, Segment::RODATA), "tf_weapon_shotgun_hwg");
+ auto strscan4 = new StrScanner(CLibSegBounds(Library::SERVER, Segment::RODATA), "tf_weapon_shotgun_pyro");
+ auto strscan5 = new StrScanner(CLibSegBounds(Library::SERVER, Segment::RODATA), "tf_weapon_shotgun_primary");
CMultiScan scan1({ strscan1, strscan2, strscan3, strscan4, strscan5 });
if (!strscan1->ExactlyOneMatch()) { DevMsg("Fail strscan1\n"); return false; }
if (!strscan2->ExactlyOneMatch()) { DevMsg("Fail strscan2\n"); return false; }
@@ -107,7 +108,7 @@ class CAddr_pszWpnEntTranslationList : public IAddr_Sym
mask.SetDword(0x1c, 0xffffffff); seek.SetDword(0x1c, (uint32_t)strscan3->FirstMatch());
mask.SetDword(0x20, 0xffffffff); seek.SetDword(0x20, (uint32_t)strscan4->FirstMatch());
mask.SetDword(0x28, 0xffffffff); seek.SetDword(0x28, (uint32_t)strscan5->FirstMatch());
- CScan scan2(CLibSegBounds(Library::SERVER, ".data"), seek, mask);
+ CScan scan2(CLibSegBounds(Library::SERVER, Segment::DATA), seek, mask);
if (!scan2.ExactlyOneMatch()) { DevMsg("Fail scan2 %u\n", scan2.Matches().size()); return false; }
auto match = (const char **)scan2.FirstMatch();
@@ -180,7 +181,7 @@ class CAddr_CTFPlayer_CanBeForcedToLaugh : public IAddr_Sym
// DevMsg("g_pGameRules: %08x\n", (uintptr_t)addr_g_pGameRules);
// DevMsg("m_bPlayingMannVsMachine: %08x\n", off_CTFGameRules_m_bPlayingMannVsMachine);
- CScan scan1(CLibSegBounds(this->GetLibrary(), ".text"), seek, mask);
+ CScan scan1(CLibSegBounds(this->GetLibrary(), Segment::TEXT), seek, mask);
if (!scan1.ExactlyOneMatch()) {
DevMsg("Fail scan1 %u\n", scan1.Matches().size());
return false;
@@ -296,6 +297,7 @@ class CAddr_IServerGameDLL : public CAddr_InterfaceVFunc
CAddr_IServerGameDLL(const std::string& n_func, int vtidx) :
CAddr_InterfaceVFunc(&gamedll, "IServerGameDLL", n_func, vtidx) {}
};
+static CAddr_IServerGameDLL addr_IServerGameDLL_LevelInit("LevelInit", GetVIdxOfMemberFunc(&IServerGameDLL::LevelInit));
static CAddr_IServerGameDLL addr_IServerGameDLL_GameFrame("GameFrame", GetVIdxOfMemberFunc(&IServerGameDLL::GameFrame));
@@ -338,12 +340,12 @@ class CAddr_CTFBotUseItem_C1 : public IAddr_Sym
virtual bool FindAddrWin(uintptr_t& addr) const override
{
- using VTRefScanner = CTypeScanner;
+ using VTRefScanner = CTypeScanner;
auto p_VT = RTTI::GetVTable(".?AVCTFBotUseItem@@");
auto p_dtor = AddrManager::GetAddr("CTFBotUseItem::~CTFBotUseItem [D2]");
- CScan scan1(CLibSegBounds(this->GetLibrary(), ".text"), p_VT);
+ CScan scan1(CLibSegBounds(this->GetLibrary(), Segment::TEXT), p_VT);
std::vector matches;
for (auto match : scan1.Matches()) {
@@ -377,7 +379,7 @@ class IAddr_Func_EBPPrologue_UniqueCall : public IAddr_Sym
return false;
}
- CScan scan1(CLibSegBounds(this->GetLibrary(), ".text"), (uint32_t)p_ref);
+ CScan scan1(CLibSegBounds(this->GetLibrary(), Segment::TEXT), (uint32_t)p_ref);
if (!scan1.ExactlyOneMatch()) {
DevMsg("IAddr_Func_EBPPrologue_UniqueCall: \"%s\": found %u refs to ostensibly unique func\n", this->GetName(), scan1.Matches().size());
return false;
@@ -500,7 +502,7 @@ class CAddr_Client_UserMessages : public IAddr_Sym
seek.SetDword(0x08 + 1, (uint32_t)p_str);
mask.SetRange(0x0d + 1, 0x04, 0x00);
- CScan scan1(CLibSegBounds(Library::CLIENT, ".text"), seek, mask);
+ CScan scan1(CLibSegBounds(Library::CLIENT, Segment::TEXT), seek, mask);
if (!scan1.ExactlyOneMatch()) {
DevMsg("%s: %u matches\n", this->GetName(), scan1.Matches().size());
return false;
@@ -550,7 +552,7 @@ class CAddr_Client_CUserMessages_Register : public IAddr_Sym
seek.SetDword(0x08 + 1, (uint32_t)p_str);
mask.SetRange(0x0d + 1, 0x04, 0x00);
- CScan scan1(CLibSegBounds(Library::CLIENT, ".text"), seek, mask);
+ CScan scan1(CLibSegBounds(Library::CLIENT, Segment::TEXT), seek, mask);
if (!scan1.ExactlyOneMatch()) {
DevMsg("%s: %u matches\n", this->GetName(), scan1.Matches().size());
return false;
@@ -602,7 +604,7 @@ class CAddr_Client_CUserMessages_HookMessage : public IAddr_Sym
seek.SetDword(0x0b + 1, (uint32_t)p_str);
mask.SetRange(0x10 + 1, 0x04, 0x00);
- CScan scan1(CLibSegBounds(Library::CLIENT, ".text"), seek, mask);
+ CScan scan1(CLibSegBounds(Library::CLIENT, Segment::TEXT), seek, mask);
if (!scan1.ExactlyOneMatch()) {
DevMsg("%s: %u matches\n", this->GetName(), scan1.Matches().size());
return false;
@@ -622,7 +624,7 @@ class IAddr_Client_CDebugOverlay : public IAddr_Sym
public:
virtual bool FindAddrWin(uintptr_t& addr) const override
{
- using StrRefScanner = CTypeScanner ;
+ using StrRefScanner = CTypeScanner ;
using NearbyPatternScanner = CMaskedScanner;
constexpr const char *str = "s_OverlayMutex";
@@ -632,7 +634,7 @@ class IAddr_Client_CDebugOverlay : public IAddr_Sym
return false;
}
- CScan scan1(CLibSegBounds(this->GetLibrary(), ".text"), p_str);
+ CScan scan1(CLibSegBounds(this->GetLibrary(), Segment::TEXT), p_str);
DevMsg("IAddr_Client_CDebugOverlay: \"%s\": found %u preliminary matches\n", this->GetName(), scan1.Matches().size());
for (auto match : scan1.Matches()) {
DevMsg(" %08x\n", (uintptr_t)match);
@@ -772,7 +774,7 @@ class CAddr_RCONClient : public IAddr_Sym
mask.SetRange(0x30 + 1, 4, 0x00);
mask.SetRange(0x35 + 1, 4, 0x00);
- CScan scan1(CLibSegBounds(Library::ENGINE, ".text"), seek, mask);
+ CScan scan1(CLibSegBounds(Library::ENGINE, Segment::TEXT), seek, mask);
if (!scan1.ExactlyOneMatch()) {
DevMsg("%s: %u matches\n", this->GetName(), scan1.Matches().size());
return false;
@@ -864,3 +866,126 @@ class CAddr_CAttributeManager_AttribHookValue : public IAddr_Func_EBPPrologue_VP
static CAddr_CAttributeManager_AttribHookValue addr_CAttributeManager_AttribHookValue_int ("CAttributeManager::AttribHookValue", "_ZN17CAttributeManager15AttribHookValueIiEET_S1_PKcPK11CBaseEntityP10CUtlVectorIPS4_10CUtlMemoryIS8_iEEb", 0x24);
static CAddr_CAttributeManager_AttribHookValue addr_CAttributeManager_AttribHookValue_float("CAttributeManager::AttribHookValue", "_ZN17CAttributeManager15AttribHookValueIfEET_S1_PKcPK11CBaseEntityP10CUtlVectorIPS4_10CUtlMemoryIS8_iEEb", 0x28);
#endif
+
+
+class CAddr_Client_g_pClientMode : public IAddr_Sym
+{
+public:
+ CAddr_Client_g_pClientMode()
+ {
+ this->SetLibrary(Library::CLIENT);
+ }
+
+ virtual const char *GetName() const override { return "g_pClientMode"; }
+ virtual const char *GetSymbol() const override { return "g_pClientMode"; }
+
+ virtual bool FindAddrWin(uintptr_t& addr) const override
+ {
+ using MyScanner = CMaskedScanner;
+
+ void *p_func = AddrManager::GetAddr("[client] CTFModeManager::LevelInit");
+ if (p_func == nullptr) {
+ DevMsg("CAddr_Client_g_pClientMode: \"%s\": failed to find parent function\n", this->GetName());
+ return false;
+ }
+
+ constexpr uint8_t buf[] = {
+ 0x55, // +0000 push ebp
+ 0x8b, 0xec, // +0001 mov ebp,esp
+ 0x8b, 0x0d, 0x00, 0x00, 0x00, 0x00, // +0003 mov ecx,0xVVVVVVVV
+ 0x83, 0xec, 0x00, // +0009 sub esp,0xXX
+ 0x8b, 0x01, // +000C mov eax,[ecx]
+ 0xff, 0x75, 0x08, // +000E push [ebp+0x8]
+ 0xff, 0x50, 0x58, // +0011 call dword ptr [eax+0x58]
+ };
+
+ ByteBuf seek(sizeof(buf));
+ ByteBuf mask(sizeof(buf));
+ seek.CopyFrom(buf);
+ mask.SetAll(0xff);
+
+ mask.SetRange(0x03 + 2, 0x04, 0x00);
+ mask.SetRange(0x09 + 2, 0x01, 0x00);
+
+ CScan scan1(CAddrOffBounds(p_func, sizeof(buf)), seek, mask);
+ if (!scan1.ExactlyOneMatch()) {
+ DevMsg("%s: %u matches\n", this->GetName(), scan1.Matches().size());
+ return false;
+ }
+
+ addr = **(uintptr_t **)((uintptr_t)scan1.FirstMatch() + 0x05);
+ return true;
+ }
+};
+static CAddr_Client_g_pClientMode addr_g_pClientMode;
+
+
+class CAddr_TGAWriter_WriteToBuffer : public IAddr_Sym
+{
+public:
+ CAddr_TGAWriter_WriteToBuffer()
+ {
+ this->SetLibrary(Library::ENGINE);
+ }
+
+ virtual const char *GetName() const override { return "TGAWriter::WriteToBuffer"; }
+ virtual const char *GetSymbol() const override { return "_ZN9TGAWriter13WriteToBufferEPhR10CUtlBufferii11ImageFormatS3_"; }
+
+ virtual bool FindAddrWin(uintptr_t& addr)
+ {
+ void *p_func = AddrManager::GetAddr("CVideoMode_Common::TakeSnapshotTGA");
+ if (p_func == nullptr) {
+ DevMsg("CAddr_TGAWriter_WriteToBuffer: \"%s\": failed to find parent function\n", this->GetName());
+ return false;
+ }
+
+ #warning TODO TODO TODO
+
+ /*
+ Disassembler dasm;
+ if (dasm.HasError()) {
+ DevMsg("CAddr_TGAWriter_WriteToBuffer: \"%s\": error in Disassembler ctor: \"%s\"\n", this->GetName(), dasm.ErrorStr());
+ return false;
+ }
+
+ auto insns = dasm.Disasm(p_func, 0x120);
+ if (dasm.HasError()) {
+ DevMsg("CAddr_TGAWriter_WriteToBuffer: \"%s\": error in Disassembler Disasm: \"%s\"\n", this->GetName(), dasm.ErrorStr());
+ return false;
+ }
+
+ for ()*/
+
+ }
+};
+static CAddr_TGAWriter_WriteToBuffer addr_TGAWriter_WriteToBuffer;
+
+
+class CAddr_g_aConditionNames : public IAddr_Sym
+{
+public:
+ virtual const char *GetName() const override { return "g_aConditionNames"; }
+ virtual const char *GetSymbol() const override { return "_ZL17g_aConditionNames"; }
+
+ virtual bool FindAddrWin(uintptr_t& addr) const override
+ {
+ using StrRefScanner = CAlignedTypeScanner;
+
+ constexpr char str[] = "TF_COND_AIMING";
+ const char *p_str = Scan::FindUniqueConstStr(this->GetLibrary(), str);
+ if (p_str == nullptr) {
+ DevMsg("CAddr_g_aConditionNames: \"%s\": failed to find string \"%s\"\n", this->GetName(), str);
+ return false;
+ }
+
+ CScan scan1(CLibSegBounds(this->GetLibrary(), Segment::RODATA), p_str);
+ if (!scan1.ExactlyOneMatch()) {
+ DevMsg("CAddr_g_aConditionNames: \"%s\": %u string ref matches\n", this->GetName(), scan1.Matches().size());
+ return false;
+ }
+
+ addr = (uintptr_t)scan1.FirstMatch();
+ return true;
+ }
+};
+static CAddr_g_aConditionNames addr_g_aConditionNames;
diff --git a/src/addr/prescan.cpp b/src/addr/prescan.cpp
index 283bdc48..66f5ed03 100644
--- a/src/addr/prescan.cpp
+++ b/src/addr/prescan.cpp
@@ -9,7 +9,7 @@ void PreScan::DoScans()
#if defined _WINDOWS
DevMsg("PreScan::DoScans\n");
-// s_WinRTTI_server = new CSingleScan(ScanDir::FORWARD, CLibSegBounds(Library::SERVER, ".data"), 1, new CStringPrefixScanner(ScanResults::ALL, ".?AV"));
+// s_WinRTTI_server = new CSingleScan(ScanDir::FORWARD, CLibSegBounds(Library::SERVER, Segment::DATA), 1, new CStringPrefixScanner(ScanResults::ALL, ".?AV"));
//
// for (auto match : s_WinRTTI_server->Matches()) {
// DevMsg("[PreScan] 0x%08x \"%s\"\n", (uintptr_t)match, (const char *)match);
diff --git a/src/addr/standard.cpp b/src/addr/standard.cpp
index 26aa348a..98f3b21a 100644
--- a/src/addr/standard.cpp
+++ b/src/addr/standard.cpp
@@ -1,4 +1,5 @@
#include "addr/standard.h"
+#include "prop.h"
#include "mem/scan.h"
#include "util/rtti.h"
@@ -15,6 +16,27 @@ bool IAddr_Sym::FindAddrLinux(uintptr_t& addr) const
}
+bool CAddr_Sym_Regex::FindAddrLinux(uintptr_t& addr) const
+{
+ float t1 = Plat_FloatTime();
+ auto results = LibMgr::FindSymRegex(this->GetLibrary(), this->GetSymbol());
+ float t2 = Plat_FloatTime();
+ ConColorMsg(Color(0xff, 0x00, 0xff, 0xff), "Regex lookup for \"%s\" \"%s\": %.3f ms\n",
+ this->GetName(), this->GetSymbol(), (t2 - t1) * 1000.0f);
+
+ bool success = std::get<0>(results);
+ std::string& name = std::get<1>(results);
+ void *sym_addr = std::get<2>(results);
+
+ if (!success || sym_addr == nullptr) {
+ return false;
+ }
+
+ addr = (uintptr_t)sym_addr;
+ return true;
+}
+
+
bool IAddr_FixedAddr::FindAddrWin(uintptr_t& addr) const
{
if (engine->GetServerVersion() != this->GetServerVersion()) {
@@ -22,8 +44,7 @@ bool IAddr_FixedAddr::FindAddrWin(uintptr_t& addr) const
return false;
}
- const LibInfo& info = LibMgr::GetInfo(this->GetLibrary());
- addr = info.baseaddr + this->GetAddress();
+ addr = LibMgr::GetInfo(this->GetLibrary()).BaseAddr() + this->GetAddress();
return true;
}
@@ -35,8 +56,8 @@ bool IAddr_DataDescMap::FindAddrWin(uintptr_t& addr) const
uint8_t buf[6];
};
- using ClassNameRefScanner = CTypeScanner;
- using GetDataDescMapScanner = CTypeScanner;
+ using ClassNameRefScanner = CTypeScanner;
+ using GetDataDescMapScanner = CTypeScanner;
const char *p_str = Scan::FindUniqueConstStr(this->GetLibrary(), this->GetClassName());
if (p_str == nullptr) {
@@ -44,7 +65,7 @@ bool IAddr_DataDescMap::FindAddrWin(uintptr_t& addr) const
return false;
}
- CScan scan1(CLibSegBounds(this->GetLibrary(), ".data"), p_str);
+ CScan scan1(CLibSegBounds(this->GetLibrary(), Segment::DATA), p_str);
std::vector scanners;
for (auto match : scan1.Matches()) {
GetDataDescMap gddm;
@@ -52,7 +73,7 @@ bool IAddr_DataDescMap::FindAddrWin(uintptr_t& addr) const
*(uint32_t *)(&gddm.buf[0x01]) = (uint32_t)match - offsetof(datamap_t, dataClassName);
gddm.buf[0x05] = 0xc3; // ret
- scanners.push_back(new GetDataDescMapScanner(CLibSegBounds(this->GetLibrary(), ".text"), gddm));
+ scanners.push_back(new GetDataDescMapScanner(CLibSegBounds(this->GetLibrary(), Segment::TEXT), gddm));
}
CMultiScan scan2(scanners);
@@ -88,8 +109,9 @@ bool IAddr_Func_KnownVTIdx::FindAddrWin(uintptr_t& addr) const
bool IAddr_Func_DataMap_VThunk::FindAddrWin(uintptr_t& addr) const
{
auto p_DM = (const datamap_t *)AddrManager::GetAddr(this->GetDataMapName());
+// auto p_DM = Prop::GetDataMapByClassname(this->GetEntClassname());
if (p_DM == nullptr) {
- DevMsg("IAddr_Func_DataMap_VThunk: \"%s\": no addr for datamap\n", this->GetName());
+ DevMsg("IAddr_Func_DataMap_VThunk: \"%s\": can't find datamap: %s\n", this->GetName(), this->GetDataMapName());
return false;
}
@@ -144,7 +166,7 @@ bool IAddr_Func_DataMap_VThunk::FindAddrWin(uintptr_t& addr) const
bool IAddr_Func_EBPPrologue_UniqueRef::FindAddrWin(uintptr_t& addr) const
{
- using SymRefScanner = CTypeScanner;
+ using SymRefScanner = CTypeScanner;
auto p_ref = AddrManager::GetAddr(this->GetUniqueSymbol());
if (p_ref == nullptr) {
@@ -152,7 +174,7 @@ bool IAddr_Func_EBPPrologue_UniqueRef::FindAddrWin(uintptr_t& addr) const
return false;
}
- CScan scan1(CLibSegBounds(this->GetLibrary(), ".text"), p_ref);
+ CScan scan1(CLibSegBounds(this->GetLibrary(), Segment::TEXT), p_ref);
if (!scan1.ExactlyOneMatch()) {
DevMsg("IAddr_Func_EBPPrologue_UniqueRef: \"%s\": found %u refs to ostensibly unique symbol\n", this->GetName(), scan1.Matches().size());
return false;
@@ -172,7 +194,7 @@ bool IAddr_Func_EBPPrologue_UniqueRef::FindAddrWin(uintptr_t& addr) const
bool IAddr_Func_EBPPrologue_UniqueStr::FindAddrWin(uintptr_t& addr) const
{
- using StrRefScanner = CTypeScanner;
+ using StrRefScanner = CTypeScanner;
const char *p_str = Scan::FindUniqueConstStr(this->GetLibrary(), this->GetUniqueStr());
if (p_str == nullptr) {
@@ -180,7 +202,7 @@ bool IAddr_Func_EBPPrologue_UniqueStr::FindAddrWin(uintptr_t& addr) const
return false;
}
- CScan scan1(CLibSegBounds(this->GetLibrary(), ".text"), p_str);
+ CScan scan1(CLibSegBounds(this->GetLibrary(), Segment::TEXT), p_str);
if (!scan1.ExactlyOneMatch()) {
DevMsg("IAddr_Func_EBPPrologue_UniqueStr: \"%s\": found %u refs to ostensibly unique string\n", this->GetName(), scan1.Matches().size());
return false;
@@ -200,7 +222,7 @@ bool IAddr_Func_EBPPrologue_UniqueStr::FindAddrWin(uintptr_t& addr) const
bool IAddr_Func_EBPPrologue_UniqueStr_KnownVTIdx::FindAddrWin(uintptr_t& addr) const
{
- using StrRefScanner = CTypeScanner;
+ using StrRefScanner = CTypeScanner;
const char *p_str = Scan::FindUniqueConstStr(this->GetLibrary(), this->GetUniqueStr());
if (p_str == nullptr) {
@@ -208,7 +230,7 @@ bool IAddr_Func_EBPPrologue_UniqueStr_KnownVTIdx::FindAddrWin(uintptr_t& addr) c
return false;
}
- CScan scan1(CLibSegBounds(this->GetLibrary(), ".text"), p_str);
+ CScan scan1(CLibSegBounds(this->GetLibrary(), Segment::TEXT), p_str);
if (!scan1.ExactlyOneMatch()) {
DevMsg("IAddr_Func_EBPPrologue_UniqueStr_KnownVTIdx: \"%s\": found %u refs to ostensibly unique string\n", this->GetName(), scan1.Matches().size());
return false;
@@ -238,6 +260,46 @@ bool IAddr_Func_EBPPrologue_UniqueStr_KnownVTIdx::FindAddrWin(uintptr_t& addr) c
}
+bool IAddr_Func_EBPPrologue_NonUniqueStr_KnownVTIdx::FindAddrWin(uintptr_t& addr) const
+{
+ using StrRefScanner = CTypeScanner;
+
+ const char *p_str = Scan::FindUniqueConstStr(this->GetLibrary(), this->GetStr());
+ if (p_str == nullptr) {
+ DevMsg("IAddr_Func_EBPPrologue_NonUniqueStr_KnownVTIdx: \"%s\": failed to find string\n", this->GetName());
+ return false;
+ }
+
+ CScan scan1(CLibSegBounds(this->GetLibrary(), Segment::TEXT), p_str);
+ if (scan1.Matches().empty()) {
+ DevMsg("IAddr_Func_EBPPrologue_NonUniqueStr_KnownVTIdx: \"%s\": no refs to string\n", this->GetName());
+ return false;
+ }
+
+ auto p_VT = RTTI::GetVTable(this->GetVTableName());
+ if (p_VT == nullptr) {
+ DevMsg("IAddr_Func_EBPPrologue_NonUniqueStr_KnownVTIdx: \"%s\": no addr for vtable\n", this->GetName());
+ return false;
+ }
+
+ for (auto p_in_func : scan1.Matches()) {
+ auto p_func = Scan::FindFuncPrologue(p_in_func);
+ if (p_func == nullptr) {
+ continue;
+ }
+
+ auto vfptr = p_VT[this->GetVTableIndex()];
+ if (vfptr == p_func) {
+ addr = (uintptr_t)p_func;
+ return true;
+ }
+ }
+
+ DevMsg("IAddr_Func_EBPPrologue_NonUniqueStr_KnownVTIdx: \"%s\": found %u string refs, but none matched vtable entry\n", this->GetName(), scan1.Matches().size());
+ return false;
+}
+
+
bool IAddr_Func_EBPPrologue_VProf::FindAddrWin(uintptr_t& addr) const
{
#if defined __GNUC__
@@ -263,7 +325,7 @@ bool IAddr_Func_EBPPrologue_VProf::FindAddrWin(uintptr_t& addr) const
};
*(const char **)(vprof + 0x01) = p_name;
*(const char **)(vprof + 0x06) = p_group;
- CScan scan1(CLibSegBounds(this->GetLibrary(), ".text"), (const void *)vprof, sizeof(vprof));
+ CScan scan1(CLibSegBounds(this->GetLibrary(), Segment::TEXT), (const void *)vprof, sizeof(vprof));
if (!scan1.ExactlyOneMatch()) {
DevMsg("IAddr_Func_EBPPrologue_VProf: \"%s\": could not locate VPROF_BUDGET\n", this->GetName());
return false;
@@ -284,7 +346,7 @@ bool IAddr_Func_EBPPrologue_VProf::FindAddrWin(uintptr_t& addr) const
#if 0
bool IAddr_Func_EBPPrologue_UniqueConVar::FindAddrWin(uintptr_t& addr) const
{
- using ConVarRefScanner = CTypeScanner;
+ using ConVarRefScanner = CTypeScanner;
ConVarRef cvref(this->GetConVarName());
if (!cvref.IsValid()) {
@@ -317,7 +379,7 @@ bool IAddr_Func_EBPPrologue_UniqueConVar::FindAddrWin(uintptr_t& addr) const
// return false;
// }
//
-// CScan scan1(CLibSegBounds(this->GetLibrary(), ".text"), p_str);
+// CScan scan1(CLibSegBounds(this->GetLibrary(), Segment::TEXT), p_str);
// if (!scan1.ExactlyOneMatch()) {
// DevMsg("IAddr_Func_EBPPrologue_UniqueStr: \"%s\": found %u refs to ostensibly unique string\n", this->GetName(), scan1.Matches().size());
// return false;
@@ -381,7 +443,7 @@ bool IAddr_Pattern::FindAddrWin(uintptr_t& addr) const
mask[i] = std::stoi(buf, nullptr, 0x10);
}
- CScan scan1(CLibSegBounds(this->GetLibrary(), this->GetSegment()), seek, mask);
+ CScan scan1(CLibSegBounds(this->GetLibrary(), LibMgr::Seg_FromString(this->GetSegment())), seek, mask);
if (!scan1.ExactlyOneMatch()) {
DevMsg("IAddr_Pattern: \"%s\": found %u pattern matches\n", this->GetName(), scan1.Matches().size());
return false;
@@ -415,3 +477,17 @@ void CAddr_Pattern::ProcessStrings()
buf_mask.push_back('\0');
this->m_strMask = buf_mask.data();
}
+
+
+bool IAddr_ConCommandBase::FindAddrLinux(uintptr_t& addr) const
+{
+ const char *name = this->GetConName();
+ bool is_command = this->IsCommand();
+
+ #warning FINISH THIS!
+ #warning FINISH THIS!
+ #warning FINISH THIS!
+ #warning FINISH THIS!
+ #warning FINISH THIS!
+ #warning FINISH THIS!
+}
diff --git a/src/addr/standard.h b/src/addr/standard.h
index cc697141..11c2a0ef 100644
--- a/src/addr/standard.h
+++ b/src/addr/standard.h
@@ -29,6 +29,16 @@ class CAddr_Sym : public IAddr_Sym
};
+class CAddr_Sym_Regex : public CAddr_Sym
+{
+public:
+ CAddr_Sym_Regex(const std::string& name, const std::string& sym) :
+ CAddr_Sym(name, sym) {}
+
+ virtual bool FindAddrLinux(uintptr_t& addr) const override;
+};
+
+
#if 0
#define _ADDR_SYM(name, namestr, sym) \
class Addr_Base__##name : public IAddr_Sym \
@@ -264,6 +274,43 @@ class CAddr_Func_EBPPrologue_UniqueStr_KnownVTIdx : public IAddr_Func_EBPPrologu
};
+/* address finder for functions with these traits:
+ * 1. func body starts with "push ebp; mov ebp,esp"
+ * 2. func body contains a string reference which may not be unique
+ * 3. func is virtual and has a confidently known vtable index
+ */
+class IAddr_Func_EBPPrologue_NonUniqueStr_KnownVTIdx : public IAddr_Sym
+{
+public:
+ virtual bool FindAddrWin(uintptr_t& addr) const override;
+
+protected:
+ virtual const char *GetStr() const = 0;
+ virtual const char *GetVTableName() const = 0;
+ virtual int GetVTableIndex() const = 0;
+};
+
+class CAddr_Func_EBPPrologue_NonUniqueStr_KnownVTIdx : public IAddr_Func_EBPPrologue_NonUniqueStr_KnownVTIdx
+{
+public:
+ CAddr_Func_EBPPrologue_NonUniqueStr_KnownVTIdx(const std::string& name, const std::string& sym, const std::string& str, const std::string& vt_name, int vt_idx) :
+ m_strName(name), m_strSymbol(sym), m_strStr(str), m_strVTName(vt_name), m_iVTIndex(vt_idx) {}
+
+ virtual const char *GetName() const override { return this->m_strName.c_str(); }
+ virtual const char *GetSymbol() const override { return this->m_strSymbol.c_str(); }
+ virtual const char *GetStr() const override { return this->m_strStr.c_str(); }
+ virtual const char *GetVTableName() const override { return this->m_strVTName.c_str(); }
+ virtual int GetVTableIndex() const override { return this->m_iVTIndex; }
+
+private:
+ std::string m_strName;
+ std::string m_strSymbol;
+ std::string m_strStr;
+ std::string m_strVTName;
+ int m_iVTIndex;
+};
+
+
class IAddr_Func_EBPPrologue_VProf : public IAddr_Sym
{
public:
@@ -413,4 +460,32 @@ class CAddr_Pattern : public IAddr_Pattern
};
+class IAddr_ConCommandBase : public IAddr
+{
+public:
+ virtual bool FindAddrLinux(uintptr_t& addr) const override;
+ virtual bool FindAddrWin(uintptr_t& addr) const override { return this->FindAddrLinux(addr); }
+
+protected:
+ virtual const char *GetConName() const = 0;
+ virtual bool IsCommand() const = 0;
+};
+
+class CAddr_ConCommandBase : public IAddr_ConCommandBase
+{
+public:
+ CAddr_ConCommandBase(const std::string& name, const std::string& con_name, bool is_command) :
+ m_strName(name), m_strConName(con_name), m_bIsCommand(is_command) {}
+
+ virtual const char *GetName() const override { return this->m_strName.c_str(); }
+ virtual const char *GetConName() const override { return this->m_strConName.c_str(); }
+ virtual bool IsCommand() const override { return this->m_bIsCommand; }
+
+private:
+ std::string m_strName;
+ std::string m_strConName;
+ bool m_bIsCommand;
+};
+
+
#endif
diff --git a/src/common.h b/src/common.h
index 1902d26e..29158fe2 100644
--- a/src/common.h
+++ b/src/common.h
@@ -33,7 +33,14 @@ class ISoundEmitterSystemBase;
class IMaterialSystem;
namespace vgui {
+ class IVGui;
+ class IInput;
+ class IPanel;
class ISchemeManager;
+ class ISystem;
+ class ILocalize;
+ class IInputInternal;
+
class ISurface;
}
class IMatSystemSurface;
@@ -61,6 +68,8 @@ namespace SourceMod {
class IExtensionManager;
}
+class IClientMode;
+
extern IVEngineServer *engine;
extern IServerGameDLL *gamedll;
@@ -87,7 +96,13 @@ extern ISoundEmitterSystemBase *soundemitterbase;
extern IMaterialSystem *g_pMaterialSystem;
+extern vgui::IVGui *g_pVGui;
+extern vgui::IInput *g_pVGuiInput;
+extern vgui::IPanel *g_pVGuiPanel;
extern vgui::ISchemeManager *g_pVGuiSchemeManager;
+extern vgui::ISystem *g_pVGuiSystem;
+extern vgui::ILocalize *g_pVGuiLocalize;
+extern vgui::IInputInternal *g_pVGuiInputInternal;
extern vgui::ISurface *g_pVGuiSurface;
extern IMatSystemSurface *g_pMatSystemSurface;
@@ -111,6 +126,8 @@ extern IMDLCache *mdlcache;
extern SourcePawn::ISourcePawnEngine *g_pSourcePawn;
extern SourceMod::IExtensionManager *smexts;
+extern IClientMode *g_pClientMode;
+
/* C++ standard library */
#include
@@ -195,6 +212,10 @@ using namespace std::literals;
#include
+/* LodePNG */
+#include
+
+
/* Capstone */
#include
@@ -278,7 +299,13 @@ class IVideoRecorder;
#include
#include
#include
+#include
+#include
+#include
#include
+#include
+#include
+#include
#include
#include
#include
diff --git a/src/disasm/disasm.cpp b/src/disasm/disasm.cpp
index 24aa9738..c3e3027e 100644
--- a/src/disasm/disasm.cpp
+++ b/src/disasm/disasm.cpp
@@ -1,448 +1,4 @@
#include "disasm/disasm.h"
-#include "library.h"
-#include "util/prof.h"
-Disasm g_Disasm;
-
-#if 0
-#include
-#include
-namespace Disasm_diStorm
-{
- void Test()
- {
- DevMsg("Disasm_diStorm::Test BEGIN\n");
-
- LibInfo info = LibMgr::GetInfo(Library::SERVER);
-
- uint32_t lib_base = info.baseaddr;
-
- uint32_t text_off = info.segs[".text"].off;
- uint32_t text_len = info.segs[".text"].len;
-
-
- // _DInst: 64 bytes per instruction
-
- // all instructions:
- // 2,305,482
- // 148 MB
-
- // just flow control:
- // 706,387
- // 45 MB
-
-
- {
- _CodeInfo codeinfo;
- codeinfo.codeOffset = lib_base + text_off;
- codeinfo.code = (const uint8_t *)(lib_base + text_off);
- codeinfo.codeLen = text_len;
- codeinfo.dt = Decode32Bits;
- codeinfo.features = DF_NONE;
-
- constexpr unsigned int maxInstructions = 3000000;
- DevMsg(" sizeof(OFFSET_INTEGER) = %u\n", sizeof(OFFSET_INTEGER));
- DevMsg(" sizeof(_DInst) = %u\n", sizeof(_DInst));
- DevMsg(" calling malloc(%u)\n", sizeof(_DInst) * maxInstructions);
- _DInst *instrs = (_DInst *)malloc(sizeof(_DInst) * maxInstructions);
- DevMsg(" malloc returned: %08x\n", (uintptr_t)instrs);
-
- Prof::Begin();
- unsigned int usedInstructionsCount = 0;
- _DecodeResult result = distorm_decompose(&codeinfo, instrs, maxInstructions, &usedInstructionsCount);
- Prof::End("diStorm all instrs");
-
- DevMsg(" result: %d\n", result);
- DevMsg(" usedInstructionsCount: %u\n", usedInstructionsCount);
-
- FILE *file = fopen("D:\\server.txt", "w");
- if (file != nullptr) {
- char *buf = (char *)malloc(1024 * 1024);
- setvbuf(file, buf, _IOFBF, 1024 * 1024);
-
- for (unsigned int i = 0; i < usedInstructionsCount; ++i) {
- const _DInst *ins = instrs + i;
-
- uintptr_t addr = ins->addr - lib_base;
-
- if (ins->opcode == I_INT_3) {
- fprintf(file, "%08x: int 0x3\n", addr);
- } else if (ins->opcode == I_RET) {
- if (ins->ops[0].type == O_NONE) {
- fprintf(file, "%08x: ret\n", addr);
- } else if (ins->ops[0].type == O_IMM) {
- fprintf(file, "%08x: ret 0x%x\n", addr, ins->imm.word);
- } else {
- fprintf(file, "%08x: ret ???\n", addr);
- }
- } else if (ins->opcode == I_PUSH) {
- // fprintf(file, "%08x: push [type:%x index:%x size:%x]\n", addr,
- // ins->ops[0].type, ins->ops[0].index, ins->ops[0].size);
- if (ins->ops[0].type == O_REG && ins->ops[0].index == R_EBP) {
- fprintf(file, "%08x: push ebp\n", addr);
- }
- }
- }
-
- fclose(file);
- free(buf);
- }
-
- free(instrs);
- }
-
- {
- _CodeInfo codeinfo;
- codeinfo.codeOffset = lib_base + text_off;
- codeinfo.code = (const uint8_t *)(lib_base + text_off);
- codeinfo.codeLen = text_len;
- codeinfo.dt = Decode32Bits;
- codeinfo.features = DF_RETURN_FC_ONLY;
-
- constexpr unsigned int maxInstructions = 3000000;
- DevMsg(" sizeof(OFFSET_INTEGER) = %u\n", sizeof(OFFSET_INTEGER));
- DevMsg(" sizeof(_DInst) = %u\n", sizeof(_DInst));
- DevMsg(" calling malloc(%u)\n", sizeof(_DInst) * maxInstructions);
- _DInst *instrs = (_DInst *)malloc(sizeof(_DInst) * maxInstructions);
- DevMsg(" malloc returned: %08x\n", (uintptr_t)instrs);
-
- Prof::Begin();
- unsigned int usedInstructionsCount = 0;
- _DecodeResult result = distorm_decompose(&codeinfo, instrs, maxInstructions, &usedInstructionsCount);
- Prof::End("diStorm flow control only");
-
- DevMsg(" result: %d\n", result);
- DevMsg(" usedInstructionsCount: %u\n", usedInstructionsCount);
-
- free(instrs);
- }
-
- DevMsg("Disasm_diStorm::Test END\n");
- }
-}
-#endif
-
-
-#if 0
-#include
-namespace Disasm_Capstone
-{
- csh handle = 0;
-
-
- void *my_malloc(size_t size)
- {
- DevMsg(" malloc(%u)\n", size);
- return malloc(size);
- }
- void *my_calloc(size_t nmemb, size_t size)
- {
- DevMsg(" calloc(%u, %u)\n", nmemb, size);
- return calloc(nmemb, size);
- }
- void *my_realloc(void *ptr, size_t size)
- {
- DevMsg(" realloc(%08x, %u)\n", (uintptr_t)ptr, size);
- return realloc(ptr, size);
- }
- void my_free(void *ptr)
- {
- DevMsg(" free(%08x)\n", (uintptr_t)ptr);
- free(ptr);
- }
- int my_vsnprintf(char *str, size_t size, const char *format, va_list ap)
- {
- return vsnprintf(str, size, format, ap);
- }
-
-
- void ErrCheck(const char *what)
- {
- cs_err err = cs_errno(handle);
- if (err != cs_err::CS_ERR_OK) {
- DevMsg(" error in %s: %s\n", what, cs_strerror(err));
- }
- }
-
- void Test()
- {
- DevMsg("Disasm_Capstone::Test BEGIN\n");
-
- LibInfo info = LibMgr::GetInfo(Library::SERVER);
-
- uint32_t lib_base = info.baseaddr;
-
- uint32_t text_off = info.segs[".text"].off;
- uint32_t text_len = info.segs[".text"].len;
-
- uint32_t code_begin = lib_base + text_off;
- uint32_t code_end = lib_base + text_off + text_len;
-
-
- cs_opt_mem my_mem = {
- &my_malloc,
- &my_calloc,
- &my_realloc,
- &my_free,
- &my_vsnprintf,
- };
-
-
- cs_open(CS_ARCH_X86, CS_MODE_32, &handle);
- ErrCheck("cs_open");
-
- cs_option(handle, CS_OPT_SYNTAX, CS_OPT_SYNTAX_INTEL);
- ErrCheck("CS_OPT_SYNTAX");
- cs_option(handle, CS_OPT_DETAIL, CS_OPT_OFF);
- ErrCheck("CS_OPT_DETAIL");
- cs_option(handle, CS_OPT_SKIPDATA, CS_OPT_ON);
- ErrCheck("CS_OPT_SKIPDATA");
- cs_option(handle, CS_OPT_MEM, (size_t)&my_mem);
- ErrCheck("CS_OPT_MEM");
-
-
- cs_insn *insn = cs_malloc(handle);
-
- const uint8_t *code = (const uint8_t *)code_begin;
- size_t size = text_len;
- uint64_t address = code_begin;
-
- FILE *file = fopen("D:\\server.txt", "w");
-
- long n_insns = 0;
- while (cs_disasm_iter(handle, &code, &size, &address, insn)) {
- fprintf(file, " %08llx: %s\t%s\n", insn->address, insn->mnemonic, insn->op_str);
- ++n_insns;
- }
- DevMsg(" %ld insns\n", n_insns);
-
- fclose(file);
-
- cs_free(insn, 1);
-
- cs_close(&handle);
-
- DevMsg("Disasm_Capstone::Test END\n");
- }
-}
-#endif
-
-
-#if 0
-#include
-namespace Disasm_Capstone_Cxx
-{
- void Test()
- {
- DevMsg("Disasm_Capstone::Test BEGIN\n");
-
- LibInfo info = LibMgr::GetInfo(Library::SERVER);
-
- uint32_t lib_base = info.baseaddr;
-
- uint32_t text_off = info.segs[".text"].off;
- uint32_t text_len = info.segs[".text"].len;
-
-
- CX86Disasm86 dis;
-
- cs_err err;
- if ((err = dis.GetError()) != CS_ERR_OK) {
- DevMsg(" capstone error: '%s'\n", dis.ErrToStr(err));
- }
-
- dis.SetSyntax(cs_opt_value::CS_OPT_SYNTAX_INTEL);
- dis.SetDetail(cs_opt_value::CS_OPT_OFF);
- dis.SetSkipData(cs_opt_value::CS_OPT_ON);
-
- auto insns = dis.Disasm((const void *)(lib_base + text_off), text_len, lib_base + text_off);
-// if (!insns.get()) {
-// DevMsg(" can't get insn\n");
-// }
-
- FILE *file = fopen("D:\\server.txt", "w");
- DevMsg(" %u insns\n", insns->Count);
- for (size_t i = 0; i < insns->Count; ++i) {
- auto insn = insns->Instructions(i);
-
- fprintf(file, "-> %08llx: %s\t%s\n", insn->address, insn->mnemonic, insn->op_str);
- }
- fclose(file);
-
- DevMsg("Disasm_Capstone::Test END\n");
- }
-}
-#endif
-
-
-#if 0
-#include
-namespace Disasm_udis86
-{
- void Test()
- {
- DevMsg("Disasm_udis86::Test BEGIN\n");
- DevMsg("Disasm_udis86::Test END\n");
- }
-}
-#endif
-
-
-#if 0
-namespace Disasm
-{
- void Test()
- {
-#if defined _MSC_VER
- Disasm_diStorm::Test();
- Disasm_Capstone::Test();
-// Disasm_CapstoneCxx::Test();
-// Test_udis86();
-#endif
- }
-}
-#endif
-
-
-Disasm::~Disasm()
-{
- // TODO: free memory
-}
-
-
-void Disasm::ErrCheck(const char *what)
-{
- cs_err err = cs_errno(this->m_Handle);
- if (err != cs_err::CS_ERR_OK) {
- DevMsg(" error in %s: %s\n", what, cs_strerror(err));
- }
-}
-
-void Disasm::Load()
-{
- DevMsg("Disasm_Capstone::Test BEGIN\n");
-
- LibInfo info = LibMgr::GetInfo(Library::SERVER);
-
- uint32_t lib_base = info.baseaddr;
-
- uint32_t text_off = info.segs[".text"].off;
- uint32_t text_len = info.segs[".text"].len;
-
- uint32_t code_begin = lib_base + text_off;
- uint32_t code_end = lib_base + text_off + text_len;
-
- cs_open(CS_ARCH_X86, CS_MODE_32, &this->m_Handle);
- ErrCheck("cs_open");
-
- cs_option(this->m_Handle, CS_OPT_SYNTAX, CS_OPT_SYNTAX_INTEL);
- ErrCheck("CS_OPT_SYNTAX");
- cs_option(this->m_Handle, CS_OPT_DETAIL, CS_OPT_ON); // TODO: disable detail if possible
- ErrCheck("CS_OPT_DETAIL");
- cs_option(this->m_Handle, CS_OPT_SKIPDATA, CS_OPT_ON);
- ErrCheck("CS_OPT_SKIPDATA");
-// cs_option(this->m_Handle, CS_OPT_MEM, (size_t)&my_mem);
-// ErrCheck("CS_OPT_MEM");
-
- cs_insn *insn = cs_malloc(this->m_Handle);
-
- const uint8_t *code = (const uint8_t *)code_begin;
- size_t size = text_len;
- uint64_t address = code_begin;
-
- FILE *file = fopen("D:\\server.txt", "w");
-
-
- // PASS: iterate all insns, store all immediate operands that are addrs in .text
- // PASS: iterate thru .rdata, store all dword-aligned dwords that are addrs in .text
- // (in both cases, filter out addrs which are not 0x10-aligned)
-
- // treat all these addrs as "potential func start points"
- // so if we have a long forward jmp and pass one of these addrs, assume the func ended
-
-
- struct FuncInfo
- {
- uint32_t addr;
- uint32_t len;
- };
-
- std::vector funcs;
-
- FuncInfo func = {(uint32_t)address, 0};
- bool in_func = true;
-
- while (cs_disasm_iter(this->m_Handle, &code, &size, &address, insn)) {
-
-
- if (insn->id == X86_INS_INT3) {
- if (in_func) {
- func.len = insn->address - func.addr;
- funcs.push_back(func);
- in_func = false;
- }
- } else {
- if (!in_func) {
- func.addr = insn->address;
- in_func = true;
- }
- }
- }
-
- if (in_func) {
- func.len = insn->address - func.addr;
- funcs.push_back(func);
- }
-
- for (const auto& func : funcs) {
- fprintf(file, " func: %08x\n", 0x10001000 + func.addr - code_begin);
- fprintf(file, " %08x\n", 0x10001000 + func.addr + func.len - code_begin - 1);
- fprintf(file, "\n");
- }
-
-
- // TODO: try to handle switch jump tables properly
- // - look at how they work
- // - see how we may be mishandling them
- // - figure out a way to handle them properly
-
-
-#if 0
- long n_insns = 0;
- std::map stats;
- while (cs_disasm_iter(this->m_Handle, &code, &size, &address, insn)) {
- ++stats[insn->mnemonic];
-// fprintf(file, " %08llx: %s\t%s\n", insn->address, insn->mnemonic, insn->op_str);
- ++n_insns;
- }
- DevMsg(" %ld insns\n", n_insns);
-
- struct InsnStat
- {
- std::string name;
- long count;
- };
- std::vector sorted;
-
- for (const auto& pair : stats) {
- sorted.push_back({pair.first, pair.second});
- }
- std::sort(sorted.begin(), sorted.end(), [](InsnStat& lhs, InsnStat& rhs){
- return lhs.count > rhs.count;
- });
-
- for (const auto& stat : sorted) {
- DevMsg(" %6ld %s\n", stat.count, stat.name.c_str());
- }
-#endif
-
-
- fclose(file);
-
- cs_free(insn, 1);
- cs_close(&this->m_Handle);
-
- DevMsg("Disasm_Capstone::Test END\n");
-}
diff --git a/src/disasm/disasm.h b/src/disasm/disasm.h
index f5d26462..7dbf313b 100644
--- a/src/disasm/disasm.h
+++ b/src/disasm/disasm.h
@@ -2,46 +2,273 @@
#define _INCLUDE_SIGSEGV_DISASM_DISASM_H_
-class Disasm
+////////////////////////////////////////////////////////////////////////////////
+// Read-only pointer+count array accessor //////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+template
+class ArrayView
{
public:
- Disasm() {};
- ~Disasm();
+ ArrayView(const T *ptr, SIZE count) : m_pArray(ptr), m_Count(count) {}
- void Load();
+ ArrayView(const ArrayView&) = delete;
+ ArrayView(ArrayView&&) = default;
+
+ const T *begin() const { return this->m_pArray; }
+ const T *end() const { return this->m_pArray + this->m_Count; }
+
+ const T *cbegin() const { return begin(); }
+ const T *cend() const { return end(); }
+
+ SIZE size() const { return this->m_Count; }
+ bool empty() const { return (this->m_Count == 0); }
+
+ const T& front() const { return this->m_pArray[0]; }
+ const T& back() const { return this->m_pArray[this->m_Count - 1]; }
+
+ const T& operator[](SIZE idx) { return this->m_pArray[idx]; }
private:
- // int 3
- // int
- // int0
- // int1
- // call
- // ret
- // jmp
- // jcc
- // iret
- // iretd
+ const T *m_pArray;
+ SIZE m_Count;
+};
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Operand info ////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+class Operand : private cs_x86_op
+{
+public:
+ x86_op_type Type() const { return this->type; }
+ uint_fast8_t Size() const { return this->size; }
- // sysenter
- // sysexit
+ x86_reg Reg() const { return this->reg; }
+ int64_t Imm() const { return this->imm; }
+ double FP () const { return this->fp; }
- // enter
- // leave
+ uint8_t Imm_U8 () const { return static_cast< uint8_t>(this->imm); }
+ int8_t Imm_S8 () const { return static_cast< int8_t>(this->imm); }
+ uint16_t Imm_U16() const { return static_cast(this->imm); }
+ int16_t Imm_S16() const { return static_cast< int16_t>(this->imm); }
+ uint32_t Imm_U32() const { return static_cast(this->imm); }
+ int32_t Imm_S32() const { return static_cast< int32_t>(this->imm); }
+ uint64_t Imm_U64() const { return static_cast(this->imm); }
+ int64_t Imm_S64() const { return static_cast< int64_t>(this->imm); }
- // push ebp
- // mov ebp,esp
+ x86_reg Mem_Seg () const { return static_cast(this->mem.segment); }
+ x86_reg Mem_Base () const { return static_cast(this->mem.base ); }
+ x86_reg Mem_Index() const { return static_cast(this->mem.index ); }
+ uint_fast8_t Mem_Scale() const { return this->mem.scale; }
+ int64_t Mem_Disp () const { return this->mem.disp; }
- // mov esp,ebp
- // pop ebp
+ x86_avx_bcast AVX_Broadcast () const { return this->avx_bcast; }
+ bool AVX_ZeroOpMask() const { return this->avx_zero_opmask; }
+};
+static_assert(sizeof(Operand) == sizeof(cs_x86_op), "");
+
+////////////////////////////////////////////////////////////////////////////////
+// Non-detailed instruction info ///////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+class InstructionBase
+{
+private:
+ using BytesView = ArrayView;
- void ErrCheck(const char *what);
+public:
+ InstructionBase(const cs_insn *insn) : m_pInsn(insn) {}
- csh m_Handle = 0;
+ x86_insn ID () const { return static_cast(Insn().id); }
+ uint32_t Addr() const { return Insn().address; }
+
+ BytesView Bytes() const { return BytesView(Insn().bytes, Insn().size); }
+
+ const char *MnemonicStr() const { return Insn().mnemonic; }
+ const char *OperandStr () const { return Insn().op_str; }
+
+protected:
+ const cs_insn& Insn() const { return *this->m_pInsn; }
+
+private:
+ const cs_insn *m_pInsn;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// Detailed-only instruction info //////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+class InstructionDetailed : public InstructionBase
+{
+private:
+ using RegsView = ArrayView;
+ using GroupsView = ArrayView;
+ using OpcodeView = ArrayView;
+ using OperandView = ArrayView;
+
+public:
+ InstructionDetailed(const cs_insn *insn) : InstructionBase(insn) {}
+
+ RegsView RegsRead () const { return RegsView(Detail().regs_read, Detail().regs_read_count); }
+ RegsView RegsWrite() const { return RegsView(Detail().regs_write, Detail().regs_write_count); }
+
+ GroupsView Groups() const { return GroupsView(Detail().groups, Detail().groups_count); }
+
+ x86_prefix PrefixRepLock () const { return static_cast(X86().prefix[0]); }
+ x86_prefix PrefixSegment () const { return static_cast(X86().prefix[1]); }
+ x86_prefix PrefixOpSize () const { return static_cast(X86().prefix[2]); }
+ x86_prefix PrefixAddrSize() const { return static_cast(X86().prefix[3]); }
+
+ OpcodeView Opcode() const { return OpcodeView(X86().opcode, 4); }
+
+ uint8_t REX () const { return X86().rex; }
+ uint8_t AddrSize() const { return X86().addr_size; }
+ uint8_t ModRM () const { return X86().modrm; }
+ uint8_t SIB () const { return X86().sib; }
+ uint8_t Disp () const { return X86().disp; }
+
+ x86_reg SIB_Index() const { return X86().sib_index; }
+ uint8_t SIB_Scale() const { return X86().sib_scale; }
+ x86_reg SIB_Base () const { return X86().sib_base; }
+
+ x86_sse_cc SSE_CC () const { return X86().sse_cc; }
+ x86_avx_cc AVX_CC () const { return X86().avx_cc; }
+ bool AVX_SAE() const { return X86().avx_sae; }
+ x86_avx_rm AVX_RM () const { return X86().avx_rm; }
+
+ OperandView Operands() const { return OperandView(reinterpret_cast(X86().operands), X86().op_count); }
- std::map m_Int3;
- std::map m_Ret;
+ // TODO: implement these funcs manually, without need for the csh handle
+// bool IsInGroup (x86_insn_group group_id) const { return cs_insn_group(this->m_Handle, &this->Insn(), group_id); }
+// bool DoesReadReg (x86_reg reg_id) const { return cs_reg_read (this->m_Handle, &this->Insn(), reg_id); }
+// bool DoesWriteReg(x86_reg reg_id) const { return cs_reg_write (this->m_Handle, &this->Insn(), reg_id); }
+// int NumOperands (x86_op_type op_type) const { return cs_op_count (this->m_Handle, &this->Insn(), op_type); }
+
+private:
+ const cs_detail& Detail() const { return *this->Insn().detail; }
+ const cs_x86& X86 () const { return this->Detail().x86; }
+};
+
+
+template
+class DisasmResult
+{
+public:
+ using InstructionType = std::conditional_t;
+
+ DisasmResult(size_t count, cs_insn *insns) :
+ m_InsnCount(count), m_pInsnBuffer(insns)
+ {
+ for (size_t i = 0; i < count; ++i) {
+ this->m_InsnVector.push_back(InstructionType(&insns[i]));
+ }
+ }
+ ~DisasmResult()
+ {
+ if (this->m_pInsnBuffer != nullptr) {
+ cs_free(this->m_pInsnBuffer, this->m_InsnCount);
+ }
+ }
+
+ DisasmResult(const DisasmResult&) = delete;
+ DisasmResult(DisasmResult&&) = default;
+
+ auto begin() const { return this->m_InsnVector.cbegin(); }
+ auto end() const { return this->m_InsnVector.cend(); }
+
+ auto cbegin() const { return this->m_InsnVector.cbegin(); }
+ auto cend() const { return this->m_InsnVector.cend(); }
+
+ size_t size() const { return this->m_InsnVector.size(); }
+ bool empty() const { return this->m_InsnVector.empty(); }
+
+ const auto& front() const { return this->m_InsnVector.front(); }
+ const auto& back() const { return this->m_InsnVector.back(); }
+
+ const auto& operator[](size_t idx) { return this->m_InsnVector[idx]; }
+
+private:
+ size_t m_InsnCount;
+ cs_insn *m_pInsnBuffer;
+
+ std::vector m_InsnVector;
+};
+
+
+template
+class Disassembler
+{
+private:
+ static constexpr bool SKIP_DATA = false;
+
+public:
+ Disassembler()
+ {
+ auto arch = static_cast(CS_ARCH_X86);
+ auto mode = static_cast(CS_MODE_32 | CS_MODE_LITTLE_ENDIAN);
+
+ this->m_InitError = cs_open(arch, mode, &this->m_Handle);
+
+ if (this->Initialized()) {
+ (void)cs_option(this->m_Handle, CS_OPT_SYNTAX, CS_OPT_SYNTAX_INTEL);
+ (void)cs_option(this->m_Handle, CS_OPT_DETAIL, (DETAIL ? CS_OPT_ON : CS_OPT_OFF));
+ (void)cs_option(this->m_Handle, CS_OPT_SKIPDATA, (SKIP_DATA ? CS_OPT_ON : CS_OPT_OFF));
+ }
+ }
+ ~Disassembler()
+ {
+ if (this->m_Handle != 0) {
+ (void)cs_close(&this->m_Handle);
+ }
+ }
+
+ cs_err InitError() const { return this->m_InitError; }
+
+ cs_err ErrorCode() const { return cs_errno(this->m_Handle); }
+ const char *ErrorString() const { return cs_strerror(this->ErrorCode()); }
+
+ DisasmResult Disassemble(uintptr_t addr, size_t len, uintptr_t offset = 0, size_t max_insns = 0)
+ {
+ cs_insn *insns = nullptr;
+ size_t count = cs_disasm(this->m_Handle, reinterpret_cast(addr), len, addr + offset, max_insns, &insns);
+
+ return DisasmResult(count, insns);
+ }
+
+ template bool IterateRange(uintptr_t addr, size_t len, FUNCTOR&& func)
+ {
+ using InstructionType = std::conditional_t;
+
+ auto iter_code = reinterpret_cast(addr);
+ size_t iter_size = len;
+ auto iter_addr = (uint64_t)addr;
+ cs_insn *iter_insn = cs_malloc(this->m_Handle);
+
+ do {
+ if (!cs_disasm_iter(this->m_Handle, &iter_code, &iter_size, &iter_addr, iter_insn)) {
+ cs_free(iter_insn, 1);
+ return false;
+ }
+ } while (func(InstructionType(iter_insn)));
+
+ cs_free(iter_insn, 1);
+ return true;
+ }
+ template bool Iterate(uintptr_t addr, FUNCTOR&& func)
+ {
+ return this->IterateRange(addr, SIZE_MAX, func);
+ }
+
+ // TODO: version of Iterate with num-of-instrs restriction
+
+ const char *RegName(x86_reg reg_id) const { return cs_reg_name (this->m_Handle, reg_id); }
+ const char *InsnName(x86_insn insn_id) const { return cs_insn_name (this->m_Handle, insn_id); }
+ const char *GroupName(x86_insn_group group_id) const { return cs_group_name(this->m_Handle, group_id); }
+
+private:
+ bool Initialized() const { return (this->m_InitError == CS_ERR_OK && this->m_Handle != 0); }
+
+ csh m_Handle = 0;
+ cs_err m_InitError;
};
-extern Disasm g_Disasm;
#endif
diff --git a/src/disasm/old1/disasm.cpp b/src/disasm/old1/disasm.cpp
new file mode 100644
index 00000000..24aa9738
--- /dev/null
+++ b/src/disasm/old1/disasm.cpp
@@ -0,0 +1,448 @@
+#include "disasm/disasm.h"
+#include "library.h"
+#include "util/prof.h"
+
+
+Disasm g_Disasm;
+
+
+#if 0
+#include
+#include
+namespace Disasm_diStorm
+{
+ void Test()
+ {
+ DevMsg("Disasm_diStorm::Test BEGIN\n");
+
+ LibInfo info = LibMgr::GetInfo(Library::SERVER);
+
+ uint32_t lib_base = info.baseaddr;
+
+ uint32_t text_off = info.segs[".text"].off;
+ uint32_t text_len = info.segs[".text"].len;
+
+
+ // _DInst: 64 bytes per instruction
+
+ // all instructions:
+ // 2,305,482
+ // 148 MB
+
+ // just flow control:
+ // 706,387
+ // 45 MB
+
+
+ {
+ _CodeInfo codeinfo;
+ codeinfo.codeOffset = lib_base + text_off;
+ codeinfo.code = (const uint8_t *)(lib_base + text_off);
+ codeinfo.codeLen = text_len;
+ codeinfo.dt = Decode32Bits;
+ codeinfo.features = DF_NONE;
+
+ constexpr unsigned int maxInstructions = 3000000;
+ DevMsg(" sizeof(OFFSET_INTEGER) = %u\n", sizeof(OFFSET_INTEGER));
+ DevMsg(" sizeof(_DInst) = %u\n", sizeof(_DInst));
+ DevMsg(" calling malloc(%u)\n", sizeof(_DInst) * maxInstructions);
+ _DInst *instrs = (_DInst *)malloc(sizeof(_DInst) * maxInstructions);
+ DevMsg(" malloc returned: %08x\n", (uintptr_t)instrs);
+
+ Prof::Begin();
+ unsigned int usedInstructionsCount = 0;
+ _DecodeResult result = distorm_decompose(&codeinfo, instrs, maxInstructions, &usedInstructionsCount);
+ Prof::End("diStorm all instrs");
+
+ DevMsg(" result: %d\n", result);
+ DevMsg(" usedInstructionsCount: %u\n", usedInstructionsCount);
+
+ FILE *file = fopen("D:\\server.txt", "w");
+ if (file != nullptr) {
+ char *buf = (char *)malloc(1024 * 1024);
+ setvbuf(file, buf, _IOFBF, 1024 * 1024);
+
+ for (unsigned int i = 0; i < usedInstructionsCount; ++i) {
+ const _DInst *ins = instrs + i;
+
+ uintptr_t addr = ins->addr - lib_base;
+
+ if (ins->opcode == I_INT_3) {
+ fprintf(file, "%08x: int 0x3\n", addr);
+ } else if (ins->opcode == I_RET) {
+ if (ins->ops[0].type == O_NONE) {
+ fprintf(file, "%08x: ret\n", addr);
+ } else if (ins->ops[0].type == O_IMM) {
+ fprintf(file, "%08x: ret 0x%x\n", addr, ins->imm.word);
+ } else {
+ fprintf(file, "%08x: ret ???\n", addr);
+ }
+ } else if (ins->opcode == I_PUSH) {
+ // fprintf(file, "%08x: push [type:%x index:%x size:%x]\n", addr,
+ // ins->ops[0].type, ins->ops[0].index, ins->ops[0].size);
+ if (ins->ops[0].type == O_REG && ins->ops[0].index == R_EBP) {
+ fprintf(file, "%08x: push ebp\n", addr);
+ }
+ }
+ }
+
+ fclose(file);
+ free(buf);
+ }
+
+ free(instrs);
+ }
+
+ {
+ _CodeInfo codeinfo;
+ codeinfo.codeOffset = lib_base + text_off;
+ codeinfo.code = (const uint8_t *)(lib_base + text_off);
+ codeinfo.codeLen = text_len;
+ codeinfo.dt = Decode32Bits;
+ codeinfo.features = DF_RETURN_FC_ONLY;
+
+ constexpr unsigned int maxInstructions = 3000000;
+ DevMsg(" sizeof(OFFSET_INTEGER) = %u\n", sizeof(OFFSET_INTEGER));
+ DevMsg(" sizeof(_DInst) = %u\n", sizeof(_DInst));
+ DevMsg(" calling malloc(%u)\n", sizeof(_DInst) * maxInstructions);
+ _DInst *instrs = (_DInst *)malloc(sizeof(_DInst) * maxInstructions);
+ DevMsg(" malloc returned: %08x\n", (uintptr_t)instrs);
+
+ Prof::Begin();
+ unsigned int usedInstructionsCount = 0;
+ _DecodeResult result = distorm_decompose(&codeinfo, instrs, maxInstructions, &usedInstructionsCount);
+ Prof::End("diStorm flow control only");
+
+ DevMsg(" result: %d\n", result);
+ DevMsg(" usedInstructionsCount: %u\n", usedInstructionsCount);
+
+ free(instrs);
+ }
+
+ DevMsg("Disasm_diStorm::Test END\n");
+ }
+}
+#endif
+
+
+#if 0
+#include
+namespace Disasm_Capstone
+{
+ csh handle = 0;
+
+
+ void *my_malloc(size_t size)
+ {
+ DevMsg(" malloc(%u)\n", size);
+ return malloc(size);
+ }
+ void *my_calloc(size_t nmemb, size_t size)
+ {
+ DevMsg(" calloc(%u, %u)\n", nmemb, size);
+ return calloc(nmemb, size);
+ }
+ void *my_realloc(void *ptr, size_t size)
+ {
+ DevMsg(" realloc(%08x, %u)\n", (uintptr_t)ptr, size);
+ return realloc(ptr, size);
+ }
+ void my_free(void *ptr)
+ {
+ DevMsg(" free(%08x)\n", (uintptr_t)ptr);
+ free(ptr);
+ }
+ int my_vsnprintf(char *str, size_t size, const char *format, va_list ap)
+ {
+ return vsnprintf(str, size, format, ap);
+ }
+
+
+ void ErrCheck(const char *what)
+ {
+ cs_err err = cs_errno(handle);
+ if (err != cs_err::CS_ERR_OK) {
+ DevMsg(" error in %s: %s\n", what, cs_strerror(err));
+ }
+ }
+
+ void Test()
+ {
+ DevMsg("Disasm_Capstone::Test BEGIN\n");
+
+ LibInfo info = LibMgr::GetInfo(Library::SERVER);
+
+ uint32_t lib_base = info.baseaddr;
+
+ uint32_t text_off = info.segs[".text"].off;
+ uint32_t text_len = info.segs[".text"].len;
+
+ uint32_t code_begin = lib_base + text_off;
+ uint32_t code_end = lib_base + text_off + text_len;
+
+
+ cs_opt_mem my_mem = {
+ &my_malloc,
+ &my_calloc,
+ &my_realloc,
+ &my_free,
+ &my_vsnprintf,
+ };
+
+
+ cs_open(CS_ARCH_X86, CS_MODE_32, &handle);
+ ErrCheck("cs_open");
+
+ cs_option(handle, CS_OPT_SYNTAX, CS_OPT_SYNTAX_INTEL);
+ ErrCheck("CS_OPT_SYNTAX");
+ cs_option(handle, CS_OPT_DETAIL, CS_OPT_OFF);
+ ErrCheck("CS_OPT_DETAIL");
+ cs_option(handle, CS_OPT_SKIPDATA, CS_OPT_ON);
+ ErrCheck("CS_OPT_SKIPDATA");
+ cs_option(handle, CS_OPT_MEM, (size_t)&my_mem);
+ ErrCheck("CS_OPT_MEM");
+
+
+ cs_insn *insn = cs_malloc(handle);
+
+ const uint8_t *code = (const uint8_t *)code_begin;
+ size_t size = text_len;
+ uint64_t address = code_begin;
+
+ FILE *file = fopen("D:\\server.txt", "w");
+
+ long n_insns = 0;
+ while (cs_disasm_iter(handle, &code, &size, &address, insn)) {
+ fprintf(file, " %08llx: %s\t%s\n", insn->address, insn->mnemonic, insn->op_str);
+ ++n_insns;
+ }
+ DevMsg(" %ld insns\n", n_insns);
+
+ fclose(file);
+
+ cs_free(insn, 1);
+
+ cs_close(&handle);
+
+ DevMsg("Disasm_Capstone::Test END\n");
+ }
+}
+#endif
+
+
+#if 0
+#include
+namespace Disasm_Capstone_Cxx
+{
+ void Test()
+ {
+ DevMsg("Disasm_Capstone::Test BEGIN\n");
+
+ LibInfo info = LibMgr::GetInfo(Library::SERVER);
+
+ uint32_t lib_base = info.baseaddr;
+
+ uint32_t text_off = info.segs[".text"].off;
+ uint32_t text_len = info.segs[".text"].len;
+
+
+ CX86Disasm86 dis;
+
+ cs_err err;
+ if ((err = dis.GetError()) != CS_ERR_OK) {
+ DevMsg(" capstone error: '%s'\n", dis.ErrToStr(err));
+ }
+
+ dis.SetSyntax(cs_opt_value::CS_OPT_SYNTAX_INTEL);
+ dis.SetDetail(cs_opt_value::CS_OPT_OFF);
+ dis.SetSkipData(cs_opt_value::CS_OPT_ON);
+
+ auto insns = dis.Disasm((const void *)(lib_base + text_off), text_len, lib_base + text_off);
+// if (!insns.get()) {
+// DevMsg(" can't get insn\n");
+// }
+
+ FILE *file = fopen("D:\\server.txt", "w");
+ DevMsg(" %u insns\n", insns->Count);
+ for (size_t i = 0; i < insns->Count; ++i) {
+ auto insn = insns->Instructions(i);
+
+ fprintf(file, "-> %08llx: %s\t%s\n", insn->address, insn->mnemonic, insn->op_str);
+ }
+ fclose(file);
+
+ DevMsg("Disasm_Capstone::Test END\n");
+ }
+}
+#endif
+
+
+#if 0
+#include
+namespace Disasm_udis86
+{
+ void Test()
+ {
+ DevMsg("Disasm_udis86::Test BEGIN\n");
+ DevMsg("Disasm_udis86::Test END\n");
+ }
+}
+#endif
+
+
+#if 0
+namespace Disasm
+{
+ void Test()
+ {
+#if defined _MSC_VER
+ Disasm_diStorm::Test();
+ Disasm_Capstone::Test();
+// Disasm_CapstoneCxx::Test();
+// Test_udis86();
+#endif
+ }
+}
+#endif
+
+
+Disasm::~Disasm()
+{
+ // TODO: free memory
+}
+
+
+void Disasm::ErrCheck(const char *what)
+{
+ cs_err err = cs_errno(this->m_Handle);
+ if (err != cs_err::CS_ERR_OK) {
+ DevMsg(" error in %s: %s\n", what, cs_strerror(err));
+ }
+}
+
+void Disasm::Load()
+{
+ DevMsg("Disasm_Capstone::Test BEGIN\n");
+
+ LibInfo info = LibMgr::GetInfo(Library::SERVER);
+
+ uint32_t lib_base = info.baseaddr;
+
+ uint32_t text_off = info.segs[".text"].off;
+ uint32_t text_len = info.segs[".text"].len;
+
+ uint32_t code_begin = lib_base + text_off;
+ uint32_t code_end = lib_base + text_off + text_len;
+
+ cs_open(CS_ARCH_X86, CS_MODE_32, &this->m_Handle);
+ ErrCheck("cs_open");
+
+ cs_option(this->m_Handle, CS_OPT_SYNTAX, CS_OPT_SYNTAX_INTEL);
+ ErrCheck("CS_OPT_SYNTAX");
+ cs_option(this->m_Handle, CS_OPT_DETAIL, CS_OPT_ON); // TODO: disable detail if possible
+ ErrCheck("CS_OPT_DETAIL");
+ cs_option(this->m_Handle, CS_OPT_SKIPDATA, CS_OPT_ON);
+ ErrCheck("CS_OPT_SKIPDATA");
+// cs_option(this->m_Handle, CS_OPT_MEM, (size_t)&my_mem);
+// ErrCheck("CS_OPT_MEM");
+
+ cs_insn *insn = cs_malloc(this->m_Handle);
+
+ const uint8_t *code = (const uint8_t *)code_begin;
+ size_t size = text_len;
+ uint64_t address = code_begin;
+
+ FILE *file = fopen("D:\\server.txt", "w");
+
+
+ // PASS: iterate all insns, store all immediate operands that are addrs in .text
+ // PASS: iterate thru .rdata, store all dword-aligned dwords that are addrs in .text
+ // (in both cases, filter out addrs which are not 0x10-aligned)
+
+ // treat all these addrs as "potential func start points"
+ // so if we have a long forward jmp and pass one of these addrs, assume the func ended
+
+
+ struct FuncInfo
+ {
+ uint32_t addr;
+ uint32_t len;
+ };
+
+ std::vector funcs;
+
+ FuncInfo func = {(uint32_t)address, 0};
+ bool in_func = true;
+
+ while (cs_disasm_iter(this->m_Handle, &code, &size, &address, insn)) {
+
+
+ if (insn->id == X86_INS_INT3) {
+ if (in_func) {
+ func.len = insn->address - func.addr;
+ funcs.push_back(func);
+ in_func = false;
+ }
+ } else {
+ if (!in_func) {
+ func.addr = insn->address;
+ in_func = true;
+ }
+ }
+ }
+
+ if (in_func) {
+ func.len = insn->address - func.addr;
+ funcs.push_back(func);
+ }
+
+ for (const auto& func : funcs) {
+ fprintf(file, " func: %08x\n", 0x10001000 + func.addr - code_begin);
+ fprintf(file, " %08x\n", 0x10001000 + func.addr + func.len - code_begin - 1);
+ fprintf(file, "\n");
+ }
+
+
+ // TODO: try to handle switch jump tables properly
+ // - look at how they work
+ // - see how we may be mishandling them
+ // - figure out a way to handle them properly
+
+
+#if 0
+ long n_insns = 0;
+ std::map stats;
+ while (cs_disasm_iter(this->m_Handle, &code, &size, &address, insn)) {
+ ++stats[insn->mnemonic];
+// fprintf(file, " %08llx: %s\t%s\n", insn->address, insn->mnemonic, insn->op_str);
+ ++n_insns;
+ }
+ DevMsg(" %ld insns\n", n_insns);
+
+ struct InsnStat
+ {
+ std::string name;
+ long count;
+ };
+ std::vector sorted;
+
+ for (const auto& pair : stats) {
+ sorted.push_back({pair.first, pair.second});
+ }
+ std::sort(sorted.begin(), sorted.end(), [](InsnStat& lhs, InsnStat& rhs){
+ return lhs.count > rhs.count;
+ });
+
+ for (const auto& stat : sorted) {
+ DevMsg(" %6ld %s\n", stat.count, stat.name.c_str());
+ }
+#endif
+
+
+ fclose(file);
+
+ cs_free(insn, 1);
+ cs_close(&this->m_Handle);
+
+ DevMsg("Disasm_Capstone::Test END\n");
+}
diff --git a/src/disasm/old1/disasm.h b/src/disasm/old1/disasm.h
new file mode 100644
index 00000000..f5d26462
--- /dev/null
+++ b/src/disasm/old1/disasm.h
@@ -0,0 +1,47 @@
+#ifndef _INCLUDE_SIGSEGV_DISASM_DISASM_H_
+#define _INCLUDE_SIGSEGV_DISASM_DISASM_H_
+
+
+class Disasm
+{
+public:
+ Disasm() {};
+ ~Disasm();
+
+ void Load();
+
+private:
+ // int 3
+ // int
+ // int0
+ // int1
+ // call
+ // ret
+ // jmp
+ // jcc
+ // iret
+ // iretd
+
+ // sysenter
+ // sysexit
+
+ // enter
+ // leave
+
+ // push ebp
+ // mov ebp,esp
+
+ // mov esp,ebp
+ // pop ebp
+
+ void ErrCheck(const char *what);
+
+ csh m_Handle = 0;
+
+ std::map m_Int3;
+ std::map m_Ret;
+};
+extern Disasm g_Disasm;
+
+
+#endif
diff --git a/src/disasm/old2/disasm.h b/src/disasm/old2/disasm.h
new file mode 100644
index 00000000..062761ff
--- /dev/null
+++ b/src/disasm/old2/disasm.h
@@ -0,0 +1,49 @@
+#ifndef _INCLUDE_SIGSEGV_DISASM_DISASM_H_
+#define _INCLUDE_SIGSEGV_DISASM_DISASM_H_
+
+
+#if !defined _MSC_VER
+#define __in
+#define __out
+#define __inout
+#define __forceinline //[[gnu::always_inline]]
+#define __checkReturn [[gnu::warn_unused_result]]
+#endif
+
+#include
+
+
+class Disassembler : private CX86Disasm86
+{
+private:
+ using Base = CX86Disasm86;
+
+public:
+ template Disassembler(ARGS... args) : Base(std::forward(args)...)
+ {
+ this->SetSyntax (cs_opt_value::CS_OPT_SYNTAX_INTEL);
+ this->SetDetail (cs_opt_value::CS_OPT_ON);
+ this->SetSkipData(cs_opt_value::CS_OPT_OFF);
+ }
+
+ using Base::GetError;
+ using Base::Version;
+ using Base::ErrToStr;
+ using Base::SetSyntax;
+ using Base::SetDetail;
+ using Base::SetMode;
+ using Base::SetMemMgrFunc;
+ using Base::SetSkipData;
+ using Base::SetSkipDataCallback;
+
+ bool HasError() { return (this->GetError() != CS_ERR_OK); }
+ const char *ErrorStr() { return Base::ErrToStr(this->GetError()); }
+
+ template std::unique_ptr Disasm(ARGS... args)
+ {
+ return std::unique_ptr(Base::Disasm(std::forward(args)...));
+ }
+};
+
+
+#endif
diff --git a/src/extension.cpp b/src/extension.cpp
index df30101a..2f7eff7e 100644
--- a/src/extension.cpp
+++ b/src/extension.cpp
@@ -42,7 +42,13 @@ ISoundEmitterSystemBase *soundemitterbase = nullptr;
IMaterialSystem *g_pMaterialSystem = nullptr;
+vgui::IVGui *g_pVGui = nullptr;
+vgui::IInput *g_pVGuiInput = nullptr;
+vgui::IPanel *g_pVGuiPanel = nullptr;
vgui::ISchemeManager *g_pVGuiSchemeManager = nullptr;
+vgui::ISystem *g_pVGuiSystem = nullptr;
+vgui::ILocalize *g_pVGuiLocalize = nullptr;
+vgui::IInputInternal *g_pVGuiInputInternal = nullptr;
vgui::ISurface *g_pVGuiSurface = nullptr;
IMatSystemSurface *g_pMatSystemSurface = nullptr;
@@ -68,6 +74,8 @@ IDedicatedExports *dedicated = nullptr;
IMDLCache *mdlcache = nullptr;
+IClientMode *g_pClientMode = nullptr;
+
bool CExtSigsegv::SDK_OnLoad(char *error, size_t maxlen, bool late)
{
@@ -96,6 +104,8 @@ bool CExtSigsegv::SDK_OnLoad(char *error, size_t maxlen, bool late)
RTTI::PreLoad();
AddrManager::Load();
+ g_pClientMode = reinterpret_cast(AddrManager::GetAddr("g_pClientMode"));
+
if (!Link::InitAll()) goto fail;
Prop::PreloadAll();
@@ -152,13 +162,16 @@ bool CExtSigsegv::QueryRunning(char *error, size_t maxlen)
#define GET_IFACE_OPTIONAL(factory, var, name) \
- var = reinterpret_cast(ismm->VInterfaceMatch(factory##Factory(), name, -1))
+ var = reinterpret_cast(ismm->VInterfaceMatch(factory##Factory(), name, -1)); \
+ if (var == nullptr) { \
+ DevWarning("Could not find optional interface: %s\n", name); \
+ }
#define GET_IFACE_REQUIRED(factory, var, name) \
var = reinterpret_cast(ismm->VInterfaceMatch(factory##Factory(), name, -1)); \
if (var == nullptr) { \
if (error != nullptr && maxlen != 0) { \
- ismm->Format(error, maxlen, "Could not find interface: %s", name); \
+ ismm->Format(error, maxlen, "Could not find required interface: %s", name); \
} \
return false; \
}
@@ -191,8 +204,8 @@ bool CExtSigsegv::SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlen, b
GET_IFACE_REQUIRED(Server, botmanager, INTERFACEVERSION_PLAYERBOTMANAGER);
GET_IFACE_REQUIRED(Server, servertools, VSERVERTOOLS_INTERFACE_VERSION);
- GET_IFACE_REQUIRED(Physics, physics, VPHYSICS_INTERFACE_VERSION);
- GET_IFACE_REQUIRED(Physics, physcollision, VPHYSICS_COLLISION_INTERFACE_VERSION);
+ GET_IFACE_REQUIRED(VPhysics, physics, VPHYSICS_INTERFACE_VERSION);
+ GET_IFACE_REQUIRED(VPhysics, physcollision, VPHYSICS_COLLISION_INTERFACE_VERSION);
GET_IFACE_OPTIONAL(Engine, debugoverlay, VDEBUG_OVERLAY_INTERFACE_VERSION);
GET_IFACE_OPTIONAL(Engine, enginetools, VENGINETOOL_INTERFACE_VERSION);
@@ -206,7 +219,13 @@ bool CExtSigsegv::SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlen, b
}
if (VGUIFactory() != nullptr) {
+ GET_IFACE_OPTIONAL(VGUI, g_pVGui, VGUI_IVGUI_INTERFACE_VERSION);
+ GET_IFACE_OPTIONAL(VGUI, g_pVGuiInput, VGUI_INPUT_INTERFACE_VERSION);
+ GET_IFACE_OPTIONAL(VGUI, g_pVGuiPanel, VGUI_PANEL_INTERFACE_VERSION);
GET_IFACE_OPTIONAL(VGUI, g_pVGuiSchemeManager, VGUI_SCHEME_INTERFACE_VERSION);
+ GET_IFACE_OPTIONAL(VGUI, g_pVGuiSystem, VGUI_SYSTEM_INTERFACE_VERSION);
+ GET_IFACE_OPTIONAL(VGUI, g_pVGuiLocalize, VGUI_LOCALIZE_INTERFACE_VERSION);
+ GET_IFACE_OPTIONAL(VGUI, g_pVGuiInputInternal, VGUI_INPUTINTERNAL_INTERFACE_VERSION);
}
if (VGUIMatSurfaceFactory() != nullptr) {
@@ -232,12 +251,17 @@ bool CExtSigsegv::SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlen, b
gpGlobals = ismm->GetCGlobals();
- LibMgr::SetPtr(Library::SERVER, ServerFactory());
- LibMgr::SetPtr(Library::ENGINE, EngineFactory());
- LibMgr::SetPtr(Library::DEDICATED, dedicated);
- LibMgr::SetPtr(Library::TIER0, &MemAllocScratch);
- LibMgr::SetPtr(Library::CLIENT, clientdll);
- LibMgr::SetPtr(Library::VGUIMATSURFACE, g_pVGuiSurface);
+ LibMgr::SetPtr(Library::SERVER, ServerFactory());
+ LibMgr::SetPtr(Library::ENGINE, EngineFactory());
+ LibMgr::SetPtr(Library::DEDICATED, DedicatedFactory());
+ LibMgr::SetPtr(Library::TIER0, &MemAllocScratch);
+ LibMgr::SetPtr(Library::CLIENT, ClientFactory());
+ LibMgr::SetPtr(Library::VGUIMATSURFACE, VGUIMatSurfaceFactory());
+ LibMgr::SetPtr(Library::MATERIALSYSTEM, MaterialSystemFactory());
+ LibMgr::SetPtr(Library::SOUNDEMITTERSYSTEM, SoundEmitterSystemFactory());
+ LibMgr::SetPtr(Library::DATACACHE, DataCacheFactory());
+ LibMgr::SetPtr(Library::VGUI, VGUIFactory());
+ LibMgr::SetPtr(Library::VPHYSICS, VPhysicsFactory());
return true;
}
diff --git a/src/factory.h b/src/factory.h
index 27cc54a3..1fa201bf 100644
--- a/src/factory.h
+++ b/src/factory.h
@@ -3,7 +3,7 @@
inline CreateInterfaceFn EngineFactory() { return g_SMAPI->GetEngineFactory (false); }
-inline CreateInterfaceFn PhysicsFactory() { return g_SMAPI->GetPhysicsFactory (false); }
+inline CreateInterfaceFn VPhysicsFactory() { return g_SMAPI->GetPhysicsFactory (false); }
inline CreateInterfaceFn FileSystemFactory() { return g_SMAPI->GetFileSystemFactory(false); }
inline CreateInterfaceFn ServerFactory() { return g_SMAPI->GetServerFactory (false); }
diff --git a/src/gameconf.cpp b/src/gameconf.cpp
index 81ed486c..f71d707f 100644
--- a/src/gameconf.cpp
+++ b/src/gameconf.cpp
@@ -35,6 +35,7 @@ static const char *const configs[] = {
"sigsegv/misc",
"sigsegv/debugoverlay",
"sigsegv/client",
+ "sigsegv/convars",
nullptr,
};
@@ -204,7 +205,7 @@ void CSigsegvGameConf::AddrEntry_Load_Common(IAddr *addr)
const auto& kv = this->m_AddrEntry_State.m_KeyValues;
if (kv.find("lib") != kv.end()) {
- addr->SetLibrary(LibMgr::FromString(kv.at("lib").c_str()));
+ addr->SetLibrary(LibMgr::Lib_FromString(kv.at("lib").c_str()));
}
}
@@ -229,6 +230,26 @@ SMCResult CSigsegvGameConf::AddrEntry_Load_Sym()
return SMCResult_Continue;
}
+SMCResult CSigsegvGameConf::AddrEntry_Load_Sym_Regex()
+{
+ const auto& name = this->m_AddrEntry_State.m_Name;
+ const auto& kv = this->m_AddrEntry_State.m_KeyValues;
+
+ for (const std::string& key : { "sym" }) {
+ if (kv.find(key) == kv.end()) {
+ DevMsg("GameData error: addr \"%s\" lacks required key \"%s\"\n", name.c_str(), key.c_str());
+ return SMCResult_HaltFail;
+ }
+ }
+
+ const auto& sym = kv.at("sym");
+
+ auto a = new CAddr_Sym_Regex(name, sym);
+ this->AddrEntry_Load_Common(a);
+ this->m_AddrPtrs.push_back(std::unique_ptr(a));
+ return SMCResult_Continue;
+}
+
SMCResult CSigsegvGameConf::AddrEntry_Load_Fixed()
{
const auto& name = this->m_AddrEntry_State.m_Name;
@@ -330,11 +351,11 @@ SMCResult CSigsegvGameConf::AddrEntry_Load_Func_DataMap_VThunk()
}
const auto& sym = kv.at("sym");
- const auto& dm_name = kv.at("datamap");
+ const auto& datamap = kv.at("datamap");
const auto& f_name = kv.at("func");
const auto& vtable = kv.at("vtable");
- auto a = new CAddr_Func_DataMap_VThunk(name, sym, dm_name, f_name, vtable);
+ auto a = new CAddr_Func_DataMap_VThunk(name, sym, datamap, f_name, vtable);
this->AddrEntry_Load_Common(a);
this->m_AddrPtrs.push_back(std::unique_ptr(a));
return SMCResult_Continue;
@@ -405,6 +426,29 @@ SMCResult CSigsegvGameConf::AddrEntry_Load_Func_EBPPrologue_UniqueStr_KnownVTIdx
return SMCResult_Continue;
}
+SMCResult CSigsegvGameConf::AddrEntry_Load_Func_EBPPrologue_NonUniqueStr_KnownVTIdx()
+{
+ const auto& name = this->m_AddrEntry_State.m_Name;
+ const auto& kv = this->m_AddrEntry_State.m_KeyValues;
+
+ for (const std::string& key : { "sym", "str", "vtable", "idx" }) {
+ if (kv.find(key) == kv.end()) {
+ DevMsg("GameData error: addr \"%s\" lacks required key \"%s\"\n", name.c_str(), key.c_str());
+ return SMCResult_HaltFail;
+ }
+ }
+
+ const auto& sym = kv.at("sym");
+ const auto& str = kv.at("str");
+ const auto& vtable = kv.at("vtable");
+ int idx = stoi(kv.at("idx"), nullptr, 0);
+
+ auto a = new CAddr_Func_EBPPrologue_NonUniqueStr_KnownVTIdx(name, sym, str, vtable, idx);
+ this->AddrEntry_Load_Common(a);
+ this->m_AddrPtrs.push_back(std::unique_ptr(a));
+ return SMCResult_Continue;
+}
+
SMCResult CSigsegvGameConf::AddrEntry_Load_Func_EBPPrologue_VProf()
{
const auto& name = this->m_AddrEntry_State.m_Name;
@@ -426,3 +470,23 @@ SMCResult CSigsegvGameConf::AddrEntry_Load_Func_EBPPrologue_VProf()
this->m_AddrPtrs.push_back(std::unique_ptr(a));
return SMCResult_Continue;
}
+
+SMCResult CSigsegvGameConf::AddrEntry_Load_ConCommandBase(bool is_command)
+{
+ const auto& name = this->m_AddrEntry_State.m_Name;
+ const auto& kv = this->m_AddrEntry_State.m_KeyValues;
+
+ for (const std::string& key : { "name" }) {
+ if (kv.find(key) == kv.end()) {
+ DevMsg("GameData error: addr \"%s\" lacks required key \"%s\"\n", name.c_str(), key.c_str());
+ return SMCResult_HaltFail;
+ }
+ }
+
+ const auto& con_name = kv.at("name");
+
+ auto a = new CAddr_ConCommandBase(name, con_name, is_command);
+ this->AddrEntry_Load_Common(a);
+ this->m_AddrPtrs.push_back(std::unique_ptr(a));
+ return SMCResult_Continue;
+}
diff --git a/src/gameconf.h b/src/gameconf.h
index 99dbd050..c343abbb 100644
--- a/src/gameconf.h
+++ b/src/gameconf.h
@@ -44,20 +44,25 @@ class CSigsegvGameConf : public ITextListener_SMC
SMCResult AddrEntry_End();
std::map m_AddrParsers{
- { "sym", &CSigsegvGameConf::AddrEntry_Load_Sym },
- { "fixed", &CSigsegvGameConf::AddrEntry_Load_Fixed },
- { "pattern", &CSigsegvGameConf::AddrEntry_Load_Pattern },
- { "datamap", &CSigsegvGameConf::AddrEntry_Load_DataDescMap },
- { "func knownvtidx", &CSigsegvGameConf::AddrEntry_Load_Func_KnownVTIdx },
- { "func datamap vthunk", &CSigsegvGameConf::AddrEntry_Load_Func_DataMap_VThunk },
- { "func ebpprologue uniref", &CSigsegvGameConf::AddrEntry_Load_Func_EBPPrologue_UniqueRef },
- { "func ebpprologue unistr", &CSigsegvGameConf::AddrEntry_Load_Func_EBPPrologue_UniqueStr },
- { "func ebpprologue unistr knownvtidx", &CSigsegvGameConf::AddrEntry_Load_Func_EBPPrologue_UniqueStr_KnownVTIdx },
- { "func ebpprologue vprof", &CSigsegvGameConf::AddrEntry_Load_Func_EBPPrologue_VProf },
+ { "sym", &CSigsegvGameConf::AddrEntry_Load_Sym },
+ { "sym regex", &CSigsegvGameConf::AddrEntry_Load_Sym_Regex },
+ { "fixed", &CSigsegvGameConf::AddrEntry_Load_Fixed },
+ { "pattern", &CSigsegvGameConf::AddrEntry_Load_Pattern },
+ { "datamap", &CSigsegvGameConf::AddrEntry_Load_DataDescMap },
+ { "func knownvtidx", &CSigsegvGameConf::AddrEntry_Load_Func_KnownVTIdx },
+ { "func datamap vthunk", &CSigsegvGameConf::AddrEntry_Load_Func_DataMap_VThunk },
+ { "func ebpprologue uniref", &CSigsegvGameConf::AddrEntry_Load_Func_EBPPrologue_UniqueRef },
+ { "func ebpprologue unistr", &CSigsegvGameConf::AddrEntry_Load_Func_EBPPrologue_UniqueStr },
+ { "func ebpprologue unistr knownvtidx", &CSigsegvGameConf::AddrEntry_Load_Func_EBPPrologue_UniqueStr_KnownVTIdx },
+ { "func ebpprologue nonunistr knownvtidx", &CSigsegvGameConf::AddrEntry_Load_Func_EBPPrologue_NonUniqueStr_KnownVTIdx },
+ { "func ebpprologue vprof", &CSigsegvGameConf::AddrEntry_Load_Func_EBPPrologue_VProf },
+ { "convar", &CSigsegvGameConf::AddrEntry_Load_ConVar },
+ { "concommand", &CSigsegvGameConf::AddrEntry_Load_ConCommand },
};
void AddrEntry_Load_Common(IAddr *addr);
SMCResult AddrEntry_Load_Sym();
+ SMCResult AddrEntry_Load_Sym_Regex();
SMCResult AddrEntry_Load_Fixed();
SMCResult AddrEntry_Load_Pattern();
SMCResult AddrEntry_Load_DataDescMap();
@@ -66,7 +71,12 @@ class CSigsegvGameConf : public ITextListener_SMC
SMCResult AddrEntry_Load_Func_EBPPrologue_UniqueRef();
SMCResult AddrEntry_Load_Func_EBPPrologue_UniqueStr();
SMCResult AddrEntry_Load_Func_EBPPrologue_UniqueStr_KnownVTIdx();
+ SMCResult AddrEntry_Load_Func_EBPPrologue_NonUniqueStr_KnownVTIdx();
SMCResult AddrEntry_Load_Func_EBPPrologue_VProf();
+
+ SMCResult AddrEntry_Load_ConCommandBase(bool is_command);
+ SMCResult AddrEntry_Load_ConVar() { return this->AddrEntry_Load_ConCommandBase(false); }
+ SMCResult AddrEntry_Load_ConCommand() { return this->AddrEntry_Load_ConCommandBase(true); }
};
extern CSigsegvGameConf g_GCHook;
diff --git a/src/library.cpp b/src/library.cpp
index 3e35b9a2..eb1208c3 100644
--- a/src/library.cpp
+++ b/src/library.cpp
@@ -7,13 +7,42 @@ std::map LibMgr::s_LibHandles;
static std::map libnames{
- { Library::INVALID, "invalid" },
- { Library::SERVER, "server" },
- { Library::ENGINE, "engine" },
- { Library::DEDICATED, "dedicated" },
- { Library::TIER0, "tier0" },
- { Library::CLIENT, "client" },
- { Library::VGUIMATSURFACE, "vguimatsurface" },
+ { Library::INVALID, "invalid" },
+ { Library::SERVER, "server" },
+ { Library::ENGINE, "engine" },
+ { Library::DEDICATED, "dedicated" },
+ { Library::TIER0, "tier0" },
+ { Library::CLIENT, "client" },
+ { Library::VGUIMATSURFACE, "vguimatsurface" },
+ { Library::MATERIALSYSTEM, "materialsystem" },
+ { Library::SOUNDEMITTERSYSTEM, "soundemittersystem" },
+ { Library::DATACACHE, "datacache" },
+ { Library::VGUI, "vgui" },
+ { Library::VPHYSICS, "vphysics" },
+};
+
+static std::map segnames{
+ { Segment::INVALID, "invalid" },
+ { Segment::TEXT, "text" },
+ { Segment::DATA, "data" },
+ { Segment::RODATA, "rodata" },
+ { Segment::BSS, "bss" },
+};
+
+static std::map segnames_plat{
+#if defined _LINUX
+ { ".text", Segment::TEXT, },
+ { ".data", Segment::DATA, },
+ { ".rodata", Segment::RODATA, },
+ { ".bss", Segment::BSS, },
+#elif defined _WINDOWS
+ { ".text", Segment::TEXT, },
+ { ".data", Segment::DATA, },
+ { ".rdata", Segment::RODATA, },
+ { ".bss", Segment::BSS, },
+#elif defined _OSX
+ #error TODO
+#endif
};
@@ -64,37 +93,51 @@ void LibMgr::FindInfo(Library lib)
memset(&dlinfo, 0x00, sizeof(dlinfo));
assert(g_MemUtils.GetLibraryInfo(GetPtr(lib), dlinfo));
- LibInfo info;
- info.baseaddr = (uintptr_t)dlinfo.baseAddress;
- info.len = (uintptr_t)dlinfo.memorySize;
+ LibInfo lib_info((uintptr_t)dlinfo.baseAddress, (uintptr_t)dlinfo.memorySize);
#if defined _LINUX
g_MemUtils.ForEachSection(s_LibHandles[lib], [&](const Elf32_Shdr *shdr, const char *name){
- SegInfo seg;
- seg.off = shdr->sh_addr;
- seg.len = shdr->sh_size;
+ SegInfo seg_info(shdr->sh_addr, shdr->sh_size);
+ seg_info.m_LibBaseAddr = lib_info.BaseAddr();
+
+ auto it = segnames_plat.find(name);
+ if (it != segnames_plat.end()) {
+ ConColorMsg(Color(0x00, 0xff, 0x00, 0xff), "Library %s: segment '%s' found: %s\n",
+ Lib_ToString(lib), name, Seg_ToString((*it).second));
+ auto result = lib_info.m_SegmentsByType.insert(std::make_pair((*it).second, seg_info));
+ assert(result.second);
+ } else {
+ ConColorMsg(Color(0xff, 0x00, 0x00, 0xff), "Library %s: segment '%s' not found!\n",
+ Lib_ToString(lib), name);
+ }
- info.segs[name] = seg;
+ auto result = lib_info.m_SegmentsByName.insert(std::make_pair(name, seg_info));
+ assert(result.second);
});
#elif defined _WINDOWS
g_MemUtils.ForEachSection(s_LibHandles[lib], [&](const IMAGE_SECTION_HEADER *pSectHdr){
- SegInfo seg;
- seg.off = pSectHdr->VirtualAddress;
- seg.len = pSectHdr->Misc.VirtualSize;
+ SegInfo seg_info(pSectHdr->VirtualAddress, pSectHdr->Misc.VirtualSize);
+ seg_info.m_LibBaseAddr = lib_info.BaseAddr();
auto name = (const char *)pSectHdr->Name;
- info.segs[name] = seg;
+
+ auto it = segnames_plat.find(name);
+ if (it != segnames_plat.end()) {
+ auto result = lib_info.m_SegmentsByType.insert(std::make_pair((*it).second, seg_info));
+ assert(result.second);
+ }
+
+ auto result = lib_info.m_SegmentsByName.insert(std::make_pair(name, seg_info));
+ assert(result.second);
});
#endif
- s_LibInfos[lib] = info;
+ auto result = s_LibInfos.insert(std::make_pair(lib, lib_info));
+ assert(result.second);
- DevMsg("Library %-34s [ %08x %08x ]\n", libnames.at(lib), info.baseaddr, info.baseaddr + info.len);
- for (const auto& pair : info.segs) {
- DevMsg(" %-40s [ %08x %08x ]\n",
- pair.first.c_str(),
- info.baseaddr + pair.second.off,
- info.baseaddr + pair.second.off + pair.second.len);
+ DevMsg("Library %-34s [ %08x %08x ]\n", libnames.at(lib), lib_info.AddrBegin(), lib_info.AddrEnd());
+ for (const auto& pair : lib_info.m_SegmentsByName) {
+ DevMsg(" %-40s [ %08x %08x ]\n", pair.first.c_str(), pair.second.AddrBegin(), pair.second.AddrEnd());
}
}
@@ -109,18 +152,21 @@ void *LibMgr::FindSym(Library lib, const char *sym)
return g_MemUtils.ResolveSymbol(handle, sym);
}
-std::tuple LibMgr::FindSymRegex(Library lib, const char *pattern, std::regex::flag_type flags)
+std::tuple LibMgr::FindSymRegex(Library lib, const char *pattern)
{
- std::regex filter(pattern);
+ std::regex filter(pattern, std::regex_constants::ECMAScript);
std::vector matches;
LibMgr::ForEachSym(lib, [&](Symbol *sym){
std::string name(sym->buffer(), sym->length);
- if (std::regex_search(name, filter, std::regex_constants::match_any)) {
+ if (std::regex_match(name, filter, std::regex_constants::match_any)) {
matches.push_back(sym);
+ if (matches.size() > 1) return false;
}
+
+ return true;
});
if (matches.size() == 1) {
@@ -131,13 +177,6 @@ std::tuple LibMgr::FindSymRegex(Library lib, const ch
}
}
-void LibMgr::ForEachSym(Library lib, const std::function& functor)
-{
- void *handle = s_LibHandles.at(lib);
- assert(handle != nullptr);
- g_MemUtils.ForEachSymbol(handle, functor);
-}
-
#if defined _LINUX || defined _OSX
@@ -201,9 +240,9 @@ Library LibMgr::WhichLibAtAddr(void *ptr)
Library lib = pair.first;
if (lib == Library::INVALID) continue;
- const LibInfo& info = GetInfo(lib);
+ const LibInfo& lib_info = GetInfo(lib);
- if (addr >= info.baseaddr && addr < info.baseaddr + info.len) {
+ if (GetInfo(lib).ContainsAddr(addr, 1)) {
return lib;
}
}
@@ -212,7 +251,7 @@ Library LibMgr::WhichLibAtAddr(void *ptr)
}
-Library LibMgr::FromString(const char *str)
+Library LibMgr::Lib_FromString(const char *str)
{
for (const auto& pair : libnames) {
if (stricmp(pair.second, str) == 0) {
@@ -223,7 +262,7 @@ Library LibMgr::FromString(const char *str)
return Library::INVALID;
}
-const char *LibMgr::ToString(Library lib)
+const char *LibMgr::Lib_ToString(Library lib)
{
for (const auto& pair : libnames) {
if (pair.first == lib) {
@@ -234,7 +273,7 @@ const char *LibMgr::ToString(Library lib)
return libnames.at(Library::INVALID);
}
-size_t LibMgr::MaxStringLen()
+size_t LibMgr::Lib_MaxStringLen()
{
size_t max = 0;
@@ -244,3 +283,37 @@ size_t LibMgr::MaxStringLen()
return max;
}
+
+
+Segment LibMgr::Seg_FromString(const char *str)
+{
+ for (const auto& pair : segnames) {
+ if (stricmp(pair.second, str) == 0) {
+ return pair.first;
+ }
+ }
+
+ return Segment::INVALID;
+}
+
+const char *LibMgr::Seg_ToString(Segment seg)
+{
+ for (const auto& pair : segnames) {
+ if (pair.first == seg) {
+ return pair.second;
+ }
+ }
+
+ return segnames.at(Segment::INVALID);
+}
+
+size_t LibMgr::Seg_MaxStringLen()
+{
+ size_t max = 0;
+
+ for (const auto& pair : segnames) {
+ max = Max(max, strlen(pair.second));
+ }
+
+ return max;
+}
diff --git a/src/library.h b/src/library.h
index 060321eb..e53ca473 100644
--- a/src/library.h
+++ b/src/library.h
@@ -11,33 +11,105 @@ enum class Library : int
TIER0,
CLIENT,
VGUIMATSURFACE,
+ MATERIALSYSTEM,
+ SOUNDEMITTERSYSTEM,
+ DATACACHE,
+ VGUI,
+ VPHYSICS,
};
-#if 0
enum class Segment : int
{
- SEG_TEXT,
- SEG_DATA,
- SEG_RODATA,
- SEG_BSS,
+ INVALID,
+ TEXT,
+ DATA,
+ RODATA,
+ BSS,
};
-#endif
-struct SegInfo
+class SegInfo
{
- uintptr_t off;
- uintptr_t len;
+public:
+ SegInfo(uintptr_t offset, uintptr_t length) :
+ m_Offset(offset), m_Length(length) {}
+
+ uintptr_t Offset() const { return this->m_Offset; }
+ uintptr_t Length() const { return this->m_Length; }
+
+ uintptr_t AddrBegin() const { return this->m_LibBaseAddr + this->m_Offset; }
+ uintptr_t AddrEnd() const { return this->m_LibBaseAddr + this->m_Offset + this->m_Length; }
+
+ bool ContainsAddr(uintptr_t addr, uintptr_t len = 0) const
+ {
+ uintptr_t range_begin = addr;
+ uintptr_t range_end = addr + len;
+
+ return (range_begin >= this->AddrBegin()) && (range_end <= this->AddrEnd());
+ }
+ template bool ContainsAddr(const T *addr, uintptr_t len = 0) const
+ {
+ return this->ContainsAddr((uintptr_t)addr, len);
+ }
+
+private:
+ uintptr_t m_Offset;
+ uintptr_t m_Length;
+
+ uintptr_t m_LibBaseAddr = 0x00000000;
+
+ friend class LibMgr;
};
-struct LibInfo
+class LibInfo
{
- uintptr_t baseaddr;
- uintptr_t len;
+public:
+ LibInfo(uintptr_t baseaddr, uintptr_t length) :
+ m_BaseAddr(baseaddr), m_Length(length) {}
+
+ uintptr_t BaseAddr() const { return this->m_BaseAddr; }
+ uintptr_t Length() const { return this->m_Length; }
+
+ uintptr_t AddrBegin() const { return this->m_BaseAddr; }
+ uintptr_t AddrEnd() const { return this->m_BaseAddr + this->m_Length; }
- std::map segs;
+ const SegInfo& GetSeg(Segment seg_type) const
+ {
+ auto it = this->m_SegmentsByType.find(seg_type);
+ assert(it != this->m_SegmentsByType.end());
+
+ return (*it).second;
+ }
+ const SegInfo& GetSeg(const char *seg_name) const
+ {
+ auto it = this->m_SegmentsByName.find(seg_name);
+ assert(it != this->m_SegmentsByName.end());
+
+ return (*it).second;
+ }
+
+ bool ContainsAddr(uintptr_t addr, uintptr_t len = 0) const
+ {
+ uintptr_t range_begin = addr;
+ uintptr_t range_end = addr + len;
+
+ return (range_begin >= this->AddrBegin()) && (range_end <= this->AddrEnd());
+ }
+ template bool ContainsAddr(const T *addr, uintptr_t len = 0) const
+ {
+ return this->ContainsAddr((uintptr_t)addr, len);
+ }
+
+private:
+ uintptr_t m_BaseAddr;
+ uintptr_t m_Length;
+
+ std::map m_SegmentsByType;
+ std::map m_SegmentsByName;
+
+ friend class LibMgr;
};
@@ -58,14 +130,25 @@ class LibMgr
static const LibInfo& GetInfo(Library lib);
static void *FindSym(Library lib, const char *sym);
- static std::tuple FindSymRegex(Library lib, const char *pattern, std::regex::flag_type flags = std::regex::ECMAScript | std::regex::icase);
- static void ForEachSym(Library lib, const std::function& functor);
+ static std::tuple FindSymRegex(Library lib, const char *pattern);
+
+ template
+ static void ForEachSym(Library lib, FUNCTOR&& functor)
+ {
+ void *handle = s_LibHandles.at(lib);
+ assert(handle != nullptr);
+ g_MemUtils.ForEachSymbol(handle, functor);
+ }
static Library WhichLibAtAddr(void *ptr);
- static Library FromString(const char *str);
- static const char *ToString(Library lib);
- static size_t MaxStringLen();
+ static Library Lib_FromString(const char *str);
+ static const char *Lib_ToString(Library lib);
+ static size_t Lib_MaxStringLen();
+
+ static Segment Seg_FromString(const char *str);
+ static const char *Seg_ToString(Segment lib);
+ static size_t Seg_MaxStringLen();
private:
LibMgr() {}
diff --git a/src/link/link.h b/src/link/link.h
index f17749e4..618d30d9 100644
--- a/src/link/link.h
+++ b/src/link/link.h
@@ -56,11 +56,13 @@ class StaticFuncThunk : public ILinkage
RET operator()(PARAMS... args) const
{
- assert(this->m_pFuncPtr != nullptr);
- return (*this->m_pFuncPtr)(args...);
+ assert(this->GetFuncPtr() != nullptr);
+ return (*this->GetFuncPtr())(args...);
}
private:
+ FPtr GetFuncPtr() const { return this->m_pFuncPtr; }
+
const char *m_pszFuncName;
FPtr m_pFuncPtr = nullptr;
diff --git a/src/mem/detour.cpp b/src/mem/detour.cpp
index 385f79f8..1ad6b45e 100644
--- a/src/mem/detour.cpp
+++ b/src/mem/detour.cpp
@@ -3,6 +3,7 @@
#include "mem/protect.h"
#include "mem/opcode.h"
#include "util/backtrace.h"
+#include "util/demangle.h"
#if !(defined(__i386) || defined(_M_IX86))
@@ -167,11 +168,11 @@ bool IDetour_SymRegex::DoLoad()
return false;
}
- const LibInfo& info = LibMgr::GetInfo(this->m_Library);
- void *text_begin = (void *)(info.baseaddr + info.segs.at(".text").off);
- void *text_end = (void *)((uintptr_t)text_begin + info.segs.at(".text").len);
+ const SegInfo& info_seg_text = LibMgr::GetInfo(this->m_Library).GetSeg(Segment::TEXT);
+ auto text_begin = reinterpret_cast(info_seg_text.AddrBegin());
+ auto text_end = reinterpret_cast(info_seg_text.AddrEnd());
- std::regex filter(this->m_strPattern);
+ std::regex filter(this->m_strPattern, std::regex_constants::ECMAScript);
std::vector syms;
LibMgr::ForEachSym(this->m_Library, [&](Symbol *sym){
const char *it_begin = sym->buffer();
@@ -181,6 +182,8 @@ bool IDetour_SymRegex::DoLoad()
syms.push_back(sym);
}
}
+
+ return true;
});
if (syms.size() != 1) {
@@ -195,7 +198,7 @@ bool IDetour_SymRegex::DoLoad()
this->m_strSymbol = std::string(syms[0]->buffer(), syms[0]->length);
this->m_pFunc = syms[0]->address;
- this->Demangle();
+ DemangleName(this->m_strSymbol.c_str(), this->m_strDemangled);
return true;
}
@@ -206,22 +209,6 @@ void IDetour_SymRegex::DoUnload()
}
-void IDetour_SymRegex::Demangle()
-{
-#if defined _LINUX || defined _OSX
- const char *demangled = cplus_demangle(this->m_strSymbol.c_str(), DMGL_GNU_V3 | DMGL_TYPES | DMGL_ANSI | DMGL_PARAMS);
- if (demangled != nullptr) {
- this->m_strDemangled = demangled;
- free((void *)demangled);
- } else {
- this->m_strDemangled = this->m_strSymbol;
- }
-#else
- this->m_strDemangled = this->m_strSymbol;
-#endif
-}
-
-
bool CDetour::DoLoad()
{
if (!IDetour_SymNormal::DoLoad()) {
@@ -520,6 +507,9 @@ void CDetouredFunc::StorePrologue()
size_t n_bytes = copy_bytes((unsigned char *)this->m_pFunc, nullptr, JmpRelImm32::Size());
assert(n_bytes >= JmpRelImm32::Size());
+ // this assert will fail in some cases if you've set a breakpoint in gdb on
+ // the function in question, because copy_bytes stops early if it hits an
+ // int3 instruction
this->m_Prologue.resize(n_bytes);
memcpy(this->m_Prologue.data(), this->m_pFunc, n_bytes);
diff --git a/src/mem/detour.h b/src/mem/detour.h
index 77c251ca..4e85eed0 100644
--- a/src/mem/detour.h
+++ b/src/mem/detour.h
@@ -78,8 +78,6 @@ class IDetour_SymRegex : public IDetour
virtual void DoUnload() override;
private:
- void Demangle();
-
Library m_Library;
std::string m_strPattern;
diff --git a/src/mem/patch.cpp b/src/mem/patch.cpp
index 4e053436..8c82ac59 100644
--- a/src/mem/patch.cpp
+++ b/src/mem/patch.cpp
@@ -3,19 +3,24 @@
#include "mem/protect.h"
-bool IPatch::Init()
+bool CPatch::Init()
{
this->m_pszFuncName = this->GetFuncName();
this->m_iFuncOffMin = this->GetFuncOffMin();
this->m_iFuncOffMax = this->GetFuncOffMax();
if (this->Verbose()) {
- DevMsg("IPatch::Init: \"%s\" %s\n", this->m_pszFuncName, typeid(*this).name());
+ DevMsg("CPatch::Init: \"%s\" %s\n", this->m_pszFuncName, typeid(*this).name());
}
this->m_pFuncAddr = AddrManager::GetAddr(this->m_pszFuncName);
if (this->m_pFuncAddr == nullptr) {
- DevMsg("IPatch::Init: FAIL: no addr for \"%s\"\n", this->m_pszFuncName);
+ DevMsg("CPatch::Init: FAIL: no addr for \"%s\"\n", this->m_pszFuncName);
+ return false;
+ }
+
+ if (!this->PostInit()) {
+ DevMsg("CPatch::Init: FAIL: \"%s\": PostInit returned false\n", this->m_pszFuncName);
return false;
}
@@ -23,20 +28,20 @@ bool IPatch::Init()
this->m_MaskPatch.SetAll(0x00);
if (!this->GetVerifyInfo(this->m_BufVerify, this->m_MaskVerify)) {
- DevMsg("IPatch::Init: FAIL: \"%s\": GetVerifyInfo returned false\n", this->m_pszFuncName);
+ DevMsg("CPatch::Init: FAIL: \"%s\": GetVerifyInfo returned false\n", this->m_pszFuncName);
return false;
}
this->m_BufPatch.CopyFrom(this->m_BufVerify);
if (!this->GetPatchInfo(this->m_BufPatch, this->m_MaskPatch)) {
- DevMsg("IPatch::Init: FAIL: \"%s\": GetPatchInfo returned false\n", this->m_pszFuncName);
+ DevMsg("CPatch::Init: FAIL: \"%s\": GetPatchInfo returned false\n", this->m_pszFuncName);
return false;
}
return true;
}
-bool IPatch::Check()
+bool CPatch::Check()
{
using PatchScanner = CMaskedScanner;
@@ -44,33 +49,35 @@ bool IPatch::Check()
uintptr_t addr_max = (uintptr_t)this->m_pFuncAddr + this->m_iFuncOffMax + this->m_iLength + 1;
if (this->Verbose()) {
- DevMsg("IPatch::Check: \"%s\" %s\n", this->m_pszFuncName, typeid(*this).name());
- DevMsg("IPatch::Check: func %08x\n", (uintptr_t)this->m_pFuncAddr);
- DevMsg("IPatch::Check: off_min %04x\n", this->m_iFuncOffMin);
- DevMsg("IPatch::Check: off_max %04x\n", this->m_iFuncOffMax);
- DevMsg("IPatch::Check: addr_min %08x\n", addr_min);
- DevMsg("IPatch::Check: addr_max %08x\n", addr_max);
+ DevMsg("CPatch::Check: \"%s\" %s\n", this->m_pszFuncName, typeid(*this).name());
+ DevMsg("CPatch::Check: func %08x\n", (uintptr_t)this->m_pFuncAddr);
+ DevMsg("CPatch::Check: off_min %04x\n", this->m_iFuncOffMin);
+ DevMsg("CPatch::Check: off_max %04x\n", this->m_iFuncOffMax);
+ DevMsg("CPatch::Check: addr_min %08x\n", addr_min);
+ DevMsg("CPatch::Check: addr_max %08x\n", addr_max);
}
CScan scan(CAddrAddrBounds((void *)addr_min, (void *)addr_max), this->m_BufVerify, this->m_MaskVerify);
if (!scan.ExactlyOneMatch()) {
- DevMsg("IPatch::Check: FAIL: \"%s\": found %u matching regions\n", this->m_pszFuncName, scan.Matches().size());
+ DevMsg("CPatch::Check: FAIL: \"%s\": found %u matching regions\n", this->m_pszFuncName, scan.Matches().size());
return false;
}
this->m_bFoundOffset = true;
this->m_iFuncOffActual = (uintptr_t)scan.FirstMatch() - (uintptr_t)this->m_pFuncAddr;
- DevMsg("IPatch::Check: OK: \"%s\": actual offset +0x%04x\n", this->m_pszFuncName, this->m_iFuncOffActual);
+ DevMsg("CPatch::Check: OK: \"%s\": actual offset +0x%04x\n", this->m_pszFuncName, this->m_iFuncOffActual);
return true;
}
-void IPatch::Apply()
+void CPatch::Apply()
{
+ if (this->VerifyOnly()) return;
+
if (this->Verbose()) {
- DevMsg("IPatch::Apply: \"%s\" %s\n", this->m_pszFuncName, typeid(*this).name());
+ DevMsg("CPatch::Apply: \"%s\" %s\n", this->m_pszFuncName, typeid(*this).name());
}
if (this->m_bApplied) {
@@ -78,7 +85,7 @@ void IPatch::Apply()
}
if (!this->m_bFoundOffset) {
- DevWarning("IPatch::Apply: haven't found actual offset yet!\n");
+ DevWarning("CPatch::Apply: haven't found actual offset yet!\n");
return;
}
@@ -100,10 +107,12 @@ void IPatch::Apply()
this->m_bApplied = true;
}
-void IPatch::UnApply()
+void CPatch::UnApply()
{
+ if (this->VerifyOnly()) return;
+
if (this->Verbose()) {
- DevMsg("IPatch::UnApply: \"%s\" %s\n", this->m_pszFuncName, typeid(*this).name());
+ DevMsg("CPatch::UnApply: \"%s\" %s\n", this->m_pszFuncName, typeid(*this).name());
}
if (!this->m_bApplied) {
@@ -111,7 +120,7 @@ void IPatch::UnApply()
}
if (!this->m_bFoundOffset) {
- DevWarning("IPatch::UnApply: haven't found actual offset yet!\n");
+ DevWarning("CPatch::UnApply: haven't found actual offset yet!\n");
return;
}
@@ -132,13 +141,13 @@ void IPatch::UnApply()
}
-uint32_t IPatch::GetActualOffset() const
+uint32_t CPatch::GetActualOffset() const
{
if (!this->m_bFoundOffset) return -1;
return this->m_iFuncOffActual;
}
-void *IPatch::GetActualLocation() const
+void *CPatch::GetActualLocation() const
{
if (!this->m_bFoundOffset) return nullptr;
return (void *)((uintptr_t)this->m_pFuncAddr + this->m_iFuncOffActual);
diff --git a/src/mem/patch.h b/src/mem/patch.h
index 198bdde3..1014a746 100644
--- a/src/mem/patch.h
+++ b/src/mem/patch.h
@@ -11,34 +11,56 @@ class IPatch
public:
virtual ~IPatch() {}
- virtual bool VerifyOnly() const { return false; }
+ virtual bool Verbose() const = 0;
+ virtual bool VerifyOnly() const = 0;
- bool Init();
- bool Check();
+ virtual bool Init() = 0;
+ virtual bool Check() = 0;
- virtual void Apply();
- virtual void UnApply();
+ virtual void Apply() = 0;
+ virtual void UnApply() = 0;
- virtual int GetLength() const final { return this->m_iLength; }
+protected:
+ IPatch() {}
+};
+
+
+class CPatch : public IPatch
+{
+public:
+ virtual ~CPatch() {}
+
+ virtual bool Verbose() const override { return false; }
+ virtual bool VerifyOnly() const override { return false; }
+
+ virtual bool Init() override final;
+ virtual bool Check() override final;
+
+ virtual void Apply() override final;
+ virtual void UnApply() override final;
+
+ int GetLength() const { return this->m_iLength; }
virtual const char *GetFuncName() const = 0;
virtual uint32_t GetFuncOffMin() const = 0;
virtual uint32_t GetFuncOffMax() const = 0;
- virtual bool Verbose() const { return false; }
-
uint32_t GetActualOffset() const;
void *GetActualLocation() const;
protected:
- IPatch(int len) :
+ CPatch(int len) :
m_iLength(len),
m_BufVerify(len), m_BufPatch(len),
m_MaskVerify(len), m_MaskPatch(len),
m_BufRestore(len) {}
+ virtual bool PostInit() { return true; }
+
virtual bool GetVerifyInfo(ByteBuf& buf, ByteBuf& mask) const = 0;
virtual bool GetPatchInfo(ByteBuf& buf, ByteBuf& mask) const = 0;
+ void *GetFuncAddr() const { return this->m_pFuncAddr; }
+
private:
const int m_iLength;
@@ -61,18 +83,15 @@ class IPatch
};
-class IVerify : public IPatch
+class CVerify : public CPatch
{
public:
- virtual ~IVerify() {}
+ virtual ~CVerify() {}
virtual bool VerifyOnly() const override final { return true; }
- virtual void Apply() override final {}
- virtual void UnApply() override final {}
-
protected:
- IVerify(int len) : IPatch(len) {}
+ CVerify(int len) : CPatch(len) {}
virtual bool GetPatchInfo(ByteBuf& buf, ByteBuf& mask) const override final { return true; }
};
diff --git a/src/mem/scan.cpp b/src/mem/scan.cpp
index 47575960..7e1be457 100644
--- a/src/mem/scan.cpp
+++ b/src/mem/scan.cpp
@@ -3,19 +3,18 @@
CLibBounds::CLibBounds(Library lib)
{
- const LibInfo& info = LibMgr::GetInfo(lib);
+ const LibInfo& lib_info = LibMgr::GetInfo(lib);
- this->m_AddrLow = (const void *)info.baseaddr;
- this->m_AddrHigh = (const void *)(info.baseaddr + info.len);
+ this->m_AddrLow = reinterpret_cast(lib_info.AddrBegin());
+ this->m_AddrHigh = reinterpret_cast(lib_info.AddrEnd());
}
-CLibSegBounds::CLibSegBounds(Library lib, const char *seg)
+CLibSegBounds::CLibSegBounds(Library lib, Segment seg)
{
- const LibInfo& l_info = LibMgr::GetInfo(lib);
- const SegInfo& s_info = l_info.segs.at(seg);
+ const SegInfo& seg_info = LibMgr::GetInfo(lib).GetSeg(seg);
- this->m_AddrLow = (const void *)(l_info.baseaddr + s_info.off);
- this->m_AddrHigh = (const void *)(l_info.baseaddr + s_info.off + s_info.len);
+ this->m_AddrLow = reinterpret_cast(seg_info.AddrBegin());
+ this->m_AddrHigh = reinterpret_cast(seg_info.AddrEnd());
}
@@ -25,7 +24,7 @@ namespace Scan
{
using StrScanner = CStringScanner;
- CScan scan(CLibSegBounds(lib, ".rdata"), str);
+ CScan scan(CLibSegBounds(lib, Segment::RODATA), str);
if (scan.ExactlyOneMatch()) {
return (const char *)scan.FirstMatch();
}
diff --git a/src/mem/scan.h b/src/mem/scan.h
index ab9c7802..4ad47ffa 100644
--- a/src/mem/scan.h
+++ b/src/mem/scan.h
@@ -78,7 +78,7 @@ class CLibBounds : public IBounds
class CLibSegBounds : public IBounds
{
public:
- CLibSegBounds(Library lib, const char *seg);
+ CLibSegBounds(Library lib, Segment seg);
virtual const void *GetLowerBound() const override { return this->m_AddrLow; }
virtual const void *GetUpperBound() const override { return this->m_AddrHigh; }
@@ -155,29 +155,24 @@ inline bool CBasicScanner::CheckOne(const void *where)
}
-template
-class CTypeScanner : public IScanner
+template
+class CTypeScanner : public CBasicScanner
{
public:
CTypeScanner(const IBounds& bounds, const T& seek) :
- IScanner(bounds, sizeof(T)), m_Seek(seek) {}
-
- bool CheckOne(const void *where);
-
-private:
- const T m_Seek;
+ CBasicScanner(bounds, reinterpret_cast(&seek), sizeof(T)) {}
+ virtual ~CTypeScanner() {}
};
-template
-inline bool CTypeScanner::CheckOne(const void *where)
+
+template
+class CAlignedTypeScanner : public CTypeScanner
{
- if (*reinterpret_cast(where) == this->m_Seek) {
- this->AddMatch(where);
- return true;
- } else {
- return false;
- }
-}
+public:
+ CAlignedTypeScanner(const IBounds& bounds, const T& seek) :
+ CTypeScanner(bounds, seek) {}
+ virtual ~CAlignedTypeScanner() {}
+};
template
diff --git a/src/mod/bot/medieval_nonmelee.cpp b/src/mod/bot/medieval_nonmelee.cpp
index 048c2ee1..11da6a08 100644
--- a/src/mod/bot/medieval_nonmelee.cpp
+++ b/src/mod/bot/medieval_nonmelee.cpp
@@ -11,12 +11,20 @@ namespace Mod_Bot_Medieval_NonMelee
0x75, 0x00, // +000C jnz +0xXX
};
- struct IPatch_CTFBot_EquipRequiredWeapon : public IPatch
+ struct CPatch_CTFBot_EquipRequiredWeapon : public CPatch
{
- IPatch_CTFBot_EquipRequiredWeapon() : IPatch(sizeof(s_Buf)) {}
+ CPatch_CTFBot_EquipRequiredWeapon() : CPatch(sizeof(s_Buf)) {}
virtual const char *GetFuncName() const override { return "CTFBot::EquipRequiredWeapon"; }
+#if defined _LINUX
+ virtual uint32_t GetFuncOffMin() const override { return 0x0000; }
+ virtual uint32_t GetFuncOffMax() const override { return 0x0100; } // @ 0x00b0
+#elif defined _WINDOWS
+ virtual uint32_t GetFuncOffMin() const override { return 0x0000; }
+ virtual uint32_t GetFuncOffMax() const override { return 0x00c0; } // @ 0x0071
+#endif
+
virtual bool GetVerifyInfo(ByteBuf& buf, ByteBuf& mask) const override
{
buf.CopyFrom(s_Buf);
@@ -42,24 +50,6 @@ namespace Mod_Bot_Medieval_NonMelee
}
};
-#if defined _LINUX
-
- struct CPatch_CTFBot_EquipRequiredWeapon : public IPatch_CTFBot_EquipRequiredWeapon
- {
- virtual uint32_t GetFuncOffMin() const override { return 0x0000; }
- virtual uint32_t GetFuncOffMax() const override { return 0x0100; } // @ 0x00b0
- };
-
-#elif defined _WINDOWS
-
- struct CPatch_CTFBot_EquipRequiredWeapon : public IPatch_CTFBot_EquipRequiredWeapon
- {
- virtual uint32_t GetFuncOffMin() const override { return 0x0000; }
- virtual uint32_t GetFuncOffMax() const override { return 0x00c0; } // @ 0x0071
- };
-
-#endif
-
class CMod : public IMod
{
diff --git a/src/mod/bot/runfast.cpp b/src/mod/bot/runfast.cpp
index 2c1cc1e6..8e699d44 100644
--- a/src/mod/bot/runfast.cpp
+++ b/src/mod/bot/runfast.cpp
@@ -21,9 +21,9 @@ namespace Mod_Bot_RunFast
};
static_assert(sizeof(s_Buf_Verify) == sizeof(s_Buf_Patch), "size mismatch");
- struct CPatch_CTFBotPushToCapturePoint_Update : public IPatch
+ struct CPatch_CTFBotPushToCapturePoint_Update : public CPatch
{
- CPatch_CTFBotPushToCapturePoint_Update() : IPatch(sizeof(s_Buf_Verify)) {}
+ CPatch_CTFBotPushToCapturePoint_Update() : CPatch(sizeof(s_Buf_Verify)) {}
virtual const char *GetFuncName() const override { return "CTFBotPushToCapturePoint::Update"; }
virtual uint32_t GetFuncOffMin() const override { return 0x0000; }
diff --git a/src/mod/cond/enhanced_cmds.cpp b/src/mod/cond/enhanced_cmds.cpp
new file mode 100644
index 00000000..5439cc98
--- /dev/null
+++ b/src/mod/cond/enhanced_cmds.cpp
@@ -0,0 +1,136 @@
+#include "mod.h"
+#include "stub/tfplayer.h"
+#include "util/misc.h"
+
+
+namespace Mod_Cond_Enhanced_Cmds
+{
+ // existing addcond syntax:
+ // addcond [condnum] [duration] [player name substring]
+
+ // existing removecond syntax:
+ // removecond [condnum] [player name substring]
+
+
+ // desired features:
+ // - allow hex cond number input
+ // - allow condition name input
+ // - regex selection of target player(s)
+ // - apply to multiple players at once if regex matches multiple
+ // - print what was done to console (with both cond num and name, plus duration for addcond)
+ // - on invalid syntax or bad cond etc, print Warning message
+ // - have feature to print list of conds (number + name): maybe "listconds"
+
+
+ // ETFCond GetTFConditionFromName(const char *name);
+ // const char *GetTFConditionName(ETFCond cond);
+
+
+ DETOUR_DECL_MEMBER(bool, CTFPlayer_ClientCommand, const CCommand& args)
+ {
+ if (FStrEq(args[0], "addcond")) {
+ // int iMaxCondNum = GetNumberOfTFConds() - 1;
+
+ #warning TODO: Cond:Enhanced_Cmds
+ // ...
+
+ return true;
+ }
+
+ if (FStrEq(args[0], "removecond")) {
+ // int iMaxCondNum = GetNumberOfTFConds() - 1;
+
+ #warning TODO: Cond:Enhanced_Cmds
+ // ...
+
+ return true;
+ }
+
+ if (FStrEq(args[0], "listconds")) {
+ // int iMaxCondNum = GetNumberOfTFConds() - 1;
+
+ #warning TODO: Cond:Enhanced_Cmds
+
+ for (int i = 0; IsValidTFConditionNumber(i); ++i) {
+ // ...
+ }
+
+ return true;
+ }
+
+ return DETOUR_MEMBER_CALL(CTFPlayer_ClientCommand)(args);
+ }
+
+
+ class CMod : public IMod
+ {
+ public:
+ CMod() : IMod("Cond:Enhanced_Cmds")
+ {
+ MOD_ADD_DETOUR_MEMBER(CTFPlayer_ClientCommand, "CTFPlayer::ClientCommand");
+ }
+ };
+ CMod s_Mod;
+
+
+ ConVar cvar_enable("sig_cond_enhanced_cmds", "0", FCVAR_NOTIFY,
+ "Mod: enhance addcond and removecond",
+ [](IConVar *pConVar, const char *pOldValue, float flOldValue) {
+ ConVarRef var(pConVar);
+ s_Mod.Toggle(var.GetBool());
+ });
+}
+
+
+// existing implementation
+#if 0
+bool CTFPlayer::ClientCommand(const CCommand& args)
+{
+ // ...
+
+ if (FStrEq(args[0], "addcond")) {
+ if (sv_cheats.GetBool() && args.ArgC() >= 2) {
+ CTFPlayer *pTarget = this;
+ if (args.ArgC() >= 4) {
+ for (int i = 1; i <= gpGlobals->maxClients; ++i) {
+ CTFPlayer *pPlayer = ToTFPlayer(UTIL_PlayerByIndex(i));
+ if (pPlayer == nullptr) continue;
+
+ if (V_strstr(pPlayer->GetPlayerName(), args[3]) != nullptr) {
+ pTarget = pPlayer;
+ break;
+ }
+ }
+ }
+
+ int iCond = Clamp(strtol(args[1], nullptr, 10), 0, TF_COND_LAST - 1));
+ float flDuration = (args.ArgC() >= 3 ? strtod(args[2], nullptr) : -1.0f);
+ pTarget->m_Shared.AddCond(iCond, flDuration);
+ }
+ return true;
+ }
+
+ if (FStrEq(args[0], "removecond")) {
+ if (sv_cheats.GetBool() && args.ArgC() >= 2) {
+ CTFPlayer *pTarget = this;
+ if (args.ArgC() >= 3) {
+ for (int i = 1; i <= gpGlobals->maxClients; ++i) {
+ CTFPlayer *pPlayer = ToTFPlayer(UTIL_PlayerByIndex(i));
+ if (pPlayer == nullptr) continue;
+
+ if (V_strstr(pPlayer->GetPlayerName(), args[3]) != nullptr) {
+ pTarget = pPlayer;
+ break;
+ }
+ }
+ }
+
+ int iCond = Clamp(strtol(args[1], nullptr, 10), 0, TF_COND_LAST - 1));
+ pTarget->m_Shared.RemoveCond(iCond);
+ }
+ return true;
+ }
+
+ // ...
+}
+#endif
diff --git a/src/mod/cond/reprogrammed.cpp b/src/mod/cond/reprogrammed.cpp
index c8e6747c..2e8d5d9c 100644
--- a/src/mod/cond/reprogrammed.cpp
+++ b/src/mod/cond/reprogrammed.cpp
@@ -15,9 +15,9 @@ namespace Mod_Cond_Reprogrammed
0xe8, // +001B call CollectPlayers
};
- struct CPatch_CMissionPopulator_UpdateMission : public IPatch
+ struct CPatch_CMissionPopulator_UpdateMission : public CPatch
{
- CPatch_CMissionPopulator_UpdateMission() : IPatch(sizeof(s_Buf_UpdateMission)) {}
+ CPatch_CMissionPopulator_UpdateMission() : CPatch(sizeof(s_Buf_UpdateMission)) {}
virtual const char *GetFuncName() const override { return "CMissionPopulator::UpdateMission"; }
virtual uint32_t GetFuncOffMin() const override { return 0x0000; }
@@ -55,9 +55,9 @@ namespace Mod_Cond_Reprogrammed
// };
using FPtr_IsBot = bool (CBasePlayer:: *)() const;
- struct CPatch_CTFGameMovement_CheckStuck : public IPatch
+ struct CPatch_CTFGameMovement_CheckStuck : public CPatch
{
- CPatch_CTFGameMovement_CheckStuck() : IPatch(sizeof(s_Buf_CheckStuck)) {}
+ CPatch_CTFGameMovement_CheckStuck() : CPatch(sizeof(s_Buf_CheckStuck)) {}
virtual const char *GetFuncName() const override { return "CTFGameMovement::CheckStuck"; }
virtual uint32_t GetFuncOffMin() const override { return 0x0000; }
@@ -102,6 +102,47 @@ namespace Mod_Cond_Reprogrammed
"Mod: make some tweaks to TF_COND_REPROGRAMMED that Hell-met requested");
+ void ChangeWeaponAndWearableTeam(CTFPlayer *player, int team)
+ {
+ // DevMsg("ChangeWeaponAndWearableTeam (#%d \"%s\"): teamnum %d => %d\n",
+ // ENTINDEX(player), player->GetPlayerName(), player->GetTeamNumber(), team);
+
+ for (int i = player->WeaponCount() - 1; i >= 0; --i) {
+ CBaseCombatWeapon *weapon = player->GetWeapon(i);
+ if (weapon == nullptr) continue;
+
+ int pre_team = weapon->GetTeamNumber();
+ int pre_skin = weapon->m_nSkin;
+
+ weapon->ChangeTeam(team);
+ weapon->m_nSkin = (team == TF_TEAM_BLUE ? 1 : 0);
+
+ int post_team = weapon->GetTeamNumber();
+ int post_skin = weapon->m_nSkin;
+
+ // DevMsg(" weapon %d (#%d \"%s\"): [Team:%d Skin:%d] => [Team:%d Skin:%d]\n",
+ // i, ENTINDEX(weapon), weapon->GetClassname(), pre_team, pre_skin, post_team, post_skin);
+ }
+
+ for (int i = player->GetNumWearables() - 1; i >= 0; --i) {
+ CEconWearable *wearable = player->GetWearable(i);
+ if (wearable == nullptr) continue;
+
+ int pre_team = wearable->GetTeamNumber();
+ int pre_skin = wearable->m_nSkin;
+
+ wearable->ChangeTeam(team);
+ wearable->m_nSkin = (team == TF_TEAM_BLUE ? 1 : 0);
+
+ int post_team = wearable->GetTeamNumber();
+ int post_skin = wearable->m_nSkin;
+
+ // DevMsg(" wearable %d (#%d \"%s\"): [Team:%d Skin:%d] => [Team:%d Skin:%d]\n",
+ // i, ENTINDEX(wearable), wearable->GetClassname(), pre_team, pre_skin, post_team, post_skin);
+ }
+ }
+
+
void OnAddReprogrammed(CTFPlayer *player)
{
DevMsg("OnAddReprogrammed(#%d \"%s\")\n", ENTINDEX(player), player->GetPlayerName());
@@ -112,6 +153,11 @@ namespace Mod_Cond_Reprogrammed
player->ForceChangeTeam(TF_TEAM_RED, false);
+ /* ensure that all weapons and wearables have their colors updated */
+ if (cvar_hellmet.GetBool()) {
+ ChangeWeaponAndWearableTeam(player, TF_TEAM_RED);
+ }
+
/* this used to be in CTFPlayerShared::OnAddReprogrammed on the client
* side, but we now have to do it from the server side */
if (!cvar_hellmet.GetBool()) {
@@ -132,6 +178,20 @@ namespace Mod_Cond_Reprogrammed
player->ForceChangeTeam(TF_TEAM_BLUE, false);
+ /* ensure that all weapons and wearables have their colors updated;
+ * we don't do this in the case of LIFE_DYING, however, because
+ * CTFPlayer::Event_Killed calls CTFPlayerShared::RemoveAllCond, and we
+ * end up making the ragdoll wearables and dropped hats etc the wrong
+ * color compared to the player ragdoll itself */
+ if (cvar_hellmet.GetBool()) {
+ if (player->m_lifeState == LIFE_DYING) {
+ // hack hack hack: make wearable gibs be red
+ player->m_nSkin = 0;
+ } else {
+ ChangeWeaponAndWearableTeam(player, TF_TEAM_BLUE);
+ }
+ }
+
/* this is far from ideal; we can only remove ALL particle effects from
* the server side */
if (!cvar_hellmet.GetBool()) {
diff --git a/src/mod/credits/magnet_disable.cpp b/src/mod/credits/magnet_disable.cpp
index 4fe9848e..b28afc0c 100644
--- a/src/mod/credits/magnet_disable.cpp
+++ b/src/mod/credits/magnet_disable.cpp
@@ -16,9 +16,9 @@ namespace Mod_Credits_Magnet_Disable
// 0xc7, 0x43, 0x3c, 0x00, 0x00, 0x02, 0x44, // +0000 mov dword ptr [ebx+0x3c],520.0f
};
- struct CPatch_CTFPlayerShared_RadiusCurrencyCollectionCheck : public IPatch
+ struct CPatch_CTFPlayerShared_RadiusCurrencyCollectionCheck : public CPatch
{
- CPatch_CTFPlayerShared_RadiusCurrencyCollectionCheck() : IPatch(sizeof(s_Buf)) {}
+ CPatch_CTFPlayerShared_RadiusCurrencyCollectionCheck() : CPatch(sizeof(s_Buf)) {}
#error need addr
virtual const char *GetFuncName() const override { return "[client] CTFGameMovement::ProcessMovement"; }
diff --git a/src/mod/debug/backtrace.cpp b/src/mod/debug/backtrace.cpp
index c5c0c9e3..5d34e2bf 100644
--- a/src/mod/debug/backtrace.cpp
+++ b/src/mod/debug/backtrace.cpp
@@ -24,7 +24,7 @@ namespace Mod_Debug_Backtrace
void AddBacktrace(const char *lib, const char *pattern)
{
- auto backtrace = new CFuncBacktrace(LibMgr::FromString(lib), pattern);
+ auto backtrace = new CFuncBacktrace(LibMgr::Lib_FromString(lib), pattern);
if (backtrace->Load()) {
backtrace->Enable();
this->m_Backtraces.emplace_back(backtrace);
diff --git a/src/mod/debug/console_scramble.cpp b/src/mod/debug/console_scramble.cpp
deleted file mode 100644
index 20339529..00000000
--- a/src/mod/debug/console_scramble.cpp
+++ /dev/null
@@ -1,51 +0,0 @@
-#include "mod.h"
-
-
-namespace Mod_Debug_Console_Scramble
-{
- FILE *f = nullptr;
- SpewOutputFunc_t RealOutputFunc = nullptr;
-
-
- SpewRetval_t MyOutputFunc(SpewType_t spewType, const tchar *pMsg)
- {
- static std::mutex m;
- std::lock_guard lock(m);
-
- fprintf(f, "MyOutputFunc [%15.10f] [T %5u] \"%s\"\n", Plat_FloatTime(), ThreadGetCurrentId(), pMsg);
- fflush(f);
-
- return RealOutputFunc(spewType, pMsg);
- }
-
-
- class CMod : public IMod
- {
- public:
- CMod() : IMod("Debug:Console_Scramble") {}
-
- virtual void OnEnable() override
- {
- f = fopen("spewlog.txt", "w");
-
- RealOutputFunc = GetSpewOutputFunc();
- SpewOutputFunc(&MyOutputFunc);
- }
-
- virtual void OnDisable() override
- {
- SpewOutputFunc(RealOutputFunc);
-
- fclose(f);
- }
- };
- CMod s_Mod;
-
-
- ConVar cvar_enable("sig_debug_console_scramble", "0", FCVAR_NOTIFY,
- "Debug: determine why mat_queue_mode 2 causes console output to go out of order",
- [](IConVar *pConVar, const char *pOldValue, float flOldValue) {
- ConVarRef var(pConVar);
- s_Mod.Toggle(var.GetBool());
- });
-}
diff --git a/src/mod/debug/console_scramble_v1.cpp b/src/mod/debug/console_scramble_v1.cpp
new file mode 100644
index 00000000..63697519
--- /dev/null
+++ b/src/mod/debug/console_scramble_v1.cpp
@@ -0,0 +1,146 @@
+#include "mod.h"
+#include
+
+
+namespace Mod_Debug_Console_Scramble_v1
+{
+ FILE *f = nullptr;
+ SpewOutputFunc_t RealOutputFunc = nullptr;
+
+
+ SpewRetval_t MyOutputFunc(SpewType_t spewType, const tchar *pMsg)
+ {
+ static std::mutex m;
+ std::lock_guard lock(m);
+
+ fprintf(f, "MyOutputFunc [%15.10f] [T %4x] \"%s\"\n", Plat_FloatTime(), ThreadGetCurrentId(), pMsg);
+ fflush(f);
+
+ // if (Coroutine_IsActive()) {
+ // size_t depth = Coroutine_GetStackDepth();
+ // fprintf(f, ">>> In coroutine! Stack depth: %lu\n", depth);
+ // fflush(f);
+ // }
+
+ // if (ThreadGetCurrentId() != 0x5914) {
+ // __asm {
+ // int 3
+ // };
+ // }
+
+ // return RealOutputFunc(spewType, pMsg);
+ return SPEW_CONTINUE;
+ }
+
+
+ class CMod : public IMod
+ {
+ public:
+ CMod() : IMod("Debug:Console_Scramble_v1") {}
+
+ virtual void OnEnable() override
+ {
+ f = fopen("spewlog.txt", "w");
+
+ RealOutputFunc = GetSpewOutputFunc();
+ SpewOutputFunc(&MyOutputFunc);
+ }
+
+ virtual void OnDisable() override
+ {
+ SpewOutputFunc(RealOutputFunc);
+
+ fclose(f);
+ }
+ };
+ CMod s_Mod;
+
+
+ // new plan: detour all of these funcs, and synchronously print enter/exit events with thread ID to file from each
+ // Msg
+ // _SpewMessage
+ // ...
+
+
+ ConVar cvar_enable("sig_debug_console_scramble_v1", "0", FCVAR_NOTIFY,
+ "Debug: determine why mat_queue_mode 2 causes console output to go out of order",
+ [](IConVar *pConVar, const char *pOldValue, float flOldValue) {
+ ConVarRef var(pConVar);
+ s_Mod.Toggle(var.GetBool());
+ });
+}
+
+/* findings:
+
+Default client spew func is Sys_SpewFunc, which calls Con_ColorPrintf (engine/console.cpp)
+Con_ColorPrintf calls Con_ColorPrint, which calls
+- g_pCVar->ConsoleColorPrintf
+- g_pConPanel->AddToNotify
+
+the deserialization has already happened by the time we get to Con_ColorPrint
+
+it's in Sys_SpewFunc: inlined function AddSpewRecord(const char *) with static CUtlLinkedList g_SpewHistory
+no wait; actually all this does is add to a linked list for post-mortem minidump purposes (sys_minidumpspewlines);
+messing with sys_minidumpspewlines does nothing
+
+also there's GetSpew
+and g_SpewMutex
+
+
+ACTUAL REALIZATION:
+it's vstdlib coroutines, man!
+
+
+non-main thread:
+> tier0.dll!DevWarning() + 478 bytes Unknown
+ [Frames below may be incorrect and/or missing, no symbols loaded for tier0.dll]
+ atiumdag.dll!60c38567() Unknown
+ atiumdag.dll!60c37a54() Unknown
+ atiumdag.dll!60c8535a() Unknown
+ atiumdag.dll!60c83b66() Unknown
+ atiumdag.dll!60be4d54() Unknown
+ d3d9.dll!_AllocateCB@8() Unknown
+ ntdll.dll!_NtSetEvent@8() Unknown
+ GameOverlayRenderer.dll!NotifyVRCleanup() + 13193 bytes Unknown
+ atiu9pag.dll!OpenAdapter() + 1717 bytes Unknown
+ d3d9.dll!CD3DDDIDX10_DrawIndexedPrimitive(class CD3DBase *,enum _D3DPRIMITIVETYPE,unsigned int,unsigned int,unsigned int,unsigned int,unsigned int) Unknown
+ atiu9pag.dll!OpenAdapter() + 1434 bytes Unknown
+ d3d9.dll!CD3DBase::UpdateTextures(void) Unknown
+ d3d9.dll!CD3DHal::SetSamplerState_FP(unsigned long,enum _D3DSAMPLERSTATETYPE,unsigned long) Unknown
+ 1750d7c0() Unknown
+ atiu9pag.dll!OpenAdapter() + 1717 bytes Unknown
+ d3d9.dll!CD3DDDIDX10_DrawIndexedPrimitive(class CD3DBase *,enum _D3DPRIMITIVETYPE,unsigned int,unsigned int,unsigned int,unsigned int,unsigned int) Unknown
+ d3d9.dll!CD3DBase::DrawIndexedPrimitive(enum _D3DPRIMITIVETYPE,int,unsigned int,unsigned int,unsigned int,unsigned int) Unknown
+ shaderapidx9.dll!145ea027() Unknown
+ shaderapidx9.dll!145f5e91() Unknown
+ MaterialSystem.dll!0f8fa7e7() Unknown
+ MaterialSystem.dll!0f8fa7f5() Unknown
+ MaterialSystem.dll!0f8fa82e() Unknown
+ atiu9pag.dll!XopOpenAdapters9() + 3039 bytes Unknown
+ MaterialSystem.dll!0f8fa7f5() Unknown
+ MaterialSystem.dll!0f8fc73a() Unknown
+ MaterialSystem.dll!0f8fa5c8() Unknown
+ MaterialSystem.dll!0f8b957e() Unknown
+ shaderapidx9.dll!145f1605() Unknown
+ shaderapidx9.dll!145e7586() Unknown
+ shaderapidx9.dll!145e7b3f() Unknown
+ shaderapidx9.dll!145f23d2() Unknown
+ shaderapidx9.dll!145edae1() Unknown
+ MaterialSystem.dll!0f8dfb65() Unknown
+ MaterialSystem.dll!0f8dbeb0() Unknown
+ MaterialSystem.dll!0f8dc7ca() Unknown
+ MaterialSystem.dll!0f8dcf33() Unknown
+ MaterialSystem.dll!0f8cf6e4() Unknown
+ MaterialSystem.dll!0f8c3290() Unknown
+ MaterialSystem.dll!0f8c7158() Unknown
+ vstdlib.dll!Coroutine_YieldToMain() + 9984 bytes Unknown
+ ntdll.dll!_NtClearEvent@4() Unknown
+ tier0.dll!CThread::ThreadProc() + 256 bytes Unknown
+ tier0.dll!0fe0d4f7() Unknown
+ tier0.dll!0fe0d61f() Unknown
+ kernel32.dll!@BaseThreadInitThunk@12() Unknown
+ ntdll.dll!__RtlUserThreadStart() Unknown
+ ntdll.dll!__RtlUserThreadStart@8() Unknown
+
+
+*/
diff --git a/src/mod/debug/console_scramble_v2.cpp b/src/mod/debug/console_scramble_v2.cpp
new file mode 100644
index 00000000..b4a71c62
--- /dev/null
+++ b/src/mod/debug/console_scramble_v2.cpp
@@ -0,0 +1,118 @@
+#include "mod.h"
+
+
+namespace Mod_Debug_Console_Scramble_v2
+{
+ FILE *f = nullptr;
+
+
+ DETOUR_DECL_STATIC(SpewRetval_t, Sys_SpewFunc, SpewType_t spewType, const char *pMsg)
+ {
+ if (f != nullptr) {
+ fprintf(f, "%04X >> Sys_SpewFunc [%12.7f] [Tick %5d] [SpewFunc %08x] \"%s\"\n", ThreadGetCurrentId(), Plat_FloatTime(), gpGlobals->tickcount, (uintptr_t)GetSpewOutputFunc(), pMsg);
+ fflush(f);
+ }
+
+ auto result = DETOUR_STATIC_CALL(Sys_SpewFunc)(spewType, pMsg);
+
+ if (f != nullptr) {
+ fprintf(f, "%04X << Sys_SpewFunc [%12.7f] [Tick %5d] [SpewFunc %08x] \"%s\"\n", ThreadGetCurrentId(), Plat_FloatTime(), gpGlobals->tickcount, (uintptr_t)GetSpewOutputFunc(), pMsg);
+ fflush(f);
+ }
+
+ return result;
+ }
+
+
+ DETOUR_DECL_STATIC(void, ConColorMsg, const Color& clr, const char *pMsgFormat, ...)
+ {
+ // auto buf = new char[0x1000];
+ char buf[0x1000];
+
+ va_list va;
+ va_start(va, pMsgFormat);
+ V_vsnprintf(buf, 0x1000, pMsgFormat, va);
+ va_end(va);
+
+ if (f != nullptr) {
+ fprintf(f, "%04X >> ConColorMsg [%12.7f] [Tick %5d] [SpewFunc %08x] \"%s\"\n", ThreadGetCurrentId(), Plat_FloatTime(), gpGlobals->tickcount, (uintptr_t)GetSpewOutputFunc(), buf);
+ fflush(f);
+ }
+
+ DETOUR_STATIC_CALL(ConColorMsg)(clr, "%s", buf);
+
+ if (f != nullptr) {
+ fprintf(f, "%04X << ConColorMsg [%12.7f] [Tick %5d] [SpewFunc %08x] \"%s\"\n", ThreadGetCurrentId(), Plat_FloatTime(), gpGlobals->tickcount, (uintptr_t)GetSpewOutputFunc(), buf);
+ fflush(f);
+ }
+
+ // delete buf;
+ }
+
+
+ class CMod : public IMod
+ {
+ public:
+ CMod() : IMod("Debug:Console_Scramble_v2")
+ {
+ // this->AddDetour(new CDetour("Sys_SpewFunc", reinterpret_cast(GetSpewOutputFunc()), GET_STATIC_CALLBACK(Sys_SpewFunc), GET_STATIC_INNERPTR(Sys_SpewFunc)));
+ // this->AddDetour(new CDetour("ConColorMsg", reinterpret_cast(static_cast(&ConColorMsg)), GET_STATIC_CALLBACK(ConColorMsg), GET_STATIC_INNERPTR(ConColorMsg)));
+ }
+
+ virtual bool OnLoad() override
+ {
+ f = fopen("spewlog.txt", "w");
+ return (f != nullptr);
+ }
+
+ virtual void OnUnload() override
+ {
+ fclose(f);
+ f = nullptr;
+ }
+ };
+ CMod s_Mod;
+
+ ConVar cvar_enable("sig_debug_console_scramble_v2", "0", FCVAR_NOTIFY,
+ "Debug: determine why mat_queue_mode 2 causes console output to go out of order",
+ [](IConVar *pConVar, const char *pOldValue, float flOldValue) {
+ ConVarRef var(pConVar);
+ s_Mod.Toggle(var.GetBool());
+ });
+
+
+ class CModA : public IMod
+ {
+ public:
+ CModA() : IMod("Debug:Console_Scramble_v2_PartA")
+ {
+ this->AddDetour(new CDetour("Sys_SpewFunc", reinterpret_cast(GetSpewOutputFunc()), GET_STATIC_CALLBACK(Sys_SpewFunc), GET_STATIC_INNERPTR(Sys_SpewFunc)));
+ }
+ };
+ CModA s_ModA;
+
+ ConVar cvar_spewfunc("sig_debug_console_scramble_v2_spewfunc", "0", FCVAR_NOTIFY,
+ "Debug: enable Sys_SpewFunc detour",
+ [](IConVar *pConVar, const char *pOldValue, float flOldValue) {
+ ConVarRef var(pConVar);
+ s_ModA.Toggle(var.GetBool());
+ });
+
+
+ class CModB : public IMod
+ {
+ public:
+ CModB() : IMod("Debug:Console_Scramble_v2_PartB")
+ {
+ this->AddDetour(new CDetour("ConColorMsg", reinterpret_cast(static_cast(&ConColorMsg)), GET_STATIC_CALLBACK(ConColorMsg), GET_STATIC_INNERPTR(ConColorMsg)));
+ }
+ };
+ CModB s_ModB;
+
+ ConVar cvar_concolormsg("sig_debug_console_scramble_v2_concolormsg", "0", FCVAR_NOTIFY,
+ "Debug: enable ConColorMsg detour",
+ [](IConVar *pConVar, const char *pOldValue, float flOldValue) {
+ ConVarRef var(pConVar);
+ s_ModB.Toggle(var.GetBool());
+ });
+}
diff --git a/src/mod/debug/ctfbotproxy.cpp b/src/mod/debug/ctfbotproxy.cpp
new file mode 100644
index 00000000..5015d432
--- /dev/null
+++ b/src/mod/debug/ctfbotproxy.cpp
@@ -0,0 +1,347 @@
+#include "mod.h"
+#include "util/misc.h"
+#include "util/rtti.h"
+#include "util/iterate.h"
+
+////////////////////////////////////////////////////////////////////////////////
+#define typeof decltype
+#include <../server/variant_t.h>
+#define private public
+#include <../server/eventqueue.h>
+#undef private
+#undef typeof
+
+const char *variant_t::ToString( void ) const
+{
+ COMPILE_TIME_ASSERT( sizeof(string_t) == sizeof(int) );
+
+ static char szBuf[512];
+
+ switch (fieldType)
+ {
+ case FIELD_STRING:
+ {
+ return(STRING(iszVal));
+ }
+
+ case FIELD_BOOLEAN:
+ {
+ if (bVal == 0)
+ {
+ Q_strncpy(szBuf, "false",sizeof(szBuf));
+ }
+ else
+ {
+ Q_strncpy(szBuf, "true",sizeof(szBuf));
+ }
+ return(szBuf);
+ }
+
+ case FIELD_INTEGER:
+ {
+ Q_snprintf( szBuf, sizeof( szBuf ), "%i", iVal );
+ return(szBuf);
+ }
+
+ case FIELD_FLOAT:
+ {
+ Q_snprintf(szBuf,sizeof(szBuf), "%g", flVal);
+ return(szBuf);
+ }
+
+ case FIELD_COLOR32:
+ {
+ Q_snprintf(szBuf,sizeof(szBuf), "%d %d %d %d", (int)rgbaVal.r, (int)rgbaVal.g, (int)rgbaVal.b, (int)rgbaVal.a);
+ return(szBuf);
+ }
+
+ case FIELD_VECTOR:
+ {
+ Q_snprintf(szBuf,sizeof(szBuf), "[%g %g %g]", (double)vecVal[0], (double)vecVal[1], (double)vecVal[2]);
+ return(szBuf);
+ }
+
+ case FIELD_VOID:
+ {
+ szBuf[0] = '\0';
+ return(szBuf);
+ }
+
+ case FIELD_EHANDLE:
+ {
+ const char *pszName = (Entity()) ? STRING(Entity()->GetEntityName()) : "<>";
+ Q_strncpy( szBuf, pszName, 512 );
+ return (szBuf);
+ }
+ }
+
+ return("No conversion to string");
+}
+////////////////////////////////////////////////////////////////////////////////
+
+
+class IMapEntityFilter {};
+
+
+class CTFBotProxy : public CBaseEntity {};
+
+
+namespace Mod_Debug_CTFBotProxy
+{
+ const char *MakeEscapedVersion(const char *str)
+ {
+ static char buf[0x100000];
+ size_t pos = 0;
+
+ for (const char *c = str; *c != '\0'; ++c) {
+ if (isprint(*c)) {
+ buf[pos++] = *c;
+ } else {
+ char tmp[0x10];
+ V_sprintf_safe(tmp, "%02X", *(const uint8_t *)c);
+
+ buf[pos++] = '\\';
+ buf[pos++] = 'x';
+ buf[pos++] = tmp[0];
+ buf[pos++] = tmp[1];
+ }
+ }
+ buf[pos] = '\0';
+
+ return buf;
+ }
+
+
+ void PrintLineBrokenEscapedVersion(const char *str)
+ {
+ bool done = false;
+
+ do {
+ static char buf[0x10000];
+ size_t pos = 0;
+
+ for ( ; ; ++str) {
+ if (*str == '\0') {
+ done = true;
+ break;
+ }
+
+ if (isprint(*str)) {
+ buf[pos++] = *str;
+ } else {
+ char tmp[0x10];
+ V_sprintf_safe(tmp, "%02X", *(const uint8_t *)str);
+
+ buf[pos++] = '\\';
+ buf[pos++] = 'x';
+ buf[pos++] = tmp[0];
+ buf[pos++] = tmp[1];
+ }
+
+ if (*str == '\n') {
+ ++str;
+ break;
+ }
+ }
+
+ buf[pos++] = '\n';
+ buf[pos++] = '\0';
+
+ Msg(buf);
+ } while (!done);
+ }
+
+
+ DETOUR_DECL_STATIC(string_t, AllocPooledString, const char *pszValue)
+ {
+ ConColorMsg(Color(0xff, 0xff, 0x00, 0xff), "AllocPooledString(%s)\n", pszValue);
+ return DETOUR_STATIC_CALL(AllocPooledString)(pszValue);
+ }
+
+ DETOUR_DECL_MEMBER(void, CTFBotProxy_C1)
+ {
+ static uintptr_t prev = 0x00000000;
+
+ uintptr_t diff = Max((uintptr_t)this, prev) - Min((uintptr_t)this, prev);
+ ConColorMsg(Color(0x00, 0xff, 0xff, 0xff), "CTFBotProxy constructed @ 0x%08x (diff: 0x%08x)\n", (uintptr_t)this, diff);
+ prev = (uintptr_t)this;
+
+ DETOUR_MEMBER_CALL(CTFBotProxy_C1)();
+ }
+
+
+ DETOUR_DECL_MEMBER(bool, IServerGameDLL_LevelInit, const char *pMapName, const char *pMapEntities, const char *pOldLevel, const char *pLandmarkName, bool loadGame, bool background)
+ {
+ ConColorMsg(Color(0xff, 0x00, 0xff, 0xff), "DETOUR for IServerGameDLL::LevelInit\n");
+
+ for (const uint8_t *c = reinterpret_cast(pMapEntities); *c != '\0'; ++c) {
+ if (*c >= 0x80 && *c <= 0xff) {
+ Msg("- Detected character %02x @ pMapEntities+0x%x\n", (int)(*c), (uintptr_t)c - (uintptr_t)pMapEntities);
+ }
+ }
+
+ return DETOUR_MEMBER_CALL(IServerGameDLL_LevelInit)(pMapName, pMapEntities, pOldLevel, pLandmarkName, loadGame, background);
+ }
+
+ DETOUR_DECL_STATIC(void, MapEntity_ParseAllEntities, const char *pMapData, IMapEntityFilter *pFilter, bool bActivateEntities)
+ {
+ printf("MapEntity_ParseAllEntities: %s\n", MakeEscapedVersion(pMapData));
+
+ DETOUR_STATIC_CALL(MapEntity_ParseAllEntities)(pMapData, pFilter, bActivateEntities);
+ }
+
+ DETOUR_DECL_STATIC(const char *, MapEntity_ParseEntity, CBaseEntity *&pEntity, const char *pEntData, IMapEntityFilter *pFilter)
+ {
+ printf("MapEntity_ParseEntity: %s\n", MakeEscapedVersion(pEntData));
+ // PrintLineBrokenEscapedVersion(pEntData);
+
+ return DETOUR_STATIC_CALL(MapEntity_ParseEntity)(pEntity, pEntData, pFilter);
+ }
+
+ DETOUR_DECL_STATIC(const char *, MapEntity_ParseToken, const char *data, char *newToken)
+ {
+ auto result = DETOUR_STATIC_CALL(MapEntity_ParseToken)(data, newToken);
+
+ int len1 = result - data;
+ int len2 = strlen(newToken);
+ Msg("MapEntity_ParseToken: %d %d %s\n", len1, len2, MakeEscapedVersion(newToken));
+
+ return result;
+ }
+
+
+ DETOUR_DECL_MEMBER(void, CEventQueue_AddEvent, EventQueuePrioritizedEvent_t *pe)
+ {
+ auto queue = reinterpret_cast(this);
+
+ ConColorMsg(Color(0x00, 0xff, 0x00, 0xff),
+ "[%10.6f] AddEvent: [t: %10.6f] [target: '%s' '%s'] [param: '%s'] [activator: '%s'] [caller: '%s']\n",
+ engine->GetServerTime(),
+ pe->m_flFireTime,
+ STRING(pe->m_iTarget),
+ STRING(pe->m_iTargetInput),
+ pe->m_VariantValue.String(),
+ (pe->m_pActivator != nullptr ? STRING(pe->m_pActivator->GetEntityName()) : "none"),
+ (pe->m_pCaller != nullptr ? STRING(pe->m_pCaller ->GetEntityName()) : "none"));
+
+ DETOUR_MEMBER_CALL(CEventQueue_AddEvent)(pe);
+ }
+
+ DETOUR_DECL_MEMBER(void, CEventQueue_ServiceEvents)
+ {
+ auto queue = reinterpret_cast(this);
+
+ if (queue->m_Events.m_pNext != nullptr) {
+ ConColorMsg(Color(0xff, 0xff, 0x00, 0xff),
+ "[%10.6f] CEventQueue::ServiceEvents DUMP:\n",
+ engine->GetServerTime());
+
+ for (EventQueuePrioritizedEvent_t *pe = queue->m_Events.m_pNext; pe != nullptr; pe = pe->m_pNext) {
+ ConColorMsg(Color(0xff, 0xff, 0x00, 0xff),
+ "[t: %10.6f] [target: '%s' '%s'] [param: '%s'] [activator: '%s'] [caller: '%s']\n",
+ pe->m_flFireTime,
+ STRING(pe->m_iTarget),
+ STRING(pe->m_iTargetInput),
+ pe->m_VariantValue.String(),
+ (pe->m_pActivator != nullptr ? STRING(pe->m_pActivator->GetEntityName()) : "none"),
+ (pe->m_pCaller != nullptr ? STRING(pe->m_pCaller ->GetEntityName()) : "none"));
+ }
+ }
+
+ DETOUR_MEMBER_CALL(CEventQueue_ServiceEvents)();
+ }
+
+
+ class CMod : public IMod
+ {
+ public:
+ CMod() : IMod("Debug:CTFBotProxy")
+ {
+ MOD_ADD_DETOUR_STATIC(AllocPooledString, "AllocPooledString");
+ MOD_ADD_DETOUR_MEMBER(CTFBotProxy_C1, "CTFBotProxy::CTFBotProxy [C1]");
+
+ // MOD_ADD_DETOUR_MEMBER(IServerGameDLL_LevelInit, "IServerGameDLL::LevelInit");
+ // MOD_ADD_DETOUR_STATIC(MapEntity_ParseAllEntities, "MapEntity_ParseAllEntities");
+ // MOD_ADD_DETOUR_STATIC(MapEntity_ParseEntity, "MapEntity_ParseEntity");
+ // MOD_ADD_DETOUR_STATIC(MapEntity_ParseToken, "MapEntity_ParseToken");
+
+ MOD_ADD_DETOUR_MEMBER(CEventQueue_AddEvent, "CEventQueue::AddEvent [EventQueuePrioritizedEvent_t *]");
+ MOD_ADD_DETOUR_MEMBER(CEventQueue_ServiceEvents, "CEventQueue::ServiceEvents");
+ }
+ };
+ CMod s_Mod;
+
+
+ ConVar cvar_enable("sig_debug_ctfbotproxy", "0", FCVAR_NOTIFY,
+ "",
+ [](IConVar *pConVar, const char *pOldValue, float flOldValue) {
+ ConVarRef var(pConVar);
+ s_Mod.Toggle(var.GetBool());
+ });
+
+
+ void PrintHeader()
+ {
+ Msg("\n--------------------------------------------------------------------------------\n");
+ Msg("%-10s %5s %-12s | %-10s\n", "ADDR", "EIDX", "NAME", "VTADDR");
+ }
+
+ void PrintProxy(CTFBotProxy *proxy)
+ {
+ CFmtStr col_addr("0x%08x", (uintptr_t)proxy);
+ CFmtStr col_eidx("#%d", ENTINDEX(proxy));
+ CFmtStr col_name("%s", STRING(proxy->GetEntityName()));
+ CFmtStr col_vt ("0x%08x", *reinterpret_cast(proxy));
+
+ Msg("%-10s %5s %-12s | %10s\n", col_addr.Get(), col_eidx.Get(), col_name.Get(), col_vt.Get());
+ }
+
+ CON_COMMAND(sig_debug_ctfbotproxy_cmd, "")
+ {
+ static auto addr_VT = (uintptr_t)RTTI::GetVTable();
+ static auto addr_RTTI = (uintptr_t)RTTI::GetRTTI ();
+
+ static auto addr_s_pTokenBuf = (uintptr_t)AddrManager::GetAddr("s_pTokenBuf");
+
+ Msg("\n================================================================================\n");
+ Msg("CTFBotProxy VT: %08x\n", addr_VT);
+ Msg("CTFBotProxy RTTI: %08x\n", addr_RTTI);
+ Msg("s_pTokenBuf: %08x\n", addr_s_pTokenBuf);
+
+
+ if (args.ArgC() > 1 && FStrEq(args[1], "list")) {
+ std::map proxies_by_addr;
+ std::map proxies_by_eidx;
+ std::map proxies_by_name;
+
+ ForEachEntityByClassname("bot_proxy", [&](CBaseEntity *ent){
+ auto proxy = static_cast(ent);
+
+ proxies_by_addr[(uintptr_t)ent] = proxy;
+ proxies_by_eidx[ENTINDEX(ent)] = proxy;
+ proxies_by_name[STRING(ent->GetEntityName())] = proxy;
+ });
+
+ bool by_addr = (args.ArgC() > 2 && FStrEq(args[2], "addr"));
+ bool by_eidx = (args.ArgC() > 2 && FStrEq(args[2], "eidx"));
+ bool by_name = (args.ArgC() > 2 && FStrEq(args[2], "name"));
+
+ if (by_addr) {
+ PrintHeader();
+ for (const auto& pair : proxies_by_addr) {
+ PrintProxy(pair.second);
+ }
+ } else if (by_eidx) {
+ PrintHeader();
+ for (const auto& pair : proxies_by_eidx) {
+ PrintProxy(pair.second);
+ }
+ } else if (by_name) {
+ PrintHeader();
+ for (const auto& pair : proxies_by_name) {
+ PrintProxy(pair.second);
+ }
+ }
+ }
+ }
+}
diff --git a/src/mod/debug/sentrybuster_mannhattan.cpp b/src/mod/debug/sentrybuster_mannhattan.cpp
new file mode 100644
index 00000000..a329858e
--- /dev/null
+++ b/src/mod/debug/sentrybuster_mannhattan.cpp
@@ -0,0 +1,135 @@
+#include "mod.h"
+#include "stub/tfbot.h"
+#include "util/scope.h"
+#include "util/iterate.h"
+
+
+namespace Mod_Debug_SentryBuster_Mannhattan
+{
+ std::vector messages;
+
+
+ RefCount rc_CTFBotTacticalMonitor_OnNavAreaChanged;
+ DETOUR_DECL_MEMBER(EventDesiredResult, CTFBotTacticalMonitor_OnNavAreaChanged, CTFBot *actor, CNavArea *area1, CNavArea *area2)
+ {
+ messages.clear();
+
+ SCOPED_INCREMENT(rc_CTFBotTacticalMonitor_OnNavAreaChanged);
+ auto result = DETOUR_MEMBER_CALL(CTFBotTacticalMonitor_OnNavAreaChanged)(actor, area1, area2);
+
+ if (result.transition == ActionTransition::SUSPEND_FOR) {
+ DevMsg("CTFBotTacticalMonitor::OnNavAreaChanged\n");
+
+ for (const char *msg : messages) {
+ DevMsg("%s", msg);
+ }
+ }
+
+ return result;
+ }
+
+ DETOUR_DECL_MEMBER(bool, CBaseTrigger_PassesTriggerFilters, CBaseEntity *pOther)
+ {
+ auto trigger = reinterpret_cast(this);
+
+ auto result = DETOUR_MEMBER_CALL(CBaseTrigger_PassesTriggerFilters)(pOther);
+
+ if (rc_CTFBotTacticalMonitor_OnNavAreaChanged > 0) {
+
+
+ messages.emplace_back(CFmtStr("- [prereq: %s] [passed filter: %s]\n", STRING(trigger->GetEntityName()), (result ? "true" : "false")));
+ }
+
+ return result;
+ }
+
+
+ // CFilterMultiple filter_multi
+ // CFilterTFBotHasTag filter_tfbot_has_tag
+
+ /*
+ _ZN11CBaseFilter16PassesFilterImplEP11CBaseEntityS1_
+ _ZN15CFilterMultiple16PassesFilterImplEP11CBaseEntityS1_
+ _ZN18CFilterTFBotHasTag16PassesFilterImplEP11CBaseEntityS1_
+ */
+
+
+ void DrawPrerequisiteOverlays()
+ {
+ static CountdownTimer ctDraw;
+ if (!ctDraw.IsElapsed()) return;
+ ctDraw.Start(1.000f);
+
+ ForEachEntityByRTTI([](CFuncNavPrerequisite *prereq){
+ constexpr float dur = 1.000f;
+
+ int task = prereq->m_task;
+ const char *task_ent_name = STRING((string_t)prereq->m_taskEntityName);
+ float task_value = prereq->m_taskValue;
+ bool enabled = !prereq->m_isDisabled;
+
+ CFmtStr task_str;
+ switch (task) {
+ case CFuncNavPrerequisite::DESTROY_ENTITY: task_str.sprintf("DESTROY_ENTITY"); break;
+ case CFuncNavPrerequisite::MOVE_TO: task_str.sprintf("MOVE_TO"); break;
+ case CFuncNavPrerequisite::WAIT: task_str.sprintf("WAIT"); break;
+
+ default:
+ task_str.sprintf("(?) %d", task);
+ break;
+ }
+
+ int r = (enabled ? 0x00 : 0xff);
+ int g = (enabled ? 0xff : 0x00);
+ int b = 0x00;
+ int a = 0x20;
+ NDebugOverlay::EntityBounds(prereq, r, g, b, a, dur);
+
+ const Vector& wsc = prereq->WorldSpaceCenter();
+
+ int l = -2;
+ NDebugOverlay::EntityTextAtPosition(wsc, l++, CFmtStr("Name: %s", STRING(prereq->GetEntityName())), dur);
+ NDebugOverlay::EntityTextAtPosition(wsc, l++, CFmtStr("Task: %s", task_str.Get()), dur);
+ NDebugOverlay::EntityTextAtPosition(wsc, l++, CFmtStr("Task ent: %s", task_ent_name), dur);
+ NDebugOverlay::EntityTextAtPosition(wsc, l++, CFmtStr("Task value: %f", task_value), dur);
+
+ ++l;
+ NDebugOverlay::EntityTextAtPosition(wsc, l++, CFmtStr("m_bDisabled: %s", (prereq->m_bDisabled ? "true" : "false")), dur);
+ NDebugOverlay::EntityTextAtPosition(wsc, l++, CFmtStr("m_isDisabled: %s", (prereq->m_isDisabled ? "true" : "false")), dur);
+
+ CBaseEntity *task_ent = servertools->FindEntityByName(nullptr, task_ent_name);
+ if (task_ent != nullptr && !task_ent->ClassMatches("func_nav_prerequisite")) {
+ NDebugOverlay::EntityBounds(task_ent, 0xff, 0xff, 0xff, 0x20, dur);
+
+ NDebugOverlay::EntityTextAtPosition(task_ent->WorldSpaceCenter(), 0, task_ent_name, dur);
+ }
+ });
+ }
+
+
+ class CMod : public IMod, public IFrameUpdateListener
+ {
+ public:
+ CMod() : IMod("Debug:SentryBuster_Mannhattan")
+ {
+ MOD_ADD_DETOUR_MEMBER(CTFBotTacticalMonitor_OnNavAreaChanged, "CTFBotTacticalMonitor::OnNavAreaChanged");
+ MOD_ADD_DETOUR_MEMBER(CBaseTrigger_PassesTriggerFilters, "CBaseTrigger::PassesTriggerFilters");
+ }
+
+ virtual bool ShouldReceiveFrameEvents() const override { return this->IsEnabled(); }
+
+ virtual void FrameUpdatePostEntityThink() override
+ {
+ DrawPrerequisiteOverlays();
+ }
+ };
+ CMod s_Mod;
+
+
+ ConVar cvar_enable("sig_debug_sentrybuster_mannhattan", "0", FCVAR_NOTIFY,
+ "Debug: investigate the specifics of the func_nav_prerequisite gate issues related to busters",
+ [](IConVar *pConVar, const char *pOldValue, float flOldValue) {
+ ConVarRef var(pConVar);
+ s_Mod.Toggle(var.GetBool());
+ });
+}
diff --git a/src/mod/debug/useitem_broken.cpp b/src/mod/debug/useitem_broken.cpp
index f5358b09..3294127c 100644
--- a/src/mod/debug/useitem_broken.cpp
+++ b/src/mod/debug/useitem_broken.cpp
@@ -7,6 +7,8 @@
#include "util/misc.h"
#include "util/clientmsg.h"
+#include
+
//#include "../mvm-reversed/server/tf/bot/behavior/tf_bot_use_item.h"
class CTFBotUseItem : public Action
@@ -215,6 +217,16 @@ namespace Mod_Debug_UseItem_Broken
ClientMsg(" \n[%8.3f] CTFBotUseItem::Update(#%d)\n", gpGlobals->curtime, ENTINDEX(actor));
+ if (useitem->m_hItem != nullptr) {
+ ClientMsg("%*s[m_bRageDraining: %s]\n", 13, " ", (actor->m_Shared->m_bRageDraining ? "true" : "false"));
+ ClientMsg("%*s[m_flRageMeter: %6.2f]\n", 13, " ", (float)actor->m_Shared->m_flRageMeter);
+ ClientMsg("%*s[m_flEnergyDrinkMeter: %6.2f]\n", 13, " ", (float)actor->m_Shared->m_flEnergyDrinkMeter);
+ ClientMsg("%*s[InCond(TF_COND_TAUNTING): %s]\n", 13, " ", (actor->m_Shared->InCond(TF_COND_TAUNTING) ? "true" : "false"));
+ ClientMsg("%*s[item->HasAmmo(): %s]\n", 13, " ", (useitem->m_hItem->HasAmmo() ? "true" : "false"));
+ ClientMsg("%*s[item->m_flLastFireTime: %8.3f]\n", 13, " ", (float)useitem->m_hItem->m_flLastFireTime);
+ ClientMsg("%*s[item->m_flEffectBarRegenTime: %8.3f]\n", 13, " ", (float)useitem->m_hItem->m_flEffectBarRegenTime);
+ }
+
if (useitem->m_ctInitialDelay.HasStarted() && useitem->m_ctInitialDelay.IsElapsed()) {
ClientMsg("%*sInitial delay elapsed; pressing +attack now\n", 13, " ");
}
@@ -242,8 +254,8 @@ namespace Mod_Debug_UseItem_Broken
auto bot = reinterpret_cast(this);
/* TODO: remove this garbage! */
- constexpr int OFF_m_RequiredWeapons = 0x2570;
- auto m_RequiredWeapons = reinterpret_cast> *>((uintptr_t)bot + OFF_m_RequiredWeapons);
+ constexpr int OFF_m_RequiredWeapons = 0x25c4;
+ auto m_RequiredWeapons = reinterpret_cast> *>((uintptr_t)bot + OFF_m_RequiredWeapons);
DETOUR_MEMBER_CALL(CTFBot_PushRequiredWeapon)(weapon);
if (rc_CTFBotUseItem_OnStart > 0) {
@@ -265,8 +277,8 @@ namespace Mod_Debug_UseItem_Broken
auto bot = reinterpret_cast(this);
/* TODO: remove this garbage! */
- constexpr int OFF_m_RequiredWeapons = 0x2570;
- auto m_RequiredWeapons = reinterpret_cast> *>((uintptr_t)bot + OFF_m_RequiredWeapons);
+ constexpr int OFF_m_RequiredWeapons = 0x25c4;
+ auto m_RequiredWeapons = reinterpret_cast> *>((uintptr_t)bot + OFF_m_RequiredWeapons);
DETOUR_MEMBER_CALL(CTFBot_PopRequiredWeapon)();
if (rc_CTFBotUseItem_OnEnd > 0) {
@@ -288,9 +300,9 @@ namespace Mod_Debug_UseItem_Broken
{
auto bot = reinterpret_cast(this);
- const char *before = WeaponID_ToString(bot->GetActiveTFWeapon()->GetWeaponID());
+ const char *before = (bot->GetActiveTFWeapon() != nullptr ? WeaponID_ToString(bot->GetActiveTFWeapon()->GetWeaponID()) : "nullptr");
auto result = DETOUR_MEMBER_CALL(CTFBot_EquipRequiredWeapon)();
- const char *after = WeaponID_ToString(bot->GetActiveTFWeapon()->GetWeaponID());
+ const char *after = (bot->GetActiveTFWeapon() != nullptr ? WeaponID_ToString(bot->GetActiveTFWeapon()->GetWeaponID()) : "nullptr");
if (strcmp(before, after) != 0) {
ClientMsg(" \n[%8.3f] CTFBot::EquipRequiredWeapon(#%d): %s -> %s\n", gpGlobals->curtime, ENTINDEX(bot), before, after);
diff --git a/src/mod/etc/melee_ignore_teammates.cpp b/src/mod/etc/melee_ignore_teammates.cpp
new file mode 100644
index 00000000..37725f70
--- /dev/null
+++ b/src/mod/etc/melee_ignore_teammates.cpp
@@ -0,0 +1,93 @@
+#include "mod.h"
+#include "stub/tfweaponbase.h"
+#include "util/scope.h"
+
+
+namespace Mod_Etc_Melee_Ignore_Teammates
+{
+ CTFWeaponBaseMelee *melee = nullptr;
+ CTFPlayer *owner = nullptr;
+ bool is_whip = false;
+
+ RefCount rc_CTFWeaponBaseMelee_DoSwingTraceInternal;
+ DETOUR_DECL_MEMBER(bool, CTFWeaponBaseMelee_DoSwingTraceInternal, CGameTrace& tr, bool cleave_attack, CUtlVector *traces)
+ {
+ auto weapon = reinterpret_cast(this);
+
+ bool result;
+ if (!cleave_attack) {
+ melee = weapon;
+ owner = (weapon != nullptr ? weapon->GetTFPlayerOwner() : nullptr);
+ is_whip = (CAttributeManager::AttribHookValue(0, "speed_buff_ally", weapon) > 0);
+
+ SCOPED_INCREMENT(rc_CTFWeaponBaseMelee_DoSwingTraceInternal);
+ result = DETOUR_MEMBER_CALL(CTFWeaponBaseMelee_DoSwingTraceInternal)(tr, cleave_attack, traces);
+
+ melee = nullptr;
+ owner = nullptr;
+ is_whip = false;
+ } else {
+ result = DETOUR_MEMBER_CALL(CTFWeaponBaseMelee_DoSwingTraceInternal)(tr, cleave_attack, traces);
+ }
+
+ return result;
+ }
+
+
+ RefCount rc_FindHullIntersection;
+ DETOUR_DECL_STATIC(void, FindHullIntersection, const Vector& vecSrc, trace_t& tr, const Vector& mins, const Vector& maxs, CBaseEntity *pEntity)
+ {
+ SCOPED_INCREMENT(rc_FindHullIntersection);
+ DETOUR_STATIC_CALL(FindHullIntersection)(vecSrc, tr, mins, maxs, pEntity);
+ }
+
+
+ DETOUR_DECL_MEMBER(void, IEngineTrace_TraceRay, const Ray_t& ray, unsigned int fMask, ITraceFilter *pTraceFilter, trace_t *pTrace)
+ {
+ if (rc_CTFWeaponBaseMelee_DoSwingTraceInternal > 0) {
+ // doing fallback stuff
+ if (rc_FindHullIntersection > 0) {
+ // if it's a CTraceFilterSimple and we're called from within FindHullIntersection, then we're doing fallback stuff
+ // ...
+ }
+
+ // if it's a CTraceFilterIgnorePlayers, then we're doing the Homewrecker thing
+ // and we should leave it alone
+
+ // if it's a CTraceFilterIgnoreTeammates, then we're doing the regular trace for MvM robots
+ // ...
+
+ // if it's a CTraceFilterIgnoreFriendlyCombatItems, then we're doing the regular trace for non-MvM-robots
+ // ...
+
+ #warning TODO
+ #warning TODO
+ #warning TODO
+ }
+
+ DETOUR_MEMBER_CALL(IEngineTrace_TraceRay)(ray, fMask, pTraceFilter, pTrace);
+ }
+
+
+ class CMod : public IMod
+ {
+ public:
+ CMod() : IMod("Etc:Melee_Ignore_Teammates")
+ {
+ MOD_ADD_DETOUR_MEMBER(CTFWeaponBaseMelee_DoSwingTraceInternal, "CTFWeaponBaseMelee::DoSwingTraceInternal");
+
+ MOD_ADD_DETOUR_STATIC(FindHullIntersection, "FindHullIntersection");
+
+ MOD_ADD_DETOUR_MEMBER(IEngineTrace_TraceRay, "IEngineTrace::TraceRay");
+ }
+ };
+ CMod s_Mod;
+
+
+ ConVar cvar_enable("sig_etc_melee_ignore_teammates", "0", FCVAR_NOTIFY,
+ "Mod: allow melee traces to pass through teammates (for anyone, not just MvM blu team players)",
+ [](IConVar *pConVar, const char *pOldValue, float flOldValue) {
+ ConVarRef var(pConVar);
+ s_Mod.Toggle(var.GetBool());
+ });
+}
diff --git a/src/mod/etc/override_move_speed.cpp b/src/mod/etc/override_move_speed.cpp
index e6fa0805..2dd910cd 100644
--- a/src/mod/etc/override_move_speed.cpp
+++ b/src/mod/etc/override_move_speed.cpp
@@ -20,9 +20,9 @@ namespace Mod_Etc_Override_Move_Speed
0xc7, 0x47, 0x3c, 0x00, 0x00, 0x02, 0x44, // +0000 mov dword ptr [edi+0x3c],520.0f
};
- struct CPatch_CTFGameMovement_ProcessMovement_Server : public IPatch
+ struct CPatch_CTFGameMovement_ProcessMovement_Server : public CPatch
{
- CPatch_CTFGameMovement_ProcessMovement_Server() : IPatch(sizeof(s_Buf_Server)) {}
+ CPatch_CTFGameMovement_ProcessMovement_Server() : CPatch(sizeof(s_Buf_Server)) {}
virtual const char *GetFuncName() const override { return "CTFGameMovement::ProcessMovement"; }
virtual uint32_t GetFuncOffMin() const override { return 0x0000; }
@@ -50,9 +50,9 @@ namespace Mod_Etc_Override_Move_Speed
0xc7, 0x43, 0x3c, 0x00, 0x00, 0x02, 0x44, // +0000 mov dword ptr [ebx+0x3c],520.0f
};
- struct CPatch_CTFGameMovement_ProcessMovement_Client : public IPatch
+ struct CPatch_CTFGameMovement_ProcessMovement_Client : public CPatch
{
- CPatch_CTFGameMovement_ProcessMovement_Client() : IPatch(sizeof(s_Buf_Client)) {}
+ CPatch_CTFGameMovement_ProcessMovement_Client() : CPatch(sizeof(s_Buf_Client)) {}
virtual const char *GetFuncName() const override { return "[client] CTFGameMovement::ProcessMovement"; }
virtual uint32_t GetFuncOffMin() const override { return 0x0000; }
diff --git a/src/mod/mvm/dominations.cpp b/src/mod/mvm/dominations.cpp
index 87a17212..1af15ced 100644
--- a/src/mod/mvm/dominations.cpp
+++ b/src/mod/mvm/dominations.cpp
@@ -10,9 +10,9 @@ namespace Mod_MvM_Dominations
0x75, 0xcc, // +0009 jnz -0x34
};
- struct CPatch_CTFGameRules_CalcDominationAndRevenge : public IPatch
+ struct CPatch_CTFGameRules_CalcDominationAndRevenge : public CPatch
{
- CPatch_CTFGameRules_CalcDominationAndRevenge() : IPatch(sizeof(s_Buf)) {}
+ CPatch_CTFGameRules_CalcDominationAndRevenge() : CPatch(sizeof(s_Buf)) {}
virtual const char *GetFuncName() const override { return "CTFGameRules::CalcDominationAndRevenge"; }
virtual uint32_t GetFuncOffMin() const override { return 0x0000; }
diff --git a/src/mod/mvm/gib_improvements.cpp b/src/mod/mvm/gib_improvements.cpp
index fc307372..17b24368 100644
--- a/src/mod/mvm/gib_improvements.cpp
+++ b/src/mod/mvm/gib_improvements.cpp
@@ -15,9 +15,9 @@ namespace Mod_MvM_Gib_Improvements
0x75, 0xde, // +0009 jnz -0x22
};
- struct CPatch_CTFPlayer_ShouldGib : public IPatch
+ struct CPatch_CTFPlayer_ShouldGib : public CPatch
{
- CPatch_CTFPlayer_ShouldGib() : IPatch(sizeof(s_Buf)) {}
+ CPatch_CTFPlayer_ShouldGib() : CPatch(sizeof(s_Buf)) {}
virtual const char *GetFuncName() const override { return "CTFPlayer::ShouldGib"; }
virtual uint32_t GetFuncOffMin() const override { return 0x0000; }
@@ -118,17 +118,24 @@ namespace Mod_MvM_Gib_Improvements
}
}
- /* explosive headshot gibbing :) */
- if (eh_tick == gpGlobals->tickcount && eh_victims.count(bot) != 0) {
- return true;
- }
-
/* can't use the vfunc thunk for this call because we specifically
* want to call the implementation in CTFPlayer */
static auto p_CTFPlayer_ShouldGib = MakePtrToMemberFunc(AddrManager::GetAddr("CTFPlayer::ShouldGib"));
return (bot->*p_CTFPlayer_ShouldGib)(info);
}
+ DETOUR_DECL_MEMBER(bool, CTFPlayer_ShouldGib, const CTakeDamageInfo& info)
+ {
+ auto player = reinterpret_cast(this);
+
+ /* explosive headshot gibbing :) */
+ if (eh_tick == gpGlobals->tickcount && eh_victims.count(player) != 0) {
+ return true;
+ }
+
+ return DETOUR_MEMBER_CALL(CTFPlayer_ShouldGib)(info);
+ }
+
// Problems:
// 1. TF_CUSTOM_PLASMA (Cow Mangler and medic shield) turns giants into
@@ -170,7 +177,8 @@ namespace Mod_MvM_Gib_Improvements
MOD_ADD_DETOUR_MEMBER(CTFSniperRifle_ExplosiveHeadShot, "CTFSniperRifle::ExplosiveHeadShot");
MOD_ADD_DETOUR_MEMBER(CTFPlayerShared_StunPlayer, "CTFPlayerShared::StunPlayer");
- MOD_ADD_DETOUR_MEMBER(CTFBot_ShouldGib, "CTFBot::ShouldGib");
+ MOD_ADD_DETOUR_MEMBER(CTFBot_ShouldGib, "CTFBot::ShouldGib");
+ MOD_ADD_DETOUR_MEMBER(CTFPlayer_ShouldGib, "CTFPlayer::ShouldGib");
MOD_ADD_DETOUR_MEMBER(CTFPlayer_CreateRagdollEntity, "CTFPlayer::CreateRagdollEntity [args]");
}
diff --git a/src/mod/mvm/medigunshield_damage.cpp b/src/mod/mvm/medigunshield_damage.cpp
index bdba4dbb..ba59e4b2 100644
--- a/src/mod/mvm/medigunshield_damage.cpp
+++ b/src/mod/mvm/medigunshield_damage.cpp
@@ -11,9 +11,9 @@ namespace Mod_MvM_MedigunShield_Damage
0xe9, 0x36, 0xfd, 0xff, 0xff, // +0011 jmp -0x2ca
};
- struct CPatch_CTFMedigunShield_ShieldTouch : public IPatch
+ struct CPatch_CTFMedigunShield_ShieldTouch : public CPatch
{
- CPatch_CTFMedigunShield_ShieldTouch() : IPatch(sizeof(s_Buf)) {}
+ CPatch_CTFMedigunShield_ShieldTouch() : CPatch(sizeof(s_Buf)) {}
virtual const char *GetFuncName() const override { return "CTFMedigunShield::ShieldTouch"; }
virtual uint32_t GetFuncOffMin() const override { return 0x02c0; }
diff --git a/src/mod/mvm/no_halloween_souls.cpp b/src/mod/mvm/no_halloween_souls.cpp
new file mode 100644
index 00000000..db5a9497
--- /dev/null
+++ b/src/mod/mvm/no_halloween_souls.cpp
@@ -0,0 +1,35 @@
+#include "mod.h"
+#include "stub/gamerules.h"
+
+
+namespace Mod_MvM_No_Halloween_Souls
+{
+ DETOUR_DECL_MEMBER(void, CTFGameRules_DropHalloweenSoulPack, int i1, const Vector& vec1, CBaseEntity *ent1, int i2)
+ {
+ if (TFGameRules()->IsMannVsMachineMode()) {
+ /* don't spawn "halloween_souls_pack" entities in MvM mode */
+ return;
+ }
+
+ DETOUR_MEMBER_CALL(CTFGameRules_DropHalloweenSoulPack)(i1, vec1, ent1, i2);
+ }
+
+
+ class CMod : public IMod
+ {
+ public:
+ CMod() : IMod("MvM:No_Halloween_Souls")
+ {
+ MOD_ADD_DETOUR_MEMBER(CTFGameRules_DropHalloweenSoulPack, "CTFGameRules::DropHalloweenSoulPack");
+ }
+ };
+ CMod s_Mod;
+
+
+ ConVar cvar_enable("sig_mvm_no_halloween_souls", "0", FCVAR_NOTIFY,
+ "Mod: disable those stupid Halloween soul drop things in MvM mode",
+ [](IConVar *pConVar, const char *pOldValue, float flOldValue) {
+ ConVarRef var(pConVar);
+ s_Mod.Toggle(var.GetBool());
+ });
+}
diff --git a/src/mod/mvm/robosapper_override.cpp b/src/mod/mvm/robosapper_override.cpp
new file mode 100644
index 00000000..b6d6e8f9
--- /dev/null
+++ b/src/mod/mvm/robosapper_override.cpp
@@ -0,0 +1,77 @@
+#include "mod.h"
+#include "stub/tfplayer.h"
+#include "stub/tf_shareddefs.h"
+#include "util/scope.h"
+
+
+namespace Mod_MvM_RoboSapper_Override
+{
+ ConVar cvar_radius("sig_mvm_robosapper_override_radius", "-1", FCVAR_NOTIFY,
+ "Mod: robo sapper radius (usual: 0 @ L0, 200 @ L1, 225 @ L2, 250 @ L3); if negative, no override will be applied");
+ ConVar cvar_duration("sig_mvm_robosapper_override_duration", "-1.0", FCVAR_NOTIFY,
+ "Mod: robo sapper duration (usual: 4.0 @ L0, 4.0 @ L1, 5.5 @ L2, 7.0 @ L3); if negative, no override will be applied");
+
+ ConVar cvar_stun_minibosses("sig_mvm_robosapper_override_stun_minibosses", "0", FCVAR_NOTIFY,
+ "Mod: robo sapper will apply full stun to minibosses instead of just partial stun (usual: 0)");
+ ConVar cvar_stun_amount("sig_mvm_robosapper_override_stun_amount", "0.85", FCVAR_NOTIFY,
+ "Mod: robo sapper will apply specified stun amount (usual: 0.85)");
+
+
+ DETOUR_DECL_MEMBER(void, CObjectSapper_ApplyRoboSapper, CTFPlayer *target, float duration, int radius)
+ {
+ if (cvar_duration.GetFloat() >= 0.0f) {
+ duration = cvar_duration.GetFloat();
+ }
+
+ if (cvar_radius.GetInt() >= 0) {
+ radius = cvar_radius.GetInt();
+ }
+
+ DETOUR_MEMBER_CALL(CObjectSapper_ApplyRoboSapper)(target, duration, radius);
+ }
+
+ RefCount rc_CObjectSapper_ApplyRoboSapperEffects;
+ DETOUR_DECL_MEMBER(bool, CObjectSapper_ApplyRoboSapperEffects, CTFPlayer *target, float duration)
+ {
+ SCOPED_INCREMENT(rc_CObjectSapper_ApplyRoboSapperEffects);
+ return DETOUR_MEMBER_CALL(CObjectSapper_ApplyRoboSapperEffects)(target, duration);
+ }
+
+ DETOUR_DECL_MEMBER(void, CTFPlayerShared_StunPlayer, float duration, float slowdown, int flags, CTFPlayer *attacker)
+ {
+ auto shared = reinterpret_cast(this);
+
+ if (rc_CObjectSapper_ApplyRoboSapperEffects > 0) {
+ CTFPlayer *player = shared->GetOuter();
+
+ if (cvar_stun_minibosses.GetBool() && player->IsMiniBoss()) {
+ flags = (TF_STUNFLAG_THIRDPERSON | TF_STUNFLAG_BONKSTUCK | TF_STUNFLAG_SLOWDOWN);
+ }
+
+ slowdown = cvar_stun_amount.GetFloat();
+ }
+
+ DETOUR_MEMBER_CALL(CTFPlayerShared_StunPlayer)(duration, slowdown, flags, attacker);
+ }
+
+
+ class CMod : public IMod
+ {
+ public:
+ CMod() : IMod("MvM:RoboSapper_Override")
+ {
+ MOD_ADD_DETOUR_MEMBER(CObjectSapper_ApplyRoboSapper, "CObjectSapper::ApplyRoboSapper");
+ MOD_ADD_DETOUR_MEMBER(CObjectSapper_ApplyRoboSapperEffects, "CObjectSapper::ApplyRoboSapperEffects");
+ MOD_ADD_DETOUR_MEMBER(CTFPlayerShared_StunPlayer, "CTFPlayerShared::StunPlayer");
+ }
+ };
+ CMod s_Mod;
+
+
+ ConVar cvar_enable("sig_mvm_robosapper_override", "0", FCVAR_NOTIFY,
+ "Mod: enable overriding aspects of the robo sapper in MvM mode",
+ [](IConVar *pConVar, const char *pOldValue, float flOldValue) {
+ ConVarRef var(pConVar);
+ s_Mod.Toggle(var.GetBool());
+ });
+}
diff --git a/src/mod/perf/medigun_shield_damage_interval.cpp b/src/mod/perf/medigun_shield_damage_interval.cpp
new file mode 100644
index 00000000..b03e5f3c
--- /dev/null
+++ b/src/mod/perf/medigun_shield_damage_interval.cpp
@@ -0,0 +1,56 @@
+#include "mod.h"
+#include "stub/tf_shareddefs.h"
+#include "stub/tfweaponbase.h"
+
+
+namespace Mod_Perf_Medigun_Shield_Damage_Interval
+{
+ DETOUR_DECL_MEMBER(int, CBaseEntity_TakeDamage, const CTakeDamageInfo& inputInfo)
+ {
+ auto ent = reinterpret_cast(this);
+
+ if (inputInfo.GetDamageCustom() == TF_DMG_CUSTOM_PLASMA) {
+ auto medigun = rtti_cast(inputInfo.GetWeapon());
+
+ if (medigun != nullptr) {
+ extern ConVar cvar_enable;
+ int interval = Max(cvar_enable.GetInt(), 1);
+
+ if (interval > 1) {
+ int victim_entindex = ENTINDEX(ent);
+
+ if ((victim_entindex % interval) == (gpGlobals->tickcount % interval)) {
+ CTakeDamageInfo newInfo = inputInfo;
+ newInfo.ScaleDamage(interval);
+
+ return DETOUR_MEMBER_CALL(CBaseEntity_TakeDamage)(newInfo);
+ } else {
+ return 0;
+ }
+ }
+ }
+ }
+
+
+ return DETOUR_MEMBER_CALL(CBaseEntity_TakeDamage)(inputInfo);
+ }
+
+
+ class CMod : public IMod
+ {
+ public:
+ CMod() : IMod("Perf:Medigun_Shield_Damage_Interval")
+ {
+ MOD_ADD_DETOUR_MEMBER(CBaseEntity_TakeDamage, "CBaseEntity::TakeDamage");
+ }
+ };
+ CMod s_Mod;
+
+
+ ConVar cvar_enable("sig_perf_medigun_shield_damage_interval", "0", FCVAR_NOTIFY,
+ "Mod: change the medigun shield damage interval to values greater than every single tick",
+ [](IConVar *pConVar, const char *pOldValue, float flOldValue) {
+ ConVarRef var(pConVar);
+ s_Mod.Toggle(var.GetBool());
+ });
+}
diff --git a/src/mod/pop/popmgr_extensions.cpp b/src/mod/pop/popmgr_extensions.cpp
index f2fb7c17..98701ef6 100644
--- a/src/mod/pop/popmgr_extensions.cpp
+++ b/src/mod/pop/popmgr_extensions.cpp
@@ -103,11 +103,14 @@ namespace Mod_Pop_PopMgr_Extensions
void Reset()
{
- this->m_bGiantsDropRareSpells = false;
- this->m_flSpellDropRateCommon = 1.00f;
- this->m_flSpellDropRateGiant = 1.00f;
- this->m_bNoReanimators = false;
- this->m_bNoMvMDeathTune = false;
+ this->m_bGiantsDropRareSpells = false;
+ this->m_flSpellDropRateCommon = 1.00f;
+ this->m_flSpellDropRateGiant = 1.00f;
+ this->m_bNoReanimators = false;
+ this->m_bNoMvMDeathTune = false;
+ this->m_bSniperHideLasers = false;
+ this->m_bSniperAllowHeadshots = false;
+ this->m_bDisableUpgradeStations = false;
this->m_MedievalMode.Reset();
this->m_SpellsEnabled.Reset();
@@ -126,6 +129,9 @@ namespace Mod_Pop_PopMgr_Extensions
float m_flSpellDropRateGiant;
bool m_bNoReanimators;
bool m_bNoMvMDeathTune;
+ bool m_bSniperHideLasers;
+ bool m_bSniperAllowHeadshots;
+ bool m_bDisableUpgradeStations;
CPopOverride_MedievalMode m_MedievalMode;
CPopOverride_ConVar m_SpellsEnabled;
@@ -224,6 +230,70 @@ namespace Mod_Pop_PopMgr_Extensions
DETOUR_MEMBER_CALL(CBaseEntity_EmitSound)(soundname, soundtime, duration);
}
+ DETOUR_DECL_MEMBER(void, CTFSniperRifle_CreateSniperDot)
+ {
+ auto rifle = reinterpret_cast(this);
+
+ if (state.m_bSniperHideLasers && TFGameRules()->IsMannVsMachineMode()) {
+ CTFPlayer *owner = rifle->GetTFPlayerOwner();
+ if (owner != nullptr && owner->GetTeamNumber() == TF_TEAM_BLUE) {
+ return;
+ }
+ }
+
+ DETOUR_MEMBER_CALL(CTFSniperRifle_CreateSniperDot)();
+ }
+
+ RefCount rc_CTFSniperRifle_CanFireCriticalShot;
+ DETOUR_DECL_MEMBER(bool, CTFSniperRifle_CanFireCriticalShot, bool bIsHeadshot)
+ {
+ SCOPED_INCREMENT(rc_CTFSniperRifle_CanFireCriticalShot);
+ return DETOUR_MEMBER_CALL(CTFSniperRifle_CanFireCriticalShot)(bIsHeadshot);
+ }
+
+ DETOUR_DECL_MEMBER(bool, CTFWeaponBase_CanFireCriticalShot, bool bIsHeadshot)
+ {
+ auto weapon = reinterpret_cast(this);
+
+ if (state.m_bSniperAllowHeadshots && rc_CTFSniperRifle_CanFireCriticalShot > 0 && TFGameRules()->IsMannVsMachineMode()) {
+ CTFPlayer *owner = weapon->GetTFPlayerOwner();
+ if (owner != nullptr && owner->GetTeamNumber() == TF_TEAM_BLUE) {
+ return true;
+ }
+ }
+
+ return DETOUR_MEMBER_CALL(CTFWeaponBase_CanFireCriticalShot)(bIsHeadshot);
+ }
+
+ RefCount rc_CTFProjectile_Arrow_StrikeTarget;
+ DETOUR_DECL_MEMBER(bool, CTFProjectile_Arrow_StrikeTarget, mstudiobbox_t *bbox, CBaseEntity *ent)
+ {
+ SCOPED_INCREMENT(rc_CTFProjectile_Arrow_StrikeTarget);
+ return DETOUR_MEMBER_CALL(CTFProjectile_Arrow_StrikeTarget)(bbox, ent);
+ }
+
+ DETOUR_DECL_MEMBER(bool, CTFGameRules_IsPVEModeControlled, CBaseEntity *ent)
+ {
+ if (state.m_bSniperAllowHeadshots && rc_CTFProjectile_Arrow_StrikeTarget > 0 && TFGameRules()->IsMannVsMachineMode()) {
+ return false;
+ }
+
+ return DETOUR_MEMBER_CALL(CTFGameRules_IsPVEModeControlled)(ent);
+ }
+
+ DETOUR_DECL_MEMBER(void, CUpgrades_UpgradeTouch, CBaseEntity *pOther)
+ {
+ if (state.m_bDisableUpgradeStations && TFGameRules()->IsMannVsMachineMode()) {
+ CTFPlayer *player = ToTFPlayer(pOther);
+ if (player != nullptr) {
+ gamehelpers->TextMsg(ENTINDEX(player), TEXTMSG_DEST_CENTER, "The Upgrade Station is disabled for this mission!");
+ return;
+ }
+ }
+
+ DETOUR_MEMBER_CALL(CUpgrades_UpgradeTouch)(pOther);
+ }
+
RefCount rc_CPopulationManager_Parse;
DETOUR_DECL_MEMBER(bool, CPopulationManager_Parse)
@@ -265,6 +335,12 @@ namespace Mod_Pop_PopMgr_Extensions
state.m_bNoReanimators = subkey->GetBool();
} else if (V_stricmp(name, "NoMvMDeathTune") == 0) {
state.m_bNoMvMDeathTune = subkey->GetBool();
+ } else if (V_stricmp(name, "SniperHideLasers") == 0) {
+ state.m_bSniperHideLasers = subkey->GetBool();
+ } else if (V_stricmp(name, "SniperAllowHeadshots") == 0) {
+ state.m_bSniperAllowHeadshots = subkey->GetBool();
+ } else if (V_stricmp(name, "DisableUpgradeStations") == 0) {
+ state.m_bDisableUpgradeStations = subkey->GetBool();
} else if (V_stricmp(name, "MedievalMode") == 0) {
state.m_MedievalMode.Set(subkey->GetBool());
} else if (V_stricmp(name, "GrapplingHook") == 0) {
@@ -317,6 +393,12 @@ namespace Mod_Pop_PopMgr_Extensions
MOD_ADD_DETOUR_MEMBER(CTFGameRules_IsUsingSpells, "CTFGameRules::IsUsingSpells");
MOD_ADD_DETOUR_STATIC(CTFReviveMarker_Create, "CTFReviveMarker::Create");
MOD_ADD_DETOUR_MEMBER(CBaseEntity_EmitSound, "CBaseEntity::EmitSound [const char *, float, float *]");
+ MOD_ADD_DETOUR_MEMBER(CTFSniperRifle_CreateSniperDot, "CTFSniperRifle::CreateSniperDot");
+ MOD_ADD_DETOUR_MEMBER(CTFSniperRifle_CanFireCriticalShot, "CTFSniperRifle::CanFireCriticalShot");
+ MOD_ADD_DETOUR_MEMBER(CTFWeaponBase_CanFireCriticalShot, "CTFWeaponBase::CanFireCriticalShot");
+ MOD_ADD_DETOUR_MEMBER(CTFProjectile_Arrow_StrikeTarget, "CTFProjectile_Arrow::StrikeTarget");
+ MOD_ADD_DETOUR_MEMBER(CTFGameRules_IsPVEModeControlled, "CTFGameRules::IsPVEModeControlled");
+ MOD_ADD_DETOUR_MEMBER(CUpgrades_UpgradeTouch, "CUpgrades::UpgradeTouch");
MOD_ADD_DETOUR_MEMBER(CPopulationManager_Parse, "CPopulationManager::Parse");
MOD_ADD_DETOUR_MEMBER(KeyValues_LoadFromFile, "KeyValues::LoadFromFile");
diff --git a/src/mod/pop/tank_extensions.cpp b/src/mod/pop/tank_extensions.cpp
index 22a35668..3e1c101c 100644
--- a/src/mod/pop/tank_extensions.cpp
+++ b/src/mod/pop/tank_extensions.cpp
@@ -11,12 +11,30 @@ namespace Mod_Pop_Tank_Extensions
{
bool disable_smokestack = false;
float scale = 1.00f;
+ bool force_romevision = false;
+
+ std::vector> tanks;
};
std::map spawners;
+ SpawnerData *FindSpawnerDataForTank(const CTFTankBoss *tank)
+ {
+ for (auto& pair : spawners) {
+ SpawnerData& data = pair.second;
+ for (auto h_tank : data.tanks) {
+ if (h_tank.Get() == tank) {
+ return &data;
+ }
+ }
+ }
+
+ return nullptr;
+ }
+
+
DETOUR_DECL_MEMBER(void, CTankSpawner_dtor0)
{
auto spawner = reinterpret_cast(this);
@@ -55,6 +73,9 @@ namespace Mod_Pop_Tank_Extensions
} else if (V_stricmp(name, "Scale") == 0) {
// DevMsg("Got \"Scale\" = %f\n", subkey->GetFloat());
spawners[spawner].scale = subkey->GetFloat();
+ } else if (V_stricmp(name, "ForceRomeVision") == 0) {
+ // DevMsg("Got \"ForceRomeVision\" = %d\n", subkey->GetBool());
+ spawners[spawner].force_romevision = subkey->GetBool();
} else {
del = false;
}
@@ -83,7 +104,7 @@ namespace Mod_Pop_Tank_Extensions
{
auto spawner = reinterpret_cast(this);
- // DevMsg("CTankSpawner::Spawn %08x\n", (uintptr_t)this);
+ DevMsg("CTankSpawner::Spawn %08x\n", (uintptr_t)this);
SCOPED_INCREMENT(rc_CTankSpawner_Spawn);
current_spawner = spawner;
@@ -100,6 +121,8 @@ namespace Mod_Pop_Tank_Extensions
auto tank = rtti_cast(ent);
if (tank != nullptr) {
+ data.tanks.push_back(tank);
+
if (data.scale != 1.00f) {
/* need to call this BEFORE changing the scale; otherwise,
* the collision bounding box will be very screwed up */
@@ -107,6 +130,49 @@ namespace Mod_Pop_Tank_Extensions
tank->SetModelScale(data.scale);
}
+
+ if (data.force_romevision) {
+ // DevMsg(" tank->m_iModelIndex: %d\n", (int)tank->m_iModelIndex);
+
+ // DevMsg(" s_TankModel[0]: \"%s\"\n", s_TankModel[0]);
+ // DevMsg(" s_TankModel[1]: \"%s\"\n", s_TankModel[1]);
+ // DevMsg(" s_TankModel[2]: \"%s\"\n", s_TankModel[2]);
+ // DevMsg(" s_TankModel[3]: \"%s\"\n", s_TankModel[3]);
+
+ // DevMsg(" s_TankModelRome[0]: \"%s\"\n", s_TankModelRome[0]);
+ // DevMsg(" s_TankModelRome[1]: \"%s\"\n", s_TankModelRome[1]);
+ // DevMsg(" s_TankModelRome[2]: \"%s\"\n", s_TankModelRome[2]);
+ // DevMsg(" s_TankModelRome[3]: \"%s\"\n", s_TankModelRome[3]);
+
+ // DevMsg(" modelinfo->GetModelIndex(s_TankModel[0]): %d\n", modelinfo->GetModelIndex(s_TankModel[0]));
+ // DevMsg(" modelinfo->GetModelIndex(s_TankModel[1]): %d\n", modelinfo->GetModelIndex(s_TankModel[1]));
+ // DevMsg(" modelinfo->GetModelIndex(s_TankModel[2]): %d\n", modelinfo->GetModelIndex(s_TankModel[2]));
+ // DevMsg(" modelinfo->GetModelIndex(s_TankModel[3]): %d\n", modelinfo->GetModelIndex(s_TankModel[3]));
+
+ // DevMsg(" modelinfo->GetModelIndex(s_TankModelRome[0]): %d\n", modelinfo->GetModelIndex(s_TankModelRome[0]));
+ // DevMsg(" modelinfo->GetModelIndex(s_TankModelRome[1]): %d\n", modelinfo->GetModelIndex(s_TankModelRome[1]));
+ // DevMsg(" modelinfo->GetModelIndex(s_TankModelRome[2]): %d\n", modelinfo->GetModelIndex(s_TankModelRome[2]));
+ // DevMsg(" modelinfo->GetModelIndex(s_TankModelRome[3]): %d\n", modelinfo->GetModelIndex(s_TankModelRome[3]));
+
+ // DevMsg(" [BEFORE] m_nModelIndexOverrides[0]: %d \"%s\"\n", tank->m_nModelIndexOverrides[0], modelinfo->GetModelName(modelinfo->GetModel(tank->m_nModelIndexOverrides[0])));
+ // DevMsg(" [BEFORE] m_nModelIndexOverrides[1]: %d \"%s\"\n", tank->m_nModelIndexOverrides[1], modelinfo->GetModelName(modelinfo->GetModel(tank->m_nModelIndexOverrides[1])));
+ // DevMsg(" [BEFORE] m_nModelIndexOverrides[2]: %d \"%s\"\n", tank->m_nModelIndexOverrides[2], modelinfo->GetModelName(modelinfo->GetModel(tank->m_nModelIndexOverrides[2])));
+ // DevMsg(" [BEFORE] m_nModelIndexOverrides[3]: %d \"%s\"\n", tank->m_nModelIndexOverrides[3], modelinfo->GetModelName(modelinfo->GetModel(tank->m_nModelIndexOverrides[3])));
+
+ tank->SetModelIndexOverride(0, modelinfo->GetModelIndex(s_TankModelRome[tank->m_iModelIndex]));
+
+ // DevMsg(" [AFTER] m_nModelIndexOverrides[0]: %d \"%s\"\n", tank->m_nModelIndexOverrides[0], modelinfo->GetModelName(modelinfo->GetModel(tank->m_nModelIndexOverrides[0])));
+ // DevMsg(" [AFTER] m_nModelIndexOverrides[1]: %d \"%s\"\n", tank->m_nModelIndexOverrides[1], modelinfo->GetModelName(modelinfo->GetModel(tank->m_nModelIndexOverrides[1])));
+ // DevMsg(" [AFTER] m_nModelIndexOverrides[2]: %d \"%s\"\n", tank->m_nModelIndexOverrides[2], modelinfo->GetModelName(modelinfo->GetModel(tank->m_nModelIndexOverrides[2])));
+ // DevMsg(" [AFTER] m_nModelIndexOverrides[3]: %d \"%s\"\n", tank->m_nModelIndexOverrides[3], modelinfo->GetModelName(modelinfo->GetModel(tank->m_nModelIndexOverrides[3])));
+
+ for (CBaseEntity *child = tank->FirstMoveChild(); child != nullptr; child = child->NextMovePeer()) {
+ // DevMsg(" child [classname \"%s\"] [model \"%s\"]\n", child->GetClassname(), STRING(child->GetModelName()));
+ if (!child->ClassMatches("prop_dynamic")) continue;
+
+ child->SetModelIndexOverride(0, child->m_nModelIndexOverrides[3]);
+ }
+ }
}
}
}
@@ -116,6 +182,57 @@ namespace Mod_Pop_Tank_Extensions
}
+ CTFTankBoss *thinking_tank = nullptr;
+ SpawnerData *thinking_tank_data = nullptr;
+
+ RefCount rc_CTFTankBoss_TankBossThink;
+ DETOUR_DECL_MEMBER(void, CTFTankBoss_TankBossThink)
+ {
+ auto tank = reinterpret_cast(this);
+
+ SpawnerData *data = FindSpawnerDataForTank(tank);
+ if (data != nullptr) {
+ thinking_tank = tank;
+ thinking_tank_data = data;
+ }
+
+ SCOPED_INCREMENT(rc_CTFTankBoss_TankBossThink);
+ DETOUR_MEMBER_CALL(CTFTankBoss_TankBossThink)();
+
+ thinking_tank = nullptr;
+ thinking_tank_data = nullptr;
+ }
+
+ DETOUR_DECL_MEMBER(void, CBaseEntity_SetModelIndexOverride, int index, int nValue)
+ {
+ auto ent = reinterpret_cast(this);
+
+ if (rc_CTFTankBoss_TankBossThink > 0 && thinking_tank != nullptr && thinking_tank_data != nullptr) {
+ CTFTankBoss *tank = thinking_tank;
+ SpawnerData *data = thinking_tank_data;
+
+ if (data->force_romevision) {
+ // DevMsg("SetModelIndexOverride(%d, %d) for ent #%d \"%s\" \"%s\"\n", index, nValue, ENTINDEX(ent), ent->GetClassname(), STRING(ent->GetModelName()));
+
+ if (ent == tank) {
+ if (index == 3) {
+ DETOUR_MEMBER_CALL(CBaseEntity_SetModelIndexOverride)(0, nValue);
+ DETOUR_MEMBER_CALL(CBaseEntity_SetModelIndexOverride)(3, nValue);
+ }
+ return;
+ }
+
+ // if (ent->GetMoveParent() == tank && ent->ClassMatches("prop_dynamic")) {
+ // DevMsg("Blocking SetModelIndexOverride(%d, %d) for tank %d prop %d \"%s\"\n", index, nValue, ENTINDEX(tank), ENTINDEX(ent), STRING(ent->GetModelName()));
+ // return;
+ // }
+ }
+ }
+
+ DETOUR_MEMBER_CALL(CBaseEntity_SetModelIndexOverride)(index, nValue);
+ }
+
+
DETOUR_DECL_MEMBER(int, CBaseAnimating_LookupAttachment, const char *szName)
{
if (rc_CTankSpawner_Spawn > 0 && current_spawner != nullptr &&
@@ -150,6 +267,9 @@ namespace Mod_Pop_Tank_Extensions
MOD_ADD_DETOUR_MEMBER(CTankSpawner_Spawn, "CTankSpawner::Spawn");
+ MOD_ADD_DETOUR_MEMBER(CTFTankBoss_TankBossThink, "CTFTankBoss::TankBossThink");
+ MOD_ADD_DETOUR_MEMBER(CBaseEntity_SetModelIndexOverride, "CBaseEntity::SetModelIndexOverride");
+
MOD_ADD_DETOUR_MEMBER(CBaseAnimating_LookupAttachment, "CBaseAnimating::LookupAttachment");
}
diff --git a/src/mod/pop/tfbot_extensions.cpp b/src/mod/pop/tfbot_extensions.cpp
index fe6c23fb..fe182207 100644
--- a/src/mod/pop/tfbot_extensions.cpp
+++ b/src/mod/pop/tfbot_extensions.cpp
@@ -90,11 +90,23 @@ namespace Mod_Pop_TFBot_Extensions
float delay = 0.0f;
};
+ enum ActionType
+ {
+ Action_Default,
+
+ // built-in
+ Action_FetchFlag,
+ Action_PushToCapturePoint,
+
+ // custom
+ Action_Mobber,
+ };
+
struct SpawnerData
{
std::vector addconds;
- bool action_mobber = false;
+ ActionType action = Action_Default;
bool use_human_model = false;
};
@@ -103,9 +115,9 @@ namespace Mod_Pop_TFBot_Extensions
std::map spawners;
- /* this is really dodgy... should probably do this with the ECAttr
- * extension system, provided we ever finish that contraption */
- std::vector> action_override_mobber;
+// /* this is really dodgy... should probably do this with the ECAttr
+// * extension system, provided we ever finish that contraption */
+// std::map, ActionType> pending_action_overrides;
struct DelayedAddCond
@@ -140,12 +152,49 @@ namespace Mod_Pop_TFBot_Extensions
}
+ /* for keeping track of which spawner each bot came from */
+ CTFBotSpawner *bot_spawner_tracker[33];
+ CTFBotSpawner *GetSpawnerOfBot(const CTFBot *bot)
+ {
+ int idx = ENTINDEX(bot);
+ if (idx == 0) return nullptr;
+
+ assert(idx > 0);
+ assert(idx < 33);
+ return bot_spawner_tracker[idx];
+ }
+ void SetSpawnerOfBot(const CTFBot *bot, CTFBotSpawner *spawner)
+ {
+ int idx = ENTINDEX(bot);
+ if (idx == 0) return;
+
+ assert(idx > 0);
+ assert(idx < 33);
+ bot_spawner_tracker[idx] = spawner;
+ }
+ void ClearTrackingForSpawner(CTFBotSpawner *spawner)
+ {
+ for (auto& elem : bot_spawner_tracker) {
+ if (elem == spawner) {
+ elem = nullptr;
+ }
+ }
+ }
+ void ClearAllTracking()
+ {
+ for (auto& elem : bot_spawner_tracker) {
+ elem = nullptr;
+ }
+ }
+
+
DETOUR_DECL_MEMBER(void, CTFBotSpawner_dtor0)
{
auto spawner = reinterpret_cast(this);
DevMsg("CTFBotSpawner %08x: dtor0\n", (uintptr_t)spawner);
spawners.erase(spawner);
+ ClearTrackingForSpawner(spawner);
DETOUR_MEMBER_CALL(CTFBotSpawner_dtor0)();
}
@@ -156,6 +205,7 @@ namespace Mod_Pop_TFBot_Extensions
DevMsg("CTFBotSpawner %08x: dtor2\n", (uintptr_t)spawner);
spawners.erase(spawner);
+ ClearTrackingForSpawner(spawner);
DETOUR_MEMBER_CALL(CTFBotSpawner_dtor2)();
}
@@ -207,8 +257,14 @@ namespace Mod_Pop_TFBot_Extensions
{
const char *value = kv->GetString();
- if (V_stricmp(value, "Mobber") == 0) {
- spawners[spawner].action_mobber = true;
+ if (V_stricmp(value, "Default") == 0) {
+ spawners[spawner].action = Action_Default;
+ } else if (V_stricmp(value, "FetchFlag") == 0) {
+ spawners[spawner].action = Action_FetchFlag;
+ } else if (V_stricmp(value, "PushToCapturePoint") == 0) {
+ spawners[spawner].action = Action_PushToCapturePoint;
+ } else if (V_stricmp(value, "Mobber") == 0) {
+ spawners[spawner].action = Action_Mobber;
} else {
Warning("Unknown value \'%s\' for TFBot Action.\n", value);
}
@@ -264,40 +320,53 @@ namespace Mod_Pop_TFBot_Extensions
auto result = DETOUR_MEMBER_CALL(CTFBotSpawner_Spawn)(where, ents);
- if (ents != nullptr) {
+ // DevMsg("\nCTFBotSpawner %08x: SPAWNED\n", (uintptr_t)spawner);
+ // DevMsg(" [classicon \"%s\"] [miniboss %d]\n", STRING(spawner->GetClassIcon(0)), spawner->IsMiniBoss(0));
+ // DevMsg("- result: %d\n", result);
+ // if (ents != nullptr) {
+ // DevMsg("- ents: ");
+ // FOR_EACH_VEC((*ents), i) {
+ // DevMsg(" #%d", ENTINDEX((*ents)[i]));
+ // }
+ // DevMsg("\n");
+ // }
+
+ if (result && ents != nullptr && !ents->IsEmpty()) {
auto it = spawners.find(spawner);
if (it != spawners.end()) {
SpawnerData& data = (*it).second;
- FOR_EACH_VEC((*ents), i) {
- CTFBot *bot = ToTFBot((*ents)[i]);
- if (bot != nullptr) {
- // DevMsg("CTFBotSpawner %08x: found %u AddCond's\n", (uintptr_t)spawner, data.addconds.size());
- for (auto addcond : data.addconds) {
- if (addcond.delay == 0.0f) {
- DevMsg("CTFBotSpawner %08x: applying AddCond(%d, %f)\n", (uintptr_t)spawner, addcond.cond, addcond.duration);
- bot->m_Shared->AddCond(addcond.cond, addcond.duration);
- } else {
- delayed_addconds.push_back({
- bot,
- gpGlobals->curtime + addcond.delay,
- addcond.cond,
- addcond.duration,
- });
- }
- }
-
- if (data.action_mobber) {
- action_override_mobber.push_back(bot);
+ CTFBot *bot = ToTFBot(ents->Tail());
+ if (bot != nullptr) {
+ SetSpawnerOfBot(bot, spawner);
+
+ // DevMsg("CTFBotSpawner %08x: found %u AddCond's\n", (uintptr_t)spawner, data.addconds.size());
+ for (auto addcond : data.addconds) {
+ if (addcond.delay == 0.0f) {
+ DevMsg("CTFBotSpawner %08x: applying AddCond(%d, %f)\n", (uintptr_t)spawner, addcond.cond, addcond.duration);
+ bot->m_Shared->AddCond(addcond.cond, addcond.duration);
+ } else {
+ delayed_addconds.push_back({
+ bot,
+ gpGlobals->curtime + addcond.delay,
+ addcond.cond,
+ addcond.duration,
+ });
}
+ }
+
+ // if (data.action != Action_Default) {
+ // pending_action_overrides.emplace(bot, data.action);
+ // }
+
+ if (data.use_human_model) {
+ DevMsg("CTFBotSpawner %08x: applying UseHumanModel on bot #%d\n", (uintptr_t)spawner, ENTINDEX(bot));
- if (data.use_human_model) {
- // calling SetCustomModel with a nullptr string *seems* to reset the model
- // dunno what the bool parameter should be; I think it doesn't matter for the nullptr case
- bot->GetPlayerClass()->SetCustomModel(nullptr, true);
- bot->UpdateModel();
- bot->SetBloodColor(BLOOD_COLOR_RED);
- }
+ // calling SetCustomModel with a nullptr string *seems* to reset the model
+ // dunno what the bool parameter should be; I think it doesn't matter for the nullptr case
+ bot->GetPlayerClass()->SetCustomModel(nullptr, true);
+ bot->UpdateModel();
+ bot->SetBloodColor(BLOOD_COLOR_RED);
}
}
}
@@ -309,18 +378,26 @@ namespace Mod_Pop_TFBot_Extensions
DETOUR_DECL_MEMBER(Action *, CTFBotScenarioMonitor_DesiredScenarioAndClassAction, CTFBot *actor)
{
- bool override_mobber = false;
+ ActionType action = Action_Default;
- for (auto it = action_override_mobber.begin(); it != action_override_mobber.end(); ) {
- if (*it == actor) {
- it = action_override_mobber.erase(it);
- override_mobber = true;
- } else {
- ++it;
+ CTFBotSpawner *spawner = GetSpawnerOfBot(actor);
+ if (spawner != nullptr) {
+ auto it = spawners.find(spawner);
+ if (it != spawners.end()) {
+ SpawnerData& data = (*it).second;
+ action = data.action;
}
}
- if (override_mobber) {
+ switch (action) {
+ case Action_FetchFlag:
+ DevMsg("CTFBotSpawner: setting initial action of bot #%d to FetchFlag\n", ENTINDEX(actor));
+ return CTFBotFetchFlag::New();
+ case Action_PushToCapturePoint:
+ DevMsg("CTFBotSpawner: setting initial action of bot #%d to PushToCapturePoint[-->FetchFlag]\n", ENTINDEX(actor));
+ return CTFBotPushToCapturePoint::New(CTFBotFetchFlag::New());
+ case Action_Mobber:
+ DevMsg("CTFBotSpawner: setting initial action of bot #%d to Mobber\n", ENTINDEX(actor));
return new CTFBotMobber();
}
@@ -328,6 +405,52 @@ namespace Mod_Pop_TFBot_Extensions
}
+ /* make engiebots that don't have any Action override always have Attributes
+ * IgnoreFlag, so that we can safely remove the special-case class check in
+ * CTFBot::GetFlagToFetch */
+ DETOUR_DECL_MEMBER(void, CTFBot_OnEventChangeAttributes, const CTFBot::EventChangeAttributes_t *ecattr)
+ {
+ auto bot = reinterpret_cast(this);
+
+ if (bot->IsPlayerClass(TF_CLASS_ENGINEER)) {
+ CTFBotSpawner *spawner = GetSpawnerOfBot(bot);
+ if (spawner != nullptr) {
+ auto it = spawners.find(spawner);
+ if (it != spawners.end()) {
+ SpawnerData& data = (*it).second;
+
+ if (data.action == Action_Default) {
+ DevMsg("CTFBot::OnEventChangeAttributes(engie #%d): adding Attributes IgnoreFlag\n", ENTINDEX(bot));
+ // const_cast(ecattr)->m_nBotAttrs |= CTFBot::ATTR_IGNORE_FLAG;
+ (int&)(ecattr->m_nBotAttrs) |= CTFBot::ATTR_IGNORE_FLAG;
+ } else {
+ DevMsg("CTFBot::OnEventChangeAttributes(engie #%d): not adding Attributes IgnoreFlag due to Action override\n", ENTINDEX(bot));
+ }
+ }
+ }
+ }
+
+ DETOUR_MEMBER_CALL(CTFBot_OnEventChangeAttributes)(ecattr);
+ }
+
+
+ RefCount rc_CTFBot_GetFlagToFetch;
+ DETOUR_DECL_MEMBER(CCaptureFlag *, CTFBot_GetFlagToFetch)
+ {
+ SCOPED_INCREMENT(rc_CTFBot_GetFlagToFetch);
+ return DETOUR_MEMBER_CALL(CTFBot_GetFlagToFetch)();
+ }
+
+ DETOUR_DECL_MEMBER(bool, CTFPlayer_IsPlayerClass, int iClass)
+ {
+ if (rc_CTFBot_GetFlagToFetch > 0 && iClass == TF_CLASS_ENGINEER) {
+ return false;
+ }
+
+ return DETOUR_MEMBER_CALL(CTFPlayer_IsPlayerClass)(iClass);
+ }
+
+
// // TEST! REMOVE ME!
// DETOUR_DECL_MEMBER(const char *, CTFPlayer_GetOverrideStepSound, const char *pszBaseStepSoundName)
// {
@@ -357,6 +480,11 @@ namespace Mod_Pop_TFBot_Extensions
MOD_ADD_DETOUR_MEMBER(CTFBotScenarioMonitor_DesiredScenarioAndClassAction, "CTFBotScenarioMonitor::DesiredScenarioAndClassAction");
+ MOD_ADD_DETOUR_MEMBER(CTFBot_OnEventChangeAttributes, "CTFBot::OnEventChangeAttributes");
+
+ MOD_ADD_DETOUR_MEMBER(CTFBot_GetFlagToFetch, "CTFBot::GetFlagToFetch");
+ MOD_ADD_DETOUR_MEMBER(CTFPlayer_IsPlayerClass, "CTFPlayer::IsPlayerClass");
+
// TEST! REMOVE ME!
// MOD_ADD_DETOUR_MEMBER(CTFPlayer_GetOverrideStepSound, "CTFPlayer::GetOverrideStepSound");
// MOD_ADD_DETOUR_MEMBER(CTFPlayer_GetSceneSoundToken, "CTFPlayer::GetSceneSoundToken");
@@ -365,11 +493,13 @@ namespace Mod_Pop_TFBot_Extensions
virtual void OnUnload() override
{
spawners.clear();
+ ClearAllTracking();
}
virtual void OnDisable() override
{
spawners.clear();
+ ClearAllTracking();
}
virtual bool ShouldReceiveFrameEvents() const override { return this->IsEnabled(); }
diff --git a/src/mod/pop/tfbot_extensions__disasm_patch_experiment.cpp b/src/mod/pop/tfbot_extensions__disasm_patch_experiment.cpp
new file mode 100644
index 00000000..02a3ff55
--- /dev/null
+++ b/src/mod/pop/tfbot_extensions__disasm_patch_experiment.cpp
@@ -0,0 +1,250 @@
+// class CPatch_CTFBot_GetFlagToFetch : public IPatch
+// {
+// public:
+// CPatch_CTFBot_GetFlagToFetch() {}
+//
+// virtual bool Verbose() const override { return false; }
+// virtual bool VerifyOnly() const override { return false; }
+//
+// virtual bool Init() override
+// {
+//
+// }
+// virtual bool Check() override
+// {
+//
+// }
+//
+// virtual void Apply() override
+// {
+//
+// }
+// virtual void UnApply() override
+// {
+//
+// }
+//
+// private:
+// Disassembler m_Disasm;
+//
+// void *m_pFuncAddr = nullptr;
+//
+//
+// };
+
+ class CPatch_CTFBot_GetFlagToFetch : public CPatch
+ {
+ public:
+ CPatch_CTFBot_GetFlagToFetch() : CPatch(s_Size), m_Buf(s_Size), m_Mask(s_Size) {}
+
+ virtual const char *GetFuncName() const override { return "CTFBot::GetFlagToFetch"; }
+
+ virtual uint32_t GetFuncOffMin() const override { return this->m_FuncOff; }
+ virtual uint32_t GetFuncOffMax() const override { return this->m_FuncOff; }
+
+ virtual bool GetVerifyInfo(ByteBuf& buf, ByteBuf& mask) const override
+ {
+ if (!this->m_bFound) return false;
+
+ // TODO
+ return false;
+ }
+
+ virtual bool GetPatchInfo(ByteBuf& buf, ByteBuf& mask) const override
+ {
+ if (!this->m_bFound) return false;
+
+ // TODO
+ return false;
+ }
+
+ private:
+ virtual bool PostInit() override
+ {
+ auto func_base = (uintptr_t)this->GetFuncAddr();
+
+ auto l_is_call_to_addr = [](const auto& insn, void *addr){
+ if (insn.ID() != X86_INS_CALL) return false;
+
+ auto operands = insn.Operands();
+ if (operands.size() != 1) return false;
+
+ auto op0 = operands[0];
+ if (op0.Type() != X86_OP_IMM || op0.Imm_U32() != (uintptr_t)addr) return false;
+
+ return true;
+ };
+
+ auto l_is_push_imm32_arg = [](const auto& insn, uint32_t esp_off, uint32_t imm_val){
+ if (insn.ID() != X86_INS_MOV) return false;
+
+ auto operands = insn.Operands();
+ if (operands.size() != 2) return false;
+
+ auto op0 = operands[0];
+ if (op0.Type() != X86_OP_MEM || op0.Size() != 4 || op0.Mem_Seg() != X86_REG_INVALID ||
+ op0.Mem_Base() != X86_REG_ESP || op0.Mem_Index() != X86_REG_INVALID || op0.Mem_Disp() != esp_off) return false;
+
+ auto op1 = operands[1];
+ if (op1.Type() != X86_OP_IMM || op1.Size() != 4 || op1.Imm_U32() != imm_val) return false;
+
+ return true;
+ };
+
+ auto l_is_test_al = [](const auto& insn){
+ if (insn.ID() != X86_INS_TEST) return false;
+
+ auto operands = insn.Operands();
+ if (operands.size() != 2) return false;
+
+ auto op0 = operands[0];
+ if (op0.Type() != X86_OP_REG || op0.Reg() != X86_REG_AL) return false;
+
+ auto op1 = operands[1];
+ if (op1.Type() != X86_OP_REG || op1.Reg() != X86_REG_AL) return false;
+
+ return true;
+ };
+
+ auto l_is_jcc_imm = [](const auto& insn){
+ switch (insn.ID()) {
+ case X86_INS_JAE:
+ case X86_INS_JA:
+ case X86_INS_JBE:
+ case X86_INS_JB:
+ case X86_INS_JE:
+ case X86_INS_JGE:
+ case X86_INS_JG:
+ case X86_INS_JLE:
+ case X86_INS_JL:
+ case X86_INS_JNE:
+ case X86_INS_JNO:
+ case X86_INS_JNP:
+ case X86_INS_JNS:
+ case X86_INS_JO:
+ case X86_INS_JP:
+ case X86_INS_JS:
+ break;
+ default:
+ return false;
+ }
+
+ auto operands = insn.Operands();
+ if (operands.size() != 1) return false;
+
+ auto op0 = operands[0];
+ if (op0.Type() != X86_OP_IMM) return false;
+
+ return true;
+ };
+
+ void *call_target = AddrManager::GetAddr("CTFPlayer::IsPlayerClass");
+ if (call_target == nullptr) return false;
+
+ Disassembler