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:
2025-11-04 10:43:34 +08:00
parent 3c3ba0cd63
commit cd22925449
4 changed files with 159 additions and 231 deletions
+157 -19
View File
@@ -947,6 +947,9 @@ func bot_try_grab_item() -> bool:
return false
# -----------------------------------------------------------------
# OLD GRAB Func
# -----------------------------------------------------------------
#func grab_item(grid_position: Vector2i = current_position) -> bool:
#if is_bot:
#return bot_try_grab_item()
@@ -995,15 +998,60 @@ func bot_try_grab_item() -> bool:
#return true
#
#return false
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:
#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:
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)
# 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
@@ -1017,32 +1065,108 @@ func grab_item(grid_position: Vector2i = current_position) -> bool:
if item == -1:
return false
# === AUTO-ARRANGE LOGIC ===
# === AUTO-ARRANGE LOGIC (Client-side pre-check) ===
var target_slot = find_best_goal_slot_for_item(item)
if target_slot == -1:
print("Player: No valid slot found for item.")
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)
if not is_multiplayer_authority():
return false
# 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)
# === Branching Logic: Host vs Client ===
if multiplayer.is_server():
# HOST/SERVER: Call the logic directly
_execute_grab(grid_position, cell, item)
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
# -----------------------------------------------------------------
# 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
# Automatically puts a goal-matching tile into an adjacent (or current) empty grid cell
# -----------------------------------------------------------------
func auto_put_item() -> bool:
if not enhanced_gridmap or action_points <= 0 or is_bot or is_in_group("Bots"):
return false
@@ -1134,6 +1258,20 @@ func auto_put_item() -> bool:
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")
func request_server_put(grid_position: Vector2i, slot_index: int, x: int, y: int, z: int, item: int):