diff options
Diffstat (limited to '')
| -rw-r--r-- | src/esp.cpp | 136 |
1 files changed, 136 insertions, 0 deletions
diff --git a/src/esp.cpp b/src/esp.cpp index 47df57d..0117d27 100644 --- a/src/esp.cpp +++ b/src/esp.cpp | |||
| @@ -1042,6 +1042,142 @@ bool melee_aimbot_apply(CUserCmd *cmd) { | |||
| 1042 | return false; | 1042 | return false; |
| 1043 | } | 1043 | } |
| 1044 | 1044 | ||
| 1045 | // --------------------------------------------------------------------------- | ||
| 1046 | // weapon spread control | ||
| 1047 | // --------------------------------------------------------------------------- | ||
| 1048 | // | ||
| 1049 | // HL2's CBaseEntity::FireBullets uses CBaseEntity::GetPredictionRandomSeed() | ||
| 1050 | // (the client usercmd's random_seed) unless a weapon opts into | ||
| 1051 | // m_bUseServerRandomSeed. HL2 weapons do not, so the client can choose the | ||
| 1052 | // 8-bit seed and with it the random cone offset. CShotManipulator::ApplySpread | ||
| 1053 | // draws four uniform floats per attempt; we precompute the best seed for one | ||
| 1054 | // shot and for the shotgun's pellet windows with the engine's own RNG. | ||
| 1055 | |||
| 1056 | static bool g_spread_ready = false; | ||
| 1057 | static int g_spread_seed1 = 0; | ||
| 1058 | static int g_spread_seed8 = 0; // first pellet exact, 7 spread | ||
| 1059 | static int g_spread_seed12 = 0; // all 12 spread | ||
| 1060 | |||
| 1061 | static void spread_compute() { | ||
| 1062 | using SeedFn = void (*)(int); | ||
| 1063 | using FloatFn = float (*)(float, float); | ||
| 1064 | SeedFn seed = (SeedFn)dlsym(RTLD_DEFAULT, "RandomSeed"); | ||
| 1065 | FloatFn rf = (FloatFn)dlsym(RTLD_DEFAULT, "RandomFloat"); | ||
| 1066 | if (!seed || !rf) { | ||
| 1067 | size_t slash = g_engine.path.find_last_of('/'); | ||
| 1068 | if (slash != std::string::npos) { | ||
| 1069 | std::string path = g_engine.path.substr(0, slash + 1) + "libvstdlib.so"; | ||
| 1070 | void *h = dlopen(path.c_str(), RTLD_NOLOAD | RTLD_LAZY | RTLD_GLOBAL); | ||
| 1071 | if (!h) | ||
| 1072 | h = dlopen(path.c_str(), RTLD_LAZY | RTLD_GLOBAL); | ||
| 1073 | if (h) { | ||
| 1074 | seed = (SeedFn)dlsym(h, "RandomSeed"); | ||
| 1075 | rf = (FloatFn)dlsym(h, "RandomFloat"); | ||
| 1076 | } | ||
| 1077 | } | ||
| 1078 | } | ||
| 1079 | if (!seed || !rf) { | ||
| 1080 | logf("spread: RandomSeed/RandomFloat unavailable"); | ||
| 1081 | return; | ||
| 1082 | } | ||
| 1083 | |||
| 1084 | auto draw = [&](int s, float &x, float &y) { | ||
| 1085 | seed(s); | ||
| 1086 | int it = 0; | ||
| 1087 | do { | ||
| 1088 | // CShotManipulator::ApplySpread with the default bias of 1.0: | ||
| 1089 | // shotBias = 1.0, flatness = 0.5. | ||
| 1090 | x = rf(-1.0f, 1.0f) * 0.5f + rf(-1.0f, 1.0f) * 0.5f; | ||
| 1091 | y = rf(-1.0f, 1.0f) * 0.5f + rf(-1.0f, 1.0f) * 0.5f; | ||
| 1092 | it++; | ||
| 1093 | } while (x * x + y * y > 1.0f && it < 64); | ||
| 1094 | }; | ||
| 1095 | |||
| 1096 | float best1 = 1e9f; | ||
| 1097 | for (int s = 0; s < 256; s++) { | ||
| 1098 | float x, y; | ||
| 1099 | draw(s, x, y); | ||
| 1100 | float r2 = x * x + y * y; | ||
| 1101 | if (r2 < best1) { | ||
| 1102 | best1 = r2; | ||
| 1103 | g_spread_seed1 = s; | ||
| 1104 | } | ||
| 1105 | } | ||
| 1106 | |||
| 1107 | auto window = [&](int n, int first) { | ||
| 1108 | int best_s = 0; | ||
| 1109 | float best = 1e9f; | ||
| 1110 | for (int s = 0; s < 256; s++) { | ||
| 1111 | float score = 0.0f; | ||
| 1112 | for (int i = first; i < n; i++) { | ||
| 1113 | float x, y; | ||
| 1114 | draw(s + i, x, y); | ||
| 1115 | score += x * x + y * y; | ||
| 1116 | } | ||
| 1117 | if (score < best) { | ||
| 1118 | best = score; | ||
| 1119 | best_s = s; | ||
| 1120 | } | ||
| 1121 | } | ||
| 1122 | return best_s; | ||
| 1123 | }; | ||
| 1124 | g_spread_seed8 = window(8, 1); | ||
| 1125 | g_spread_seed12 = window(12, 0); | ||
| 1126 | seed(0); | ||
| 1127 | |||
| 1128 | logf("spread: seeds single=%d shotgun8=%d shotgun12=%d", g_spread_seed1, | ||
| 1129 | g_spread_seed8, g_spread_seed12); | ||
| 1130 | g_spread_ready = true; | ||
| 1131 | } | ||
| 1132 | |||
| 1133 | static bool active_weapon_is_shotgun(void *local_ent) { | ||
| 1134 | if (!local_ent || g_net.activeweapon < 0) | ||
| 1135 | return false; | ||
| 1136 | uint32_t h = *(uint32_t *)((uintptr_t)local_ent + g_net.activeweapon); | ||
| 1137 | if (h == 0xFFFFFFFFu) | ||
| 1138 | return false; | ||
| 1139 | int idx = (int)(h & 0xFFFF); | ||
| 1140 | if (idx <= 0 || idx > 4096) | ||
| 1141 | return false; | ||
| 1142 | void *wep = entitylist_get(idx); | ||
| 1143 | void *net = entity_networkable(idx); | ||
| 1144 | const char *cls = net ? entity_class_name(net, nullptr) : nullptr; | ||
| 1145 | const char *model = wep ? entity_model_name(wep) : nullptr; | ||
| 1146 | return (cls && strstr(cls, "Shotgun")) || | ||
| 1147 | (model && strstr(model, "shotgun")); | ||
| 1148 | } | ||
| 1149 | |||
| 1150 | bool spread_control_apply(CUserCmd *cmd, void *local_ent) { | ||
| 1151 | if (!feature_active(FEAT_SPREAD) || !spread_no_spread_enabled()) | ||
| 1152 | return false; | ||
| 1153 | if (!(cmd->buttons & (IN_ATTACK | IN_ATTACK2))) | ||
| 1154 | return false; | ||
| 1155 | if (!g_spread_ready) { | ||
| 1156 | static bool tried = false; | ||
| 1157 | if (!tried) { | ||
| 1158 | tried = true; | ||
| 1159 | spread_compute(); | ||
| 1160 | } | ||
| 1161 | } | ||
| 1162 | if (!g_spread_ready) | ||
| 1163 | return false; | ||
| 1164 | |||
| 1165 | bool shotgun = active_weapon_is_shotgun(local_ent); | ||
| 1166 | int seed = g_spread_seed1; | ||
| 1167 | if (shotgun) | ||
| 1168 | seed = (cmd->buttons & IN_ATTACK2) ? g_spread_seed12 : g_spread_seed8; | ||
| 1169 | if (cmd->random_seed == seed) | ||
| 1170 | return false; | ||
| 1171 | cmd->random_seed = seed; | ||
| 1172 | |||
| 1173 | static int logs = 0; | ||
| 1174 | if (logs < 10) { | ||
| 1175 | logs++; | ||
| 1176 | logf("spread: seed=%d (%s)", seed, shotgun ? "shotgun" : "single"); | ||
| 1177 | } | ||
| 1178 | return true; | ||
| 1179 | } | ||
| 1180 | |||
| 1045 | bool triggerbot_apply(CUserCmd *cmd) { | 1181 | bool triggerbot_apply(CUserCmd *cmd) { |
| 1046 | if (!g_iface.enginetrace || !g_iface.entitylist) | 1182 | if (!g_iface.enginetrace || !g_iface.entitylist) |
| 1047 | return false; | 1183 | return false; |
