Refactor item grabbing logic and remove TileGrabber
Moved item grabbing and auto-arrange logic from the separate TileGrabber node into the player.gd script, consolidating server/client authority checks and RPC handling for multiplayer. Removed obsolete tile_grabber.gd and its UID file. Updated main.tscn to clean up unused UI nodes and adjust visibility settings for player boards.
This commit is contained in:
+2
-39
@@ -74,6 +74,7 @@ grow_vertical = 2
|
|||||||
theme_override_styles/panel = ExtResource("5_dvx6y")
|
theme_override_styles/panel = ExtResource("5_dvx6y")
|
||||||
|
|
||||||
[node name="NetworkInfo" type="VBoxContainer" parent="NetworkPanel"]
|
[node name="NetworkInfo" type="VBoxContainer" parent="NetworkPanel"]
|
||||||
|
layout_mode = 0
|
||||||
offset_left = 8.0
|
offset_left = 8.0
|
||||||
offset_right = 124.0
|
offset_right = 124.0
|
||||||
offset_bottom = 50.0
|
offset_bottom = 50.0
|
||||||
@@ -90,7 +91,6 @@ horizontal_alignment = 1
|
|||||||
vertical_alignment = 1
|
vertical_alignment = 1
|
||||||
|
|
||||||
[node name="PlayerboardUI" type="GridContainer" parent="."]
|
[node name="PlayerboardUI" type="GridContainer" parent="."]
|
||||||
visible = false
|
|
||||||
clip_contents = true
|
clip_contents = true
|
||||||
anchors_preset = 2
|
anchors_preset = 2
|
||||||
anchor_top = 1.0
|
anchor_top = 1.0
|
||||||
@@ -1056,44 +1056,6 @@ environment = ExtResource("4_ky38j")
|
|||||||
|
|
||||||
[node name="CanvasLayer" type="CanvasLayer" parent="."]
|
[node name="CanvasLayer" type="CanvasLayer" parent="."]
|
||||||
|
|
||||||
[node name="MarginContainer" type="Control" parent="."]
|
|
||||||
visible = false
|
|
||||||
clip_contents = true
|
|
||||||
layout_direction = 2
|
|
||||||
layout_mode = 3
|
|
||||||
anchors_preset = 5
|
|
||||||
anchor_left = 0.5
|
|
||||||
anchor_right = 0.5
|
|
||||||
offset_left = -248.0
|
|
||||||
offset_top = 24.0
|
|
||||||
offset_right = 275.0
|
|
||||||
offset_bottom = 129.0
|
|
||||||
grow_horizontal = 2
|
|
||||||
|
|
||||||
[node name="Panel4" type="Panel" parent="MarginContainer"]
|
|
||||||
custom_minimum_size = Vector2(105, 105)
|
|
||||||
layout_mode = 2
|
|
||||||
offset_left = 137.0
|
|
||||||
offset_right = 242.0
|
|
||||||
offset_bottom = 105.0
|
|
||||||
theme_override_styles/panel = SubResource("StyleBoxTexture_5oeq4")
|
|
||||||
|
|
||||||
[node name="Panel5" type="Panel" parent="MarginContainer"]
|
|
||||||
custom_minimum_size = Vector2(105, 105)
|
|
||||||
layout_mode = 2
|
|
||||||
offset_left = 275.0
|
|
||||||
offset_right = 380.0
|
|
||||||
offset_bottom = 105.0
|
|
||||||
theme_override_styles/panel = SubResource("StyleBoxTexture_5oeq4")
|
|
||||||
|
|
||||||
[node name="Panel6" type="Panel" parent="MarginContainer"]
|
|
||||||
custom_minimum_size = Vector2(105, 105)
|
|
||||||
layout_mode = 2
|
|
||||||
offset_left = 413.0
|
|
||||||
offset_right = 518.0
|
|
||||||
offset_bottom = 105.0
|
|
||||||
theme_override_styles/panel = SubResource("StyleBoxTexture_5oeq4")
|
|
||||||
|
|
||||||
[node name="AllPlayerGoals" type="HBoxContainer" parent="."]
|
[node name="AllPlayerGoals" type="HBoxContainer" parent="."]
|
||||||
y_sort_enabled = true
|
y_sort_enabled = true
|
||||||
clip_contents = true
|
clip_contents = true
|
||||||
@@ -6052,6 +6014,7 @@ grow_vertical = 2
|
|||||||
texture = ExtResource("10_my1qp")
|
texture = ExtResource("10_my1qp")
|
||||||
|
|
||||||
[node name="AllPlayerBoards" type="TabContainer" parent="."]
|
[node name="AllPlayerBoards" type="TabContainer" parent="."]
|
||||||
|
visible = false
|
||||||
clip_contents = true
|
clip_contents = true
|
||||||
anchors_preset = 4
|
anchors_preset = 4
|
||||||
anchor_top = 0.5
|
anchor_top = 0.5
|
||||||
|
|||||||
+155
-17
@@ -947,6 +947,9 @@ func bot_try_grab_item() -> bool:
|
|||||||
|
|
||||||
return false
|
return false
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------
|
||||||
|
# OLD GRAB Func
|
||||||
|
# -----------------------------------------------------------------
|
||||||
#func grab_item(grid_position: Vector2i = current_position) -> bool:
|
#func grab_item(grid_position: Vector2i = current_position) -> bool:
|
||||||
#if is_bot:
|
#if is_bot:
|
||||||
#return bot_try_grab_item()
|
#return bot_try_grab_item()
|
||||||
@@ -995,7 +998,52 @@ func bot_try_grab_item() -> bool:
|
|||||||
#return true
|
#return true
|
||||||
#
|
#
|
||||||
#return false
|
#return false
|
||||||
|
# -----------------------------------------------------------------
|
||||||
|
#func grab_item(grid_position: Vector2i = current_position) -> bool:
|
||||||
|
#if not enhanced_gridmap or action_points <= 0:
|
||||||
|
#return false
|
||||||
|
#
|
||||||
|
#var cell = Vector3i(grid_position.x, 1, grid_position.y)
|
||||||
|
#var item = enhanced_gridmap.get_cell_item(cell)
|
||||||
|
#
|
||||||
|
## Validate adjacency (unless it's current position)
|
||||||
|
#if grid_position != current_position:
|
||||||
|
#var neighbors = enhanced_gridmap.get_neighbors(current_position, 0)
|
||||||
|
#var is_adjacent = false
|
||||||
|
#for neighbor in neighbors:
|
||||||
|
#if neighbor.position == grid_position:
|
||||||
|
#is_adjacent = true
|
||||||
|
#break
|
||||||
|
#if not is_adjacent:
|
||||||
|
#return false
|
||||||
|
#
|
||||||
|
#if item == -1:
|
||||||
|
#return false
|
||||||
|
#
|
||||||
|
## === AUTO-ARRANGE LOGIC ===
|
||||||
|
#var target_slot = find_best_goal_slot_for_item(item)
|
||||||
|
#if target_slot == -1:
|
||||||
|
#return false # no space
|
||||||
|
#
|
||||||
|
## Perform the grab and auto-place
|
||||||
|
#if is_multiplayer_authority():
|
||||||
|
## Update gridmap: remove item
|
||||||
|
#rpc("sync_grid_item", cell.x, cell.y, cell.z, -1)
|
||||||
|
## Update playerboard
|
||||||
|
#playerboard[target_slot] = item
|
||||||
|
#rpc("sync_playerboard", playerboard)
|
||||||
|
## Consume action
|
||||||
|
#has_performed_action = true
|
||||||
|
#consume_action_points(1)
|
||||||
|
#
|
||||||
|
## Optional: visual feedback
|
||||||
|
#var main = get_tree().get_root().get_node_or_null("Main")
|
||||||
|
#if main:
|
||||||
|
#main.update_playerboard_ui()
|
||||||
|
#main.set_action_state(main.ActionState.NONE)
|
||||||
|
#
|
||||||
|
#return true
|
||||||
|
# -----------------------------------------------------------------
|
||||||
func grab_item(grid_position: Vector2i = current_position) -> bool:
|
func grab_item(grid_position: Vector2i = current_position) -> bool:
|
||||||
if not enhanced_gridmap or action_points <= 0:
|
if not enhanced_gridmap or action_points <= 0:
|
||||||
return false
|
return false
|
||||||
@@ -1017,32 +1065,108 @@ func grab_item(grid_position: Vector2i = current_position) -> bool:
|
|||||||
if item == -1:
|
if item == -1:
|
||||||
return false
|
return false
|
||||||
|
|
||||||
# === AUTO-ARRANGE LOGIC ===
|
# === AUTO-ARRANGE LOGIC (Client-side pre-check) ===
|
||||||
var target_slot = find_best_goal_slot_for_item(item)
|
var target_slot = find_best_goal_slot_for_item(item)
|
||||||
if target_slot == -1:
|
if target_slot == -1:
|
||||||
|
print("Player: No valid slot found for item.")
|
||||||
return false # no space
|
return false # no space
|
||||||
|
|
||||||
# Perform the grab and auto-place
|
if not is_multiplayer_authority():
|
||||||
if is_multiplayer_authority():
|
return false
|
||||||
# Update gridmap: remove item
|
|
||||||
rpc("sync_grid_item", cell.x, cell.y, cell.z, -1)
|
|
||||||
# Update playerboard
|
|
||||||
playerboard[target_slot] = item
|
|
||||||
rpc("sync_playerboard", playerboard)
|
|
||||||
# Consume action
|
|
||||||
has_performed_action = true
|
|
||||||
consume_action_points(1)
|
|
||||||
|
|
||||||
# Optional: visual feedback
|
# === Branching Logic: Host vs Client ===
|
||||||
var main = get_tree().get_root().get_node_or_null("Main")
|
if multiplayer.is_server():
|
||||||
if main:
|
# HOST/SERVER: Call the logic directly
|
||||||
main.update_playerboard_ui()
|
_execute_grab(grid_position, cell, item)
|
||||||
main.set_action_state(main.ActionState.NONE)
|
else:
|
||||||
|
# CLIENT: Send RPC request to server (peer 1)
|
||||||
|
rpc_id(1, "request_server_grab", grid_position, cell.x, cell.y, cell.z, item)
|
||||||
|
|
||||||
|
return true # Request was sent or processed
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------
|
||||||
|
# Execute Grab
|
||||||
|
# -----------------------------------------------------------------
|
||||||
|
|
||||||
|
func _execute_grab(grid_pos: Vector2i, cell: Vector3i, item_id: int):
|
||||||
|
var main = get_tree().get_root().get_node_or_null("Main")
|
||||||
|
if not main:
|
||||||
|
push_error("Server: Main node not found.")
|
||||||
|
return false
|
||||||
|
|
||||||
|
var server_gridmap = main.get_node("EnhancedGridMap")
|
||||||
|
if not server_gridmap:
|
||||||
|
push_error("Server: EnhancedGridMap not found.")
|
||||||
|
return false
|
||||||
|
|
||||||
|
# 1. Server-side Validation
|
||||||
|
var server_item = server_gridmap.get_cell_item(cell)
|
||||||
|
|
||||||
|
# Check if item is still there
|
||||||
|
if server_item != item_id:
|
||||||
|
print("Server: Item mismatch or already taken. Server has ", server_item)
|
||||||
|
return false
|
||||||
|
|
||||||
|
# Check action points
|
||||||
|
if action_points <= 0:
|
||||||
|
print("Server: Player has no action points.")
|
||||||
|
return false
|
||||||
|
|
||||||
|
# Check adjacency
|
||||||
|
if grid_pos != current_position:
|
||||||
|
var neighbors = server_gridmap.get_neighbors(current_position, 0)
|
||||||
|
if not neighbors.any(func(n): return n.position == grid_pos):
|
||||||
|
print("Server: Player is not adjacent to item.")
|
||||||
|
return false
|
||||||
|
|
||||||
|
# 2. Server-side Auto-Arrange
|
||||||
|
var target_slot = find_best_goal_slot_for_item(item_id)
|
||||||
|
if target_slot == -1:
|
||||||
|
print("Server: Player has no valid slot for item.")
|
||||||
|
return false
|
||||||
|
|
||||||
|
# 3. Server Executes the Action
|
||||||
|
|
||||||
|
# 3a. Update gridmap (using Main's RPC, which has authority)
|
||||||
|
main.rpc("sync_grid_item", cell.x, cell.y, cell.z, -1)
|
||||||
|
|
||||||
|
# 3b. Update playerboard state (on this server-side instance)
|
||||||
|
playerboard[target_slot] = item_id
|
||||||
|
|
||||||
|
# 3c. Broadcast the new playerboard state to all clients
|
||||||
|
rpc("sync_playerboard", playerboard)
|
||||||
|
|
||||||
|
# 3d. Consume action points
|
||||||
|
has_performed_action = true
|
||||||
|
consume_action_points(1)
|
||||||
|
|
||||||
|
# 3e. Reset the UI for the player who acted
|
||||||
|
# This will RPC to the client, or run locally for the host
|
||||||
|
rpc("force_action_state_none")
|
||||||
|
|
||||||
return true
|
return true
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------
|
||||||
|
# This function runs on the server when requested by a client
|
||||||
|
# -----------------------------------------------------------------
|
||||||
|
@rpc("any_peer", "reliable")
|
||||||
|
func request_server_grab(grid_pos: Vector2i, x: int, y: int, z: int, item_id: int):
|
||||||
|
# 1. Only the server (peer 1) should process this
|
||||||
|
if not multiplayer.is_server():
|
||||||
|
return
|
||||||
|
|
||||||
|
# 2. Security check: Did this request come from the actual owner of this node?
|
||||||
|
if multiplayer.get_remote_sender_id() != get_multiplayer_authority():
|
||||||
|
push_error("Security: Non-authority tried to grab item!")
|
||||||
|
return
|
||||||
|
|
||||||
|
# 3. Call the execution logic
|
||||||
|
_execute_grab(grid_pos, Vector3i(x, y, z), item_id)
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------
|
||||||
# Auto-put: no manual selection needed
|
# Auto-put: no manual selection needed
|
||||||
# Automatically puts a goal-matching tile into an adjacent (or current) empty grid cell
|
# Automatically puts a goal-matching tile into an adjacent (or current) empty grid cell
|
||||||
|
# -----------------------------------------------------------------
|
||||||
func auto_put_item() -> bool:
|
func auto_put_item() -> bool:
|
||||||
if not enhanced_gridmap or action_points <= 0 or is_bot or is_in_group("Bots"):
|
if not enhanced_gridmap or action_points <= 0 or is_bot or is_in_group("Bots"):
|
||||||
return false
|
return false
|
||||||
@@ -1134,6 +1258,20 @@ func auto_put_item() -> bool:
|
|||||||
|
|
||||||
return true
|
return true
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------
|
||||||
|
# Force ActionState : None
|
||||||
|
# -----------------------------------------------------------------
|
||||||
|
|
||||||
|
@rpc("authority", "reliable")
|
||||||
|
func force_action_state_none():
|
||||||
|
# This is called by the server on the client to reset the UI
|
||||||
|
var main = get_tree().get_root().get_node_or_null("Main")
|
||||||
|
if main:
|
||||||
|
main.set_action_state(main.ActionState.NONE)
|
||||||
|
clear_highlights()
|
||||||
|
clear_playerboard_highlights()
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------
|
||||||
|
|
||||||
@rpc("any_peer", "reliable")
|
@rpc("any_peer", "reliable")
|
||||||
func request_server_put(grid_position: Vector2i, slot_index: int, x: int, y: int, z: int, item: int):
|
func request_server_put(grid_position: Vector2i, slot_index: int, x: int, y: int, z: int, item: int):
|
||||||
|
|||||||
@@ -1,172 +0,0 @@
|
|||||||
# tekton-enet/scripts/tile_grabber.gd
|
|
||||||
extends Node
|
|
||||||
|
|
||||||
class_name TileGrabber
|
|
||||||
|
|
||||||
signal tile_grabbed(tile_id: int, position: Vector3i)
|
|
||||||
signal tiles_arranged(arranged_tiles: Array)
|
|
||||||
|
|
||||||
@export var enhanced_gridmap_path: NodePath
|
|
||||||
@export var player_board_path: NodePath
|
|
||||||
|
|
||||||
var enhanced_gridmap: EnhancedGridMap
|
|
||||||
var player_board: Node
|
|
||||||
var grabbed_tile: int = -1
|
|
||||||
var grabbed_position: Vector3i
|
|
||||||
|
|
||||||
# Goal combinations - define what patterns score points
|
|
||||||
var goal_combinations = [
|
|
||||||
{
|
|
||||||
"name": "Line of 3",
|
|
||||||
"pattern": [
|
|
||||||
[1, 1, 1],
|
|
||||||
[0, 0, 0],
|
|
||||||
[0, 0, 0]
|
|
||||||
],
|
|
||||||
"score": 10
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "L-Shape",
|
|
||||||
"pattern": [
|
|
||||||
[1, 0, 0],
|
|
||||||
[1, 0, 0],
|
|
||||||
[1, 1, 0]
|
|
||||||
],
|
|
||||||
"score": 15
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Square",
|
|
||||||
"pattern": [
|
|
||||||
[1, 1, 0],
|
|
||||||
[1, 1, 0],
|
|
||||||
[0, 0, 0]
|
|
||||||
],
|
|
||||||
"score": 20
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
func _ready():
|
|
||||||
if enhanced_gridmap_path:
|
|
||||||
enhanced_gridmap = get_node(enhanced_gridmap_path)
|
|
||||||
if player_board_path:
|
|
||||||
player_board = get_node(player_board_path)
|
|
||||||
|
|
||||||
func grab_tile(grid_position: Vector3i) -> bool:
|
|
||||||
if not enhanced_gridmap:
|
|
||||||
print("Error: EnhancedGridMap not found")
|
|
||||||
return false
|
|
||||||
|
|
||||||
# Get the tile at the specified position
|
|
||||||
var tile_id = enhanced_gridmap.get_cell_item(grid_position)
|
|
||||||
if tile_id == -1:
|
|
||||||
print("No tile at position: ", grid_position)
|
|
||||||
return false
|
|
||||||
|
|
||||||
# Store the grabbed tile and its position
|
|
||||||
grabbed_tile = tile_id
|
|
||||||
grabbed_position = grid_position
|
|
||||||
|
|
||||||
# Remove the tile from the grid
|
|
||||||
enhanced_gridmap.set_cell_item(grid_position, -1)
|
|
||||||
|
|
||||||
# Emit signal that a tile was grabbed
|
|
||||||
tile_grabbed.emit(tile_id, grid_position)
|
|
||||||
|
|
||||||
print("Grabbed tile ", tile_id, " from position ", grid_position)
|
|
||||||
return true
|
|
||||||
|
|
||||||
func auto_arrange_tile() -> bool:
|
|
||||||
if grabbed_tile == -1:
|
|
||||||
print("No tile to arrange")
|
|
||||||
return false
|
|
||||||
|
|
||||||
# Find the best position for the grabbed tile based on goal combinations
|
|
||||||
var best_position = find_best_position_for_tile(grabbed_tile)
|
|
||||||
|
|
||||||
if best_position == Vector3i(-1, -1, -1):
|
|
||||||
print("No valid position found for tile")
|
|
||||||
return false
|
|
||||||
|
|
||||||
# Place the tile at the best position
|
|
||||||
enhanced_gridmap.set_cell_item(best_position, grabbed_tile)
|
|
||||||
|
|
||||||
# Reset grabbed tile
|
|
||||||
grabbed_tile = -1
|
|
||||||
grabbed_position = Vector3i(-1, -1, -1)
|
|
||||||
|
|
||||||
# Emit signal that tiles were arranged
|
|
||||||
tiles_arranged.emit([best_position])
|
|
||||||
|
|
||||||
print("Auto-arranged tile at position: ", best_position)
|
|
||||||
return true
|
|
||||||
|
|
||||||
func find_best_position_for_tile(tile_id: int) -> Vector3i:
|
|
||||||
var best_position = Vector3i(-1, -1, -1)
|
|
||||||
var best_score = -1
|
|
||||||
|
|
||||||
# Check all possible positions on the grid
|
|
||||||
for x in range(enhanced_gridmap.columns):
|
|
||||||
for z in range(enhanced_gridmap.rows):
|
|
||||||
var position = Vector3i(x, 0, z)
|
|
||||||
|
|
||||||
# Skip if position is already occupied
|
|
||||||
if enhanced_gridmap.get_cell_item(position) != -1:
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Temporarily place the tile to check for goal combinations
|
|
||||||
enhanced_gridmap.set_cell_item(position, tile_id)
|
|
||||||
|
|
||||||
# Calculate score for this position
|
|
||||||
var score = calculate_position_score(position)
|
|
||||||
|
|
||||||
# Remove the temporary tile
|
|
||||||
enhanced_gridmap.set_cell_item(position, -1)
|
|
||||||
|
|
||||||
# Update best position if this one scores higher
|
|
||||||
if score > best_score:
|
|
||||||
best_score = score
|
|
||||||
best_position = position
|
|
||||||
|
|
||||||
return best_position
|
|
||||||
|
|
||||||
func calculate_position_score(position: Vector3i) -> int:
|
|
||||||
var total_score = 0
|
|
||||||
|
|
||||||
# Check each goal combination
|
|
||||||
for goal in goal_combinations:
|
|
||||||
var matches = check_goal_combination(position, goal.pattern)
|
|
||||||
if matches:
|
|
||||||
total_score += goal.score
|
|
||||||
|
|
||||||
return total_score
|
|
||||||
|
|
||||||
func check_goal_combination(center_position: Vector3i, pattern: Array) -> bool:
|
|
||||||
# Get the pattern dimensions
|
|
||||||
var pattern_width = pattern[0].size()
|
|
||||||
var pattern_height = pattern.size()
|
|
||||||
|
|
||||||
# Calculate the top-left position of the pattern
|
|
||||||
var start_x = center_position.x - (pattern_width / 2)
|
|
||||||
var start_z = center_position.z - (pattern_height / 2)
|
|
||||||
|
|
||||||
# Check if the pattern fits within the grid
|
|
||||||
if start_x < 0 or start_z < 0 or start_x + pattern_width > enhanced_gridmap.columns or start_z + pattern_height > enhanced_gridmap.rows:
|
|
||||||
return false
|
|
||||||
|
|
||||||
# Check each cell in the pattern
|
|
||||||
for z in range(pattern_height):
|
|
||||||
for x in range(pattern_width):
|
|
||||||
var pattern_value = pattern[z][x]
|
|
||||||
var grid_position = Vector3i(start_x + x, 0, start_z + z)
|
|
||||||
var grid_value = enhanced_gridmap.get_cell_item(grid_position)
|
|
||||||
|
|
||||||
# If pattern expects a tile (1) but grid is empty (-1), no match
|
|
||||||
if pattern_value == 1 and grid_value == -1:
|
|
||||||
return false
|
|
||||||
|
|
||||||
# If pattern expects empty (0) but grid has a tile, no match
|
|
||||||
if pattern_value == 0 and grid_value != -1:
|
|
||||||
return false
|
|
||||||
|
|
||||||
# All cells match the pattern
|
|
||||||
return true
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
uid://dc1cw21830bfp
|
|
||||||
Reference in New Issue
Block a user