Skip to content

Commit a9ef6eb

Browse files
d3nd3cursoragent
andcommitted
Release v7.3: deathmatch-only loading rule, simplify connect latch
Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 1a628f0 commit a9ef6eb

13 files changed

Lines changed: 50 additions & 172 deletions

File tree

CHANGELOG.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,34 @@
11
# Changelog
22

3+
## v7.3
4+
5+
### Internal menus — deathmatch-only loading rule
6+
7+
- **Removed cls/connect-flow latch** (`Qcommon_Frame` Post, plaque context, savegame/`sv.loadgame` heuristics) — vanilla vs custom loading now follows stock **`deathmatch` `exinclude`** timing only.
8+
- **`internal_menus_use_vanilla_loading_menu()`:** `deathmatch==0` → pak `loading.rmf`; `deathmatch!=0` → Buddy custom loading menu.
9+
- **Loading header:** `<exinclude deathmatch>` picks **`loading_network`** (map + download status) in DM or empty **`loading_network_sp`** in SP — replaces `_sofbuddy_loading_network` `cninclude`.
10+
- **`SCR_BeginLoadingPlaque`:** skip redundant second plaque only when still on the **vanilla** path; never skip when switching to custom MP loading (e.g. deathmatch set after first plaque).
11+
12+
### HTTP maps
13+
14+
- **Connect assist** gated on latched **`deathmatch`** only (removed MP connect-flow check).
15+
16+
## v7.2
17+
18+
### Internal menus — loading context & connect-flow fixes
19+
20+
- **Loading plaque context:** `begin/end_loading_plaque_context` tracks savegame loads (`sv.loadgame`) and SP local map loads so vanilla vs custom loading UI is chosen per plaque, not from stale latch state.
21+
- **MP connect latch:** Requires **two consecutive `ca_disconnected` frames** in deathmatch before clearing (avoids one-frame cls glitches during MP map load). SP `newgame.cfg` disconnect+map scripts clear immediately.
22+
- **`ca_active``ca_connected`:** Treated as SP local reload (mission/quickload), not MP connect — clears connect latch and HTTP maps loading state.
23+
- **Savegame loads:** Always use vanilla pak `loading.rmf`; network status panel hidden.
24+
25+
### HTTP maps — loading UI state
26+
27+
- **`http_maps_on_sp_local_map_load()`:** Clears cached loading UI / map labels when SP loads a local map.
28+
- **`http_maps_refresh_loading_menu_labels()`:** Updates map name on the existing loading menu when the second `SCR_BeginLoadingPlaque` is skipped (no killmenu flash).
29+
- **Network panel:** `_sofbuddy_loading_network` is on only during **MP connect + HTTP maps assist**, not savegame or SP local loads.
30+
- **Loading UI show:** Sets `loading_ui_active` / map path before `loading_show_ui()`; `http_maps_should_assist_connect` exported in `shared.h`.
31+
332
## v7.1
433

534
### cl_maxfps singleplayer — simplify freeze sync

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
7.2
1+
7.3

