summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorsalmonik <salmonik@tuta.io>2026-10-27 21:11:32 +0100
committersalmonik <salmonik@tuta.io>2026-10-27 21:11:32 +0100
commitc91c7248fcb3911a8a2b6442d8657167364a911c (patch)
treeca0b0304463c17bc93a67091522fef711f49b526 /src
parentBind labels: name unlisted scancodes instead of showing None (diff)
downloadhl2h-c91c7248fcb3911a8a2b6442d8657167364a911c.tar.gz
hl2h-c91c7248fcb3911a8a2b6442d8657167364a911c.zip
Stucklaunch: fix prop detection and add diagnostics
- Client physics props are CPhysicsProp/CPhysBox, not the server class prop_physics; the old case-sensitive class check never matched. Detect MOVETYPE_VPHYSICS first (the reliable signal), then case-insensitive class/model patterns. - Log the first few prop checks with index, movetype, class and model so a failed ground lookup is diagnosable. - Log once when Stucklaunch is active (with run state, bind and ground offset), when it engages, and when the ground is not a prop. - Toast a warning when binding a feature that is not Active yet.
Diffstat (limited to '')
-rw-r--r--src/esp.cpp46
-rw-r--r--src/gui.cpp7
-rw-r--r--src/hl2h.cpp29
-rw-r--r--src/hl2h.h2
4 files changed, 73 insertions, 11 deletions
diff --git a/src/esp.cpp b/src/esp.cpp
index bda6232..ca7bae0 100644
--- a/src/esp.cpp
+++ b/src/esp.cpp
@@ -2,6 +2,7 @@
2#include "hl2h.h" 2#include "hl2h.h"
3#include <cmath> 3#include <cmath>
4#include <cstring> 4#include <cstring>
5#include <strings.h>
5#include <cstddef> 6#include <cstddef>
6#include <cstdlib> 7#include <cstdlib>
7#include <ctime> 8#include <ctime>
@@ -1131,18 +1132,49 @@ static void spread_compute() {
1131 g_spread_ready = true; 1132 g_spread_ready = true;
1132} 1133}
1133 1134
1135static bool icontains(const char *hay, const char *needle) {
1136 if (!hay || !needle || !*needle)
1137 return false;
1138 size_t n = strlen(needle);
1139 for (const char *p = hay; *p; p++)
1140 if (strncasecmp(p, needle, n) == 0)
1141 return true;
1142 return false;
1143}
1144
1134bool entity_is_physics_prop(int idx) { 1145bool entity_is_physics_prop(int idx) {
1135 if (idx <= 0 || idx > 4096) 1146 if (idx <= 0 || idx > 4096)
1136 return false; 1147 return false;
1148 void *ent = entitylist_get(idx);
1149 if (!ent)
1150 return false;
1151 int mt = -1;
1152 // The reliable signal: physics objects use MOVETYPE_VPHYSICS. The client
1153 // class is CPhysicsProp / CPhysBox, not the server's prop_physics name.
1154 if (g_net.movetype >= 0) {
1155 mt = *(int *)((uintptr_t)ent + g_net.movetype);
1156 if (mt == MOVETYPE_VPHYSICS)
1157 return true;
1158 }
1137 void *net = entity_networkable(idx); 1159 void *net = entity_networkable(idx);
1138 const char *cls = net ? entity_class_name(net, nullptr) : nullptr; 1160 const char *cls = net ? entity_class_name(net, nullptr) : nullptr;
1139 void *ent = entitylist_get(idx); 1161 const char *model = entity_model_name(ent);
1140 const char *model = ent ? entity_model_name(ent) : nullptr; 1162 bool is_prop = icontains(cls, "physicsprop") || icontains(cls, "physbox") ||
1141 if (cls && (strstr(cls, "prop_physics") || strstr(cls, "physbox"))) 1163 icontains(cls, "prop_physics") ||
1142 return true; 1164 icontains(model, "props_junk") ||
1143 if (model && (strstr(model, "props_junk") || strstr(model, "props_physics"))) 1165 icontains(model, "props_physics") ||
1144 return true; 1166 icontains(model, "props_c17") ||
1145 return false; 1167 icontains(model, "props_interiors") ||
1168 icontains(model, "props_lab");
1169 if (!is_prop) {
1170 static int miss_logs = 0;
1171 if (miss_logs < 6) {
1172 miss_logs++;
1173 logf("stucklaunch prop? idx=%d movetype=%d cls=%s model=%s", idx, mt,
1174 cls ? cls : "?", model ? model : "?");
1175 }
1176 }
1177 return is_prop;
1146} 1178}
1147 1179
1148bool active_weapon_is_gravity_gun(void *local_ent) { 1180bool active_weapon_is_gravity_gun(void *local_ent) {
diff --git a/src/gui.cpp b/src/gui.cpp
index 9af8003..156e496 100644
--- a/src/gui.cpp
+++ b/src/gui.cpp
@@ -879,6 +879,8 @@ static void handle_capture(const unsigned char *keys) {
879 config_save(); 879 config_save();
880 toastf(TOAST_INFO, "%s bound to %s", card.title, 880 toastf(TOAST_INFO, "%s bound to %s", card.title,
881 scancode_name(card.feat->bind)); 881 scancode_name(card.feat->bind));
882 if (!card.feat->active)
883 toastf(TOAST_WARN, "%s is not Active yet", card.title);
882 return; 884 return;
883 } 885 }
884 for (int k = 0; k < 512; k++) { 886 for (int k = 0; k < 512; k++) {
@@ -890,9 +892,12 @@ static void handle_capture(const unsigned char *keys) {
890 card.feat->bind = k; 892 card.feat->bind = k;
891 g_capture_card = -1; 893 g_capture_card = -1;
892 config_save(); 894 config_save();
893 if (card.feat) 895 if (card.feat) {
894 toastf(TOAST_INFO, "%s bound to %s", card.title, 896 toastf(TOAST_INFO, "%s bound to %s", card.title,
895 scancode_name(card.feat->bind)); 897 scancode_name(card.feat->bind));
898 if (!card.feat->active)
899 toastf(TOAST_WARN, "%s is not Active yet", card.title);
900 }
896 return; 901 return;
897 } 902 }
898} 903}
diff --git a/src/hl2h.cpp b/src/hl2h.cpp
index 84de815..defdd27 100644
--- a/src/hl2h.cpp
+++ b/src/hl2h.cpp
@@ -172,8 +172,14 @@ static void apply_autostrafe(CUserCmd *cmd, const float *vel) {
172// True while the player stands on (or just left) a physics prop. m_hGroundEntity 172// True while the player stands on (or just left) a physics prop. m_hGroundEntity
173// is latched briefly because it clears during each hop. 173// is latched briefly because it clears during each hop.
174static bool stucklaunch_prop_ok(void *ent, int tick) { 174static bool stucklaunch_prop_ok(void *ent, int tick) {
175 if (g_net.groundentity < 0) 175 if (g_net.groundentity < 0) {
176 static bool logged = false;
177 if (!logged) {
178 logged = true;
179 logf("stucklaunch: m_hGroundEntity unavailable; prop detection off");
180 }
176 return true; // no netvar: the bind is the only safeguard 181 return true; // no netvar: the bind is the only safeguard
182 }
177 static int last_prop_tick = -100000; 183 static int last_prop_tick = -100000;
178 uint32_t h = *(uint32_t *)((uintptr_t)ent + g_net.groundentity); 184 uint32_t h = *(uint32_t *)((uintptr_t)ent + g_net.groundentity);
179 int gi = (h == 0xFFFFFFFFu) ? 0 : (int)(h & 0xFFFF); 185 int gi = (h == 0xFFFFFFFFu) ? 0 : (int)(h & 0xFFFF);
@@ -182,9 +188,15 @@ static bool stucklaunch_prop_ok(void *ent, int tick) {
182 static int prop_logs = 0; 188 static int prop_logs = 0;
183 if (prop_logs < 4) { 189 if (prop_logs < 4) {
184 prop_logs++; 190 prop_logs++;
185 logf("stucklaunch: prop idx=%d", gi); 191 logf("stucklaunch: prop idx=%d engaged", gi);
186 } 192 }
187 last_prop_tick = tick; 193 last_prop_tick = tick;
194 } else {
195 static int miss_logs = 0;
196 if (miss_logs < 4) {
197 miss_logs++;
198 logf("stucklaunch: ground h=%#x idx=%d is not a physics prop", h, gi);
199 }
188 } 200 }
189 return tick - last_prop_tick < 32; // ~0.5 s at 66 tick 201 return tick - last_prop_tick < 32; // ~0.5 s at 66 tick
190} 202}
@@ -194,6 +206,11 @@ static bool stucklaunch_prop_ok(void *ent, int tick) {
194// gun's +attack) to keep regrabbing the prop, and air-strafes the hops. 206// gun's +attack) to keep regrabbing the prop, and air-strafes the hops.
195static void stucklaunch_apply(CUserCmd *cmd, void *local_ent, bool onground, 207static void stucklaunch_apply(CUserCmd *cmd, void *local_ent, bool onground,
196 const float *vel) { 208 const float *vel) {
209 static bool engaged_logged = false;
210 if (!engaged_logged) {
211 engaged_logged = true;
212 logf("stucklaunch: applying jump/spam (onground=%d)", (int)onground);
213 }
197 cmd->buttons |= IN_JUMP; 214 cmd->buttons |= IN_JUMP;
198 int period = stucklaunch_spam_ticks(); 215 int period = stucklaunch_spam_ticks();
199 if (period < 1) 216 if (period < 1)
@@ -629,6 +646,14 @@ static void do_move(int seq, float frametime) {
629 } 646 }
630 647
631 bool stuck_on = feature_active(FEAT_STUCKLAUNCH); 648 bool stuck_on = feature_active(FEAT_STUCKLAUNCH);
649 if (g_stucklaunch.active) {
650 static bool state_logged = false;
651 if (!state_logged) {
652 state_logged = true;
653 logf("stucklaunch: active=1 run=%d bind=%d groundoff=%d",
654 (int)stuck_on, g_stucklaunch.bind, g_net.groundentity);
655 }
656 }
632 bool stuck_engaged = stuck_on && stucklaunch_prop_ok(ent, cmd->tick_count); 657 bool stuck_engaged = stuck_on && stucklaunch_prop_ok(ent, cmd->tick_count);
633 if (stuck_engaged) { 658 if (stuck_engaged) {
634 stucklaunch_apply(cmd, ent, onground, vel); 659 stucklaunch_apply(cmd, ent, onground, vel);
diff --git a/src/hl2h.h b/src/hl2h.h
index 2607ece..d6729cb 100644
--- a/src/hl2h.h
+++ b/src/hl2h.h
@@ -141,7 +141,7 @@ struct CUserCmd {
141 141
142enum { IN_ATTACK = 1 << 0, IN_JUMP = 1 << 1, IN_DUCK = 1 << 2, IN_USE = 1 << 5, IN_ATTACK2 = 1 << 11, IN_SPEED = 1 << 17 }; 142enum { IN_ATTACK = 1 << 0, IN_JUMP = 1 << 1, IN_DUCK = 1 << 2, IN_USE = 1 << 5, IN_ATTACK2 = 1 << 11, IN_SPEED = 1 << 17 };
143enum { FL_ONGROUND = 1 << 0, FL_DUCKING = 1 << 1, FL_INWATER = 1 << 9 }; 143enum { FL_ONGROUND = 1 << 0, FL_DUCKING = 1 << 1, FL_INWATER = 1 << 9 };
144enum { MOVETYPE_WALK = 2, MOVETYPE_NOCLIP = 8, MOVETYPE_LADDER = 9 }; 144enum { MOVETYPE_WALK = 2, MOVETYPE_VPHYSICS = 6, MOVETYPE_NOCLIP = 8, MOVETYPE_LADDER = 9 };
145 145
146// --------------------------------------------------------------------------- 146// ---------------------------------------------------------------------------
147// vector math 147// vector math