summaryrefslogtreecommitdiffstats
path: root/src/config_table.cpp
diff options
context:
space:
mode:
authorsalmonik <salmonik@tuta.io>2026-11-06 16:30:10 +0100
committersalmonik <salmonik@tuta.io>2026-11-06 16:30:10 +0100
commite339d1dc45b3113648552b0002e0c15f55e61cb2 (patch)
tree4570dc0ba1501ea26e87447d234693ad5532e813 /src/config_table.cpp
parentdocs: record the esp.cpp split in the plan (diff)
downloadhl2h-e339d1dc45b3113648552b0002e0c15f55e61cb2.tar.gz
hl2h-e339d1dc45b3113648552b0002e0c15f55e61cb2.zip
Config: generate save/load/reset from one settings table
Every persisted setting now lives in a single descriptor table (config_table.cpp) with its section, key, type, default and clamp range. config_save(), config_load() and config_reset_defaults() iterate it, so the three functions can no longer disagree about defaults or bounds, and the old hand-written 350-line parser is gone. Section and key names are unchanged, so existing config files keep loading, and the duplicated [view] scalar clamp block is replaced by per-entry limits.
Diffstat (limited to '')
-rw-r--r--src/config_table.cpp230
1 files changed, 230 insertions, 0 deletions
diff --git a/src/config_table.cpp b/src/config_table.cpp
new file mode 100644
index 0000000..f688d12
--- /dev/null
+++ b/src/config_table.cpp
@@ -0,0 +1,230 @@
1// config_table.cpp — every persisted setting in one descriptor table.
2//
3// config_save(), config_load() and config_reset_defaults() are generated from
4// this table, so adding an option no longer means editing three functions (and
5// getting the clamp bounds out of sync between them).
6#include "hl2h.h"
7
8#include <cstdlib>
9
10namespace {
11
12enum SettingType { S_BOOL, S_INT };
13
14struct SettingDesc {
15 const char *section;
16 const char *key;
17 SettingType type;
18 void *ptr;
19 int def;
20 int lo;
21 int hi;
22};
23
24// A FeatureState is persisted as the usual active/bind pair.
25#define FEAT(sec, state, def_active, def_bind) \
26 {sec, "active", S_BOOL, &(state).active, def_active, 0, 1}, \
27 {sec, "bind", S_INT, &(state).bind, def_bind, 0, 1000}
28
29const SettingDesc kSettings[] = {
30 // movement
31 FEAT("bhop", g_bhop, 1, 0),
32 {"bhop", "autostrafe", S_BOOL, &g_bhop_autostrafe, 1, 0, 1},
33 FEAT("abh", g_abh, 1, 0),
34 FEAT("jumpbug", g_jumpbug, 1, 0),
35 {"jumpbug", "assist", S_BOOL, &g_jumpbug_assist, 0, 0, 1},
36 FEAT("melee", g_melee, 1, 0),
37 {"movement", "crouchjump", S_BOOL, &g_auto_crouchjump, 0, 0, 1},
38 {"movement", "edgejump", S_BOOL, &g_edge_jump, 0, 0, 1},
39
40 // spread
41 FEAT("spread", g_spread, 1, 0),
42 {"spread", "no_spread", S_BOOL, &g_spread_no_spread, 1, 0, 1},
43 {"spread", "engine", S_BOOL, &g_spread_engine, 1, 0, 1},
44
45 // aim
46 FEAT("aimbot", g_aimbot, 1, 604),
47 {"aimbot", "smooth", S_INT, &g_aim_smooth, 5, 1, 45},
48 {"aimbot", "vischeck", S_BOOL, &g_aim_vischeck, 1, 0, 1},
49 {"aimbot", "fov", S_INT, &g_aim_fov, 60, 1, 180},
50 {"aimbot", "fov_circle", S_BOOL, &g_aim_fov_circle, 1, 0, 1},
51 {"aimbot", "punch", S_BOOL, &g_aim_punch, 1, 0, 1},
52 {"aimbot", "bone_head", S_BOOL, &g_aim_bones[AIM_BONE_HEAD], 1, 0, 1},
53 {"aimbot", "bone_torso", S_BOOL, &g_aim_bones[AIM_BONE_TORSO], 0, 0, 1},
54 {"aimbot", "bone_larm", S_BOOL, &g_aim_bones[AIM_BONE_LARM], 0, 0, 1},
55 {"aimbot", "bone_rarm", S_BOOL, &g_aim_bones[AIM_BONE_RARM], 0, 0, 1},
56 {"aimbot", "bone_lleg", S_BOOL, &g_aim_bones[AIM_BONE_LLEG], 0, 0, 1},
57 {"aimbot", "bone_rleg", S_BOOL, &g_aim_bones[AIM_BONE_RLEG], 0, 0, 1},
58 FEAT("triggerbot", g_triggerbot, 1, 603),
59 FEAT("silentaim", g_silentaim, 1, 602),
60
61 // view
62 {"view", "fov", S_INT, &g_fov_camera, 75, 40, 140},
63 {"view", "vmfov", S_INT, &g_fov_viewmodel, 54, 20, 120},
64 {"view", "tonemap", S_INT, &g_tonemap, 0, 0, 30},
65
66 // esp
67 FEAT("esp", g_esp, 1, 0),
68 {"esp", "neutral", S_BOOL, &g_esp_opt[ESP_OPT_SHOW_NEUTRAL], 1, 0, 1},
69 {"esp", "healthbar", S_BOOL, &g_esp_opt[ESP_OPT_SHOW_HEALTHBAR], 1, 0, 1},
70 {"esp", "healthnum", S_BOOL, &g_esp_opt[ESP_OPT_SHOW_HEALTHNUM], 1, 0, 1},
71 {"esp", "name", S_BOOL, &g_esp_opt[ESP_OPT_SHOW_NAME], 1, 0, 1},
72 {"esp", "skeleton", S_BOOL, &g_esp_opt[ESP_OPT_SHOW_SKELETON], 1, 0, 1},
73 {"esp", "box", S_BOOL, &g_esp_opt[ESP_OPT_SHOW_BOX], 1, 0, 1},
74 {"esp", "speedgraph", S_BOOL, &g_esp_opt[ESP_OPT_SHOW_SPEEDGRAPH], 1, 0, 1},
75 {"esp", "dmg", S_BOOL, &g_esp_opt[ESP_OPT_DAMAGE_TAGS], 1, 0, 1},
76 {"esp", "alert", S_BOOL, &g_esp_opt[ESP_OPT_ALERT], 1, 0, 1},
77 {"esp", "weapon", S_BOOL, &g_esp_opt[ESP_OPT_WEAPON], 1, 0, 1},
78 {"esp", "arrows", S_BOOL, &g_esp_opt[ESP_OPT_ARROWS], 1, 0, 1},
79 {"esp", "hr", S_INT, &g_esp_col_hostile[0], 255, 0, 255},
80 {"esp", "hg", S_INT, &g_esp_col_hostile[1], 60, 0, 255},
81 {"esp", "hb", S_INT, &g_esp_col_hostile[2], 60, 0, 255},
82 {"esp", "nr", S_INT, &g_esp_col_neutral[0], 220, 0, 255},
83 {"esp", "ng", S_INT, &g_esp_col_neutral[1], 220, 0, 255},
84 {"esp", "nb", S_INT, &g_esp_col_neutral[2], 220, 0, 255},
85 {"esp", "fr", S_INT, &g_esp_col_friendly[0], 60, 0, 255},
86 {"esp", "fg", S_INT, &g_esp_col_friendly[1], 255, 0, 255},
87 {"esp", "fb", S_INT, &g_esp_col_friendly[2], 60, 0, 255},
88
89 // items
90 FEAT("items", g_item_esp, 1, 0),
91 {"items", "health", S_BOOL, &g_item_health, 1, 0, 1},
92 {"items", "ammo", S_BOOL, &g_item_ammo, 1, 0, 1},
93 {"items", "armor", S_BOOL, &g_item_armor, 1, 0, 1},
94 {"items", "weapons", S_BOOL, &g_item_weapons, 1, 0, 1},
95 {"items", "crates", S_BOOL, &g_item_crates, 1, 0, 1},
96 {"items", "distance", S_BOOL, &g_item_distance, 1, 0, 1},
97 {"items", "usable", S_BOOL, &g_item_usable, 1, 0, 1},
98 {"items", "max_dist", S_INT, &g_item_max_dist, 5000, 0, 10000},
99
100 // projectiles
101 FEAT("projectiles", g_projectiles, 1, 0),
102 {"projectiles", "fuse", S_BOOL, &g_proj_fuse, 1, 0, 1},
103 {"projectiles", "radius", S_BOOL, &g_proj_radius, 1, 0, 1},
104 {"projectiles", "trajectory", S_BOOL, &g_proj_traj, 1, 0, 1},
105
106 // chams
107 FEAT("chams", g_chams, 0, 0),
108#define CHAMS_GROUP(sec, grp, von, vr, vg, vb, ion, ir, ig, ib) \
109 {sec, "vis", S_BOOL, &(grp).vis_on, von, 0, 1}, \
110 {sec, "vis_mat", S_INT, &(grp).vis_mat, 3, 0, 6}, \
111 {sec, "vis_r", S_INT, &(grp).vis_rgb[0], vr, 0, 255}, \
112 {sec, "vis_g", S_INT, &(grp).vis_rgb[1], vg, 0, 255}, \
113 {sec, "vis_b", S_INT, &(grp).vis_rgb[2], vb, 0, 255}, \
114 {sec, "vis_a", S_INT, &(grp).vis_rgb[3], 255, 0, 255}, \
115 {sec, "inv", S_BOOL, &(grp).inv_on, ion, 0, 1}, \
116 {sec, "inv_mat", S_INT, &(grp).inv_mat, 3, 0, 6}, \
117 {sec, "inv_r", S_INT, &(grp).inv_rgb[0], ir, 0, 255}, \
118 {sec, "inv_g", S_INT, &(grp).inv_rgb[1], ig, 0, 255}, \
119 {sec, "inv_b", S_INT, &(grp).inv_rgb[2], ib, 0, 255}, \
120 {sec, "inv_a", S_INT, &(grp).inv_rgb[3], 255, 0, 255}
121 CHAMS_GROUP("chams_hostile", g_chams_hostile, 1, 255, 60, 60, 1, 255, 60,
122 60),
123 CHAMS_GROUP("chams_neutral", g_chams_neutral, 1, 220, 220, 220, 0, 220, 220,
124 220),
125 CHAMS_GROUP("chams_friendly", g_chams_friendly, 1, 60, 255, 60, 0, 60, 255,
126 60),
127#undef CHAMS_GROUP
128 {"chams_vm", "on", S_BOOL, &g_chams_viewmodel, 0, 0, 1},
129 {"chams_vm", "mat", S_INT, &g_chams_vm_mat, 3, 0, 6},
130 {"chams_vm", "r", S_INT, &g_chams_vm_rgb[0], 200, 0, 255},
131 {"chams_vm", "g", S_INT, &g_chams_vm_rgb[1], 200, 0, 255},
132 {"chams_vm", "b", S_INT, &g_chams_vm_rgb[2], 255, 0, 255},
133 {"chams_vm", "a", S_INT, &g_chams_vm_rgb[3], 255, 0, 255},
134
135 // visuals
136 FEAT("fullbright", g_fullbright, 0, 0),
137 FEAT("worldtint", g_world_tint, 0, 0),
138 {"worldtint", "world", S_BOOL, &g_tint_world_on, 1, 0, 1},
139 {"worldtint", "sky", S_BOOL, &g_tint_sky_on, 1, 0, 1},
140 {"worldtint", "prop", S_BOOL, &g_tint_prop_on, 1, 0, 1},
141 {"worldtint", "wr", S_INT, &g_tint_world_rgb[0], 255, 0, 255},
142 {"worldtint", "wg", S_INT, &g_tint_world_rgb[1], 255, 0, 255},
143 {"worldtint", "wb", S_INT, &g_tint_world_rgb[2], 255, 0, 255},
144 {"worldtint", "sr", S_INT, &g_tint_sky_rgb[0], 255, 0, 255},
145 {"worldtint", "sg", S_INT, &g_tint_sky_rgb[1], 255, 0, 255},
146 {"worldtint", "sb", S_INT, &g_tint_sky_rgb[2], 255, 0, 255},
147 {"worldtint", "pr", S_INT, &g_tint_prop_rgb[0], 255, 0, 255},
148 {"worldtint", "pg", S_INT, &g_tint_prop_rgb[1], 255, 0, 255},
149 {"worldtint", "pb", S_INT, &g_tint_prop_rgb[2], 255, 0, 255},
150 FEAT("fog", g_fog, 0, 0),
151 {"fog", "r", S_INT, &g_fog_rgb[0], 160, 0, 255},
152 {"fog", "g", S_INT, &g_fog_rgb[1], 170, 0, 255},
153 {"fog", "b", S_INT, &g_fog_rgb[2], 190, 0, 255},
154 {"fog", "start", S_INT, &g_fog_start, 200, 0, 8000},
155 {"fog", "end", S_INT, &g_fog_end, 3000, 0, 20000},
156 {"fog", "skybox", S_BOOL, &g_fog_skybox, 1, 0, 1},
157 {"fog", "disable", S_BOOL, &g_fog_disable, 0, 0, 1},
158 FEAT("skybox", g_skybox, 0, 0),
159};
160
161constexpr int kSettingCount = (int)(sizeof(kSettings) / sizeof(kSettings[0]));
162
163const SettingDesc *find_setting(const char *section, const char *key) {
164 for (int i = 0; i < kSettingCount; i++) {
165 if (strcmp(kSettings[i].section, section) == 0 &&
166 strcmp(kSettings[i].key, key) == 0)
167 return &kSettings[i];
168 }
169 return nullptr;
170}
171
172} // namespace
173
174void settings_save(FILE *f) {
175 const char *section = nullptr;
176 for (int i = 0; i < kSettingCount; i++) {
177 const SettingDesc &s = kSettings[i];
178 if (!section || strcmp(section, s.section) != 0) {
179 fprintf(f, "\n[%s]\n", s.section);
180 section = s.section;
181 }
182 int v = s.type == S_BOOL ? (*(bool *)s.ptr ? 1 : 0) : *(int *)s.ptr;
183 fprintf(f, "%s=%d\n", s.key, v);
184 }
185}
186
187void settings_load(FILE *f) {
188 char line[256];
189 char section[64] = "";
190 while (fgets(line, sizeof(line), f)) {
191 line[strcspn(line, "\r\n")] = 0;
192 if (line[0] == '[') {
193 const char *end = strchr(line, ']');
194 if (!end)
195 continue;
196 size_t n = (size_t)(end - line - 1);
197 if (n >= sizeof(section))
198 n = sizeof(section) - 1;
199 memcpy(section, line + 1, n);
200 section[n] = 0;
201 continue;
202 }
203 char *eq = strchr(line, '=');
204 if (!eq)
205 continue;
206 *eq = 0;
207 const SettingDesc *d = find_setting(section, line);
208 if (!d)
209 continue; // [gui] and unknown keys belong to other readers
210 int v = atoi(eq + 1);
211 if (v < d->lo)
212 v = d->lo;
213 if (v > d->hi)
214 v = d->hi;
215 if (d->type == S_BOOL)
216 *(bool *)d->ptr = v != 0;
217 else
218 *(int *)d->ptr = v;
219 }
220}
221
222void settings_reset_defaults() {
223 for (int i = 0; i < kSettingCount; i++) {
224 const SettingDesc &s = kSettings[i];
225 if (s.type == S_BOOL)
226 *(bool *)s.ptr = s.def != 0;
227 else
228 *(int *)s.ptr = s.def;
229 }
230}