build/generated_registrations.h

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@ extern void internal_menus_M_PushMenu_pre(char const*& menu_file, char const*& p
5353
extern void internal_menus_PostCvarInit();
5454
extern void internal_menus_SCR_BeginLoadingPlaque_post(qboolean noPlaque);
5555
extern int internal_menus_fs_loadfile_override_callback(char* path, void** buffer, bool override_pak, detour_FS_LoadFile::tFS_LoadFile original);
56-
extern void internal_menus_qcommon_frame_post(int msec);
5756
extern void lightblend_PostCvarInit();
5857
extern void lightblend_RefDllLoaded(char const* name);
5958
extern void mediaTimers_EarlyStartup();
@@ -235,15 +234,6 @@ inline void RegisterAllFeatureHooks() {
235234
90);
236235
PrintOut(PRINT_LOG, "[RegisterAllFeatureHooks] M_PushMenu post callbacks: %zu\n", mgr.GetPostCallbackCount());
237236
}
238-
{
239-
auto& mgr = detour_Qcommon_Frame::GetManager();
240-
PrintOut(PRINT_LOG, "[RegisterAllFeatureHooks] Qcommon_Frame manager at 0x%p\n", &mgr);
241-
mgr.RegisterPostCallback(
242-
"internal_menus", "internal_menus_qcommon_frame_post",
243-
[](int msec) { internal_menus_qcommon_frame_post(msec); },
244-
85);
245-
PrintOut(PRINT_LOG, "[RegisterAllFeatureHooks] Qcommon_Frame post callbacks: %zu\n", mgr.GetPostCallbackCount());
246-
}
247237
{
248238
auto& mgr = detour_SCR_BeginLoadingPlaque::GetManager();
249239
PrintOut(PRINT_LOG, "[RegisterAllFeatureHooks] SCR_BeginLoadingPlaque manager at 0x%p\n", &mgr);

hdr/version.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,4 @@
77
Increment version using: ./increment_version.sh
88
*/
99

10-
#define SOFBUDDY_VERSION "7.2"
10+
#define SOFBUDDY_VERSION "7.3"

src/features/http_maps/http_maps.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1732,7 +1732,7 @@ bool http_maps_should_assist_connect(void)
17321732
if (static_cast<int>(_sofbuddy_http_maps->value) <= 0) return false;
17331733
if (http_maps_frame_work_pending()) return true;
17341734
#if FEATURE_INTERNAL_MENUS
1735-
return internal_menus_mp_connect_flow_active() || internal_menus_deathmatch_mode_active();
1735+
return internal_menus_deathmatch_mode_active();
17361736
#else
17371737
if (!detour_Cvar_Get::oCvar_Get) return false;
17381738
cvar_t* dm = detour_Cvar_Get::oCvar_Get("deathmatch", "0", 0, nullptr);

src/features/internal_menus/hooks/fs_loadfile_override.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ int internal_menus_fs_loadfile_override_callback(char* path, void** buffer, bool
5555
std::string filename = path_to_filename(path);
5656
if (menu_name.empty() || filename.empty()) return original(path, buffer, override_pak);
5757

58-
// SP / non-DM: vanilla pak loading menus (deathmatch exinclude / menu_nostats stats gating).
58+
// SP (deathmatch==0): vanilla pak loading.rmf — same rule as stock <exinclude deathmatch> in loading.rmf.
5959
if (menu_name == "loading" && internal_menus_use_vanilla_loading_menu())
6060
return original(path, buffer, override_pak);
6161

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,6 @@
1-
[{"function":"FS_LoadFile","callback":"internal_menus_fs_loadfile_override_callback","override":true},{"function":"M_PushMenu","callback":"internal_menus_M_PushMenu_pre","phase":"Pre","priority":90},{"function":"M_PushMenu","callback":"internal_menus_M_PushMenu_post","phase":"Post","priority":90},{"function":"Qcommon_Frame","callback":"internal_menus_qcommon_frame_post","phase":"Post","priority":85},{"function":"SCR_BeginLoadingPlaque","callback":"internal_menus_SCR_BeginLoadingPlaque_post","phase":"Post","priority":90}]
1+
[
2+
{"function":"FS_LoadFile","callback":"internal_menus_fs_loadfile_override_callback","override":true},
3+
{"function":"M_PushMenu","callback":"internal_menus_M_PushMenu_pre","phase":"Pre","priority":90},
4+
{"function":"M_PushMenu","callback":"internal_menus_M_PushMenu_post","phase":"Post","priority":90},
5+
{"function":"SCR_BeginLoadingPlaque","callback":"internal_menus_SCR_BeginLoadingPlaque_post","phase":"Post","priority":90}
6+
]

src/features/internal_menus/hooks/qcommon_frame_post.cpp

Lines changed: 0 additions & 15 deletions
This file was deleted.

src/features/internal_menus/hooks/scr_beginloadingplaque_post.cpp

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,29 +14,22 @@ void internal_menus_SCR_BeginLoadingPlaque_post(qboolean noPlaque) {
1414
if (noPlaque) return;
1515
if (!detour_M_PushMenu::oM_PushMenu) return;
1616

17-
static int* s_cls_state = (int*)rvaToAbsExe((void*)0x001C1F00);
18-
const int cls = s_cls_state ? *s_cls_state : -1;
19-
if (s_cls_state) internal_menus_update_connect_flow(cls);
20-
internal_menus_begin_loading_plaque_context(cls);
21-
22-
// SP local load: vanilla loading.rmf from pak. Avoid killmenu so blankscreen/outfit interstitials
23-
// are not cleared early.
2417
if (internal_menus_use_vanilla_loading_menu()) {
25-
if (internal_menus_savegame_load_active())
26-
internal_menus_on_loadgame_map_load();
2718
internal_menus_sync_loading_network_ui();
2819
detour_M_PushMenu::oM_PushMenu("loading", "", true);
2920
internal_menus_call_SCR_UpdateScreen(true);
30-
internal_menus_end_loading_plaque_context();
3121
return;
3222
}
3323

3424
const bool lock_input = internal_menus_should_lock_loading_input();
3525
#if FEATURE_HTTP_MAPS
36-
if (lock_input && http_maps_should_skip_loading_plaque_menu()) {
26+
// Vanilla re-evaluates <exinclude deathmatch> on every menu push; only skip a redundant
27+
// second vanilla re-push. Never skip when switching to the custom MP menu (deathmatch set
28+
// after the first plaque, or map/http_maps finished before CL_Changing).
29+
if (lock_input && internal_menus_use_vanilla_loading_menu() &&
30+
http_maps_should_skip_loading_plaque_menu()) {
3731
internal_menus_sync_loading_network_ui();
3832
http_maps_refresh_loading_menu_labels();
39-
internal_menus_end_loading_plaque_context();
4033
return;
4134
}
4235
#endif
@@ -53,7 +46,6 @@ void internal_menus_SCR_BeginLoadingPlaque_post(qboolean noPlaque) {
5346
#endif
5447
detour_M_PushMenu::oM_PushMenu(internal_menus_loading_menu_name(), "", lock_input);
5548
internal_menus_call_SCR_UpdateScreen(true);
56-
internal_menus_end_loading_plaque_context();
5749
}
5850

5951
#endif

src/features/internal_menus/internal_menus.cpp

Lines changed: 3 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -426,135 +426,17 @@ bool internal_menus_deathmatch_mode_active(void) {
426426
return dm && dm->value != 0.0f;
427427
}
428428

429-
static bool g_mp_connect_flow = false;
430-
static bool g_plaque_savegame_load = false;
431-
static bool g_plaque_sp_local = false;
432-
static int s_prev_cls_for_connect = -1;
433-
434-
// server_t.loadgame (Q2 layout: state + attractloop + loadgame).
435-
static constexpr uintptr_t kSvLoadgameRva = 0x003A1F25;
436-
437-
static bool internal_menus_is_connect_handshake_state(connstate_t st) {
438-
switch (st) {
439-
case ca_connecting:
440-
case ca_won_receive_result:
441-
case ca_connecting_stage2:
442-
case ca_won_challenge:
443-
case ca_won_receive_challenge1:
444-
return true;
445-
default:
446-
return false;
447-
}
448-
}
449-
450-
static int internal_menus_read_sv_loadgame(void) {
451-
auto* loadgame = reinterpret_cast<unsigned char*>(rvaToAbsExe(reinterpret_cast<void*>(kSvLoadgameRva)));
452-
return (loadgame && *loadgame) ? 1 : 0;
453-
}
454-
455-
void internal_menus_update_connect_flow(int cls_state) {
456-
const connstate_t st = static_cast<connstate_t>(cls_state);
457-
switch (st) {
458-
case ca_uninitialized:
459-
case ca_disconnected:
460-
// cls can glitch to disconnected for one frame during MP map load; require two
461-
// consecutive disconnected observations before clearing (matches http_maps).
462-
// SP menu loads (newgame.cfg: disconnect; map) run in one script — one frame only.
463-
if (!internal_menus_deathmatch_mode_active())
464-
g_mp_connect_flow = false;
465-
else if (s_prev_cls_for_connect == ca_disconnected)
466-
g_mp_connect_flow = false;
467-
break;
468-
case ca_connecting:
469-
case ca_won_receive_result:
470-
case ca_connecting_stage2:
471-
case ca_won_challenge:
472-
case ca_won_receive_challenge1:
473-
g_mp_connect_flow = true;
474-
break;
475-
case ca_connected: {
476-
const connstate_t prev = static_cast<connstate_t>(s_prev_cls_for_connect);
477-
// SP local reload (mission, quickload): 8 -> 7 — not MP connect, even if deathmatch latched.
478-
if (prev == ca_active) {
479-
g_mp_connect_flow = false;
480-
#if FEATURE_HTTP_MAPS
481-
http_maps_on_sp_local_map_load();
482-
#endif
483-
break;
484-
}
485-
// MP join: 2 -> 4 -> 7. Keep latch through map load.
486-
if (!g_mp_connect_flow && internal_menus_is_connect_handshake_state(prev))
487-
g_mp_connect_flow = true;
488-
break;
489-
}
490-
case ca_active:
491-
g_mp_connect_flow = false;
492-
break;
493-
default:
494-
break;
495-
}
496-
s_prev_cls_for_connect = cls_state;
497-
}
498-
499-
bool internal_menus_mp_connect_flow_active(void) {
500-
return g_mp_connect_flow;
501-
}
502-
503-
void internal_menus_begin_loading_plaque_context(int cls_state) {
504-
const int lg = internal_menus_read_sv_loadgame();
505-
g_plaque_savegame_load = lg != 0 && cls_state != static_cast<int>(ca_connected);
506-
g_plaque_sp_local = false;
507-
if (internal_menus_deathmatch_mode_active()) return;
508-
const connstate_t st = static_cast<connstate_t>(cls_state);
509-
const connstate_t prev = static_cast<connstate_t>(s_prev_cls_for_connect);
510-
if (internal_menus_is_connect_handshake_state(st) || internal_menus_is_connect_handshake_state(prev))
511-
return;
512-
g_plaque_sp_local = true;
513-
g_mp_connect_flow = false;
514-
#if FEATURE_HTTP_MAPS
515-
http_maps_on_sp_local_map_load();
516-
#endif
517-
}
518-
519-
void internal_menus_end_loading_plaque_context(void) {
520-
g_plaque_savegame_load = false;
521-
g_plaque_sp_local = false;
522-
}
523-
524-
bool internal_menus_savegame_load_active(void) {
525-
return g_plaque_savegame_load;
526-
}
527-
528-
void internal_menus_on_loadgame_map_load(void) {
529-
g_mp_connect_flow = false;
530-
#if FEATURE_HTTP_MAPS
531-
http_maps_on_sp_local_map_load();
532-
#endif
533-
}
534-
535429
bool internal_menus_use_vanilla_loading_menu(void) {
536-
if (internal_menus_savegame_load_active()) return true;
537-
if (g_plaque_sp_local) return true;
538-
#if FEATURE_HTTP_MAPS
539-
if (http_maps_wants_custom_loading_menu()) return false;
540-
#endif
541-
if (g_mp_connect_flow) return false;
542-
return true;
430+
return !internal_menus_deathmatch_mode_active();
543431
}
544432

545433
bool internal_menus_should_killmenu_before_loading(void) {
546434
return !internal_menus_use_vanilla_loading_menu();
547435
}
548436

549437
void internal_menus_sync_loading_network_ui(void) {
550-
#if FEATURE_HTTP_MAPS
551-
const bool network = !internal_menus_savegame_load_active() &&
552-
internal_menus_mp_connect_flow_active() &&
553-
http_maps_should_assist_connect();
554-
set_runtime_cvar_int("_sofbuddy_loading_network", network ? 1 : 0);
555-
#else
556-
set_runtime_cvar_int("_sofbuddy_loading_network", 0);
557-
#endif
438+
// Map/download header uses <exinclude deathmatch> in loading_header.rmf (same timing as vanilla).
439+
set_runtime_cvar_int("_sofbuddy_loading_network", internal_menus_deathmatch_mode_active() ? 1 : 0);
558440
}
559441

560442
bool internal_menus_is_mp_loading_context(void) {

0 commit comments

Comments
 (0)