class_name Match3SaveManager extends RefCounted ## Save/Load manager for Match3 gameplay state ## ## Handles serialization and deserialization of Match3 game state. ## Converts game objects to data structures for storage and restoration. ## ## Usage: ## # Save current state ## var grid_data = Match3SaveManager.serialize_grid_state(game_grid, grid_size) ## ## # Restore previous state ## var success = Match3SaveManager.deserialize_grid_state(grid_data, game_grid, grid_size) static func serialize_grid_state(grid: Array, grid_size: Vector2i) -> Array: ## Convert the current game grid to a serializable 2D array of tile types. ## ## Extracts the tile_type property from each tile node and creates a 2D array ## that can be saved to disk. Invalid or missing tiles are represented as -1. ## ## Args: ## grid: The current game grid (2D array of tile nodes) ## grid_size: Dimensions of the grid to serialize ## ## Returns: ## Array: 2D array where each element is either a tile type (int) or -1 for empty var serialized_grid = [] var valid_tiles = 0 var null_tiles = 0 for y in range(grid_size.y): var row = [] for x in range(grid_size.x): if y < grid.size() and x < grid[y].size() and grid[y][x]: row.append(grid[y][x].tile_type) valid_tiles += 1 else: row.append(-1) # Invalid/empty tile null_tiles += 1 serialized_grid.append(row) DebugManager.log_info( ( "Serialized grid state: %dx%d grid, %d valid tiles, %d null tiles" % [grid_size.x, grid_size.y, valid_tiles, null_tiles] ), "Match3" ) return serialized_grid static func get_active_gem_types_from_grid(grid: Array, tile_types: int) -> Array: # Get active gem types from the first available tile if grid.size() > 0 and grid[0].size() > 0 and grid[0][0]: return grid[0][0].active_gem_types.duplicate() # Fallback to default var default_types = [] for i in range(tile_types): default_types.append(i) return default_types static func save_game_state(grid: Array, grid_size: Vector2i, tile_types: int): # Save complete game state var grid_layout = serialize_grid_state(grid, grid_size) var active_gems = get_active_gem_types_from_grid(grid, tile_types) DebugManager.log_info( ( "Saving match3 state: size(%d,%d), %d tile types, %d active gems" % [grid_size.x, grid_size.y, tile_types, active_gems.size()] ), "Match3" ) SaveManager.save_grid_state(grid_size, tile_types, active_gems, grid_layout) static func restore_grid_from_layout( match3_node: Node2D, grid_layout: Array, active_gems: Array[int], grid_size: Vector2i, tile_scene: PackedScene, grid_offset: Vector2, tile_size: float, tile_types: int ) -> Array[Array]: # Clear ALL existing tile children var all_tile_children = [] for child in match3_node.get_children(): if child.has_method("get_script") and child.get_script(): var script_path = child.get_script().resource_path if script_path == "res://scenes/game/gameplays/tile.gd": all_tile_children.append(child) # Remove all found tile children for child in all_tile_children: child.queue_free() # Wait for nodes to be freed await match3_node.get_tree().process_frame # Create new grid var new_grid: Array[Array] = [] for y in range(grid_size.y): new_grid.append(Array([])) for x in range(grid_size.x): var tile = tile_scene.instantiate() var tile_position = grid_offset + Vector2(x, y) * tile_size tile.position = tile_position tile.grid_position = Vector2i(x, y) match3_node.add_child(tile) # Configure Area2D tile.monitoring = true tile.monitorable = true tile.input_pickable = true tile.set_tile_size(tile_size) tile.set_active_gem_types(active_gems) # Set the saved tile type var saved_tile_type = grid_layout[y][x] if saved_tile_type >= 0 and saved_tile_type < tile_types: tile.tile_type = saved_tile_type else: tile.tile_type = randi() % tile_types # Connect tile signals if tile.has_signal("tile_selected") and match3_node.has_method("_on_tile_selected"): tile.tile_selected.connect(match3_node._on_tile_selected) if tile.has_signal("tile_hovered") and match3_node.has_method("_on_tile_hovered"): tile.tile_hovered.connect(match3_node._on_tile_hovered) tile.tile_unhovered.connect(match3_node._on_tile_unhovered) new_grid[y].append(tile) return new_grid