Walk-up callsign/mech request: join menu -> relay -> the session egg
The 1995 front-desk conversation, over the internet. join.bat/
join_lan.bat now open a JOIN-GAME menu (the FE in BT_FE_JOIN trim:
CALLSIGN edit + the 18-mech list + JOIN); the choice relaunches into the
normal join with BT_CALLSIGN/BT_MECH env, rides the relay SEAT_REQUEST
as {callsign NUL mech NUL} (empty payload = roster defaults, wire-
compatible), and the relay validates the mech tag, HOLDS egg delivery
until every pod's console pad is connected, rewrites the egg via
eggmodel (vehicle= + rasterized callsign bitmaps, graceful no-PySide6
fallback) and streams it to all pads -- so every player's egg copy
carries every player's callsign.
The hold is gated on CONSOLE-PAD count, not game-side registration: a
pod HELLOs only after parsing the egg's roster, so a registration gate
deadlocks (hit live in the first run; pods animate in WAITING FOR
MISSION ASSIGNMENT during the hold).
Verified 2-node e2e (env-injected requests): thor/vulture requested over
roster defaults bhk1/ava1 -> relay held 1/2, released at 2/2, rewrote
both seats (relay log), the delivered egg carries vehicle=thor/vulture +
name=VIPER/MONGOOSE, both pods launched and built [cyl] tables for both
requested mechs. Join-menu layout screenshot-verified; the menu's
click-through relaunch awaits live human verification.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
eb618fe9e6
commit
fcedc046cf
@@ -457,6 +457,16 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
|
||||
SetEnvironmentVariableA("BT_FE_EGG", NULL);
|
||||
sprintf(fe_arguments, "-net %d -platform glass", fe_spec.consolePort);
|
||||
break;
|
||||
case BTFeLaunchJoinRelay:
|
||||
// BT_FE_JOIN (join.bat): the callsign/mech request rides env
|
||||
// into the relaunched pod; L4NET's SEAT_REQUEST carries it to
|
||||
// the relay, which writes it into the session egg. Args = the
|
||||
// universal join contract (join.bat's own OPERATOR.EGG/1501).
|
||||
SetEnvironmentVariableA("BT_FE_EGG", NULL);
|
||||
SetEnvironmentVariableA("BT_CALLSIGN", fe_spec.joinCallsign);
|
||||
SetEnvironmentVariableA("BT_MECH", fe_spec.joinVehicle);
|
||||
strcpy(fe_arguments, "-egg OPERATOR.EGG -net 1501 -platform glass");
|
||||
break;
|
||||
#ifdef BT_STEAM
|
||||
case BTFeLaunchJoinSteam:
|
||||
SetEnvironmentVariableA("BT_FE_EGG", NULL);
|
||||
|
||||
+63
-11
@@ -588,6 +588,25 @@ static int
|
||||
return s;
|
||||
}
|
||||
|
||||
//
|
||||
// BT_FE_JOIN=1 (join.bat / join_lan.bat): the JOIN-GAME menu -- the walk-up
|
||||
// desk conversation of the 1995 centers, over the internet. Only CALLSIGN +
|
||||
// MECH are the player's to pick (the operator owns the mission + the rest of
|
||||
// the loadout); the choice rides the relay SEAT_REQUEST and the relay writes
|
||||
// it into the session egg (btconsole.py).
|
||||
//
|
||||
static int
|
||||
FeJoinOnly()
|
||||
{
|
||||
static int s = -1;
|
||||
if (s < 0)
|
||||
{
|
||||
const char *e = getenv("BT_FE_JOIN");
|
||||
s = (e != NULL && *e != '0') ? 1 : 0;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
static int
|
||||
GroupSize(int group)
|
||||
{
|
||||
@@ -719,6 +738,15 @@ static void
|
||||
{
|
||||
menu.itemCount = 0;
|
||||
int y;
|
||||
if (FeJoinOnly())
|
||||
{
|
||||
// JOIN trim: the mech list + the JOIN button; callsign is the edit
|
||||
// control (repositioned in BTFrontEnd_Run). Everything else is the
|
||||
// operator's call.
|
||||
y = MenuTopY; AddGroup(GroupVehicle, MenuCol2X, &y);
|
||||
AddButton(GroupLaunch, MenuCol5X, MenuClientH - 190, 220, 52);
|
||||
return;
|
||||
}
|
||||
// col1: the mission
|
||||
y = MenuTopY; AddGroup(GroupMap, MenuCol1X, &y);
|
||||
AddGroup(GroupScenario, MenuCol1X, &y);
|
||||
@@ -843,8 +871,10 @@ static void
|
||||
|
||||
HFONT old_font = (HFONT)SelectObject(dc, menu.titleFont);
|
||||
RECT title_rect = { MenuCol1X, 14, client.right - 24, 54 };
|
||||
DrawMenuText(dc, "BATTLETECH -- MISSION CONSOLE", &title_rect,
|
||||
kGreenBright, DT_LEFT | DT_TOP | DT_SINGLELINE);
|
||||
DrawMenuText(dc,
|
||||
FeJoinOnly() ? "BATTLETECH -- JOIN GAME"
|
||||
: "BATTLETECH -- MISSION CONSOLE",
|
||||
&title_rect, kGreenBright, DT_LEFT | DT_TOP | DT_SINGLELINE);
|
||||
|
||||
SelectObject(dc, menu.textFont);
|
||||
|
||||
@@ -896,12 +926,15 @@ static void
|
||||
// Edit labels (the controls themselves are child windows in col5).
|
||||
//
|
||||
RECT label = { MenuCol5X, MenuNameLabelY, MenuCol5X + 240, MenuNameLabelY + MenuRowH };
|
||||
DrawMenuText(dc, "PILOT NAME", &label, kGreenDim,
|
||||
DT_LEFT | DT_VCENTER | DT_SINGLELINE);
|
||||
label.top = MenuPeersLabelY;
|
||||
label.bottom = label.top + MenuRowH;
|
||||
DrawMenuText(dc, "LAN PEERS (host: ip:port,...)", &label, kGreenDim,
|
||||
DT_LEFT | DT_VCENTER | DT_SINGLELINE);
|
||||
DrawMenuText(dc, FeJoinOnly() ? "CALLSIGN" : "PILOT NAME", &label,
|
||||
kGreenDim, DT_LEFT | DT_VCENTER | DT_SINGLELINE);
|
||||
if (!FeJoinOnly())
|
||||
{
|
||||
label.top = MenuPeersLabelY;
|
||||
label.bottom = label.top + MenuRowH;
|
||||
DrawMenuText(dc, "LAN PEERS (host: ip:port,...)", &label, kGreenDim,
|
||||
DT_LEFT | DT_VCENTER | DT_SINGLELINE);
|
||||
}
|
||||
|
||||
//
|
||||
// Buttons (framed, RP412 style).
|
||||
@@ -911,7 +944,7 @@ static void
|
||||
{
|
||||
const MenuItem &item = menu.items[i];
|
||||
const char *text =
|
||||
(item.group == GroupLaunch) ? "L A U N C H" :
|
||||
(item.group == GroupLaunch) ? (FeJoinOnly() ? "J O I N" : "L A U N C H") :
|
||||
(item.group == GroupSteamHost) ? "HOST STEAM LOBBY" :
|
||||
(item.group == GroupSteamJoin) ? "JOIN STEAM LOBBY" : NULL;
|
||||
if (text == NULL)
|
||||
@@ -926,7 +959,9 @@ static void
|
||||
DeleteObject(frame);
|
||||
|
||||
RECT help = { MenuCol1X, client.bottom - 30, client.right - 24, client.bottom - 6 };
|
||||
DrawMenuText(dc, "click to select ENTER = launch ESC = quit",
|
||||
DrawMenuText(dc,
|
||||
FeJoinOnly() ? "click to select ENTER = join ESC = quit"
|
||||
: "click to select ENTER = launch ESC = quit",
|
||||
&help, kGreenDim, DT_LEFT | DT_TOP | DT_SINGLELINE);
|
||||
|
||||
SelectObject(dc, old_font);
|
||||
@@ -1037,7 +1072,8 @@ int
|
||||
DWORD style = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;
|
||||
AdjustWindowRect(&frame_rect, style, FALSE);
|
||||
menu.window = CreateWindowW(
|
||||
L"BTFrontEndWnd", L"BattleTech - Mission Console",
|
||||
L"BTFrontEndWnd",
|
||||
FeJoinOnly() ? L"BattleTech - Join Game" : L"BattleTech - Mission Console",
|
||||
style, 100, 80,
|
||||
frame_rect.right - frame_rect.left, frame_rect.bottom - frame_rect.top,
|
||||
NULL, NULL, GetModuleHandleW(NULL), NULL);
|
||||
@@ -1067,6 +1103,10 @@ int
|
||||
SendMessageW(menu.peersEdit, WM_SETFONT, (WPARAM)menu.textFont, TRUE);
|
||||
SetWindowTextA(menu.nameEdit, pilot_name);
|
||||
SetWindowTextA(menu.peersEdit, peers);
|
||||
if (FeJoinOnly())
|
||||
{
|
||||
ShowWindow(menu.peersEdit, SW_HIDE); // operator's concern, not the joiner's
|
||||
}
|
||||
|
||||
ShowWindow(menu.window, SW_SHOW);
|
||||
SetForegroundWindow(menu.window);
|
||||
@@ -1104,6 +1144,18 @@ int
|
||||
//
|
||||
// Resolve the launch spec + write the egg.
|
||||
//
|
||||
if (FeJoinOnly())
|
||||
{
|
||||
// JOIN GAME: no egg, no port math -- the relay owns the session. The
|
||||
// callsign + mech request rides the SEAT_REQUEST payload (L4NET reads
|
||||
// BT_CALLSIGN / BT_MECH, set by WinMain from this spec).
|
||||
spec->mode = BTFeLaunchJoinRelay;
|
||||
strncpy(spec->joinCallsign, pilot_name[0] ? pilot_name : "Pilot",
|
||||
sizeof(spec->joinCallsign) - 1);
|
||||
strncpy(spec->joinVehicle, kVehicles[menu.selection[GroupVehicle]].key,
|
||||
sizeof(spec->joinVehicle) - 1);
|
||||
return 0;
|
||||
}
|
||||
int console_port = kPorts[menu.selection[GroupPort]];
|
||||
const RoleEntry &scenario = kScenarios[menu.selection[GroupScenario]];
|
||||
BTFeMission mission;
|
||||
|
||||
@@ -55,6 +55,7 @@ enum BTFeLaunchMode
|
||||
BTFeLaunchRawSolo, // plain -egg endless solo (renderer work)
|
||||
BTFeLaunchHostLan, // marshal feeds self + remote pods
|
||||
BTFeLaunchJoinLan, // plain -net pod; a remote host's marshal feeds us
|
||||
BTFeLaunchJoinRelay, // BT_FE_JOIN: relay join with callsign/mech request
|
||||
BTFeLaunchHostSteam, // (BT_STEAM) lobby host: marshal over the Steam wire
|
||||
BTFeLaunchJoinSteam // (BT_STEAM) lobby member: -net pod on the Steam wire
|
||||
};
|
||||
@@ -68,6 +69,8 @@ struct BTFeLaunchSpec
|
||||
int missionSeconds;
|
||||
char steamMyToken[48]; // (BT_STEAM) my roster token ip
|
||||
char steamMap[512]; // (BT_STEAM) ip=steamid64;...
|
||||
char joinCallsign[32]; // (BT_FE_JOIN) requested callsign
|
||||
char joinVehicle[16]; // (BT_FE_JOIN) requested mech tag
|
||||
};
|
||||
|
||||
//
|
||||
|
||||
Reference in New Issue
Block a user