|
27 | 27 | #include <vector> |
28 | 28 |
|
29 | 29 | #include "dialog_utils.h" |
| 30 | +#include "mojang_api.h" |
30 | 31 | #include "settings_utils.h" // ImGui imported through this |
31 | 32 | #include "global_event_handler.h" // For global variables |
32 | 33 | #include "path_utils.h" // For path_exists() |
@@ -124,10 +125,20 @@ static bool are_settings_different(const AppSettings *a, const AppSettings *b) { |
124 | 125 | a->network_mode != b->network_mode || |
125 | 126 | a->coop_goal_logic != b->coop_goal_logic || |
126 | 127 | strcmp(a->host_port, b->host_port) != 0 || |
127 | | - strcmp(a->receiver_invite_code, b->receiver_invite_code) != 0) { |
| 128 | + strcmp(a->receiver_invite_code, b->receiver_invite_code) != 0 || |
| 129 | + a->coop_player_count != b->coop_player_count) { |
128 | 130 | return true; |
129 | 131 | } |
130 | 132 |
|
| 133 | + // Compare player roster |
| 134 | + for (int i = 0; i < a->coop_player_count; ++i) { |
| 135 | + if (strcmp(a->coop_players[i].username, b->coop_players[i].username) != 0 || |
| 136 | + strcmp(a->coop_players[i].uuid, b->coop_players[i].uuid) != 0 || |
| 137 | + strcmp(a->coop_players[i].display_name, b->coop_players[i].display_name) != 0) { |
| 138 | + return true; |
| 139 | + } |
| 140 | + } |
| 141 | + |
131 | 142 | // Compare hotkeys separately |
132 | 143 | if (a->hotkey_count != b->hotkey_count) return true; |
133 | 144 | for (int i = 0; i < a->hotkey_count; ++i) { |
@@ -2340,6 +2351,125 @@ ImGui::SetTooltip("%s", tooltip_buffer); \ |
2340 | 2351 | ImGui::Separator(); |
2341 | 2352 | ImGui::Spacing(); |
2342 | 2353 |
|
| 2354 | + // --- Player Roster --- |
| 2355 | + ImGui::Text("Player Roster"); |
| 2356 | + ImGui::TextDisabled("Add Minecraft usernames to track. UUIDs are fetched automatically."); |
| 2357 | + ImGui::Spacing(); |
| 2358 | + |
| 2359 | + // Add player input |
| 2360 | + static char new_username[64] = ""; |
| 2361 | + static char roster_status_msg[256] = ""; |
| 2362 | + static bool roster_status_is_error = false; |
| 2363 | + |
| 2364 | + ImGui::SetNextItemWidth(200.0f); |
| 2365 | + ImGui::InputText("##new_username", new_username, sizeof(new_username)); |
| 2366 | + ImGui::SameLine(); |
| 2367 | + bool can_add = new_username[0] != '\0' && temp_settings.coop_player_count < MAX_COOP_PLAYERS; |
| 2368 | + if (!can_add) ImGui::BeginDisabled(); |
| 2369 | + if (ImGui::Button("Add Player")) { |
| 2370 | + // Check for duplicate username |
| 2371 | + bool duplicate = false; |
| 2372 | + for (int i = 0; i < temp_settings.coop_player_count; i++) { |
| 2373 | + if (strcmp(temp_settings.coop_players[i].username, new_username) == 0) { |
| 2374 | + duplicate = true; |
| 2375 | + break; |
| 2376 | + } |
| 2377 | + } |
| 2378 | + if (duplicate) { |
| 2379 | + snprintf(roster_status_msg, sizeof(roster_status_msg), |
| 2380 | + "Player '%s' is already in the roster.", new_username); |
| 2381 | + roster_status_is_error = true; |
| 2382 | + } else { |
| 2383 | + char fetched_uuid[48] = ""; |
| 2384 | + bool fetched = mojang_fetch_uuid(new_username, fetched_uuid, sizeof(fetched_uuid)); |
| 2385 | + if (fetched) { |
| 2386 | + CoopPlayer *p = &temp_settings.coop_players[temp_settings.coop_player_count]; |
| 2387 | + memset(p, 0, sizeof(CoopPlayer)); |
| 2388 | + strncpy(p->username, new_username, sizeof(p->username) - 1); |
| 2389 | + strncpy(p->uuid, fetched_uuid, sizeof(p->uuid) - 1); |
| 2390 | + p->display_name[0] = '\0'; |
| 2391 | + temp_settings.coop_player_count++; |
| 2392 | + snprintf(roster_status_msg, sizeof(roster_status_msg), |
| 2393 | + "Added '%s' (UUID: %s)", new_username, fetched_uuid); |
| 2394 | + roster_status_is_error = false; |
| 2395 | + new_username[0] = '\0'; |
| 2396 | + } else { |
| 2397 | + snprintf(roster_status_msg, sizeof(roster_status_msg), |
| 2398 | + "Could not find player '%s'.\n" |
| 2399 | + "Check the username.", new_username); |
| 2400 | + roster_status_is_error = true; |
| 2401 | + } |
| 2402 | + } |
| 2403 | + } |
| 2404 | + if (!can_add) ImGui::EndDisabled(); |
| 2405 | + |
| 2406 | + if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) { |
| 2407 | + char tooltip_buf[256]; |
| 2408 | + if (temp_settings.coop_player_count >= MAX_COOP_PLAYERS) { |
| 2409 | + snprintf(tooltip_buf, sizeof(tooltip_buf), "Roster is full (%d players max).", MAX_COOP_PLAYERS); |
| 2410 | + } else { |
| 2411 | + snprintf(tooltip_buf, sizeof(tooltip_buf), |
| 2412 | + "Type a Minecraft username and click to fetch their UUID\n" |
| 2413 | + "from the Mojang API and add them to the roster."); |
| 2414 | + } |
| 2415 | + ImGui::SetTooltip("%s", tooltip_buf); |
| 2416 | + } |
| 2417 | + |
| 2418 | + // Status message |
| 2419 | + if (roster_status_msg[0] != '\0') { |
| 2420 | + if (roster_status_is_error) |
| 2421 | + ImGui::TextColored(ImVec4(1.0f, 0.4f, 0.4f, 1.0f), "%s", roster_status_msg); |
| 2422 | + else |
| 2423 | + ImGui::TextColored(ImVec4(0.4f, 1.0f, 0.4f, 1.0f), "%s", roster_status_msg); |
| 2424 | + } |
| 2425 | + |
| 2426 | + ImGui::Spacing(); |
| 2427 | + |
| 2428 | + // Player list |
| 2429 | + int remove_index = -1; |
| 2430 | + for (int i = 0; i < temp_settings.coop_player_count; i++) { |
| 2431 | + ImGui::PushID(i + 1000); // Offset to avoid ID conflicts with goal logic |
| 2432 | + CoopPlayer *p = &temp_settings.coop_players[i]; |
| 2433 | + |
| 2434 | + // Display name (editable) |
| 2435 | + ImGui::SetNextItemWidth(120.0f); |
| 2436 | + char display_label[128]; |
| 2437 | + snprintf(display_label, sizeof(display_label), "##display_%d", i); |
| 2438 | + ImGui::InputTextWithHint(display_label, "Display Name", p->display_name, sizeof(p->display_name)); |
| 2439 | + if (ImGui::IsItemHovered()) { |
| 2440 | + char tooltip_buf[256]; |
| 2441 | + snprintf(tooltip_buf, sizeof(tooltip_buf), |
| 2442 | + "Custom display name (leave empty to use '%s').\n" |
| 2443 | + "UUID: %s", |
| 2444 | + p->username, p->uuid); |
| 2445 | + ImGui::SetTooltip("%s", tooltip_buf); |
| 2446 | + } |
| 2447 | + |
| 2448 | + ImGui::SameLine(); |
| 2449 | + ImGui::TextDisabled("%s", p->username); |
| 2450 | + |
| 2451 | + ImGui::SameLine(); |
| 2452 | + if (ImGui::SmallButton("Remove")) { |
| 2453 | + remove_index = i; |
| 2454 | + } |
| 2455 | + |
| 2456 | + ImGui::PopID(); |
| 2457 | + } |
| 2458 | + |
| 2459 | + // Handle removal |
| 2460 | + if (remove_index >= 0) { |
| 2461 | + for (int i = remove_index; i < temp_settings.coop_player_count - 1; i++) { |
| 2462 | + temp_settings.coop_players[i] = temp_settings.coop_players[i + 1]; |
| 2463 | + } |
| 2464 | + temp_settings.coop_player_count--; |
| 2465 | + memset(&temp_settings.coop_players[temp_settings.coop_player_count], 0, sizeof(CoopPlayer)); |
| 2466 | + roster_status_msg[0] = '\0'; |
| 2467 | + } |
| 2468 | + |
| 2469 | + ImGui::Spacing(); |
| 2470 | + ImGui::Separator(); |
| 2471 | + ImGui::Spacing(); |
| 2472 | + |
2343 | 2473 | // Invite Code Generation (placeholder - will be functional with networking) |
2344 | 2474 | ImGui::Text("Invite Code"); |
2345 | 2475 | ImGui::TextDisabled("Generate an invite code to share with receivers."); |
|
0 commit comments