diff --git a/data/images/background/corrupted_forest/test b/data/images/background/corrupted_forest/test deleted file mode 100644 index b2888c437aa..00000000000 --- a/data/images/background/corrupted_forest/test +++ /dev/null @@ -1 +0,0 @@ -dgbyfjgfjduku diff --git a/data/images/engine/editor/select-mode3.png b/data/images/engine/editor/select-mode3.png new file mode 100644 index 00000000000..ac80da9ede9 Binary files /dev/null and b/data/images/engine/editor/select-mode3.png differ diff --git a/src/addon/addon_manager.cpp b/src/addon/addon_manager.cpp index 6302d047e58..ea4c572fb1d 100644 --- a/src/addon/addon_manager.cpp +++ b/src/addon/addon_manager.cpp @@ -545,15 +545,13 @@ std::vector AddonManager::get_local_addon_screenshots(const AddonId& addon_id) { std::vector screenshots; - std::unique_ptr rc(PHYSFS_enumerateFiles(m_screenshots_cache_directory.c_str()), PHYSFS_freeList); - for (char** i = rc.get(); *i != nullptr; ++i) - { + physfsutil::enumerate_files(m_screenshots_cache_directory, [&screenshots, &addon_id, this](const std::string& filename) { // Push any files from the cache directory, starting with the ID of the add-on. - if (StringUtil::starts_with(*i, addon_id)) + if (StringUtil::starts_with(filename, addon_id)) { - screenshots.push_back(FileSystem::join(m_screenshots_cache_directory, *i)); + screenshots.push_back(FileSystem::join(m_screenshots_cache_directory, filename)); } - } + }); return screenshots; } @@ -753,28 +751,24 @@ AddonManager::scan_for_archives() const std::vector archives; // Search for archives and add them to the search path. - std::unique_ptr - rc(PHYSFS_enumerateFiles(m_addon_directory.c_str()), - PHYSFS_freeList); - for (char** i = rc.get(); *i != nullptr; ++i) - { - const std::string fullpath = FileSystem::join(m_addon_directory, *i); + physfsutil::enumerate_files(m_addon_directory, [this, &archives](const std::string& filename) { + const std::string fullpath = FileSystem::join(m_addon_directory, filename); if (physfsutil::is_directory(fullpath)) { // Ignore dot files (e.g. '.git/'), as well as the addon cache directory. - if ((*i)[0] != '.' && fullpath != m_cache_directory) { + if (filename[0] != '.' && fullpath != m_cache_directory) { archives.push_back(fullpath); } } else { - if (StringUtil::has_suffix(StringUtil::tolower(*i), ".zip")) { + if (StringUtil::has_suffix(StringUtil::tolower(filename), ".zip")) { if (PHYSFS_exists(fullpath.c_str())) { archives.push_back(fullpath); } } } - } + }); return archives; } @@ -782,14 +776,11 @@ AddonManager::scan_for_archives() const std::string AddonManager::scan_for_info(const std::string& archive_os_path) const { - std::unique_ptr - rc2(PHYSFS_enumerateFiles("/"), - PHYSFS_freeList); - for (char** j = rc2.get(); *j != nullptr; ++j) - { - if (StringUtil::has_suffix(*j, ".nfo")) + std::string nfoFilename = std::string(); + physfsutil::enumerate_files("/", [archive_os_path, &nfoFilename](const std::string& file) { + if (StringUtil::has_suffix(file, ".nfo")) { - std::string nfo_filename = FileSystem::join("/", *j); + std::string nfo_filename = FileSystem::join("/", file); // Make sure it's in the current archive_os_path. const char* realdir = PHYSFS_getRealDir(nfo_filename.c_str()); @@ -801,13 +792,13 @@ AddonManager::scan_for_info(const std::string& archive_os_path) const { if (realdir == archive_os_path) { - return nfo_filename; + nfoFilename = nfo_filename; } } } - } + }); - return std::string(); + return nfoFilename; } void diff --git a/src/editor/overlay_widget.cpp b/src/editor/overlay_widget.cpp index 3be7f1b7f47..310b107ba16 100644 --- a/src/editor/overlay_widget.cpp +++ b/src/editor/overlay_widget.cpp @@ -84,12 +84,14 @@ EditorOverlayWidget::~EditorOverlayWidget() void EditorOverlayWidget::update(float dt_sec) { - if (m_hovered_object && !m_hovered_object->is_valid()) { + if (m_hovered_object && !m_hovered_object->is_valid()) + { m_hovered_object = nullptr; m_object_tip = nullptr; } - if (m_selected_object && !m_selected_object->is_valid()) { + if (m_selected_object && !m_selected_object->is_valid()) + { delete_markers(); } } @@ -109,11 +111,11 @@ EditorOverlayWidget::delete_markers() { auto* sector = m_editor.get_sector(); - if (m_selected_object && m_selected_object->is_valid()) { + if (m_selected_object && m_selected_object->is_valid()) m_selected_object->editor_deselect(); - } - for (auto& marker : sector->get_objects_by_type()) { + for (auto& marker : sector->get_objects_by_type()) + { marker.remove_me(); } @@ -127,18 +129,24 @@ EditorOverlayWidget::drag_rect() const { int start_x, start_y, end_x, end_y; - if (m_drag_start.x < m_sector_pos.x) { + if (m_drag_start.x < m_sector_pos.x) + { start_x = static_cast(m_drag_start.x); end_x = static_cast(m_sector_pos.x); - } else { + } + else + { start_x = static_cast(m_sector_pos.x); end_x = static_cast(m_drag_start.x); } - if (m_drag_start.y < m_sector_pos.y) { + if (m_drag_start.y < m_sector_pos.y) + { start_y = static_cast(m_drag_start.y); end_y = static_cast(m_sector_pos.y); - } else { + } + else + { start_y = static_cast(m_sector_pos.y); end_y = static_cast(m_drag_start.y); } @@ -153,9 +161,7 @@ void EditorOverlayWidget::input_tile(const Vector& pos, uint32_t tile) { auto tilemap = m_editor.get_selected_tilemap(); - if (!tilemap || !is_position_inside_tilemap(tilemap, pos)) { - return; - } + if (!tilemap || !is_position_inside_tilemap(tilemap, pos)) return; tilemap->save_state(); tilemap->change(static_cast(pos.x), static_cast(pos.y), tile); @@ -165,9 +171,7 @@ void EditorOverlayWidget::autotile(const Vector& pos, uint32_t tile) { auto tilemap = m_editor.get_selected_tilemap(); - if (!tilemap || !is_position_inside_tilemap(tilemap, pos)) { - return; - } + if (!tilemap || !is_position_inside_tilemap(tilemap, pos)) return; tilemap->save_state(); tilemap->autotile(static_cast(pos.x), static_cast(pos.y), tile); @@ -197,9 +201,7 @@ EditorOverlayWidget::autotile_corner(const Vector& pos, uint32_t tile, TileMap::AutotileCornerOperation op) { auto tilemap = m_editor.get_selected_tilemap(); - if (!tilemap || !is_position_inside_tilemap(tilemap, pos)) { - return; - } + if (!tilemap || !is_position_inside_tilemap(tilemap, pos)) return; tilemap->save_state(); tilemap->autotile_corner(static_cast(pos.x), static_cast(pos.y), tile, op); @@ -233,23 +235,33 @@ EditorOverlayWidget::put_tile(const Vector& target_tile) Vector hovered_corner = target_tile + Vector(0.5f, 0.5f); auto tiles = m_editor.get_tiles(); Vector add_tile(0.0f, 0.0f); - for (add_tile.x = static_cast(tiles->m_width) - 1.0f; add_tile.x >= 0.0f; add_tile.x--) { - for (add_tile.y = static_cast(tiles->m_height) - 1.0f; add_tile.y >= 0; add_tile.y--) { + for (add_tile.x = static_cast(tiles->m_width) - 1.0f; add_tile.x >= 0.0f; add_tile.x--) + { + for (add_tile.y = static_cast(tiles->m_height) - 1.0f; add_tile.y >= 0; add_tile.y--) + { uint32_t tile = tiles->pos(static_cast(add_tile.x), static_cast(add_tile.y)); auto tilemap = m_editor.get_selected_tilemap(); - if (g_config->editor_autotile_mode && ((tilemap && tilemap->get_autotileset(tile)) || tile == 0)) { - if (tile == 0) { + if (g_config->editor_autotile_mode && ((tilemap && tilemap->get_autotileset(tile)) || tile == 0)) + { + if (tile == 0) + { tilemap->autotile_erase(target_tile + add_tile, hovered_corner + add_tile); - } else if (tilemap->get_autotileset(tile)->is_corner()) { + } + else if (tilemap->get_autotileset(tile)->is_corner()) + { input_autotile_corner(hovered_corner + add_tile, tile, target_tile + add_tile); - } else { + } + else + { input_autotile(target_tile + add_tile, tile); } - } else { + } + else + { input_tile(target_tile + add_tile, tile); } @@ -262,15 +274,16 @@ namespace { // segment from pos1 to pos2 (similarly to a line drawing algorithm) std::vector rasterize_line_segment(Vector pos1, Vector pos2) { - if (pos1 == pos2) - return std::vector {pos1}; + if (pos1 == pos2) return std::vector {pos1}; // An integer position (x, y) contains all floating point vectors in // [x, x+1) x [y, y+1) std::vector positions; Vector diff = pos2 - pos1; - if (fabsf(diff.x) > fabsf(diff.y)) { + if (fabsf(diff.x) > fabsf(diff.y)) + { // Go along X, from left to right - if (diff.x < 0) { + if (diff.x < 0) + { Vector tmp = pos1; pos1 = pos2; pos2 = tmp; @@ -280,10 +293,12 @@ namespace { float y_step = diff.y / diff.x; // The x coordinate of the first vertical grid line right of pos1 float x_first_gridline = floorf(pos1.x + 1.0f); - for (float x = x_first_gridline; x < pos2.x; ++x) { + for (float x = x_first_gridline; x < pos2.x; ++x) + { // The y coordinate where our line intersects the vertical grid line float y = pos1.y + (x - pos1.x) * y_step; - if (floorf(y) != floorf(y_prev)) { + if (floorf(y) != floorf(y_prev)) + { // The current position is one horizontal grid line higher than // the previous one, // so add the position left to the current vertical grid line @@ -293,14 +308,18 @@ namespace { // Add the position right to the current vertical grid line positions.emplace_back(Vector(x + 0.5f, y)); } - if (x_first_gridline > pos2.x && floorf(pos2.y) != floorf(pos1.y)) { + if (x_first_gridline > pos2.x && floorf(pos2.y) != floorf(pos1.y)) + { // Special case: a single horizontal grid line is crossed with an acute // angle but no vertical grid line, so the for loop was skipped positions.emplace_back(pos2); } - } else { + } + else + { // Go along Y, from top to bottom - if (diff.y < 0) { + if (diff.y < 0) + { Vector tmp = pos1; pos1 = pos2; pos2 = tmp; @@ -309,20 +328,23 @@ namespace { float x_prev = pos1.x; float x_step = diff.x / diff.y; float y_first_gridline = floorf(pos1.y + 1.0f); - for (float y = y_first_gridline; y < pos2.y; ++y) { + for (float y = y_first_gridline; y < pos2.y; ++y) + { float x = pos1.x + (y - pos1.y) * x_step; - if (floorf(x) != floorf(x_prev)) { + if (floorf(x) != floorf(x_prev)) + { positions.emplace_back(Vector(x, y - 0.5f)); x_prev = x; } positions.emplace_back(Vector(x, y + 0.5f)); } - if (y_first_gridline > pos2.y && floorf(pos2.x) != floorf(pos1.x)) { + if (y_first_gridline > pos2.y && floorf(pos2.x) != floorf(pos1.x)) + { positions.emplace_back(pos2); } } return positions; - }; + } } // namespace void @@ -332,7 +354,8 @@ EditorOverlayWidget::put_next_tiles() int expired_ms = static_cast(std::chrono::duration_cast< std::chrono::milliseconds>(time_now - m_time_prev_put_tile).count()); m_time_prev_put_tile = time_now; - if (expired_ms > 70) { + if (expired_ms > 70) + { // Avoid drawing lines when the user has hold the left mouse button for some // time while not putting a tile put_tile(m_hovered_tile); @@ -342,7 +365,8 @@ EditorOverlayWidget::put_next_tiles() // Interpolate on a sub-grid with twice width and height because autotiling // needs to know the closest corner for (const Vector &pos : rasterize_line_segment(m_hovered_tile_prev * 2.0f, - m_hovered_tile * 2.0f)) { + m_hovered_tile * 2.0f)) + { put_tile(pos * 0.5f); } m_hovered_tile_prev = m_hovered_tile; @@ -361,9 +385,11 @@ EditorOverlayWidget::preview_rectangle() m_rectangle_preview->m_width = static_cast(dr.get_width()) + 1; m_rectangle_preview->m_height = static_cast(dr.get_height()) + 1; int y_ = sgn_y ? 0 : static_cast(-dr.get_height()); - for (int y = static_cast(dr.get_top()); y <= static_cast(dr.get_bottom()); y++, y_++) { + for (int y = static_cast(dr.get_top()); y <= static_cast(dr.get_bottom()); y++, y_++) + { int x_ = sgn_x ? 0 : static_cast(-dr.get_width()); - for (int x = static_cast(dr.get_left()); x <= static_cast(dr.get_right()); x++, x_++) { + for (int x = static_cast(dr.get_left()); x <= static_cast(dr.get_right()); x++, x_++) + { m_rectangle_preview->m_tiles.push_back(m_editor.get_tiles()->pos(x_, y_)); } } @@ -380,14 +406,15 @@ EditorOverlayWidget::draw_rectangle() bool sgn_y = m_drag_start.y < m_sector_pos.y; int x_ = sgn_x ? 0 : static_cast(-dr.get_width()); - for (int x = static_cast(dr.get_left()); x <= static_cast(dr.get_right()); x++, x_++) { + for (int x = static_cast(dr.get_left()); x <= static_cast(dr.get_right()); x++, x_++) + { int y_ = sgn_y ? 0 : static_cast(-dr.get_height()); - for (int y = static_cast(dr.get_top()); y <= static_cast(dr.get_bottom()); y++, y_++) { - if (g_config->editor_autotile_mode) { - input_autotile( Vector(static_cast(x), static_cast(y)), m_editor.get_tiles()->pos(x_, y_) ); - } else { - input_tile( Vector(static_cast(x), static_cast(y)), m_editor.get_tiles()->pos(x_, y_) ); - } + for (int y = static_cast(dr.get_top()); y <= static_cast(dr.get_bottom()); y++, y_++) + { + if (g_config->editor_autotile_mode) + input_autotile(Vector(static_cast(x), static_cast(y)), m_editor.get_tiles()->pos(x_, y_)); + else + input_tile(Vector(static_cast(x), static_cast(y)), m_editor.get_tiles()->pos(x_, y_)); } } } @@ -397,12 +424,15 @@ EditorOverlayWidget::check_tiles_for_fill(uint32_t replace_tile, uint32_t target_tile, uint32_t third_tile) const { - if (g_config->editor_autotile_mode) { + if (g_config->editor_autotile_mode) + { return m_editor.get_tileset()->get_autotileset_from_tile(replace_tile) == m_editor.get_tileset()->get_autotileset_from_tile(target_tile) && m_editor.get_tileset()->get_autotileset_from_tile(replace_tile) != m_editor.get_tileset()->get_autotileset_from_tile(third_tile); - } else { + } + else + { return replace_tile == target_tile && replace_tile != third_tile; } } @@ -412,14 +442,13 @@ EditorOverlayWidget::fill() { auto tiles = m_editor.get_tiles(); auto tilemap = m_editor.get_selected_tilemap(); - if (!tilemap) { - return; - } + if (!tilemap) return; // The tile that is going to be replaced: - Uint32 replace_tile = tilemap->get_tile_id(static_cast(m_hovered_tile.x), static_cast(m_hovered_tile.y)); + uint32_t replace_tile = tilemap->get_tile_id(static_cast(m_hovered_tile.x), static_cast(m_hovered_tile.y)); - if (replace_tile == tiles->pos(0, 0)) { + if (replace_tile == tiles->pos(0, 0)) + { // Replacing by the same tiles shouldn't do anything. return; } @@ -429,9 +458,11 @@ EditorOverlayWidget::fill() pos_stack.push_back(m_hovered_tile); // Passing recursively trough all tiles to be replaced... - while (pos_stack.size()) { + while (pos_stack.size()) + { - if (pos_stack.size() > 1000000) { + if (pos_stack.size() > 1000000) + { log_warning << "More than 1'000'000 tiles in stack to fill, STOP" << std::endl; return; } @@ -453,10 +484,12 @@ EditorOverlayWidget::fill() // Going left... pos_ = pos + Vector(-1, 0); - if (pos_.x >= 0) { + if (pos_.x >= 0) + { if (check_tiles_for_fill(replace_tile, tilemap->get_tile_id(static_cast(pos_.x), static_cast(pos_.y)), - tiles->pos(static_cast(tpos.x - 1), static_cast(tpos.y)))) { + tiles->pos(static_cast(tpos.x - 1), static_cast(tpos.y)))) + { pos_stack.push_back( pos_ ); continue; } @@ -464,10 +497,12 @@ EditorOverlayWidget::fill() // Going right... pos_ = pos + Vector(1, 0); - if (pos_.x < static_cast(tilemap->get_width())) { + if (pos_.x < static_cast(tilemap->get_width())) + { if (check_tiles_for_fill(replace_tile, tilemap->get_tile_id(static_cast(pos_.x), static_cast(pos_.y)), - tiles->pos(static_cast(tpos.x + 1), static_cast(tpos.y)))) { + tiles->pos(static_cast(tpos.x + 1), static_cast(tpos.y)))) + { pos_stack.push_back( pos_ ); continue; } @@ -475,10 +510,12 @@ EditorOverlayWidget::fill() // Going up... pos_ = pos + Vector(0, -1); - if (pos_.y >= 0) { + if (pos_.y >= 0) + { if (check_tiles_for_fill(replace_tile, tilemap->get_tile_id(static_cast(pos_.x), static_cast(pos_.y)), - tiles->pos(static_cast(tpos.x), static_cast(tpos.y - 1)))) { + tiles->pos(static_cast(tpos.x), static_cast(tpos.y - 1)))) + { pos_stack.push_back( pos_ ); continue; } @@ -486,25 +523,51 @@ EditorOverlayWidget::fill() // Going down... pos_ = pos + Vector(0, 1); - if (pos_.y < static_cast(tilemap->get_height())) { + if (pos_.y < static_cast(tilemap->get_height())) + { if (check_tiles_for_fill(replace_tile, tilemap->get_tile_id(static_cast(pos_.x), static_cast(pos_.y)), - tiles->pos(static_cast(tpos.x), static_cast(tpos.y + 1)))) { + tiles->pos(static_cast(tpos.x), static_cast(tpos.y + 1)))) + { pos_stack.push_back( pos_ ); continue; } } // Autotile happens after directional detection (because of borders; see snow tileset) - if (g_config->editor_autotile_mode) { + if (g_config->editor_autotile_mode) input_autotile(pos, tiles->pos(static_cast(tpos.x), static_cast(tpos.y))); - } // When tiles on each side are already filled or occupied by another tiles, it ends. pos_stack.pop_back(); } } +void +EditorOverlayWidget::replace() +{ + auto tilemap = m_editor.get_selected_tilemap(); + uint32_t replace_tile = tilemap->get_tile_id(static_cast(m_hovered_tile.x), static_cast(m_hovered_tile.y)); + + // Don't do anything if the old and new tiles are the same tile. + if (m_editor.get_tiles()->m_width == 1 && m_editor.get_tiles()->m_height == 1 && replace_tile == m_editor.get_tiles()->pos(0, 0)) return; + + tilemap->save_state(); + for (int x = 0; x < tilemap->get_width(); ++x) + { + for (int y = 0; y < tilemap->get_height(); ++y) + { + if (tilemap->get_tile_id(x, y) == replace_tile) + { + tilemap->change(x, y, m_editor.get_tiles()->pos( + (x - static_cast(m_hovered_tile.x)) % m_editor.get_tiles()->m_width, + (y - static_cast(m_hovered_tile.y)) % m_editor.get_tiles()->m_height) + ); + } + } + } +} + void EditorOverlayWidget::hover_object() { @@ -519,8 +582,10 @@ EditorOverlayWidget::hover_object() for (auto& moving_object : m_editor.get_sector()->get_objects_by_type()) { Rectf bbox = moving_object.get_bbox(); - if (bbox.contains(m_sector_pos)) { - if (&moving_object != m_hovered_object) { + if (bbox.contains(m_sector_pos)) + { + if (&moving_object != m_hovered_object) + { // Ignore BezierMarkers if ctrl isn't pressed... (1/2) auto* bezier_marker = dynamic_cast(&moving_object); @@ -577,7 +642,8 @@ EditorOverlayWidget::edit_path(PathGameObject* path, GameObject* new_marked_obje if (!path) return; delete_markers(); - if (!path->is_valid()) { + if (!path->is_valid()) + { m_edited_path = nullptr; return; } @@ -604,15 +670,16 @@ EditorOverlayWidget::select_object() delete_markers(); if (!m_dragged_object || !m_dragged_object->is_valid()) return; - if (m_dragged_object->has_variable_size()) { + if (m_dragged_object->has_variable_size()) + { m_selected_object = m_dragged_object; m_dragged_object->editor_select(); return; } auto path_obj = dynamic_cast(m_dragged_object.get()); - if (path_obj && path_obj->get_path_gameobject()) - { + + if (path_obj && path_obj->get_path_gameobject()) { edit_path(path_obj->get_path_gameobject(), m_dragged_object.get()); } } @@ -620,7 +687,8 @@ EditorOverlayWidget::select_object() void EditorOverlayWidget::grab_object() { - if (m_hovered_object) { + if (m_hovered_object) + { if (!m_hovered_object->is_valid()) { m_hovered_object = nullptr; @@ -633,9 +701,8 @@ EditorOverlayWidget::grab_object() m_dragged_object->save_state(); auto* pm = dynamic_cast(m_hovered_object.get()); - if (!pm) { - select_object(); - } + if (!pm) select_object(); + m_last_node_marker = dynamic_cast(pm); } } @@ -648,7 +715,9 @@ EditorOverlayWidget::grab_object() m_edited_path->is_valid()) { // do nothing - } else { + } + else + { delete_markers(); } } @@ -657,8 +726,10 @@ EditorOverlayWidget::grab_object() void EditorOverlayWidget::clone_object() { - if (m_hovered_object && m_hovered_object->is_saveable()) { - if (!m_hovered_object->is_valid()) { + if (m_hovered_object && m_hovered_object->is_saveable()) + { + if (!m_hovered_object->is_valid()) + { m_hovered_object = nullptr; return; } @@ -705,20 +776,22 @@ EditorOverlayWidget::show_object_menu(GameObject& object) void EditorOverlayWidget::move_object() { - if (m_dragged_object) { - if (!m_dragged_object->is_valid()) { + if (m_dragged_object) + { + if (!m_dragged_object->is_valid()) + { m_dragged_object = nullptr; return; } Vector new_pos = m_sector_pos - m_obj_mouse_desync; - if (g_config->editor_snap_to_grid) { + if (g_config->editor_snap_to_grid) + { auto& snap_grid_size = snap_grid_sizes[g_config->editor_selected_snap_grid_size]; new_pos = glm::floor(new_pos / static_cast(snap_grid_size)) * static_cast(snap_grid_size); auto pm = dynamic_cast(m_dragged_object.get()); - if (pm) { + if (pm) new_pos -= pm->get_offset(); - } } // TODO: Temporarily disabled during ongoing discussion @@ -745,9 +818,11 @@ EditorOverlayWidget::rubber_object() if (!m_edited_path) { delete_markers(); } + if (m_dragged_object) { m_dragged_object->editor_delete(); } + m_last_node_marker = nullptr; } @@ -756,11 +831,13 @@ EditorOverlayWidget::rubber_rect() { delete_markers(); Rectf dr = drag_rect(); - for (auto& moving_object : m_editor.get_sector()->get_objects_by_type()) { + for (auto& moving_object : m_editor.get_sector()->get_objects_by_type()) + { Rectf bbox = moving_object.get_bbox(); if (dr.contains(bbox)) { moving_object.editor_delete(); } + } m_last_node_marker = nullptr; } @@ -772,7 +849,8 @@ EditorOverlayWidget::update_node_iterators() if (!m_edited_path->is_valid()) return; auto* sector = m_editor.get_sector(); - for (auto& moving_object : sector->get_objects_by_type()) { + for (auto& moving_object : sector->get_objects_by_type()) + { auto marker = dynamic_cast(&moving_object); if (marker) { marker->update_iterator(); @@ -834,7 +912,8 @@ EditorOverlayWidget::put_object() object->after_editor_set(); auto* mo = dynamic_cast (object.get()); - if (mo && !g_config->editor_snap_to_grid) { + if (mo && !g_config->editor_snap_to_grid) + { auto bbox = mo->get_bbox(); mo->move_to(mo->get_pos() - Vector(bbox.get_width() / 2, bbox.get_height() / 2)); } @@ -851,8 +930,7 @@ EditorOverlayWidget::put_object() void EditorOverlayWidget::process_left_click() { - if (MenuManager::instance().has_dialog()) - return; + if (MenuManager::instance().has_dialog()) return; m_dragging = true; m_dragging_right = false; m_drag_start = m_sector_pos; @@ -876,6 +954,10 @@ EditorOverlayWidget::process_left_click() fill(); break; + case 3: + replace(); + break; + default: break; } @@ -896,11 +978,12 @@ EditorOverlayWidget::process_left_click() break; } - if (!m_editor.get_tileselect_object().empty()) { - if (!m_dragged_object) { - put_object(); - } - } else { + if (!m_editor.get_tileselect_object().empty()) + { + if (!m_dragged_object) put_object(); + } + else + { rubber_object(); } break; @@ -977,9 +1060,7 @@ EditorOverlayWidget::update_tile_selection() Rectf select = tile_drag_rect(); auto tiles = m_editor.get_tiles(); auto tilemap = m_editor.get_selected_tilemap(); - if (!tilemap) { - return; - } + if (!tilemap) return; tiles->m_tiles.clear(); tiles->m_width = static_cast(select.get_width()); @@ -987,11 +1068,16 @@ EditorOverlayWidget::update_tile_selection() int w = static_cast(tilemap->get_width()); int h = static_cast(tilemap->get_height()); - for (int y = static_cast(select.get_top()); y < static_cast(select.get_bottom()); y++) { - for (int x = static_cast(select.get_left()); x < static_cast(select.get_right()); x++) { - if ( x < 0 || y < 0 || x >= w || y >= h) { + for (int y = static_cast(select.get_top()); y < static_cast(select.get_bottom()); y++) + { + for (int x = static_cast(select.get_left()); x < static_cast(select.get_right()); x++) + { + if ( x < 0 || y < 0 || x >= w || y >= h) + { tiles->m_tiles.push_back(0); - } else { + } + else + { tiles->m_tiles.push_back(tilemap->get_tile_id(x, y)); } } @@ -1015,12 +1101,15 @@ EditorOverlayWidget::on_mouse_button_up(const SDL_MouseButtonEvent& button) } else if (m_editor.get_tileselect_input_type() == EditorToolboxWidget::InputType::OBJECT) { - if (m_dragging && m_dragged_object) + if (m_dragging && m_dragged_object) { m_dragged_object->check_state(); + } } } else if (button.button == SDL_BUTTON_MIDDLE) + { m_scrolling = false; + } m_dragging = false; @@ -1062,10 +1151,14 @@ EditorOverlayWidget::on_mouse_motion(const SDL_MouseMotionEvent& motion) switch (m_editor.get_tileselect_input_type()) { case EditorToolboxWidget::InputType::TILE: - if (m_dragging_right) { + if (m_dragging_right) + { update_tile_selection(); - } else { - switch (m_editor.get_tileselect_select_mode()) { + } + else + { + switch (m_editor.get_tileselect_select_mode()) + { case 0: put_next_tiles(); break; @@ -1079,11 +1172,15 @@ EditorOverlayWidget::on_mouse_motion(const SDL_MouseMotionEvent& motion) break; case EditorToolboxWidget::InputType::OBJECT: - if (m_editor.get_tileselect_object().empty()) { - if (m_editor.get_tileselect_select_mode() == 1) { + if (m_editor.get_tileselect_object().empty()) + { + if (m_editor.get_tileselect_select_mode() == 1) + { rubber_rect(); } - } else { + } + else + { move_object(); } break; @@ -1109,11 +1206,11 @@ bool EditorOverlayWidget::on_key_up(const SDL_KeyboardEvent& key) { auto sym = key.keysym.sym; - if (sym == SDLK_LSHIFT) - { + if (sym == SDLK_LSHIFT) { g_config->editor_snap_to_grid = !g_config->editor_snap_to_grid; } - if (sym == SDLK_LCTRL || sym == SDLK_RCTRL) { + if (sym == SDLK_LCTRL || sym == SDLK_RCTRL) + { if (action_pressed) { g_config->editor_autotile_mode = !g_config->editor_autotile_mode; @@ -1138,7 +1235,8 @@ EditorOverlayWidget::on_key_down(const SDL_KeyboardEvent& key) if (sym == SDLK_F7 || sym == SDLK_LSHIFT) { g_config->editor_snap_to_grid = !g_config->editor_snap_to_grid; } - if (sym == SDLK_F5 || ((sym == SDLK_LCTRL || sym == SDLK_RCTRL) && !action_pressed)) { + if (sym == SDLK_F5 || ((sym == SDLK_LCTRL || sym == SDLK_RCTRL) && !action_pressed)) + { g_config->editor_autotile_mode = !g_config->editor_autotile_mode; action_pressed = true; // Hovered objects depend on which keys are pressed @@ -1153,8 +1251,7 @@ EditorOverlayWidget::on_key_down(const SDL_KeyboardEvent& key) void EditorOverlayWidget::update_pos() { - if(m_editor.get_sector() == nullptr) - return; + if(m_editor.get_sector() == nullptr) return; m_sector_pos = m_mouse_pos + m_editor.get_sector()->get_camera().get_translation(); m_hovered_tile = sp_to_tp(m_sector_pos); @@ -1166,23 +1263,22 @@ EditorOverlayWidget::update_pos() void EditorOverlayWidget::draw_tile_tip(DrawingContext& context) { - if ( m_editor.get_tileselect_input_type() == EditorToolboxWidget::InputType::TILE ) { - + if (m_editor.get_tileselect_input_type() == EditorToolboxWidget::InputType::TILE) + { auto tilemap = m_editor.get_selected_tilemap(); - if (!tilemap) { - return; - } + if (!tilemap) return; - if (m_editor.get_tiles()->empty()) - return; + if (m_editor.get_tiles()->empty()) return; Vector screen_corner = context.get_cliprect().p2() + m_editor.get_sector()->get_camera().get_translation(); Vector drawn_tile = m_hovered_tile; // FIXME: Why is this initialised if it's going to be overwritten right below? auto tiles = m_editor.get_tiles(); - for (drawn_tile.x = static_cast(tiles->m_width) - 1.0f; drawn_tile.x >= 0.0f; drawn_tile.x--) { - for (drawn_tile.y = static_cast(tiles->m_height) - 1.0f; drawn_tile.y >= 0.0f; drawn_tile.y--) { + for (drawn_tile.x = static_cast(tiles->m_width) - 1.0f; drawn_tile.x >= 0.0f; drawn_tile.x--) + { + for (drawn_tile.y = static_cast(tiles->m_height) - 1.0f; drawn_tile.y >= 0.0f; drawn_tile.y--) + { Vector on_tile = m_hovered_tile + drawn_tile; if (on_tile.x < 0 || @@ -1190,18 +1286,19 @@ EditorOverlayWidget::draw_tile_tip(DrawingContext& context) on_tile.x >= static_cast(tilemap->get_width()) || on_tile.y >= static_cast(tilemap->get_height()) || on_tile.x >= ceilf(screen_corner.x / 32) || - on_tile.y >= ceilf(screen_corner.y / 32)) { + on_tile.y >= ceilf(screen_corner.y / 32)) + { continue; } uint32_t tile_id = tiles->pos(static_cast(drawn_tile.x), static_cast(drawn_tile.y)); draw_tile(context.color(), *m_editor.get_tileset(), tile_id, align_to_tilemap(on_tile) - m_editor.get_sector()->get_camera().get_translation(), LAYER_GUI-11, Color(1, 1, 1, 0.5)); - /*if (tile_id) { - const Tile* tg_tile = m_editor.get_tileset()->get( tile_id ); - tg_tile->draw(context.color(), tp_to_sp(on_tile) - m_editor.get_sector()->camera->get_translation(), - LAYER_GUI-11, Color(1, 1, 1, 0.5)); - }*/ + //if (tile_id) { + //const Tile* tg_tile = m_editor.get_tileset()->get( tile_id ); + //tg_tile->draw(context.color(), tp_to_sp(on_tile) - m_editor.get_sector()->camera->get_translation(), + // LAYER_GUI-11, Color(1, 1, 1, 0.5)); + //} } } } @@ -1211,12 +1308,9 @@ void EditorOverlayWidget::draw_rectangle_preview(DrawingContext& context) { auto tilemap = m_editor.get_selected_tilemap(); - if (!tilemap) { - return; - } + if (!tilemap) return; - if (m_rectangle_preview->empty()) - return; + if (m_rectangle_preview->empty()) return; Vector screen_corner = context.get_cliprect().p2() + m_editor.get_sector()->get_camera().get_translation(); @@ -1225,8 +1319,10 @@ EditorOverlayWidget::draw_rectangle_preview(DrawingContext& context) std::min(sp_to_tp(m_drag_start).y, m_hovered_tile.y)); auto tiles = m_rectangle_preview.get(); - for (drawn_tile.x = static_cast(tiles->m_width) - 1.0f; drawn_tile.x >= 0.0f; drawn_tile.x--) { - for (drawn_tile.y = static_cast(tiles->m_height) - 1.0f; drawn_tile.y >= 0.0f; drawn_tile.y--) { + for (drawn_tile.x = static_cast(tiles->m_width) - 1.0f; drawn_tile.x >= 0.0f; drawn_tile.x--) + { + for (drawn_tile.y = static_cast(tiles->m_height) - 1.0f; drawn_tile.y >= 0.0f; drawn_tile.y--) + { Vector on_tile = corner + drawn_tile; if (on_tile.x < 0 || @@ -1234,7 +1330,8 @@ EditorOverlayWidget::draw_rectangle_preview(DrawingContext& context) on_tile.x >= static_cast(tilemap->get_width()) || on_tile.y >= static_cast(tilemap->get_height()) || on_tile.x >= ceilf(screen_corner.x / 32) || - on_tile.y >= ceilf(screen_corner.y / 32)) { + on_tile.y >= ceilf(screen_corner.y / 32)) + { continue; } uint32_t tile_id = tiles->pos(static_cast(drawn_tile.x), static_cast(drawn_tile.y)); @@ -1250,8 +1347,7 @@ EditorOverlayWidget::draw_tile_grid(DrawingContext& context, int tile_size, bool draw_shadow) const { auto current_tm = m_editor.get_selected_tilemap(); - if (current_tm == nullptr) - return; + if (current_tm == nullptr) return; int tm_width = current_tm->get_width() * (32 / tile_size); int tm_height = current_tm->get_height() * (32 / tile_size); @@ -1272,12 +1368,14 @@ EditorOverlayWidget::draw_tile_grid(DrawingContext& context, int tile_size, { context.color().draw_line(from, to, col, current_tm->get_layer()); }; - if (draw_shadow) { + if (draw_shadow) + { Vector viewport_scale = VideoSystem::current()->get_viewport().get_scale(); const Color shadow_colour(0.0f, 0.0f, 0.0f, 0.05f); const Vector shadow_offset(1.0f / viewport_scale.x, 1.0f / viewport_scale.y); - for (int i = static_cast(start.x); i <= static_cast(end.x); i++) { + for (int i = static_cast(start.x); i <= static_cast(end.x); i++) + { line_start = tile_screen_pos(Vector(static_cast(i), 0.0f), tile_size) + shadow_offset; line_end = tile_screen_pos(Vector(static_cast(i), end.y), @@ -1285,7 +1383,8 @@ EditorOverlayWidget::draw_tile_grid(DrawingContext& context, int tile_size, draw_line(line_start, line_end, shadow_colour); } - for (int i = static_cast(start.y); i <= static_cast(end.y); i++) { + for (int i = static_cast(start.y); i <= static_cast(end.y); i++) + { line_start = tile_screen_pos(Vector(0.0f, static_cast(i)), tile_size) + shadow_offset; line_end = tile_screen_pos(Vector(end.x, static_cast(i)), @@ -1295,13 +1394,15 @@ EditorOverlayWidget::draw_tile_grid(DrawingContext& context, int tile_size, } const Color line_color(1.f, 1.f, 1.f, 0.2f); - for (int i = static_cast(start.x); i <= static_cast(end.x); i++) { + for (int i = static_cast(start.x); i <= static_cast(end.x); i++) + { line_start = tile_screen_pos(Vector(static_cast(i), 0.0f), tile_size); line_end = tile_screen_pos(Vector(static_cast(i), end.y), tile_size); draw_line(line_start, line_end, line_color); } - for (int i = static_cast(start.y); i <= static_cast(end.y); i++) { + for (int i = static_cast(start.y); i <= static_cast(end.y); i++) + { line_start = tile_screen_pos(Vector(0.0f, static_cast(i)), tile_size); line_end = tile_screen_pos(Vector(end.x, static_cast(i)), tile_size); draw_line(line_start, line_end, line_color); @@ -1311,11 +1412,10 @@ EditorOverlayWidget::draw_tile_grid(DrawingContext& context, int tile_size, void EditorOverlayWidget::draw_tilemap_border(DrawingContext& context) { - if ( !m_editor.get_selected_tilemap() ) return; + if (!m_editor.get_selected_tilemap()) return; auto current_tm = m_editor.get_selected_tilemap(); - if (!current_tm) - return; + if (!current_tm) return; Vector start = tile_screen_pos( Vector(0, 0) ); Vector end = tile_screen_pos( Vector(static_cast(current_tm->get_width()), @@ -1334,15 +1434,20 @@ EditorOverlayWidget::draw_path(DrawingContext& context) if (!m_selected_object->is_valid()) return; if (!m_edited_path->is_valid()) return; - for (auto i = m_edited_path->get_path().m_nodes.begin(); i != m_edited_path->get_path().m_nodes.end(); ++i) { + for (auto i = m_edited_path->get_path().m_nodes.begin(); i != m_edited_path->get_path().m_nodes.end(); ++i) + { auto j = i+1; Path::Node* node1 = &(*i); Path::Node* node2; - if (j == m_edited_path->get_path().m_nodes.end()) { - if (m_edited_path->get_path().m_mode == WalkMode::CIRCULAR) { + if (j == m_edited_path->get_path().m_nodes.end()) + { + if (m_edited_path->get_path().m_mode == WalkMode::CIRCULAR) + { //loop to the first node node2 = &(*m_edited_path->get_path().m_nodes.begin()); - } else { + } + else + { // Just draw the bezier lines auto cam_translation = m_editor.get_sector()->get_camera().get_translation(); context.color().draw_line(node1->position - cam_translation, @@ -1353,7 +1458,9 @@ EditorOverlayWidget::draw_path(DrawingContext& context) Color(0, 0, 1), LAYER_GUI - 21); continue; } - } else { + } + else + { node2 = &(*j); } auto cam_translation = m_editor.get_sector()->get_camera().get_translation(); @@ -1384,11 +1491,13 @@ EditorOverlayWidget::draw(DrawingContext& context) draw_rectangle_preview(context); draw_path(context); - if (g_config->editor_render_grid) { + if (g_config->editor_render_grid) + { draw_tile_grid(context, 32, true); draw_tilemap_border(context); auto snap_grid_size = snap_grid_sizes[g_config->editor_selected_snap_grid_size]; - if (snap_grid_size != 32) { + if (snap_grid_size != 32) + { draw_tile_grid(context, snap_grid_size, false); } } @@ -1398,7 +1507,8 @@ EditorOverlayWidget::draw(DrawingContext& context) } if (m_dragging && m_editor.get_tileselect_select_mode() == 1 - && !m_dragging_right) { + && !m_dragging_right) + { // Draw selection rectangle... auto cam_translation = m_editor.get_sector()->get_camera().get_translation(); Vector p0 = m_drag_start - cam_translation; @@ -1406,9 +1516,11 @@ EditorOverlayWidget::draw(DrawingContext& context) if (p0.x > p3.x) { std::swap(p0.x, p3.x); } + if (p0.y > p3.y) { std::swap(p0.y, p3.y); } + Vector p1 = Vector(p0.x, p3.y); Vector p2 = Vector(p3.x, p0.y); @@ -1425,27 +1537,39 @@ EditorOverlayWidget::draw(DrawingContext& context) Color(0.0f, 1.0f, 0.0f, 0.2f), 0.0f, LAYER_GUI-5); } - if (m_dragging && m_dragging_right) { + if (m_dragging && m_dragging_right) + { context.color().draw_filled_rect(selection_draw_rect(), Color(0.2f, 0.4f, 1.0f, 0.6f), 0.0f, LAYER_GUI-13); } - if (g_config->editor_autotile_help) { + if (g_config->editor_autotile_help) + { if (m_editor.get_tileset()->get_autotileset_from_tile(m_editor.get_tiles()->pos(0, 0)) != nullptr) { - if (g_config->editor_autotile_mode) { + if (g_config->editor_autotile_mode) + { context.color().draw_text(Resources::normal_font, _("Autotile mode is on"), Vector(144, 16), ALIGN_LEFT, LAYER_OBJECTS+1, EditorOverlayWidget::text_autotile_active_color); - } else { + } + else + { context.color().draw_text(Resources::normal_font, _("Hold Ctrl to enable autotile"), Vector(144, 16), ALIGN_LEFT, LAYER_OBJECTS+1, EditorOverlayWidget::text_autotile_available_color); } - } else if (g_config->editor_autotile_mode) { - if (m_editor.get_tiles()->pos(0, 0) == 0) { + } + else if (g_config->editor_autotile_mode) + { + if (m_editor.get_tiles()->pos(0, 0) == 0) + { context.color().draw_text(Resources::normal_font, _("Autotile erasing mode is on"), Vector(144, 16), ALIGN_LEFT, LAYER_OBJECTS+1, EditorOverlayWidget::text_autotile_active_color); - } else { + } + else + { context.color().draw_text(Resources::normal_font, _("Selected tile isn't autotileable"), Vector(144, 16), ALIGN_LEFT, LAYER_OBJECTS+1, EditorOverlayWidget::text_autotile_error_color); } - } else if (m_editor.get_tiles()->pos(0, 0) == 0) { + } + else if (m_editor.get_tiles()->pos(0, 0) == 0) + { context.color().draw_text(Resources::normal_font, _("Hold Ctrl to enable autotile erasing"), Vector(144, 16), ALIGN_LEFT, LAYER_OBJECTS+1, EditorOverlayWidget::text_autotile_available_color); } } @@ -1456,10 +1580,7 @@ Vector EditorOverlayWidget::tp_to_sp(const Vector& tp, int tile_size) const { auto tilemap = m_editor.get_selected_tilemap(); - if (!tilemap) - { - return Vector(0, 0); - } + if (!tilemap) return Vector(0, 0); Vector sp = tp * static_cast(tile_size); return sp + tilemap->get_offset(); @@ -1469,10 +1590,7 @@ Vector EditorOverlayWidget::sp_to_tp(const Vector& sp, int tile_size) const { auto tilemap = m_editor.get_selected_tilemap(); - if (!tilemap) - { - return Vector(0, 0); - } + if (!tilemap) return Vector(0, 0); Vector sp_ = sp - tilemap->get_offset(); return sp_ / static_cast(tile_size); @@ -1489,10 +1607,7 @@ Vector EditorOverlayWidget::align_to_tilemap(const Vector& sp, int tile_size) const { auto tilemap = m_editor.get_selected_tilemap(); - if (!tilemap) - { - return Vector(0, 0); - } + if (!tilemap) return Vector(0, 0); Vector sp_ = sp + tilemap->get_offset() / static_cast(tile_size); return glm::trunc(sp_) * static_cast(tile_size); diff --git a/src/editor/overlay_widget.hpp b/src/editor/overlay_widget.hpp index 63e0b2801ca..ac322d94cc8 100644 --- a/src/editor/overlay_widget.hpp +++ b/src/editor/overlay_widget.hpp @@ -83,6 +83,7 @@ class EditorOverlayWidget final : public Widget void preview_rectangle(); bool check_tiles_for_fill(uint32_t replace_tile, uint32_t target_tile, uint32_t third_tile) const; void fill(); + void replace(); void put_object(); void rubber_object(); diff --git a/src/editor/toolbox_widget.cpp b/src/editor/toolbox_widget.cpp index a5b38f8bb64..62076b34346 100644 --- a/src/editor/toolbox_widget.cpp +++ b/src/editor/toolbox_widget.cpp @@ -65,6 +65,7 @@ EditorToolboxWidget::EditorToolboxWidget(Editor& editor) : { m_select_mode->push_mode("images/engine/editor/select-mode1.png"); m_select_mode->push_mode("images/engine/editor/select-mode2.png"); + m_select_mode->push_mode("images/engine/editor/select-mode3.png"); m_move_mode->push_mode("images/engine/editor/move-mode1.png"); m_undo_mode->push_mode("images/engine/editor/redo.png"); //settings_mode->push_mode("images/engine/editor/settings-mode1.png"); diff --git a/src/gui/menu_filesystem.cpp b/src/gui/menu_filesystem.cpp index a37c70d6217..2fc4e864df5 100644 --- a/src/gui/menu_filesystem.cpp +++ b/src/gui/menu_filesystem.cpp @@ -71,31 +71,24 @@ FileSystemMenu::refresh_items() if (m_directory != "/") { m_directories.push_back(".."); } - - char** dir_files = PHYSFS_enumerateFiles(m_directory.c_str()); - if (dir_files) - { - for (const char* const* file = dir_files; *file != nullptr; ++file) + physfsutil::enumerate_files(m_directory, [this](const std::string& file) { + std::string filepath = FileSystem::join(m_directory, file); + if (physfsutil::is_directory(filepath)) { - std::string filepath = FileSystem::join(m_directory, *file); - if (physfsutil::is_directory(filepath)) - { - m_directories.push_back(*file); + m_directories.push_back(file); + } + else + { + if (AddonManager::current()->is_from_old_addon(filepath)) { + return; } - else - { - if (AddonManager::current()->is_from_old_addon(filepath)) { - continue; - } - if (has_right_suffix(*file)) - { - m_files.push_back(*file); - } + if (has_right_suffix(file)) + { + m_files.push_back(file); } } - PHYSFS_freeList(dir_files); - } + }); for (const auto& item : m_directories) { diff --git a/src/object/tilemap.cpp b/src/object/tilemap.cpp index a9aadd9f5a4..d3a3c744a42 100644 --- a/src/object/tilemap.cpp +++ b/src/object/tilemap.cpp @@ -677,7 +677,9 @@ TileMap::get_tile_at(const Vector& pos) const void TileMap::change(int x, int y, uint32_t newtile) { - assert(x >= 0 && x < m_width && y >= 0 && y < m_height); + if(x < 0 || x >= m_width || y < 0 || y >= m_height) + return; + m_tiles[y*m_width + x] = newtile; } diff --git a/src/physfs/physfs_file_system.cpp b/src/physfs/physfs_file_system.cpp index dbb8d20a00c..2356e086c97 100644 --- a/src/physfs/physfs_file_system.cpp +++ b/src/physfs/physfs_file_system.cpp @@ -19,6 +19,7 @@ #include #include "physfs/ifile_stream.hpp" +#include "physfs/util.hpp" PhysFSFileSystem::PhysFSFileSystem() { @@ -28,14 +29,9 @@ std::vector PhysFSFileSystem::open_directory(const std::string& pathname) { std::vector files; - - char** directory = PHYSFS_enumerateFiles(pathname.c_str()); - for (char** i = directory; *i != nullptr; ++i) - { - files.push_back(*i); - } - PHYSFS_freeList(directory); - + physfsutil::enumerate_files(pathname, [&files](const std::string& file) { + files.push_back(file); + }); return files; } diff --git a/src/physfs/util.cpp b/src/physfs/util.cpp index f237d041515..6c00ff23085 100644 --- a/src/physfs/util.cpp +++ b/src/physfs/util.cpp @@ -18,6 +18,7 @@ #include +#include "physfs/physfs_file_system.hpp" #include "util/file_system.hpp" namespace physfsutil { @@ -66,16 +67,12 @@ bool remove(const std::string& filename) void remove_content(const std::string& dir) { PHYSFS_UTIL_DIRECTORY_GUARD; - - char** files = PHYSFS_enumerateFiles(dir.c_str()); - for (const char* const* file = files; *file != nullptr; file++) - { - std::string path = FileSystem::join(dir, *file); + enumerate_files(dir, [&dir](const std::string& file) { + std::string path = FileSystem::join(dir, file); if (is_directory(path)) remove_with_content(path); PHYSFS_delete(path.c_str()); - } - PHYSFS_freeList(files); + }); } void remove_with_content(const std::string& dir) @@ -86,6 +83,23 @@ void remove_with_content(const std::string& dir) remove(dir); } +bool enumerate_files(const std::string& pathname, std::function callback) +{ + std::unique_ptr + files(PHYSFS_enumerateFiles(pathname.c_str()), + PHYSFS_freeList); + + if(files == nullptr) + return false; + + for (const char* const* filename = files.get(); *filename != nullptr; ++filename) + { + callback(*filename); + } + + return true; +} + } // namespace physfsutil /* EOF */ diff --git a/src/physfs/util.hpp b/src/physfs/util.hpp index 597b3151403..2e525b87402 100644 --- a/src/physfs/util.hpp +++ b/src/physfs/util.hpp @@ -17,6 +17,7 @@ #ifndef HEADER_SUPERTUX_PHYSFS_UTIL_HPP #define HEADER_SUPERTUX_PHYSFS_UTIL_HPP +#include #include namespace physfsutil { @@ -37,6 +38,9 @@ void remove_content(const std::string& dir); /** Removes directory with content */ void remove_with_content(const std::string& dir); +/** Open directory and call callback for each file */ +bool enumerate_files(const std::string& pathname, std::function callback); + } // namespace physfsutil #endif diff --git a/src/supertux/levelset.cpp b/src/supertux/levelset.cpp index 420c572d93e..4fc2991e791 100644 --- a/src/supertux/levelset.cpp +++ b/src/supertux/levelset.cpp @@ -48,25 +48,17 @@ void Levelset::walk_directory(const std::string& directory, bool recursively) { bool is_basedir = (directory == m_basedir); - char** files = PHYSFS_enumerateFiles(directory.c_str()); - if (!files) - { - log_warning << "Couldn't read subset dir '" << directory << "'" << std::endl; - return; - } - - for (const char* const* filename = files; *filename != nullptr; ++filename) - { - auto filepath = FileSystem::join(directory.c_str(), *filename); + bool enumerateSuccess = physfsutil::enumerate_files(directory, [directory, is_basedir, recursively, this](const auto& filename) { + auto filepath = FileSystem::join(directory, filename); if (physfsutil::is_directory(filepath) && recursively) { walk_directory(filepath, true); } - if (StringUtil::has_suffix(*filename, ".stl")) + if (StringUtil::has_suffix(filename, ".stl")) { if (is_basedir) { - m_levels.push_back(*filename); + m_levels.push_back(filename); } else { @@ -75,8 +67,12 @@ Levelset::walk_directory(const std::string& directory, bool recursively) m_levels.push_back(filepath); } } + }); + + if (!enumerateSuccess) + { + log_warning << "Couldn't read subset dir '" << directory << "'" << std::endl; } - PHYSFS_freeList(files); } /* EOF */ diff --git a/src/supertux/menu/contrib_menu.cpp b/src/supertux/menu/contrib_menu.cpp index 8d9a4ab252e..02087c4ef8f 100644 --- a/src/supertux/menu/contrib_menu.cpp +++ b/src/supertux/menu/contrib_menu.cpp @@ -39,44 +39,31 @@ ContribMenu::ContribMenu() : { // Generating contrib levels list by making use of Level Subset. std::vector level_worlds; - - std::unique_ptr - files(PHYSFS_enumerateFiles("levels"), - PHYSFS_freeList); - for (const char* const* filename = files.get(); *filename != nullptr; ++filename) - { - std::string filepath = FileSystem::join("levels", *filename); + physfsutil::enumerate_files("levels", [&level_worlds](const std::string& filename) { + std::string filepath = FileSystem::join("levels", filename); if (physfsutil::is_directory(filepath)) { level_worlds.push_back(filepath); } - } + }); - std::unique_ptr - addons(PHYSFS_enumerateFiles("custom"), - PHYSFS_freeList); - for (const char* const* addondir = addons.get(); *addondir != nullptr; ++addondir) - { - std::string addonpath = FileSystem::join("custom", *addondir); + physfsutil::enumerate_files("custom", [&level_worlds](const std::string& addon_filename) { + std::string addonpath = FileSystem::join("custom", addon_filename); if (physfsutil::is_directory(addonpath)) { std::string addonlevelpath = FileSystem::join(addonpath.c_str(), "levels"); if (physfsutil::is_directory(addonlevelpath)) { - std::unique_ptr - addonfiles(PHYSFS_enumerateFiles(addonlevelpath.c_str()), - PHYSFS_freeList); - for (const char* const* filename = addonfiles.get(); *filename != nullptr; ++filename) - { - std::string filepath = FileSystem::join(addonlevelpath.c_str(), *filename); + physfsutil::enumerate_files(addonlevelpath, [addonlevelpath, &level_worlds](const std::string& filename) { + std::string filepath = FileSystem::join(addonlevelpath.c_str(), filename); if (physfsutil::is_directory(filepath)) { level_worlds.push_back(filepath); } - } + }); } } - } + }); add_label(_("Contrib Levels")); add_hl(); diff --git a/src/supertux/menu/editor_levelset_select_menu.cpp b/src/supertux/menu/editor_levelset_select_menu.cpp index a3c8aff6cdf..97c08cec155 100644 --- a/src/supertux/menu/editor_levelset_select_menu.cpp +++ b/src/supertux/menu/editor_levelset_select_menu.cpp @@ -55,21 +55,18 @@ void EditorLevelsetSelectMenu::initialize() { Editor::current()->m_deactivate_request = true; - // Generating contrib levels list by making use of Level Subset. - std::vector level_worlds; m_contrib_worlds.clear(); - std::unique_ptr - files(PHYSFS_enumerateFiles("levels"), - PHYSFS_freeList); - for (const char* const* filename = files.get(); *filename != nullptr; ++filename) - { - std::string filepath = FileSystem::join("levels", *filename); + // Generating contrib levels list by making use of Level Subset. + std::vector level_worlds; + + physfsutil::enumerate_files("levels", [&level_worlds](const auto& filename) { + std::string filepath = FileSystem::join("levels", filename); if (physfsutil::is_directory(filepath)) { level_worlds.push_back(filepath); } - } + }); add_label(_("Choose World")); add_hl(); diff --git a/src/supertux/menu/profile_menu.cpp b/src/supertux/menu/profile_menu.cpp index 8eb0d115629..6d10d2098e3 100644 --- a/src/supertux/menu/profile_menu.cpp +++ b/src/supertux/menu/profile_menu.cpp @@ -24,6 +24,7 @@ #include "gui/dialog.hpp" #include "gui/menu_manager.hpp" #include "gui/menu_item.hpp" +#include "physfs/util.hpp" #include "supertux/gameconfig.hpp" #include "supertux/globals.hpp" #include "supertux/menu/profile_name_menu.hpp" @@ -222,13 +223,10 @@ namespace savegames_util { std::vector get_savegames() { std::vector savegames; - char **rc = PHYSFS_enumerateFiles("/"); - char **i; - for (i = rc; *i != nullptr; i++) - { - if (std::string(*i).substr(0, 7) == "profile") savegames.push_back(std::stoi(std::string(*i).substr(7))); - } - PHYSFS_freeList(rc); + physfsutil::enumerate_files("/", [&savegames](const std::string& filename) { + if (std::string(filename).substr(0, 7) == "profile") + savegames.push_back(std::stoi(std::string(filename).substr(7))); + }); std::sort(savegames.begin(), savegames.end()); return savegames; } @@ -236,14 +234,10 @@ namespace savegames_util { void delete_savegames(int idx, bool reset) { const auto& profile_path = "profile" + std::to_string(idx); - std::unique_ptr - files(PHYSFS_enumerateFiles(profile_path.c_str()), - PHYSFS_freeList); - for (const char* const* filename = files.get(); *filename != nullptr; ++filename) - { - std::string filepath = FileSystem::join(profile_path.c_str(), *filename); + physfsutil::enumerate_files(profile_path, [profile_path](const std::string& filename) { + std::string filepath = FileSystem::join(profile_path.c_str(), filename); PHYSFS_delete(filepath.c_str()); - } + }); if (!reset) PHYSFS_delete(profile_path.c_str()); } } // namespace savegames_util diff --git a/src/video/bitmap_font.cpp b/src/video/bitmap_font.cpp index e82cc8c27cb..0b07ac5c358 100644 --- a/src/video/bitmap_font.cpp +++ b/src/video/bitmap_font.cpp @@ -23,6 +23,7 @@ #include #include "physfs/physfs_sdl.hpp" +#include "physfs/util.hpp" #include "util/file_system.hpp" #include "util/log.hpp" #include "util/reader_document.hpp" @@ -70,20 +71,18 @@ BitmapFont::BitmapFont(GlyphWidth glyph_width_, const std::string fontname = FileSystem::basename(filename); // Scan for prefix-filename in addons search path. - char **rc = PHYSFS_enumerateFiles(fontdir.c_str()); - for (char **i = rc; *i != nullptr; i++) { - std::string filename_(*i); - if ( filename_.rfind(fontname) != std::string::npos ) { + physfsutil::enumerate_files(fontdir, [fontdir, fontname, this](const std::string& file) { + std::string filepath = FileSystem::join(fontdir, file); + if (file.rfind(fontname) != std::string::npos) { try { - loadFontFile(fontdir + filename_); + loadFontFile(filepath); } catch(const std::exception& e) { log_fatal << "Couldn't load font file: " << e.what() << std::endl; } } - } - PHYSFS_freeList(rc); + }); } void