Add MCLQ water, TaxiPathNode transports, and vanilla M2 particles

- Parse MCLQ sub-chunks in vanilla ADTs for water rendering (WotLK uses MH2O)
- Load TaxiPathNode.dbc for MO_TRANSPORT world-coordinate paths (vanilla boats)
- Parse data[] from SMSG_GAMEOBJECT_QUERY_RESPONSE (taxiPathId for transports)
- Support vanilla M2 particle emitters (504-byte struct, different from WotLK 476)
- Add character preview texture diagnostic logging
- Fix disconnect handling on character screen (show error only when no chars)
This commit is contained in:
Kelsi 2026-02-14 20:20:43 -08:00
parent cbb3035313
commit bf31da8c13
14 changed files with 556 additions and 55 deletions

View file

@ -59,18 +59,6 @@ void CharacterScreen::render(game::GameHandler& gameHandler) {
// Get character list
const auto& characters = gameHandler.getCharacters();
// Handle disconnected state (e.g. Warden kicked us)
if (gameHandler.getState() == game::WorldState::DISCONNECTED ||
gameHandler.getState() == game::WorldState::FAILED) {
ImGui::TextColored(ImVec4(1.0f, 0.4f, 0.4f, 1.0f), "Disconnected from server.");
ImGui::TextWrapped("The server closed the connection. This may be caused by "
"anti-cheat (Warden) verification failure.");
ImGui::Spacing();
if (ImGui::Button("Back", ImVec2(120, 36))) { if (onBack) onBack(); }
ImGui::End();
return;
}
// Request character list if not available.
// Also show a loading state while CHAR_LIST_REQUESTED is in-flight (characters may be cleared to avoid stale UI).
if (characters.empty() &&
@ -84,6 +72,18 @@ void CharacterScreen::render(game::GameHandler& gameHandler) {
return;
}
// Handle disconnected state with no characters received
if (characters.empty() &&
(gameHandler.getState() == game::WorldState::DISCONNECTED ||
gameHandler.getState() == game::WorldState::FAILED)) {
ImGui::TextColored(ImVec4(1.0f, 0.4f, 0.4f, 1.0f), "Disconnected from server.");
ImGui::TextWrapped("The server closed the connection before sending the character list.");
ImGui::Spacing();
if (ImGui::Button("Back", ImVec2(120, 36))) { if (onBack) onBack(); }
ImGui::End();
return;
}
if (characters.empty()) {
ImGui::Text("No characters available.");
// Bottom buttons even when empty
@ -343,6 +343,12 @@ void CharacterScreen::render(game::GameHandler& gameHandler) {
// Enter World button — full width
float btnW = ImGui::GetContentRegionAvail().x;
bool disconnected = (gameHandler.getState() == game::WorldState::DISCONNECTED ||
gameHandler.getState() == game::WorldState::FAILED);
if (disconnected) {
ImGui::TextColored(ImVec4(1.0f, 0.6f, 0.3f, 1.0f), "Connection lost — click Back to reconnect");
}
if (disconnected) ImGui::BeginDisabled();
if (ImGui::Button("Enter World", ImVec2(btnW, 44))) {
characterSelected = true;
saveLastCharacter(character.guid);
@ -352,6 +358,7 @@ void CharacterScreen::render(game::GameHandler& gameHandler) {
gameHandler.selectCharacter(character.guid);
if (onCharacterSelected) onCharacterSelected(character.guid);
}
if (disconnected) ImGui::EndDisabled();
ImGui::EndChild();
}