#include "room_loader.hpp" #include // Para exception #include // Para cout, cerr #include // Para YAML::Node, YAML::LoadFile #include "core/resources/resource_helper.hpp" // Para Resource::Helper #include "utils/defines.hpp" // Para TILE_SIZE #include "utils/utils.hpp" // Para stringToColor // Convierte room connection de YAML a formato con extensión auto RoomLoader::convertRoomConnection(const std::string& value) -> std::string { if (value == "null" || value.empty()) { return "0"; } // "02" → "02.yaml" return value + ".yaml"; } // Convierte un tilemap 2D a vector 1D flat auto RoomLoader::flattenTilemap(const std::vector>& tilemap_2d) -> std::vector { std::vector tilemap_flat; tilemap_flat.reserve(512); // 16 rows × 32 cols for (const auto& row : tilemap_2d) { for (int tile : row) { tilemap_flat.push_back(tile); } } return tilemap_flat; } // Carga un archivo de room en formato YAML auto RoomLoader::loadYAML(const std::string& file_path, bool verbose) -> Room::Data { Room::Data room; // Extract filename for logging const std::string FILE_NAME = file_path.substr(file_path.find_last_of("\\/") + 1); try { // Load YAML file using ResourceHelper (supports both filesystem and pack) auto file_data = Resource::Helper::loadFile(file_path); if (file_data.empty()) { std::cerr << "Error: Unable to load file " << FILE_NAME << '\n'; return room; } // Parse YAML from string std::string yaml_content(file_data.begin(), file_data.end()); YAML::Node yaml = YAML::Load(yaml_content); // --- Parse room configuration --- if (yaml["room"]) { const YAML::Node& room_node = yaml["room"]; // Extract room number from filename (e.g., "01.yaml" → "01") room.number = FILE_NAME.substr(0, FILE_NAME.find_last_of('.')); // Basic properties if (room_node["name"]) { room.name = room_node["name"].as(); } if (room_node["bgColor"]) { room.bg_color = room_node["bgColor"].as(); } if (room_node["border"]) { room.border_color = room_node["border"].as(); } if (room_node["tileSetFile"]) { room.tile_set_file = room_node["tileSetFile"].as(); } // Room connections if (room_node["connections"]) { const YAML::Node& conn = room_node["connections"]; if (conn["up"]) { room.upper_room = convertRoomConnection(conn["up"].as("null")); } else { room.upper_room = "0"; } if (conn["down"]) { room.lower_room = convertRoomConnection(conn["down"].as("null")); } else { room.lower_room = "0"; } if (conn["left"]) { room.left_room = convertRoomConnection(conn["left"].as("null")); } else { room.left_room = "0"; } if (conn["right"]) { room.right_room = convertRoomConnection(conn["right"].as("null")); } else { room.right_room = "0"; } } // Item colors if (room_node["itemColor1"]) { room.item_color1 = room_node["itemColor1"].as("yellow"); } else { room.item_color1 = "yellow"; } if (room_node["itemColor2"]) { room.item_color2 = room_node["itemColor2"].as("magenta"); } else { room.item_color2 = "magenta"; } // Conveyor belt direction if (room_node["autoSurface"]) { room.conveyor_belt_direction = room_node["autoSurface"].as(0); } else { room.conveyor_belt_direction = 0; } } // --- Parse tilemap --- if (yaml["tilemap"]) { const YAML::Node& tilemap_node = yaml["tilemap"]; // Read 2D array std::vector> tilemap_2d; tilemap_2d.reserve(16); for (const auto& row_node : tilemap_node) { std::vector row; row.reserve(32); for (const auto& tile_node : row_node) { row.push_back(tile_node.as()); } tilemap_2d.push_back(row); } // Convert to 1D flat array room.tile_map = flattenTilemap(tilemap_2d); if (verbose) { std::cout << "Loaded tilemap: " << room.tile_map.size() << " tiles\n"; } } else { std::cerr << "Warning: No tilemap found in " << FILE_NAME << '\n'; } // --- Parse enemies --- if (yaml["enemies"] && !yaml["enemies"].IsNull()) { const YAML::Node& enemies_node = yaml["enemies"]; for (const auto& enemy_node : enemies_node) { Enemy::Data enemy; // Animation path if (enemy_node["animation"]) { enemy.animation_path = enemy_node["animation"].as(); } // Position (in tiles, convert to pixels) if (enemy_node["position"]) { const YAML::Node& pos = enemy_node["position"]; if (pos["x"]) { enemy.x = pos["x"].as() * TILE_SIZE; } if (pos["y"]) { enemy.y = pos["y"].as() * TILE_SIZE; } } // Velocity (already in pixels/second) if (enemy_node["velocity"]) { const YAML::Node& vel = enemy_node["velocity"]; if (vel["x"]) { enemy.vx = vel["x"].as(); } if (vel["y"]) { enemy.vy = vel["y"].as(); } } // Boundaries (in tiles, convert to pixels) if (enemy_node["boundaries"]) { const YAML::Node& bounds = enemy_node["boundaries"]; if (bounds["x1"]) { enemy.x1 = bounds["x1"].as() * TILE_SIZE; } if (bounds["y1"]) { enemy.y1 = bounds["y1"].as() * TILE_SIZE; } if (bounds["x2"]) { enemy.x2 = bounds["x2"].as() * TILE_SIZE; } if (bounds["y2"]) { enemy.y2 = bounds["y2"].as() * TILE_SIZE; } } // Color if (enemy_node["color"]) { enemy.color = enemy_node["color"].as("white"); } else { enemy.color = "white"; } // Optional fields if (enemy_node["flip"]) { enemy.flip = enemy_node["flip"].as(false); } else { enemy.flip = false; } if (enemy_node["mirror"]) { enemy.mirror = enemy_node["mirror"].as(false); } else { enemy.mirror = false; } if (enemy_node["frame"]) { enemy.frame = enemy_node["frame"].as(-1); } else { enemy.frame = -1; } room.enemies.push_back(enemy); } if (verbose) { std::cout << "Loaded " << room.enemies.size() << " enemies\n"; } } // --- Parse items --- if (yaml["items"] && !yaml["items"].IsNull()) { const YAML::Node& items_node = yaml["items"]; for (const auto& item_node : items_node) { Item::Data item; // Tileset file if (item_node["tileSetFile"]) { item.tile_set_file = item_node["tileSetFile"].as(); } // Tile index if (item_node["tile"]) { item.tile = item_node["tile"].as(); } // Position (in tiles, convert to pixels) if (item_node["position"]) { const YAML::Node& pos = item_node["position"]; if (pos["x"]) { item.x = pos["x"].as() * TILE_SIZE; } if (pos["y"]) { item.y = pos["y"].as() * TILE_SIZE; } } // Counter if (item_node["counter"]) { item.counter = item_node["counter"].as(0); } else { item.counter = 0; } // Colors (assigned from room defaults) item.color1 = stringToColor(room.item_color1); item.color2 = stringToColor(room.item_color2); room.items.push_back(item); } if (verbose) { std::cout << "Loaded " << room.items.size() << " items\n"; } } if (verbose) { std::cout << "Room loaded successfully: " << FILE_NAME << '\n'; } } catch (const YAML::Exception& e) { std::cerr << "YAML parsing error in " << FILE_NAME << ": " << e.what() << '\n'; } catch (const std::exception& e) { std::cerr << "Error loading room " << FILE_NAME << ": " << e.what() << '\n'; } return room; }