Fix StationMovement in Multiplayer, still works singleplayer

This commit is contained in:
JonShard
2026-08-10 13:02:19 +02:00
parent dbaad35e50
commit bf31f85b02
5 changed files with 144 additions and 42 deletions
+24 -24
View File
@@ -10,34 +10,34 @@
[ext_resource type="PackedScene" uid="uid://cqhw276realc" path="res://addons/godot-xr-tools/functions/function_pointer.tscn" id="6_ptr"] [ext_resource type="PackedScene" uid="uid://cqhw276realc" path="res://addons/godot-xr-tools/functions/function_pointer.tscn" id="6_ptr"]
[ext_resource type="PackedScene" uid="uid://bjcxf427un2wp" path="res://addons/godot-xr-tools/player/poke/poke.tscn" id="7_1fmci"] [ext_resource type="PackedScene" uid="uid://bjcxf427un2wp" path="res://addons/godot-xr-tools/player/poke/poke.tscn" id="7_1fmci"]
[sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_ouruy"] [sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_1fmci"]
animation = &"Grip" animation = &"Grip"
[sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_i0gvw"] [sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_itrmp"]
animation = &"Grip" animation = &"Grip"
[sub_resource type="AnimationNodeBlend2" id="AnimationNodeBlend2_5mmou"] [sub_resource type="AnimationNodeBlend2" id="AnimationNodeBlend2_nrfrd"]
filter_enabled = true filter_enabled = true
filters = ["Armature/Skeleton3D:Little_Distal_L", "Armature/Skeleton3D:Little_Intermediate_L", "Armature/Skeleton3D:Little_Metacarpal_L", "Armature/Skeleton3D:Little_Proximal_L", "Armature/Skeleton3D:Middle_Distal_L", "Armature/Skeleton3D:Middle_Intermediate_L", "Armature/Skeleton3D:Middle_Metacarpal_L", "Armature/Skeleton3D:Middle_Proximal_L", "Armature/Skeleton3D:Ring_Distal_L", "Armature/Skeleton3D:Ring_Intermediate_L", "Armature/Skeleton3D:Ring_Metacarpal_L", "Armature/Skeleton3D:Ring_Proximal_L", "Armature/Skeleton3D:Thumb_Distal_L", "Armature/Skeleton3D:Thumb_Metacarpal_L", "Armature/Skeleton3D:Thumb_Proximal_L", "Armature/Skeleton:Little_Distal_L", "Armature/Skeleton:Little_Intermediate_L", "Armature/Skeleton:Little_Proximal_L", "Armature/Skeleton:Middle_Distal_L", "Armature/Skeleton:Middle_Intermediate_L", "Armature/Skeleton:Middle_Proximal_L", "Armature/Skeleton:Ring_Distal_L", "Armature/Skeleton:Ring_Intermediate_L", "Armature/Skeleton:Ring_Proximal_L", "Armature/Skeleton:Thumb_Distal_L", "Armature/Skeleton:Thumb_Proximal_L"] filters = ["Armature/Skeleton3D:Little_Distal_L", "Armature/Skeleton3D:Little_Intermediate_L", "Armature/Skeleton3D:Little_Metacarpal_L", "Armature/Skeleton3D:Little_Proximal_L", "Armature/Skeleton3D:Middle_Distal_L", "Armature/Skeleton3D:Middle_Intermediate_L", "Armature/Skeleton3D:Middle_Metacarpal_L", "Armature/Skeleton3D:Middle_Proximal_L", "Armature/Skeleton3D:Ring_Distal_L", "Armature/Skeleton3D:Ring_Intermediate_L", "Armature/Skeleton3D:Ring_Metacarpal_L", "Armature/Skeleton3D:Ring_Proximal_L", "Armature/Skeleton3D:Thumb_Distal_L", "Armature/Skeleton3D:Thumb_Metacarpal_L", "Armature/Skeleton3D:Thumb_Proximal_L", "Armature/Skeleton:Little_Distal_L", "Armature/Skeleton:Little_Intermediate_L", "Armature/Skeleton:Little_Proximal_L", "Armature/Skeleton:Middle_Distal_L", "Armature/Skeleton:Middle_Intermediate_L", "Armature/Skeleton:Middle_Proximal_L", "Armature/Skeleton:Ring_Distal_L", "Armature/Skeleton:Ring_Intermediate_L", "Armature/Skeleton:Ring_Proximal_L", "Armature/Skeleton:Thumb_Distal_L", "Armature/Skeleton:Thumb_Proximal_L"]
[sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_yfij0"] [sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_73fu8"]
animation = &"Grip 5" animation = &"Grip 5"
[sub_resource type="AnimationNodeBlend2" id="AnimationNodeBlend2_2ebvs"] [sub_resource type="AnimationNodeBlend2" id="AnimationNodeBlend2_ouruy"]
filter_enabled = true filter_enabled = true
filters = ["Armature/Skeleton3D:Index_Distal_L", "Armature/Skeleton3D:Index_Intermediate_L", "Armature/Skeleton3D:Index_Metacarpal_L", "Armature/Skeleton3D:Index_Proximal_L", "Armature/Skeleton:Index_Distal_L", "Armature/Skeleton:Index_Intermediate_L", "Armature/Skeleton:Index_Proximal_L"] filters = ["Armature/Skeleton3D:Index_Distal_L", "Armature/Skeleton3D:Index_Intermediate_L", "Armature/Skeleton3D:Index_Metacarpal_L", "Armature/Skeleton3D:Index_Proximal_L", "Armature/Skeleton:Index_Distal_L", "Armature/Skeleton:Index_Intermediate_L", "Armature/Skeleton:Index_Proximal_L"]
[sub_resource type="AnimationNodeBlendTree" id="AnimationNodeBlendTree_l8v2a"] [sub_resource type="AnimationNodeBlendTree" id="AnimationNodeBlendTree_i0gvw"]
graph_offset = Vector2(-536, 11) graph_offset = Vector2(-536, 11)
nodes/ClosedHand1/node = SubResource("AnimationNodeAnimation_ouruy") nodes/ClosedHand1/node = SubResource("AnimationNodeAnimation_1fmci")
nodes/ClosedHand1/position = Vector2(-600, 300) nodes/ClosedHand1/position = Vector2(-600, 300)
nodes/ClosedHand2/node = SubResource("AnimationNodeAnimation_i0gvw") nodes/ClosedHand2/node = SubResource("AnimationNodeAnimation_itrmp")
nodes/ClosedHand2/position = Vector2(-360, 300) nodes/ClosedHand2/position = Vector2(-360, 300)
nodes/Grip/node = SubResource("AnimationNodeBlend2_5mmou") nodes/Grip/node = SubResource("AnimationNodeBlend2_nrfrd")
nodes/Grip/position = Vector2(0, 20) nodes/Grip/position = Vector2(0, 20)
nodes/OpenHand/node = SubResource("AnimationNodeAnimation_yfij0") nodes/OpenHand/node = SubResource("AnimationNodeAnimation_73fu8")
nodes/OpenHand/position = Vector2(-600, 100) nodes/OpenHand/position = Vector2(-600, 100)
nodes/Trigger/node = SubResource("AnimationNodeBlend2_2ebvs") nodes/Trigger/node = SubResource("AnimationNodeBlend2_ouruy")
nodes/Trigger/position = Vector2(-360, 20) nodes/Trigger/position = Vector2(-360, 20)
node_connections = [&"output", 0, &"Grip", &"Grip", 0, &"Trigger", &"Grip", 1, &"ClosedHand2", &"Trigger", 0, &"OpenHand", &"Trigger", 1, &"ClosedHand1"] node_connections = [&"output", 0, &"Grip", &"Grip", 0, &"Trigger", &"Grip", 1, &"ClosedHand2", &"Trigger", 0, &"OpenHand", &"Trigger", 1, &"ClosedHand1"]
@@ -45,34 +45,34 @@ node_connections = [&"output", 0, &"Grip", &"Grip", 0, &"Trigger", &"Grip", 1, &
transparency = 1 transparency = 1
albedo_color = Color(1, 1, 1, 0.5882353) albedo_color = Color(1, 1, 1, 0.5882353)
[sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_qpjda"] [sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_5mmou"]
animation = &"Grip" animation = &"Grip"
[sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_37hbl"] [sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_yfij0"]
animation = &"Grip" animation = &"Grip"
[sub_resource type="AnimationNodeBlend2" id="AnimationNodeBlend2_to5tn"] [sub_resource type="AnimationNodeBlend2" id="AnimationNodeBlend2_2ebvs"]
filter_enabled = true filter_enabled = true
filters = ["Armature/Skeleton3D:Little_Distal_R", "Armature/Skeleton3D:Little_Intermediate_R", "Armature/Skeleton3D:Little_Metacarpal_R", "Armature/Skeleton3D:Little_Proximal_R", "Armature/Skeleton3D:Middle_Distal_R", "Armature/Skeleton3D:Middle_Intermediate_R", "Armature/Skeleton3D:Middle_Metacarpal_R", "Armature/Skeleton3D:Middle_Proximal_R", "Armature/Skeleton3D:Ring_Distal_R", "Armature/Skeleton3D:Ring_Intermediate_R", "Armature/Skeleton3D:Ring_Metacarpal_R", "Armature/Skeleton3D:Ring_Proximal_R", "Armature/Skeleton3D:Thumb_Distal_R", "Armature/Skeleton3D:Thumb_Metacarpal_R", "Armature/Skeleton3D:Thumb_Proximal_R", "Armature/Skeleton:Little_Distal_R", "Armature/Skeleton:Little_Intermediate_R", "Armature/Skeleton:Little_Proximal_R", "Armature/Skeleton:Middle_Distal_R", "Armature/Skeleton:Middle_Intermediate_R", "Armature/Skeleton:Middle_Proximal_R", "Armature/Skeleton:Ring_Distal_R", "Armature/Skeleton:Ring_Intermediate_R", "Armature/Skeleton:Ring_Proximal_R", "Armature/Skeleton:Thumb_Distal_R", "Armature/Skeleton:Thumb_Proximal_R"] filters = ["Armature/Skeleton3D:Little_Distal_R", "Armature/Skeleton3D:Little_Intermediate_R", "Armature/Skeleton3D:Little_Metacarpal_R", "Armature/Skeleton3D:Little_Proximal_R", "Armature/Skeleton3D:Middle_Distal_R", "Armature/Skeleton3D:Middle_Intermediate_R", "Armature/Skeleton3D:Middle_Metacarpal_R", "Armature/Skeleton3D:Middle_Proximal_R", "Armature/Skeleton3D:Ring_Distal_R", "Armature/Skeleton3D:Ring_Intermediate_R", "Armature/Skeleton3D:Ring_Metacarpal_R", "Armature/Skeleton3D:Ring_Proximal_R", "Armature/Skeleton3D:Thumb_Distal_R", "Armature/Skeleton3D:Thumb_Metacarpal_R", "Armature/Skeleton3D:Thumb_Proximal_R", "Armature/Skeleton:Little_Distal_R", "Armature/Skeleton:Little_Intermediate_R", "Armature/Skeleton:Little_Proximal_R", "Armature/Skeleton:Middle_Distal_R", "Armature/Skeleton:Middle_Intermediate_R", "Armature/Skeleton:Middle_Proximal_R", "Armature/Skeleton:Ring_Distal_R", "Armature/Skeleton:Ring_Intermediate_R", "Armature/Skeleton:Ring_Proximal_R", "Armature/Skeleton:Thumb_Distal_R", "Armature/Skeleton:Thumb_Proximal_R"]
[sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_nlnu7"] [sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_l8v2a"]
animation = &"Grip 5" animation = &"Grip 5"
[sub_resource type="AnimationNodeBlend2" id="AnimationNodeBlend2_we6ah"] [sub_resource type="AnimationNodeBlend2" id="AnimationNodeBlend2_qpjda"]
filter_enabled = true filter_enabled = true
filters = ["Armature/Skeleton3D:Index_Distal_R", "Armature/Skeleton3D:Index_Intermediate_R", "Armature/Skeleton3D:Index_Metacarpal_R", "Armature/Skeleton3D:Index_Proximal_R", "Armature/Skeleton:Index_Distal_R", "Armature/Skeleton:Index_Intermediate_R", "Armature/Skeleton:Index_Proximal_R"] filters = ["Armature/Skeleton3D:Index_Distal_R", "Armature/Skeleton3D:Index_Intermediate_R", "Armature/Skeleton3D:Index_Metacarpal_R", "Armature/Skeleton3D:Index_Proximal_R", "Armature/Skeleton:Index_Distal_R", "Armature/Skeleton:Index_Intermediate_R", "Armature/Skeleton:Index_Proximal_R"]
[sub_resource type="AnimationNodeBlendTree" id="AnimationNodeBlendTree_dtgvk"] [sub_resource type="AnimationNodeBlendTree" id="AnimationNodeBlendTree_37hbl"]
graph_offset = Vector2(-552.664, 107.301) graph_offset = Vector2(-552.664, 107.301)
nodes/ClosedHand1/node = SubResource("AnimationNodeAnimation_qpjda") nodes/ClosedHand1/node = SubResource("AnimationNodeAnimation_5mmou")
nodes/ClosedHand1/position = Vector2(-600, 300) nodes/ClosedHand1/position = Vector2(-600, 300)
nodes/ClosedHand2/node = SubResource("AnimationNodeAnimation_37hbl") nodes/ClosedHand2/node = SubResource("AnimationNodeAnimation_yfij0")
nodes/ClosedHand2/position = Vector2(-360, 300) nodes/ClosedHand2/position = Vector2(-360, 300)
nodes/Grip/node = SubResource("AnimationNodeBlend2_to5tn") nodes/Grip/node = SubResource("AnimationNodeBlend2_2ebvs")
nodes/Grip/position = Vector2(0, 40) nodes/Grip/position = Vector2(0, 40)
nodes/OpenHand/node = SubResource("AnimationNodeAnimation_nlnu7") nodes/OpenHand/node = SubResource("AnimationNodeAnimation_l8v2a")
nodes/OpenHand/position = Vector2(-600, 100) nodes/OpenHand/position = Vector2(-600, 100)
nodes/Trigger/node = SubResource("AnimationNodeBlend2_we6ah") nodes/Trigger/node = SubResource("AnimationNodeBlend2_qpjda")
nodes/Trigger/position = Vector2(-360, 40) nodes/Trigger/position = Vector2(-360, 40)
node_connections = [&"output", 0, &"Grip", &"Grip", 0, &"Trigger", &"Grip", 1, &"ClosedHand2", &"Trigger", 0, &"OpenHand", &"Trigger", 1, &"ClosedHand1"] node_connections = [&"output", 0, &"Grip", &"Grip", 0, &"Trigger", &"Grip", 1, &"ClosedHand2", &"Trigger", 0, &"OpenHand", &"Trigger", 1, &"ClosedHand1"]
@@ -120,7 +120,7 @@ bone_idx = 9
[node name="Poke" parent="XRControllerLeftHand/LeftHand/Hand_low_L/Armature/Skeleton3D/BoneAttachment3D" unique_id=259928841 instance=ExtResource("7_1fmci")] [node name="Poke" parent="XRControllerLeftHand/LeftHand/Hand_low_L/Armature/Skeleton3D/BoneAttachment3D" unique_id=259928841 instance=ExtResource("7_1fmci")]
[node name="AnimationTree" parent="XRControllerLeftHand/LeftHand" index="1"] [node name="AnimationTree" parent="XRControllerLeftHand/LeftHand" index="1"]
tree_root = SubResource("AnimationNodeBlendTree_l8v2a") tree_root = SubResource("AnimationNodeBlendTree_i0gvw")
[node name="MovementDirect" parent="XRControllerLeftHand" unique_id=1865515938 instance=ExtResource("2_q1xvu")] [node name="MovementDirect" parent="XRControllerLeftHand" unique_id=1865515938 instance=ExtResource("2_q1xvu")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.009340696, -0.0074635968, 0.024033919) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.009340696, -0.0074635968, 0.024033919)
@@ -181,7 +181,7 @@ bone_idx = 9
[node name="Poke" parent="XRControllerRightHand/RightHand/Hand_low_R/Armature/Skeleton3D/BoneAttachment3D" unique_id=303927399 instance=ExtResource("7_1fmci")] [node name="Poke" parent="XRControllerRightHand/RightHand/Hand_low_R/Armature/Skeleton3D/BoneAttachment3D" unique_id=303927399 instance=ExtResource("7_1fmci")]
[node name="AnimationTree" parent="XRControllerRightHand/RightHand" index="1"] [node name="AnimationTree" parent="XRControllerRightHand/RightHand" index="1"]
tree_root = SubResource("AnimationNodeBlendTree_dtgvk") tree_root = SubResource("AnimationNodeBlendTree_37hbl")
[node name="MovementTurn" parent="XRControllerRightHand" unique_id=154529119 instance=ExtResource("4_rd8py")] [node name="MovementTurn" parent="XRControllerRightHand" unique_id=154529119 instance=ExtResource("4_rd8py")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.0074635968, 0.024033919) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.0074635968, 0.024033919)
+95 -17
View File
@@ -7,11 +7,15 @@ extends Node
var move_handle_rigid: RigidBody3D var move_handle_rigid: RigidBody3D
var original_collision_layer: int = 0 var original_collision_layer: int = 0
var original_y_pos: float = 0.0 var original_handle_y_pos: float = 0.0
var original_station_transform: Transform3D = Transform3D.IDENTITY var original_station_transform: Transform3D = Transform3D.IDENTITY
@export var moving: bool = false @export var moving: bool = false
var ghost_materials: Array[StandardMaterial3D] = [] var ghost_materials: Array[StandardMaterial3D] = []
# Ghost update throttling (clients send unreliable RPCs to server at this rate)
var ghost_send_interval: float = 0.1 # seconds (10 Hz)
var _ghost_send_accum: float = 0.0
const GHOST_COLOR_VALID: Color = Color(0, 1, 0, 0.35) const GHOST_COLOR_VALID: Color = Color(0, 1, 0, 0.35)
const GHOST_COLOR_INVALID: Color = Color(1, 0, 0, 0.35) const GHOST_COLOR_INVALID: Color = Color(1, 0, 0, 0.35)
@@ -42,7 +46,7 @@ func _ready() -> void:
move_handle_rigid = move_handle as RigidBody3D move_handle_rigid = move_handle as RigidBody3D
original_collision_layer = station.collision_layer original_collision_layer = station.collision_layer
original_y_pos = move_handle.transform.origin.y original_handle_y_pos = move_handle.transform.origin.y
original_station_transform = station.global_transform original_station_transform = station.global_transform
move_handle.picked_up.connect(_handle_pickup) move_handle.picked_up.connect(_handle_pickup)
move_handle.dropped.connect(_handle_drop) move_handle.dropped.connect(_handle_drop)
@@ -93,16 +97,21 @@ func _handle_pickup(_by: Node) -> void:
if move_handle.get_picked_up_by() is XRToolsSnapZone: if move_handle.get_picked_up_by() is XRToolsSnapZone:
print("StationMovement handle pickup by snap zone, dropping and resetting position") print("StationMovement handle pickup by snap zone, dropping and resetting position")
move_handle.drop() move_handle.drop()
move_handle.global_position = station.global_position + Vector3(0, original_y_pos, 0) move_handle.global_position = station.global_position + Vector3(0, original_handle_y_pos, 0)
move_handle.rotation = station.rotation move_handle.rotation = station.rotation
return return
moving = true moving = true
move_ghost.visible = true
station.visible = false
station.collision_layer = 0 station.collision_layer = 0
original_station_transform = station.global_transform original_station_transform = station.global_transform
move_ghost.global_transform = original_station_transform move_ghost.global_transform = original_station_transform
if NetworkManager.is_online():
# Ask the server to update visibility (reliable)
server_update_visibility.rpc_id(1, true, false)
else:
# If not connected to server (single-player or test), apply locally
move_ghost.visible = true
station.visible = false
func _handle_drop(_by: Node) -> void: func _handle_drop(_by: Node) -> void:
@@ -111,24 +120,43 @@ func _handle_drop(_by: Node) -> void:
move_ghost.visible = false move_ghost.visible = false
station.visible = true station.visible = true
station.collision_layer = original_collision_layer station.collision_layer = original_collision_layer
if _is_move_position_valid():
station.global_transform = move_ghost.global_transform
else:
station.global_transform = original_station_transform
move_handle.global_position = station.global_position + Vector3(0, original_y_pos, 0)
move_handle.rotation = station.rotation
var is_valid: bool = _is_move_position_valid()
if NetworkManager.is_online():
server_handle_drop.rpc_id(1, move_ghost.global_transform, is_valid)
else:
# If not connected to server (single-player or test), apply locally only when valid
if is_valid:
station.global_transform = move_ghost.global_transform
move_handle.global_transform = move_ghost.global_transform.translated(Vector3(0, original_handle_y_pos, 0))
print("StationMovement handle drop (local apply), station authority: ", station.get_multiplayer_authority(), " move_handle authority: ", move_handle.get_multiplayer_authority())
else:
station.global_transform = original_station_transform
move_handle.global_transform = original_station_transform.translated(Vector3(0, original_handle_y_pos, 0))
print("StationMovement handle drop (local reject), restoring original position")
func _process(_delta: float) -> void: func _process(_delta: float) -> void:
if not moving: if not moving:
return return
# Update the ghost locally for instant feedback and send throttled unreliable RPCs to the server
move_ghost.visible = true
station.visible = false
move_ghost.global_transform = Helper.get_snapped_transform(move_handle) move_ghost.global_transform = Helper.get_snapped_transform(move_handle)
move_ghost.global_transform.origin.y = original_station_transform.origin.y move_ghost.global_transform.origin.y = original_station_transform.origin.y
if _is_move_position_valid():
_set_ghost_color(GHOST_COLOR_VALID) var ghost_color = GHOST_COLOR_VALID if _is_move_position_valid() else GHOST_COLOR_INVALID
else: _set_ghost_color(ghost_color)
_set_ghost_color(GHOST_COLOR_INVALID)
# Throttle and send ghost transform updates to server so other clients see the preview
_ghost_send_accum += _delta
if _ghost_send_accum >= ghost_send_interval:
_ghost_send_accum = 0.0
# Unreliable RPC to the server to update the server-side ghost; server will replicate to clients
# Use rpc_unreliable_id to avoid blocking traffic
if NetworkManager.is_online():
server_update_move_ghost_transform.rpc_id(1, move_ghost.global_transform, ghost_color)
func _is_move_position_valid() -> bool: func _is_move_position_valid() -> bool:
@@ -146,9 +174,59 @@ func _is_move_position_valid() -> bool:
return false return false
for area in move_ghost.get_overlapping_areas(): for area in move_ghost.get_overlapping_areas():
print("Overlapping area: ", area) #print("Overlapping area: ", area)
if area == move_ghost: if area == move_ghost:
continue continue
return false return false
return true return true
@rpc("any_peer", "call_remote", "reliable")
func server_handle_drop(new_transform: Transform3D, client_thinks_valid: bool):
if not multiplayer.is_server():
return
if not (client_thinks_valid):
# Reset state for everyone, including server
var original_trans = original_station_transform # Make a copy to avoid server_update_station_transform setting it before move handle uses it
server_update_station_transform.rpc(original_trans)
server_update_move_ghost_transform.rpc(original_trans)
server_update_handle_transform.rpc(original_trans.translated(Vector3(0, original_handle_y_pos, 0)))
server_update_visibility.rpc(false, true)
print("StationMovement server_handle_drop: transform rejected (invalid)")
return
server_update_station_transform.rpc(new_transform)
server_update_move_ghost_transform.rpc(new_transform)
server_update_handle_transform.rpc(new_transform.translated(Vector3(0, original_handle_y_pos, 0)))
server_update_visibility.rpc(false, true)
print("StationMovement server_handle_drop: transform applied")
@rpc("any_peer", "call_local", "reliable") # Server updates clients
func server_update_station_transform(new_transform: Transform3D) -> void:
print("StationMovement server_update_station_transform")
station.global_transform = new_transform
original_station_transform = new_transform
@rpc("any_peer", "call_local", "reliable") # Server updates clients
func server_update_handle_transform(new_transform: Transform3D) -> void:
print("StationMovement server_update_handle_transform")
move_handle.global_transform = new_transform
@rpc("any_peer", "call_local", "reliable")
func server_update_visibility(ghost_visible: bool, station_visible: bool) -> void:
print("StationMovement server_update_visibility")
move_ghost.visible = ghost_visible
station.visible = station_visible
@rpc("any_peer", "call_local", "unreliable")
func server_update_move_ghost_transform(new_transform: Transform3D, new_color: Color = Color.YELLOW) -> void:
print("StationMovement server_update_move_ghost_transform")
move_ghost.global_transform = new_transform
_set_ghost_color(new_color)
+19
View File
@@ -0,0 +1,19 @@
extends Node
func _ready() -> void:
if OS.has_feature("editor"):
# Force subwindows to be native OS windows instead of embedded viewports
get_tree().root.gui_embed_subwindows = false
get_tree().create_timer(0.05).timeout.connect(_position_window)
func _position_window() -> void:
var is_server: bool = OS.get_cmdline_args().has("--server")
var screen_rect: Rect2i = DisplayServer.screen_get_usable_rect(DisplayServer.window_get_current_screen())
var window_width: int = screen_rect.size.x / 2
var window_height: int = int(screen_rect.size.y * (2.0 / 3.0))
DisplayServer.window_set_size(Vector2i(window_width - 10, window_height))
var x_pos: int = screen_rect.position.x + window_width if is_server else screen_rect.position.x
DisplayServer.window_set_position(Vector2i(x_pos, screen_rect.position.y))
+1
View File
@@ -0,0 +1 @@
uid://de8j52uus1pbv
+5 -1
View File
@@ -2,7 +2,7 @@ extends Node
func _unhandled_input(event: InputEvent) -> void: func _unhandled_input(event: InputEvent) -> void:
if event.is_action_pressed("quit_game"): if event.is_action_pressed("quit_game"):
get_tree().quit() all_quit_game.rpc()
if event.is_action_pressed("satisfy_table_orders"): if event.is_action_pressed("satisfy_table_orders"):
satisfy_table_orders() satisfy_table_orders()
if event.is_action_pressed("set_building_mode"): if event.is_action_pressed("set_building_mode"):
@@ -12,6 +12,10 @@ func _unhandled_input(event: InputEvent) -> void:
if event.is_action_pressed("set_game_over"): if event.is_action_pressed("set_game_over"):
set_game_over() set_game_over()
# Kill all clients
@rpc("any_peer", "call_local", "reliable")
func all_quit_game():
get_tree().quit()
# Finds any node of class/type Table and calls satisfyAllOrders() # Finds any node of class/type Table and calls satisfyAllOrders()
func satisfy_table_orders() -> void: func satisfy_table_orders() -> void: