ghost: fix auto-assigned room code flickering + copy button

When the relay auto-assigns a room, the code lives in the connection state
while the skate3_ghost_room cvar stays empty. The network loop was
overwriting the active room with the empty cvar every 25 ms, making the code
flicker in and out of the menu, and the Copy button copied the empty cvar.

- Loop: only sync the cvar into the active room when it is non-empty;
  preserve the server-assigned code otherwise.
- Menu: Copy grabs the ACTIVE room from GetStatus() (works for auto-assigned
  rooms, with a brief 'copied' hint); the room field now surfaces the
  auto-assigned code instead of staying blank.
This commit is contained in:
MiTHRAL 2026-08-27 12:56:22 -04:00
parent eabb989ff7
commit 4ec504ac6c
3 changed files with 37 additions and 4 deletions

View file

@ -738,8 +738,15 @@ void GhostNetworkLoop() {
RoomSet(room_buf, room_len, room_str.c_str()); RoomSet(room_buf, room_len, room_str.c_str());
{ {
std::lock_guard<std::mutex> lock(g_mu); std::lock_guard<std::mutex> lock(g_mu);
std::memcpy(g_room, room_buf, kGhostMaxRoomLen); // A non-empty room cvar is the user's explicit choice: sync it into
g_room_len = room_len; // the active room. An EMPTY cvar means "server auto-assigns" - keep
// the code the relay handed back on HELLO. Overwriting the assigned
// code with the empty cvar every 25 ms is what made the room code
// flicker in and out of the multiplayer menu.
if (room_len != 0) {
std::memcpy(g_room, room_buf, kGhostMaxRoomLen);
g_room_len = room_len;
}
} }
if (sock == GHOST_INVALID_SOCKET) { if (sock == GHOST_INVALID_SOCKET) {

View file

@ -45,7 +45,19 @@ void GhostDialog::Toggle() {
void GhostDialog::SyncBuffersFromCvars() { void GhostDialog::SyncBuffersFromCvars() {
const std::string room = REXCVAR_GET(skate3_ghost_room); const std::string room = REXCVAR_GET(skate3_ghost_room);
std::snprintf(room_input_, sizeof(room_input_), "%s", room.c_str()); if (!room.empty()) {
std::snprintf(room_input_, sizeof(room_input_), "%s", room.c_str());
} else {
// Auto-assigned room: the active code comes from the connection, not the
// (empty) cvar - surface it in the input so the user can see/copy it.
skate3::native_ghost::Status st;
if (skate3::native_ghost::GetStatus(&st) && st.room_len > 0) {
std::snprintf(room_input_, sizeof(room_input_), "%.*s",
int(st.room_len), st.room);
} else {
room_input_[0] = '\0';
}
}
const std::string server = REXCVAR_GET(skate3_ghost_server); const std::string server = REXCVAR_GET(skate3_ghost_server);
std::snprintf(server_input_, sizeof(server_input_), "%s", server.c_str()); std::snprintf(server_input_, sizeof(server_input_), "%s", server.c_str());
const std::string name = REXCVAR_GET(skate3_ghost_name); const std::string name = REXCVAR_GET(skate3_ghost_name);
@ -92,8 +104,21 @@ void GhostDialog::OnDraw(ImGuiIO& io) {
ImGui::SetKeyboardFocusHere(-1); ImGui::SetKeyboardFocusHere(-1);
} }
ImGui::SameLine(); ImGui::SameLine();
// Copy the ACTIVE room (the one this player is actually in), which for an
// auto-assigned room lives in the connection state, not the cvar.
if (ImGui::Button("Copy")) { if (ImGui::Button("Copy")) {
ImGui::SetClipboardText(REXCVAR_GET(skate3_ghost_room).c_str()); skate3::native_ghost::Status st;
if (skate3::native_ghost::GetStatus(&st) && st.room_len > 0) {
char buf[skate3::native_ghost::kGhostMaxRoomLen + 1] = {};
std::memcpy(buf, st.room, st.room_len);
ImGui::SetClipboardText(buf);
copy_feedback_ = true;
}
}
if (copy_feedback_) {
ImGui::SameLine();
ImGui::TextDisabled("copied");
copy_feedback_ = false;
} }
ImGui::TextDisabled("Empty = the server assigns one; share it with friends."); ImGui::TextDisabled("Empty = the server assigns one; share it with friends.");

View file

@ -27,6 +27,7 @@ class GhostDialog final : public rex::ui::ImGuiDialog {
bool visible_ = false; bool visible_ = false;
bool synced_ = false; bool synced_ = false;
bool copy_feedback_ = false;
char room_input_[16] = {}; char room_input_[16] = {};
char server_input_[128] = {}; char server_input_[128] = {};
char name_input_[skate3::native_ghost::kGhostMaxNameLen + 1] = {}; char name_input_[skate3::native_ghost::kGhostMaxNameLen + 1] = {};