Automated formatting applied by tools/run_development.py 🤖 Generated by Gitea Actions Workflow: Continuous Integration Run: http://server:3000/nett00n/skelly/actions/runs/90
144 lines
4.3 KiB
GDScript
144 lines
4.3 KiB
GDScript
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
|